diff --git a/.gitignore b/.gitignore index 4ac78ce82e..698b60de5a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,21 +24,9 @@ libraries/wallet/api_documentation.cpp libraries/wallet/doxygen programs/cli_wallet/cli_wallet -programs/js_operation_serializer/js_operation_serializer programs/vizd/vizd -programs/vizd/test -programs/delayed_node programs/build_helpers/cat-parts -programs/size_checker/size_checker programs/util/get_dev_key -programs/util/inflation_model - -tests/app_test -tests/chain_bench -tests/chain_test -tests/plugin_test -tests/intense_test -tests/performance_test wallet.json node_data_dir @@ -58,7 +46,7 @@ build-*/ node_modules/* -.qoder/logs/* +.qoder/ # Local design specs and implementation plans (not part of repo) docs/superpowers/ diff --git a/.qoder/agents/senior-engineer.md b/.qoder/agents/senior-engineer.md deleted file mode 100644 index 01e308ca3c..0000000000 --- a/.qoder/agents/senior-engineer.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: senior-engineer -description: Senior engineer focused on implementation speed and correctness. Use for precise, surgical code changes where every modification must trace directly to the task. Ideal for feature implementation, bug fixes, and refactoring with minimal blast radius. -tools: Read, Write, Edit, Bash, Grep, Glob ---- - -# Role Definition - -You are a senior engineer focused on implementation speed and correctness. - -Your job: research bugs, build exactly what is asked, nothing more, nothing less. - -## Language Rules - -- **Chat responses**: respond to the user **only in Russian** -- **Plan, commit messages, code comments**: write in **English** -- **In-code comments**: must be self-contained — no references to external log files, ticket numbers, fix IDs, or task numbers (log files are temporary and will be deleted) - -## Rules - -- Read the full context before writing a single line -- Make surgical changes only, touch nothing adjacent to the task -- If you see a better approach, say so before building -- Validate your changes against existing logic before responding -- Every changed line must trace directly to the task -- For long-horizon tasks, state your plan and verify each step before moving to the next - -## Agent Behavior - -- Report progress every 30 steps -- Flag blockers immediately instead of working around them silently -- If a subtask fails, pause and surface it rather than continuing -- **Never suggest building the project** — this is a public project that auto-builds via GitHub Actions and publishes to Docker Hub. Always assume you are working with the latest build. - -## Debugging Rules - -- **Never guess workflow from logs.** Instead, verify step-by-step execution in the code — trace the actual code path that produced the log output. -- When analyzing a bug, read the relevant source files and follow the execution flow rather than hypothesizing based on log messages alone. - -## Workflow - -1. Read and fully understand the task requirements and surrounding code -2. Identify the minimal set of files and lines that need to change -3. If a better approach exists, state it clearly before proceeding -4. Plan the changes, listing each file and the specific modification -5. Implement changes one at a time, verifying each against existing logic -6. Confirm nothing adjacent was broken -7. After implementation, generate a **medium-length** git commit message in English and output it in chat inside a ``` block **without literal \n characters** so the user can copy-paste it in one click - -## Output Format - -**Plan** -- List of files to modify and what changes are needed -- Write the plan in **English** -- Ask to make changes, implement plan - -**Changes Made** -- File and line references for each modification -- Brief justification tracing back to the task -- Code comments must be **self-contained** — no references to log files, fix numbers, task IDs, or any external artifact - -**Verification** -- How the changes were validated -- Any risks or follow-up items - -**Commit Message** -- After all changes are implemented, output a medium-length English commit message in a single ``` block -- Do NOT use literal `\n` in the message — write actual line breaks -- The message must be ready to copy-paste with one click - -## Constraints - -**MUST DO:** -- Trace every changed line directly to the task -- Verify changes against existing logic before finalizing -- Surface blockers immediately -- Ask to implement plan before making changes to files -- Respond to the user in Russian in chat -- Write plans and commit messages in English -- Make code comments self-contained without references to external artifacts -- Verify code execution paths step by step instead of guessing from logs -- Assume the latest build — never suggest building - -**MUST NOT DO:** -- Touch code unrelated to the task -- Make speculative or "while I'm here" improvements -- Work around blockers silently -- Continue past a failed subtask without surfacing it -- Reference log file paths or names in code comments -- Include fix/task/ticket numbers in code comments -- Guess workflow from logs — verify in code -- Suggest building the project -- Use literal `\n` in commit message blocks - -## Success Criteria - -The change works, nothing else broke, every step is traceable. diff --git a/.qoder/docs/block-log-reader.js b/.qoder/docs/block-log-reader.js deleted file mode 100644 index 510e0d85a1..0000000000 --- a/.qoder/docs/block-log-reader.js +++ /dev/null @@ -1,2107 +0,0 @@ -/** - * VIZ Block Log Reader for JavaScript/Node.js - * - * Reads block_log and dlt_block_log files from VIZ blockchain nodes. - * Based on block-log-spec.json specification. - * - * @module block-log-reader - */ - -const fs = require('fs'); -const path = require('path'); -const crypto = require('crypto'); - -// ============================================================================ -// Constants -// ============================================================================ - -const CONSTANTS = { - CHAIN_BLOCK_SIZE: 1048576, // Max block size (1 MB) - MIN_VALID_FILE_SIZE: 8, // Minimum valid file size - INDEX_HEADER_SIZE: 8, // DLT index header size - SIGNATURE_SIZE: 65, // Compact signature size - HASH_SIZE_RIPEMD160: 20, // RIPEMD-160 hash size - HASH_SIZE_SHA256: 32, // SHA-256 hash size - NPOS: BigInt('0xFFFFFFFFFFFFFFFF'), // Invalid position marker - - CHAIN_ADDRESS_PREFIX: 'VIZ', // Public key base58 prefix - - // Asset symbols (Steem-style: byte 0 = decimals, bytes 1-6 = ASCII name, byte 7 = 0x00) - // From config.hpp: SHARES_SYMBOL = 6|('S'<<8)|('H'<<16)|('A'<<24)|('R'<<32)|('E'<<40)|('S'<<48) - // TOKEN_SYMBOL = 3|('V'<<8)|('I'<<16)|('Z'<<24) - TOKEN_SYMBOL: BigInt('0x000000005A495603'), - SHARES_SYMBOL: BigInt('0x0053455241485306') -}; - -// Operation type IDs mapping -const OPERATION_TYPES = { - 0: { name: 'vote_operation', isVirtual: false }, - 1: { name: 'content_operation', isVirtual: false }, - 2: { name: 'transfer_operation', isVirtual: false }, - 3: { name: 'transfer_to_vesting_operation', isVirtual: false }, - 4: { name: 'withdraw_vesting_operation', isVirtual: false }, - 5: { name: 'account_update_operation', isVirtual: false }, - 6: { name: 'witness_update_operation', isVirtual: false }, - 7: { name: 'account_witness_vote_operation', isVirtual: false }, - 8: { name: 'account_witness_proxy_operation', isVirtual: false }, - 9: { name: 'delete_content_operation', isVirtual: false }, - 10: { name: 'custom_operation', isVirtual: false }, - 11: { name: 'set_withdraw_vesting_route_operation', isVirtual: false }, - 12: { name: 'request_account_recovery_operation', isVirtual: false }, - 13: { name: 'recover_account_operation', isVirtual: false }, - 14: { name: 'change_recovery_account_operation', isVirtual: false }, - 15: { name: 'escrow_transfer_operation', isVirtual: false }, - 16: { name: 'escrow_dispute_operation', isVirtual: false }, - 17: { name: 'escrow_release_operation', isVirtual: false }, - 18: { name: 'escrow_approve_operation', isVirtual: false }, - 19: { name: 'delegate_vesting_shares_operation', isVirtual: false }, - 20: { name: 'account_create_operation', isVirtual: false }, - 21: { name: 'account_metadata_operation', isVirtual: false }, - 22: { name: 'proposal_create_operation', isVirtual: false }, - 23: { name: 'proposal_update_operation', isVirtual: false }, - 24: { name: 'proposal_delete_operation', isVirtual: false }, - 25: { name: 'chain_properties_update_operation', isVirtual: false }, - 26: { name: 'author_reward_operation', isVirtual: true }, - 27: { name: 'curation_reward_operation', isVirtual: true }, - 28: { name: 'content_reward_operation', isVirtual: true }, - 29: { name: 'fill_vesting_withdraw_operation', isVirtual: true }, - 30: { name: 'shutdown_witness_operation', isVirtual: true }, - 31: { name: 'hardfork_operation', isVirtual: true }, - 32: { name: 'content_payout_update_operation', isVirtual: true }, - 33: { name: 'content_benefactor_reward_operation', isVirtual: true }, - 34: { name: 'return_vesting_delegation_operation', isVirtual: true }, - 35: { name: 'committee_worker_create_request_operation', isVirtual: false }, - 36: { name: 'committee_worker_cancel_request_operation', isVirtual: false }, - 37: { name: 'committee_vote_request_operation', isVirtual: false }, - 38: { name: 'committee_cancel_request_operation', isVirtual: true }, - 39: { name: 'committee_approve_request_operation', isVirtual: true }, - 40: { name: 'committee_payout_request_operation', isVirtual: true }, - 41: { name: 'committee_pay_request_operation', isVirtual: true }, - 42: { name: 'witness_reward_operation', isVirtual: true }, - 43: { name: 'create_invite_operation', isVirtual: false }, - 44: { name: 'claim_invite_balance_operation', isVirtual: false }, - 45: { name: 'invite_registration_operation', isVirtual: false }, - 46: { name: 'versioned_chain_properties_update_operation', isVirtual: false }, - 47: { name: 'award_operation', isVirtual: false }, - 48: { name: 'receive_award_operation', isVirtual: true }, - 49: { name: 'benefactor_award_operation', isVirtual: true }, - 50: { name: 'set_paid_subscription_operation', isVirtual: false }, - 51: { name: 'paid_subscribe_operation', isVirtual: false }, - 52: { name: 'paid_subscription_action_operation', isVirtual: true }, - 53: { name: 'cancel_paid_subscription_operation', isVirtual: true }, - 54: { name: 'set_account_price_operation', isVirtual: false }, - 55: { name: 'set_subaccount_price_operation', isVirtual: false }, - 56: { name: 'buy_account_operation', isVirtual: false }, - 57: { name: 'account_sale_operation', isVirtual: true }, - 58: { name: 'use_invite_balance_operation', isVirtual: false }, - 59: { name: 'expire_escrow_ratification_operation', isVirtual: true }, - 60: { name: 'fixed_award_operation', isVirtual: false }, - 61: { name: 'target_account_sale_operation', isVirtual: false }, - 62: { name: 'bid_operation', isVirtual: true }, - 63: { name: 'outbid_operation', isVirtual: true } -}; - -// ============================================================================ -// Binary Reading Utilities -// ============================================================================ - -class BinaryReader { - constructor(buffer, offset = 0) { - this.buffer = buffer; - this.offset = offset; - } - - /** - * Read unsigned 8-bit integer - */ - readUint8() { - return this.buffer.readUInt8(this.offset++); - } - - /** - * Read unsigned 16-bit integer (little-endian) - */ - readUint16LE() { - const value = this.buffer.readUInt16LE(this.offset); - this.offset += 2; - return value; - } - - /** - * Read unsigned 32-bit integer (little-endian) - */ - readUint32LE() { - const value = this.buffer.readUInt32LE(this.offset); - this.offset += 4; - return value; - } - - /** - * Read unsigned 64-bit integer as BigInt (little-endian) - */ - readUint64LE() { - const value = this.buffer.readBigUInt64LE(this.offset); - this.offset += 8; - return value; - } - - /** - * Read signed 32-bit integer (little-endian) - */ - readInt32LE() { - const value = this.buffer.readInt32LE(this.offset); - this.offset += 4; - return value; - } - - /** - * Read signed 64-bit integer as BigInt (little-endian) - */ - readInt64LE() { - const value = this.buffer.readBigInt64LE(this.offset); - this.offset += 8; - return value; - } - - /** - * Read variable-length unsigned integer (fc::unsigned_int) - * Uses protobuf-style varint encoding - */ - readVarint() { - let value = BigInt(0); - let shift = 0; - - while (true) { - const byte = this.readUint8(); - value |= BigInt(byte & 0x7F) << BigInt(shift); - - if (!(byte & 0x80)) break; - shift += 7; - } - - return value; - } - - /** - * Read variable-length signed integer (fc::signed_int) - * Uses zigzag encoding + varint - */ - readSignedVarint() { - const n = this.readVarint(); - // Un-zigzag: (n >> 1) ^ -(n & 1) - return Number((n >> BigInt(1)) ^ (-(n & BigInt(1)))); - } - - /** - * Read fixed-length bytes - */ - readBytes(length) { - const data = this.buffer.slice(this.offset, this.offset + length); - this.offset += length; - return data; - } - - /** - * Read fc::raw serialized string - */ - readString() { - const length = Number(this.readVarint()); - if (length === 0) return ''; - const data = this.readBytes(length); - return data.toString('utf8'); - } - - /** - * Read fc::raw serialized vector of items using provided reader function - * @param {Function} itemReader - Function to read each item - * @param {number} [maxItems=100000] - Safety cap to prevent OOM from corrupted data - */ - readVector(itemReader, maxItems = 100000) { - const count = Number(this.readVarint()); - if (count > maxItems) { - throw new Error(`readVector: count ${count} exceeds safety cap ${maxItems} (offset ${this.offset})`); - } - const items = []; - - for (let i = 0; i < count; i++) { - items.push(itemReader(this)); - } - - return items; - } - - /** - * Read fc::raw serialized optional value - */ - readOptional(itemReader) { - const flag = this.readUint8(); - if (flag === 0) return null; - return itemReader(this); - } - - /** - * Read flat_set of pairs - */ - readFlatSetOfPairs(keyReader, valueReader) { - const count = Number(this.readVarint()); - const items = []; - for (let i = 0; i < count; i++) { - const key = keyReader(this); - const value = valueReader(this); - items.push([key, value]); - } - return items; - } - - /** - * Get current position - */ - getPosition() { - return this.offset; - } - - /** - * Set position - */ - setPosition(pos) { - this.offset = pos; - } - - /** - * Get remaining bytes - */ - getRemaining() { - return this.buffer.length - this.offset; - } -} - -// ============================================================================ -// Type Deserializers -// ============================================================================ - -/** - * Read RIPEMD-160 hash (20 bytes) - */ -function readRipemd160(reader) { - return reader.readBytes(CONSTANTS.HASH_SIZE_RIPEMD160); -} - -/** - * Read SHA-256 hash (32 bytes) - */ -function readSha256(reader) { - return reader.readBytes(CONSTANTS.HASH_SIZE_SHA256); -} - -/** - * Read compact signature (65 bytes) - */ -function readCompactSignature(reader) { - return reader.readBytes(CONSTANTS.SIGNATURE_SIZE); -} - -/** - * Read time_point_sec (uint32 Unix timestamp) - */ -function readTimePointSec(reader) { - const timestamp = reader.readUint32LE(); - return new Date(timestamp * 1000); -} - -/** - * Read block_header_extension (static_variant) - * - * Type 0: void_t — empty struct, no serialized data - * Type 1: version — uint32_t v_num (major.hardfork.release packed as 8.8.16 bits) - * Type 2: hardfork_version_vote — hardfork_version (uint32_t) + time_point_sec (uint32_t) - */ -function readBlockHeaderExtension(reader) { - const typeIndex = Number(reader.readVarint()); - switch (typeIndex) { - case 0: return { typeIndex, name: 'void_t', data: {} }; - case 1: { - const vNum = reader.readUint32LE(); - const major = (vNum >> 24) & 0xFF; - const hardfork = (vNum >> 16) & 0xFF; - const release = vNum & 0xFFFF; - return { typeIndex, name: 'version', data: { v_num: vNum, version: `${major}.${hardfork}.${release}` } }; - } - case 2: { - const vNum = reader.readUint32LE(); - const major = (vNum >> 24) & 0xFF; - const hardfork = (vNum >> 16) & 0xFF; - const hfTime = readTimePointSec(reader); - return { typeIndex, name: 'hardfork_version_vote', data: { hf_version: `${major}.${hardfork}.0`, hf_time: hfTime } }; - } - default: - // Unknown extension type — can't skip without schema, deserialization will likely fail - return { typeIndex, name: 'unknown_extension', data: { _warning: 'unknown extension type, stream may be corrupted' } }; - } -} - -/** - * Read block_header - * - * Note (Steem/VIZ lineage): block_id_type and checksum_type are fc::ripemd160 (20 bytes), - * NOT fc::sha256 (32 bytes). This is an inherited design from the Steem codebase where - * block IDs and merkle roots use the shorter ripemd160 hash. - */ -function readBlockHeader(reader) { - return { - previous: readRipemd160(reader), - timestamp: readTimePointSec(reader), - witness: reader.readString(), - transaction_merkle_root: readRipemd160(reader), - extensions: reader.readVector(readBlockHeaderExtension) - }; -} - -/** - * Read signed_block_header - */ -function readSignedBlockHeader(reader) { - const header = readBlockHeader(reader); - return { - ...header, - witness_signature: readCompactSignature(reader) - }; -} - -// ============================================================================ -// Common Types for Operations -// ============================================================================ - -/** - * Decode Steem-style asset symbol from uint64. - * Format (from asset.cpp comments): - * byte 0 : decimals (precision) - * bytes 1-6 : ASCII symbol name - * byte 7 : 0x00 (null terminator) - */ -function decodeAssetSymbol(symbol) { - // Read as 8-byte buffer (little-endian uint64) - const buf = Buffer.alloc(8); - buf.writeBigUInt64LE(BigInt(symbol), 0); - - const decimals = buf.readUInt8(0); - let name = ''; - for (let i = 1; i < 7; i++) { - const c = buf.readUInt8(i); - if (c === 0) break; - name += String.fromCharCode(c); - } - return { decimals, name }; -} - -/** - * Read asset (int64 amount + uint64 symbol) - * - * Asset symbol format inherited from Steem codebase: - * byte 0 = decimal precision, bytes 1-6 = ASCII name, byte 7 = null - */ -function readAsset(reader) { - const amount = reader.readInt64LE(); - const symbol = reader.readUint64LE(); - const decoded = decodeAssetSymbol(symbol); - return { amount: Number(amount), symbol: decoded.name, decimals: decoded.decimals }; -} - -/** - * Base58 encode (Bitcoin alphabet). - * Encodes a Buffer to a base58 string. - */ -const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; -function base58Encode(buf) { - let num = BigInt('0x' + buf.toString('hex')); - let result = ''; - while (num > 0n) { - result = BASE58_ALPHABET[Number(num % 58n)] + result; - num = num / 58n; - } - // Leading zero bytes -> leading '1' chars - for (let i = 0; i < buf.length && buf[i] === 0; i++) { - result = '1' + result; - } - return result; -} - -/** - * Convert raw 33-byte compressed public key to "VIZ..." address string. - * Mirrors C++ public_key_type::operator std::string(): - * 1. Compute ripemd160 of the 33 raw bytes - * 2. Take first 4 bytes of the hash as checksum - * 3. Pack: [33 bytes key data][4 bytes checksum LE] = 37 bytes - * 4. Base58 encode and prepend "VIZ" prefix - */ -function publicKeyToString(keyBytes) { - const checksum = crypto.createHash('ripemd160').update(keyBytes).digest(); - const packed = Buffer.alloc(37); - keyBytes.copy(packed, 0); // 33 bytes key data - checksum.copy(packed, 33, 0, 4); // 4 bytes checksum - return CONSTANTS.CHAIN_ADDRESS_PREFIX + base58Encode(packed); -} - -/** - * Read public_key_type (33 bytes compressed) as "VIZ..." string - */ -function readPublicKey(reader) { - const keyBytes = reader.readBytes(33); - return publicKeyToString(keyBytes); -} - -/** - * Read account_name_type (string) - */ -function readAccountName(reader) { - return reader.readString(); -} - -/** - * Read authority - */ -function readAuthority(reader) { - return { - weight_threshold: reader.readUint32LE(), - account_auths: reader.readFlatSetOfPairs(readAccountName, (r) => r.readUint16LE()), - key_auths: reader.readFlatSetOfPairs(readPublicKey, (r) => r.readUint16LE()) - }; -} - -/** - * Read beneficiary_route_type - */ -function readBeneficiaryRoute(reader) { - return { - account: readAccountName(reader), - weight: reader.readUint16LE() - }; -} - -// ============================================================================ -// Operation Deserializers -// ============================================================================ - -/** - * Read transfer_operation (ID: 2) - */ -function readTransferOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - amount: readAsset(reader), - memo: reader.readString() - }; -} - -/** - * Read account_create_operation (ID: 20) - */ -function readAccountCreateOperation(reader) { - return { - fee: readAsset(reader), - delegation: readAsset(reader), - creator: readAccountName(reader), - new_account_name: readAccountName(reader), - master: readAuthority(reader), - active: readAuthority(reader), - regular: readAuthority(reader), - memo_key: readPublicKey(reader), - json_metadata: reader.readString(), - referrer: readAccountName(reader), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read witness_update_operation (ID: 6) - */ -function readWitnessUpdateOperation(reader) { - return { - owner: readAccountName(reader), - url: reader.readString(), - block_signing_key: readPublicKey(reader) - }; -} - -/** - * Read award_operation (ID: 47) - */ -function readAwardOperation(reader) { - return { - initiator: readAccountName(reader), - receiver: readAccountName(reader), - energy: reader.readUint16LE(), - custom_sequence: Number(reader.readUint64LE()), - memo: reader.readString(), - beneficiaries: reader.readVector(readBeneficiaryRoute) - }; -} - -/** - * Read transfer_to_vesting_operation (ID: 3) - */ -function readTransferToVestingOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - amount: readAsset(reader) - }; -} - -/** - * Read delegate_vesting_shares_operation (ID: 19) - */ -function readDelegateVestingSharesOperation(reader) { - return { - delegator: readAccountName(reader), - delegatee: readAccountName(reader), - vesting_shares: readAsset(reader) - }; -} - -/** - * Read create_invite_operation (ID: 43) - */ -function readCreateInviteOperation(reader) { - return { - creator: readAccountName(reader), - balance: readAsset(reader), - invite_key: readPublicKey(reader) - }; -} - -/** - * Read custom_operation (ID: 10) - */ -function readCustomOperation(reader) { - return { - required_active_auths: reader.readVector(readAccountName), - required_regular_auths: reader.readVector(readAccountName), - id: reader.readString(), - json: reader.readString() - }; -} - -/** - * Read author_reward_operation (ID: 26) - virtual - */ -function readAuthorRewardOperation(reader) { - return { - author: readAccountName(reader), - permlink: reader.readString(), - token_payout: readAsset(reader), - vesting_payout: readAsset(reader) - }; -} - -/** - * Read witness_reward_operation (ID: 42) - virtual - */ -function readWitnessRewardOperation(reader) { - return { - witness: readAccountName(reader), - shares: readAsset(reader) - }; -} - -/** - * Read account_update_operation (ID: 5) - */ -function readAccountUpdateOperation(reader) { - return { - account: readAccountName(reader), - master: reader.readOptional(readAuthority), - active: reader.readOptional(readAuthority), - regular: reader.readOptional(readAuthority), - memo_key: readPublicKey(reader), - json_metadata: reader.readString() - }; -} - -/** - * Read withdraw_vesting_operation (ID: 4) - */ -function readWithdrawVestingOperation(reader) { - return { - account: readAccountName(reader), - vesting_shares: readAsset(reader) - }; -} - -// ============================================================================ -// Missing operation readers — must advance reader past all fields correctly -// to prevent stream corruption. Field order from FC_REFLECT in C++ source. -// ============================================================================ - -/** - * Read vote_operation (ID: 0) - deprecated but still in blocks - * Fields: voter, author, permlink, weight - */ -function readVoteOperation(reader) { - return { - voter: readAccountName(reader), - author: readAccountName(reader), - permlink: reader.readString(), - weight: reader.readUint16LE() | 0 - }; -} - -/** - * Read content_operation (ID: 1) - deprecated - * Fields: parent_author, parent_permlink, author, permlink, title, body, curation_percent, json_metadata, extensions - */ -function readContentOperation(reader) { - return { - parent_author: readAccountName(reader), - parent_permlink: reader.readString(), - author: readAccountName(reader), - permlink: reader.readString(), - title: reader.readString(), - body: reader.readString(), - curation_percent: reader.readUint16LE(), - json_metadata: reader.readString(), - extensions: reader.readVector(readContentExtension) - }; -} - -/** - * Read content_extension (static_variant for content_operation extensions) - */ -function readContentExtension(reader) { - const typeIndex = Number(reader.readVarint()); - switch (typeIndex) { - case 0: { - // content_payout_beneficiaries - const beneficiaries = reader.readVector(readBeneficiaryRoute); - return { typeIndex, name: 'content_payout_beneficiaries', data: { beneficiaries } }; - } - default: - return { typeIndex, name: 'unknown_content_extension', data: {} }; - } -} - -/** - * Read account_witness_vote_operation (ID: 7) - * Fields: account, witness, approve - */ -function readAccountWitnessVoteOperation(reader) { - return { - account: readAccountName(reader), - witness: readAccountName(reader), - approve: reader.readUint8() !== 0 - }; -} - -/** - * Read account_witness_proxy_operation (ID: 8) - * Fields: account, proxy - */ -function readAccountWitnessProxyOperation(reader) { - return { - account: readAccountName(reader), - proxy: readAccountName(reader) - }; -} - -/** - * Read delete_content_operation (ID: 9) - deprecated - * Fields: author, permlink - */ -function readDeleteContentOperation(reader) { - return { - author: readAccountName(reader), - permlink: reader.readString() - }; -} - -/** - * Read set_withdraw_vesting_route_operation (ID: 11) - * Fields: from_account, to_account, percent, auto_vest - */ -function readSetWithdrawVestingRouteOperation(reader) { - return { - from_account: readAccountName(reader), - to_account: readAccountName(reader), - percent: reader.readUint16LE(), - auto_vest: reader.readUint8() !== 0 - }; -} - -/** - * Read request_account_recovery_operation (ID: 12) - * Fields: recovery_account, account_to_recover, new_master_authority, extensions - */ -function readRequestAccountRecoveryOperation(reader) { - return { - recovery_account: readAccountName(reader), - account_to_recover: readAccountName(reader), - new_master_authority: readAuthority(reader), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read recover_account_operation (ID: 13) - * Fields: account_to_recover, new_master_authority, recent_master_authority, extensions - */ -function readRecoverAccountOperation(reader) { - return { - account_to_recover: readAccountName(reader), - new_master_authority: readAuthority(reader), - recent_master_authority: readAuthority(reader), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read change_recovery_account_operation (ID: 14) - * Fields: account_to_recover, new_recovery_account, extensions - */ -function readChangeRecoveryAccountOperation(reader) { - return { - account_to_recover: readAccountName(reader), - new_recovery_account: readAccountName(reader), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read escrow_transfer_operation (ID: 15) - * Fields: from, to, token_amount, escrow_id, agent, fee, json_metadata, ratification_deadline, escrow_expiration - */ -function readEscrowTransferOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - token_amount: readAsset(reader), - escrow_id: reader.readUint32LE(), - agent: readAccountName(reader), - fee: readAsset(reader), - json_metadata: reader.readString(), - ratification_deadline: readTimePointSec(reader), - escrow_expiration: readTimePointSec(reader) - }; -} - -/** - * Read escrow_dispute_operation (ID: 16) - * Fields: from, to, agent, who, escrow_id - */ -function readEscrowDisputeOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - agent: readAccountName(reader), - who: readAccountName(reader), - escrow_id: reader.readUint32LE() - }; -} - -/** - * Read escrow_release_operation (ID: 17) - * Fields: from, to, agent, who, receiver, escrow_id, token_amount - */ -function readEscrowReleaseOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - agent: readAccountName(reader), - who: readAccountName(reader), - receiver: readAccountName(reader), - escrow_id: reader.readUint32LE(), - token_amount: readAsset(reader) - }; -} - -/** - * Read escrow_approve_operation (ID: 18) - * Fields: from, to, agent, who, escrow_id, approve - */ -function readEscrowApproveOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - agent: readAccountName(reader), - who: readAccountName(reader), - escrow_id: reader.readUint32LE(), - approve: reader.readUint8() !== 0 - }; -} - -/** - * Read account_metadata_operation (ID: 21) - * Fields: account, json_metadata - */ -function readAccountMetadataOperation(reader) { - return { - account: readAccountName(reader), - json_metadata: reader.readString() - }; -} - -/** - * Read proposal_create_operation (ID: 22) - * Fields: author, title, memo, expiration_time, proposed_operations, review_period_time, extensions - */ -function readProposalCreateOperation(reader) { - return { - author: readAccountName(reader), - title: reader.readString(), - memo: reader.readString(), - expiration_time: readTimePointSec(reader), - proposed_operations: reader.readVector(readOperationWrapper), - review_period_time: reader.readOptional(readTimePointSec), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read operation_wrapper (just wraps an operation) - */ -function readOperationWrapper(reader) { - return { op: readOperation(reader) }; -} - -/** - * Read proposal_update_operation (ID: 23) - * Fields: author, title, active_approvals_to_add, active_approvals_to_remove, - * master_approvals_to_add, master_approvals_to_remove, - * regular_approvals_to_add, regular_approvals_to_remove, - * key_approvals_to_add, key_approvals_to_remove, extensions - */ -function readProposalUpdateOperation(reader) { - return { - author: readAccountName(reader), - title: reader.readString(), - active_approvals_to_add: reader.readVector(readAccountName), - active_approvals_to_remove: reader.readVector(readAccountName), - master_approvals_to_add: reader.readVector(readAccountName), - master_approvals_to_remove: reader.readVector(readAccountName), - regular_approvals_to_add: reader.readVector(readAccountName), - regular_approvals_to_remove: reader.readVector(readAccountName), - key_approvals_to_add: reader.readVector(readPublicKey), - key_approvals_to_remove: reader.readVector(readPublicKey), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read proposal_delete_operation (ID: 24) - * FC_REFLECT: (author)(title)(requester)(extensions) - */ -function readProposalDeleteOperation(reader) { - return { - author: readAccountName(reader), - title: reader.readString(), - requester: readAccountName(reader), - extensions: reader.readVector(() => reader.readVarint()) - }; -} - -/** - * Read chain_properties_update_operation (ID: 25) - * Fields: owner, props - */ -function readChainPropertiesUpdateOperation(reader) { - return { - owner: readAccountName(reader), - props: readChainPropertiesInit(reader) - }; -} - -/** - * Read chain_properties_init (used by chain_properties_update_operation) - * FC_REFLECT: (account_creation_fee)(maximum_block_size)(create_account_delegation_ratio) - * (create_account_delegation_time)(min_delegation)(min_curation_percent)(max_curation_percent) - * (bandwidth_reserve_percent)(bandwidth_reserve_below)(flag_energy_additional_cost) - * (vote_accounting_min_rshares)(committee_request_approve_min_percent) - */ -function readChainPropertiesInit(reader) { - return { - account_creation_fee: readAsset(reader), - maximum_block_size: reader.readUint32LE(), - create_account_delegation_ratio: reader.readUint32LE(), - create_account_delegation_time: reader.readUint32LE(), - min_delegation: readAsset(reader), - min_curation_percent: reader.readUint16LE() | 0, - max_curation_percent: reader.readUint16LE() | 0, - bandwidth_reserve_percent: reader.readUint16LE() | 0, - bandwidth_reserve_below: readAsset(reader), - flag_energy_additional_cost: reader.readUint16LE() | 0, - vote_accounting_min_rshares: reader.readUint32LE(), - committee_request_approve_min_percent: reader.readUint16LE() | 0 - }; -} - -/** - * Read versioned_chain_properties (static_variant of chain_properties_init/hf4/hf6/hf9) - * Used by versioned_chain_properties_update_operation. - * FC_REFLECT_DERIVED means each variant includes all base fields + its own. - */ -function readVersionedChainProperties(reader) { - const typeIndex = Number(reader.readVarint()); - const init = readChainPropertiesInit(reader); - - if (typeIndex === 0) { - // chain_properties_init — no additional fields - return { _type: 'chain_properties_init', ...init }; - } - - // chain_properties_hf4 = init + 3 fields - init.inflation_witness_percent = reader.readUint16LE() | 0; - init.inflation_ratio_committee_vs_reward_fund = reader.readUint16LE() | 0; - init.inflation_recalc_period = reader.readUint32LE(); - - if (typeIndex === 1) { - return { _type: 'chain_properties_hf4', ...init }; - } - - // chain_properties_hf6 = hf4 + 3 fields - init.data_operations_cost_additional_bandwidth = reader.readUint32LE(); - init.witness_miss_penalty_percent = reader.readUint16LE() | 0; - init.witness_miss_penalty_duration = reader.readUint32LE(); - - if (typeIndex === 2) { - return { _type: 'chain_properties_hf6', ...init }; - } - - // chain_properties_hf9 = hf6 + 7 fields - init.create_invite_min_balance = readAsset(reader); - init.committee_create_request_fee = readAsset(reader); - init.create_paid_subscription_fee = readAsset(reader); - init.account_on_sale_fee = readAsset(reader); - init.subaccount_on_sale_fee = readAsset(reader); - init.witness_declaration_fee = readAsset(reader); - init.withdraw_intervals = reader.readUint16LE(); - - return { _type: 'chain_properties_hf9', ...init }; -} - -// ---- Virtual operations (ID: 27-34, 38-41, 48-49, 52-53, 57, 59, 62-63) ---- - -/** - * Read curation_reward_operation (ID: 27) - virtual - * Fields: curator, reward, content_author, content_permlink - */ -function readCurationRewardOperation(reader) { - return { - curator: readAccountName(reader), - reward: readAsset(reader), - content_author: readAccountName(reader), - content_permlink: reader.readString() - }; -} - -/** - * Read content_reward_operation (ID: 28) - virtual - * Fields: author, permlink, payout - */ -function readContentRewardOperation(reader) { - return { - author: readAccountName(reader), - permlink: reader.readString(), - payout: readAsset(reader) - }; -} - -/** - * Read fill_vesting_withdraw_operation (ID: 29) - virtual - * Fields: from_account, to_account, withdrawn, deposited - */ -function readFillVestingWithdrawOperation(reader) { - return { - from_account: readAccountName(reader), - to_account: readAccountName(reader), - withdrawn: readAsset(reader), - deposited: readAsset(reader) - }; -} - -/** - * Read shutdown_witness_operation (ID: 30) - virtual - * Fields: owner - */ -function readShutdownWitnessOperation(reader) { - return { - owner: readAccountName(reader) - }; -} - -/** - * Read hardfork_operation (ID: 31) - virtual - * Fields: hardfork_id - */ -function readHardforkOperation(reader) { - return { - hardfork_id: reader.readUint32LE() - }; -} - -/** - * Read content_payout_update_operation (ID: 32) - virtual - * Fields: author, permlink - */ -function readContentPayoutUpdateOperation(reader) { - return { - author: readAccountName(reader), - permlink: reader.readString() - }; -} - -/** - * Read content_benefactor_reward_operation (ID: 33) - virtual - * Fields: benefactor, author, permlink, reward - */ -function readContentBenefactorRewardOperation(reader) { - return { - benefactor: readAccountName(reader), - author: readAccountName(reader), - permlink: reader.readString(), - reward: readAsset(reader) - }; -} - -/** - * Read return_vesting_delegation_operation (ID: 34) - virtual - * Fields: account, vesting_shares - */ -function readReturnVestingDelegationOperation(reader) { - return { - account: readAccountName(reader), - vesting_shares: readAsset(reader) - }; -} - -/** - * Read committee_worker_create_request_operation (ID: 35) - * Fields: creator, url, worker, required_amount_min, required_amount_max, duration - */ -function readCommitteeWorkerCreateRequestOperation(reader) { - return { - creator: readAccountName(reader), - url: reader.readString(), - worker: readAccountName(reader), - required_amount_min: readAsset(reader), - required_amount_max: readAsset(reader), - duration: reader.readUint32LE() - }; -} - -/** - * Read committee_worker_cancel_request_operation (ID: 36) - * Fields: creator, request_id - */ -function readCommitteeWorkerCancelRequestOperation(reader) { - return { - creator: readAccountName(reader), - request_id: reader.readUint32LE() - }; -} - -/** - * Read committee_vote_request_operation (ID: 37) - * Fields: voter, request_id, vote_percent - */ -function readCommitteeVoteRequestOperation(reader) { - return { - voter: readAccountName(reader), - request_id: reader.readUint32LE(), - vote_percent: reader.readUint16LE() | 0 - }; -} - -/** - * Read committee_cancel_request_operation (ID: 38) - virtual - * Fields: request_id - */ -function readCommitteeCancelRequestOperation(reader) { - return { - request_id: reader.readUint32LE() - }; -} - -/** - * Read committee_approve_request_operation (ID: 39) - virtual - * Fields: request_id - */ -function readCommitteeApproveRequestOperation(reader) { - return { - request_id: reader.readUint32LE() - }; -} - -/** - * Read committee_payout_request_operation (ID: 40) - virtual - * Fields: request_id - */ -function readCommitteePayoutRequestOperation(reader) { - return { - request_id: reader.readUint32LE() - }; -} - -/** - * Read committee_pay_request_operation (ID: 41) - virtual - * Fields: worker, request_id, tokens - */ -function readCommitteePayRequestOperation(reader) { - return { - worker: readAccountName(reader), - request_id: reader.readUint32LE(), - tokens: readAsset(reader) - }; -} - -/** - * Read claim_invite_balance_operation (ID: 44) - * Fields: initiator, receiver, invite_secret - */ -function readClaimInviteBalanceOperation(reader) { - return { - initiator: readAccountName(reader), - receiver: readAccountName(reader), - invite_secret: reader.readString() // WIF-encoded private key string - }; -} - -/** - * Read invite_registration_operation (ID: 45) - * Fields: initiator, new_account_name, invite_secret, new_account_key - */ -function readInviteRegistrationOperation(reader) { - return { - initiator: readAccountName(reader), - new_account_name: readAccountName(reader), - invite_secret: reader.readString(), // WIF-encoded private key string - new_account_key: readPublicKey(reader) - }; -} - -/** - * Read versioned_chain_properties_update_operation (ID: 46) - * Fields: owner, props - */ -function readVersionedChainPropertiesUpdateOperation(reader) { - return { - owner: readAccountName(reader), - props: readVersionedChainProperties(reader) - }; -} - -/** - * Read receive_award_operation (ID: 48) - virtual - * Fields: initiator, receiver, custom_sequence, memo, shares - */ -function readReceiveAwardOperation(reader) { - return { - initiator: readAccountName(reader), - receiver: readAccountName(reader), - custom_sequence: Number(reader.readUint64LE()), - memo: reader.readString(), - shares: readAsset(reader) - }; -} - -/** - * Read benefactor_award_operation (ID: 49) - virtual - * Fields: same as award but for benefactor - */ -function readBenefactorAwardOperation(reader) { - return { - initiator: readAccountName(reader), - benefactor: readAccountName(reader), - receiver: readAccountName(reader), - custom_sequence: Number(reader.readUint64LE()), - memo: reader.readString(), - shares: readAsset(reader) - }; -} - -/** - * Read set_paid_subscription_operation (ID: 50) - * Fields: account, url, levels, amount, period - */ -function readSetPaidSubscriptionOperation(reader) { - return { - account: readAccountName(reader), - url: reader.readString(), - levels: reader.readUint16LE(), - amount: readAsset(reader), - period: reader.readUint16LE() - }; -} - -/** - * Read paid_subscribe_operation (ID: 51) - * Fields: subscriber, account, level, amount, period, auto_renewal - */ -function readPaidSubscribeOperation(reader) { - return { - subscriber: readAccountName(reader), - account: readAccountName(reader), - level: reader.readUint16LE(), - amount: readAsset(reader), - period: reader.readUint16LE(), - auto_renewal: reader.readUint8() !== 0 - }; -} - -/** - * Read paid_subscription_action_operation (ID: 52) - virtual - * FC_REFLECT: (subscriber)(account)(level)(amount)(period)(summary_duration_sec)(summary_amount) - */ -function readPaidSubscriptionActionOperation(reader) { - return { - subscriber: readAccountName(reader), - account: readAccountName(reader), - level: reader.readUint16LE(), - amount: readAsset(reader), - period: reader.readUint16LE(), - summary_duration_sec: Number(reader.readUint64LE()), - summary_amount: readAsset(reader) - }; -} - -/** - * Read cancel_paid_subscription_operation (ID: 53) - virtual - * FC_REFLECT: (subscriber)(account) - */ -function readCancelPaidSubscriptionOperation(reader) { - return { - subscriber: readAccountName(reader), - account: readAccountName(reader) - }; -} - -/** - * Read set_account_price_operation (ID: 54) - * Fields: account, account_seller, account_offer_price, account_on_sale - */ -function readSetAccountPriceOperation(reader) { - return { - account: readAccountName(reader), - account_seller: readAccountName(reader), - account_offer_price: readAsset(reader), - account_on_sale: reader.readUint8() !== 0 - }; -} - -/** - * Read set_subaccount_price_operation (ID: 55) - * Fields: account, subaccount_seller, subaccount_offer_price, subaccount_on_sale - */ -function readSetSubaccountPriceOperation(reader) { - return { - account: readAccountName(reader), - subaccount_seller: readAccountName(reader), - subaccount_offer_price: readAsset(reader), - subaccount_on_sale: reader.readUint8() !== 0 - }; -} - -/** - * Read buy_account_operation (ID: 56) - * Fields: buyer, account, account_offer_price, account_authorities_key, tokens_to_shares - */ -function readBuyAccountOperation(reader) { - return { - buyer: readAccountName(reader), - account: readAccountName(reader), - account_offer_price: readAsset(reader), - account_authorities_key: readPublicKey(reader), - tokens_to_shares: readAsset(reader) - }; -} - -/** - * Read account_sale_operation (ID: 57) - virtual - */ -function readAccountSaleOperation(reader) { - return { - account: readAccountName(reader), - price: readAsset(reader), - buyer: readAccountName(reader), - seller: readAccountName(reader) - }; -} - -/** - * Read use_invite_balance_operation (ID: 58) - * Fields: initiator, receiver, invite_secret - */ -function readUseInviteBalanceOperation(reader) { - return { - initiator: readAccountName(reader), - receiver: readAccountName(reader), - invite_secret: reader.readString() // WIF-encoded private key string - }; -} - -/** - * Read expire_escrow_ratification_operation (ID: 59) - virtual - */ -function readExpireEscrowRatificationOperation(reader) { - return { - from: readAccountName(reader), - to: readAccountName(reader), - agent: readAccountName(reader), - escrow_id: reader.readUint32LE(), - token_amount: readAsset(reader), - fee: readAsset(reader), - ratification_deadline: readTimePointSec(reader) - }; -} - -/** - * Read fixed_award_operation (ID: 60) - * Fields: initiator, receiver, reward_amount, max_energy, custom_sequence, memo, beneficiaries - */ -function readFixedAwardOperation(reader) { - return { - initiator: readAccountName(reader), - receiver: readAccountName(reader), - reward_amount: readAsset(reader), - max_energy: reader.readUint16LE(), - custom_sequence: Number(reader.readUint64LE()), - memo: reader.readString(), - beneficiaries: reader.readVector(readBeneficiaryRoute) - }; -} - -/** - * Read target_account_sale_operation (ID: 61) - * Fields: account, account_seller, target_buyer, account_offer_price, account_on_sale - */ -function readTargetAccountSaleOperation(reader) { - return { - account: readAccountName(reader), - account_seller: readAccountName(reader), - target_buyer: readAccountName(reader), - account_offer_price: readAsset(reader), - account_on_sale: reader.readUint8() !== 0 - }; -} - -/** - * Read bid_operation (ID: 62) - virtual - */ -function readBidOperation(reader) { - return { - account: readAccountName(reader), - bidder: readAccountName(reader), - bid: readAsset(reader) - }; -} - -/** - * Read outbid_operation (ID: 63) - virtual - */ -function readOutbidOperation(reader) { - return { - account: readAccountName(reader), - bidder: readAccountName(reader), - bid: readAsset(reader) - }; -} - -// Operation deserializer registry -const OPERATION_READERS = { - 0: readVoteOperation, - 1: readContentOperation, - 2: readTransferOperation, - 3: readTransferToVestingOperation, - 4: readWithdrawVestingOperation, - 5: readAccountUpdateOperation, - 6: readWitnessUpdateOperation, - 7: readAccountWitnessVoteOperation, - 8: readAccountWitnessProxyOperation, - 9: readDeleteContentOperation, - 10: readCustomOperation, - 11: readSetWithdrawVestingRouteOperation, - 12: readRequestAccountRecoveryOperation, - 13: readRecoverAccountOperation, - 14: readChangeRecoveryAccountOperation, - 15: readEscrowTransferOperation, - 16: readEscrowDisputeOperation, - 17: readEscrowReleaseOperation, - 18: readEscrowApproveOperation, - 19: readDelegateVestingSharesOperation, - 20: readAccountCreateOperation, - 21: readAccountMetadataOperation, - 22: readProposalCreateOperation, - 23: readProposalUpdateOperation, - 24: readProposalDeleteOperation, - 25: readChainPropertiesUpdateOperation, - 26: readAuthorRewardOperation, - 27: readCurationRewardOperation, - 28: readContentRewardOperation, - 29: readFillVestingWithdrawOperation, - 30: readShutdownWitnessOperation, - 31: readHardforkOperation, - 32: readContentPayoutUpdateOperation, - 33: readContentBenefactorRewardOperation, - 34: readReturnVestingDelegationOperation, - 35: readCommitteeWorkerCreateRequestOperation, - 36: readCommitteeWorkerCancelRequestOperation, - 37: readCommitteeVoteRequestOperation, - 38: readCommitteeCancelRequestOperation, - 39: readCommitteeApproveRequestOperation, - 40: readCommitteePayoutRequestOperation, - 41: readCommitteePayRequestOperation, - 42: readWitnessRewardOperation, - 43: readCreateInviteOperation, - 44: readClaimInviteBalanceOperation, - 45: readInviteRegistrationOperation, - 46: readVersionedChainPropertiesUpdateOperation, - 47: readAwardOperation, - 48: readReceiveAwardOperation, - 49: readBenefactorAwardOperation, - 50: readSetPaidSubscriptionOperation, - 51: readPaidSubscribeOperation, - 52: readPaidSubscriptionActionOperation, - 53: readCancelPaidSubscriptionOperation, - 54: readSetAccountPriceOperation, - 55: readSetSubaccountPriceOperation, - 56: readBuyAccountOperation, - 57: readAccountSaleOperation, - 58: readUseInviteBalanceOperation, - 59: readExpireEscrowRatificationOperation, - 60: readFixedAwardOperation, - 61: readTargetAccountSaleOperation, - 62: readBidOperation, - 63: readOutbidOperation -}; - -/** - * Read operation (static_variant) - * Fully deserializes known operations, returns raw data for unknown ones - */ -function readOperation(reader) { - const typeIndex = Number(reader.readVarint()); - if (typeIndex > 1000) { - throw new Error(`readOperation: typeIndex ${typeIndex} exceeds safety cap (offset ${reader.offset})`); - } - const typeInfo = OPERATION_TYPES[typeIndex] || { name: 'unknown_operation', isVirtual: false }; - const opReader = OPERATION_READERS[typeIndex]; - - let data; - const opStartOffset = reader.offset; - if (opReader) { - try { - data = opReader(reader); - } catch (e) { - const bytesRead = reader.offset - opStartOffset; - console.error(` readOperation ERROR: type=${typeIndex}(${typeInfo.name}) offset=${opStartOffset} bytesRead=${bytesRead} err=${e.message}`); - throw e; - } - } else { - // Unknown operation - can't skip without schema, deserialization will likely fail - console.error(` readOperation: unknown type ${typeIndex} at offset ${opStartOffset}, stream will be corrupted`); - data = { _raw: `unknown operation type ${typeIndex}` }; - } - - // Log per-operation byte consumption when verbose debug is enabled - if (global.__BLR_VERBOSE_OPS__) { - const bytesRead = reader.offset - opStartOffset; - process.stderr.write(` op[${typeIndex}]=${typeInfo.name} @${opStartOffset} +${bytesRead}B\n`); - } - - return { - typeId: typeIndex, - typeName: typeInfo.name, - isVirtual: typeInfo.isVirtual, - data - }; -} - -/** - * Read transaction - */ -function readTransaction(reader) { - return { - ref_block_num: reader.readUint16LE(), - ref_block_prefix: reader.readUint32LE(), - expiration: readTimePointSec(reader), - operations: reader.readVector(readOperation), - extensions: reader.readVector(() => reader.readVarint()) // extensions_type is empty vector - }; -} - -/** - * Read signed_transaction - */ -function readSignedTransaction(reader) { - const trx = readTransaction(reader); - return { - ...trx, - signatures: reader.readVector(readCompactSignature) - }; -} - -/** - * Read signed_block - */ -function readSignedBlock(reader) { - const startOffset = reader.offset; - const header = readSignedBlockHeader(reader); - const headerEndOffset = reader.offset; - let transactions; - try { - const txCount = Number(reader.readVarint()); - if (txCount > 100000) { - throw new Error(`readSignedBlock: tx count ${txCount} exceeds safety cap (offset ${reader.offset})`); - } - const items = []; - for (let i = 0; i < txCount; i++) { - const txStartOffset = reader.offset; - try { - items.push(readSignedTransaction(reader)); - } catch (e) { - console.error(` readSignedBlock: tx[${i}] FAILED at offset ${txStartOffset} (headerEnd=${headerEndOffset}) err=${e.message}`); - throw e; - } - } - transactions = items; - } catch (e) { - console.error(` readSignedBlock ERROR at offset ${startOffset}: headerEnd=${headerEndOffset} err=${e.message}`); - throw e; - } - return { - ...header, - transactions - }; -} - -// ============================================================================ -// Block Number Utilities -// ============================================================================ - -/** - * Extract block number from block_id_type (ripemd160 hash) - * The block number is stored in the first 4 bytes. - * C++ uses fc::endian_reverse_u32 which reads as big-endian uint32. - */ -function numFromId(blockId) { - if (!blockId || blockId.length < 4) return 0; - return blockId.readUInt32BE(0); -} - -/** - * Get block number from signed_block - */ -function getBlockNum(block) { - return numFromId(block.previous) + 1; -} - -/** - * Convert block ID to hex string - */ -function blockIdToHex(blockId) { - return blockId.toString('hex'); -} - -// ============================================================================ -// Block Log Reader -// ============================================================================ - -/** - * Block Log Reader for standard block_log files - */ -class BlockLogReader { - constructor() { - this.dataFd = null; - this.indexFd = null; - this.dataPath = null; - this.indexPath = null; - this.dataSize = 0n; - this.indexSize = 0n; - this._headBlock = null; - this._headBlockNum = 0; - } - - /** - * Open block log files - * @param {string} dataPath - Path to block_log file - * @param {string} [indexPath] - Path to block_log.index file (auto-derived if not provided) - */ - open(dataPath, indexPath) { - this.dataPath = dataPath; - this.indexPath = indexPath || (dataPath + '.index'); - - // Open data file - this.dataFd = fs.openSync(this.dataPath, 'r'); - const dataStats = fs.fstatSync(this.dataFd); - this.dataSize = BigInt(dataStats.size); - - // Open index file - this.indexFd = fs.openSync(this.indexPath, 'r'); - const indexStats = fs.fstatSync(this.indexFd); - this.indexSize = BigInt(indexStats.size); - - // Determine head block number from the index file size. - // Index has 8 bytes per block, starting from block 1 at offset 0. - // head_block_num = index_size / 8 - // This is reliable — we don't need to deserialize the head block for this. - if (this.indexSize >= 8n) { - this._headBlockNum = Number(this.indexSize / 8n); - } - - // Optionally cache the head block (may fail for blocks with unknown ops) - if (this.dataSize > BigInt(CONSTANTS.MIN_VALID_FILE_SIZE)) { - try { - this._headBlock = this.readHead(); - } catch (e) { - this._headBlock = null; - } - } - } - - /** - * Close block log files - */ - close() { - if (this.dataFd !== null) { - fs.closeSync(this.dataFd); - this.dataFd = null; - } - if (this.indexFd !== null) { - fs.closeSync(this.indexFd); - this.indexFd = null; - } - this._headBlock = null; - this._headBlockNum = 0; - } - - /** - * Check if log is open - */ - isOpen() { - return this.dataFd !== null; - } - - /** - * Read bytes from data file - */ - _readData(position, length) { - const buffer = Buffer.allocUnsafe(Number(length)); - fs.readSync(this.dataFd, buffer, 0, Number(length), Number(position)); - return buffer; - } - - /** - * Read bytes from index file - */ - _readIndex(position, length) { - const buffer = Buffer.allocUnsafe(Number(length)); - fs.readSync(this.indexFd, buffer, 0, Number(length), Number(position)); - return buffer; - } - - /** - * Read uint64 from data file - */ - _readDataUint64(position) { - const buffer = this._readData(position, 8); - return buffer.readBigUInt64LE(0); - } - - /** - * Read uint64 from index file - */ - _readIndexUint64(position) { - const buffer = this._readIndex(position, 8); - return buffer.readBigUInt64LE(0); - } - - /** - * Get head block position (last 8 bytes of data file) - */ - _getHeadPosition() { - return this._readDataUint64(this.dataSize - 8n); - } - - /** - * Read block at specified position - * @param {bigint} position - File offset - * @returns {{ block: object, nextPosition: bigint }} - */ - readBlock(position) { - const maxBlockSize = CONSTANTS.CHAIN_BLOCK_SIZE; - const availableSize = Number(this.dataSize - position); - const readSize = Math.min(availableSize, maxBlockSize + 8); - - const buffer = this._readData(position, readSize); - const reader = new BinaryReader(buffer); - - const block = readSignedBlock(reader); - const blockEndPos = reader.getPosition(); - - // Read position marker - const posMarker = buffer.readBigUInt64LE(blockEndPos); - - // Verify position marker matches our read position - if (posMarker !== position) { - throw new Error(`Position mismatch: expected ${position}, got ${posMarker}`); - } - - const nextPosition = blockEndPos + 8; - - return { block, nextPosition }; - } - - /** - * Read head block - */ - readHead() { - if (this._headBlock) return this._headBlock; - - const pos = this._getHeadPosition(); - const result = this.readBlock(pos); - return result.block; - } - - /** - * Get block position from index by block number - * Matches C++ block_log: offset = 8 * (block_num - 1) - * @param {number} blockNum - Block number (1-indexed, matching C++) - * @returns {bigint} Position in data file, or NPOS if out of range - */ - getBlockPos(blockNum) { - if (blockNum < 1 || blockNum > this._headBlockNum) { - return CONSTANTS.NPOS; - } - - const indexOffset = BigInt(blockNum - 1) * 8n; - // Bounds check: index may be incomplete (fewer entries than head block) - if (indexOffset + 8n > this.indexSize) { - return CONSTANTS.NPOS; - } - return this._readIndexUint64(indexOffset); - } - - /** - * Read block by number - * @param {number} blockNum - Block number - * @returns {object|null} Signed block, or null if block_num out of range - * @throws Error if block found but deserialization failed - */ - readBlockByNum(blockNum) { - const pos = this.getBlockPos(blockNum); - if (pos === CONSTANTS.NPOS) return null; - - const result = this.readBlock(pos); - return result.block; - } - - /** - * Read only the block header by number (no transactions/operations). - * Useful when full block deserialization fails due to unknown operation types. - * @param {number} blockNum - Block number - * @returns {object|null} Block header object, or null if out of range - */ - readBlockHeaderByNum(blockNum) { - const pos = this.getBlockPos(blockNum); - if (pos === CONSTANTS.NPOS) return null; - - try { - const maxBlockSize = CONSTANTS.CHAIN_BLOCK_SIZE; - const availableSize = Number(this.dataSize - pos); - const readSize = Math.min(availableSize, maxBlockSize + 8); - - const buffer = this._readData(pos, readSize); - const br = new BinaryReader(buffer); - - // Only read the signed_block_header part - const header = readSignedBlockHeader(br); - return { - ...header, - _blockNum: getBlockNum(header), - _position: Number(pos), - _headerOnly: true - }; - } catch (e) { - return null; - } - } - - /** - * Read raw block bytes by number. - * Uses the index to find block start offset and the next block's offset to determine size. - * Returns the raw data including the trailing 8-byte position marker. - * @param {number} blockNum - Block number - * @returns {Buffer|null} Raw block bytes, or null if out of range - */ - readBlockRawData(blockNum) { - const startPos = this.getBlockPos(blockNum); - if (startPos === CONSTANTS.NPOS) return null; - - let endPos; - // If there's a next block in the index, its offset is our end - const nextPos = this.getBlockPos(blockNum + 1); - if (nextPos !== CONSTANTS.NPOS) { - endPos = Number(nextPos); - } else { - // Last block: read until end of data file minus the final 8-byte head position pointer - endPos = Number(this.dataSize) - 8; - } - - const size = endPos - Number(startPos); - if (size <= 0 || size > CONSTANTS.CHAIN_BLOCK_SIZE + 16) return null; - - return this._readData(startPos, size); - } - - /** - * Read only the transaction count for a block by number. - * Uses exact block size from index (no 1MB over-read) and skips operation deserialization. - * Virtual operations are NOT in block_log transactions, so tx_count > 0 means the block - * has non-free operations. - * @param {number} blockNum - Block number - * @returns {number} Transaction count, or -1 if out of range / error - */ - readBlockTxCountByNum(blockNum) { - const startPos = this.getBlockPos(blockNum); - if (startPos === CONSTANTS.NPOS) return -1; - - // Calculate exact block size from index - let endPos; - const nextPos = this.getBlockPos(blockNum + 1); - if (nextPos !== CONSTANTS.NPOS) { - endPos = Number(nextPos); - } else { - endPos = Number(this.dataSize) - 8; - } - const size = endPos - Number(startPos); - if (size <= 0 || size > CONSTANTS.CHAIN_BLOCK_SIZE + 16) return -1; - - try { - const buffer = this._readData(startPos, size); - const br = new BinaryReader(buffer); - - // Skip past the signed_block_header (we don't need its data) - readSignedBlockHeader(br); - - // The next varint is the transactions vector length - return Number(br.readVarint()); - } catch (e) { - return -1; - } - } - - /** - * Read a batch of block positions from the index file in one I/O operation. - * Much faster than calling getBlockPos() one at a time for sequential scanning. - * @param {number} startBlockNum - First block number - * @param {number} count - Number of positions to read - * @returns {bigint[]} Array of positions, may be shorter than count if near end - */ - readBlockPosBatch(startBlockNum, count) { - if (startBlockNum < 1 || startBlockNum > this._headBlockNum) return []; - - const actualCount = Math.min(count, this._headBlockNum - startBlockNum + 2); // +1 for next-block boundary - const indexOffset = BigInt(startBlockNum - 1) * 8n; - const readBytes = Number(BigInt(actualCount) * 8n); - - if (indexOffset + BigInt(readBytes) > this.indexSize) { - // Trim to available index - const avail = Number((this.indexSize - indexOffset) / 8n); - if (avail <= 0) return []; - return this.readBlockPosBatch(startBlockNum, avail); - } - - const buf = Buffer.alloc(readBytes); - fs.readSync(this.indexFd, buf, 0, readBytes, Number(indexOffset)); - - const positions = []; - for (let i = 0; i < actualCount; i++) { - positions.push(buf.readBigUInt64LE(i * 8)); - } - return positions; - } - - /** - * Get head block number - */ - getHeadBlockNum() { - return this._headBlockNum; - } - - /** - * Get start block number (always 1 for standard block_log, matching C++) - */ - getStartBlockNum() { - return 1; - } - - /** - * Get total number of blocks (based on index entries) - */ - getNumBlocks() { - return Number(this.indexSize / 8n); - } - - /** - * Iterate all blocks sequentially - * @yields {object} Signed block - */ - *iterateBlocks() { - let pos = 0n; - - while (pos < this.dataSize - 8n) { - const result = this.readBlock(pos); - yield result.block; - pos = BigInt(result.nextPosition); - } - } - - /** - * Validate index file against data file - */ - validateIndex() { - const dataHeadPos = this._getHeadPosition(); - const indexHeadPos = this._readIndexUint64(this.indexSize - 8n); - - return dataHeadPos === indexHeadPos; - } -} - -// ============================================================================ -// DLT Block Log Reader -// ============================================================================ - -/** - * Block Log Reader for DLT (rolling) block log files - */ -class DltBlockLogReader extends BlockLogReader { - constructor() { - super(); - this._startBlockNum = 0; - } - - /** - * Open DLT block log files - */ - open(dataPath, indexPath) { - super.open(dataPath, indexPath); - - // Read start_block_num from index header - if (this.indexSize >= BigInt(CONSTANTS.INDEX_HEADER_SIZE)) { - this._startBlockNum = Number(this._readIndexUint64(0n)); - } - } - - /** - * Get block position from index by block number - * @param {number} blockNum - Block number - * @returns {bigint} Position in data file - */ - getBlockPos(blockNum) { - if (this._startBlockNum === 0) return CONSTANTS.NPOS; - - if (blockNum < this._startBlockNum || blockNum > this._headBlockNum) { - return CONSTANTS.NPOS; - } - - const indexOffset = BigInt(CONSTANTS.INDEX_HEADER_SIZE) + BigInt(blockNum - this._startBlockNum) * 8n; - return this._readIndexUint64(indexOffset); - } - - /** - * Get start block number - */ - getStartBlockNum() { - return this._startBlockNum; - } - - /** - * Get total number of blocks - */ - getNumBlocks() { - if (!this._headBlock || this._startBlockNum === 0) return 0; - return this._headBlockNum - this._startBlockNum + 1; - } - - /** - * Validate index file - */ - validateIndex() { - const dataHeadPos = this._getHeadPosition(); - const indexHeadPos = this._readIndexUint64(this.indexSize - 8n); - - return dataHeadPos === indexHeadPos; - } -} - -// ============================================================================ -// Factory Function -// ============================================================================ - -/** - * Create appropriate block log reader based on file type - * @param {string} dataPath - Path to block log data file - * @param {string} [indexPath] - Path to index file (auto-derived if not provided) - * @param {boolean} [isDlt=false] - True for DLT block log - * @returns {BlockLogReader|DltBlockLogReader} - */ -function createBlockLogReader(dataPath, indexPath, isDlt = false) { - const reader = isDlt ? new DltBlockLogReader() : new BlockLogReader(); - reader.open(dataPath, indexPath); - return reader; -} - -// ============================================================================ -// Exports -// ============================================================================ - -module.exports = { - // Constants - CONSTANTS, - OPERATION_TYPES, - - // Classes - BinaryReader, - BlockLogReader, - DltBlockLogReader, - - // Factory - createBlockLogReader, - - // Utilities - numFromId, - getBlockNum, - blockIdToHex, - - // Deserializers - readRipemd160, - readSha256, - readCompactSignature, - readTimePointSec, - readBlockHeader, - readSignedBlockHeader, - readTransaction, - readSignedTransaction, - readSignedBlock, - - // Operation deserializers - readAsset, - readPublicKey, - publicKeyToString, - base58Encode, - readAccountName, - readAuthority, - readBeneficiaryRoute, - readOperation, - readTransferOperation, - readAccountCreateOperation, - readWitnessUpdateOperation, - readAwardOperation, - readTransferToVestingOperation, - readDelegateVestingSharesOperation, - readCreateInviteOperation, - readCustomOperation, - readAuthorRewardOperation, - readWitnessRewardOperation, - readAccountUpdateOperation, - readWithdrawVestingOperation, - OPERATION_READERS -}; diff --git a/.qoder/docs/block-log-spec.json b/.qoder/docs/block-log-spec.json deleted file mode 100644 index d9c0a87252..0000000000 --- a/.qoder/docs/block-log-spec.json +++ /dev/null @@ -1,1182 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "block-log-spec.json", - "title": "VIZ Block Log File Format Specification", - "description": "Machine-readable specification for VIZ blockchain block log files", - "version": "1.1.0", - - "definitions": { - "varint": { - "type": "object", - "description": "Variable-length integer encoding (fc::unsigned_int)", - "properties": { - "type": { "const": "varint" }, - "encoding": { "const": "protobuf-style" }, - "maxBytes": { "const": 5 }, - "description": { - "const": "7 bits per byte, MSB=1 means more bytes follow. Each byte: [7 data bits][1 continuation bit]" - } - } - }, - - "zigzag_varint": { - "type": "object", - "description": "Signed variable-length integer (fc::signed_int)", - "properties": { - "type": { "const": "zigzag_varint" }, - "encoding": { "const": "zigzag + varint" }, - "description": { - "const": "Zigzag encode: (n << 1) ^ (n >> 31), then varint" - } - } - }, - - "uint8": { - "type": "object", - "properties": { - "type": { "const": "uint8" }, - "size": { "const": 1 }, - "endian": { "const": "none" } - } - }, - - "uint16_le": { - "type": "object", - "properties": { - "type": { "const": "uint16" }, - "size": { "const": 2 }, - "endian": { "const": "little" } - } - }, - - "uint32_le": { - "type": "object", - "properties": { - "type": { "const": "uint32" }, - "size": { "const": 4 }, - "endian": { "const": "little" } - } - }, - - "uint64_le": { - "type": "object", - "properties": { - "type": { "const": "uint64" }, - "size": { "const": 8 }, - "endian": { "const": "little" }, - "jsType": { "const": "BigInt" } - } - }, - - "ripemd160": { - "type": "object", - "properties": { - "type": { "const": "ripemd160" }, - "size": { "const": 20 }, - "description": { "const": "20-byte RIPEMD-160 hash" } - } - }, - - "sha256": { - "type": "object", - "properties": { - "type": { "const": "sha256" }, - "size": { "const": 32 }, - "description": { "const": "32-byte SHA-256 hash" } - } - }, - - "compact_signature": { - "type": "object", - "properties": { - "type": { "const": "compact_signature" }, - "size": { "const": 65 }, - "description": { "const": "secp256k1 compact signature: [1 byte recovery id][32 bytes r][32 bytes s]" } - } - }, - - "public_key_type": { - "type": "object", - "description": "secp256k1 compressed public key with base58 string representation", - "properties": { - "type": { "const": "public_key_type" }, - "wire_size": { "const": 33 }, - "wire_format": { "const": "Raw compressed secp256k1 point: [0x02/0x03 prefix][32 bytes x-coordinate]" }, - "string_encoding": { - "type": "object", - "description": "How public_key_type is displayed as a string (not stored on wire)", - "steps": [ - "Compute ripemd160 hash of the 33 raw key bytes", - "Take first 4 bytes of hash as checksum", - "Concatenate: [33 bytes key][4 bytes checksum] = 37 bytes", - "Base58-encode the 37-byte buffer", - "Prepend CHAIN_ADDRESS_PREFIX ('VIZ')" - ], - "example": "VIZ7wMEutJdCfdSKNgVAp17v9uoTqwwkUqn2kwVsJ6zG5XYJcvj81" - } - } - }, - - "flat_set": { - "type": "object", - "description": "fc::raw serialized flat_set (same wire format as vector)", - "properties": { - "type": { "const": "flat_set" }, - "structure": { - "type": "array", - "items": [ - { "$ref": "#/definitions/varint", "description": "Element count" }, - { "type": "object", "description": "Repeated element type (sorted, unique)" } - ] - } - } - }, - - "flat_map": { - "type": "object", - "description": "fc::raw serialized flat_map (same wire format as vector>)", - "properties": { - "type": { "const": "flat_map" }, - "structure": { - "type": "array", - "items": [ - { "$ref": "#/definitions/varint", "description": "Pair count" }, - { "type": "object", "description": "Repeated pair (K then V for each)" } - ] - } - } - }, - - "optional": { - "type": "object", - "description": "fc::raw serialized optional", - "properties": { - "type": { "const": "optional" }, - "structure": { - "type": "array", - "items": [ - { "type": "object", "properties": { "type": { "const": "uint8" }, "description": { "const": "Flag: 0=absent, 1=present" } } }, - { "type": "object", "description": "Value (only if flag=1)" } - ] - } - } - }, - - "extensions_type": { - "type": "object", - "description": "future_extensions type used in operation extensions fields", - "properties": { - "type": { "const": "extensions_type" }, - "definition": { "const": "flat_set" }, - "future_extensions": { "const": "static_variant" }, - "wire_format": { "const": "varint count + [varint type_index=0] for each item" }, - "usual_state": { "const": "Empty (count=0, serialized as single byte 0x00)" } - } - }, - - "time_point_sec": { - "type": "object", - "properties": { - "type": { "const": "time_point_sec" }, - "size": { "const": 4 }, - "description": { "const": "Unix timestamp in seconds (uint32_t)" } - } - }, - - "fc_string": { - "type": "object", - "description": "fc::raw serialized string", - "properties": { - "type": { "const": "fc_string" }, - "structure": { - "type": "array", - "items": [ - { "$ref": "#/definitions/varint", "description": "Length in bytes" }, - { "type": "object", "properties": { "type": { "const": "bytes" }, "encoding": { "const": "utf-8" } } } - ] - } - } - }, - - "fc_vector": { - "type": "object", - "description": "fc::raw serialized vector", - "properties": { - "type": { "const": "fc_vector" }, - "elementType": { "type": "object" }, - "structure": { - "type": "array", - "items": [ - { "$ref": "#/definitions/varint", "description": "Element count" }, - { "type": "object", "description": "Repeated element type" } - ] - } - } - }, - - "block_header": { - "type": "object", - "description": "block_header structure", - "properties": { - "name": { "const": "block_header" }, - "fields": { - "type": "array", - "items": [ - { - "name": "previous", - "type": { "$ref": "#/definitions/ripemd160" }, - "description": "Hash of previous block (block_id_type)" - }, - { - "name": "timestamp", - "type": { "$ref": "#/definitions/time_point_sec" }, - "description": "Block creation time" - }, - { - "name": "witness", - "type": { "$ref": "#/definitions/fc_string" }, - "description": "Witness account name" - }, - { - "name": "transaction_merkle_root", - "type": { "$ref": "#/definitions/ripemd160" }, - "description": "Merkle root of transactions (checksum_type)" - }, - { - "name": "extensions", - "type": { "$ref": "#/definitions/fc_vector" }, - "description": "Block header extensions (usually empty)" - } - ] - } - } - }, - - "signed_block_header": { - "type": "object", - "description": "signed_block_header extends block_header", - "properties": { - "name": { "const": "signed_block_header" }, - "extends": { "$ref": "#/definitions/block_header" }, - "additionalFields": { - "type": "array", - "items": [ - { - "name": "witness_signature", - "type": { "$ref": "#/definitions/compact_signature" }, - "description": "Witness signature" - } - ] - } - } - }, - - "transaction": { - "type": "object", - "description": "transaction structure", - "properties": { - "name": { "const": "transaction" }, - "fields": { - "type": "array", - "items": [ - { - "name": "ref_block_num", - "type": { "$ref": "#/definitions/uint16_le" }, - "description": "Reference block number" - }, - { - "name": "ref_block_prefix", - "type": { "$ref": "#/definitions/uint32_le" }, - "description": "Reference block prefix" - }, - { - "name": "expiration", - "type": { "$ref": "#/definitions/time_point_sec" }, - "description": "Transaction expiration" - }, - { - "name": "operations", - "type": { "$ref": "#/definitions/fc_vector" }, - "description": "List of operations (static_variant)" - }, - { - "name": "extensions", - "type": { "$ref": "#/definitions/fc_vector" }, - "description": "Transaction extensions (usually empty)" - } - ] - } - } - }, - - "signed_transaction": { - "type": "object", - "description": "signed_transaction extends transaction", - "properties": { - "name": { "const": "signed_transaction" }, - "extends": { "$ref": "#/definitions/transaction" }, - "additionalFields": { - "type": "array", - "items": [ - { - "name": "signatures", - "type": { - "type": "object", - "properties": { - "type": { "const": "fc_vector" }, - "elementType": { "$ref": "#/definitions/compact_signature" } - } - }, - "description": "Transaction signatures" - } - ] - } - } - }, - - "signed_block": { - "type": "object", - "description": "signed_block extends signed_block_header", - "properties": { - "name": { "const": "signed_block" }, - "extends": { "$ref": "#/definitions/signed_block_header" }, - "additionalFields": { - "type": "array", - "items": [ - { - "name": "transactions", - "type": { - "type": "object", - "properties": { - "type": { "const": "fc_vector" }, - "elementType": { "$ref": "#/definitions/signed_transaction" } - } - }, - "description": "List of transactions in block" - } - ] - } - } - }, - - "block_log_entry": { - "type": "object", - "description": "Single block entry in block_log", - "properties": { - "name": { "const": "block_log_entry" }, - "structure": { - "type": "array", - "items": [ - { - "name": "block_data", - "type": { "$ref": "#/definitions/signed_block" }, - "description": "Serialized signed_block" - }, - { - "name": "position_marker", - "type": { "$ref": "#/definitions/uint64_le" }, - "description": "Offset of this block's start position in the file" - } - ] - } - } - }, - - "block_log_index_entry": { - "type": "object", - "description": "Entry in block_log.index", - "properties": { - "name": { "const": "block_log_index_entry" }, - "structure": { - "type": "array", - "items": [ - { - "name": "position", - "type": { "$ref": "#/definitions/uint64_le" }, - "description": "File offset of block in block_log" - } - ] - } - } - } - }, - - "file_formats": { - "block_log": { - "description": "Main block data file", - "filename": "block_log", - "structure": { - "type": "sequence", - "description": "Sequence of block_log_entry structures", - "entry": { "$ref": "#/definitions/block_log_entry" } - }, - "features": { - "head_block_position": { - "description": "Last 8 bytes contain position of head block", - "offset": "file_size - 8", - "type": { "$ref": "#/definitions/uint64_le" } - }, - "backward_scan": { - "description": "Can scan backwards by reading position markers", - "method": "Read last 8 bytes for position, seek to position, read block, repeat" - } - }, - "index_file": "block_log.index" - }, - - "block_log_index": { - "description": "Index file for block_log", - "filename": "block_log.index", - "structure": { - "type": "array", - "entry": { "$ref": "#/definitions/block_log_index_entry" }, - "entry_size": 8 - }, - "lookup": { - "description": "Find position of block N", - "formula": "offset = 8 * (N - 1)", - "example": { - "block_1": "offset 0", - "block_2": "offset 8", - "block_1000000": "offset 7999992" - } - }, - "validation": { - "description": "Last entry should match last position in block_log", - "check": "read_last_uint64(block_log) == read_last_uint64(block_log.index)" - } - }, - - "dlt_block_log": { - "description": "DLT rolling block data file (same format as block_log)", - "filename": "dlt_block_log", - "structure": { - "type": "sequence", - "description": "Sequence of block_log_entry structures (starts at arbitrary block number)", - "entry": { "$ref": "#/definitions/block_log_entry" } - }, - "index_file": "dlt_block_log.index", - "notes": [ - "Same binary format as block_log", - "Can start at any block number", - "Supports truncation of old blocks" - ] - }, - - "dlt_block_log_index": { - "description": "Index file for dlt_block_log (offset-aware)", - "filename": "dlt_block_log.index", - "structure": { - "type": "object", - "fields": [ - { - "name": "header", - "offset": 0, - "size": 8, - "type": { "$ref": "#/definitions/uint64_le" }, - "description": "start_block_num - the first block number in this log" - }, - { - "name": "entries", - "offset": 8, - "type": "array", - "entry": { "$ref": "#/definitions/block_log_index_entry" }, - "entry_size": 8, - "description": "Array of block positions" - } - ] - }, - "lookup": { - "description": "Find position of block N", - "formula": "offset = 8 + 8 * (N - start_block_num)", - "prerequisite": "Read header first to get start_block_num", - "example": { - "start_block_num": 10000000, - "block_10000000": "offset 8", - "block_10000001": "offset 16", - "block_10050000": "offset 400008" - } - } - } - }, - - "algorithms": { - "read_head_block": { - "description": "Read the most recent (head) block from block_log or dlt_block_log", - "steps": [ - { "step": 1, "action": "Get file size" }, - { "step": 2, "action": "Seek to position: file_size - 8" }, - { "step": 3, "action": "Read uint64_t position (little-endian)" }, - { "step": 4, "action": "Seek to that position" }, - { "step": 5, "action": "Deserialize signed_block" } - ] - }, - - "read_block_by_number": { - "description": "Read a specific block by number using the index", - "steps": [ - { "step": 1, "action": "Calculate index offset: 8 * (N - 1) for block_log, or 8 + 8 * (N - start_block_num) for dlt_block_log" }, - { "step": 2, "action": "Read uint64_t position from index file" }, - { "step": 3, "action": "Seek to position in data file" }, - { "step": 4, "action": "Deserialize signed_block" } - ] - }, - - "scan_all_blocks": { - "description": "Sequential scan of all blocks", - "steps": [ - { "step": 1, "action": "Start at position 0" }, - { "step": 2, "action": "Deserialize signed_block" }, - { "step": 3, "action": "Read uint64_t position marker (should match current position)" }, - { "step": 4, "action": "Next block at: current_position + block_size + 8" }, - { "step": 5, "action": "Repeat until end of file" } - ] - }, - - "reconstruct_index": { - "description": "Reconstruct index file from data file", - "steps": [ - { "step": 1, "action": "Scan all blocks sequentially" }, - { "step": 2, "action": "Record each block's start position" }, - { "step": 3, "action": "For block_log: write positions array starting at offset 0" }, - { "step": 4, "action": "For dlt_block_log: write start_block_num header (8 bytes), then positions array" } - ] - }, - - "get_block_number": { - "description": "Extract block number from a signed_block", - "method": "block_num = num_from_id(block.previous) + 1", - "num_from_id": { - "description": "Extract block number from block_id_type", - "input": "20-byte ripemd160 hash", - "output": "uint32_t", - "method": "Read first 4 bytes as little-endian uint32_t" - }, - "genesis_block": { - "description": "Genesis block has previous = all zeros", - "block_num": 1 - } - } - }, - - "javascript_types": { - "block_log_reader": { - "description": "TypeScript/JavaScript interface for block log reader", - "interface": { - "name": "BlockLogReader", - "methods": [ - { - "name": "open", - "params": [{ "name": "dataPath", "type": "string" }, { "name": "indexPath", "type": "string" }], - "returns": "void" - }, - { - "name": "close", - "params": [], - "returns": "void" - }, - { - "name": "readBlock", - "params": [{ "name": "position", "type": "bigint" }], - "returns": "{ block: SignedBlock, nextPosition: bigint }" - }, - { - "name": "readBlockByNum", - "params": [{ "name": "blockNum", "type": "number" }], - "returns": "SignedBlock | null" - }, - { - "name": "readHead", - "params": [], - "returns": "SignedBlock" - }, - { - "name": "getHeadBlockNum", - "params": [], - "returns": "number" - }, - { - "name": "getStartBlockNum", - "params": [], - "returns": "number", - "description": "Returns 1 for block_log, or start_block_num for dlt_block_log" - } - ] - } - }, - - "signed_block": { - "description": "TypeScript interface for signed_block", - "interface": { - "name": "SignedBlock", - "extends": "SignedBlockHeader", - "properties": [ - { "name": "transactions", "type": "SignedTransaction[]" } - ] - } - }, - - "signed_block_header": { - "description": "TypeScript interface for signed_block_header", - "interface": { - "name": "SignedBlockHeader", - "extends": "BlockHeader", - "properties": [ - { "name": "witness_signature", "type": "Buffer" } - ] - } - }, - - "block_header": { - "description": "TypeScript interface for block_header", - "interface": { - "name": "BlockHeader", - "properties": [ - { "name": "previous", "type": "Buffer", "size": 20 }, - { "name": "timestamp", "type": "Date" }, - { "name": "witness", "type": "string" }, - { "name": "transaction_merkle_root", "type": "Buffer", "size": 20 }, - { "name": "extensions", "type": "any[]" } - ] - } - }, - - "signed_transaction": { - "description": "TypeScript interface for signed_transaction", - "interface": { - "name": "SignedTransaction", - "extends": "Transaction", - "properties": [ - { "name": "signatures", "type": "Buffer[]" } - ] - } - }, - - "transaction": { - "description": "TypeScript interface for transaction", - "interface": { - "name": "Transaction", - "properties": [ - { "name": "ref_block_num", "type": "number" }, - { "name": "ref_block_prefix", "type": "number" }, - { "name": "expiration", "type": "Date" }, - { "name": "operations", "type": "Operation[]" }, - { "name": "extensions", "type": "any[]" } - ] - } - }, - - "operation": { - "description": "TypeScript interface for operation (static_variant)", - "interface": { - "name": "Operation", - "properties": [ - { "name": "typeId", "type": "number", "description": "Operation type index (0-63)" }, - { "name": "typeName", "type": "string", "description": "Operation name" }, - { "name": "isVirtual", "type": "boolean" }, - { "name": "data", "type": "object", "description": "Operation-specific data" } - ] - } - } - }, - - "operations": { - "description": "VIZ protocol operation definitions", - "serialization": { - "format": "static_variant", - "structure": [ - { "name": "type_index", "type": "varint", "description": "Operation type ID (0-63)" }, - { "name": "operation_data", "type": "operation_specific", "description": "Fields depend on operation type" } - ] - }, - "type_ids": [ - { "id": 0, "name": "vote_operation", "isVirtual": false, "status": "deprecated" }, - { "id": 1, "name": "content_operation", "isVirtual": false, "status": "deprecated" }, - { "id": 2, "name": "transfer_operation", "isVirtual": false, "status": "active" }, - { "id": 3, "name": "transfer_to_vesting_operation", "isVirtual": false, "status": "active" }, - { "id": 4, "name": "withdraw_vesting_operation", "isVirtual": false, "status": "active" }, - { "id": 5, "name": "account_update_operation", "isVirtual": false, "status": "active" }, - { "id": 6, "name": "witness_update_operation", "isVirtual": false, "status": "active" }, - { "id": 7, "name": "account_witness_vote_operation", "isVirtual": false, "status": "active" }, - { "id": 8, "name": "account_witness_proxy_operation", "isVirtual": false, "status": "active" }, - { "id": 9, "name": "delete_content_operation", "isVirtual": false, "status": "deprecated" }, - { "id": 10, "name": "custom_operation", "isVirtual": false, "status": "active" }, - { "id": 11, "name": "set_withdraw_vesting_route_operation", "isVirtual": false, "status": "active" }, - { "id": 12, "name": "request_account_recovery_operation", "isVirtual": false, "status": "active" }, - { "id": 13, "name": "recover_account_operation", "isVirtual": false, "status": "active" }, - { "id": 14, "name": "change_recovery_account_operation", "isVirtual": false, "status": "active" }, - { "id": 15, "name": "escrow_transfer_operation", "isVirtual": false, "status": "active" }, - { "id": 16, "name": "escrow_dispute_operation", "isVirtual": false, "status": "active" }, - { "id": 17, "name": "escrow_release_operation", "isVirtual": false, "status": "active" }, - { "id": 18, "name": "escrow_approve_operation", "isVirtual": false, "status": "active" }, - { "id": 19, "name": "delegate_vesting_shares_operation", "isVirtual": false, "status": "active" }, - { "id": 20, "name": "account_create_operation", "isVirtual": false, "status": "active" }, - { "id": 21, "name": "account_metadata_operation", "isVirtual": false, "status": "active" }, - { "id": 22, "name": "proposal_create_operation", "isVirtual": false, "status": "active" }, - { "id": 23, "name": "proposal_update_operation", "isVirtual": false, "status": "active" }, - { "id": 24, "name": "proposal_delete_operation", "isVirtual": false, "status": "active" }, - { "id": 25, "name": "chain_properties_update_operation", "isVirtual": false, "status": "active" }, - { "id": 26, "name": "author_reward_operation", "isVirtual": true, "status": "active" }, - { "id": 27, "name": "curation_reward_operation", "isVirtual": true, "status": "active" }, - { "id": 28, "name": "content_reward_operation", "isVirtual": true, "status": "active" }, - { "id": 29, "name": "fill_vesting_withdraw_operation", "isVirtual": true, "status": "active" }, - { "id": 30, "name": "shutdown_witness_operation", "isVirtual": true, "status": "active" }, - { "id": 31, "name": "hardfork_operation", "isVirtual": true, "status": "active" }, - { "id": 32, "name": "content_payout_update_operation", "isVirtual": true, "status": "active" }, - { "id": 33, "name": "content_benefactor_reward_operation", "isVirtual": true, "status": "active" }, - { "id": 34, "name": "return_vesting_delegation_operation", "isVirtual": true, "status": "active" }, - { "id": 35, "name": "committee_worker_create_request_operation", "isVirtual": false, "status": "active" }, - { "id": 36, "name": "committee_worker_cancel_request_operation", "isVirtual": false, "status": "active" }, - { "id": 37, "name": "committee_vote_request_operation", "isVirtual": false, "status": "active" }, - { "id": 38, "name": "committee_cancel_request_operation", "isVirtual": true, "status": "active" }, - { "id": 39, "name": "committee_approve_request_operation", "isVirtual": true, "status": "active" }, - { "id": 40, "name": "committee_payout_request_operation", "isVirtual": true, "status": "active" }, - { "id": 41, "name": "committee_pay_request_operation", "isVirtual": true, "status": "active" }, - { "id": 42, "name": "witness_reward_operation", "isVirtual": true, "status": "active" }, - { "id": 43, "name": "create_invite_operation", "isVirtual": false, "status": "active" }, - { "id": 44, "name": "claim_invite_balance_operation", "isVirtual": false, "status": "active" }, - { "id": 45, "name": "invite_registration_operation", "isVirtual": false, "status": "active" }, - { "id": 46, "name": "versioned_chain_properties_update_operation", "isVirtual": false, "status": "active" }, - { "id": 47, "name": "award_operation", "isVirtual": false, "status": "active" }, - { "id": 48, "name": "receive_award_operation", "isVirtual": true, "status": "active" }, - { "id": 49, "name": "benefactor_award_operation", "isVirtual": true, "status": "active" }, - { "id": 50, "name": "set_paid_subscription_operation", "isVirtual": false, "status": "active" }, - { "id": 51, "name": "paid_subscribe_operation", "isVirtual": false, "status": "active" }, - { "id": 52, "name": "paid_subscription_action_operation", "isVirtual": true, "status": "active" }, - { "id": 53, "name": "cancel_paid_subscription_operation", "isVirtual": true, "status": "active" }, - { "id": 54, "name": "set_account_price_operation", "isVirtual": false, "status": "active" }, - { "id": 55, "name": "set_subaccount_price_operation", "isVirtual": false, "status": "active" }, - { "id": 56, "name": "buy_account_operation", "isVirtual": false, "status": "active" }, - { "id": 57, "name": "account_sale_operation", "isVirtual": true, "status": "active" }, - { "id": 58, "name": "use_invite_balance_operation", "isVirtual": false, "status": "active" }, - { "id": 59, "name": "expire_escrow_ratification_operation", "isVirtual": true, "status": "active" }, - { "id": 60, "name": "fixed_award_operation", "isVirtual": false, "status": "active" }, - { "id": 61, "name": "target_account_sale_operation", "isVirtual": false, "status": "active" }, - { "id": 62, "name": "bid_operation", "isVirtual": true, "status": "active" }, - { "id": 63, "name": "outbid_operation", "isVirtual": true, "status": "active" } - ], - "common_types": { - "asset": { - "description": "Token amount with symbol", - "wire_size": "16 bytes (fixed)", - "fields": [ - { "name": "amount", "type": "int64", "size": 8, "description": "Amount in tolikah (signed)" }, - { "name": "symbol", "type": "uint64", "size": 8, "description": "Asset symbol identifier (packed: byte0=decimals, bytes1-6=ASCII name, byte7=0x00)" } - ], - "js_output": "{ amount: number, symbol: string, decimals: number }", - "symbols": { - "VIZ": "0x000000005A495603", - "SHARES": "0x0053455241485306" - } - }, - "authority": { - "description": "Multi-signature authority", - "fields": [ - { "name": "weight_threshold", "type": "uint32" }, - { "name": "account_auths", "type": "flat_map" }, - { "name": "key_auths", "type": "flat_map" } - ] - }, - "public_key_type": { - "description": "secp256k1 compressed public key", - "wire_size": 33, - "wire_format": "Raw bytes: [0x02/0x03 prefix][32 bytes x-coordinate]", - "string_format": "VIZ + base58([33 key bytes][4 ripemd160 checksum bytes])", - "example": "VIZ7wMEutJdCfdSKNgVAp17v9uoTqwwkUqn2kwVsJ6zG5XYJcvj81" - }, - "beneficiary_route_type": { - "description": "Beneficiary route for awards", - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "weight", "type": "uint16" } - ] - }, - "chain_properties_init": { - "description": "Chain properties (12 fields, used by chain_properties_update_operation)", - "fields": [ - { "name": "account_creation_fee", "type": "asset" }, - { "name": "maximum_block_size", "type": "uint32" }, - { "name": "create_account_delegation_ratio", "type": "uint32" }, - { "name": "create_account_delegation_time", "type": "uint32" }, - { "name": "min_delegation", "type": "asset" }, - { "name": "min_curation_percent", "type": "uint16" }, - { "name": "max_curation_percent", "type": "uint16" }, - { "name": "bandwidth_reserve_percent", "type": "uint16" }, - { "name": "bandwidth_reserve_below", "type": "asset" }, - { "name": "flag_energy_additional_cost", "type": "uint16" }, - { "name": "vote_accounting_min_rshares", "type": "uint32" }, - { "name": "committee_request_approve_min_percent", "type": "uint16" } - ] - }, - "versioned_chain_properties": { - "description": "static_variant of chain_properties variants", - "format": "[varint: type_index][chain_properties_init base][additional fields based on type]", - "variants": [ - { "type_index": 0, "name": "chain_properties_init", "fields": 12 }, - { "type_index": 1, "name": "chain_properties_hf4", "base": "init", "additional_fields": ["inflation_witness_percent (uint16)", "inflation_ratio_committee_vs_reward_fund (uint16)", "inflation_recalc_period (uint32)"] }, - { "type_index": 2, "name": "chain_properties_hf6", "base": "hf4", "additional_fields": ["data_operations_cost_additional_bandwidth (uint32)", "witness_miss_penalty_percent (uint16)", "witness_miss_penalty_duration (uint32)"] }, - { "type_index": 3, "name": "chain_properties_hf9", "base": "hf6", "additional_fields": ["create_invite_min_balance (asset)", "committee_create_request_fee (asset)", "create_paid_subscription_fee (asset)", "account_on_sale_fee (asset)", "subaccount_on_sale_fee (asset)", "witness_declaration_fee (asset)", "withdraw_intervals (uint16)"] } - ] - } - }, - "operation_schemas": { - "transfer_operation": { - "id": 2, - "fields": [ - { "name": "from", "type": "account_name_type" }, - { "name": "to", "type": "account_name_type" }, - { "name": "amount", "type": "asset" }, - { "name": "memo", "type": "string" } - ] - }, - "account_create_operation": { - "id": 20, - "fields": [ - { "name": "fee", "type": "asset" }, - { "name": "delegation", "type": "asset" }, - { "name": "creator", "type": "account_name_type" }, - { "name": "new_account_name", "type": "account_name_type" }, - { "name": "master", "type": "authority" }, - { "name": "active", "type": "authority" }, - { "name": "regular", "type": "authority" }, - { "name": "memo_key", "type": "public_key_type" }, - { "name": "json_metadata", "type": "string" }, - { "name": "referrer", "type": "account_name_type" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "witness_update_operation": { - "id": 6, - "fields": [ - { "name": "owner", "type": "account_name_type" }, - { "name": "url", "type": "string" }, - { "name": "block_signing_key", "type": "public_key_type" } - ] - }, - "award_operation": { - "id": 47, - "fields": [ - { "name": "initiator", "type": "account_name_type" }, - { "name": "receiver", "type": "account_name_type" }, - { "name": "energy", "type": "uint16" }, - { "name": "custom_sequence", "type": "uint64" }, - { "name": "memo", "type": "string" }, - { "name": "beneficiaries", "type": "vector" } - ] - }, - "transfer_to_vesting_operation": { - "id": 3, - "fields": [ - { "name": "from", "type": "account_name_type" }, - { "name": "to", "type": "account_name_type" }, - { "name": "amount", "type": "asset" } - ] - }, - "delegate_vesting_shares_operation": { - "id": 19, - "fields": [ - { "name": "delegator", "type": "account_name_type" }, - { "name": "delegatee", "type": "account_name_type" }, - { "name": "vesting_shares", "type": "asset" } - ] - }, - "create_invite_operation": { - "id": 43, - "fields": [ - { "name": "creator", "type": "account_name_type" }, - { "name": "balance", "type": "asset" }, - { "name": "invite_key", "type": "public_key_type" } - ] - }, - "custom_operation": { - "id": 10, - "fields": [ - { "name": "required_active_auths", "type": "flat_set" }, - { "name": "required_regular_auths", "type": "flat_set" }, - { "name": "id", "type": "string" }, - { "name": "json", "type": "string" } - ] - }, - "author_reward_operation": { - "id": 26, - "isVirtual": true, - "fields": [ - { "name": "author", "type": "account_name_type" }, - { "name": "permlink", "type": "string" }, - { "name": "token_payout", "type": "asset" }, - { "name": "vesting_payout", "type": "asset" } - ] - }, - "witness_reward_operation": { - "id": 42, - "isVirtual": true, - "fields": [ - { "name": "witness", "type": "account_name_type" }, - { "name": "shares", "type": "asset" } - ] - }, - "invite_registration_operation": { - "id": 45, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "new_account_key", "type": "public_key_type" }, - { "name": "invite_secret", "type": "string", "description": "WIF-encoded private key (e.g. '5Kd...'), NOT raw bytes" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "claim_invite_balance_operation": { - "id": 44, - "fields": [ - { "name": "initiator", "type": "account_name_type" }, - { "name": "receiver", "type": "account_name_type" }, - { "name": "invite_secret", "type": "string", "description": "WIF-encoded private key string" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "use_invite_balance_operation": { - "id": 58, - "fields": [ - { "name": "initiator", "type": "account_name_type" }, - { "name": "receiver", "type": "account_name_type" }, - { "name": "invite_secret", "type": "string", "description": "WIF-encoded private key string" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "chain_properties_update_operation": { - "id": 25, - "fields": [ - { "name": "owner", "type": "account_name_type" }, - { "name": "props", "type": "chain_properties_init", "description": "12-field struct, NOT chain_properties_hf9" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "versioned_chain_properties_update_operation": { - "id": 46, - "fields": [ - { "name": "owner", "type": "account_name_type" }, - { "name": "props", "type": "versioned_chain_properties", "description": "static_variant with progressive fields" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "benefactor_award_operation": { - "id": 49, - "isVirtual": true, - "fields": [ - { "name": "initiator", "type": "account_name_type" }, - { "name": "benefactor", "type": "account_name_type", "description": "NOTE: FC_REFLECT order is initiator, benefactor (not benefactor, initiator)" }, - { "name": "receiver", "type": "account_name_type" }, - { "name": "custom_sequence", "type": "uint64" }, - { "name": "memo", "type": "string" }, - { "name": "shares", "type": "asset" } - ] - }, - "set_paid_subscription_operation": { - "id": 50, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "url", "type": "string" }, - { "name": "levels", "type": "uint16", "description": "NOT uint8" }, - { "name": "amount", "type": "asset" }, - { "name": "period", "type": "uint16", "description": "NOT uint32" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "paid_subscribe_operation": { - "id": 51, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "subscriber", "type": "account_name_type" }, - { "name": "level", "type": "uint16", "description": "NOT uint8" }, - { "name": "amount", "type": "asset" }, - { "name": "period", "type": "uint16", "description": "NOT uint32" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "paid_subscription_action_operation": { - "id": 52, - "isVirtual": true, - "fields": [ - { "name": "subscriber", "type": "account_name_type" }, - { "name": "account", "type": "account_name_type" }, - { "name": "level", "type": "uint16" }, - { "name": "amount", "type": "asset" }, - { "name": "period", "type": "uint16" }, - { "name": "summary_duration_sec", "type": "uint64" }, - { "name": "summary_amount", "type": "asset" } - ] - }, - "cancel_paid_subscription_operation": { - "id": 53, - "isVirtual": true, - "fields": [ - { "name": "subscriber", "type": "account_name_type" }, - { "name": "account", "type": "account_name_type" } - ] - }, - "buy_account_operation": { - "id": 56, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "buyer", "type": "account_name_type" }, - { "name": "tokens_to_shares", "type": "asset", "description": "NOT bool/uint8" }, - { "name": "extensions", "type": "extensions_type" } - ] - }, - "account_sale_operation": { - "id": 57, - "isVirtual": true, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "price", "type": "asset" }, - { "name": "buyer", "type": "account_name_type" }, - { "name": "seller", "type": "account_name_type" } - ] - }, - "expire_escrow_ratification_operation": { - "id": 59, - "isVirtual": true, - "fields": [ - { "name": "from", "type": "account_name_type" }, - { "name": "to", "type": "account_name_type" }, - { "name": "agent", "type": "account_name_type" }, - { "name": "escrow_id", "type": "uint32" }, - { "name": "token_amount", "type": "asset" }, - { "name": "fee", "type": "asset" }, - { "name": "ratification_deadline", "type": "time_point_sec" } - ] - }, - "bid_operation": { - "id": 62, - "isVirtual": true, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "bidder", "type": "account_name_type", "description": "NOTE: FC_REFLECT order is account, bidder (not bidder, account)" }, - { "name": "bid", "type": "asset" } - ] - }, - "outbid_operation": { - "id": 63, - "isVirtual": true, - "fields": [ - { "name": "account", "type": "account_name_type" }, - { "name": "bidder", "type": "account_name_type", "description": "NOTE: FC_REFLECT order is account, bidder (not bidder, account)" }, - { "name": "bid", "type": "asset" } - ] - }, - "proposal_delete_operation": { - "id": 24, - "fields": [ - { "name": "author", "type": "account_name_type" }, - { "name": "title", "type": "string" }, - { "name": "requester", "type": "account_name_type" }, - { "name": "extensions", "type": "extensions_type" } - ] - } - } - }, - - "file_formats_additional": { - "block_log_bitmask": { - "description": "Bitmask file marking which blocks have non-free operations", - "filename": "block_log.bitmask", - "structure": { - "type": "object", - "fields": [ - { - "name": "header", - "offset": 0, - "size": 16, - "fields": [ - { "name": "start_block_num", "offset": 0, "size": 8, "type": "uint64_le", "description": "First block number in range" }, - { "name": "end_block_num", "offset": 8, "size": 8, "type": "uint64_le", "description": "Last block number in range" } - ] - }, - { - "name": "bit_array", - "offset": 16, - "type": "bit_array", - "description": "1 bit per block, bit=1 means block has non-free operations", - "bit_order": "bit 0 = start_block_num, bit 1 = start_block_num+1, etc.", - "size": "ceil((end - start + 1) / 8) bytes" - } - ] - }, - "example": "10,000,000 blocks = ~1.25 MB bitmask file", - "auto_load": "Loaded on startup if file exists and range matches current block_log" - }, - - "search_export": { - "description": "Export file from 'e' command in block-log-viewer", - "filename_pattern": "search_export_.json", - "format": "JSON array of operation record objects", - "record_fields": [ - { "name": "block", "type": "number", "description": "Block number" }, - { "name": "timestamp", "type": "string", "description": "Formatted UTC timestamp" }, - { "name": "witness", "type": "string", "description": "Witness account name" }, - { "name": "typeId", "type": "number", "description": "Operation type ID (0-63)" }, - { "name": "typeName", "type": "string", "description": "Operation type name" }, - { "name": "isVirtual", "type": "boolean", "description": "Whether this is a virtual operation" }, - { "name": "data", "type": "object", "description": "Operation-specific data (Buffers as hex, BigInts as decimal strings)" } - ] - } - }, - - "viewer_commands": { - "description": "block-log-viewer.js interactive commands", - "navigation": [ - { "cmd": "f", "description": "First block" }, - { "cmd": "l", "description": "Last block" }, - { "cmd": "n", "description": "Next block" }, - { "cmd": "p", "description": "Previous block" }, - { "cmd": "N", "description": "Next block with non-free operations (bitmask-accelerated)" }, - { "cmd": "P", "description": "Prev block with non-free operations (bitmask-accelerated)" }, - { "cmd": "g ", "description": "Go to block #num" }, - { "cmd": "", "description": "Jump to block number directly" } - ], - "operations": [ - { "cmd": "o", "description": "Show all operations in current block" }, - { "cmd": "o ", "description": "Show operations matching type name (e.g. o transfer)" }, - { "cmd": "s ", "description": "Search forward for operation by type name" }, - { "cmd": "S ", "description": "Search forward for substring in any operation's data (incl. virtual)" }, - { "cmd": "S =", "description": "Search forward for exact string match (= prefix for exact, not substring)" }, - { "cmd": "R ", "description": "Fast raw ASCII byte search in block data (no UTF-8/emoji)" }, - { "cmd": "e ", "description": "Export all ops containing string to search_export_.json" }, - { "cmd": "e =", "description": "Export all ops exactly matching string (= prefix for exact match)" }, - { "cmd": "c", "description": "Continue last search (s/S/R/e)" } - ], - "other": [ - { "cmd": "scan", "description": "Scan all blocks, build & save bitmask for fast navigation" }, - { "cmd": "i", "description": "Show block header info" }, - { "cmd": "hex", "description": "Show raw block data in hex" }, - { "cmd": "h", "description": "Help" }, - { "cmd": "q", "description": "Quit" } - ] - }, - - "constants": { - "CHAIN_BLOCK_SIZE": { - "value": 1048576, - "description": "Maximum block size in bytes (1 MB)" - }, - "MIN_VALID_FILE_SIZE": { - "value": 8, - "description": "Minimum valid file size (at least one position marker)" - }, - "INDEX_HEADER_SIZE": { - "value": 8, - "description": "DLT index header size (start_block_num)" - }, - "SIGNATURE_SIZE": { - "value": 65, - "description": "Compact signature size in bytes" - }, - "HASH_SIZE_RIPEMD160": { - "value": 20, - "description": "RIPEMD-160 hash size in bytes" - }, - "HASH_SIZE_SHA256": { - "value": 32, - "description": "SHA-256 hash size in bytes" - } - } -} diff --git a/.qoder/docs/block-log-spec.md b/.qoder/docs/block-log-spec.md deleted file mode 100644 index 98e9780fd4..0000000000 --- a/.qoder/docs/block-log-spec.md +++ /dev/null @@ -1,978 +0,0 @@ -# Block Log File Format Specification - -This document specifies the binary file formats for VIZ blockchain block logs. - -## Overview - -VIZ uses two types of block logs: -- **block_log**: Full blockchain history (used by archive nodes) -- **dlt_block_log**: Rolling window of recent blocks (used by DLT/snapshot nodes) - -Each log consists of two files: -- **Data file**: Contains serialized block data -- **Index file**: Contains offsets for random access by block number - ---- - -## fc::raw Binary Serialization - -All data in block logs is serialized using `fc::raw` format. - -### Primitive Types - -| Type | Size | Format | -|------|------|--------| -| `uint8_t` | 1 byte | Little-endian | -| `uint16_t` | 2 bytes | Little-endian | -| `uint32_t` | 4 bytes | Little-endian | -| `uint64_t` | 8 bytes | Little-endian | -| `int8_t` | 1 byte | Two's complement | -| `int16_t` | 2 bytes | Little-endian, two's complement | -| `int32_t` | 4 bytes | Little-endian, two's complement | -| `int64_t` | 8 bytes | Little-endian, two's complement | -| `bool` | 1 byte | `0x00` = false, `0x01` = true | - -### Variable-Length Integer (varint) - -`fc::unsigned_int` uses a variable-length encoding similar to protobuf: - -``` -Each byte: [7 data bits][1 continuation bit] -- Continuation bit = 1: more bytes follow -- Continuation bit = 0: last byte - -Value is reconstructed by concatenating 7-bit chunks in order. -``` - -**Examples:** -- `0x00` → 0 -- `0x01` → 1 -- `0x7F` → 127 -- `0x80 0x01` → 128 -- `0xFF 0x01` → 255 -- `0x80 0x02` → 256 - -`fc::signed_int` uses zigzag encoding before varint: -- Zigzag: `(n << 1) ^ (n >> 31)` for encoding -- Un-zigzag: `(n >> 1) ^ -(n & 1)` for decoding - -### String - -``` -[varint: length][bytes: UTF-8 string data] -``` - -- Length is serialized as `fc::unsigned_int` (varint) -- Empty string: `[0x00]` - -### Vector - -``` -[varint: element_count][element_1][element_2]...[element_n] -``` - -### Optional - -``` -[uint8: flag][value if flag=1] -``` - -- `flag = 0`: no value (empty optional) -- `flag = 1`: value follows - -### flat_set - -``` -[varint: element_count][element_1][element_2]...[element_n] -``` - -Same wire format as `vector`. Elements are sorted and unique in the data structure, but serialized in sorted order. - -### flat_map - -``` -[varint: pair_count][key_1][value_1][key_2][value_2]...[key_n][value_n] -``` - -Same wire format as `vector>`. Each pair is serialized as key then value. - -### Optional - -``` -[uint8: flag][value if flag=1] -``` - -- `flag = 0`: no value (empty optional) -- `flag = 1`: value follows - -### Static Variant - -``` -[varint: type_index][serialized_value] -``` - -The type index identifies which type in the variant is stored. - -### extensions_type - -``` -[varint: count][varint: type_index_0]...[varint: type_index_n] -``` - -Defined as `flat_set` where `future_extensions = static_variant`. -Each extension item is just a varint type index (always 0 for `void_t`). -Usually empty (serialized as single byte `0x00`). - -### Reflected Structures - -Structures with `FC_REFLECT` macro are serialized field-by-field in the order defined by the macro. **Field order matters** — the binary layout must match the `FC_REFLECT` declaration exactly. - ---- - -## block_log (Data File) - -**Filename:** `block_log` - -### File Layout - -``` -+------------------+--------------------+------------------+--------------------+-----+ -| Block 1 (binary) | Position (8 bytes) | Block 2 (binary) | Position (8 bytes) | ... | -+------------------+--------------------+------------------+--------------------+-----+ -``` - -Each block entry consists of: -1. **Block data**: fc::raw serialized `signed_block` -2. **Position**: `uint64_t` little-endian offset of this block's start position - -### Reading the Head Block - -1. Seek to the last 8 bytes of the file -2. Read `uint64_t` position value -3. Seek to that position -4. Deserialize `signed_block` - -### Sequential Scan - -Starting from position 0: -1. Deserialize `signed_block` -2. Read next 8 bytes as `uint64_t` position (should match current position) -3. Next block starts at `current_position + block_size + 8` -4. Repeat until end of file - -### Block Number Extraction - -Block number is NOT stored directly. It is derived from: -- `block.previous` field (20-byte `block_id_type` / `ripemd160` hash) -- `block_num = num_from_id(previous) + 1` -- For genesis block: `previous` is all zeros, `block_num = 1` - -The `num_from_id` function extracts bytes 0-3 (first 4 bytes) of the hash as `uint32_t` little-endian. - ---- - -## block_log.index (Index File) - -**Filename:** `block_log.index` - -### File Layout - -``` -+------------------+------------------+-----+------------------------+ -| Position of #1 | Position of #2 | ... | Position of Head Block | -+------------------+------------------+-----+------------------------+ - 8 bytes 8 bytes 8 bytes -``` - -### Index Entry Location - -For block number `N`: -``` -offset = 8 * (N - 1) -``` - -**Example:** -- Block 1: offset 0 -- Block 2: offset 8 -- Block 1000000: offset 7999992 - -### Index Validation - -The last 8 bytes of both files should contain the same position value: -- `block_log`: position of head block -- `block_log.index`: position of head block - -If they differ, the index should be reconstructed from the data file. - ---- - -## dlt_block_log (Data File) - -**Filename:** `dlt_block_log` - -### File Layout - -Identical to regular `block_log`: -``` -+------------------+--------------------+------------------+--------------------+-----+ -| Block N (binary) | Position (8 bytes) | Block N+1 (bin) | Position (8 bytes) | ... | -+------------------+--------------------+------------------+--------------------+-----+ -``` - -The key difference: **can start at any block number**, not necessarily block 1. - ---- - -## dlt_block_log.index (Index File) - -**Filename:** `dlt_block_log.index` - -### File Layout - -``` -+-------------------+------------------+------------------+-----+------------------------+ -| start_block_num | Position of #S | Position of #S+1 | ... | Position of Head Block | -| (8 bytes header) | (8 bytes) | (8 bytes) | | (8 bytes) | -+-------------------+------------------+------------------+-----+------------------------+ -``` - -### Header - -- **Bytes 0-7**: `uint64_t` little-endian `start_block_num` -- The first block number stored in this rolling log - -### Index Entry Location - -For block number `N`: -``` -offset = 8 + 8 * (N - start_block_num) -``` - -**Example** (start_block_num = 10000000): -- Block 10000000: offset 8 -- Block 10000001: offset 16 -- Block 10050000: offset 400008 - -### Reading a Block by Number - -1. Read header (first 8 bytes) → `start_block_num` -2. Verify: `N >= start_block_num` and `N <= head_block_num` -3. Calculate offset: `8 + 8 * (N - start_block_num)` -4. Read `uint64_t` position at that offset -5. Seek to position in `dlt_block_log` -6. Deserialize `signed_block` - ---- - -## signed_block Structure - -``` -signed_block extends signed_block_header - └─ signed_block_header extends block_header - └─ block_header -``` - -### block_header Fields - -| Field | Type | Description | -|-------|------|-------------| -| `previous` | `block_id_type` (20 bytes) | Hash of previous block | -| `timestamp` | `time_point_sec` (4 bytes) | Block creation time (Unix timestamp) | -| `witness` | `string` | Witness account name | -| `transaction_merkle_root` | `checksum_type` (20 bytes) | Merkle root of transactions | -| `extensions` | `vector` | Future extensions (usually empty) | - -### block_header_extension (static_variant) - -Defined as `static_variant` in -`libraries/protocol/include/graphene/protocol/base.hpp`. - -| Type Index | Name | Serialized Data | Description | -|------------|------|----------------|-------------| -| 0 | `void_t` | (none) | Empty placeholder | -| 1 | `version` | `uint32_t v_num` (4 bytes) | Witness version reporting (8.8.16 bit packing) | -| 2 | `hardfork_version_vote` | `uint32_t` hf_version + `uint32_t` hf_time (8 bytes) | Hardfork vote | - -Version `v_num` packing: `(major << 24) | (hardfork << 16) | release`. Example: `0x00000001` = version 0.0.1. - -### signed_block_header Additional Fields - -| Field | Type | Description | -|-------|------|-------------| -| `witness_signature` | `signature_type` (65 bytes) | Witness signature (compact) | - -### signed_block Additional Fields - -| Field | Type | Description | -|-------|------|-------------| -| `transactions` | `vector` | List of transactions | - -### Serialization Order - -``` -block_header: - [20 bytes: previous] - [4 bytes: timestamp] - [varint + string: witness] - [20 bytes: transaction_merkle_root] - [varint + extensions: extensions] - -signed_block_header (after block_header): - [65 bytes: witness_signature] - -signed_block (after signed_block_header): - [varint + transactions: transactions] -``` - ---- - -## signed_transaction Structure - -### transaction Fields - -| Field | Type | Description | -|-------|------|-------------| -| `ref_block_num` | `uint16_t` (2 bytes) | Reference block number | -| `ref_block_prefix` | `uint32_t` (4 bytes) | Reference block prefix | -| `expiration` | `time_point_sec` (4 bytes) | Transaction expiration | -| `operations` | `vector` | List of operations | -| `extensions` | `extensions_type` | Extensions (usually empty) | - -### signed_transaction Additional Fields - -| Field | Type | Description | -|-------|------|-------------| -| `signatures` | `vector` | Transaction signatures | - -### Serialization Order - -``` -transaction: - [2 bytes: ref_block_num] - [4 bytes: ref_block_prefix] - [4 bytes: expiration] - [varint + operations: operations] - [varint + extensions: extensions] - -signed_transaction (after transaction): - [varint + signatures: signatures] -``` - ---- - -## Special Types - -### block_id_type / checksum_type / transaction_id_type - -All are `fc::ripemd160` hashes (20 bytes). - -> **Steem lineage note:** VIZ inherits this design from the Steem codebase. Rather than using -> the full 32-byte `fc::sha256` for block IDs and merkle roots, VIZ uses the shorter 20-byte -> `fc::ripemd160`. The `block_id_type` is defined as `typedef fc::ripemd160 block_id_type` and -> `checksum_type` as `typedef fc::ripemd160 checksum_type` in -> `libraries/protocol/include/graphene/protocol/types.hpp`. This is sometimes called a "feature" -> by the original developers — the shorter hash saves space and the collision risk is considered -> acceptable for block identification within a running chain. - -### signature_type - -`fc::ecc::compact_signature` - 65 bytes: -- 1 byte: recovery id -- 32 bytes: r coordinate -- 32 bytes: s coordinate - -### time_point_sec - -`uint32_t` Unix timestamp (seconds since 1970-01-01 00:00:00 UTC). - -### account_name_type - -`fc::fixed_string_32` - serialized as regular string (varint length + UTF-8 bytes). - ---- - -## JavaScript Implementation Notes - -### Endianness - -All multi-byte integers are **little-endian**. - -### BigInt Handling - -- Use `BigInt` for `uint64_t` positions (JavaScript numbers lose precision above 2^53) -- Convert to `Number` only when safe (< 2^53) - -### Buffer Reading - -```javascript -const fs = require('fs'); -const { Buffer } = require('buffer'); - -// Read uint64_t as BigInt -function readUint64LE(buffer, offset) { - return buffer.readBigUInt64LE(offset); -} - -// Read uint32_t -function readUint32LE(buffer, offset) { - return buffer.readUInt32LE(offset); -} - -// Read varint (fc::unsigned_int) -function readVarint(buffer, offset) { - let value = 0n; - let shift = 0; - let pos = offset; - - while (true) { - const byte = buffer.readUInt8(pos++); - value |= BigInt(byte & 0x7F) << BigInt(shift); - if (!(byte & 0x80)) break; - shift += 7; - } - - return { value: Number(value), bytesRead: pos - offset }; -} -``` - -### File Reading Strategy - -1. Use `fs.open()` + `fs.read()` for random access -2. Or use `mmap`-like approach with `Buffer` for frequent access -3. Cache the index file in memory for fast lookups - ---- - -## Error Handling - -### Index Mismatch - -When `block_log` and `block_log.index` positions don't match: -1. Delete the index file -2. Reconstruct by scanning the data file -3. Write new index entries - -### Corrupted Block - -If a block fails to deserialize: -1. Check if position marker matches actual position -2. If mismatch, scan backward from end of file -3. The file may be truncated from a crash - -### Empty Files - -- New/empty `block_log`: 1 null byte (implementation artifact) -- Valid minimum size: > 8 bytes (at least one position marker) - ---- - -## Operation Types - -Operations are serialized as `fc::static_variant` with a type index followed by the operation data. - -### Operation Type IDs - -| ID | Operation Name | Type | -|----|----------------|------| -| 0 | `vote_operation` | deprecated | -| 1 | `content_operation` | deprecated | -| 2 | `transfer_operation` | regular | -| 3 | `transfer_to_vesting_operation` | regular | -| 4 | `withdraw_vesting_operation` | regular | -| 5 | `account_update_operation` | regular | -| 6 | `witness_update_operation` | regular | -| 7 | `account_witness_vote_operation` | regular | -| 8 | `account_witness_proxy_operation` | regular | -| 9 | `delete_content_operation` | deprecated | -| 10 | `custom_operation` | regular | -| 11 | `set_withdraw_vesting_route_operation` | regular | -| 12 | `request_account_recovery_operation` | regular | -| 13 | `recover_account_operation` | regular | -| 14 | `change_recovery_account_operation` | regular | -| 15 | `escrow_transfer_operation` | regular | -| 16 | `escrow_dispute_operation` | regular | -| 17 | `escrow_release_operation` | regular | -| 18 | `escrow_approve_operation` | regular | -| 19 | `delegate_vesting_shares_operation` | regular | -| 20 | `account_create_operation` | regular | -| 21 | `account_metadata_operation` | regular | -| 22 | `proposal_create_operation` | regular | -| 23 | `proposal_update_operation` | regular | -| 24 | `proposal_delete_operation` | regular | -| 25 | `chain_properties_update_operation` | regular | -| 26 | `author_reward_operation` | virtual | -| 27 | `curation_reward_operation` | virtual | -| 28 | `content_reward_operation` | virtual | -| 29 | `fill_vesting_withdraw_operation` | virtual | -| 30 | `shutdown_witness_operation` | virtual | -| 31 | `hardfork_operation` | virtual | -| 32 | `content_payout_update_operation` | virtual | -| 33 | `content_benefactor_reward_operation` | virtual | -| 34 | `return_vesting_delegation_operation` | virtual | -| 35 | `committee_worker_create_request_operation` | regular | -| 36 | `committee_worker_cancel_request_operation` | regular | -| 37 | `committee_vote_request_operation` | regular | -| 38 | `committee_cancel_request_operation` | virtual | -| 39 | `committee_approve_request_operation` | virtual | -| 40 | `committee_payout_request_operation` | virtual | -| 41 | `committee_pay_request_operation` | virtual | -| 42 | `witness_reward_operation` | virtual | -| 43 | `create_invite_operation` | regular | -| 44 | `claim_invite_balance_operation` | regular | -| 45 | `invite_registration_operation` | regular | -| 46 | `versioned_chain_properties_update_operation` | regular | -| 47 | `award_operation` | regular | -| 48 | `receive_award_operation` | virtual | -| 49 | `benefactor_award_operation` | virtual | -| 50 | `set_paid_subscription_operation` | regular | -| 51 | `paid_subscribe_operation` | regular | -| 52 | `paid_subscription_action_operation` | virtual | -| 53 | `cancel_paid_subscription_operation` | virtual | -| 54 | `set_account_price_operation` | regular | -| 55 | `set_subaccount_price_operation` | regular | -| 56 | `buy_account_operation` | regular | -| 57 | `account_sale_operation` | virtual | -| 58 | `use_invite_balance_operation` | regular | -| 59 | `expire_escrow_ratification_operation` | virtual | -| 60 | `fixed_award_operation` | regular | -| 61 | `target_account_sale_operation` | regular | -| 62 | `bid_operation` | virtual | -| 63 | `outbid_operation` | virtual | - -### Operation Serialization Format - -``` -[varint: type_index][operation_specific_fields...] -``` - -### Common Types - -#### asset - -``` -[int64: amount][uint64: symbol] -``` - -**Asset symbol format** (inherited from Steem codebase, defined in `asset.cpp`): - -The `uint64 symbol` is a packed structure with the following byte layout (little-endian): - -| Byte | Field | Description | -|------|-------|-------------| -| 0 | decimals | Number of decimal places (0-14) | -| 1-6 | name | ASCII symbol name (up to 6 chars) | -| 7 | null | Always 0x00 (null terminator) | - -Known symbols (from `config.hpp`): - -| Name | Decimals | uint64 (LE bytes) | uint64 (hex) | -|------|----------|--------------------|--------------| -| `VIZ` | 3 | `03 56 49 5A 00 00 00 00` | `0x000000005A495603` | -| `SHARES` | 6 | `06 53 48 41 52 45 53 00` | `0x0053455241485306` | - -> **Steem lineage note:** This symbol encoding format is inherited from the Steem codebase. -> Rather than using an enum or string, the symbol is packed as a uint64 with precision in byte 0 -> and the ASCII name in bytes 1-6. This design allows the symbol to carry its own decimal -> precision information without requiring a separate lookup. - -#### authority -``` -[uint32: weight_threshold] -[flat_map: account_auths] -[flat_map: key_auths] -``` - -> **Note:** `account_auths` and `key_auths` are `flat_map` (not `flat_set>`). -> Wire format is identical to `vector>`: varint count + (key, value) pairs. - -#### public_key_type - -**Wire format:** 33 raw bytes of compressed secp256k1 public key: -``` -[1 byte: 0x02 or 0x03 prefix][32 bytes: x-coordinate] -``` - -**String representation** (in JSON output, not on wire): -1. Compute `ripemd160(33_key_bytes)` -2. First 4 bytes of hash = checksum -3. Concatenate: `[33 key bytes][4 checksum bytes]` = 37 bytes -4. Base58-encode the 37-byte buffer -5. Prepend `"VIZ"` (CHAIN_ADDRESS_PREFIX) - -Example: `VIZ7wMEutJdCfdSKNgVAp17v9uoTqwwkUqn2kwVsJ6zG5XYJcvj81` - -Matches C++ `public_key_type::operator std::string()` in `libraries/protocol/types.cpp`. - -#### chain_properties_init - -Used by `chain_properties_update_operation` (ID 25). **12 fields only** — NOT the same as `chain_properties_hf9`. -``` -[asset: account_creation_fee] -[uint32: maximum_block_size] -[uint32: create_account_delegation_ratio] -[uint32: create_account_delegation_time] -[asset: min_delegation] -[uint16: min_curation_percent] -[uint16: max_curation_percent] -[uint16: bandwidth_reserve_percent] -[asset: bandwidth_reserve_below] -[uint16: flag_energy_additional_cost] -[uint32: vote_accounting_min_rshares] -[uint16: committee_request_approve_min_percent] -``` - -#### versioned_chain_properties - -Used by `versioned_chain_properties_update_operation` (ID 46). A `static_variant` of chain property variants: - -``` -[varint: type_index][chain_properties_init base fields][variant-specific additional fields] -``` - -| Type Index | Name | Base | Additional Fields | -|------------|------|------|-------------------| -| 0 | `chain_properties_init` | — | (12 base fields only) | -| 1 | `chain_properties_hf4` | init | +3: `inflation_witness_percent`(uint16), `inflation_ratio_committee_vs_reward_fund`(uint16), `inflation_recalc_period`(uint32) | -| 2 | `chain_properties_hf6` | hf4 | +3: `data_operations_cost_additional_bandwidth`(uint32), `witness_miss_penalty_percent`(uint16), `witness_miss_penalty_duration`(uint32) | -| 3 | `chain_properties_hf9` | hf6 | +7: `create_invite_min_balance`(asset), `committee_create_request_fee`(asset), `create_paid_subscription_fee`(asset), `account_on_sale_fee`(asset), `subaccount_on_sale_fee`(asset), `witness_declaration_fee`(asset), `withdraw_intervals`(uint16) | - -### Operation Structures - -#### transfer_operation (ID: 2) -``` -[account_name_type: from] -[account_name_type: to] -[asset: amount] -[string: memo] -``` - -#### account_create_operation (ID: 20) -``` -[asset: fee] -[asset: delegation] -[account_name_type: creator] -[account_name_type: new_account_name] -[authority: master] -[authority: active] -[authority: regular] -[public_key_type: memo_key] -[string: json_metadata] -[account_name_type: referrer] -[extensions_type: extensions] -``` - -#### witness_update_operation (ID: 6) -``` -[account_name_type: owner] -[string: url] -[public_key_type: block_signing_key] -``` - -#### award_operation (ID: 47) -``` -[account_name_type: initiator] -[account_name_type: receiver] -[uint16: energy] -[uint64: custom_sequence] -[string: memo] -[vector: beneficiaries] -``` - -#### beneficiary_route_type -``` -[account_name_type: account] -[uint16: weight] -``` - -#### invite_registration_operation (ID: 45) -``` -[account_name_type: account] -[public_key_type: new_account_key] -[string: invite_secret] ← WIF-encoded private key (e.g. '5Kd...'), NOT raw bytes -[extensions_type: extensions] -``` - -> **Important:** `invite_secret` is a `string` (WIF-encoded private key), NOT raw 32 bytes. -> The same applies to `claim_invite_balance_operation` (ID 44) and `use_invite_balance_operation` (ID 58). - -#### claim_invite_balance_operation (ID: 44) -``` -[account_name_type: initiator] -[account_name_type: receiver] -[string: invite_secret] ← WIF-encoded private key string -[extensions_type: extensions] -``` - -#### use_invite_balance_operation (ID: 58) -``` -[account_name_type: initiator] -[account_name_type: receiver] -[string: invite_secret] ← WIF-encoded private key string -[extensions_type: extensions] -``` - -#### chain_properties_update_operation (ID: 25) -``` -[account_name_type: owner] -[chain_properties_init: props] ← 12-field struct, NOT chain_properties_hf9 -[extensions_type: extensions] -``` - -#### versioned_chain_properties_update_operation (ID: 46) -``` -[account_name_type: owner] -[versioned_chain_properties: props] ← static_variant -[extensions_type: extensions] -``` - -#### benefactor_award_operation (ID: 49, virtual) -``` -[account_name_type: initiator] ← FC_REFLECT order: initiator BEFORE benefactor -[account_name_type: benefactor] -[account_name_type: receiver] -[uint64: custom_sequence] -[string: memo] -[asset: shares] -``` - -#### set_paid_subscription_operation (ID: 50) -``` -[account_name_type: account] -[string: url] -[uint16: levels] ← uint16, NOT uint8 -[asset: amount] -[uint16: period] ← uint16, NOT uint32 -[extensions_type: extensions] -``` - -#### paid_subscribe_operation (ID: 51) -``` -[account_name_type: account] -[account_name_type: subscriber] -[uint16: level] ← uint16, NOT uint8 -[asset: amount] -[uint16: period] ← uint16, NOT uint32 -[extensions_type: extensions] -``` - -#### paid_subscription_action_operation (ID: 52, virtual) -``` -[account_name_type: subscriber] -[account_name_type: account] -[uint16: level] -[asset: amount] -[uint16: period] -[uint64: summary_duration_sec] -[asset: summary_amount] -``` - -#### cancel_paid_subscription_operation (ID: 53, virtual) -``` -[account_name_type: subscriber] -[account_name_type: account] -``` - -> Only 2 fields — no `level` field. - -#### buy_account_operation (ID: 56) -``` -[account_name_type: account] -[account_name_type: buyer] -[asset: tokens_to_shares] ← asset type, NOT bool/uint8 -[extensions_type: extensions] -``` - -#### account_sale_operation (ID: 57, virtual) -``` -[account_name_type: account] -[asset: price] -[account_name_type: buyer] -[account_name_type: seller] -``` - -#### expire_escrow_ratification_operation (ID: 59, virtual) -``` -[account_name_type: from] -[account_name_type: to] -[account_name_type: agent] -[uint32: escrow_id] -[asset: token_amount] -[asset: fee] -[time_point_sec: ratification_deadline] -``` - -#### bid_operation (ID: 62, virtual) -``` -[account_name_type: account] ← FC_REFLECT order: account BEFORE bidder -[account_name_type: bidder] -[asset: bid] -``` - -#### outbid_operation (ID: 63, virtual) -``` -[account_name_type: account] ← FC_REFLECT order: account BEFORE bidder -[account_name_type: bidder] -[asset: bid] -``` - -#### proposal_delete_operation (ID: 24) -``` -[account_name_type: author] -[string: title] -[account_name_type: requester] ← was previously missing -[extensions_type: extensions] -``` - -## Tools - -### block-log-reader.js - -JavaScript module for reading block_log and dlt_block_log files. Provides programmatic access to block data. - -**Usage:** -```javascript -const { createBlockLogReader, getBlockNum, publicKeyToString } = require('./block-log-reader'); - -const reader = createBlockLogReader('/path/to/block_log'); -// Or for DLT: createBlockLogReader('/path/to/dlt_block_log', undefined, true); - -const block = reader.readBlockByNum(1000); -console.log(getBlockNum(block), block.witness); -reader.close(); -``` - -### block-log-viewer.js - -Interactive terminal UI for browsing block logs. No external dependencies. - -**Usage:** -``` -node block-log-viewer.js [--dlt] [--reader=] -``` - -`` can be either: -- Path to a `block_log` or `dlt_block_log` file directly -- Path to a directory containing `block_log` / `dlt_block_log` (auto-detected) - -**Options:** - -| Option | Description | -|--------|-------------| -| `--dlt` | Use DLT (rolling) block log reader | -| `--reader=` | Path to `block-log-reader.js` module | - -**Directory auto-detection** (when `` is a directory): - -| Files present | `--dlt` | Result | -|--------------|---------|--------| -| `block_log` only | no | Standard mode | -| `dlt_block_log` only | no | Auto-switches to DLT mode | -| Both | no | Standard mode (`block_log`) | -| Both | yes | DLT mode (`dlt_block_log`) | -| Neither | — | Error | - -**Module resolution** (if `block-log-reader.js` is not in the same directory): -- `--reader=/path/to/block-log-reader.js` — explicit CLI option -- `BLOCK_LOG_READER=/path/to/block-log-reader.js` — environment variable - -#### Navigation Commands - -| Command | Description | -|---------|-------------| -| `f` | First block | -| `l` | Last block | -| `n` | Next block | -| `p` | Previous block | -| `N` | Next block with non-free operations (bitmask-accelerated) | -| `P` | Prev block with non-free operations (bitmask-accelerated) | -| `g ` | Go to block #num | -| `` | Jump to block number directly | - -#### Operation Commands - -| Command | Description | -|---------|-------------| -| `o` | Show all operations in current block (JSON) | -| `o ` | Show operations matching type name (e.g. `o transfer`) | -| `s ` | Search forward for block containing operation by type name | -| `S ` | Search forward for substring in any operation's data (incl. virtual) | -| `S =` | Search forward for **exact** string match (`=` prefix disables substring matching) | -| `R ` | Fast raw ASCII byte search in block data (no UTF-8/emoji) | -| `e ` | Export all ops containing string to `search_export_.json` | -| `e =` | Export all ops **exactly matching** string (`=` prefix for exact match) | -| `c` | Continue last search (s/S/R/e) | - -> **Search modes:** Without `=` prefix, string search uses substring matching (e.g. `S VIZ` matches -> any occurrence of "VIZ" in data). With `=` prefix, uses exact match (e.g. `e ="V"` finds only -> the value `V`, not `VIZ`). Surrounding quotes are automatically stripped. - -#### Other - -| Command | Description | -|---------|-------------| -| `scan` | Scan all blocks, build & save bitmask for fast navigation | -| `i` | Show block header info | -| `hex` | Show raw block data in hex | -| `h` | Help | -| `q` | Quit | - -#### Bitmask File (block_log.bitmask) - -The `scan` command builds a compact bitmask file that marks which blocks contain non-free (non-virtual) operations. Once built, `N` and `P` commands jump instantly between non-empty blocks without deserializing skipped blocks. - -**File format:** - -``` -+-------------------+-------------------+-------------------------------+ -| start_block_num | end_block_num | bit array | -| (8 bytes, uint64) | (8 bytes, uint64) | 1 bit per block | -+-------------------+-------------------+-------------------------------+ -``` - -- **Bytes 0–7**: `uint64_t` LE — `start_block_num` -- **Bytes 8–15**: `uint64_t` LE — `end_block_num` -- **Bytes 16+**: bit array, 1 bit per block (bit 0 = `start_block_num`) - - `1` = block has non-free operations - - `0` = block is empty or has only virtual operations -- Total size: `16 + ceil((end - start + 1) / 8)` bytes - -**Example:** 10,000,000 blocks → ~1.25 MB bitmask file. - -The bitmask is auto-loaded on startup if it exists and matches the current block range. If the range differs, a rescan is suggested. - -#### String Search (`S`), Raw Search (`R`), and Export (`e`) - -The `S` command searches the **full operation data** (including virtual) for a substring match. The `=` prefix enables exact match mode — `S ="V"` finds only the exact value `V`, not `VIZ` or other strings containing `V`. - -The `R` command performs a fast raw ASCII byte search directly in the block's binary data, without deserialization. No UTF-8/emoji support. Useful for quickly locating blocks containing specific ASCII patterns. - -The `e` command performs the same search as `S` across **all** blocks and writes results to a JSON file in the block_log directory: - -``` -search_export_1745312345.json -``` - -Export format: -```json -[ - { - "block": 12345, - "timestamp": "2024-01-15 10:30:00 UTC", - "witness": "on1x", - "typeId": 47, - "typeName": "award_operation", - "isVirtual": false, - "data": { "initiator": "alice", "receiver": "on1x", ... } - } -] -``` - -Buffers are serialized as hex strings; BigInts as decimal strings. - ---- - -## See Also - -- [data-types.md](data-types.md) - VIZ data type definitions -- [snapshot-plugin.md](snapshot-plugin.md) - DLT mode documentation -- [block-log-spec.json](block-log-spec.json) - Machine-readable specification diff --git a/.qoder/docs/block-log-viewer.js b/.qoder/docs/block-log-viewer.js deleted file mode 100644 index 8e35fcf511..0000000000 --- a/.qoder/docs/block-log-viewer.js +++ /dev/null @@ -1,1309 +0,0 @@ -#!/usr/bin/env node -/** - * VIZ Block Log Viewer - Interactive terminal UI - * No external dependencies. Uses block-log-reader.js for parsing. - * - * Usage: node block-log-viewer.js [--dlt] [--reader=] - * - * The viewer will look for block-log-reader.js in this order: - * 1. --reader= CLI option - * 2. Same directory as this script - * 3. BLOCK_LOG_READER environment variable - */ - -const fs = require('fs'); -const path = require('path'); -const readline = require('readline'); - -// Resolve block-log-reader module from multiple locations -function resolveReaderModule() { - const cliReader = process.argv.find(a => a.startsWith('--reader=')); - if (cliReader) { - const p = cliReader.split('=')[1]; - if (fs.existsSync(p)) return p; - console.error(`--reader path not found: ${p}`); - process.exit(1); - } - - const candidates = [ - path.join(__dirname, 'block-log-reader'), // same dir as this script - process.env.BLOCK_LOG_READER, // env var - ].filter(Boolean); - - for (const candidate of candidates) { - try { - require.resolve(candidate); - return candidate; - } catch (e) { /* not found, try next */ } - } - - console.error('Cannot find block-log-reader.js'); - console.error('Place it in the same directory as this script, or use:'); - console.error(' node block-log-viewer.js --reader=/path/to/block-log-reader.js'); - console.error(' set BLOCK_LOG_READER=/path/to/block-log-reader.js'); - process.exit(1); -} - -const readerModule = resolveReaderModule(); -const { - createBlockLogReader, - getBlockNum, - blockIdToHex, - OPERATION_TYPES, - CONSTANTS, - BinaryReader, - readSignedBlockHeader, - readSignedBlock -} = require(readerModule); - -// ============================================================================ -// State -// ============================================================================ - -let reader = null; -let currentBlockNum = 0; -let startBlock = 1; -let endBlock = 0; -let scanning = false; -let lastSearch = null; // { type: 's'|'S'|'e', term: string } - -// Bitmask: 1 bit per block, 1 = has non-free ops, 0 = empty/virtual-only -let bitmask = null; // Buffer or null -let bitmaskStart = 0; // start_block_num stored in bitmask -let bitmaskEnd = 0; // end_block_num stored in bitmask - -// ============================================================================ -// Helpers -// ============================================================================ - -function isNonFreeOp(op) { - return !op.isVirtual; -} - -/** - * Check if a Buffer contains an ASCII string (case-insensitive). - * Searches raw bytes without any string conversion or object allocation. - */ -function bufIncludesAscii(buf, searchLower) { - const len = searchLower.length; - const bufLen = buf.length; - outer: - for (let i = 0; i <= bufLen - len; i++) { - for (let j = 0; j < len; j++) { - let c = buf[i + j]; - // Convert to lowercase: A-Z (0x41-0x5A) -> a-z (0x61-0x7A) - if (c >= 0x41 && c <= 0x5A) c += 0x20; - if (c !== searchLower.charCodeAt(j)) continue outer; - } - return true; - } - return false; -} - -function hasNonFreeOps(block) { - for (const tx of block.transactions) { - for (const op of tx.operations) { - if (isNonFreeOp(op)) return true; - } - } - return false; -} - -function collectOps(block) { - const ops = []; - for (const tx of block.transactions) { - for (const op of tx.operations) { - ops.push(op); - } - } - return ops; -} - -function formatTimestamp(d) { - return d.toISOString().replace('T', ' ').replace('.000Z', ' UTC'); -} - -function hashHex(h) { - return h ? Buffer.from(h).toString('hex') : '(null)'; -} - -function shortenHex(hex, len = 16) { - if (!hex || hex.length <= len * 2) return hex; - return hex.slice(0, len) + '...' + hex.slice(-len); -} - -// ============================================================================ -// Bitmask (block_log.bitmask) -// ============================================================================ -// -// File format: -// [8 bytes] start_block_num (uint64 LE) -// [8 bytes] end_block_num (uint64 LE) -// [N bytes] bit array, 1 bit per block (bit i = block startBlock+i) -// bit=1 means block has non-free (non-virtual) operations -// Total bytes = ceil((end - start + 1) / 8) -// -// Saved alongside block_log as block_log.bitmask -// ============================================================================ - -function bitmaskPath() { - return reader.dataPath + '.bitmask'; -} - -/** - * Set bit for blockNum (1 = has non-free ops) - */ -function bitmaskSet(buf, start, blockNum) { - const idx = blockNum - start; - const byteIdx = idx >> 3; - const bitIdx = idx & 7; - buf[byteIdx] |= (1 << bitIdx); -} - -/** - * Get bit for blockNum. Returns 0 or 1. If no bitmask loaded, returns -1. - */ -function bitmaskGet(blockNum) { - if (!bitmask) return -1; - if (blockNum < bitmaskStart || blockNum > bitmaskEnd) return -1; - const idx = blockNum - bitmaskStart; - const byteIdx = idx >> 3; - const bitIdx = idx & 7; - return (bitmask[byteIdx] >> bitIdx) & 1; -} - -/** - * Check if bitmask is loaded and valid for current range - */ -function bitmaskValid() { - return bitmask && bitmaskStart === startBlock && bitmaskEnd === endBlock; -} - -/** - * Load bitmask from file. Returns true if loaded and valid. - */ -function bitmaskLoad() { - const p = bitmaskPath(); - if (!fs.existsSync(p)) return false; - try { - const fd = fs.openSync(p, 'r'); - const stat = fs.fstatSync(fd); - if (stat.size < 16) { fs.closeSync(fd); return false; } - - const hdr = Buffer.allocUnsafe(16); - fs.readSync(fd, hdr, 0, 16, 0); - const s = Number(hdr.readBigUInt64LE(0)); - const e = Number(hdr.readBigUInt64LE(8)); - - const expectedBits = e - s + 1; - const expectedBytes = Math.ceil(expectedBits / 8); - if (stat.size < 16 + expectedBytes) { fs.closeSync(fd); return false; } - - const bits = Buffer.allocUnsafe(expectedBytes); - fs.readSync(fd, bits, 0, expectedBytes, 16); - fs.closeSync(fd); - - bitmask = bits; - bitmaskStart = s; - bitmaskEnd = e; - - if (s === startBlock && e === endBlock) { - return true; // fully valid - } - console.log(` Bitmask range #${s}-#${e} differs from log #${startBlock}-#${endBlock}, will rescan.`); - return false; - } catch (e) { - return false; - } -} - -/** - * Scan all blocks, build bitmask, save to file. - * Uses lightweight tx-count check (no full block deserialization) with - * batch I/O for the index file and progressive bitmask writes. - * Virtual operations are NOT stored in block_log, so tx_count > 0 = has ops. - */ -function bitmaskScan() { - if (scanning) { console.log(' Already scanning.'); return; } - scanning = true; - const total = endBlock - startBlock + 1; - const byteLen = Math.ceil(total / 8); - const BATCH_SIZE = 50000; - - // Prepare file - const p = bitmaskPath(); - const hdr = Buffer.allocUnsafe(16); - hdr.writeBigUInt64LE(BigInt(startBlock), 0); - hdr.writeBigUInt64LE(BigInt(endBlock), 8); - - // Write header + empty bitmask placeholder - const fd = fs.openSync(p, 'w'); - fs.writeSync(fd, hdr, 0, 16, 0); - const zeroChunk = Buffer.alloc(Math.min(byteLen, 65536)); - for (let off = 0; off < byteLen; off += zeroChunk.length) { - const writeLen = Math.min(zeroChunk.length, byteLen - off); - fs.writeSync(fd, zeroChunk, 0, writeLen, 16 + off); - } - - console.log(` Scanning ${total} blocks for non-free operations...`); - console.log(` Bitmask file: ${path.basename(p)} (${((16 + byteLen) / 1024).toFixed(1)} KB)`); - console.log(` Batch size: ${BATCH_SIZE} blocks (lightweight: header + tx count only)`); - - // Process in batches - let currentNum = startBlock; - let nonFreeCount = 0; - let lastPct = -1; - - function processBatch() { - const batchEnd = Math.min(currentNum + BATCH_SIZE - 1, endBlock); - const batchCount = batchEnd - currentNum + 1; - const batchBits = Buffer.alloc(Math.ceil(batchCount / 8)); - - // Read index positions in bulk (one I/O for the whole batch + 1 extra for size boundary) - const positions = reader.readBlockPosBatch(currentNum, batchCount + 1); - if (positions.length === 0) { - currentNum = batchEnd + 1; - setImmediate(processBatch); - return; - } - - for (let i = 0; i < batchCount; i++) { - const num = currentNum + i; - const startPos = Number(positions[i]); - const endPos = (i + 1 < positions.length) ? Number(positions[i + 1]) : (Number(reader.dataSize) - 8); - const blockSize = endPos - startPos; - - if (blockSize <= 0 || blockSize > CONSTANTS.CHAIN_BLOCK_SIZE + 16) continue; - - try { - // Read exact block bytes and parse only header + tx count - const buffer = reader._readData(BigInt(startPos), blockSize); - const br = new BinaryReader(buffer); - readSignedBlockHeader(br); // skip header - const txCount = Number(br.readVarint()); - - if (txCount > 0) { - const byteIdx = Math.floor(i / 8); - const bitOffset = i % 8; - batchBits[byteIdx] |= (1 << bitOffset); - nonFreeCount++; - } - } catch (e) { - // Skip blocks that fail to parse - } - } - - // Write this batch's bits to the file - const batchFileOffset = Math.floor((currentNum - startBlock) / 8); - fs.writeSync(fd, batchBits, 0, batchBits.length, 16 + batchFileOffset); - - // Progress - const processed = batchEnd - startBlock + 1; - const pct = Math.floor((processed / total) * 100); - if (pct !== lastPct) { - lastPct = pct; - const memMB = Math.round(process.memoryUsage().heapUsed / 1024 / 1024); - process.stdout.write(`\r Scanning... ${pct}% (#${batchEnd}, ${nonFreeCount} with ops, ${memMB} MB heap) `); - } - - currentNum = batchEnd + 1; - if (currentNum <= endBlock) { - setImmediate(processBatch); - } else { - // Done — load the completed bitmask - fs.closeSync(fd); - - bitmaskLoad(); - - const empty = total - nonFreeCount; - const sizeKB = ((16 + byteLen) / 1024).toFixed(1); - console.log(`\r Done. ${nonFreeCount} with ops, ${empty} empty. Saved ${sizeKB} KB to ${path.basename(p)} `); - scanning = false; - showPrompt(); - } - } - - processBatch(); -} - -/** - * Find next block with non-free ops using bitmask (fast, no deserialization) - * Returns block number or 0 if none found - */ -function bitmaskFindNext(fromBlock) { - if (!bitmaskValid()) return 0; - for (let num = fromBlock; num <= bitmaskEnd; num++) { - if (bitmaskGet(num) === 1) return num; - } - return 0; -} - -/** - * Find prev block with non-free ops using bitmask - */ -function bitmaskFindPrev(fromBlock) { - if (!bitmaskValid()) return 0; - for (let num = fromBlock; num >= bitmaskStart; num--) { - if (bitmaskGet(num) === 1) return num; - } - return 0; -} - -// ============================================================================ -// Display -// ============================================================================ - -function showBlock(block) { - const num = getBlockNum(block); - const ops = collectOps(block); - const nonFree = ops.filter(isNonFreeOp); - const virtual = ops.filter(o => o.isVirtual); - - console.log(''); - console.log('='.repeat(72)); - console.log(` Block #${num}`); - console.log('='.repeat(72)); - console.log(` Timestamp : ${formatTimestamp(block.timestamp)}`); - console.log(` Witness : ${block.witness}`); - console.log(` Previous : ${shortenHex(hashHex(block.previous))}`); - console.log(` Tx Merkle : ${shortenHex(hashHex(block.transaction_merkle_root))}`); - console.log(` Signature : ${shortenHex(hashHex(block.witness_signature))}`); - console.log(` Tx count : ${block.transactions.length}`); - if (block.extensions && block.extensions.length > 0) { - for (const ext of block.extensions) { - if (ext.name === 'version') { - console.log(` Extension : version = ${ext.data.version}`); - } else if (ext.name === 'hardfork_version_vote') { - console.log(` Extension : hardfork_version_vote = ${ext.data.hf_version} at ${ext.data.hf_time}`); - } else { - console.log(` Extension : ${ext.name} ${JSON.stringify(ext.data)}`); - } - } - } - console.log(` Ops total : ${ops.length} (non-free: ${nonFree.length}, virtual: ${virtual.length})`); - console.log('-'.repeat(72)); -} - -function showOps(block, filter) { - const ops = collectOps(block); - const filtered = filter ? ops.filter(o => o.typeName.includes(filter)) : ops; - - if (filtered.length === 0) { - if (filter) { - console.log(` No operations matching "${filter}" in this block.`); - } else { - console.log(' (no operations)'); - } - return; - } - - for (let i = 0; i < filtered.length; i++) { - const op = filtered[i]; - const tag = op.isVirtual ? '[V]' : ' '; - console.log(` ${tag} [${i}] ${op.typeName}`); - try { - const json = JSON.stringify(op.data, (key, val) => { - if (val && val.type === 'Buffer') return ``; - if (Buffer.isBuffer(val)) return ``; - if (typeof val === 'bigint') return val.toString(); - return val; - }, 2); - for (const line of json.split('\n')) { - console.log(' ' + line); - } - } catch (e) { - console.log(' (serialization error)'); - } - console.log(''); - } -} - -function showHelp() { - console.log(''); - console.log('Commands:'); - console.log(' f - First block'); - console.log(' l - Last block'); - console.log(' n - Next block'); - console.log(' p - Previous block'); - console.log(' N - Next block with non-free operations (uses bitmask)'); - console.log(' P - Prev block with non-free operations (uses bitmask)'); - console.log(' g - Go to block #num'); - console.log(' o - Show operations in current block'); - console.log(' o - Show operations matching name'); - console.log(' s - Search forward for block containing operation name'); - console.log(' S - Search forward for string in op JSON (incl. virtual)'); - console.log(' Prefix with = for exact match: S =\"V\" finds V but not VIZ'); - console.log(' R - Fast raw ASCII byte search (no UTF-8/emoji)'); - console.log(' e - Export all ops containing string to search_export_.json'); - console.log(' Prefix with = for exact match: e =\"V\" exports only exact V matches'); - console.log(' c - Continue last search (s/S/e)'); - console.log(' scan - Scan all blocks, build & save bitmask for fast nav'); - console.log(' i - Show block info (header only)'); - console.log(' hex - Show raw block data in hex'); - console.log(' h - This help'); - console.log(' q - Quit'); - const bm = bitmaskValid() ? `LOADED (${endBlock - startBlock + 1} blocks)` : 'not loaded'; - console.log(` Bitmask : ${bm}`); - console.log(''); -} - -function showPrompt() { - const pct = endBlock > startBlock ? Math.round(((currentBlockNum - startBlock) / (endBlock - startBlock)) * 100) : 0; - process.stdout.write(`[${currentBlockNum}/${endBlock}] ${pct}% > `); -} - -// ============================================================================ -// Navigation -// ============================================================================ - -/** - * Safely read a block by number. Returns the block or null. - * Logs errors but does NOT throw — for use in scan loops. - */ -function safeReadBlock(num) { - try { - return reader.readBlockByNum(num); - } catch (e) { - return null; // skip blocks that fail to deserialize - } -} - -function showBlockHeaderOnly(header, blockNum, errorMsg) { - console.log(''); - console.log('='.repeat(72)); - console.log(` Block #${blockNum} (HEADER ONLY - deserialization failed)`); - console.log('='.repeat(72)); - if (header) { - console.log(` Timestamp : ${formatTimestamp(header.timestamp)}`); - console.log(` Witness : ${header.witness}`); - console.log(` Previous : ${shortenHex(hashHex(header.previous))}`); - console.log(` Tx Merkle : ${shortenHex(hashHex(header.transaction_merkle_root))}`); - console.log(` Signature : ${shortenHex(hashHex(header.witness_signature))}`); - console.log(` Block Num : ${header._blockNum} (from previous)`); - console.log(` File Pos : ${header._position}`); - } else { - console.log(' (header also could not be read)'); - } - console.log('-'.repeat(72)); - console.log(` Error: ${errorMsg}`); - console.log('-'.repeat(72)); -} - -function goTo(num) { - num = Math.max(startBlock, Math.min(endBlock, num)); - let block; - try { - block = reader.readBlockByNum(num); - } catch (e) { - // Full deserialization failed — try header-only - const header = reader.readBlockHeaderByNum(num); - showBlockHeaderOnly(header, num, e.message); - currentBlockNum = num; - return; - } - if (!block) { - // Block number out of index range - console.log(`Block #${num} is not in the index (out of range).`); - return; - } - currentBlockNum = num; - showBlock(block); -} - -function goNext() { - if (currentBlockNum >= endBlock) { console.log('Already at last block.'); return; } - goTo(currentBlockNum + 1); -} - -function goPrev() { - if (currentBlockNum <= startBlock) { console.log('Already at first block.'); return; } - goTo(currentBlockNum - 1); -} - -function goFirst() { - goTo(startBlock); -} - -function goLast() { - goTo(endBlock); -} - -function goNextWithOps() { - // Fast path: use bitmask to skip empty blocks without deserialization - if (bitmaskValid()) { - const next = bitmaskFindNext(currentBlockNum + 1); - if (next === 0) { - console.log(' No more blocks with non-free operations forward.'); - return; - } - // Only read & deserialize the one block we found - currentBlockNum = next; - try { - const block = reader.readBlockByNum(next); - if (block) showBlock(block); - else showBlockHeaderOnly(reader.readBlockHeaderByNum(next), next, 'Block returned null'); - } catch (e) { - showBlockHeaderOnly(reader.readBlockHeaderByNum(next), next, e.message); - } - return; - } - - // Slow fallback: scan by reading each block - for (let num = currentBlockNum + 1; num <= endBlock; num++) { - const block = safeReadBlock(num); - if (block && hasNonFreeOps(block)) { - currentBlockNum = num; - showBlock(block); - return; - } - if ((num - currentBlockNum) % 1000 === 0) { - process.stdout.write(`\r Scanning... #${num} `); - } - } - console.log('\r No more blocks with non-free operations forward. '); -} - -function goPrevWithOps() { - // Fast path: use bitmask - if (bitmaskValid()) { - const prev = bitmaskFindPrev(currentBlockNum - 1); - if (prev === 0) { - console.log(' No more blocks with non-free operations backward.'); - return; - } - currentBlockNum = prev; - try { - const block = reader.readBlockByNum(prev); - if (block) showBlock(block); - else showBlockHeaderOnly(reader.readBlockHeaderByNum(prev), prev, 'Block returned null'); - } catch (e) { - showBlockHeaderOnly(reader.readBlockHeaderByNum(prev), prev, e.message); - } - return; - } - - // Slow fallback - for (let num = currentBlockNum - 1; num >= startBlock; num--) { - const block = safeReadBlock(num); - if (block && hasNonFreeOps(block)) { - currentBlockNum = num; - showBlock(block); - return; - } - if ((currentBlockNum - num) % 1000 === 0) { - process.stdout.write(`\r Scanning... #${num} `); - } - } - console.log('\r No more blocks with non-free operations backward. '); -} - -/** - * Run a search function in batches to avoid OOM. - * The checkFn receives (blockNum) and should return false to skip this block, - * or true to proceed with full deserialization via matchFn. - * matchFn receives (blockNum, block) and should return truthy to stop (the match). - * Calls onProgress(currentNum) for status updates. - */ -function batchSearch(checkFn, matchFn, onProgress, onDone) { - if (scanning) { console.log(' Already scanning.'); return; } - scanning = true; - const BATCH_SIZE = 10000; - let currentNum = currentBlockNum + 1; - - function processBatch() { - const batchEnd = Math.min(currentNum + BATCH_SIZE - 1, endBlock); - - for (let num = currentNum; num <= batchEnd; num++) { - // Lightweight pre-check: skip empty blocks - if (!checkFn(num)) continue; - - // Full deserialize only blocks that pass the check - const block = safeReadBlock(num); - if (block) { - const result = matchFn(num, block); - if (result) { - currentBlockNum = num; - scanning = false; - onDone(null); - return; - } - } - if ((num - currentNum) % 2000 === 0 && num > currentNum) { - onProgress(num); - } - } - - onProgress(batchEnd); - currentNum = batchEnd + 1; - if (currentNum <= endBlock) { - setImmediate(processBatch); - } else { - scanning = false; - onDone('not found'); - } - } - - processBatch(); -} - -function searchOpForward(name) { - lastSearch = { type: 's', term: name }; - console.log(` Searching for operation "${name}" forward from #${currentBlockNum + 1}...`); - - batchSearch( - (num) => { - // Skip blocks with no transactions (bitmask only — no per-block I/O) - if (bitmaskValid()) return bitmaskGet(num) === 1; - return true; // without bitmask, can't skip - }, - (num, block) => { - const ops = collectOps(block); - if (ops.some(o => o.typeName.includes(name))) { - showBlock(block); - showOps(block, name); - return true; - } - return false; - }, - (num) => process.stdout.write(`\r Scanning... #${num} `), - (err) => { - if (err === 'not found') console.log('\r No matching operations found. '); - else console.log('\r No more matching operations. '); - showPrompt(); - } - ); -} - -// ============================================================================ -// String Search in Operation JSON (including virtual ops) -// ============================================================================ - -/** - * Parse search term: strip surrounding quotes, detect = prefix for exact match. - * Returns { term: string, exact: boolean } - * Examples: - * '="V"' → { term: 'V', exact: true } - * '=V' → { term: 'V', exact: true } - * '"V"' → { term: 'V', exact: false } - * 'VIZ' → { term: 'VIZ', exact: false } - */ -function parseSearch(str) { - if (!str) return { term: str, exact: false }; - let exact = false; - if (str.startsWith('=')) { - exact = true; - str = str.slice(1); - } - if ((str.startsWith('"') && str.endsWith('"')) || - (str.startsWith("'") && str.endsWith("'"))) { - str = str.slice(1, -1); - } - return { term: str, exact }; -} - -/** - * Recursively walk an object looking for a string value matching searchStr. - * Zero-allocation: no JSON.stringify, just walks existing objects. - * If exact=true, uses === instead of .includes() for string values. - */ -function deepIncludes(obj, searchStr, exact) { - if (obj === null || obj === undefined) return false; - if (typeof obj === 'string') return exact ? (obj === searchStr) : obj.includes(searchStr); - if (typeof obj === 'number' || typeof obj === 'boolean') return false; - if (typeof obj === 'bigint') return exact ? (obj.toString() === searchStr) : obj.toString().includes(searchStr); - if (Buffer.isBuffer(obj)) return false; // skip binary - if (Array.isArray(obj)) { - for (let i = 0; i < obj.length; i++) { - if (deepIncludes(obj[i], searchStr, exact)) return true; - } - return false; - } - if (typeof obj === 'object') { - for (const key of Object.keys(obj)) { - if (exact ? (key === searchStr) : key.includes(searchStr)) return true; - if (deepIncludes(obj[key], searchStr, exact)) return true; - } - } - return false; -} - -/** - * Check if any operation in a block contains the search string. - * Uses recursive walk instead of JSON.stringify to avoid large temp strings. - * Returns matching operations array (empty if none). - */ -function findOpsByString(block, searchStr, exact) { - const ops = collectOps(block); - const matched = []; - for (const op of ops) { - if (op.typeName && (exact ? op.typeName === searchStr : op.typeName.includes(searchStr))) { - matched.push(op); - continue; - } - if (deepIncludes(op.data, searchStr, exact)) { - matched.push(op); - } - } - return matched; -} - -/** - * Deserialize a block from an existing raw buffer (no re-read, no 1MB over-allocate). - * Returns the block object or null on error. - */ -function deserializeFromRaw(rawBuf) { - try { - const br = new BinaryReader(rawBuf); - const block = readSignedBlock(br); - return block; - } catch (e) { - console.error(` deserializeFromRaw ERROR: ${e.message} (bufLen=${rawBuf.length})`); - return null; - } -} - -/** - * Fast raw ASCII byte search forward — no deserialization, just scans raw block bytes. - * Only finds ASCII strings (English, digits). Use S for UTF-8/emoji search. - */ -function searchRawForward(str) { - lastSearch = { type: 'R', term: str }; - if (scanning) { console.log(' Already scanning.'); return; } - scanning = true; - const YIELD_EVERY = 200; // raw scan is lighter, can do more per yield - let currentNum = currentBlockNum + 1; - - console.log(` Raw searching for ASCII "${str}" forward from #${currentNum}...`); - - function processChunk() { - const chunkEnd = Math.min(currentNum + YIELD_EVERY - 1, endBlock); - - const positions = reader.readBlockPosBatch(currentNum, chunkEnd - currentNum + 2); - if (positions.length === 0) { - currentNum = chunkEnd + 1; - setImmediate(processChunk); - return; - } - - for (let num = currentNum; num <= chunkEnd; num++) { - const i = num - currentNum; - const startPos = Number(positions[i]); - const endPos = (i + 1 < positions.length) ? Number(positions[i + 1]) : (Number(reader.dataSize) - 8); - const blockSize = endPos - startPos; - if (blockSize <= 0 || blockSize > CONSTANTS.CHAIN_BLOCK_SIZE + 16) continue; - - let rawBuf = null; - try { - rawBuf = reader._readData(BigInt(startPos), blockSize); - if (bufIncludesAscii(rawBuf, str)) { - // Found — deserialize to show context - const block = deserializeFromRaw(rawBuf); - rawBuf = null; - if (block) { - currentBlockNum = num; - showBlock(block); - showOps(block); - } else { - currentBlockNum = num; - console.log(` Block #${num} contains "${str}" in raw bytes (could not deserialize).`); - } - scanning = false; - showPrompt(); - return; - } - } catch (e) { /* skip */ } - rawBuf = null; // free buffer - } - - process.stdout.write(`\r Scanning... #${chunkEnd} `); - currentNum = chunkEnd + 1; - if (currentNum <= endBlock) { - setImmediate(processChunk); - } else { - console.log('\r No blocks containing ASCII "' + str + '" found. '); - scanning = false; - showPrompt(); - } - } - - processChunk(); -} - -/** - * Search forward for next block containing string in any operation's JSON. - * Only deserializes blocks that have operations (bitmask or tx-count filter). - * Yields to event loop every YIELD_EVERY blocks so GC can reclaim memory. - * Supports UTF-8, emoji, and any string in operation data. - */ -function searchStringForward(str, exact) { - lastSearch = { type: 'S', term: str, exact: !!exact }; - if (scanning) { console.log(' Already scanning.'); return; } - scanning = true; - const YIELD_EVERY = 100; - let currentNum = currentBlockNum + 1; - - console.log(` Searching for ${exact ? 'exact' : 'substring'} "${str}" in op JSON forward from #${currentNum}...`); - - function processChunk() { - const chunkEnd = Math.min(currentNum + YIELD_EVERY - 1, endBlock); - - // Read index positions in bulk for this chunk - const positions = reader.readBlockPosBatch(currentNum, chunkEnd - currentNum + 2); - if (positions.length === 0) { - currentNum = chunkEnd + 1; - setImmediate(processChunk); - return; - } - - for (let num = currentNum; num <= chunkEnd; num++) { - const i = num - currentNum; - - // Skip blocks with no operations (bitmask only — no per-block I/O) - if (bitmaskValid() && bitmaskGet(num) === 0) continue; - - // Read exact-size bytes and deserialize - const startPos = Number(positions[i]); - const endPos = (i + 1 < positions.length) ? Number(positions[i + 1]) : (Number(reader.dataSize) - 8); - const blockSize = endPos - startPos; - if (blockSize <= 0 || blockSize > CONSTANTS.CHAIN_BLOCK_SIZE + 16) continue; - - // Debug: log block number and size every 1000 blocks or if block is large - if (num % 1000 === 0 || blockSize > 100000) { - const memMB = process.memoryUsage().heapUsed / 1024 / 1024; - process.stdout.write(`\r #${num} size=${blockSize} heap=${memMB.toFixed(0)}MB \n`); - } - - let rawBuf = null; - let block = null; - try { - rawBuf = reader._readData(BigInt(startPos), blockSize); - block = deserializeFromRaw(rawBuf); - } catch (e) { /* skip */ } - rawBuf = null; - - if (block) { - const matched = findOpsByString(block, str, exact); - if (matched.length > 0) { - currentBlockNum = num; - showBlock(block); - for (const op of matched) { - const tag = op.isVirtual ? '[V]' : ' '; - console.log(` ${tag} ${op.typeName}`); - try { - const json = JSON.stringify(op.data, (key, val) => { - if (val && val.type === 'Buffer') return ``; - if (Buffer.isBuffer(val)) return ``; - if (typeof val === 'bigint') return val.toString(); - return val; - }, 2); - for (const line of json.split('\n')) { - console.log(' ' + line); - } - } catch (e) { - console.log(' (serialization error)'); - } - console.log(''); - } - scanning = false; - showPrompt(); - return; - } - } - block = null; - } - - process.stdout.write(`\r Scanning... #${chunkEnd} `); - currentNum = chunkEnd + 1; - if (currentNum <= endBlock) { - setImmediate(processChunk); - } else { - console.log('\r No matching operations found. '); - scanning = false; - showPrompt(); - } - } - - processChunk(); -} - -/** - * JSON replacer for Buffer/bigint serialization - */ -function jsonReplacer(key, val) { - if (val && val.type === 'Buffer' && Array.isArray(val.data)) return Buffer.from(val.data).toString('hex'); - if (Buffer.isBuffer(val)) return val.toString('hex'); - if (typeof val === 'bigint') return val.toString(); - return val; -} - -/** - * Search all blocks and export matching operations to JSON file. - * Streams results to disk: writes each chunk's matches as JSON objects, - * then clears them from memory. Yields every YIELD_EVERY blocks for GC. - * Final file = "[" + obj1 + "," + obj2 + ... + "]". - */ -function searchExport(str, exact) { - lastSearch = { type: 'e', term: str, exact: !!exact }; - if (scanning) { console.log(' Already scanning.'); return; } - scanning = true; - - let matchCount = 0; - let blockCount = 0; - let writtenBytes = 0; - const total = endBlock - startBlock + 1; - let lastPct = -1; - const YIELD_EVERY = 100; - let currentNum = startBlock; - let needComma = false; // whether to prepend "," before next object - - // Open export file, write opening "[" - const unixTime = Math.floor(Date.now() / 1000); - const outPath = path.join(path.dirname(reader.dataPath), `search_export_${unixTime}.json`); - const fd = fs.openSync(outPath, 'w'); - fs.writeSync(fd, '[\n', null, 'utf8'); - writtenBytes += 2; - - console.log(` Exporting all operations ${exact ? 'exactly matching' : 'containing'} "${str}" from #${startBlock} to #${endBlock}...`); - console.log(` Output: ${path.basename(outPath)}`); - - function processChunk() { - const chunkEnd = Math.min(currentNum + YIELD_EVERY - 1, endBlock); - - // Read index positions in bulk - const positions = reader.readBlockPosBatch(currentNum, chunkEnd - currentNum + 2); - - for (let num = currentNum; num <= chunkEnd; num++) { - const i = num - currentNum; - - // Skip blocks with no operations (bitmask only — no per-block I/O) - if (bitmaskValid() && bitmaskGet(num) === 0) continue; - - const startPos = (i < positions.length) ? Number(positions[i]) : 0; - const endPos = (i + 1 < positions.length) ? Number(positions[i + 1]) : 0; - const blockSize = endPos - startPos; - if (blockSize <= 0 || blockSize > CONSTANTS.CHAIN_BLOCK_SIZE + 16) continue; - - // Debug: log block number and size every 1000 blocks or if block is large - if (num % 1000 === 0 || blockSize > 100000) { - const memMB = process.memoryUsage().heapUsed / 1024 / 1024; - process.stdout.write(`\r #${num} size=${blockSize} heap=${memMB.toFixed(0)}MB \n`); - } - - // Read exact-size bytes and deserialize - let rawBuf = null; - let block = null; - try { - rawBuf = reader._readData(BigInt(startPos), blockSize); - block = deserializeFromRaw(rawBuf); - } catch (e) { /* skip */ } - rawBuf = null; - - if (block) { - const matched = findOpsByString(block, str, exact); - if (matched.length > 0) { - blockCount++; - for (const op of matched) { - matchCount++; - // Flush each op immediately — don't accumulate references - const prefix = needComma ? ',\n' : ''; - needComma = true; - const record = { - block: num, - timestamp: formatTimestamp(block.timestamp), - witness: block.witness, - typeId: op.typeId, - typeName: op.typeName, - isVirtual: op.isVirtual, - data: op.data - }; - const json = JSON.stringify(record, jsonReplacer, 2); - const chunk = prefix + json; - fs.writeSync(fd, chunk, null, 'utf8'); - writtenBytes += Buffer.byteLength(chunk, 'utf8'); - } - } - } - block = null; - } - - const pct = Math.floor(((chunkEnd - startBlock) / total) * 100); - if (pct !== lastPct && pct % 5 === 0) { - lastPct = pct; - const sizeMB = (writtenBytes / 1024 / 1024).toFixed(1); - process.stdout.write(`\r Scanning... ${pct}% (#${chunkEnd}, ${matchCount} ops in ${blockCount} blocks, ${sizeMB} MB written) `); - } else { - process.stdout.write(`\r Scanning... #${chunkEnd} (${matchCount} ops) `); - } - - currentNum = chunkEnd + 1; - if (currentNum <= endBlock) { - setImmediate(processChunk); - } else { - // Close the JSON array - fs.writeSync(fd, '\n]', null, 'utf8'); - writtenBytes += 2; - fs.closeSync(fd); - - if (matchCount === 0) { - // Remove empty file - fs.unlinkSync(outPath); - console.log('\r No matching operations found. '); - } else { - const sizeMB = (writtenBytes / 1024 / 1024).toFixed(1); - console.log(`\r Done. ${matchCount} ops in ${blockCount} blocks. Saved ${sizeMB} MB to ${path.basename(outPath)} `); - } - scanning = false; - showPrompt(); - } - } - - processChunk(); -} - -function showCurrentOps(filter) { - try { - const block = reader.readBlockByNum(currentBlockNum); - if (!block) { console.log('No current block (deserialization failed).'); return; } - showOps(block, filter || null); - } catch (e) { - console.log(`Cannot show ops: ${e.message}`); - } -} - -function showCurrentInfo() { - try { - const block = reader.readBlockByNum(currentBlockNum); - if (!block) { - const header = reader.readBlockHeaderByNum(currentBlockNum); - showBlockHeaderOnly(header, currentBlockNum, 'Full deserialization failed'); - return; - } - showBlock(block); - } catch (e) { - const header = reader.readBlockHeaderByNum(currentBlockNum); - showBlockHeaderOnly(header, currentBlockNum, e.message); - } -} - -function showBlockHex() { - const raw = reader.readBlockRawData(currentBlockNum); - if (!raw) { - console.log(`Block #${currentBlockNum} raw data not available (out of range).`); - return; - } - - const pos = reader.getBlockPos(currentBlockNum); - console.log(''); - console.log(`Raw block #${currentBlockNum}: offset ${pos}, ${raw.length} bytes`); - console.log('='.repeat(73)); - - const BYTES_PER_LINE = 16; - for (let offset = 0; offset < raw.length; offset += BYTES_PER_LINE) { - const slice = raw.slice(offset, Math.min(offset + BYTES_PER_LINE, raw.length)); - const hexParts = []; - const asciiParts = []; - - for (let i = 0; i < BYTES_PER_LINE; i++) { - if (i < slice.length) { - hexParts.push(slice.readUInt8(i).toString(16).padStart(2, '0')); - const c = slice.readUInt8(i); - asciiParts.push(c >= 0x20 && c < 0x7f ? String.fromCharCode(c) : '.'); - } else { - hexParts.push(' '); - asciiParts.push(' '); - } - if (i === 7) hexParts.push(''); // extra space in the middle - } - - const addr = offset.toString(16).padStart(8, '0'); - console.log(` ${addr} ${hexParts.join(' ')} |${asciiParts.join('')}|`); - } - - console.log('='.repeat(73)); - console.log(` ${raw.length} bytes total`); - - // Also show as continuous hex on one line for easy copy - const hexLine = raw.toString('hex'); - console.log(` Hex (first 128 bytes): ${hexLine.slice(0, 256)}`); - if (hexLine.length > 256) { - console.log(` ... (${hexLine.length / 2 - 128} more bytes)`); - } -} - -// ============================================================================ -// Main Loop -// ============================================================================ - -function main() { - const args = process.argv.slice(2); - if (args.length < 1) { - console.log('Usage: node block-log-viewer.js [--dlt] [--reader=]'); - console.log(''); - console.log(' can be:'); - console.log(' - Path to block_log or dlt_block_log file directly'); - console.log(' - Path to directory containing block_log / dlt_block_log'); - console.log(''); - console.log('Options:'); - console.log(' --dlt Use DLT (rolling) block log reader'); - console.log(' --reader= Path to block-log-reader.js module'); - process.exit(1); - } - - let dataPath = args.find(a => !a.startsWith('--')); - let isDlt = args.includes('--dlt'); - - // If path is a directory, auto-detect block_log or dlt_block_log inside it - if (fs.existsSync(dataPath) && fs.statSync(dataPath).isDirectory()) { - const dltPath = path.join(dataPath, 'dlt_block_log'); - const stdPath = path.join(dataPath, 'block_log'); - - if (!isDlt && fs.existsSync(dltPath) && !fs.existsSync(stdPath)) { - // Only dlt_block_log exists — auto-switch to DLT mode - dataPath = dltPath; - isDlt = true; - } else if (isDlt) { - if (!fs.existsSync(dltPath)) { - console.log(`dlt_block_log not found in: ${dataPath}`); - process.exit(1); - } - dataPath = dltPath; - } else { - if (!fs.existsSync(stdPath)) { - console.log(`block_log not found in: ${dataPath}`); - process.exit(1); - } - dataPath = stdPath; - } - } - - if (!fs.existsSync(dataPath)) { - console.log(`File not found: ${dataPath}`); - process.exit(1); - } - - try { - reader = createBlockLogReader(dataPath, undefined, isDlt); - } catch (e) { - console.log(`Failed to open block log: ${e.message}`); - process.exit(1); - } - - startBlock = reader.getStartBlockNum(); - endBlock = reader.getHeadBlockNum(); - - if (endBlock === 0) { - console.log('Block log appears empty (index has no entries).'); - reader.close(); - process.exit(1); - } - - console.log(''); - console.log(`VIZ Block Log Viewer`); - console.log(` File : ${dataPath}`); - console.log(` Type : ${isDlt ? 'DLT (rolling)' : 'Standard'}`); - console.log(` Blocks : #${startBlock} - #${endBlock} (${endBlock - startBlock + 1} total)`); - - // Try to load bitmask - const bmLoaded = bitmaskLoad(); - if (bmLoaded) { - console.log(` Bitmask : LOADED (${path.basename(bitmaskPath())})`); - } else if (bitmask) { - console.log(` Bitmask : outdated, run 'scan' to rebuild`); - } else { - console.log(` Bitmask : not found, run 'scan' to build`); - } - console.log(''); - - // Show first block - goTo(startBlock); - showHelp(); - - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - prompt: '' - }); - - const onLine = (line) => { - if (scanning) return; // ignore input during scan - const trimmed = line.trim(); - if (!trimmed) { showPrompt(); return; } - - const parts = trimmed.split(/\s+/); - const cmd = parts[0]; - - switch (cmd) { - case 'f': goFirst(); break; - case 'l': goLast(); break; - case 'n': goNext(); break; - case 'p': goPrev(); break; - case 'N': goNextWithOps(); break; - case 'P': goPrevWithOps(); break; - case 'scan': bitmaskScan(); break; - case 'g': { - const num = parseInt(parts[1], 10); - if (isNaN(num)) { console.log('Usage: g '); break; } - goTo(num); - break; - } - case 'o': { - showCurrentOps(parts.slice(1).join(' ') || null); - break; - } - case 's': { - const name = parts.slice(1).join(' '); - if (!name) { console.log('Usage: s '); break; } - searchOpForward(name); - break; - } - case 'S': { - const { term, exact } = parseSearch(parts.slice(1).join(' ')); - if (!term) { console.log('Usage: S (prefix with = for exact match, e.g. S ="V")'); break; } - searchStringForward(term, exact); - break; - } - case 'R': { - const { term } = parseSearch(parts.slice(1).join(' ')); - if (!term) { console.log('Usage: R (ASCII only)'); break; } - searchRawForward(term); - break; - } - case 'e': { - const { term, exact } = parseSearch(parts.slice(1).join(' ')); - if (!term) { console.log('Usage: e (prefix with = for exact match, e.g. e ="V")'); break; } - searchExport(term, exact); - break; - } - case 'c': { - if (!lastSearch) { console.log('No previous search. Use s, S, R, or e first.'); break; } - if (lastSearch.type === 's') searchOpForward(lastSearch.term); - else if (lastSearch.type === 'S') searchStringForward(lastSearch.term, lastSearch.exact); - else if (lastSearch.type === 'R') searchRawForward(lastSearch.term); - else if (lastSearch.type === 'e') searchExport(lastSearch.term, lastSearch.exact); - break; - } - case 'i': showCurrentInfo(); break; - case 'hex': showBlockHex(); break; - case 'h': showHelp(); break; - case 'q': - console.log('Bye.'); - reader.close(); - process.exit(0); - break; - default: - // Allow raw number input to jump to block - const maybeNum = parseInt(cmd, 10); - if (!isNaN(maybeNum) && parts.length === 1) { - goTo(maybeNum); - } else { - console.log(`Unknown command: ${cmd}. Type h for help.`); - } - } - showPrompt(); - }; - - rl.on('line', onLine); - showPrompt(); -} - -main(); diff --git a/.qoder/docs/block-processing.md b/.qoder/docs/block-processing.md deleted file mode 100644 index 82ed5e64c0..0000000000 --- a/.qoder/docs/block-processing.md +++ /dev/null @@ -1,413 +0,0 @@ -# VIZ Blockchain — Block Processing & Pending Transactions - -Internal mechanics of block application, transaction queuing, and the pending transaction lifecycle. - ---- - -## Overview - -When a node receives a new block via P2P, it must: -1. Temporarily remove its pending (mempool) transactions from the database -2. Apply the incoming block -3. Re-apply the pending transactions that were not included in the block - -This process is managed by the `without_pending_transactions` helper in `db_with.hpp`. - ---- - -## Key Data Structures - -| Structure | Type | Location | Purpose | -|---|---|---|---| -| `_pending_tx` | `vector` | `database.hpp:473` | Transactions received from the network, waiting to be included in a block | -| `_popped_tx` | `deque` | `database.hpp:472` | Transactions from a popped block (during fork switch), to be re-applied | -| `_pending_tx_session` | `optional` | `database.hpp:517` | Undo session covering all pending transaction state changes | - ---- - -## Block Application Flow - -### `push_block()` → `without_pending_transactions()` - -``` -push_block(new_block) - └─ without_pending_transactions(db, skip, _pending_tx, callback) - ├─ pending_transactions_restorer constructor: clear_pending() - ├─ callback: _push_block(new_block) ← apply the incoming block - └─ ~pending_transactions_restorer() ← restore pending transactions -``` - -Source: [database.cpp:897-920](../../libraries/chain/database.cpp#L897) - -The destructor of `pending_transactions_restorer` is where the "Postponed" log messages appear. - ---- - -## Pending Transaction Restoration (Destructor Logic) - -Source: [db_with.hpp](../../libraries/chain/include/graphene/chain/db_with.hpp) - -The destructor processes two lists in order: - -### Step 1: Re-apply `_popped_tx` (from fork switches) - -``` -for each tx in _popped_tx: - if time limit exceeded → push to _pending_tx (postpone) - else if is_known_transaction → skip (already in chain) - else → _push_transaction(tx) → applied_txs++ -``` - -### Step 2: Re-apply `_pending_transactions` (original mempool) - -``` -for each tx in _pending_transactions: - if time limit exceeded → push to _pending_tx (postpone) - else if is_known_transaction → skip (already in the new block) - else → _push_transaction(tx) → applied_txs++ - on transaction_exception → dlog (invalid, discard) - on fc::exception → silently discard -``` - -### Step 3: Log summary - -If any transactions were postponed, a single warning is logged: -``` -Postponed N pending transactions. M were applied. -``` - ---- - -## Time Limit: CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT - -**Value:** `fc::milliseconds(200)` ([config.hpp:141](../../libraries/protocol/include/graphene/protocol/config.hpp#L141)) - -The destructor tracks elapsed time since the start of restoration. Once 200ms is exceeded, all remaining transactions are postponed (pushed back to `_pending_tx`) without attempting to apply them. This prevents the node from blocking for too long when re-applying a large number of pending transactions. - -### When the time limit triggers - -- High transaction throughput blocks (many pending txs to restore) -- Slow individual transaction evaluation (complex operations) -- System under load (CPU contention) - ---- - -## Block Size Limit: CHAIN_BLOCK_GENERATION_POSTPONED_TX_LIMIT - -**Value:** `5` ([config.hpp:140](../../libraries/protocol/include/graphene/protocol/config.hpp#L140)) - -During block **generation** (`_generate_block`), transactions that would exceed `maximum_block_size` are skipped. After `CHAIN_BLOCK_GENERATION_POSTPONED_TX_LIMIT` consecutive oversized transactions, the loop breaks entirely. These transactions remain in `_pending_tx` for the next block. - -This is a different code path from the `pending_transactions_restorer` and produces a separate log: -``` -Postponed N transactions due to block size limit -``` - -Source: [database.cpp:1125-1160](../../libraries/chain/database.cpp#L1125) - ---- - -## Fork DB Head-Seeding - -Source: [database.cpp `_push_block`](../../libraries/chain/database.cpp) - -Before pushing a block to `fork_db`, `_push_block()` ensures the current database head block is present in `fork_db`. After snapshot import, stale sync recovery, or fork_db trimming, the head block may be absent from `fork_db`'s `_index`. - -Without this seed, any block whose `previous == head_block_id()` would throw `unlinkable_block_exception` inside `fork_database::_push_block()` ("block does not link to known chain"), silently rejecting valid next-blocks and preventing head advancement. - -``` -if new_block.previous == head_block_id() - AND head_block_id() NOT in fork_db: - fetch head block from block log - fork_db.start_block(head_block) ← seeds fork_db with the head -``` - -This also fixes **validator nodes that generate their own blocks**: `generate_block()` sets `pending_block.previous = head_block_id()`, and without the seed the self-generated block would fail to push into `fork_db`. - ---- - -## Direct-Extension Bypass - -Source: [database.cpp `_push_block`](../../libraries/chain/database.cpp) - -After pushing a block to `fork_db`, `_push_block()` checks whether the block directly extends the database head (`new_block.previous == head_block_id()`). If so, the fork switch logic is bypassed entirely and the block falls through to `apply_block()`. - -This handles the case where `fork_db._head` points to a stale higher block accumulated from previous failed sync cycles (stale sync recovery does not reset `fork_db`). Without this bypass: - -1. `fork_db.push_block()` returns the stale `_head` (e.g., block #79609893) -2. `new_head->data.previous != head_block_id()` evaluates to TRUE -3. The fork switch logic either rejects the block (head not in fork_db) or can't compare branches -4. The valid next-block is silently dropped, head never advances - -``` -if new_block.previous == head_block_id(): - → skip fork switch, fall through to apply_block -else if new_head->data.previous != head_block_id(): - → existing fork switch logic (unchanged) -``` - -Together with fork_db head-seeding, this ensures blocks that correctly link to the database head are always applied, regardless of `fork_db`'s internal `_head` state. - ---- - -## Fork Switch Flow - -When a node switches to a different fork: - -1. `pop_block()` removes the current head block - - Transactions from the popped block are saved to `_popped_tx` - - Source: [database.cpp](../../libraries/chain/database.cpp) - -2. The new block is applied via `push_block()` - -3. In `~pending_transactions_restorer()`: - - `_popped_tx` transactions are processed first (from the old fork) - - Then original `_pending_transactions` are processed - - Duplicate transactions (already in the new chain) are silently skipped - -### Linear Extension vs. Actual Fork - -When `fork_db._push_next()` auto-links orphan blocks from the unlinked index, the fork_db head can jump multiple blocks ahead of the database head in a single `push_block()` call. This triggers the fork switch code path (`new_head->data.previous != head_block_id()`), but there is no actual fork — the new chain extends directly from the current head. - -`fetch_branch_from(new_head, head_block_id)` always appends the common ancestor to **both** branches. For a linear extension, the common ancestor IS the current head: -- `branches.first` = `[new_tip, ..., HEAD]` (blocks to apply + common ancestor) -- `branches.second` = `[HEAD]` (just the common ancestor) - -**Detection:** `is_linear_extension = branches.second.size() == 1 && branches.second.back()->id == head_block_id()`. - -**Behavior when linear:** -- Skip the pop loop entirely (the common ancestor is already applied, no blocks to undo) -- Skip the common ancestor when applying `branches.first` (avoid re-applying HEAD) -- On error: pop any newly applied blocks back to the common ancestor, set fork_db head to it - -**Why this matters in DLT mode:** In DLT mode, LIB = head, so undo sessions are committed (not just pushed). `pop_block()` → `undo()` has no effect — `head_block_id()` never changes. The pop loop becomes infinite, eventually emptying the fork_db and crashing with "popping head block would leave fork DB empty". - -For **actual forks** (`branches.second.size() > 1` or common ancestor != head), the original behavior is preserved: pop old-fork blocks including the common ancestor, then re-apply the common ancestor and new-fork blocks from `branches.first`. - -### Debug Logging - -Diagnostic logs at every `pop_block()` call site: - -| Log prefix | Location | Meaning | -|---|---|---| -| `Fork switch: new_head=#X, db_head=#Y, branches.first=N, branches.second=M` | Before fork switch | Shows branch sizes; `branches.second=0` = linear extension | -| `FORK-SWITCH-POP: popping head #H` | Main pop loop | Normal fork switch pop | -| `FORK-RECOVER-POP: popping head #H` | Error recovery pop loop | Reverting failed fork switch | -| `POP_BLOCK: db_head=#X, fork_db_head=#Y, fork_db_head_prev=Z` | Inside `database::pop_block()` | Fork_db state before every pop; `prev=0` = root block (will crash) | - ---- - -## Orphan Block Handling (Unlinked Index) - -Source: [database.cpp `_push_block`](../../libraries/chain/database.cpp), [fork_database.cpp](../../libraries/chain/fork_database.cpp) - -When a block arrives whose parent is unknown (missed broadcast), the node can either reject it or defer it for later linking. - -### Pre-check in `_push_block()` - -``` -if block.num > head_num - AND block.previous != head_block_id - AND block.previous not in fork_db: - if gap > 100 → reject (too far ahead, avoid memory bloat) - if gap <= 100 → allow through to fork_db -``` - -Blocks within 100 of head pass to `fork_db.push_block()`, which throws `unlinkable_block_exception` but stores the block in `_unlinked_index` first. - -### Auto-linking via `_push_next()` - -When the missing parent block finally arrives and is pushed to fork_db: -1. `_push_block(parent)` links the parent to the chain -2. `_push_next(parent)` searches `_unlinked_index` for children of `parent` -3. Found children are moved from `_unlinked_index` to `_index` and recursively linked -4. fork_db head may jump multiple blocks ahead in one call - -This triggers the linear extension fork switch (see above). - -### P2P Recovery - -When `unlinkable_block_exception` propagates to the P2P layer (`process_block_during_normal_operation`): -- Block **at or below head** → strike counter incremented (soft-ban after 20 strikes) -- Block **ahead of head** → `start_synchronizing_with_peer()` restarts sync to fetch the missing block - ---- - -## Peer Strike-Based Soft-Ban - -Source: [node.cpp](../../libraries/network/node.cpp), [peer_connection.hpp](../../libraries/network/include/graphene/network/peer_connection.hpp) - -Peers are not immediately soft-banned for sending unlinkable or rejected blocks. Instead, a strike counter accumulates: - -| Path | Threshold | Counter field | -|---|---|---| -| Normal operation: unlinkable block at/below head | 20 strikes | `unlinkable_block_strikes` | -| Sync path: generic block rejection | 20 strikes | `unlinkable_block_strikes` | -| Dead fork / block too old | Immediate | N/A | - -**Reset on valid block:** When a peer sends a block that is successfully accepted (normal or sync), their `unlinkable_block_strikes` counter resets to 0. This allows honest peers to recover from transient errors (snapshot reload, timing races, brief micro-forks). - ---- - -## Bug Fix: False "Postponed" Log Messages - -### Original Bug (fixed) - -In `db_with.hpp`, the `~pending_transactions_restorer()` destructor had three bugs on the logging line: - -```cpp -// BUGGY CODE (before fix) -if( postponed_txs++ ) { - wlog( "Postponed ${p} pending transactions. ${a} were applied.", ("p", postponed_txs)("a", applied_txs) ); -} -``` - -| Bug | Impact | -|---|---| -| `postponed_txs++` inside `if` condition | Double increment: once in `else` branch, once in `if` condition — inflated counter | -| Log inside the `for` loop | Message printed on every iteration after first increment, instead of once at the end | -| Counter incremented for skipped known transactions | Transactions already in the block (`is_known_transaction` = true) still triggered the `if(postponed_txs++)` check | - -### Example of False Output - -With 3 pending transactions that are all already in the incoming block: -``` -Postponed 2 pending transactions. 0 were applied. ← iteration 2 (postponed_txs was 1, now 2) -Postponed 3 pending transactions. 0 were applied. ← iteration 3 (postponed_txs was 2, now 3) -``` - -None of the transactions were actually postponed — they were already known, just skipped. - -### Fix - -Move the log outside the loop and remove the double increment: - -```cpp -// FIXED CODE -} // end of for loop -if( postponed_txs > 0 ) { - wlog( "Postponed ${p} pending transactions. ${a} were applied.", ("p", postponed_txs)("a", applied_txs) ); -} -``` - -Now the log only fires once, after both loops complete, with an accurate count of truly postponed transactions. - ---- - -## Bug Fix: Validator Plugin Option Parsing - -Source: [validator.cpp](../../plugins/validator/validator.cpp) - -### Bug 1: `enable-stale-production` with `implicit_value(false)` - -```cpp -// BUGGY CODE (before fix) -("enable-stale-production", bpo::value()->implicit_value(false), ...) -``` - -Using `--enable-stale-production` on the command line (without `=true`) would set the value to `false` — the same as the default. The flag was effectively a no-op unless you explicitly wrote `--enable-stale-production=true`. - -**Fix:** Changed to `implicit_value(true)` so the bare flag enables stale production as expected. - -### Bug 2: `required-participation` double-scaling - -```cpp -// BUGGY CODE (before fix) -("required-participation", bpo::value()->implicit_value(33), ...) -// ... -int e = options["required-participation"].as(); -_required_witness_participation = uint32_t(e * CHAIN_1_PERCENT); -``` - -The value passed by the user (e.g. `33` meaning 33%) was multiplied by `CHAIN_1_PERCENT` (100), producing 3300 basis points. This was correct for percentage input but: -- It was inconsistent with internal representation (basis points) -- Users putting basis points in config files would get 100× scaling -- `implicit_value(33)` made the bare flag `--required-participation` set 33%, but the behavior was unclear - -**Fix:** Changed to `default_value(33 * CHAIN_1_PERCENT)` and removed the multiplication in parsing. The value is now always in basis points (0–10000 = 0%–100%): - -```cpp -// FIXED CODE -("required-participation", bpo::value()->default_value(33 * CHAIN_1_PERCENT), ...) -// ... -_required_witness_participation = options["required-participation"].as(); -``` - ---- - -## Legitimate Reasons for Pending Transaction Postponement - -| Reason | Mechanism | Log | -|---|---|---| -| **200ms timeout exceeded** | `CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT` — remaining txs pushed to `_pending_tx` | `Postponed N pending transactions. M were applied.` | -| **Block size limit** (during generation) | `maximum_block_size` — oversized txs skipped, >5 consecutive → break | `Postponed N transactions due to block size limit` | -| **Transaction became invalid** | State changed by new block (e.g., account balance insufficient) | Caught by `fc::exception`, silently discarded | -| **Transaction already in block** | `is_known_transaction()` returns true | Silently skipped (no postpone, no log) | - ---- - -## validator Block Production Timing - -Source: [validator.cpp](../../plugins/validator/validator.cpp) - -### Production Loop Mechanism - -The Validator Plugin uses a timer-based production loop with a look-ahead to detect when it's time to produce a block: - -1. **Timer** fires every **250ms** (aligned to 250ms boundaries, minimum sleep 50ms) -2. On each tick, `maybe_produce_block()` computes `now = NTP_time + 250ms` (look-ahead) -3. `get_slot_at_time(now)` finds which slot corresponds to `now` -4. If the slot belongs to one of our validators and `|scheduled_time - now| <= 500ms`, the block is produced with `scheduled_time` as the timestamp - -The block timestamp is always the **deterministic slot time** (computed from `head_block_time` rounded to `CHAIN_BLOCK_INTERVAL` boundary + `slot_num × 3s`), never the current clock time. - -### Why 250ms tick + 250ms look-ahead? - -With these matching values, the tick at `T_slot - 250ms` aligns `now` exactly to the slot boundary: - -``` -Slot at T=6.000, tick at T=5.750: - now = 5.750 + 0.250 = 6.000 → slot matched → lag = 0ms → PRODUCE -``` - -This gives a **500ms safety margin** against the LAG threshold, compared to 0ms margin with the previous 1000ms tick + 500ms look-ahead. - -### Missed Block Behavior - -When a validator misses their slot, the production loop does NOT wait or retry. The next tick simply finds a later slot: - -``` -Slot T=3 missed (validator A absent): - Tick at T=3.000 → now=3.250 → slot=1 → validator A → not our validator → not_my_turn - (A's slot passes unclaimed) - -Slot T=6 (validator B - our validator): - Tick at T=5.750 → now=6.000 → slot=2 → validator B → PRODUCE with timestamp T=6.000 -``` - -When block at T=6 is pushed, `update_global_dynamic_data()` counts `missed_blocks = get_slot_at_time(6.000) - 1 = 1` and increments `current_aslot` accordingly. - -### Production Conditions (in order) - -| Check | Condition | Result if failed | -|---|---|---| -| Sync status | Chain is not stale (or `enable-stale-production`) | `not_synced` | -| Slot time | `get_slot_at_time(now) > 0` | `not_time_yet` | -| validator ownership | Scheduled validator is in our `_validators` set | `not_my_turn` | -| Signing key | validator has non-zero `signing_key` on chain | `not_my_turn` | -| Private key | We have the private key for the signing key | `no_private_key` | -| Participation | Network participation ≥ required (pre-HF12 only) | `low_participation` | -| Lag | `|scheduled_time - now| <= 500ms` | `lag` | -| Fork collision | No competing block at same height in fork_db | `fork_collision` | -| Minority fork | Last 21 blocks NOT all from our own validators (or `enable-stale-production` or emergency mode) | `minority_fork` | - ---- - -## Configuration Constants - -| Constant | Value | Purpose | -|---|---|---| -| `CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT` | 200ms | Max time to spend re-applying pending txs after block push | -| `CHAIN_BLOCK_GENERATION_POSTPONED_TX_LIMIT` | 5 | Max consecutive oversized txs to skip during block generation | -| `CHAIN_BLOCK_SIZE` | 65536 bytes | Hard limit on block size | -| `maximum_block_size` | Dynamic (validator median) | Soft limit on block size | diff --git a/.qoder/docs/chain-properties-governance.md b/.qoder/docs/chain-properties-governance.md deleted file mode 100644 index f147a95648..0000000000 --- a/.qoder/docs/chain-properties-governance.md +++ /dev/null @@ -1,235 +0,0 @@ -# Chain Properties: How validators Govern Network Parameters - -## Overview - -In VIZ, there is no central authority that sets network fees, block sizes, inflation rates, or other critical parameters. Instead, **every active validator publishes their preferred values**, and the blockchain automatically calculates the **median** — the middle value that represents the consensus of all elected validators. - -Since validators are elected by stake-weighted voting from all SHARES holders, chain properties are ultimately governed by the community: users vote for validators whose parameter choices align with their vision of the public good. - ---- - -## How It Works - -### Step 1: validators Publish Their Preferences - -Each validator publishes their preferred chain properties using the `versioned_chain_properties_update_operation`: - -```json -["versioned_chain_properties_update", { - "owner": "witness1", - "props": [3, { - "account_creation_fee": "1.000 VIZ", - "maximum_block_size": 131072, - "create_account_delegation_ratio": 10, - "create_account_delegation_time": 2592000, - "min_delegation": "1.000 VIZ", - "min_curation_percent": 0, - "max_curation_percent": 10000, - "bandwidth_reserve_percent": 1000, - "bandwidth_reserve_below": "500.000000 SHARES", - "flag_energy_additional_cost": 0, - "vote_accounting_min_rshares": 5000000, - "committee_request_approve_min_percent": 1000, - "inflation_witness_percent": 2000, - "inflation_ratio_committee_vs_reward_fund": 5000, - "inflation_recalc_period": 806400, - "data_operations_cost_additional_bandwidth": 0, - "witness_miss_penalty_percent": 100, - "witness_miss_penalty_duration": 86400, - "create_invite_min_balance": "10.000 VIZ", - "committee_create_request_fee": "100.000 VIZ", - "create_paid_subscription_fee": "100.000 VIZ", - "account_on_sale_fee": "10.000 VIZ", - "subaccount_on_sale_fee": "100.000 VIZ", - "witness_declaration_fee": "10.000 VIZ", - "withdraw_intervals": 28 - }] -} -``` - -The `[3, {...}]` format indicates the version — `3` means `chain_properties_hf9` (the latest). Older versions (`0` = init, `1` = hf4, `2` = hf6) are accepted for backward compatibility. - -### Step 2: Median Calculation - -Every time the validator schedule is updated, the blockchain runs `update_median_witness_props()`. For **each property independently**: - -1. Collect the property value from every active validator -2. Sort the values -3. Pick the **median** (the middle value) - -``` -Example: 5 validators set account_creation_fee to: - 0.5 VIZ, 1.0 VIZ, 1.0 VIZ, 2.0 VIZ, 5.0 VIZ - ↑ - median = 1.0 VIZ -``` - -The algorithm uses `std::nth_element` with position `active.size() / 2`, which selects the value at the middle index after partial sorting. - -**Why median?** The median is resistant to extremes. A single validator cannot push a parameter to an absurdly high or low value — they can only shift the median by one position. To change a parameter significantly, a **majority of active validators** must agree. - -### Step 3: Application - -The calculated `median_props` is stored in the `witness_schedule_object` and used across the entire blockchain to enforce rules. - ---- - -## All Governable Properties - -### Account & Delegation Rules - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `account_creation_fee` | asset (VIZ) | 1.000 VIZ | Minimum fee to create a new account | -| `create_account_delegation_ratio` | uint32 | 10 | Multiplier: delegation = ratio × fee | -| `create_account_delegation_time` | uint32 (sec) | 30 days | How long creation delegation is locked | -| `min_delegation` | asset (VIZ) | 1.000 VIZ | Minimum amount for any delegation | - -**How it's used**: When someone creates a new account, they must pay at least `account_creation_fee` and provide delegation of at least `ratio × fee` in SHARES equivalent. The delegation is locked for `create_account_delegation_time`. This prevents cheap mass account creation (Sybil attacks) while keeping the network accessible. - -### Block Size & Bandwidth - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `maximum_block_size` | uint32 (bytes) | 131072 | Maximum block size — controls network throughput | -| `bandwidth_reserve_percent` | int16 (bp) | 1000 (10%) | Extra bandwidth for small accounts | -| `bandwidth_reserve_below` | asset (SHARES) | 500.000000 | Threshold for bandwidth reserve | -| `data_operations_cost_additional_bandwidth` | uint32 (%) | 0 | Extra bandwidth cost for data-heavy operations | - -**How it's used**: Transaction bandwidth is allocated proportionally to SHARES. Accounts below `bandwidth_reserve_below` get an additional `bandwidth_reserve_percent` reserve so they can still transact. `maximum_block_size` directly controls how many transactions the network can process per block. - -### Inflation & Economics - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `inflation_witness_percent` | int16 (bp) | 2000 (20%) | validator share of block inflation | -| `inflation_ratio_committee_vs_reward_fund` | int16 (bp) | 5000 (50%) | How remaining inflation is split between committee fund and reward fund | -| `inflation_recalc_period` | uint32 (blocks) | 806400 (28 days) | How often inflation parameters are recalculated | - -**How it's used**: Each block creates new tokens (inflation). First, `inflation_witness_percent` goes to the block-producing validator. The remainder is split: `inflation_ratio_committee_vs_reward_fund` percent goes to the committee DAO fund, the rest to the reward fund (used for awards). validators directly control how the economy works. - -### Reward System - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `min_curation_percent` | int16 (bp) | 500 (5%) | Minimum curation reward share | -| `max_curation_percent` | int16 (bp) | 500 (5%) | Maximum curation reward share | -| `vote_accounting_min_rshares` | uint32 | 5000000 | Minimum rshares for an award to have effect | -| `flag_energy_additional_cost` | int16 (bp) | 0 | Extra energy cost for downvoting | - -**How it's used**: When content receives awards, curation rewards are bounded by `[min_curation_percent, max_curation_percent]`. Awards with fewer than `vote_accounting_min_rshares` rshares produce zero reward (dust filter). `flag_energy_additional_cost` can make downvotes more expensive than upvotes. - -### validator Accountability - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `witness_miss_penalty_percent` | int16 (bp) | 100 (1%) | Vote reduction for missing a block | -| `witness_miss_penalty_duration` | uint32 (sec) | 86400 (1 day) | How long the penalty lasts | - -**How it's used**: When a validator misses their scheduled block, their effective votes are reduced by `witness_miss_penalty_percent` for `witness_miss_penalty_duration` seconds. This is self-governing accountability: validators vote on how harshly missed blocks are punished. - -### Fee Structure - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `committee_create_request_fee` | asset (VIZ) | 100.000 VIZ | Fee to create a DAO proposal | -| `create_paid_subscription_fee` | asset (VIZ) | 100.000 VIZ | Fee to create a paid subscription | -| `account_on_sale_fee` | asset (VIZ) | 10.000 VIZ | Fee to list an account for sale | -| `subaccount_on_sale_fee` | asset (VIZ) | 100.000 VIZ | Fee to list subaccounts for sale | -| `witness_declaration_fee` | asset (VIZ) | 10.000 VIZ | One-time fee for new validator registration | -| `create_invite_min_balance` | asset (VIZ) | 10.000 VIZ | Minimum balance to create an invite | - -**How it's used**: All fees go to the **committee fund** (DAO treasury). validators control how expensive various network operations are. Higher fees discourage spam; lower fees improve accessibility. The community decides the balance through validator elections. - -### Vesting Withdrawal - -| Property | Type | Default | What It Controls | -|---|---|---|---| -| `withdraw_intervals` | uint16 | 28 | Number of daily installments for unstaking | - -**How it's used**: When a user unstakes SHARES, the withdrawal happens over `withdraw_intervals` days (one installment per day). validators can make unstaking faster or slower, affecting how liquid the network's governance token is. - ---- - -## The Governance Loop: Users → validators → Parameters - -### Users Shape the Network Through validator Selection - -Users cannot directly set chain properties. Instead, they **vote for validators** whose published properties match their preferences. This creates a representative governance system: - -``` -Users (SHARES holders) - │ - ├── Vote for validators who want LOW fees - │ → More validators with low fee props get elected - │ → Median fees decrease - │ - ├── Vote for validators who want HIGH inflation to reward fund - │ → More reward-focused validators get elected - │ → Inflation shifts toward reward fund - │ - └── Vote for validators who want STRICT miss penalties - → More accountability-focused validators get elected - → Miss penalties increase -``` - -### Why This Is a Public Good Mechanism - -Traditional blockchains set parameters through hard-coded values or foundation decisions. VIZ makes **every parameter a public good decision**: - -1. **Transparency**: every validator's preferred properties are on-chain and publicly visible -2. **Accountability**: if a validator sets harmful parameters, users can unvote them -3. **Gradual change**: the median shifts slowly — no single validator can cause sudden parameter swings -4. **No single point of failure**: even if some validators are compromised, the median protects the network -5. **Aligned incentives**: validators earn block rewards, so they're incentivized to keep the network healthy - -### Example: How a Fee Change Happens - -Suppose the community wants to lower the `committee_create_request_fee` from 100 VIZ to 50 VIZ: - -1. Users discuss in community channels that the fee is too high -2. Some validators update their properties: `committee_create_request_fee: "50.000 VIZ"` -3. Users shift votes to validators who support lower fees -4. As more low-fee validators enter the active set, the **median shifts down** -5. Once more than half of active validators publish 50 VIZ or less, the median becomes 50 VIZ -6. The new fee takes effect automatically — no hardfork, no governance proposal, no vote counting - -### Comparing Governance Models - -| Approach | VIZ Median Properties | Token Voting (e.g., Snapshot) | Foundation Governance | -|---|---|---|---| -| **Who decides** | Elected validators (indirectly: all SHARES holders) | Token holders directly | Core team / foundation | -| **Resistance to extremes** | Strong (median) | Weak (whale dominance) | N/A (centralized) | -| **Speed of change** | Gradual (median shifts slowly) | Fast (single vote) | Fast or slow (depends on team) | -| **Parameter granularity** | Every parameter independently | Usually binary proposals | Any | -| **Sybil resistance** | Built-in (stake-weighted Fair-DPOS) | Depends on implementation | N/A | -| **Transparency** | Full (all validator props on-chain) | Partial (off-chain voting) | Low | - ---- - -## Versioning and Hardfork Compatibility - -Properties were introduced in stages: - -| Version | Hardfork | Properties Added | -|---|---|---| -| `chain_properties_init` | Genesis | account_creation_fee, maximum_block_size, delegation params, curation, bandwidth, flag cost, vote min rshares, committee threshold | -| `chain_properties_hf4` | HF4 | inflation_witness_percent, inflation_ratio_committee_vs_reward_fund, inflation_recalc_period | -| `chain_properties_hf6` | HF6 | data_operations_cost_additional_bandwidth, witness_miss_penalty_percent, witness_miss_penalty_duration | -| `chain_properties_hf9` | HF9 | create_invite_min_balance, committee_create_request_fee, create_paid_subscription_fee, account_on_sale_fee, subaccount_on_sale_fee, witness_declaration_fee, withdraw_intervals | - -validators publish properties using `versioned_chain_properties` — a variant that accepts any version. The evaluator validates the version against the current hardfork (you can't publish HF9 properties before HF9 activates). Properties from older versions use default values for newer fields. - ---- - -## Summary - -Chain properties governance in VIZ is a **continuous, median-based, representative system** where: - -- **validators** are the direct governors who publish their preferred parameters -- **Users** are the ultimate governors who elect validators based on their published properties -- **The median** ensures no single actor can impose extreme values -- **Every parameter** — from fees to inflation to bandwidth — is a public good decision made collectively -- **Changes happen organically**: as community preferences shift, validator elections shift, and the median follows - -This creates a self-regulating network where the "rules of the game" are constantly optimized by the people who have the most at stake. diff --git a/.qoder/docs/cli-wallet.md b/.qoder/docs/cli-wallet.md deleted file mode 100644 index 3d1be9cf00..0000000000 --- a/.qoder/docs/cli-wallet.md +++ /dev/null @@ -1,1126 +0,0 @@ -# VIZ CLI Wallet — Complete Command Reference - -Complete reference for all `cli_wallet` commands with syntax and examples. - ---- - -## Table of Contents - -1. [Wallet Management](#wallet-management) -2. [Key Management](#key-management) -3. [Query Operations](#query-operations) -4. [Account Operations](#account-operations) -5. [Transfer & Vesting](#transfer--vesting) -6. [validator Operations](#validator-operations) -7. [Content Operations](#content-operations) -8. [Escrow Operations](#escrow-operations) -9. [Recovery Operations](#recovery-operations) -10. [Committee Operations](#committee-operations) -11. [Invite System](#invite-system) -12. [Award Operations](#award-operations) -13. [Subscription Operations](#subscription-operations) -14. [Account Market](#account-market) -15. [Proposal Operations](#proposal-operations) -16. [Transaction Builder](#transaction-builder) -17. [NS DNS Helpers](#ns-dns-helpers) -18. [Private Messaging](#private-messaging) - ---- - -## Wallet Management - -### help -Returns a list of all commands supported by the wallet API. - -```bash -help -``` - -### gethelp -Returns detailed help on a single API command. - -```bash -gethelp "transfer" -``` - -### about -Returns info such as client version, git version, version of boost, openssl. - -```bash -about -``` - -### is_new -Checks whether the wallet has just been created and has not yet had a password set. - -```bash -is_new -# Returns: true or false -``` - -### is_locked -Checks whether the wallet is locked (is unable to use its private keys). - -```bash -is_locked -# Returns: true or false -``` - -### lock -Locks the wallet immediately. - -```bash -lock -``` - -### unlock -Unlocks the wallet. - -```bash -unlock "your_password" -``` - -### set_password -Sets a new password on the wallet. The wallet must be either 'new' or 'unlocked'. - -```bash -set_password "your_new_password" -``` - -### load_wallet_file -Loads a specified wallet file. - -```bash -load_wallet_file "wallet.json" -# Or reload current file: -load_wallet_file "" -``` - -### save_wallet_file -Saves the current wallet to the given filename. - -```bash -save_wallet_file "backup_wallet.json" -# Or save to current filename: -save_wallet_file "" -``` - -### quit -Quits the wallet application. - -```bash -quit -``` - -### set_transaction_expiration -Sets the amount of time in the future until a transaction expires. - -```bash -set_transaction_expiration 60 # 60 seconds -``` - ---- - -## Key Management - -### import_key -Imports a WIF Private Key into the wallet to be used to sign transactions. - -```bash -import_key "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" -``` - -### suggest_brain_key -Suggests a safe brain key to use for creating your account. - -```bash -suggest_brain_key -# Returns: { "brain_priv_key": "...", "pub_key": "VIZ...", "wif_priv_key": "5K..." } -``` - -### list_keys -Dumps all private keys owned by the wallet in WIF format. - -```bash -list_keys -# Returns: { "VIZpubkey...": "5Kprivkey..." } -``` - -### get_private_key -Get the WIF private key corresponding to a public key. The private key must already be in the wallet. - -```bash -get_private_key "VIZ6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" -``` - -### get_private_key_from_password -Generates a private key from account name, role, and password. - -```bash -get_private_key_from_password "myaccount" "active" "mypassword123" -# Returns: ["VIZpubkey...", "5Kprivkey..."] -``` - -### normalize_brain_key -Transforms a brain key to reduce the chance of errors when re-entering. - -```bash -normalize_brain_key "my brain key words here" -``` - ---- - -## Query Operations - -### info -Returns info about the current state of the blockchain. - -```bash -info -``` - -### database_info -Returns info about database objects. - -```bash -database_info -``` - -### get_block -Returns the information about a block. - -```bash -get_block 1000000 -``` - -### get_ops_in_block -Returns sequence of operations in a specified block. - -```bash -get_ops_in_block 1000000 false # all operations -get_ops_in_block 1000000 true # only virtual operations -``` - -### get_active_validators -Returns the list of validators producing blocks in the current round (21 blocks). - -```bash -get_active_validators -``` - -### get_account -Returns information about the given account. - -```bash -get_account "alice" -``` - -### list_accounts -Lists all accounts registered in the blockchain. - -```bash -list_accounts "" 100 # First 100 accounts -list_accounts "bob" 100 # 100 accounts starting from "bob" -``` - -### list_my_accounts -Gets the account information for all accounts for which this wallet has a private key. - -```bash -list_my_accounts -``` - -### get_account_history -Returns account operations history in the range [from-limit, from]. - -```bash -get_account_history "alice" -1 100 # Last 100 operations -get_account_history "alice" 500 100 # Operations 400-500 -``` - -### get_transaction -Returns transaction by ID. - -```bash -get_transaction "0123456789abcdef0123456789abcdef01234567" -``` - -### get_master_history -Returns master authority history for an account. - -```bash -get_master_history "alice" -``` - -### get_withdraw_routes -Returns vesting withdraw routes for an account. - -```bash -get_withdraw_routes "alice" "all" # all routes -get_withdraw_routes "alice" "incoming" # incoming routes -get_withdraw_routes "alice" "outgoing" # outgoing routes -``` - ---- - -## Account Operations - -### create_account -Creates a new account with auto-generated keys (controlled by this wallet). - -```bash -create_account "creator" "1.000 VIZ" "10.000000 SHARES" "newaccount" "{}" true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| creator | string | Account creating the new account | -| tokens_fee | asset | Amount of VIZ to pay as fee | -| delegated_vests | asset | Amount of SHARES to delegate | -| new_account_name | string | Name of the new account | -| json_metadata | string | JSON metadata for the account | -| broadcast | bool | Whether to broadcast the transaction | - -### create_account_with_keys -Creates a new account with specified keys (for faucets). - -```bash -create_account_with_keys "creator" "1.000 VIZ" "10.000000 SHARES" "newaccount" "{}" \ - "VIZmaster..." "VIZactive..." "VIZregular..." "VIZmemo..." true -``` - -### update_account -Updates the keys of an existing account. - -```bash -update_account "myaccount" "{\"profile\":\"test\"}" \ - "VIZmaster..." "VIZactive..." "VIZregular..." "VIZmemo..." true -``` - -### update_account_auth_key -Updates a key of an authority for an existing account. - -```bash -update_account_auth_key "myaccount" "active" "VIZ6newkey..." 1 true -# Set weight to 0 to remove key: -update_account_auth_key "myaccount" "active" "VIZ6oldkey..." 0 true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| account_name | string | Account to update | -| type | enum | Authority type: `master`, `active`, or `regular` | -| key | public_key | Public key to add/remove | -| weight | uint16 | Weight (0 = remove) | -| broadcast | bool | Whether to broadcast | - -### update_account_auth_account -Updates an account authority for an existing account. - -```bash -update_account_auth_account "myaccount" "active" "guardian" 1 true -# Remove account from authority: -update_account_auth_account "myaccount" "active" "guardian" 0 true -``` - -### update_account_auth_threshold -Updates the weight threshold of an authority. - -```bash -update_account_auth_threshold "myaccount" "active" 2 true -``` - -### update_account_meta -Updates the account JSON metadata. - -```bash -update_account_meta "myaccount" "{\"profile\":{\"name\":\"Alice\"}}" true -``` - -### update_account_memo_key -Updates the memo key of an account. - -```bash -update_account_memo_key "myaccount" "VIZnewmemokey..." true -``` - -### delegate_vesting_shares -Delegates SHARES from one account to another. - -```bash -delegate_vesting_shares "alice" "bob" "100.000000 SHARES" true -# Remove delegation (delegate 0): -delegate_vesting_shares "alice" "bob" "0.000000 SHARES" true -``` - ---- - -## Transfer & Vesting - -### transfer -Transfer funds from one account to another. - -```bash -transfer "alice" "bob" "10.000 VIZ" "payment memo" true -# Encrypted memo (prefix with #): -transfer "alice" "bob" "10.000 VIZ" "#secret message" true -``` - -### transfer_to_vesting -Transfer VIZ into vesting fund (SHARES). - -```bash -transfer_to_vesting "alice" "bob" "100.000 VIZ" true -# Self-vest: -transfer_to_vesting "alice" "alice" "100.000 VIZ" true -``` - -### withdraw_vesting -Set up a vesting withdraw request (power down). - -```bash -withdraw_vesting "alice" "100.000000 SHARES" true -# Cancel withdrawal (withdraw 0): -withdraw_vesting "alice" "0.000000 SHARES" true -``` - -### set_withdraw_vesting_route -Set up a vesting withdraw route. - -```bash -# Route 50% of withdrawals to "bob" as VIZ: -set_withdraw_vesting_route "alice" "bob" 5000 false true -# Route 25% to "charlie" as SHARES: -set_withdraw_vesting_route "alice" "charlie" 2500 true true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| from | string | Account withdrawing | -| to | string | Destination account | -| percent | uint16 | Percent (100 = 1%, 10000 = 100%) | -| auto_vest | bool | true = receive as SHARES, false = receive as VIZ | -| broadcast | bool | Whether to broadcast | - ---- - -## validator Operations - -### list_validators -Lists all validators registered in the blockchain. - -```bash -list_validators "" 100 # First 100 validators -list_validators "bob" 100 # 100 validators starting from "bob" -``` - -### get_validator -Returns information about the given validator. - -```bash -get_validator "validatorname" -``` - -### update_validator -Update a validator object. - -```bash -update_validator "myvalidator" "https://myvalidator.com" "VIZsigningkey..." true -# Disable block production (empty key): -update_validator "myvalidator" "" "" true -``` - -### update_chain_properties -Vote for the chain properties. - -```bash -update_chain_properties "myvalidator" \ - {"account_creation_fee":"1.000 VIZ","maximum_block_size":65536,"create_account_delegation_ratio":10,...} \ - true -``` - -### versioned_update_chain_properties -Vote for the versioned chain properties. - -```bash -versioned_update_chain_properties "myvalidator" \ - {"account_creation_fee":"1.000 VIZ","maximum_block_size":65536,...} \ - true -``` - -### set_voting_proxy -Set the voting proxy for an account. - -```bash -set_voting_proxy "alice" "trustedvoter" true -# Remove proxy: -set_voting_proxy "alice" "" true -``` - -### vote_for_validator -Vote for a validator to become a block producer. - -```bash -vote_for_validator "alice" "myvalidator" true true # Vote for -vote_for_validator "alice" "myvalidator" false true # Vote against -``` - ---- - -## Content Operations - -> Note: Content operations are deprecated in VIZ. - -### post_content -Post or update a content. - -```bash -post_content "author" "my-permlink" "" "" "Title" "Body content" 5000 "{}" true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| author | string | Account authoring the content | -| permlink | string | Unique permlink for the content | -| parent_author | string | Parent author (empty for top-level) | -| parent_permlink | string | Parent permlink (empty for top-level) | -| title | string | Title of the content | -| body | string | Body of the content | -| curation_percent | int16 | Curation reward percent (0-10000) | -| json | string | JSON metadata | -| broadcast | bool | Whether to broadcast | - -### vote -Vote on a content. - -```bash -vote "voter" "author" "permlink" 100 true # 100% upvote -vote "voter" "author" "permlink" -100 true # 100% downvote -vote "voter" "author" "permlink" 0 true # Remove vote -``` - -### delete_content -Delete a content. - -```bash -delete_content "author" "permlink" true -``` - -### custom -Broadcast a custom operation. - -```bash -custom ["alice"] [] "follow" "{\"follower\":\"alice\",\"following\":\"bob\"}" true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| required_active_auths | array | Accounts requiring active authority | -| required_regular_auths | array | Accounts requiring regular authority | -| id | string | Custom operation type identifier | -| json | string | JSON data for the custom operation | -| broadcast | bool | Whether to broadcast | - ---- - -## Escrow Operations - -### escrow_transfer -Transfer funds using escrow. - -```bash -escrow_transfer "alice" "bob" "agent" 1 "100.000 VIZ" "1.000 VIZ" \ - "2024-01-15T12:00:00" "2024-02-15T12:00:00" "{}" true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| from | string | Funding account | -| to | string | Destination account | -| agent | string | Escrow agent account | -| escrow_id | uint32 | Unique escrow ID | -| token_amount | asset | Amount to escrow | -| fee | asset | Agent fee | -| ratification_deadline | time | Deadline for approval | -| escrow_expiration | time | Expiration time | -| json_metadata | string | JSON metadata | -| broadcast | bool | Whether to broadcast | - -### escrow_approve -Approve a proposed escrow transfer. - -```bash -escrow_approve "alice" "bob" "agent" "bob" 1 true true # Approve -escrow_approve "alice" "bob" "agent" "agent" 1 true true # Agent approves -escrow_approve "alice" "bob" "agent" "bob" 1 false true # Reject (refund) -``` - -### escrow_dispute -Raise a dispute on the escrow transfer. - -```bash -escrow_dispute "alice" "bob" "agent" "alice" 1 true # from disputes -escrow_dispute "alice" "bob" "agent" "bob" 1 true # to disputes -``` - -### escrow_release -Release funds held in escrow. - -```bash -# Agent releases to bob: -escrow_release "alice" "bob" "agent" "agent" "bob" 1 "100.000 VIZ" true -# After expiration, alice can release to herself: -escrow_release "alice" "bob" "agent" "alice" "alice" 1 "100.000 VIZ" true -``` - ---- - -## Recovery Operations - -### request_account_recovery -Create an account recovery request as a recovery account. - -```bash -request_account_recovery "recovery_account" "account_to_recover" \ - {"weight_threshold":1,"account_auths":[],"key_auths":[["VIZnewkey...",1]]} true -``` - -### recover_account -Recover your account using a recovery request. - -```bash -recover_account "myaccount" \ - {"weight_threshold":1,"account_auths":[],"key_auths":[["VIZoldkey...",1]]} \ - {"weight_threshold":1,"account_auths":[],"key_auths":[["VIZnewkey...",1]]} true -``` - -### change_recovery_account -Change your recovery account (30 day delay). - -```bash -change_recovery_account "myaccount" "new_recovery_account" true -``` - ---- - -## Committee Operations - -### committee_worker_create_request -Create a committee worker request. - -```bash -committee_worker_create_request "creator" "https://proposal.com/info" "worker" \ - "100.000 VIZ" "500.000 VIZ" 2592000 true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| creator | string | Account creating the request | -| url | string | URL with request information | -| worker | string | Worker account to receive payment | -| required_amount_min | asset | Minimum amount requested | -| required_amount_max | asset | Maximum amount requested | -| duration | uint32 | Duration in seconds | -| broadcast | bool | Whether to broadcast | - -### committee_worker_cancel_request -Cancel a committee worker request. - -```bash -committee_worker_cancel_request "creator" 123 true -``` - -### committee_vote_request -Vote on a committee worker request. - -```bash -committee_vote_request "voter" 123 10000 true # 100% support -committee_vote_request "voter" 123 -10000 true # 100% against -committee_vote_request "voter" 123 0 true # Remove vote -``` - ---- - -## Invite System - -### create_invite -Create an invite with a balance. - -```bash -create_invite "creator" "10.000 VIZ" "VIZinvitekey..." true -``` - -### claim_invite_balance -Claim an invite balance to an existing account. - -```bash -claim_invite_balance "initiator" "receiver" "5Kinvitesecret..." true -``` - -### invite_registration -Register a new account using an invite. - -```bash -invite_registration "initiator" "newaccount" "5Kinvitesecret..." "VIZnewaccountkey..." true -``` - -### use_invite_balance -Use invite balance to transfer to vesting. - -```bash -use_invite_balance "initiator" "receiver" "5Kinvitesecret..." true -``` - ---- - -## Award Operations - -### award -Award an account (energy-based reward). - -```bash -# Simple award: -award "initiator" "receiver" 1000 0 "Great work!" [] true - -# Award with beneficiaries: -award "initiator" "receiver" 1000 0 "memo" \ - [{"account":"beneficiary1","weight":5000},{"account":"beneficiary2","weight":5000}] true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| initiator | string | Account giving the award | -| receiver | string | Account receiving the award | -| energy | uint16 | Energy to use (0-10000 = 0-100%) | -| custom_sequence | uint64 | Custom sequence number | -| memo | string | Memo for the award | -| beneficiaries | array | List of beneficiaries with weights | -| broadcast | bool | Whether to broadcast | - -### fixed_award -Fixed award an account (fixed amount reward). - -```bash -fixed_award "initiator" "receiver" "10.000 VIZ" 10000 0 "Fixed award" [] true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| initiator | string | Account giving the award | -| receiver | string | Account receiving the award | -| reward_amount | asset | Fixed reward amount | -| max_energy | uint16 | Maximum energy to use | -| custom_sequence | uint64 | Custom sequence number | -| memo | string | Memo for the award | -| beneficiaries | array | List of beneficiaries | -| broadcast | bool | Whether to broadcast | - ---- - -## Subscription Operations - -### set_paid_subscription -Set up a paid subscription. - -```bash -set_paid_subscription "creator" "https://sub.com/info" 5 "10.000 VIZ" 2592000 true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| account | string | Account setting up subscription | -| url | string | URL with subscription info | -| levels | uint16 | Number of subscription levels | -| amount | asset | Cost per level | -| period | uint16 | Subscription period in seconds | -| broadcast | bool | Whether to broadcast | - -### paid_subscribe -Subscribe to a paid subscription. - -```bash -paid_subscribe "subscriber" "creator" 1 "10.000 VIZ" 2592000 true true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| subscriber | string | Subscribing account | -| account | string | Account with the subscription | -| level | uint16 | Subscription level | -| amount | asset | Payment amount | -| period | uint16 | Subscription period | -| auto_renewal | bool | Enable auto renewal | -| broadcast | bool | Whether to broadcast | - ---- - -## Account Market - -### set_account_price -Set an account up for sale. - -```bash -# Put account on sale: -set_account_price "myaccount" "myaccount" "100.000 VIZ" true true -# Remove from sale: -set_account_price "myaccount" "myaccount" "0.000 VIZ" false true -``` - -### set_subaccount_price -Set subaccount creation for sale. - -```bash -# Allow subaccount creation for a fee: -set_subaccount_price "myaccount" "myaccount" "50.000 VIZ" true true -# Disable: -set_subaccount_price "myaccount" "myaccount" "0.000 VIZ" false true -``` - -### buy_account -Buy an account. - -```bash -buy_account "buyer" "accountforsale" "100.000 VIZ" "VIZnewkey..." "0.000 VIZ" true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| buyer | string | Buying account | -| account | string | Account being bought | -| account_offer_price | asset | Purchase price | -| account_authorities_key | public_key | New public key for the account | -| tokens_to_shares | asset | Amount to convert to shares | -| broadcast | bool | Whether to broadcast | - -### target_account_sale -Set an account for sale to a specific target buyer. - -```bash -target_account_sale "myaccount" "myaccount" "targetbuyer" "100.000 VIZ" true true -``` - ---- - -## Proposal Operations - -### approve_proposal -Approve or disapprove a proposal. - -```bash -# Add active approval: -approve_proposal "author" "proposal_title" \ - {"active_approvals_to_add":["myaccount"],"active_approvals_to_remove":[]} true - -# Remove master approval: -approve_proposal "author" "proposal_title" \ - {"master_approvals_to_remove":["myaccount"]} true -``` - -### delete_proposal -Delete a proposal. - -```bash -delete_proposal "author" "proposal_title" "requester" true -``` - -### get_proposed_transactions -Returns proposals for the account. - -```bash -get_proposed_transactions "myaccount" 0 100 -``` - ---- - -## Transaction Builder - -### begin_builder_transaction -Begins building a new transaction. - -```bash -begin_builder_transaction -# Returns: transaction handle (e.g., 0) -``` - -### add_operation_to_builder_transaction -Adds an operation to a builder transaction. - -```bash -add_operation_to_builder_transaction 0 [2,{"from":"alice","to":"bob","amount":"10.000 VIZ","memo":""}] -``` - -### add_operation_copy_to_builder_transaction -Copies an operation from one builder transaction to another. - -```bash -add_operation_copy_to_builder_transaction 0 1 0 -``` - -### replace_operation_in_builder_transaction -Replaces an operation in a builder transaction. - -```bash -replace_operation_in_builder_transaction 0 0 [2,{"from":"alice","to":"charlie","amount":"5.000 VIZ","memo":""}] -``` - -### preview_builder_transaction -Previews a builder transaction. - -```bash -preview_builder_transaction 0 -``` - -### sign_builder_transaction -Signs and optionally broadcasts a builder transaction. - -```bash -sign_builder_transaction 0 true # Sign and broadcast -sign_builder_transaction 0 false # Sign only -``` - -### propose_builder_transaction -Creates a proposal from a builder transaction. - -```bash -propose_builder_transaction 0 "author" "proposal_title" "memo" \ - "2024-02-01T00:00:00" "2024-01-15T00:00:00" true -``` - -### remove_builder_transaction -Removes a builder transaction. - -```bash -remove_builder_transaction 0 -``` - -### get_prototype_operation -Returns an uninitialized object representing a given blockchain operation. - -```bash -get_prototype_operation "transfer_operation" -get_prototype_operation "award_operation" -``` - -### serialize_transaction -Converts a signed transaction in JSON form to its binary representation. - -```bash -serialize_transaction {"ref_block_num":...,"operations":[...]} -``` - -### sign_transaction -Signs a transaction with the necessary keys. - -```bash -sign_transaction {"ref_block_num":...,"operations":[...]} true -``` - ---- - -## NS DNS Helpers - -VIZ DNS Nameserver helpers for storing DNS records in account metadata. - -### ns_validate_ipv4 -Validates an IPv4 address string. - -```bash -ns_validate_ipv4 "188.120.231.153" -# Returns: true - -ns_validate_ipv4 "256.0.0.1" -# Returns: false -``` - -### ns_validate_sha256_hash -Validates a SHA256 hash string (64 hex characters). - -```bash -ns_validate_sha256_hash "4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2" -# Returns: true -``` - -### ns_validate_ttl -Validates a TTL value (must be positive integer). - -```bash -ns_validate_ttl 28800 -# Returns: true -``` - -### ns_validate_ssl_txt_record -Validates an SSL TXT record format (ssl=). - -```bash -ns_validate_ssl_txt_record "ssl=4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2" -# Returns: true -``` - -### ns_validate_metadata -Performs complete validation of NS metadata options. - -```bash -ns_validate_metadata {"a_records":["188.120.231.153"],"ssl_hash":"4a4613...","ttl":28800} -# Returns: {"is_valid":true,"errors":[]} -``` - -### ns_create_metadata -Creates NS metadata JSON object from options. - -```bash -ns_create_metadata {"a_records":["188.120.231.153"],"ssl_hash":"4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2","ttl":28800} -# Returns: {"ns":[["A","188.120.231.153"],["TXT","ssl=4a4613..."]],"ttl":28800} -``` - -### ns_get_summary -Gets complete NS summary from an account's metadata. - -```bash -ns_get_summary "myaccount" -# Returns: {"a_records":["188.120.231.153"],"ssl_hash":"4a4613...","ttl":28800,"has_ns_data":true} -``` - -### ns_extract_a_records -Extracts A records (IPv4 addresses) from an account's metadata. - -```bash -ns_extract_a_records "myaccount" -# Returns: ["188.120.231.153", "192.168.1.100"] -``` - -### ns_extract_ssl_hash -Extracts SSL hash from an account's metadata TXT records. - -```bash -ns_extract_ssl_hash "myaccount" -# Returns: "4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2" -``` - -### ns_extract_ttl -Extracts TTL value from an account's metadata. - -```bash -ns_extract_ttl "myaccount" -# Returns: 28800 -``` - -### ns_set_records -Sets NS records for an account (merges with existing metadata). - -```bash -# Set A record only: -ns_set_records "myaccount" {"a_records":["188.120.231.153"],"ttl":28800} true - -# Set A records with SSL hash: -ns_set_records "myaccount" \ - {"a_records":["188.120.231.153","192.168.1.100"],"ssl_hash":"4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2","ttl":28800} \ - true - -# Round-robin DNS with multiple A records: -ns_set_records "myaccount" \ - {"a_records":["188.120.231.153","192.168.1.100","10.0.0.50"],"ttl":3600} \ - true -``` - -| Parameter | Type | Description | -|-----------|------|-------------| -| account_name | string | Account to update | -| options | object | NS metadata options | -| options.a_records | array | List of IPv4 addresses | -| options.ssl_hash | string | SHA256 hash for SSL (optional) | -| options.ttl | uint32 | TTL in seconds (default: 28800) | -| broadcast | bool | Whether to broadcast | - -### ns_remove_records -Removes NS records from an account's metadata (preserves other fields). - -```bash -ns_remove_records "myaccount" true -``` - ---- - -## Private Messaging - -### get_encrypted_memo -Returns the encrypted memo if memo starts with '#', otherwise returns memo. - -```bash -get_encrypted_memo "alice" "bob" "#secret message" -``` - -### decrypt_memo -Returns the decrypted memo if possible given wallet's known private keys. - -```bash -decrypt_memo "#encrypteddata..." -``` - -### get_inbox -Gets private messages received by an account. - -```bash -get_inbox "myaccount" "2024-01-15T00:00:00" 100 0 -``` - -### get_outbox -Gets private messages sent by an account. - -```bash -get_outbox "myaccount" "2024-01-15T00:00:00" 100 0 -``` - ---- - -## Data Types Reference - -### Asset Format -- **VIZ**: 3 decimal places, e.g., `"10.000 VIZ"` -- **SHARES**: 6 decimal places, e.g., `"10.000000 SHARES"` - -### Authority Object -```json -{ - "weight_threshold": 1, - "account_auths": [["guardian", 1]], - "key_auths": [["VIZ6...", 1]] -} -``` - -### Beneficiary Route -```json -{"account": "beneficiary", "weight": 5000} -``` -Weight is in basis points (5000 = 50%). - -### NS Metadata Options -```json -{ - "a_records": ["188.120.231.153"], - "ssl_hash": "4a4613daef37cbc5c4a5156cd7b24ea2e6ee2e5f1e7461262a2df2b63cbf17e2", - "ttl": 28800 -} -``` - ---- - -## Authority Requirements Summary - -| Operation | Required Authority | -|-----------|-------------------| -| Account creation | active | -| Account update | master (for keys), active (for other) | -| Account metadata | regular | -| Transfer VIZ | active | -| Transfer SHARES | master | -| Vesting operations | active | -| validator operations | active | -| Content operations | regular | -| Custom operation | active or regular (specified) | -| Recovery operations | varies | -| Committee operations | regular | -| Invite operations | active | -| Award operations | regular | -| Subscription operations | active | -| Account sale | master | -| NS operations | regular (via account_metadata) | diff --git a/.qoder/docs/committee-dao-and-prediction-markets.md b/.qoder/docs/committee-dao-and-prediction-markets.md deleted file mode 100644 index 6d44d12b2c..0000000000 --- a/.qoder/docs/committee-dao-and-prediction-markets.md +++ /dev/null @@ -1,304 +0,0 @@ -# Committee DAO System and Prediction Market Dispute Resolution - -## Part 1: How the VIZ Committee System Works - -### Overview - -The VIZ committee is a **decentralized autonomous governance** (DAO) mechanism built directly into the blockchain protocol. It enables community-funded worker proposals: any account can create a funding request, and all VIZ SHARES holders vote to approve or reject it using **stake-weighted bipolar voting** (positive and negative). - -The committee fund accumulates from request creation fees. Approved requests are paid out proportionally from this fund. - -### Core Operations - -| Operation | Description | -|---|---| -| `committee_worker_create_request` | Create a funding proposal with URL, min/max amounts, duration (5–30 days) | -| `committee_worker_cancel_request` | Creator cancels their own active proposal | -| `committee_vote_request` | Any account votes on an active proposal (−10000 to +10000) | - -### Voting Mechanics - -Every VIZ account can vote on any active committee request. The vote is expressed as `vote_percent` in range **−10000 to +10000** (basis points, i.e. −100% to +100%). - -- **Positive vote** (+1 to +10000): supports the request -- **Negative vote** (−10000 to −1): opposes the request -- **Vote weight** is proportional to the voter's `effective_vesting_shares` (staked VIZ) - -Each voter can change their vote at any time while the request is active. Only one vote per account per request is stored; updating replaces the previous vote. - -### Stake-Weighted Calculation - -When the request's `end_time` is reached, the blockchain evaluates votes: - -``` -max_rshares = SUM( voter.effective_vesting_shares ) // for all voters -actual_rshares = SUM( voter.effective_vesting_shares * vote_percent / 10000 ) // signed sum -``` - -**Three thresholds must be met for approval:** - -1. **Participation threshold**: `max_rshares >= total_vesting_shares * committee_request_approve_min_percent / 10000` - - If insufficient participation → status = 2 (rejected, not enough voters) - -2. **Consensus threshold**: `actual_rshares > 0` - - If net negative → status = 3 (rejected, community says no) - -3. **Minimum payout**: `calculated_payment >= required_amount_min` - - Payout formula: `calculated_payment = required_amount_max * (actual_rshares / max_rshares)` - - If payout too low → status = 3 (rejected, below minimum) - - If all pass → status = 4 (approved) - -### Payout Processing - -Approved requests (status=4) receive payouts from `committee_fund` every 10 minutes (200 blocks). The fund is split equally across all approved requests. Each cycle: - -``` -max_payment_per_request = committee_fund / count_of_approved_requests -current_payment = min(max_payment_per_request, remain_payout_amount) -``` - -When `remain_payout_amount` reaches 0, status becomes 5 (completed). - -### Request Lifecycle - -``` -[Created, status=0] → voting period (5–30 days) - → Insufficient participation → [Rejected, status=2] - → Net negative votes → [Expired, status=3] - → Payout below minimum → [Expired, status=3] - → Creator cancels → [Canceled, status=1] - → Approved → [Approved, status=4] → payouts → [Completed, status=5] -``` - -### Key Properties - -1. **Bipolar**: every voter can express support OR opposition with fine-grained intensity -2. **Stake-weighted**: votes are weighted by locked tokens, making Sybil attacks expensive -3. **Proportional payout**: stronger consensus → higher payout (up to `required_amount_max`) -4. **Self-funding**: creation fees flow into the committee fund -5. **Non-custodial**: no trusted intermediary; the protocol enforces all rules - ---- - -## Part 2: Applying the Committee Model to Prediction Markets - -### Why Committee Voting is Useful for Dispute Resolution - -The committee system solves a fundamental governance problem: **how to make a collective, weighted decision where the outcome is proportional to conviction**. This is exactly what prediction markets need when: - -- An oracle reports a result that participants dispute -- A market creator sets up an unfair or fraudulent market -- The correct outcome is ambiguous and requires human judgment - -The committee model is useful for dispute resolution because: - -1. **It's already battle-tested** on the VIZ blockchain for DAO funding -2. **Negative votes matter** — they aren't just "abstain", they actively oppose, creating a true signal -3. **Weighted by stake** — actors with more skin in the game have proportionally more say -4. **Proportional outcomes** — the result isn't binary "yes/no" but a gradient, which maps well to penalties/rewards -5. **Participation threshold** — prevents tiny minorities from dictating outcomes - -### Prediction Market Dispute Resolution: Implementation Proposal - -#### Market Structure - -A prediction market has: -- **Market creator**: account that defines the event and outcomes -- **Oracle**: account responsible for reporting the correct outcome -- **Outcomes**: N possible results (e.g., "Team A wins", "Team B wins", "Draw") -- **Oracle insurance fund**: a deposit the oracle stakes to guarantee honest reporting -- **Participants**: accounts that buy outcome shares - -#### Dispute Flow - -``` -[Oracle reports outcome] → [Challenge period starts] - → No disputes filed → [Outcome finalized] - → Dispute filed (fee required) → [Committee vote opens] - → Vote concludes → [Resolution applied] -``` - -#### New Operations (Conceptual) - -##### `prediction_market_create_operation` - -``` -creator: account_name_type // who creates the market -url: string // market description -outcomes: vector // e.g. ["Team A", "Team B", "Draw"] -oracle: account_name_type // designated result reporter -oracle_insurance: asset // oracle's deposit (staked as guarantee) -resolution_duration: uint32_t // voting period if disputed (seconds) -penalty_percent: int16_t // −10000 to +10000 (see below) -oracle_ban_type: uint8_t // 0=no ban, 1=temporary, 2=permanent -creator_ban_type: uint8_t // 0=no ban, 1=temporary, 2=permanent -ban_duration: uint32_t // seconds (if temporary) -``` - -**About `penalty_percent`:** - -| Value | Meaning | -|---|---| -| +5000 (+50%) | If dispute succeeds, oracle loses 50% of insurance fund | -| +10000 (+100%) | Oracle loses entire insurance fund | -| 0 | No penalty (dispute just corrects the outcome) | -| −5000 (−50%) | Oracle is actually **rewarded** 50% bonus from dispute fee pool — use this for markets where oracles face genuine ambiguity and shouldn't be punished for honest mistakes | - -A negative `penalty_percent` means: "we understand this market is hard to judge, so we don't penalize the oracle even if the community overrides the result." This is critical for markets involving subjective outcomes (e.g., "Was the product delivered satisfactorily?"). - -##### `prediction_dispute_operation` - -``` -disputer: account_name_type -market_id: uint32_t -proposed_outcome: uint16_t // which outcome the disputer believes is correct (index into outcomes[]) -``` - -Filing a dispute requires a fee (similar to committee request creation fee) to prevent spam. This opens a **committee-style voting period**. - -##### `prediction_dispute_vote_operation` - -``` -voter: account_name_type -market_id: uint32_t -vote_outcome: uint16_t // which outcome this voter believes is correct (1 of N) -vote_percent: int16_t // −10000 to +10000 (conviction strength) -``` - -**Key difference from committee voting**: here the voter selects **one correct outcome** from multiple options AND expresses conviction strength. - -- `vote_outcome` = the outcome index the voter believes is correct -- `vote_percent` = how confident they are (positive = "I'm sure this is right", negative = "I'm sure the oracle was actually correct, reject the dispute") - -#### Resolution Algorithm (Weighted Decision) - -When the dispute voting period ends: - -```cpp -// Step 1: Calculate stake-weighted votes per outcome -for each vote in dispute_votes: - voter_weight = voter.effective_vesting_shares - if vote_percent > 0: - // Voter supports changing the outcome - outcome_rshares[vote_outcome] += voter_weight * vote_percent / 10000 - total_change_rshares += voter_weight * vote_percent / 10000 - else: - // Voter opposes the dispute (supports oracle's original result) - oracle_defense_rshares += voter_weight * abs(vote_percent) / 10000 - max_rshares += voter_weight - -// Step 2: Participation check -approve_min_shares = total_vesting_shares * dispute_approve_min_percent / 10000 -if max_rshares < approve_min_shares: - // Not enough participation — oracle's result stands - finalize_with_oracle_result() - return - -// Step 3: Compare oracle defense vs total change votes -if oracle_defense_rshares >= total_change_rshares: - // Community supports oracle — dispute rejected - finalize_with_oracle_result() - // Dispute fee goes to oracle as compensation - return - -// Step 4: Find winning outcome among change votes -winning_outcome = argmax(outcome_rshares) -winning_rshares = outcome_rshares[winning_outcome] - -// Step 5: Calculate penalty proportional to conviction -// consensus_strength = winning_rshares / max_rshares (0.0 to 1.0) -// This makes the penalty proportional to how strongly the community disagrees -consensus_strength = winning_rshares * CHAIN_100_PERCENT / max_rshares - -if penalty_percent > 0: - actual_penalty = oracle_insurance * penalty_percent / 10000 - // Scale by consensus strength — weak consensus = smaller penalty - actual_penalty = actual_penalty * consensus_strength / CHAIN_100_PERCENT - // Deduct from oracle insurance, distribute to dispute participants - oracle_insurance -= actual_penalty -elif penalty_percent < 0: - // Negative penalty = oracle gets rewarded even when overridden - oracle_bonus = dispute_fee_pool * abs(penalty_percent) / 10000 - oracle_balance += oracle_bonus - -// Step 6: Apply bans based on consensus strength -if oracle_ban_type == 1 and consensus_strength > BAN_THRESHOLD: - // Temporary ban — duration scaled by consensus strength - oracle.banned_until = now + ban_duration * consensus_strength / CHAIN_100_PERCENT -elif oracle_ban_type == 2 and consensus_strength > PERMANENT_BAN_THRESHOLD: - oracle.permanently_banned = true - -// Same logic for creator bans (for fraudulent market setup) -if creator_ban_type == 1 and consensus_strength > BAN_THRESHOLD: - creator.banned_until = now + ban_duration * consensus_strength / CHAIN_100_PERCENT -elif creator_ban_type == 2 and consensus_strength > PERMANENT_BAN_THRESHOLD: - creator.permanently_banned = true - -// Step 7: Override result -finalize_with_outcome(winning_outcome) -``` - -#### Making the Decision Weighted - -The key insight from the committee system is that **all decisions should be proportional, not binary**. Here's how each aspect is weighted: - -##### 1. Outcome Selection is Weighted - -Unlike a simple majority vote, the winning outcome must accumulate more stake-weighted support than ALL other options combined (including oracle defense). This prevents a small but passionate minority from overriding the oracle. - -##### 2. Penalty is Weighted by Consensus Strength - -If `penalty_percent = +10000` (100%) but the community only barely overrides the oracle (51% vs 49%), the actual penalty applied is: - -``` -actual_penalty = insurance * 10000/10000 * 5100/10000 = insurance * 51% -``` - -Strong consensus (90% agreement) → nearly full penalty. Weak consensus → mild penalty. This is fair because a close call suggests the oracle's mistake was understandable. - -##### 3. Ban Duration is Weighted - -A temporary ban isn't fixed-length — it scales with `consensus_strength`: - -``` -effective_ban = ban_duration * consensus_strength / 10000 -``` - -If `ban_duration = 30 days` and consensus is 70%, the ban is 21 days. - -##### 4. Negative Penalty Protects Good-Faith Oracles - -Setting `penalty_percent = -5000` means: "even if the community overrides this oracle, give the oracle a bonus from the dispute fees." This is useful for: -- Subjective markets ("Best movie of 2025") -- Markets where the ground truth is genuinely ambiguous -- Encouraging oracles to participate in difficult markets - -##### 5. Creator Accountability - -The `creator_ban_type` field allows the community to also penalize market creators who set up misleading or fraudulent markets. The same weighted logic applies — a temporary ban scaled by consensus strength, or a permanent ban only with overwhelming agreement. - -### Comparison: Committee DAO vs Prediction Market Disputes - -| Aspect | Committee DAO | Prediction Market Dispute | -|---|---|---| -| **What is voted on** | Whether to fund a worker | Which outcome is correct | -| **Vote type** | Single scalar (−100% to +100%) | Outcome choice + conviction (−100% to +100%) | -| **Positive vote** | "Fund this worker" | "This outcome is correct" | -| **Negative vote** | "Don't fund" | "Oracle was right, reject dispute" | -| **Payout calculation** | `max * (actual_rshares / max_rshares)` | Penalty: `insurance * penalty% * consensus_strength` | -| **Participation threshold** | `approve_min_percent` of total vesting | Same mechanism | -| **Result** | Proportional payout from committee fund | Outcome correction + proportional penalty | -| **Self-funding** | Creation fees → committee fund | Dispute fees → resolution pool | - -### Summary - -The VIZ committee system provides a proven, battle-tested model for **stake-weighted collective decision-making** with bipolar voting. Applying the same principles to prediction market dispute resolution gives us: - -1. **Fair outcome selection**: 1 correct result chosen from N options, weighted by stake -2. **Proportional penalties**: oracle insurance fund penalty scales with community conviction -3. **Flexible punishment**: negative penalty percent to protect good-faith oracles in ambiguous markets -4. **Graduated bans**: temporary or permanent, with duration proportional to consensus strength -5. **Creator accountability**: same weighted mechanism applies to market creators -6. **Sybil resistance**: all votes weighted by staked VIZ, making manipulation expensive - -The fundamental advantage of this approach over binary "guilty/not guilty" arbitration systems is that **every parameter of the resolution is a gradient**, not a switch. This produces fairer outcomes in a decentralized setting where absolute truth is often elusive. diff --git a/.qoder/docs/consensus-emergency-params.md b/.qoder/docs/consensus-emergency-params.md deleted file mode 100644 index 6f0a2bf334..0000000000 --- a/.qoder/docs/consensus-emergency-params.md +++ /dev/null @@ -1,475 +0,0 @@ -# VIZ Blockchain — Consensus Emergency Parameters - -Parameters used to restart stuck consensus, their operational mechanics, and the micro-fork risks when operators forget to revert them after the emergency is resolved. - ---- - -## Overview - -When the VIZ network stalls — no blocks are produced because too few validators are online — operators can activate emergency parameters to unblock production: - -| Parameter | Normal Value | Emergency Value | Location | -|---|---|---|---| -| `enable-stale-production` | `false` | `true` | Validator Plugin | -| `required-participation` | `3300` (33%) | `0` | Validator Plugin | -| `fork_db` `_max_size` | `1024` (dynamic) | `1024` (initial) | chain library | - -Starting with Hardfork 12, the on-chain **emergency consensus activation** is fully automatic and deterministic. When the network stalls for >1 hour (`b.timestamp - lib_block.timestamp >= 3600`), emergency consensus mode activates on every node — no config flags needed. The activation uses only signed block timestamps from the chain state, ensuring identical results during replay. **All real validators are disabled** on activation (signing_key zeroed); operators must re-register via `witness_update_operation`. LIB advances every block (capped at HEAD−1), so the undo limit is never reached. Emergency exits automatically when 75% (16/21) of schedule slots are real validators. The older `enable-stale-production` and `required-participation` overrides are still available for pre-HF12 scenarios or manual recovery. - -These parameters are essential for chain recovery, but if left in emergency mode after the network stabilizes, they become the **root cause of micro-forks**: isolated delegates continue producing blocks on their own divergent chain during any subsequent network partition. - ---- - -## Parameter 1: `enable-stale-production` - -### Definition - -Controls whether the validator node produces blocks when the chain is "stale" — i.e., the node has not received recent blocks and its head block is behind the network. - -| Property | Value | -|---|---| -| Type | `bool` | -| Default | `false` | -| Command line | `--enable-stale-production` | -| Config file | `enable-stale-production = true` | -| Source | [validator.cpp:126](../../plugins/validator/validator.cpp#L126) | - -### How It Works - -When `enable-stale-production = false` (default), the Validator Plugin starts with `_production_enabled = false`. Before each production attempt, the check at [validator.cpp:333-339](../../plugins/validator/validator.cpp#L333) runs: - -```cpp -if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; // auto-enable once caught up - } else { - return block_production_condition::not_synced; - } -} -``` - -The node will **not** produce blocks until it receives a block whose timestamp places the next slot in the present or future — confirming it is synchronized with the network. Once caught up, production auto-enables permanently. - -When `enable-stale-production = true`, `_production_enabled` is set to `true` immediately at initialization ([validator.cpp:149-151](../../plugins/validator/validator.cpp#L149)), bypassing the sync check entirely. - -### Side Effect: `skip_undo_history_check` - -Setting `enable-stale-production = true` also activates the `skip_undo_history_check` production flag ([validator.cpp:184](../../plugins/validator/validator.cpp#L184)): - -```cpp -if (pimpl->_production_enabled) { - pimpl->_production_skip_flags |= graphene::chain::database::skip_undo_history_check; -} -``` - -This bypasses a critical safety assertion in `_apply_block` ([database.cpp:4114-4123](../../libraries/chain/database.cpp#L4114)): - -```cpp -if (!(skip & skip_undo_history_check)) { - CHAIN_ASSERT( - _dgp.head_block_number - _dgp.last_irreversible_block_num < CHAIN_MAX_UNDO_HISTORY, - undo_database_exception, - "The database does not have enough undo history..."); -} -``` - -`CHAIN_MAX_UNDO_HISTORY` = 10000 blocks ([config.hpp:108](../../libraries/protocol/include/graphene/protocol/config.hpp#L108)). Without this check, a node producing blocks alone can accumulate an unlimited gap between head and last irreversible block (LIB), since LIB only advances when enough validators sign off via block post-validation. - -### Emergency Use Case - -When the network has completely stalled (no validators producing), setting `enable-stale-production = true` on at least one validator node allows it to start producing blocks from its current head, even if it considers the chain stale. This breaks the deadlock and restarts block production. - -### Micro-Fork Risk - -**If the operator forgets to revert this to `false` after the network recovers**, any subsequent network partition causes the node to continue producing blocks in isolation: - -1. The node loses P2P connectivity to other validators -2. No new blocks are received, so `get_slot_time(1) < now` — but since `enable-stale-production = true`, this check is skipped -3. The node keeps producing blocks on its own fork -4. `skip_undo_history_check` means there is **no limit** on how far the head-LIB gap grows -5. When connectivity is restored, the node has a long divergent fork that must be reconciled - ---- - -## Parameter 2: `required-participation` - -### Definition - -The minimum validator participation rate (in basis points) required for block production. The participation rate measures what fraction of the last 128 block slots were actually filled by validators. - -| Property | Value | -|---|---| -| Type | `uint32_t` | -| Default | `33 * CHAIN_1_PERCENT` = `3300` (33%) | -| Range | 0–9900 (0%–99%) | -| Command line | `--required-participation ` | -| Config file | `required-participation = ` | -| Source | [validator.cpp:127](../../plugins/validator/validator.cpp#L127) | - -### Internal Representation - -The value is stored in **basis points** where `CHAIN_100_PERCENT = 10000` and `CHAIN_1_PERCENT = 100` ([config.hpp:57-58](../../libraries/protocol/include/graphene/protocol/config.hpp#L57)): - -- Config value `3300` = 33% participation threshold -- Config value `0` = no participation required (emergency) -- Config value `9900` = 99% participation required (very strict) - -### Participation Rate Calculation - -The rate is computed in [database.cpp:870-873](../../libraries/chain/database.cpp#L870): - -```cpp -uint32_t database::witness_participation_rate() const { - const dynamic_global_property_object &dpo = get_dynamic_global_properties(); - return uint64_t(CHAIN_100_PERCENT) * - dpo.recent_slots_filled.popcount() / 128; -} -``` - -`recent_slots_filled` is a 128-bit bitmask ([global_property_object.hpp:94](../../libraries/chain/include/graphene/chain/global_property_object.hpp#L94)) where each bit represents one of the last 128 block slots. A `1` means the slot was filled by a validator, `0` means it was missed. The rate is the percentage of filled slots. - -The bitmask is updated on each block application at [database.cpp:4060-4063](../../libraries/chain/database.cpp#L4060): - -```cpp -for (uint32_t i = 0; i < missed_blocks + 1; i++) { - dgp.participation_count -= dgp.recent_slots_filled.hi & 0x8000000000000000ULL ? 1 : 0; - dgp.recent_slots_filled = (dgp.recent_slots_filled << 1) + (i == 0 ? 1 : 0); - dgp.participation_count += (i == 0 ? 1 : 0); -} -``` - -For each missed block, a `0` is shifted in. For the current block, a `1` is shifted in. This gives a rolling 128-slot window of participation history. - -### Production Check - -Before producing a block, the Validator Plugin checks ([validator.cpp:436-439](../../plugins/validator/validator.cpp#L436)): - -```cpp -uint32_t prate = db.witness_participation_rate(); -if (prate < _required_witness_participation) { - capture("pct", uint32_t(prate / CHAIN_1_PERCENT)); - return block_production_condition::low_participation; -} -``` - -If the participation rate is below the threshold, block production is suppressed and the error message logs: -``` -Not producing block because node appears to be on a minority fork with only X% validator participation -``` - -### Emergency Use Case - -When the network has stalled, `recent_slots_filled` will be mostly zeros (many missed slots), so the participation rate will be very low — potentially below the 33% default threshold. Even if `enable-stale-production = true`, blocks won't be produced because the participation check fails. Setting `required-participation = 0` bypasses this safety check entirely. - -### Micro-Fork Risk - -**If the operator forgets to revert this to `3300` (33%) after the network recovers**, the participation check becomes ineffective: - -1. A network partition occurs -2. On the minority fork, `recent_slots_filled` decays (more missed slots) -3. With the default 33% threshold, production would stop within ~85 missed slots (when participation drops below 33%) -4. With `required-participation = 0`, the node **never stops producing** regardless of how isolated it is -5. A single validator on a completely isolated node continues producing blocks alone - -This is the most dangerous of the three parameters because it removes the **last automatic safeguard** against solo block production on a minority fork. - ---- - -## Parameter 3: `fork_db` `_max_size = 1024` - -### Definition - -The maximum number of blocks the fork database retains for fork detection and resolution. This is not a user-configurable parameter — it is hardcoded in the chain library. - -| Property | Value | -|---|---| -| Type | `uint32_t` | -| Default | `1024` blocks | -| Source | [fork_database.hpp:117](../../libraries/chain/include/graphene/chain/fork_database.hpp#L117) | -| Configurable | No (hardcoded) | - -### How It Works - -The fork database (`fork_database`) maintains a tree of recently received blocks, allowing the node to detect and switch between competing chain tips. When a new block arrives that extends a different parent than the current head, the node has a fork. - -The `_max_size` determines how many blocks are retained in the fork database. Blocks with `block_num < head_block_num - _max_size` are pruned ([fork_database.cpp:105-137](../../libraries/chain/fork_database.cpp#L105)). - -At 3-second block intervals, 1024 blocks equals approximately **51 minutes** of chain history. - -### Dynamic Resizing - -During normal operation, `_max_size` is dynamically resized to match the gap between head and LIB: - -```cpp -_fork_db.set_max_size(dpo.head_block_number - dpo.last_irreversible_block_num + 1); -``` - -This happens in three places: -- [database.cpp:4244-4245](../../libraries/chain/database.cpp#L4244) — after block post-validation chain check -- [database.cpp:4389-4390](../../libraries/chain/database.cpp#L4389) — after block post-validation application -- [database.cpp:4629-4630](../../libraries/chain/database.cpp#L4629) — after `update_last_irreversible_block` - -In normal operation with healthy participation, LIB advances within a few blocks of head, so `_max_size` is small (e.g., 10-30 blocks). The initial 1024 is only used until the first LIB advancement after startup. - -### Emergency Relevance - -When consensus is stuck, the fork database is mostly irrelevant (it contains few blocks). The 1024-block default is sufficient for initial chain restart scenarios. - -However, the fork_db becomes critical **after** the emergency, when forgotten parameters cause a delegate to produce blocks alone: - -1. **Isolation < 51 minutes**: The fork database can hold both the main chain and the divergent chain blocks. When connectivity is restored, fork resolution works correctly — the longer chain wins. - -2. **Isolation > 51 minutes**: The fork database has already pruned older blocks from the divergent chain. When the node reconnects, it cannot fully compare branches. The node must re-sync from the main chain, which involves popping blocks and replaying — a costly operation. - -3. **Isolation > CHAIN_MAX_UNDO_HISTORY blocks (~8.3 hours)**: Even with `skip_undo_history_check` bypassed during solo production, the state divergence is enormous. After reconnection, the node may need a full replay from a snapshot or block log. - -### Why 1024 Specifically - -The value 1024 matches the `MAX_BLOCK_REORDERING` constant ([fork_database.hpp:57](../../libraries/chain/include/graphene/chain/fork_database.hpp#L57)): - -```cpp -const static int MAX_BLOCK_REORDERING = 1024; -``` - -This limits how far back a block can be inserted out-of-order. Blocks more than 1024 positions behind the head are rejected with `unlinkable_block_exception`. The fork_db size and reordering limit are aligned to ensure consistent behavior. - ---- - -## The Combined Micro-Fork Scenario - -The three parameters interact to create a specific failure pattern: - -``` -Timeline: -──────────────────────────────────────────────────────────────────► - -1. Network stalls 2. Emergency activated 3. Network recovers - (no blocks) (delegate sets: (delegate forgets - enable-stale=true, to revert settings) - required-participation=0) - -4. Normal operation 5. Network partition 6. Micro-fork detected - (with emergency (delegate loses (delegate built blocks - settings still active) P2P connectivity) on its own fork) -``` - -### Step-by-step breakdown - -1. **Network stalls**: Insufficient validators are online to meet the 33% participation threshold. No blocks are produced. - -2. **Emergency activated**: A delegate sets `enable-stale-production = true` and `required-participation = 0` in their config. The node starts producing blocks, restarting the chain. - -3. **Network recovers**: Other validators come online, see the new blocks, and start participating. The network is healthy again — but the emergency settings are still active in the delegate's config. - -4. **Normal operation with emergency settings**: Everything appears fine. The delegate is producing blocks normally. The participation rate is high, so `required-participation = 0` makes no difference. The node is synced, so `enable-stale-production = true` makes no difference. - -5. **Network partition occurs**: The delegate's server loses P2P connectivity (ISP issue, DDoS, routing problem, etc.). - -6. **Micro-fork**: With the emergency settings still active: - - `enable-stale-production = true` → The node does not stop producing when it stops receiving blocks - - `required-participation = 0` → The participation check doesn't stop production even as `recent_slots_filled` decays - - `skip_undo_history_check` → No limit on head-LIB gap growth - - The delegate produces blocks on their own fork - -7. **Reconnection**: When connectivity is restored: - - If the isolation lasted < 51 minutes (< 1024 blocks): Fork resolution occurs via fork_db. The longer main chain wins, and the delegate's fork blocks are discarded. Short disruption. - - If the isolation lasted > 51 minutes but < ~8.3 hours: The fork_db has pruned old blocks. Re-sync required. Moderate disruption. - - If the isolation lasted > ~8.3 hours: Massive state divergence. Full replay may be needed. Severe disruption. - -### Why Normal Settings Prevent This - -With normal settings (`enable-stale-production = false`, `required-participation = 3300`): - -1. **Network partition occurs**: The node stops receiving blocks from other validators. - -2. **Participation decays**: `recent_slots_filled` shifts in zeros for each missed slot. After ~85 missed slots (about 4 minutes), participation drops below 33%. - -3. **Production stops**: The `low_participation` check suppresses block production. The node logs: - ``` - Not producing block because node appears to be on a minority fork with only X% validator participation - ``` - -4. **Even if participation hasn't decayed yet**: When the node's chain becomes stale (no recent blocks), the `_production_enabled` check would block production if `enable-stale-production = false` had been set and the node had somehow lost its synced state. - -The dual safeguard (stale check + participation check) ensures that an isolated delegate stops producing within minutes, keeping any potential fork to at most ~85 blocks (~4 minutes) — well within the fork_db's 1024-block resolution window. - ---- - -## Operational Guidelines - -### Activating Emergency Mode - -When the network has stalled and block production must be restarted: - -1. **Edit config.ini** (or pass command-line flags): - ```ini - # Needed for block production on a stale chain: - enable-stale-production = true - required-participation = 0 - ``` - Note: Emergency consensus activation (HF12+) is automatic and deterministic — no config flag is needed. When `b.timestamp - lib_block.timestamp >= 3600`, emergency mode activates on all nodes. - -2. **Restart the node**: - ```bash - vizd --enable-stale-production --required-participation=0 - ``` - -3. **Monitor production** — confirm blocks are being generated: - ``` - Generated block #N with timestamp T at time C by W - ``` - -4. **Wait for network recovery** — once other validators are back online and the participation rate stabilizes above 33%, **immediately revert the settings**. - -### Reverting Emergency Mode (Critical Step) - -```ini -enable-stale-production = false -required-participation = 3300 -``` - -Then restart the node. **Do not skip this step.** Leaving emergency settings active is the primary cause of micro-forks in practice. - -### Checklist for Emergency Activation - -| Step | Action | Verification | -|------|--------|-------------| -| 1 | Set `enable-stale-production = true` | Node produces blocks on stale chain | -| 2 | Set `required-participation = 0` | Production continues despite low participation | -| 3 | Monitor participation rate via API | `witness_participation_rate` rises as others rejoin | -| 4 | **When participation > 50%** | Revert both settings to normal values | -| 5 | Restart node with normal config | Confirm production continues with normal checks active | -| 6 | Verify `low_participation` safeguard works | Node would stop if isolated (test by briefly disconnecting) | - -### Red Flags: Emergency Settings Still Active - -If you observe any of these log patterns, a validator is likely running with emergency settings still active: - -- **Blocks produced during a network partition**: A validator that should have stopped continues generating blocks -- **Participation rate logs showing < 33% but blocks still produced**: `required-participation = 0` is active -- **Head-LIB gap growing beyond 10000 blocks**: `skip_undo_history_check` is active (via `enable-stale-production = true`) -- **Fork collision warnings with rapid reoccurrence**: Isolated validator creates competing blocks at the same heights - ---- - -## Configuration File Examples - -### Production validator (Normal Operation) - -```ini -# Normal validator configuration — SAFE -enable-stale-production = false -required-participation = 3300 -``` - -Source: [config_witness.ini:76-80](../../share/vizd/config/config_witness.ini#L76) - -### Debug / Testnet (Emergency Mode Acceptable) - -```ini -# Testnet/debug configuration — emergency settings acceptable -enable-stale-production = true -required-participation = 0 -``` - -Source: [config_debug.ini:95-99](../../share/vizd/config/config_debug.ini#L95), [config_testnet.ini:99-101](../../share/vizd/config/config_testnet.ini#L99) - -### Emergency Recovery (Temporary) - -```ini -# EMERGENCY ONLY — revert immediately after network recovers! -enable-stale-production = true -required-participation = 0 -``` - ---- - -## Technical Reference - -### Key Constants - -| Constant | Value | Meaning | Source | -|---|---|---|---| -| `CHAIN_100_PERCENT` | 10000 | 100% in basis points | [config.hpp:57](../../libraries/protocol/include/graphene/protocol/config.hpp#L57) | -| `CHAIN_1_PERCENT` | 100 | 1% in basis points | [config.hpp:58](../../libraries/protocol/include/graphene/protocol/config.hpp#L58) | -| `CHAIN_MAX_UNDO_HISTORY` | 10000 | Max head-LIB gap before undo history exception | [config.hpp:108](../../libraries/protocol/include/graphene/protocol/config.hpp#L108) | -| `CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC` | 3600 | Seconds since LIB before emergency activates | [config.hpp:112](../../libraries/protocol/include/graphene/protocol/config.hpp#L112) | -| `CHAIN_IRREVERSIBLE_THRESHOLD` | 7500 (75%) | validator validation threshold for LIB advancement | [config.hpp:110](../../libraries/protocol/include/graphene/protocol/config.hpp#L110) | -| `fork_db._max_size` | 1024 | Default fork database depth | [fork_database.hpp:117](../../libraries/chain/include/graphene/chain/fork_database.hpp#L117) | -| `MAX_BLOCK_REORDERING` | 1024 | Max out-of-order block insertion distance | [fork_database.hpp:57](../../libraries/chain/include/graphene/chain/fork_database.hpp#L57) | - -### Participation Rate Timeline - -With 3-second block intervals and 128-slot window: - -| Missed Slots | Participation Rate | Status | -|---|---|---| -| 0 | 100% | All validators active | -| 32 (1.6 min) | 75% | Healthy | -| 64 (3.2 min) | 50% | Degraded | -| 85 (4.3 min) | 33.6% | Just above default threshold | -| 86 (4.3 min) | 32.8% | **Below 33% — production stops** (with normal settings) | -| 96 (4.8 min) | 25% | Significant participation loss | -| 128 (6.4 min) | 0% | Complete stall | - -### Fork Database Depth Timeline - -| Solo Production Duration | Approx. Blocks | Fork DB Coverage | -|---|---|---| -| < 51 minutes | < 1024 | Full coverage — clean fork resolution | -| 51 min – 1 hour | 1020–1200 | Partial pruning begins | -| 1–8 hours | 1200–9600 | Significant pruning, re-sync likely needed | -| > 8.3 hours | > 10000 | Exceeds CHAIN_MAX_UNDO_HISTORY, replay may be needed | - -### Code Flow: Block Production Decision - -``` -maybe_produce_block() - │ - ├─ [HF12+] Is emergency_consensus_active? - │ └─ Yes: Three-state safety handles production/sync checks: - │ ├─ IS emergency master? (emergency key in _validators) - │ │ └─ Yes: _production_enabled = true (bypass sync/stale/participation) - │ └─ NOT emergency master (slave): - │ ├─ _production_enabled already? → continue - │ └─ Else: check get_slot_time(1) >= now - │ ├─ Yes: _production_enabled = true - │ └─ No: return not_synced - │ - ├─ Is _production_enabled? - │ ├─ No: Is chain synced (get_slot_time(1) >= now)? - │ │ ├─ Yes: _production_enabled = true (auto-enable) - │ │ └─ No: return not_synced ← BYPASSED when enable-stale-production=true - │ └─ Yes: continue - │ - ├─ Is it my turn? (scheduled validator check) - │ └─ No: return not_my_turn - │ - ├─ Do I have the private key? - │ └─ No: return no_private_key - │ - ├─ Is participation rate >= required-participation? - │ └─ No: return low_participation ← BYPASSED when required-participation=0 - │ - ├─ Am I within 500ms of scheduled time? - │ └─ No: return lag - │ - ├─ Fork collision in fork_db? - │ └─ Yes: return fork_collision - │ - ├─ Minority fork detection? (last 21 blocks all ours) - │ └─ Yes: return minority_fork ← BYPASSED when enable-stale-production=true - │ - └─ Generate and broadcast block - └─ return produced - -update_global_dynamic_data() — Emergency activation: - │ - ├─ HF12 not active or emergency already active? → skip - ├─ LIB block not available (snapshot restore)? → skip - ├─ seconds_since_lib = b.timestamp - lib_block.timestamp - ├─ seconds_since_lib < 3600? → skip - └─ Activate emergency consensus mode -``` - -The two emergency parameters bypass the two most important safeguards (steps 1 and 4), removing all automatic protection against solo production during network partitions. diff --git a/.qoder/docs/data-types.md b/.qoder/docs/data-types.md deleted file mode 100644 index f454271cb5..0000000000 --- a/.qoder/docs/data-types.md +++ /dev/null @@ -1,322 +0,0 @@ -# VIZ Blockchain — Common Data Types - -This document describes all shared data types used across VIZ protocol operations and virtual operations. These types appear as field types throughout operation structures. - ---- - -## Primitive Types - -| C++ type | JSON representation | Description | -|---|---|---| -| `string` | `string` | UTF-8 string | -| `bool` | `boolean` | true / false | -| `uint8_t` | `integer` | Unsigned 8-bit integer | -| `uint16_t` | `integer` | Unsigned 16-bit integer (0–65535) | -| `int16_t` | `integer` | Signed 16-bit integer (-32768–32767) | -| `uint32_t` | `integer` | Unsigned 32-bit integer | -| `int32_t` | `integer` | Signed 32-bit integer | -| `uint64_t` | `string` or `integer` | Unsigned 64-bit integer (use string in JS to avoid overflow) | -| `int64_t` | `string` or `integer` | Signed 64-bit integer | -| `share_type` | `integer` | Alias for `safe` — token satoshi amount | -| `time_point_sec` | `string` | ISO 8601 UTC datetime: `"2024-01-15T12:00:00"` | - ---- - -## `account_name_type` - -Fixed-length string (max 32 bytes). Must comply with domain-name rules: -- Dot-separated labels, each label 3+ characters -- Begins with a letter, ends with letter or digit -- Only lowercase letters, digits, hyphens -- Min length: `CHAIN_MIN_ACCOUNT_NAME_LENGTH` (2) -- Max length: `CHAIN_MAX_ACCOUNT_NAME_LENGTH` (16) - -**JSON:** plain string, e.g. `"alice"`, `"alice.bob"` - ---- - -## `public_key_type` - -A secp256k1 compressed public key encoded in base58check with `VIZ` prefix. - -**JSON:** string, e.g. `"VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9"` - -### Checklist -- [ ] Prefix must be `VIZ` (not `STM`, `GLS`, etc.) -- [ ] 33-byte compressed public key + 4-byte checksum = 37 bytes base58-encoded -- [ ] Validate checksum on deserialization - ---- - -## `asset` - -Represents a token amount with its symbol. - -``` -{ - "amount": integer, // satoshi value (int64) - "symbol": integer // asset_symbol_type (uint64) -} -``` - -**However**, in JSON API the asset is typically serialized as a string: -``` -"10.000 VIZ" -"5.000000 SHARES" -``` - -### Asset Symbols - -| Symbol name | String | Decimals | Description | -|---|---|---|---| -| `TOKEN_SYMBOL` | `VIZ` | 3 | Main liquid token | -| `SHARES_SYMBOL` | `SHARES` | 6 | Vesting shares (staked VIZ) | - -### Checklist -- [ ] Parse/format amount with correct decimal places (VIZ=3, SHARES=6) -- [ ] When constructing `asset` for operations, use the string format: `"10.000 VIZ"` -- [ ] Validate symbol matches expected token type per operation field - ---- - -## `authority` - -Multi-signature authority structure controlling an account's permission level. - -```json -{ - "weight_threshold": 1, - "account_auths": [ - ["alice", 1] - ], - "key_auths": [ - ["VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9", 1] - ] -} -``` - -### Fields - -| Field | Type | Description | -|---|---|---| -| `weight_threshold` | `uint32_t` | Minimum total weight required to satisfy authority | -| `account_auths` | `[[account_name, weight], ...]` | Account-based signers | -| `key_auths` | `[[public_key, weight], ...]` | Key-based signers | - -### Authority Levels - -| Level | Used for | -|---|---| -| `master` | Highest security — changing keys, account recovery | -| `active` | Token operations — transfer, vesting, validator voting | -| `regular` | Social operations — content, awards, committee voting | - -### Checklist -- [ ] Sum of weights for satisfied keys/accounts must be >= `weight_threshold` -- [ ] `account_auths` entries are `[string, uint16]` pairs -- [ ] `key_auths` entries are `[string, uint16]` pairs (public key as VIZ-prefixed base58) -- [ ] Empty authority = `{ "weight_threshold": 0, "account_auths": [], "key_auths": [] }` - ---- - -## `beneficiary_route_type` - -Specifies a beneficiary account and their share weight for content rewards. - -```json -{ - "account": "alice", - "weight": 2500 -} -``` - -| Field | Type | Description | -|---|---|---| -| `account` | `account_name_type` | Beneficiary account name | -| `weight` | `uint16_t` | Weight in basis points (100% = 10000) | - -### Checklist -- [ ] Sum of all beneficiary weights must not exceed 10000 (100%) -- [ ] Beneficiaries array must be sorted by account name (ascending) -- [ ] Each beneficiary account must exist on-chain - ---- - -## `extensions_type` - -Currently unused — always an empty array `[]`. - -```json -"extensions": [] -``` - ---- - -## `versioned_chain_properties` - -A static variant holding one of the chain property versions. The variant is serialized as a 2-element array `[type_index, object]`. - -| Index | Type | -|---|---| -| 0 | `chain_properties_init` | -| 1 | `chain_properties_hf4` | -| 2 | `chain_properties_hf6` | -| 3 | `chain_properties_hf9` | - -Example (hf9 = index 3): -```json -[3, { - "account_creation_fee": "1.000 VIZ", - "maximum_block_size": 65536, - "create_account_delegation_ratio": 10, - "create_account_delegation_time": 2592000, - "min_delegation": "1.000 VIZ", - "min_curation_percent": 0, - "max_curation_percent": 10000, - "bandwidth_reserve_percent": 1000, - "bandwidth_reserve_below": "1.000000 SHARES", - "flag_energy_additional_cost": 1000, - "vote_accounting_min_rshares": 0, - "committee_request_approve_min_percent": 1000, - "inflation_witness_percent": 2000, - "inflation_ratio_committee_vs_reward_fund": 1000, - "inflation_recalc_period": 28800, - "data_operations_cost_additional_bandwidth": 0, - "witness_miss_penalty_percent": 100, - "witness_miss_penalty_duration": 86400, - "create_invite_min_balance": "1.000 VIZ", - "committee_create_request_fee": "1.000 VIZ", - "create_paid_subscription_fee": "1.000 VIZ", - "account_on_sale_fee": "10.000 VIZ", - "subaccount_on_sale_fee": "1.000 VIZ", - "witness_declaration_fee": "1.000 VIZ", - "withdraw_intervals": 28 -}] -``` - ---- - -## `chain_properties_init` Fields - -| Field | Type | Default | Description | -|---|---|---|---| -| `account_creation_fee` | `asset` (VIZ) | `1.000 VIZ` | Fee to create a new account | -| `maximum_block_size` | `uint32_t` | 131072 | Max block size in bytes | -| `create_account_delegation_ratio` | `uint32_t` | 10 | Ratio of delegated SHARES on account creation | -| `create_account_delegation_time` | `uint32_t` | 2592000 | Minimum delegation time (seconds) | -| `min_delegation` | `asset` (VIZ) | `1.000 VIZ` | Minimum delegation amount | -| `min_curation_percent` | `int16_t` | 0 | Min curation reward percent (basis points) | -| `max_curation_percent` | `int16_t` | 10000 | Max curation reward percent (basis points) | -| `bandwidth_reserve_percent` | `int16_t` | 1000 | % of bandwidth reserved for low-stake accounts | -| `bandwidth_reserve_below` | `asset` (SHARES) | `1.000000 SHARES` | Threshold for bandwidth reserve | -| `flag_energy_additional_cost` | `int16_t` | 1000 | Extra energy cost for flag/downvote | -| `vote_accounting_min_rshares` | `uint32_t` | 0 | Min rshares for payout accounting | -| `committee_request_approve_min_percent` | `int16_t` | 1000 | Min approval % for committee requests | - -## Additional fields in `chain_properties_hf4` - -| Field | Type | Description | -|---|---|---| -| `inflation_witness_percent` | `int16_t` | validator reward % from block inflation | -| `inflation_ratio_committee_vs_reward_fund` | `int16_t` | Ratio committee/reward fund | -| `inflation_recalc_period` | `uint32_t` | Blocks per inflation recalc | - -## Additional fields in `chain_properties_hf6` - -| Field | Type | Description | -|---|---|---| -| `data_operations_cost_additional_bandwidth` | `uint32_t` | Extra bandwidth % for data operations | -| `witness_miss_penalty_percent` | `int16_t` | Vote penalty % for missed block | -| `witness_miss_penalty_duration` | `uint32_t` | Duration of miss penalty (seconds) | - -## Additional fields in `chain_properties_hf9` - -| Field | Type | Description | -|---|---|---| -| `create_invite_min_balance` | `asset` (VIZ) | Min balance to create invite | -| `committee_create_request_fee` | `asset` (VIZ) | Fee to create committee request | -| `create_paid_subscription_fee` | `asset` (VIZ) | Fee to create paid subscription | -| `account_on_sale_fee` | `asset` (VIZ) | Fee to list account for sale | -| `subaccount_on_sale_fee` | `asset` (VIZ) | Fee to list subaccounts for sale | -| `witness_declaration_fee` | `asset` (VIZ) | Fee to declare as validator | -| `withdraw_intervals` | `uint16_t` | Number of withdraw intervals | - ---- - -## Operation Type Indices - -The `operation` is a `static_variant`. When serialized, it is a 2-element array: `[type_id, operation_object]`. - -### Regular Operations - -| ID | Operation Name | -|---|---| -| 0 | `vote_operation` *(deprecated)* | -| 1 | `content_operation` *(deprecated)* | -| 2 | `transfer_operation` | -| 3 | `transfer_to_vesting_operation` | -| 4 | `withdraw_vesting_operation` | -| 5 | `account_update_operation` | -| 6 | `witness_update_operation` | -| 7 | `account_witness_vote_operation` | -| 8 | `account_witness_proxy_operation` | -| 9 | `delete_content_operation` *(deprecated)* | -| 10 | `custom_operation` | -| 11 | `set_withdraw_vesting_route_operation` | -| 12 | `request_account_recovery_operation` | -| 13 | `recover_account_operation` | -| 14 | `change_recovery_account_operation` | -| 15 | `escrow_transfer_operation` | -| 16 | `escrow_dispute_operation` | -| 17 | `escrow_release_operation` | -| 18 | `escrow_approve_operation` | -| 19 | `delegate_vesting_shares_operation` | -| 20 | `account_create_operation` | -| 21 | `account_metadata_operation` | -| 22 | `proposal_create_operation` | -| 23 | `proposal_update_operation` | -| 24 | `proposal_delete_operation` | -| 25 | `chain_properties_update_operation` | - -### Virtual Operations - -| ID | Operation Name | -|---|---| -| 26 | `author_reward_operation` | -| 27 | `curation_reward_operation` | -| 28 | `content_reward_operation` | -| 29 | `fill_vesting_withdraw_operation` | -| 30 | `shutdown_witness_operation` | -| 31 | `hardfork_operation` | -| 32 | `content_payout_update_operation` | -| 33 | `content_benefactor_reward_operation` | -| 34 | `return_vesting_delegation_operation` | -| 35 | `committee_worker_create_request_operation` | -| 36 | `committee_worker_cancel_request_operation` | -| 37 | `committee_vote_request_operation` | -| 38 | `committee_cancel_request_operation` *(virtual)* | -| 39 | `committee_approve_request_operation` *(virtual)* | -| 40 | `committee_payout_request_operation` *(virtual)* | -| 41 | `committee_pay_request_operation` *(virtual)* | -| 42 | `witness_reward_operation` *(virtual)* | -| 43 | `create_invite_operation` | -| 44 | `claim_invite_balance_operation` | -| 45 | `invite_registration_operation` | -| 46 | `versioned_chain_properties_update_operation` | -| 47 | `award_operation` | -| 48 | `receive_award_operation` *(virtual)* | -| 49 | `benefactor_award_operation` *(virtual)* | -| 50 | `set_paid_subscription_operation` | -| 51 | `paid_subscribe_operation` | -| 52 | `paid_subscription_action_operation` *(virtual)* | -| 53 | `cancel_paid_subscription_operation` *(virtual)* | -| 54 | `set_account_price_operation` | -| 55 | `set_subaccount_price_operation` | -| 56 | `buy_account_operation` | -| 57 | `account_sale_operation` *(virtual)* | -| 58 | `use_invite_balance_operation` | -| 59 | `expire_escrow_ratification_operation` *(virtual)* | -| 60 | `fixed_award_operation` | -| 61 | `target_account_sale_operation` | -| 62 | `bid_operation` *(virtual)* | -| 63 | `outbid_operation` *(virtual)* | diff --git a/.qoder/docs/dlt-4-node-code-audit-2026-05-08.md b/.qoder/docs/dlt-4-node-code-audit-2026-05-08.md deleted file mode 100644 index 0b174a6b9f..0000000000 --- a/.qoder/docs/dlt-4-node-code-audit-2026-05-08.md +++ /dev/null @@ -1,321 +0,0 @@ -# DLT P2P Node — Code Audit vs. Documentation (2026-05-08) - -Audit of the `fix-validator` branch against the problem/fix log in -`dlt-4-node-sync-scenarios.md`. Checks which fixes are actually in the code, -identifies logic errors not yet documented, and lists undocumented problems -found via code comments. - ---- - -## Status of Documented Fixes - -### Fixes (2026-05-05) — alignment & handshake - -| # | Description | Status | -|---|-------------|--------| -| P1/P2/P6/P7/P8/P13/P15 | `check_fork_alignment` extended with boundary link + range overlap | **DONE** — `dlt_p2p_node.cpp:788-828` | -| P9 | Empty peer (`head_block_num==0`) returns `true` immediately | **DONE** — line 796-798 | -| P3/P14 | `on_dlt_hello` lifecycle: `hello.node_status == DLT_NODE_STATUS_SYNC` added | **DONE** — line ~867 | -| P4 | Block range start clamped to `peer_dlt_earliest` | **DONE** — line 1049 | - -### Fixes (2026-05-06) — stability & crash protection - -| # | Description | Status | -|---|-------------|--------| -| P20/P21 | `DEAD_FORK` enum + `accept_block` returns DEAD_FORK for unlinkable at/below head | **DONE** — `p2p_plugin.cpp:240-283` | -| P20/P21 | `on_dlt_block_range_reply` soft-bans on DEAD_FORK | **DONE** — line 1263-1271 | -| P20/P21 | `on_dlt_block_reply` soft-bans on DEAD_FORK | **DONE** — line 1456-1462 | -| P20/P21 | `transition_to_forward()` in range reply guarded by `any_block_applied` | **DONE** — line 1297 | -| P17 | `dlt_block_log::is_consistent_with()` + corruption auto-reset in `database::open()` | **DONE** | -| P22 | Grace period: near-head blocks → FORK_DB_ONLY not DEAD_FORK for first 60s | **DONE** — `p2p_plugin.cpp:248-277` | -| P24 | `_block_processing_paused` early-return in periodic task | **DONE** — line 598 | -| P24 | Per-block pause check inside range processing loop | **DONE** — line 1195 | -| P27 | Write lock diagnostic logging in `notify_applied_block` | **DONE** | -| P19 | Gap detection: log warning when our head < peer_earliest | **DONE** — line 1012-1014 | -| P25 | `exchange_enabled` re-evaluated when peer block accepted | **DONE** — line 1247-1249 | -| P26 | `check_sync_catchup()` called on single-block accept | **DONE** — line 1495 | -| P31 | `constexpr uint32_t dlt_peer_state::MAX_RECONNECT_BACKOFF_SEC;` defined | **DONE** — line 25 | -| P28/P29/P30 | Build errors in p2p_plugin.cpp / multimap::erase / validator header | **DONE** | - ---- - -## Logic Errors Found in Current Code - -### BUG-A: `range_fallback_mode` transition to FORWARD without `any_block_applied` guard - -**File:** [dlt_p2p_node.cpp:1513-1527](libraries/network/dlt_p2p_node.cpp#L1513-L1527) - -```cpp -// on_dlt_block_reply — fallback path -if (state.range_fallback_mode && _node_status == DLT_NODE_STATUS_SYNC) { - if (reply.next_available > 0) { - // request next block - } else if (reply.is_last) { - state.range_fallback_mode = false; - transition_to_forward(); // ← UNGUARDED - } -} -``` - -**Problem:** When range deserialization fails, the node falls back to requesting blocks -one-at-a-time. If the peer's replies are all `ALREADY_KNOWN` or `FORK_DB_ONLY` (no -block actually applied to the chain) and the peer sends `is_last=true`, the node calls -`transition_to_forward()` without having made any real progress. The node can enter -FORWARD mode while still behind the network. - -**Contrast:** The range reply handler at line 1297 has the correct guard: -```cpp -if (any_block_applied) { - if (reply.is_last) { transition_to_forward(); } -} -``` - -**Fix:** Track `any_block_applied` in `on_dlt_block_reply` and gate the fallback -`transition_to_forward()` on it, OR replace the call with `check_sync_catchup()` which -already verifies all active peers' heads before transitioning. - -**Severity:** HIGH — node can enter FORWARD without catching up, misses blocks, never -re-enters SYNC because it thinks it's caught up. - ---- - -### BUG-B: `check_fork_alignment` returns `true` for empty peer but `exchange_enabled` becomes `true` - -**File:** [dlt_p2p_node.cpp:792-798](libraries/network/dlt_p2p_node.cpp#L792-L798) - -```cpp -if (hello.head_block_num == 0) { - return true; // recognized_head_out stays zero_id -} -``` - -For empty peers `fork_alignment=true` → `exchange_enabled=true`. This is intentional -(they stay connected). However, in `send_to_all_our_fork_peers`, block broadcasts are -sent to all `exchange_enabled` peers. An empty peer (slaveC) will receive forward blocks -it cannot process (its fork_db is empty). This wastes bandwidth and could fill its -fork_db with unlinked blocks if it has no snapshot yet. - -**Current mitigation:** `request_blocks_from_peer` checks `peer_latest == 0` and -doesn't send range requests. But broadcast blocks still arrive. - -**Severity:** LOW — bandwidth waste; not a correctness issue since blocks that can't -link go to `_unlinked_index` and are eventually pruned. - ---- - -### BUG-C: `check_fork_alignment` range-overlap branch can silently fail for in-range peers - -**File:** [dlt_p2p_node.cpp:803-808](libraries/network/dlt_p2p_node.cpp#L803-L808) - -```cpp -if (hello.head_block_num >= our_earliest && hello.head_block_num <= our_latest) { - if (_delegate->is_block_known(hello.head_block_id)) { - recognized_head_out = hello.head_block_id; - } - // ← no else: if is_block_known returns false, we silently skip -} -``` - -If a peer's head is numerically within our DLT range but `is_block_known` returns -`false` (e.g., it's a competing fork tip within our range), `recognized_head_out` stays -zero. The code then falls to the LIB check. If LIB also fails, `fork_alignment=false`. -This is the **correct** behavior for a hostile fork peer. - -However: in DLT mode, blocks at the boundary of the rolling window can be partially -pruned from the chain index. A legitimate peer at e.g. `our_earliest + 2` may have its -block ID not in `is_block_known` if the index was trimmed. This is a narrow window but -can cause a false `fork_alignment=false` for a valid peer. - -**Severity:** LOW — rare; only during the first few blocks of the DLT window. The -boundary link check and LIB fallback provide redundancy. - ---- - -### BUG-D: `transition_to_forward()` called from `check_sync_catchup()` without checking peers with `peer_head_num == 0` - -**File:** [dlt_p2p_node.cpp:2406-2445](libraries/network/dlt_p2p_node.cpp#L2406-L2445) - -```cpp -// check_sync_catchup: -for (const auto& _peer_item : _peer_states) { - ... - if (state.peer_head_num == 0) continue; // skip peers with no head info - if (our_head < state.peer_head_num) { - has_peer_ahead = true; - break; - } -} -// If no peer is ahead → transition to FORWARD -``` - -Peers are skipped if `peer_head_num == 0`. Empty peers (slaveC) and peers whose hello -didn't include a head num will be skipped. If slaveC is the ONLY connected peer and our -head is 1500, `has_peer_ahead = false` → `transition_to_forward()`. The node enters -FORWARD mode "connected" to an empty peer, with no real connectivity to the network. - -This can happen during initial startup or after all block-bearing peers disconnect while -only an empty peer remains. - -**Severity:** MEDIUM — leads to an oscillation: FORWARD on an empty peer → no blocks -arrive → `check_forward_stagnation()` falls back to SYNC → requests from empty peer → -no reply → stagnation again. - ---- - -## Undocumented Problems Fixed in Code (P32+) - -The code comments reference problems not yet in `dlt-4-node-sync-scenarios.md`. - -| Code tag | Description inferred from comments | -|----------|------------------------------------| -| **P36** | Out-of-order single block received in FORWARD mode triggers unnecessary SYNC→FORWARD oscillation. Fixed: gap fill requested instead of mode switch. (`dlt_p2p_node.cpp:1378-1383`) | -| **P37** | `peer_head_num` goes stale after hello — not updated when the peer sends us blocks. Fixed: `peer_head_num` updated from received block number in both range and single-block handlers. (`lines 1183-1185, 1339-1341`) | -| **P39** | `fork_db._head` jumps ahead of database head via `_push_next` cascade when a parent block arrives. The block being pushed can then appear "too old" (block_too_old_exception). Fixed in `_push_block`. (`p2p_plugin.cpp:185-192`) | -| **P40** | Iterator invalidation in `periodic_lifecycle_timeout_check()` when `handle_disconnect` erases entries from `_peer_states` during iteration. Fixed: collect timed-out peers into a vector first. (`dlt_p2p_node.cpp:417-418`) | -| **P42** | `request_blocks_from_peer` uses stale `peer_dlt_latest` as the peer's chain tip. Fixed: `peer_latest = max(peer_dlt_latest, peer_head_num)` to use whichever is fresher. (`dlt_p2p_node.cpp:956-960`) | -| **P49** | Range request starts at `our_head + 1`, skipping our own head block. If two validators signed competing blocks at the same height, we'd never detect the divergence. Fixed: start at `our_head`. (`dlt_p2p_node.cpp:982-986`) | - ---- - -## Documentation Gaps - -The `dlt-4-node-sync-scenarios.md` file ends at P31 but the codebase implements fixes -through at least P49. The following sections are absent from the documentation: - -1. **P32-P35** — not referenced in any code comment; may be internal tracking numbers - or obsolete entries. -2. **P36-P40** — out-of-order oscillation, stale peer head, fork_db cascade, iterator - invalidation — all fixed in code but not in docs. -3. **P42, P49** — stale peer_dlt_latest, sync start offset — fixed in code, not in docs. - -**Recommendation:** Update `dlt-4-node-sync-scenarios.md` with a "Post-P31 Fixes" -section covering P36-P49. - ---- - ---- - -### BUG-E: Spam strike on fork_db-only range response causes false soft-ban of master peer - -**File:** [dlt_p2p_node.cpp:1288](libraries/network/dlt_p2p_node.cpp#L1288) - -```cpp -record_packet_result(peer, any_block_applied); // BUG: penalises legit fork_db batches -``` - -During a large-gap sync (`head=79740486`, `peer_head=79746356`, gap=5854), the node syncs -from LIB using `request_blocks_from_peer`. The peer is on the majority fork; the node's -head diverged. Every range response has `any_block_applied=false` (all blocks go to -`fork_db` as competing-fork candidates). After 10 such responses `spam_strikes` reaches -`SPAM_STRIKE_THRESHOLD` → soft-ban for 3600s. - -The same `on_dlt_block_range_r` handler explicitly continues fetching for `fork_db`-only -batches (line 1304-1310, "competing fork? — continue fetch") while simultaneously -punishing the peer for sending them. Self-contradictory. - -**Observed log:** -``` -Soft-banning peer 185.146.232.170:2001 for 3600s (reason: spam strike threshold exceeded) -``` - -**Severity:** HIGH — the node's only sync peer gets banned mid-sync; gap never fills. - ---- - -### BUG-F: DLT snapshot node cannot accept competing fork starting at snapshot LIB block - -**Files:** [database.cpp:355-376](libraries/chain/database.cpp#L355), [database.cpp:1518-1522](libraries/chain/database.cpp#L1518), [fork_database.cpp](libraries/chain/fork_database.cpp) - -After importing a DLT snapshot at block N (e.g. 79740482): -1. DLT block log starts at N+1; block N is **not stored** anywhere `fetch_block_by_id` - can reach (no main block_log in DLT mode; DLT log starts at N+1; fork_db seeded - with head-only via `start_block`). -2. Fork_db seeded top-down: only the head block (N+4) is inserted via `start_block` - with `prev=null`; blocks N+1…N+3 are absent from fork_db entirely. -3. Master peer is on the majority fork diverging at block N+1. -4. Master sends sync range starting at N: block N arrives → `ALREADY_KNOWN` - (same ID) → silently discarded. Block N+1_master (parent=N.id) arrives: - - `is_known_block(N.id)` → **false** (N not in fork_db) - - `fetch_block_by_id(N.id)` → **null** (not in any log) - - → DEAD_FORK. Rejected forever. -5. Fork switch never triggers; node stays stuck at N+4 while master advances. - -**Observed log:** -``` -Rejecting block 79740483 from a different fork: parent not in fork_db and not on main chain (head=79740486) -Range stored in fork_db only (competing fork?), continuing fetch from #79740682 -``` -*(continues indefinitely, head never advances)* - -**Root causes (two independent failures):** -- DLT seeding builds no `prev` chain; `fetch_branch_from` would crash walking the slave - branch past the null `prev` on the `start_block` root. -- Snapshot block N is unreachable via `fetch_block_by_id`, so `_push_block` cannot seed - fork_db with it when N+1_master arrives. - -**Severity:** CRITICAL — node with a diverged head after snapshot is permanently stuck; -gap never fills regardless of how many peers are connected. - ---- - -## Summary - -``` -BUG-A [HIGH] range_fallback_mode transition_to_forward() not guarded → FIXED (2026-05-08) -BUG-B [LOW] Empty peer gets exchange_enabled=true → broadcast waste (accepted as-is) -BUG-C [LOW] check_fork_alignment range-overlap silent fail at window boundary (accepted as-is) -BUG-D [MEDIUM] check_sync_catchup ignores peer_head_num==0 peers → FIXED (2026-05-08) -BUG-E [HIGH] fork_db-only range response counted as spam → soft-ban → FIXED (2026-05-08) -BUG-F [CRITICAL] DLT snapshot: competing fork starting at LIB permanently rejected → FIXED (2026-05-08) - -DOCS [INFO] P32-P49 implemented in code but not documented in dlt-4-node-sync-scenarios.md -``` - -### Fixes Applied (2026-05-08) - -**BUG-A** — [dlt_p2p_node.cpp:1523-1527](libraries/network/dlt_p2p_node.cpp#L1523-L1527) - -Replaced `transition_to_forward()` with `check_sync_catchup()` in the `range_fallback_mode` path. `check_sync_catchup()` already verifies that our head ≥ all known-head peers before transitioning, so it correctly handles the case where all single-block replies were ALREADY_KNOWN/FORK_DB_ONLY with no real progress. - -**BUG-D** — [dlt_p2p_node.cpp:2420-2462](libraries/network/dlt_p2p_node.cpp#L2420-L2462) - -Added `known_head_peers` counter alongside `active_peer_count`. Empty peers (`peer_head_num==0`) still count toward `active_peer_count` (so isolation detection works) but do not increment `known_head_peers`. The final transition guard now requires `known_head_peers > 0 && !has_peer_ahead`: a node surrounded only by empty peers will never claim "caught up" and stays in SYNC until the stagnation / snapshot-plugin recovery path fires. - -**BUG-E** — [dlt_p2p_node.cpp:1290](libraries/network/dlt_p2p_node.cpp#L1290) - -Changed `record_packet_result(peer, any_block_applied)` to -`record_packet_result(peer, any_block_applied || any_fork_db_only)`. - -A peer that sends valid blocks landing in fork_db (normal during competing-fork or -LIB-based sync) provides useful data and must not be penalised. The existing continuation -path at line 1304 already recognises this ("competing fork — keep fetching"), making the -spam penalty a direct contradiction. With the fix, spam strikes only accumulate when the -peer sends batches that produce neither applied blocks nor fork_db entries (true spam or -dead-fork responses). - -**BUG-F** — [database.cpp](libraries/chain/database.cpp), [fork_database.cpp](libraries/chain/fork_database.cpp), [fork_database.hpp](libraries/chain/include/graphene/chain/fork_database.hpp) - -Three coordinated changes: - -1. **DLT mode startup seeding** ([database.cpp:~355](libraries/chain/database.cpp#L355)): - Replaced single-block `start_block(head)` with bottom-up seeding. Scans the DLT - block log for the oldest block within a 100-block window, uses `start_block` on it, - then pushes each successive block in order up to the head. Result: the slave's recent - chain (e.g. N+1…N+4) is in fork_db with correct `prev` pointers so - `fetch_branch_from` can walk the slave branch during fork switch. - -2. **ALREADY_KNOWN path** ([database.cpp:1518](libraries/chain/database.cpp#L1518)): - When block N arrives as ALREADY_KNOWN and is not yet in fork_db, call - `_fork_db.insert_as_base(new_block)`. The peer sent us the full block data — this - is the only opportunity to seed fork_db with the snapshot LIB block whose data is - absent from every log file. - -3. **`fork_database::insert_as_base` + `_repair_child_prev_links`** - ([fork_database.cpp](libraries/chain/fork_database.cpp)): - `insert_as_base(b)` inserts block `b` into `_index` without requiring its parent to - be present (it is a known-chain anchor). Calls `_push_next` to link any blocks in - `_unlinked_index` waiting for this parent, then calls `_repair_child_prev_links` which - finds child blocks already in `_index` (inserted via `start_block` with null `prev`) - and sets their `prev` pointer. This reconnects the slave chain so - `fetch_branch_from` can traverse it: both the slave branch and the master's - competing branch now walk back to block N as their common ancestor. diff --git a/.qoder/docs/dlt-4-node-sync-scenarios.md b/.qoder/docs/dlt-4-node-sync-scenarios.md deleted file mode 100644 index 46e49a26c1..0000000000 --- a/.qoder/docs/dlt-4-node-sync-scenarios.md +++ /dev/null @@ -1,992 +0,0 @@ -# DLT 4-Node Sync Scenarios — Problems & Analysis - -Analysis of a 4-node DLT network under emergency consensus: 1 master + 3 slaves, based on the current `dlt_p2p_node.cpp` implementation. - ---- - -## Network Setup - -``` -Master: dlt_block_log [1000-2000], snapshot at block 1500, FORWARD mode -slaveA: head at block 800, no snapshot, SYNC mode -slaveB: head at block 999, no snapshot, SYNC mode -slaveC: no blocks at all, SYNC mode -``` - -All nodes have each other as seeds. Emergency consensus is active. - ---- - -## Scenario 1: slaveA (head=800) - -### Step-by-step - -**1. slaveA connects to master → sends `dlt_hello_message`:** -``` -head_block_num=800, head_block_id= -lib_block_num=790, lib_block_id= -dlt_earliest_block=0 (or whatever), dlt_latest_block=800 -node_status=SYNC -``` - -**2. Master receives slaveA's hello → `on_dlt_hello()`:** - -- Stores slaveA's chain state in `dlt_peer_state` -- Calls `build_hello_reply(peer, hello)`: - - `check_fork_alignment(H800, H790)`: - - `is_block_known(H800)` → **FALSE** — master's dlt block log is [1000-2000], block 800 has been pruned. If `is_block_known` also checks the chain index and block 800 was pruned from there too, it returns false. - - `is_block_known(H790)` → **FALSE** — same reason. - - **Result: `fork_alignment = false`** - - `exchange_enabled = fork_alignment = false` - -- **Lifecycle transition check (line 500-504):** - ```cpp - if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC) - ``` - - `exchange_enabled = false` - - `_node_status` = DLT_NODE_STATUS_FORWARD (master) - - `false || false` → **false** → slaveA stays in **HANDSHAKING** on master - -- Records packet as good: `record_packet_result(peer, true)` — no spam strike - -**3. Master sends `dlt_hello_reply_message`:** -``` -exchange_enabled=false, fork_alignment=false -``` - -**4. Master's periodic check → `periodic_lifecycle_timeout_check()`:** -- slaveA has been in HANDSHAKING for >10s → **TIMEOUT** → `handle_disconnect()` -- slaveA disconnected with backoff - -**5. slaveA's perspective (receiving master's hello):** - -When master sent its hello (head=2000, LIB=1990), slaveA received it: -- `check_fork_alignment(H2000, H1990)`: - - `is_block_known(H2000)` → **FALSE** (slaveA only has up to 800) - - `is_block_known(H1990)` → **FALSE** - - **Result: `fork_alignment = false`** - -- Lifecycle transition: `exchange_enabled(false) || _node_status(SYNC)` → **true** (slaveA is SYNC) -- Master transitions to ACTIVE on slaveA's side -- `_node_status == SYNC && exchange_enabled` → `true && false` → **does NOT request blocks** - -**6. slaveA sync stagnation:** -- `sync_stagnation_check()` runs every ~5s via periodic task -- After 30s with no block received → retry 1/3 → re-requests from all active peers (master: `request_blocks_from_peer`) - - `our_head(800) >= peer_latest(2000)`? → **No**, 800 < 2000 - - Requests blocks 801-1000 from master - - Master receives `dlt_get_block_range_message(start=801, end=1000)` - - `on_dlt_get_block_range()`: loops 801..1000, calls `read_block_by_num(n)` — blocks 801-999 return empty (not in dlt block log), blocks 1000 returns the block - - Reply contains only block 1000 (blocks 801-999 are missing from master's dlt log) - - slaveA receives block 1000, `prev=H999` ≠ `slaveA's head H800` → "does NOT link to our head — possible fork" - - Block goes to fork_db as unlinkable - -- After 3 stagnation retries (90s total) → `transition_to_forward()` - -**7. Snapshot plugin kicks in:** -- `stalled-sync-timeout-minutes` (default 2 min) after last block -- Snapshot plugin: detects stall → tries P2P recovery (trigger_resync) → waits 1 min → downloads snapshot from trusted peers (master) -- After snapshot import at block 1500, slaveA resyncs from 1500 → catches up to 2000 - -### Problems Identified - -| # | Problem | Severity | -|---|---------|----------| -| P1 | **`check_fork_alignment` is too narrow**: Only checks if peer's head/LIB ID is known. In DLT mode, old blocks are pruned. A peer at block 800 IS on the same chain but can't prove it because blocks 800-999 are gone. | **CRITICAL** | -| P2 | **No range-overlap check**: The code doesn't check if `peer_head_num` is within `[our_dlt_earliest, our_dlt_latest]` or adjacent to it. This is the obvious fix — if ranges are adjacent and the boundary block links, the peer IS fork-aligned. | **CRITICAL** | -| P3 | **HANDSHAKING timeout loop**: When exchange_enabled=false and master is FORWARD, the peer stays in HANDSHAKING forever → 10s timeout → disconnect → reconnect → repeat. The backoff grows to 3600s. This wastes connections and delays recovery. | **HIGH** | -| P4 | **Wasted block requests**: slaveA requests blocks 801-1000 from master. Master only has 1000. Blocks 801-999 are served as empty. This wastes bandwidth and the partial reply (just block 1000) goes to fork_db. | **MEDIUM** | -| P5 | **Recovery is entirely snapshot-plugin driven**: The P2P layer has no "you need a snapshot" signal. It relies on the snapshot plugin's stalled-sync detection, which takes 2+ minutes. | **HIGH** | - ---- - -## Scenario 2: slaveB (head=999) - -### Step-by-step - -**1. slaveB connects to master → sends `dlt_hello_message`:** -``` -head_block_num=999, head_block_id= -lib_block_num=989, lib_block_id= -dlt_earliest_block=0, dlt_latest_block=999 -node_status=SYNC -``` - -**2. Master receives slaveB's hello → `on_dlt_hello()`:** - -- `check_fork_alignment(H999, H989)`: - - `is_block_known(H999)` → **FALSE** — block 999 is NOT in master's dlt block log [1000-2000]. It was pruned. - - `is_block_known(H989)` → **FALSE** — same. - - **Result: `fork_alignment = false`** - -**This is the key bug.** slaveB's head is at block 999, and master's earliest dlt block is 1000. Block 1000's `previous` field is exactly block 999's ID. This means: - -``` -slaveB.head_block_id == master.dlt_block_log.block_at(1000).previous -``` - -But `check_fork_alignment` **never checks this boundary condition**. It only checks `is_block_known()` on the head/LIB IDs directly, which fails because block 999 has been pruned from the master's dlt block log. - -**3. Everything else proceeds identically to slaveA:** -- `exchange_enabled = false` -- Master (FORWARD): slaveB stays HANDSHAKING → 10s timeout → disconnect -- slaveB (SYNC): master transitions to ACTIVE but no blocks are requested -- slaveB stagnation: requests blocks, gets partial reply, blocks go to fork_db -- Eventually: snapshot plugin downloads snapshot at 1500 - -### The Expected Behavior vs. Reality - -| Expected | Reality | -|----------|---------| -| slaveB's head (999) links to master's earliest block (1000) via `previous` | Code doesn't check `previous` linkage | -| slaveB should get `fork_alignment=true` and sync blocks 1000-2000 | `fork_alignment=false`, gets disconnected | -| slaveB should transition to FORWARD after catching up | slaveB has to go through snapshot download | - -### Problems Identified - -| # | Problem | Severity | -|---|---------|----------| -| P6 | **Missing "boundary link" check**: When `peer_head_num + 1 == our_dlt_earliest`, the code should check if `our_dlt_earliest_block.previous == peer_head_id`. This proves the peer is on the same chain without needing the pruned block. | **CRITICAL** | -| P7 | **`check_fork_alignment` doesn't consider DLT range at all**: The function receives only two block IDs. It has no access to `peer_dlt_earliest`, `peer_dlt_latest`, `our_dlt_earliest`, `our_dlt_latest`, or the block log to verify range adjacency. | **CRITICAL** | -| P8 | **No block number check in alignment**: Even a simple check like "peer_head_num >= our_dlt_earliest - 1" would catch this case. The function only processes IDs, not numbers. | **HIGH** | - ---- - -## Scenario 3: slaveC (no blocks at all) - -### Step-by-step - -**1. slaveC connects to master → sends `dlt_hello_message`:** -``` -head_block_num=0, head_block_id= (all zeros) -lib_block_num=0, lib_block_id= -dlt_earliest_block=0, dlt_latest_block=0 -node_status=SYNC -``` - -**2. Master receives slaveC's hello → `on_dlt_hello()`:** - -- `check_fork_alignment(zero_id, zero_id)`: - - `is_block_known(zero_id)` → **FALSE** (all-zeros block ID is never a real block) - - **Result: `fork_alignment = false`** - -- Lifecycle: `exchange_enabled(false) || FORWARD` → false → slaveC stays HANDSHAKING - -- `record_packet_result(peer, true)` → **GOOD packet** — no spam strike - -**3. HANDSHAKING timeout → disconnect → reconnect loop** (same as slaveA/slaveB) - -**4. Does master soft-ban slaveC?** **NO.** - -- Soft-ban only triggers when `spam_strikes >= SPAM_STRIKE_THRESHOLD (10)` via `record_packet_result(peer, false)` -- The hello handler always records `true` (good packet) for hello messages (line 507) -- Even the disconnect isn't triggered by spam — it's a lifecycle timeout -- **No soft-ban, no "not my guy" flag, no counting of useless peers** - -**5. Does master mark slaveC as "don't send forward blocks"?** - -The `exchange_enabled` flag IS set to `false` for slaveC. When master broadcasts blocks via `send_to_all_our_fork_peers()`, it only sends to peers where `exchange_enabled == true`. So slaveC won't receive forward blocks. - -But this is a side effect, not an intentional "this peer needs a snapshot" design. - -**6. slaveC's recovery path:** - -- Stagnation (90s) → FORWARD with 0 blocks → snapshot plugin detects stall → downloads snapshot from trusted peers → imports at block 1500 → resyncs - -**7. What about peer exchange? Does slaveC get shared?** - -No. `on_dlt_peer_exchange_request()` only shares peers where `exchange_enabled=true` (line 868): -```cpp -if (!s.exchange_enabled) continue; -``` - -### Does Master Tell slaveC "You Need a Snapshot"? - -**No.** There is no message type for this. The protocol has no way to say: -- "Your blocks are too old, get a snapshot" -- "I have a snapshot at block 1500 you can download" -- "I don't recognize your chain at all" - -The snapshot serving happens on a **separate TCP port** (e.g., 8092) via a completely different protocol. The DLT P2P layer has zero awareness of snapshots. - -### Problems Identified - -| # | Problem | Severity | -|---|---------|----------| -| P9 | **No "empty peer" recognition**: An all-zero hello should be recognized as "new node with no state" and treated differently. Currently it's indistinguishable from a far-behind peer. | **MEDIUM** | -| P10 | **No "needs snapshot" signal**: The protocol can't tell a peer "you're too far behind, download a snapshot from me/trusted peers." The snapshot mechanism is entirely separate. | **HIGH** | -| P11 | **Peer exchange works correctly** (doesn't share useless peers) but for the wrong reason — it's by accident via `exchange_enabled=false`, not by design. | **LOW** | -| P12 | **No anti-spam for "useless" peers**: A peer that repeatedly connects with 0 blocks doesn't accumulate spam strikes. It just loops: connect → handshake timeout → disconnect → reconnect. | **LOW** | - ---- - -## Cross-Cutting Problems - -### P13: `check_fork_alignment` Signature is Insufficient - -```cpp -// Current signature (dlt_p2p_node.hpp line 116-117): -bool check_fork_alignment(const block_id_type& head_id, const block_id_type& lib_id, - block_id_type& recognized_head_out, block_id_type& recognized_lib_out) const; -``` - -This function receives **only two block IDs**. It has **no access** to: -- The peer's block numbers (head_num, lib_num) -- The peer's DLT range (dlt_earliest, dlt_latest) -- Our DLT range -- The actual block data to check `previous` linkage - -It delegates to `_delegate->is_block_known()` which is a **binary yes/no** on whether a specific block ID exists in the chain or fork_db. In DLT mode, blocks outside the rolling window are pruned, so `is_block_known()` returns false for them. - -**The function needs to be redesigned to consider DLT range adjacency.** - -### P14: `on_dlt_hello` Lifecycle Logic is Broken for FORWARD Mode - -```cpp -// Lines 500-504: -if (state.lifecycle_state == DLT_PEER_LIFECYCLE_HANDSHAKING) { - if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC) { - state.lifecycle_state = DLT_PEER_LIFECYCLE_ACTIVE; - } -} -``` - -When the master is FORWARD and a peer has `exchange_enabled=false`: -- Peer stays HANDSHAKING → 10s timeout → disconnect -- This is correct behavior for a **hostile fork** peer -- But it also applies to **same-chain peers whose blocks were pruned** — they can never transition to ACTIVE - -**The condition should be:** -```cpp -if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC || - hello.node_status == DLT_NODE_STATUS_SYNC) // Also let SYNC peers through -``` - -Or better, separate the concepts: -- `fork_alignment` = "are we on the same chain?" (structure check including range adjacency) -- `exchange_enabled` = "do we want to do full block exchange with this peer?" (policy) - -### P15: No DLT Range Negotiation in Hello - -The hello message carries DLT range info but it's only used for display and for `request_blocks_from_peer` (to know `peer_dlt_latest`). No logic uses the range to determine fork alignment. - -What should happen in `build_hello_reply`: -``` -1. If peer_head_num >= our_dlt_earliest: - → Check is_block_known(peer_head_id) as now -2. If peer_head_num == our_dlt_earliest - 1: - → Check our_dlt_earliest_block.previous == peer_head_id - → If match: fork_aligned = true (boundary link) -3. If peer_head_num < our_dlt_earliest - 1: - → Not aligned via DLT range — fall back to is_block_known on LIB -4. If peer_head_num == 0 (empty peer): - → Special case: "needs snapshot" or accept as aligned with caveat -``` - -### P16: Master Doesn't Differentiate "Why" exchange_enabled is False - -Currently `exchange_enabled=false` means one of: -- "You're on a different fork" (hostile) -- "Your blocks are too old and I pruned them" (needs snapshot) -- "You have no blocks" (new node) -- "Protocol version mismatch" - -All four cases get the same treatment: HANDSHAKING timeout → disconnect. The protocol should distinguish these and respond differently: -- Hostile fork → disconnect immediately, maybe soft-ban -- Needs snapshot → keep connection, mark as "snapshot candidate", don't send blocks -- New node → redirect to snapshot server -- Version mismatch → disconnect with clear reason - ---- - -## Summary of All Problems - -``` -P1 [CRIT] check_fork_alignment only checks is_block_known — fails for pruned blocks -P2 [CRIT] No range-overlap check in fork alignment -P3 [HIGH] HANDSHAKING timeout loop for same-chain peers -P4 [MED] Wasted block range requests that return mostly empty -P5 [HIGH] Recovery entirely depends on snapshot plugin (2+ min delay) -P6 [CRIT] Missing boundary link check (peer_head+1 == our_earliest) -P7 [CRIT] check_fork_alignment doesn't have access to DLT ranges -P8 [HIGH] No block number check in alignment logic -P9 [MED] No "empty peer" recognition -P10 [HIGH] No "needs snapshot" signal in protocol -P11 [LOW] Peer exchange excludes empty peers by accident, not design -P12 [LOW] No anti-spam for empty peer reconnect loops -P13 [CRIT] check_fork_alignment signature is insufficient (needs range data) -P14 [HIGH] on_dlt_hello lifecycle logic broken for FORWARD mode -P15 [CRIT] No DLT range negotiation in hello handshake -P16 [HIGH] No differentiation between reasons for exchange_enabled=false -``` - ---- - -## Recommended Fix Priority - -### Immediate (would fix all 3 slave scenarios) - -1. **Extend `check_fork_alignment`** to accept the peer's `dlt_hello_message` and our DLT range: - - Add boundary link check: `if (peer.head_num + 1 == our_dlt_earliest)` → verify `our_block_at(earliest).previous == peer.head_id` - - Add range overlap check: `if (peer.head_num >= our_dlt_earliest)` → use existing `is_block_known` logic - - Add empty peer check: `if (peer.head_num == 0)` → treat as "needs snapshot" (aligned but with zero blocks) - -2. **Fix `on_dlt_hello` lifecycle transition** so SYNC peers always reach ACTIVE state: - ```cpp - if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC - || hello.node_status == DLT_NODE_STATUS_SYNC) - ``` - -3. **Add a `peer_needs_snapshot` flag** to `dlt_peer_state` and expose it so the snapshot plugin can act on it without waiting for the 2-minute stall timeout. - -### Short-term - -4. **Add a `dlt_need_snapshot` message type** so master can actively tell far-behind peers to get a snapshot instead of disconnecting them. - -5. **Skip empty range requests**: In `request_blocks_from_peer`, if `our_head + 1 < peer_dlt_earliest`, don't send a request — we know the peer doesn't have those blocks. - -### Long-term - -6. **Integrate P2P with snapshot serving**: Allow the master to advertise its snapshot endpoint in the hello message so peers know where to download without separate config. - -7. **Add a dedicated lifecycle state** for "snapshot-needed" peers so they don't cycle through HANDSHAKING→DISCONNECTED repeatedly. - ---- - -## Implemented Fixes (2026-05-05) - -### Changes Made - -**Files modified:** -- `libraries/network/include/graphene/network/dlt_p2p_node.hpp` — `check_fork_alignment` signature -- `libraries/network/dlt_p2p_node.cpp` — implementation + lifecycle transitions - -**1. `check_fork_alignment` extended** (fixes P1, P2, P6, P7, P8, P9, P13, P15): - -``` -OLD signature: - bool check_fork_alignment(const block_id_type& head_id, const block_id_type& lib_id, - block_id_type& recognized_head_out, block_id_type& recognized_lib_out) const; - -NEW signature — accepts the full hello for DLT-range-aware alignment: - bool check_fork_alignment(const dlt_hello_message& hello, - block_id_type& recognized_head_out, block_id_type& recognized_lib_out) const; -``` - -New alignment checks (see `dlt_p2p_node.cpp` lines 448-489): - -| Check | Condition | Result | -|-------|-----------|--------| -| Empty peer | `head_block_num == 0` | Returns `true` — no fork to be on | -| Range overlap | `head_num >= our_earliest && head_num <= our_latest` | Uses `is_block_known(head_id)` | -| Boundary link | `head_num + 1 == our_earliest` | Reads `our_earliest_block`, checks `previous == head_id` | -| LIB fallback | Always | `is_block_known(lib_id)` as before | - -**2. `on_dlt_hello` lifecycle transition fixed** (fixes P3, P14): - -``` -OLD: if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC) -NEW: if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC - || hello.node_status == DLT_NODE_STATUS_SYNC) -``` - -Added diagnostic log for non-aligned SYNC peers so operators can distinguish "needs snapshot" from "hostile fork". - -### New Expected Behavior — Per-Slave - -#### slaveA (head=800, master dlt=[1000-2000]) - -| Step | Before Fix | After Fix | -|------|-----------|-----------| -| Hello to master | fork_alignment=false (block 800 pruned) | fork_alignment=false (800+1 ≠ 1000) | -| Lifecycle on master | HANDSHAKING → 10s timeout → disconnect | **Transitions to ACTIVE** (hello.node_status == SYNC) | -| Blocks exchanged? | No — gets disconnected | No — exchange_enabled=false, but stays connected | -| Recovery path | Snapshot plugin stall detection → download | Same — needs snapshot from trusted peers | -| **Improvement** | Disconnect/reconnect loop with backoff | **Stays connected**, no backoff penalty | - -#### slaveB (head=999, master dlt=[1000-2000]) - -| Step | Before Fix | After Fix | -|------|-----------|-----------| -| Hello to master | fork_alignment=false (block 999 pruned) | **fork_alignment=true** — boundary link: block 1000.previous == H999 | -| Lifecycle on master | HANDSHAKING → timeout | **Transitions to ACTIVE** (exchange_enabled=true) | -| Blocks exchanged? | No | **Yes!** Requests blocks 1000-1199, master sends full range | -| Sync completion | N/A | Catches up 999→2000, transitions to FORWARD | -| **Improvement** | Had to snapshot-download from 1500 | **Direct P2P sync 999→2000** — zero snapshot overhead | - -#### slaveC (no blocks, empty node) - -| Step | Before Fix | After Fix | -|------|-----------|-----------| -| Hello to master | fork_alignment=false (zero_id not known) | **fork_alignment=true** — empty peer check | -| Lifecycle on master | HANDSHAKING → timeout | **Transitions to ACTIVE** (exchange_enabled=true) | -| Blocks exchanged? | No | No — peer_dlt_latest==0, no request sent | -| Recovery path | Snapshot plugin stall detection → download | Same — needs snapshot from trusted peers | -| **Improvement** | Disconnect/reconnect loop | **Stays connected**, doesn't waste bandwidth | - -### Problems Resolved - -``` -P1 [OK] check_fork_alignment now DLT-range-aware -P2 [OK] Range-overlap check added -P3 [OK] HANDSHAKING timeout loop fixed (SYNC peers always → ACTIVE) -P6 [OK] Boundary link check added -P7 [OK] check_fork_alignment receives full hello with range data -P8 [OK] Block number comparison via boundary link + range overlap -P9 [OK] Empty peer (head=0) recognized and accepted -P13 [OK] check_fork_alignment signature updated -P14 [OK] on_dlt_hello lifecycle logic fixed -P15 [OK] DLT range negotiation via boundary link check - -P4 [OK] Wasted range requests fixed — start clamped to peer_dlt_earliest -P5 [ ] Recovery still snapshot-plugin-driven (but no reconnect loop delays it) -P10 [ ] No "needs snapshot" signal yet -P11 [NA] Peer exchange works correctly — no fix needed -P12 [NA] No anti-spam needed — lifecycle fix eliminated reconnect loop -P16 [ ] No differentiation between reasons (improved via diagnostic log) - -P17 [OK] DLT block log corruption → auto-detected and reset on startup -P20 [OK] Dead fork blocks → DEAD_FORK result, soft-ban peer, no crash -P21 [OK] Dead fork crash loop → dead-fork blocks rejected, fork_db protected -P24 [OK] Snapshot lock isolation → periodic tasks skip DB locks, stall check skips -P27 [OK] Write lock diagnostic → overall + per-plugin timing, chainbase lock-holder ID -``` - ---- - -## New Problems Discovered (Post-Implementation) - -After deploying the fixes, the following new issues were observed in production (emergency consensus, DLT mode, 4-node network). - ---- - -### P17: DLT Block Log Corruption on Crash → Infinite Restart Loop - -**Observed on:** Master node (185.146.232.170) - -**Symptom:** Node crashes, then on restart the DLT block log opens with only **one block**: -``` -DLT block log: opened with blocks 79637600-79637600 -``` -Immediately after: -``` -terminate called after throwing an instance of 'boost::interprocess::lock_exception' - what(): boost::interprocess::lock_exception -``` -Node auto-restarts and loops with high CPU overhead. - -**Root cause hypothesis:** On crash, the DLT block log index/data files become inconsistent. The index truncates to a single entry while the database head is far ahead. The `boost::interprocess::lock_exception` is thrown when the database tries to acquire the shared memory lock that the previous (crashed) process held. - -**Severity:** **CRITICAL** — node cannot recover without manual intervention. - -**Related files:** -- [dlt_block_log.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/dlt_block_log.cpp) -- [database.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/database.cpp) (open path) - ---- - -### P18: Master Block Production Halt (No Clear Reason) - -**Observed on:** Master node (185.146.232.170, ~16-20 scheduled slots) - -**Symptom:** Node was producing blocks normally, then abruptly stopped. In logs: -``` -maybe_produce_block returned 3 (slot=0 — missed/not-my-slot) -``` -This repeated for hundreds of iterations (minutes of wall time) with no blocks produced. Eventually recovered on its own. During the halt, `slot=0` was returned every cycle, meaning `get_slot_at_time()` returned slot 0 — either the time was before the first slot, or the slot calculation was wrong. - -**Also observed:** After some restarts the pattern changed: -``` -maybe_produce_block returned 1 (not my slot, but slot had a value) -``` -Here `scheduled_witness=social` (a slave validator), so the master correctly doesn't produce, but the slave's block never arrived. - -**Severity:** **CRITICAL** — network stalls for minutes with no block production. - -**Related files:** -- [validator.cpp](file:///d:/Work/viz-cpp-node/plugins/validator/validator.cpp) — `maybe_produce_block` - ---- - -### P19: Slave Stuck in Sync — Never Catches Up - -**Observed on:** Slave node (80.87.202.57) - -**Symptom:** Slave connects to master, synopsis exchange happens, but slave never receives blocks. Stays in SYNC mode indefinitely. No `Got X transactions` lines appear. The synopsis response from master returns an empty reply because the synopsis anchor from the slave references blocks outside the master's DLT range. - -**Severity:** **HIGH** — slave never syncs, relies on snapshot plugin for recovery. - ---- - -### P20: Dead Fork Blocks Trigger Sync Status Loss → Silent Crash - -**Observed on:** Master node (185.146.232.170) - -**Symptom:** Master is producing blocks normally (head=79641907). Then peers send sync blocks 79641905-79641908 which are on a **different fork**: -``` -Block 79641905 is from a dead fork (parent not in fork_db, head=79641907) -Block 79641906 is from a dead fork (parent not in fork_db, head=79641907) -Block 79641907 is from a dead fork (parent not in fork_db, head=79641907) -``` -Block 79641908 (gap=0) is treated as "near-caught-up" and triggers: -``` -Sync mode ended: received normal block #79641908 (head: 79641907) -``` -This **resets sync status** on the master. Shortly after, the node silently crashes: -``` -json_rpc plugin: plugin_initialize() begin ← fresh restart -``` - -**Root cause:** A block from a different fork with `gap=0` triggers `accept_block` logic that treats it as a "normal block", ending sync mode. This corrupts the node's internal state. The crash is likely an OOM (from fork_db growing with unlinkable blocks) or an assertion failure. - -**Severity:** **CRITICAL** — malicious peers can crash the master by sending dead-fork blocks. - -**Related files:** -- [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) — `handle_block` -- [database.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/database.cpp) — `_push_block` - ---- - -### P21: Dead Fork → Crash → Restart → Dead Fork Loop - -**Observed on:** Master node (185.146.232.170) - -**Symptom:** After recovering from P20's crash, the master restarts, produces a few blocks, then another dead-fork block arrives: -``` -Block from a different fork whose parent is not in fork_db (block 79641912, head=79641913) -``` -Note: **head (79641913) > block num (79641912)** — this means the node's head advanced past the block it's rejecting. The node crashes again. This creates an infinite restart loop. - -**Key observation:** `head > block_num` when rejecting — the node's own head has moved beyond the rejected block, which means the fork_db might be in an inconsistent state where unlinkable blocks accumulate but the chain head advances independently. - -**Severity:** **CRITICAL** — infinite crash loop, node cannot stay up. - ---- - -### P22: fork_db Rejection Cascade on Restart - -**Observed on:** Master node after restart - -**Symptom:** On restart with DLT range [79640201..79641912], peers send sync blocks 79641905-79641908. These are **older than the node's head** (79641912) but the fork_db doesn't contain their parent chain: -``` -Chain pushing sync block #79641905 (head: 79641912, gap: -8) -Rejecting block 79641905 from a different fork: parent not in fork_db (head=79641912) -``` -All 4 blocks rejected. Node crashes shortly after. - -**Root cause:** After restart, the fork_db is seeded from the DLT block log at block 79641912. Blocks 79641905-79641908 are in the DLT range [79640201..79641912] but their parent chain (below 79641905) is in the fork_db unlinked section or pruned. The gap of -8 means the node is being asked to process blocks it should already have. - -**Severity:** **HIGH** — restart recovery fails if peers send older blocks. - ---- - -### P23: fetch_branch_from Assertion in fork_db During Synopsis - -**Observed on:** Slave node (80.87.202.57) - -**Symptom:** When constructing a synopsis for peer 185.45.192.155:2001: -``` -Unable to construct a blockchain synopsis for reference hash 04bf3d5a... -assert_exception: Assert Exception -second_branch_itr != _index.get().end(): - {"first":"04bf3de9...","second":"04bf3d5a..."} - fork_database.cpp:201 fetch_branch_from -``` -The peer's reference block is on a fork that our fork_db doesn't know about. The `fetch_branch_from` function assumes both branches exist in the index, but the second branch doesn't. - -**Also causes:** Connection breakage with that peer, synopsis failure, lost sync time. - -**Severity:** **HIGH** — can crash the node or break sync with legitimate peers. - -**Related files:** -- [fork_database.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/fork_database.cpp) — `fetch_branch_from` -- [database.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/database.cpp) — `get_block_ids_on_fork` - ---- - -### P24: Snapshot Write Lock Freezes Entire Node - -**Observed on:** Slave node (80.87.202.57) - -**Symptom:** When a periodic snapshot fires at block 79642200: -``` -Periodic snapshot at block 79642200: /var/lib/vizd/snapshots/snapshot-block-79642200.vizjson -``` -Immediately, **all P2P connections** start failing: -``` -Read lock timeout -Read lock timeout -... (repeated hundreds of times) -Peer connection terminating (95.217.177.173:2001), now 5 active peers -Peer connection closing (95.217.177.173:2001): Disconnecting due to inactivity -... -Peer connection closing (185.146.232.170:2001): Disconnecting due to inactivity, now 0 active peers -``` - -**Timeline:** -| Time | Event | -|------|-------| -| T+0s | Snapshot starts, WRITE lock acquired | -| T+13s | `auto-clearing stuck peer_needs_sync_items_from_us` for master peer (30s timeout) | -| T+20s | `Skipping head_block_num read: Unable to acquire READ lock` | -| T+130s | All peers disconnected due to inactivity | -| T+150s | `Stalled sync detected while snapshot in progress — cancelling snapshot to release locks` | -| T+160s | `Snapshot still in progress after 10s wait, proceeding with recovery anyway` | - -**The stall detection itself fails** because it can't acquire the READ lock: -``` -trigger_resync: could not read head block (lock contention?): Unable to acquire READ lock -``` - -**Root cause:** The snapshot serialization holds a WRITE lock on the database for the entire duration. P2P needs READ locks for every operation (reading head, LIB, block IDs). The snapshot can take 2+ minutes for large state, during which the node is completely isolated from the network. - -**Severity:** **CRITICAL** — periodic snapshots cause complete network disconnection. Self-reinforcing: no peers → no blocks → stall detection → can't recover because of lock. - -**Related files:** -- [snapshot/plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/snapshot/plugin.cpp) — `on_applied_block` → snapshot creation - ---- - -### P25: Slave-Produced Block Ignored by Master → Fork Switch - -**Observed on:** Slave (80.87.202.57) + Master (185.146.232.170) - -**Symptom:** Slave produces block #79645211 (validator="social", slot time 10:20:24), sends it via P2P. Master never receives/processes it and produces its own block #79645211 (validator="committee", slot time 10:20:27) — 3 seconds later for the same block number: - -**Slave side:** -``` -Block num collision at block 79645211: 2 blocks with SAME parent (possible double-production) -Fork switch: new_head=#79645211, db_head=#79645211 -FORK-SWITCH-POP: popping head #79645211 (target=04bf4a1a...) -``` - -**Master side:** -``` -scheduled_witness=social -maybe_produce_block returned 2 (not our slot to produce) -scheduled_witness=committee -... produces block #79645211 by committee -``` - -**Root cause:** The slave sent its block but the master either: -1. Had the slave peer in a state where blocks from it weren't accepted -2. The block was delayed/lost in P2P transmission -3. The master's `exchange_enabled` flag for the slave was false - -The master then produced a competing block because it didn't see the slave's block within the slot window. - -**Severity:** **HIGH** — causes unnecessary fork switches, wastes blocks, confuses validators. - ---- - -### P26: Sync State Confusion on Slave — Blocks Received But Status Stays SYNC - -**Observed on:** Slave node (80.87.202.57) - -**Symptom:** Slave receives blocks normally via sync (`Chain pushing sync block #...`), processes them, even generates its own blocks, but the node status **never transitions from SYNC to FORWARD**. It stays in SYNC mode while actually having caught up. - -**Severity:** **MEDIUM** — node functions but reports wrong status, may affect peer selection logic. - ---- - -### P27: Write Lock Held 25+ Seconds During Block Application - -**Observed on:** Master node (185.146.232.170) - -**Symptom:** During `_apply_block`, the write lock is held for **25+ seconds**: - -``` -Read lock timeout [lock=READ waiter_tid=... wait_ms=500 readers=0 writer_tid=... writer_held_ms=503] -Read lock timeout [lock=READ waiter_tid=... wait_ms=1000 readers=0 writer_tid=... writer_held_ms=1003] -... -Read lock timeout [lock=READ waiter_tid=... wait_ms=2000 readers=0 writer_tid=... writer_held_ms=25670] -``` - -**All RPC calls fail** during this period: -``` -elapsed: 2.01s, error: 'Unable to acquire READ lock [writer_held_ms=22857]' -``` - -The lock is held between these DEBUG_CRASH markers: -``` -DEBUG_CRASH: notify_applied_block start ← lock acquired before this -... 25+ seconds pass ... -DEBUG_CRASH: notify_applied_block done ← lock released after this -``` - -**User explicitly requests:** "add normal logs that show WHO set lock, where in which method?" — the current `Read lock timeout` messages show the writer's TID but not which function/code line is holding the lock. - -**Severity:** **CRITICAL** — 25-second write lock makes the node unresponsive to all P2P and RPC traffic. The `notify_applied_block` plugin callbacks are the bottleneck — one of the plugins (likely `operation_history`, `account_history`, or `snapshot`) is doing heavy synchronous work under the write lock. - -**Related files:** -- [database.cpp](file:///d:/Work/viz-cpp-node/libraries/chain/database.cpp) — `_apply_block` -- All plugin `on_applied_block` handlers - ---- - -### P28: Build Error — multimap::erase and ip::address::data() API - -**Observed on:** Docker build (GCC 13) - -**Symptom:** Compilation fails in `dlt_p2p_node.cpp`: - -1. **multimap::erase with pair**: -```cpp -_mempool_by_expiry.erase(std::make_pair(it->second.trx.expiration, it->first)); -``` -Error: `no matching function for call to 'std::multimap<...>::erase(std::pair<...>)'` - -In C++17, `multimap::erase` no longer accepts a value/pair directly — it requires an iterator, key, or iterator range. **Fix:** Use `_mempool_by_expiry.erase(it_by_expiry)` where `it_by_expiry` is the iterator to the element. - -2. **ip::address::data() doesn't exist**: -```cpp -auto a_data = a.data(); // 'const class fc::ip::address' has no member named 'data' -``` -**Fix:** Use `fc::raw::pack(a)` or the appropriate fc serialization method. - -**Severity:** **MEDIUM** — blocks compilation with newer GCC. - -**Affected locations** (3 call sites): -- `transition_to_forward()` line 972 -- `remove_transactions_in_block()` line 1089 -- `prune_mempool_on_fork_switch()` line 1099 - -**Related files:** -- [dlt_p2p_node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/dlt_p2p_node.cpp) - ---- - -### P29: Build Error — Missing witness_plugin.hpp Header - -**Observed on:** Docker build - -**Symptom:** -``` -fatal error: graphene/plugins/validator/witness_plugin.hpp: No such file or directory -#include -``` - -**Root cause:** The include path is wrong. The actual file is at `plugins/validator/include/graphene/plugins/validator/validator.hpp` (note: `validator.hpp` not `witness_plugin.hpp`). The CMake include directories may not include the Validator Plugin's include path. - -**Severity:** **MEDIUM** — blocks compilation in certain build configurations. - -**Related files:** -- [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) line 9 - ---- - -### P30: Multiple API Mismatches in p2p_plugin.cpp - -**Observed on:** Docker build (after fixing P29) - -**Symptom:** Multiple compilation errors in `p2p_plugin.cpp`: - -| # | Error | Root Cause | -|---|-------|------------| -| 1 | `with_read_lock([&]{...})` — candidate expects 6 arguments, 1 provided | The `with_read_lock` API changed — now requires `(lock_type, timeout_ms, lambda, file, line, func)` | -| 2 | `'is_emergency_consensus' is not a member` | Field was renamed or removed from `dynamic_global_property_object` | -| 3 | `blocks.front()->id()` — no match for call to `(block_id_type)()` | `id` is a field, not a method. Should be `blocks.front()->id` (without `()`) | -| 4 | `catch (const unlinkable_block_exception&)` — expected unqualified-id before `&` | Missing exception variable name: `catch (const unlinkable_block_exception& e)` | -| 5 | `accept_transaction` doesn't exist, did you mean `apply_transaction`? | Method was renamed | -| 6 | `push_block(*block)` where `block` is `fork_item` — can't convert | `fork_item` is not a `signed_block`. Need `fork_item->data` or cast | -| 7 | `is_known_block(ref_block_num)` with `uint32_t` — expects `block_id_type` | Need to fetch block ID by number first | - -**Severity:** **HIGH** — blocks compilation, indicates the p2p_plugin.cpp was written against a different API version than what's in the codebase. - -**Related files:** -- [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) - ---- - -### P31: Linker Error — static constexpr ODR-use - -**Observed on:** Docker build - -**Symptom:** -``` -/usr/bin/ld: undefined reference to `graphene::network::dlt_peer_state::MAX_RECONNECT_BACKOFF_SEC' -``` - -**Root cause:** `MAX_RECONNECT_BACKOFF_SEC` is declared as `static constexpr` in the header but used in a context that requires a definition (ODR-use). The code takes its address or binds a reference to it. In C++17, `static constexpr` members still need an out-of-line definition if they're ODR-used. - -**Fix:** Add a definition in the `.cpp` file: -```cpp -constexpr uint32_t dlt_peer_state::MAX_RECONNECT_BACKOFF_SEC; -``` -Or change the usage to avoid ODR-use. - -**Severity:** **MEDIUM** — linker error, blocks final linking. - -**Related files:** -- [dlt_p2p_peer_state.hpp](file:///d:/Work/viz-cpp-node/libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp) -- [dlt_p2p_node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/dlt_p2p_node.cpp) - ---- - -## Implemented Fixes (2026-05-06) - -### Fix 1: Dead Fork Block Crash Protection (P20/P21) - -**Files:** `libraries/network/include/graphene/network/dlt_p2p_node.hpp`, `plugins/p2p/p2p_plugin.cpp`, `libraries/network/dlt_p2p_node.cpp` - -**Root cause:** When a FORWARD node receives sync blocks from a peer on a dead fork (parent not in fork_db, head already past the block), `_push_block` throws `unlinkable_block_exception`. But the P2P layer's `on_dlt_block_range_reply` didn't distinguish between "rejected because validation failed" and "rejected because dead fork." A block with `block_num == head` (gap=0) from a dead fork could trigger "sync mode ended" logic, corrupting internal state. The fork_db accumulated unlinked blocks until OOM/assertion crash. After restart, peers re-sent the same blocks, creating a crash loop. - -**Changes:** - -1. **`dlt_block_accept_result` enum** — Added `DEAD_FORK` value to distinguish dead-fork rejection from generic rejection (`dlt_p2p_node.hpp` line 34). - -2. **`dlt_delegate::accept_block()`** (`p2p_plugin.cpp` line 166-183) — When `push_block()` throws `unlinkable_block_exception`: - - If `block.block_num() <= head_block_num()`: returns `DEAD_FORK` (peer is on a competing fork that diverged before our fork_db window). Does NOT push to `fork_db._unlinked_index`, preventing unbounded growth. - - If `block.block_num() > head_block_num()`: returns `FORK_DB_ONLY` (block is ahead but has a gap — store in `_unlinked_index` for later linking). - -3. **`on_dlt_block_range_reply()`** (`dlt_p2p_node.cpp` line 760-768) — On `DEAD_FORK` result: soft-ban the peer immediately and break out of the block processing loop. No more blocks are accepted from that peer in the range. - -4. **`on_dlt_block_reply()`** (`dlt_p2p_node.cpp` line 856-862) — Same DEAD_FORK soft-ban for single-block replies. - -5. **`transition_to_forward()` guard** (`dlt_p2p_node.cpp` line 784) — Only transition from SYNC to FORWARD if `any_block_applied` is true. A range full of dead-fork rejects does NOT end sync mode. - -**Expected behavior after fix:** -- Dead-fork blocks are rejected immediately without polluting fork_db -- Peers sending dead-fork blocks are soft-banned (10 min) -- No more "sync mode ended" from dead-fork gap=0 blocks -- No more crash loops from fork_db OOM or state corruption - ---- - -### Fix 2: DLT Block Log Corruption Recovery (P17) - -**Files:** `libraries/chain/include/graphene/chain/dlt_block_log.hpp`, `libraries/chain/dlt_block_log.cpp`, `libraries/chain/database.cpp` - -**Root cause:** On crash, the DLT block log index/data files can become inconsistent — the index truncates to a single entry while the database head is far ahead. Opening a corrupted DLT block log and using it for fork_db seeding causes cascading P2P failures (dead forks, sync stalls, crash loops). - -**Changes:** - -1. **`dlt_block_log::is_consistent_with()`** (`dlt_block_log.cpp` line 604-652) — New method that compares the DLT block log state with the database head block number. Detection rules: - - Empty DB or empty DLT log → consistent (normal) - - 1 block in log but DB has thousands → **corrupted** (index truncated on crash) - - DLT head exceeds DB head → **corrupted** - - DB head > DLT head + 1000 and DLT has < 10 blocks → **corrupted** (partial wipe) - -2. **Corruption detection in `database::open()`** (`database.cpp` line 269-280) — Before seeding fork_db from the DLT block log, validate consistency. If corrupted: - - Log a clear error with database head block number - - Call `_dlt_block_log.reset()` to wipe the corrupted log - - P2P sync will rebuild the DLT block log from scratch - -**Expected behavior after fix:** -- Corrupted DLT block log is detected and auto-reset on startup -- No more infinite restart loops from inconsistent block log -- P2P sync rebuilds the log naturally after reset - ---- - -### Fix 3: Snapshot Lock Isolation Prevention (P24) - -**Files:** `libraries/network/dlt_p2p_node.cpp`, `plugins/snapshot/plugin.cpp` - -**Root cause:** Snapshot `create_snapshot()` runs on a background thread with a strong read lock on the database. During the 30-120s serialization, the P2P thread's periodic tasks (stats, peer exchange, hello broadcasts, stall detection) also need read locks but time out because the snapshot's lock blocks them. This cascades into all peer disconnections. - -**Changes:** - -1. **`periodic_task()` early-return guard** (`dlt_p2p_node.cpp` line 1682-1708) — When `_block_processing_paused` is true (snapshot in progress), skip periodic operations that need database read locks: - - Skip `sync_stagnation_check()` — stale blocks won't arrive anyway - - Skip `periodic_peer_exchange()` — can wait - - Skip `log_peer_stats()` — cosmetic only - - Still run: `periodic_reconnect_check()`, `periodic_lifecycle_timeout_check()`, `block_validation_timeout()`, `periodic_mempool_cleanup()`, banned-peer unban check - -2. **`check_stalled_sync_loop()` snapshot awareness** (`snapshot/plugin.cpp` line 1833-1843) — When `snapshot_in_progress` is true, skip the stall check entirely and reset the timer. The stall is caused by the snapshot (expected), not by actual network failure. Without this, the stall detector would trigger a false recovery (cancel the snapshot, attempt resync while still locked). - -3. **`serialize_state()` progress logging** (`snapshot/plugin.cpp` line 845-860) — The `EXPORT_INDEX` macro now logs progress every 5 seconds during long serialization. Operators can see the snapshot is progressing instead of assuming the node is frozen. - -**Expected behavior after fix:** -- Snapshot creation no longer causes peer disconnections -- Stall detection doesn't trigger false recovery during snapshots -- Progress logs give visibility into snapshot serialization - ---- - -### Fix 4: Write Lock Diagnostic Logging (P27) - -**Files:** `libraries/chain/database.cpp`, `plugins/mongo_db/mongo_db_plugin.cpp`, `plugins/operation_history/plugin.cpp`, `plugins/account_history/plugin.cpp` - -**Root cause:** `_apply_block` holds the WRITE lock through `notify_applied_block()` which calls ALL registered plugin callbacks synchronously. One plugin (likely `operation_history`, `account_history`, or `mongo_db`) does heavy work under the lock, blocking all P2P and RPC for 25+ seconds. - -**Changes:** - -1. **Overall timing in `notify_applied_block()`** (`database.cpp` line 2181-2199) — Times the total `applied_block` signal notification. If it exceeds 200ms, logs a warning with block number, duration, and number of connected plugins. This identifies when the bottleneck occurs without changing behavior. - -2. **Per-plugin self-timing** — Added self-timing to the 3 most likely slow `applied_block` handlers: - - `mongo_db_plugin.cpp` line 99-108: Times `on_block()`, logs if >100ms - - `operation_history/plugin.cpp` line 266-275: Times `purge_old_history()`, logs if >100ms - - `account_history/plugin.cpp` line 543-552: Times `purge_old_history()`, logs if >100ms - -3. **Lock-holder identification** — Already implemented in chainbase (`chainbase.hpp` line 1330-1342): `with_strong_write_lock` macro auto-captures `__FILE__`, `__LINE__`, `__func__` at every call site. Lock timeout messages now include `writer_at=file:line func`, `writer_held_ms`, and `writer_tid`. - -**Expected behavior after fix:** -- When a 25s write lock occurs, the log will show: - - Which block triggered it (`applied_block notification took Xms for block #N`) - - Which specific plugin is slow (`mongo_db on_block took Xms` or `operation_history purge_old_history took Xms`) - - Which write lock call site is holding it (from chainbase diagnostics) -- No behavior change — only diagnostic logging added - -**Next step (not implemented):** Once the slow plugin is identified, defer its heavy work to a background thread after the write lock is released. - ---- - -## Summary of New Problems - -``` -P17 [FIX] DLT block log corruption on crash → infinite restart loop -P18 [FIX] Master stops producing blocks for minutes (slot=0 loop) → stall detector + NTP force-sync -P19 [FIX] Slave stuck in SYNC → gap detection + multi-peer fallback + snapshot warning -P20 [FIX] Dead fork blocks trigger sync status loss → silent crash -P21 [FIX] Dead fork → crash → restart → dead fork loop -P22 [FIX] fork_db rejection cascade on restart → seed 100 blocks + 60s grace period -P23 [FIX] fetch_branch_from assertion failure → graceful empty-branch return -P24 [FIX] Snapshot write lock freezes entire node (all peers disconnect, self-isolation) -P25 [FIX] Slave-produced block ignored by master → exchange_enabled re-evaluated -P26 [FIX] Sync state confusion → check_sync_catchup() on block accept + periodic -P27 [FIX] Write lock held 25+ sec during _apply_block (notify_applied_block bottleneck) -P28 [MED] Build error: multimap::erase with pair, ip::address::data() missing -P29 [MED] Build error: missing witness_plugin.hpp include -P30 [HIGH] Build error: multiple API mismatches in p2p_plugin.cpp (6+ separate issues) -P31 [MED] Linker error: static constexpr ODR-use (MAX_RECONNECT_BACKOFF_SEC) -``` - ---- - -## New Problem Priority Matrix - -### Immediate (node stability) - -| # | Problem | Impact | Status | -|---|---------|--------|--------| -| P17 | DLT block log corruption → restart loop | Node can't recover | **Fixed** | -| P20 | Dead fork blocks → crash | Malicious peer can crash master | **Fixed** | -| P21 | Dead fork → crash loop | Node stays down | **Fixed** | -| P24 | Snapshot lock → network isolation | Node disappears from network | **Fixed** | -| P27 | 25s write lock → all RPC/P2P fails | Node unresponsive | **Fixed** (diagnostic) | - -### High (sync/catchup reliability) - -| # | Problem | Impact | Status | -|---|---------|--------|--------| -| P18 | Master stops producing blocks | Network stalls | **Fixed** | -| P19 | Slave stuck in SYNC | Never catches up | **Fixed** | -| P22 | fork_db rejection cascade | Restart recovery fails | **Fixed** | -| P23 | fetch_branch_from assertion | Sync with some peers breaks | **Fixed** | -| P25 | Slave block ignored by master | Fork switches | **Fixed** | - -### Build (must compile) - -| # | Problem | Impact | -|---|---------|--------| -| P28 | multimap::erase, ip::address API | Won't compile on GCC 13+ | -| P29 | Missing header include | Won't compile | -| P30 | 6+ API mismatches in p2p_plugin | Won't compile | -| P31 | static constexpr linker error | Won't link | - -### Lower - -| # | Problem | Impact | Status | -|---|---------|--------|--------| -| P26 | Sync state confusion | Cosmetic status bug | **Fixed** | diff --git a/.qoder/docs/dlt-forward-mode.md b/.qoder/docs/dlt-forward-mode.md deleted file mode 100644 index dbd922f402..0000000000 --- a/.qoder/docs/dlt-forward-mode.md +++ /dev/null @@ -1,502 +0,0 @@ -# DLT Forward Mode — Block & Transaction Exchange - -## Overview - -Forward mode (`DLT_NODE_STATUS_FORWARD`) is the normal operating state of a DLT P2P node after it catches up with the network. In this mode, nodes actively **push** new blocks and transactions to each other as they arrive, rather than pulling them via range requests. - -This document describes how exchange works in forward mode: what gets sent, to whom, and the filtering mechanisms that control it. - ---- - -## Two-Phase Lifecycle - -A DLT node operates in one of two modes: - -| Mode | Enum Value | Behavior | -|------|-----------|----------| -| **SYNC** | `DLT_NODE_STATUS_SYNC = 0` | Pull-based: requests block ranges from peers to catch up. Mempool entries are tagged *provisional* (not forwarded). | -| **FORWARD** | `DLT_NODE_STATUS_FORWARD = 1` | Push-based: broadcasts new blocks/transactions to all fork-aligned peers. Mempool entries are validated and forwarded. | - -The transition from SYNC → FORWARD happens via `transition_to_forward()` (see [SYNC→FORWARD Transition](#syncforward-transition) below). - ---- - -## Core Mechanism: `send_to_all_our_fork_peers` - -All broadcasting in forward mode funnels through a single method: - -```cpp -// dlt_p2p_node.cpp -void dlt_p2p_node::send_to_all_our_fork_peers(const message& msg, peer_id exclude = INVALID_PEER_ID, const block_id_type& block_id = block_id_type()) { - for (auto& [id, state] : _peer_states) { - if (id == exclude) continue; - if (state.exchange_enabled && state.lifecycle_state == DLT_PEER_LIFECYCLE_ACTIVE) { - if (block_id != block_id_type() && state.has_block(block_id)) continue; // echo suppression - send_message(id, msg); - if (block_id != block_id_type()) state.record_known_block(block_id); - } - } -} -``` - -**Two filters control delivery:** - -| Filter | Source | Meaning | -|--------|--------|---------| -| `exchange_enabled == true` | Set during hello handshake, combined via OR in hello_reply (P27 fix); re-evaluated on block accept and FORWARD transition (P25 fix) | Peer is on our fork — its head block is known to us | -| `lifecycle_state == ACTIVE` | Peer lifecycle FSM | Peer has completed handshake and is in normal operation | - -**`exclude` parameter:** When relaying a message received from a peer, that peer's ID is passed as `exclude` to avoid echoing the message back. - -**`block_id` parameter (echo suppression):** When broadcasting or relaying a block, the block's ID is passed as `block_id`. The function checks each peer's `known_blocks` ring buffer — if the peer already has this block, the send is skipped and the peer is counted in the `skipped_echo` diagnostic. After a successful send, the block ID is recorded in the peer's `known_blocks`. - ---- - -## Block Echo Suppression - -### Problem - -In a multi-peer mesh, a block can echo back to the node that produced it: - -``` -1. Master A generates block #N, broadcasts to B, V, G -2. V receives #N first, accepts it, retransmits to B and G (standard relay) -3. B receives #N from V, accepts it, retransmits to A and G -4. A receives its own block #N back from B — wasted bandwidth + log noise -``` - -The `exclude` parameter only filters the **direct sender**. It cannot filter peer B, which received the block from V (not from A) and relayed it to A. - -### Solution: Per-Peer `known_blocks` Ring Buffer - -Each peer state maintains a small ring buffer of recent block IDs that the peer is **known to have**: - -```cpp -// dlt_p2p_peer_state.hpp -static constexpr size_t KNOWN_BLOCKS_WINDOW = 20; // ~60 seconds of blocks at 3s/block -std::vector known_blocks; - -bool has_block(const block_id_type& id) const; -void record_known_block(const block_id_type& id); -``` - -A peer is recorded as having a block in two situations: - -| Signal | Why it means the peer has the block | -|--------|-------------------------------------| -| **We sent the block to the peer** | `send_to_all_our_fork_peers` records the block ID after each successful send | -| **The peer sent the block to us** | `on_dlt_block_reply` records the block ID from the incoming message | - -Before sending a block to a peer, `send_to_all_our_fork_peers` checks `has_block()`. If the peer already has it, the send is skipped. - -### Scope - -Echo suppression only applies to **block_reply** messages (the primary broadcast vector in FORWARD mode). Transactions, fork_status messages, and other P2P messages are not affected — the `block_id` parameter defaults to `block_id_type()` (null) for those calls. - -### Diagnostics - -The relay log line now includes echo-filtered count: -``` -Relay block_reply to 3 peers (0 skipped: no_exchange, 0 skipped: not_active, 1 skipped: echo) -``` - ---- - -## Block Broadcasting - -### Self-Produced Blocks - -When a validator produces a block, the flow is: - -``` -validator.cpp:1081 p2p().broadcast_block(block) - → p2p_plugin.cpp:482 my->node->broadcast_block(block) - → dlt_p2p_node.cpp:1117 -``` - -```cpp -void dlt_p2p_node::broadcast_block(const signed_block& block) { - dlt_block_reply_message reply; - reply.block = block; - reply.next_available = 0; - reply.is_last = true; - send_to_all_our_fork_peers(message(reply), INVALID_PEER_ID, block.id()); // NO exclude, WITH echo suppression -} -``` - -The block goes to **all** ACTIVE peers with `exchange_enabled=true`, **except** peers that already have this block (echo suppression). - -### Relaying Received Blocks - -When a block arrives from a peer (via `on_dlt_block_reply`), the node applies it and **retransmits** to all other fork-aligned peers: - -```cpp -// dlt_p2p_node.cpp -// Record that sender has this block (echo suppression) -state.record_known_block(reply.block.id()); -// Retransmit to our-fork peers (with echo suppression) -send_to_all_our_fork_peers(message(dlt_block_reply_message(reply)), peer, reply.block.id()); -``` - -The `peer` (sender) is excluded via the `exclude` parameter. Additionally, peers that already have this block in their `known_blocks` are skipped via echo suppression. The sender's `known_blocks` is updated so that if this block is later received from another peer, it won't be sent back to the original sender. - -### Block Post-Validation Broadcast - -`broadcast_block_post_validation()` sends a lightweight fork-status message (block ID + validator + signature) instead of the full block. This is called by the Validator Plugin for each block in the production round after validation completes. - ---- - -## Transaction Broadcasting - -### Self-Originated Transactions - -When a transaction arrives via API (`network_broadcast_api`): - -```cpp -// dlt_p2p_node.cpp -void dlt_p2p_node::broadcast_transaction(const signed_transaction& trx) { - add_to_mempool(trx, /*from_peer=*/false, INVALID_PEER_ID); - dlt_transaction_message msg; - msg.trx = trx; - dlog(DLT_LOG_DGRAY "Broadcasting transaction ${id} to fork peers" DLT_LOG_RESET, - ("id", trx.id())); - send_to_all_our_fork_peers(message(msg)); // NO exclude -} -``` - -The transaction is added to the local mempool and broadcast to **all** fork-aligned peers. - -### Relaying Received Transactions - -When a transaction arrives from a peer (via `on_dlt_transaction` → `add_to_mempool`): - -```cpp -// dlt_p2p_node.cpp — in add_to_mempool() -// Retranslate to our-fork peers (if from peer) -if (from_peer && sender != INVALID_PEER_ID) { - dlog(DLT_LOG_DGRAY "Relaying transaction ${id} to fork peers (excluding sender)" DLT_LOG_RESET, - ("id", trx_id)); - dlt_transaction_message msg; - msg.trx = trx; - send_to_all_our_fork_peers(message(msg), sender); // exclude sender -} -``` - -The sender is excluded; all other fork-aligned peers receive the relay. - -### Transaction Diagnostic Logging - -All transaction exchange events produce dark-gray `dlog` messages (visible at debug log level): - -| Event | Log Message | Level | -|-------|-------------|-------| -| Self-originated send (API) | `Broadcasting transaction ${id} to fork peers` | `dlog` DGRAY | -| Peer relay (retransmit) | `Relaying transaction ${id} to fork peers (excluding sender)` | `dlog` DGRAY | -| Relay stats in `send_to_all_our_fork_peers` | `Relay transaction to ${e} peers (${nx} skipped: no_exchange, ${na} skipped: not_active)` | `dlog` DGRAY | -| Received from peer (new) | `Got transaction ${id} from peer ${ep}` | `dlog` DGRAY | -| Received duplicate | *Silent — no log emitted* | — | - -Duplicate transactions (already in `_mempool_by_id`) are silently ignored in both `on_dlt_transaction` and `add_to_mempool`, same as duplicate blocks — no console spam. - -### Mempool Validation (Pre-Forwarding) - -Before a transaction is added to mempool or forwarded, it passes these checks: - -| Check | Failure Action | -|-------|---------------| -| **Dedup** (`_mempool_by_id`) | Silently skip | -| **Expired** (`trx.expiration < now`) | Reject, increment spam strike if from peer | -| **Expiration too far** (>24h) | Reject, increment spam strike if from peer | -| **Too large** (>64KB) | Reject, increment spam strike if from peer | -| **TaPoS invalid** (ref block unknown) | Reject, increment spam strike if from peer | -| **Mempool full** | Evict oldest-expiry entry, retry | - -During SYNC mode, accepted transactions are tagged `is_provisional = true` — they are stored but NOT forwarded to peers. On transition to FORWARD, provisional entries are revalidated (TaPoS check against current head) and the invalid ones are purged. - ---- - -## SYNC→FORWARD Transition - -The transition from SYNC to FORWARD is governed by `transition_to_forward()`: - -```cpp -// dlt_p2p_node.cpp:1247 -void dlt_p2p_node::transition_to_forward() { - if (_node_status == DLT_NODE_STATUS_FORWARD) return; - _node_status = DLT_NODE_STATUS_FORWARD; - _sync_stagnation_retries = 0; - // ... -} -``` - -### Transition Triggers - -| Trigger | Location | Condition | -|---------|----------|------------| -| **Block range complete** | `on_dlt_block_range_reply()` | `is_last == true` AND `any_block_applied == true` (P20 guard) | -| **Sync catchup** | `check_sync_catchup()` | `our_head >= all_active_peer_heads` AND at least one active peer exists | -| **Stagnation timeout** | `sync_stagnation_check()` | 30s no-block, 3 retries exhausted → FORWARD with warning | - -`check_sync_catchup()` is called from two places (P26 fix): -- `on_dlt_block_reply()` — after accepting a single block -- `periodic_task()` — every ~5 seconds - -**Isolation guard (P53 fix):** `check_sync_catchup()` does NOT claim "caught up" when zero active peers exist. With no peers to compare against, the node cannot determine whether it has actually caught up. Instead, it tracks isolation via `_isolation_detected_time` and after 60 seconds calls `emergency_peer_reset()` to force reconnection. See [Peer Isolation Recovery](#peer-isolation-recovery) below. - -### What Happens on Transition - -1. **Notify all connected peers**: Send `dlt_fork_status_message` with `node_status=FORWARD` to ALL active/syncing peers (not just exchange-enabled). This lets peers know we're now in FORWARD mode so they can re-evaluate `exchange_enabled` for us. -2. **Re-evaluate `exchange_enabled` for all peers** (P25 fix): peers whose head block is now recognized (because we synced past it) get `exchange_enabled = true` -3. **Revalidate provisional mempool entries**: entries tagged during SYNC are checked for TaPoS validity against the current head; invalid ones are purged -4. **Reset stagnation retries**: counter set to 0 for clean slate - ---- - -## FORWARD→SYNC Transition (P27) - -| Trigger | Location | Condition | -|---------|----------|------------| -| **Peer ahead in hello_reply** | `on_dlt_hello_reply()` | `peer_head_num > our_head + FORWARD_FALLBEHIND_THRESHOLD` while in FORWARD mode | -| **Periodic fallbehind check** | `check_forward_behind()` | Any active peer is ahead by > `FORWARD_FALLBEHIND_THRESHOLD` (2) blocks | -| **FORWARD stagnation** | `check_forward_stagnation()` | Head stuck for 30s with active peers and at least one peer ahead → SYNC (P37). No peer ahead → reset stagnation timer, stay in FORWARD (P55). Isolated (no active peers) → emergency reset after 60s (P53) | - ---- - -## The `exchange_enabled` Flag - -`exchange_enabled` is the primary gatekeeper for forward-mode traffic. It is set during hello handshake, combined via logical OR in hello_reply, and re-evaluated at key lifecycle events. - -### Initial Setting (Hello Handshake) - -During `build_hello_reply()`, `check_fork_alignment()` determines whether the peer's head/LIB blocks are known to us: - -| Check | Condition | Result | -|-------|-----------|--------| -| Empty peer (`head==0`) | Always | Aligned (new node) | -| Range overlap | `peer_head_num ∈ [our_earliest, our_latest]` | Use `is_block_known(head_id)` | -| Boundary link | `peer_head_num + 1 == our_earliest` | Check `our_earliest_block.previous == head_id` | -| LIB fallback | Always | `is_block_known(lib_id)` | - -If any check passes → `exchange_enabled = true`, `fork_alignment = true`. - -### P27 Fix: OR Combination in `on_dlt_hello_reply` - -When two nodes connect, **both sides send hello messages** to each other. Each side computes its own `exchange_enabled` in `on_dlt_hello` (local determination), then receives the other side's determination in `on_dlt_hello_reply`. - -**The bug (P27):** `on_dlt_hello_reply` used to **overwrite** `state.exchange_enabled` with the remote side's determination. This caused a critical failure: - -``` -Slave (head=79673001) connects to Master (head=79673101) - -1. Master's on_dlt_hello: - - check_fork_alignment(slave_head) → true (master has block 79673001) - - state.exchange_enabled = true ✅ - -2. Slave's on_dlt_hello: - - check_fork_alignment(master_head) → false (slave doesn't have block 79673101) - - state.exchange_enabled = false - - Sends hello_reply with exchange_enabled=false to master - -3. Master's on_dlt_hello_reply: - - state.exchange_enabled = reply.exchange_enabled (overwrite!) - - state.exchange_enabled = false ❌ BUG! - - Master stops broadcasting blocks to slave! -``` - -**The fix:** Use `state.exchange_enabled = state.exchange_enabled || reply.exchange_enabled`. If **either** side considers the peer fork-aligned, exchange is enabled: -- If we think the peer is on our fork → we should send blocks to them -- If they think we're on their fork → we should receive blocks from them -- If both are false → truly different forks, no exchange - -### Receiving FORWARD Transition from a Peer - -When `on_dlt_fork_status()` receives a status update from a peer that just transitioned SYNC→FORWARD, the node re-evaluates `exchange_enabled` for that peer. The peer's head block may now be within our known chain, meaning we should enable block/transaction exchange with it. - -### Re-Evaluation Triggers (P25 Fix) - -The original implementation set `exchange_enabled` once and never updated it, causing slave-produced blocks to be ignored by the master. Re-evaluation points: - -1. **`transition_to_forward()`**: Re-checks `is_block_known(peer_head_id)` for all peers with `exchange_enabled=false` -2. **`on_dlt_fork_status()`**: When a peer transitions SYNC→FORWARD, re-checks if the peer's head block is now known to us -3. **`on_dlt_block_range_reply()`**: When a non-exchange-enabled peer's block is ACCEPTED, enables exchange for that peer -4. **`on_dlt_block_reply()`**: Same — when a single block from a non-exchange-enabled peer is ACCEPTED - ---- - -## FORWARD→SYNC Fallback (P27 Fix) - -In FORWARD mode, blocks arrive via broadcast from fork-aligned peers. But if broadcast blocks are missed (e.g., connection dropped, `exchange_enabled` was incorrectly false), the node can fall behind with no recovery mechanism. - -Two detection points were added: - -### 1. In `on_dlt_hello_reply` (Reactive) - -When a FORWARD node receives a hello_reply from a peer that is significantly ahead (`peer_head_num > our_head + FORWARD_FALLBEHIND_THRESHOLD`), it transitions to SYNC and requests the missing range: - -```cpp -if (_node_status == DLT_NODE_STATUS_FORWARD) { - uint32_t our_head = _delegate->get_head_block_num(); - if (state.peer_head_num > our_head + FORWARD_FALLBEHIND_THRESHOLD) { - transition_to_sync(); - request_blocks_from_peer(peer); - } -} -``` - -### 2. In `check_forward_behind()` (Periodic) - -Called every ~5 seconds from `periodic_task()`. Iterates all active peers and checks if any is ahead by more than `FORWARD_FALLBEHIND_THRESHOLD` blocks: - -```cpp -void dlt_p2p_node::check_forward_behind() { - if (_node_status != DLT_NODE_STATUS_FORWARD) return; - for (const auto& [id, state] : _peer_states) { - if (state.peer_head_num > our_head + FORWARD_FALLBEHIND_THRESHOLD) { - transition_to_sync(); - // Request blocks from ALL exchange-enabled ahead peers - break; - } - } -} -``` - -The threshold is `FORWARD_FALLBEHIND_THRESHOLD = 2` (3+ blocks behind = ~9s at 3s/block). This avoids false triggers from normal 1-block broadcast latency. - ---- - -## Peer Isolation Recovery (P53) - -### Problem - -When all peers are disconnected or banned (e.g., after a snapshot pause), the node becomes **isolated** — no active peer connections exist. This caused a SYNC↔FORWARD oscillation loop: - -``` -1. All peers DISC → check_sync_catchup() sees 0 active peers → all_caught_up=true → FORWARD -2. In FORWARD with no connections → check_forward_stagnation() after 30s → SYNC -3. In SYNC with no connections → check_sync_catchup() sees 0 active → FORWARD -4. Repeat forever, head never advances, backoffs never expire (up to 3600s) -``` - -The root cause: `check_sync_catchup()` treated zero active peers as "caught up" (vacuously true for the `all_caught_up` check), and `check_forward_stagnation()` transitioned to SYNC without any peer to request blocks from. - -### Solution: Isolation Detection + Emergency Reset - -A new field `_isolation_detected_time` tracks when isolation was first detected. After 60 seconds (`ISOLATION_RESET_SEC`) of continuous isolation, `emergency_peer_reset()` fires: - -1. **Clears all soft bans** — BANNED peers are moved to DISCONNECTED state, `ban_reason` and `spam_strikes` are reset. -2. **Resets all backoffs** — Every DISCONNECTED peer gets `reconnect_backoff_sec = INITIAL_RECONNECT_BACKOFF_SEC` (30s) and `next_reconnect_attempt = now` (immediate). -3. **Resets stagnation counters** — `_sync_stagnation_retries` is cleared. -4. **Clears isolation timer** — `_isolation_detected_time` is reset so the timer can re-trigger if isolation recurs. - -On the next `periodic_task()` tick (5 seconds), `periodic_reconnect_check()` will attempt immediate reconnection to all peers. - -### Where Isolation Is Handled - -| Function | Behavior When Isolated | -|----------|----------------------| -| `check_sync_catchup()` | Returns early (does not claim caught up). Starts isolation timer or calls `emergency_peer_reset()` after 60s. | -| `check_forward_stagnation()` | Returns early (does not transition to SYNC). Starts isolation timer or calls `emergency_peer_reset()` after 60s. | -| `emergency_peer_reset()` | Clears bans, resets backoffs, enables immediate reconnection. | - ---- - -## FORWARD Stagnation When No Peer Is Ahead (P55) - -A second oscillation pattern was observed when the head is stuck but no connected peer has a higher block number: - -``` -1. Head stuck at block N, all 5 peers also at block N → check_forward_stagnation() after 30s → SYNC -2. In SYNC, sync_stagnation_check() fires immediately (stale timer, see below) -3. check_sync_catchup() sees our_head >= all peers → FORWARD -4. Repeat — SYNC never actually requests or processes any blocks -``` - -**Two root causes:** - -1. `transition_to_sync()` did not reset `_last_block_received_time`, so the sync stagnation timer inherited the stale timestamp from the last block received in FORWARD mode (~30s ago). `sync_stagnation_check()` fired on the very next periodic tick. - -2. `check_forward_stagnation()` transitioned to SYNC even when no peer was ahead. With no peer to sync from, SYNC mode was useless — `check_sync_catchup()` immediately returned to FORWARD. - -**Fixes:** - -1. `transition_to_sync()` now resets `_last_block_received_time = fc::time_point::now()`, giving the sync phase a full 30s window. - -2. `check_forward_stagnation()` now checks for peers ahead before transitioning to SYNC. If no peer has `peer_head_num > our_head`, the function resets the stagnation timer and stays in FORWARD instead of oscillating. - ---- - -## What Does NOT Get Forwarded - -### Peers on a Different Fork - -Peers whose `exchange_enabled=false` (fork not aligned) receive nothing. This is by design — blocks and transactions from one fork are meaningless on another. - -### SYNC-Mode Nodes - -While in SYNC mode, a node does NOT broadcast blocks or relay transactions to peers. The only outbound traffic is block range requests (`dlt_get_block_range_message`) and gap fill requests (`dlt_gap_fill_request`). Gap fill works in both SYNC and FORWARD modes — in SYNC mode, it provides an alternative path to request missing blocks when `request_blocks_from_peer()` cannot bridge a gap (e.g., blocks below the syncing peer's DLT range). Large gaps are served in 100-block chunks. - -### Block Processing Paused - -When `_block_processing_paused == true` (snapshot in progress), periodic tasks skip DB-accessing operations, but the node can still receive and broadcast blocks. The flag primarily prevents sync-stagnation false positives and lock contention. - ---- - -## Comparison: Old Graphene vs. DLT Forward Mode - -| Aspect | Old Graphene (`node.cpp`) | DLT (`dlt_p2p_node.cpp`) | -|--------|--------------------------|--------------------------| -| **Broadcast trigger** | Inventory gossip → peer requests items | Direct push of full block/transaction | -| **Filtering** | `peer_needs_sync_items_from_us` / `we_need_sync_items_from_peer` per-peer flags | `exchange_enabled` (fork alignment) + `lifecycle_state == ACTIVE` | -| **Block format** | `block_message` with synopsis negotiation | `dlt_block_reply_message` — full block, always | -| **Transaction format** | `trx_message` via inventory | `dlt_transaction_message` — direct push | -| **Relay exclusion** | Complex inventory tracking | Simple `exclude` parameter on `send_to_all_our_fork_peers` | -| **Mempool** | Chain's `_pending_tx` | Separate P2P mempool with expiry/TaPoS/size filtering | -| **Anti-spam** | Multiple counters (`unlinkable_block_strikes`, `sync_spam_strikes`, etc.) | Single `spam_strikes` counter, reset on good packet | - ---- - -## Summary: Who Gets What in Forward Mode - -| Event | Sent to | Excluded | Echo Filtered | -|-------|---------|----------|---------------| -| Node produces a block | All ACTIVE peers with `exchange_enabled=true` | *none* | Peers that already have the block (from a previous relay) | -| Node originates a transaction | All ACTIVE peers with `exchange_enabled=true` | *none* | N/A | -| Node receives a block from peer X | All ACTIVE peers with `exchange_enabled=true` | X | Peers that already have the block | -| Node receives a transaction from peer X | All ACTIVE peers with `exchange_enabled=true` | X | N/A | -| Peer has `exchange_enabled=false` | *nothing* | — | — | -| Node is in SYNC mode | *nothing* (only range requests and gap fill) | - | - | - ---- - -## Peer Stats: Stale `peer_head_num` Caveat - -The `peer_head_num` shown in the P2P stats table is **not real-time**. It is a snapshot from the last communication event: - -| Update Source | When `peer_head_num` Gets Updated | -|-------------|----------------------------------| -| `dlt_hello_message` | Initial handshake when connection is established | -| `dlt_fork_status_message` | Periodic fork_status exchanges between peers | -| `dlt_block_reply_message` | Updated if a peer sends us block #N, its head must be ≥ N | - -Between these events, the peer's actual chain head may advance significantly (e.g., the peer produces or receives blocks via broadcast). **Do not treat `peer_head_num` in the stats table as the peer's current chain state.** It is useful for relative ordering and sync progress estimation, but not as a real-time block height monitor. - ---- - -## Relevant Source Files - -| File | Content | -|------|---------| -| `libraries/network/dlt_p2p_node.cpp` | `broadcast_block()`, `broadcast_transaction()`, `send_to_all_our_fork_peers()`, `transition_to_forward()`, `check_sync_catchup()`, `check_forward_behind()`, `check_forward_stagnation()`, `emergency_peer_reset()`, `add_to_mempool()` | -| `libraries/network/include/graphene/network/dlt_p2p_node.hpp` | `dlt_p2p_node` class declaration, `dlt_node_status` enum | -| `libraries/network/include/graphene/network/dlt_p2p_messages.hpp` | `dlt_block_reply_message`, `dlt_transaction_message`, `dlt_message_type_enum` | -| `libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp` | `dlt_peer_state` (contains `exchange_enabled`, `fork_alignment`, `known_blocks` for echo suppression) | -| `plugins/p2p/p2p_plugin.cpp` | `dlt_delegate::accept_block()`, `p2p_plugin::broadcast_block()`, `p2p_plugin::broadcast_transaction()` | -| `plugins/validator/validator.cpp` | Calls `p2p().broadcast_block()` after block production | - ---- - -## Related Documents - -- [DLT P2P Network Redesign](./dlt-p2p-network-redesign.md) — Full implementation overview -- [DLT 4-Node Sync Scenarios](./dlt-4-node-sync-scenarios.md) — Problem analysis for SYNC/FORWARD edge cases -- [P2P Sync Workflow](./p2p-sync-workflow.md) — Old Graphene synopsis-based sync (pre-DLT, for comparison) diff --git a/.qoder/docs/dlt-hardfork-new-objects.md b/.qoder/docs/dlt-hardfork-new-objects.md deleted file mode 100644 index 4a3881cb12..0000000000 --- a/.qoder/docs/dlt-hardfork-new-objects.md +++ /dev/null @@ -1,383 +0,0 @@ -# DLT Hardforks with New Consensus Objects - -This document describes how to implement hardforks that introduce new consensus objects in DLT (Distributed Ledger Technology) mode, and how the snapshot system handles compatibility between nodes running different versions. - -## Overview - -In DLT mode, nodes can start from snapshots instead of replaying the entire blockchain. When a hardfork introduces new consensus objects, the system must ensure: - -1. **Forward compatibility**: Old nodes can load snapshots containing unknown objects -2. **Backward compatibility**: New nodes can load older snapshots missing new objects -3. **Consensus safety**: Nodes only participate in consensus for hardforks they understand - -## Adding New Consensus Objects in a Hardfork - -### Step 1: Define the Object Type - -Add the new object type to `libraries/chain/include/graphene/chain/chain_object_types.hpp`: - -```cpp -enum object_type { - // ... existing types ... - block_post_validation_object_type, // last existing type - prediction_market_object_type, // NEW: add new type at the end -}; - -// Forward declaration -class prediction_market_object; - -// Type alias -typedef object_id prediction_market_object_id_type; - -// Add to FC_REFLECT_ENUM -FC_REFLECT_ENUM(graphene::chain::object_type, - // ... existing types ... - (block_post_validation_object_type) - (prediction_market_object_type) // NEW -) -``` - -### Step 2: Create the Object Definition - -Create a new header file `libraries/chain/include/graphene/chain/prediction_market_object.hpp`: - -```cpp -#pragma once - -#include -#include - -namespace graphene { namespace chain { - -class prediction_market_object - : public object { -public: - prediction_market_object() = delete; - - template - prediction_market_object(Constructor&& c, allocator a) - : title(a), description(a) { - c(*this); - } - - id_type id; - account_name_type creator; - shared_string title; - shared_string description; - asset total_stake; - time_point_sec resolution_time; - uint16_t status = 0; // 0=open, 1=resolved, 2=cancelled -}; - -struct by_creator; -struct by_resolution_time; - -typedef multi_index_container< - prediction_market_object, - indexed_by< - ordered_unique, - member>, - ordered_non_unique, - member>, - ordered_non_unique, - member> - >, - allocator -> prediction_market_index; - -}} // graphene::chain - -FC_REFLECT((graphene::chain::prediction_market_object), - (id)(creator)(title)(description)(total_stake)(resolution_time)(status)) -CHAINBASE_SET_INDEX_TYPE(graphene::chain::prediction_market_object, graphene::chain::prediction_market_index) -``` - -### Step 3: Register the Index - -Add the index registration in `libraries/chain/database.cpp` in `initialize_indexes()`: - -```cpp -void database::initialize_indexes() { - // ... existing indexes ... - add_core_index(*this); - - // NEW: Register prediction market index - add_core_index(*this); - - _plugin_index_signal(); -} -``` - -### Step 4: Update Snapshot Plugin - -Add serialization support in `plugins/snapshot/plugin.cpp`: - -**In `serialize_state()`:** -```cpp -fc::mutable_variant_object snapshot_plugin::plugin_impl::serialize_state() { - fc::mutable_variant_object state; - - // ... existing EXPORT_INDEX calls ... - - // NEW: Export prediction market objects - EXPORT_INDEX(prediction_market_index, prediction_market_object, "prediction_market") - - #undef EXPORT_INDEX - return state; -} -``` - -**In `load_snapshot()` - add import logic:** -```cpp -// NEW: Import prediction market objects (in appropriate section) -if (state.contains("prediction_market")) { - auto n = detail::import_prediction_markets(db, state["prediction_market"].get_array()); - ilog("Imported ${n} prediction markets", ("n", n)); -} -``` - -**Create specialized import function (if using shared_string):** -```cpp -inline uint32_t import_prediction_markets( - graphene::chain::database& db, - const fc::variants& arr -) { - uint32_t count = 0; - for (const auto& v : arr) { - auto id_val = v["id"].as_int64(); - auto& mutable_idx = db.get_mutable_index(); - mutable_idx.set_next_id(prediction_market_object_id_type(id_val)); - - db.create([&](prediction_market_object& obj) { - obj.creator = v["creator"].as(); - from_string(obj.title, v["title"].as_string()); - from_string(obj.description, v["description"].as_string()); - obj.total_stake = v["total_stake"].as(); - obj.resolution_time = v["resolution_time"].as(); - obj.status = v["status"].as_uint64(); - }); - ++count; - } - return count; -} -``` - -### Step 5: Implement Hardfork Logic - -Add the hardfork case in `libraries/chain/database.cpp` in `apply_hardfork()`: - -```cpp -void database::apply_hardfork(uint32_t hardfork) { - switch (hardfork) { - // ... existing cases ... - - case CHAIN_HARDFORK_10: // NEW hardfork - { - // Initialize any required state for prediction markets - // This runs when the hardfork activates - - // Example: Set initial parameters, migrate data, etc. - const auto& props = get_dynamic_global_properties(); - modify(props, [&](dynamic_global_property_object& p) { - // Set any new parameters - }); - - break; - } - - default: - break; - } - - // Update hardfork property object - modify(get_hardfork_property_object(), [&](hardfork_property_object& hfp) { - hfp.processed_hardforks.push_back(_hardfork_times[hardfork]); - hfp.last_hardfork = hardfork; - hfp.current_hardfork_version = _hardfork_versions[hardfork]; - }); -} -``` - -### Step 6: Define Hardfork Constants - -Add hardfork constants to the appropriate header (e.g., `libraries/chain/include/graphene/chain/hardfork.hpp` or hardfork.d files): - -```cpp -#ifndef CHAIN_HARDFORK_10 -#define CHAIN_HARDFORK_10 10 -#define CHAIN_HARDFORK_10_TIME 1893456000 // Unix timestamp -#define CHAIN_HARDFORK_10_VERSION hardfork_version( 1, 10, 0 ) -#endif -``` - -Update `CHAIN_NUM_HARDFORKS` if necessary. - -## Snapshot Compatibility - -### Forward Compatibility (Old Node → New Snapshot) - -When an older node loads a snapshot created by a newer node: - -1. **Unknown objects are silently ignored** - The snapshot loader uses conditional checks: - ```cpp - if (state.contains("prediction_market")) { - // import prediction markets - } - ``` - If the old node doesn't check for `prediction_market`, it simply won't be imported. - -2. **Hardfork state is preserved** - The `hardfork_property_object` contains: - - `last_hardfork` - highest applied hardfork number - - `current_hardfork_version` - current network version - - `processed_hardforks` - timestamps of applied hardforks - -3. **Node behavior** - The old node will: - - Successfully load the snapshot - - Continue operating at its known hardfork level - - Reject blocks containing unknown operations - - Eventually fall out of consensus when the new hardfork activates - -### Backward Compatibility (New Node → Old Snapshot) - -When a newer node loads an older snapshot: - -1. **Missing objects are handled gracefully** - All object imports are conditional: - ```cpp - if (state.contains("prediction_market")) { - // import prediction markets - } - // If not present, the index remains empty - ``` - -2. **Hardfork initialization** - After loading, `initialize_hardforks()` sets up the hardfork schedule. When the hardfork time arrives, `apply_hardfork()` will: - - Initialize any required state - - Create initial objects if needed - - Update the hardfork property - -3. **Node behavior** - The new node will: - - Successfully load the older snapshot - - Have empty indexes for new object types - - Apply the hardfork at the scheduled time - - Participate normally in consensus after the hardfork - -## Compatibility Matrix - -| Scenario | Snapshot Contains | Node Version | Result | -|----------|-------------------|--------------|--------| -| Old node loads new snapshot | Unknown objects | Older | ✅ Ignores unknown objects, continues at its hardfork | -| New node loads old snapshot | Missing new objects | Newer | ✅ Initializes empty indexes, applies hardfork when triggered | -| Old node processes new HF blocks | N/A | Older | ❌ Rejects unknown operations (expected consensus split) | -| New node processes old blocks | N/A | Newer | ✅ Validates normally, hardfork not yet active | - -## Best Practices - -### 1. Object Type Ordering - -Always add new object types at the **end** of the `object_type` enum to avoid reordering existing types, which would break binary compatibility. - -### 2. Optional vs Required Objects - -Consider whether new objects should be: -- **Critical**: Required for consensus (must be in snapshot) -- **Important**: Needed for full functionality (should be in snapshot) -- **Optional**: Can be reconstructed (nice to have in snapshot) - -### 3. Hardfork State Validation - -Nodes should validate the hardfork state after loading a snapshot: - -```cpp -const auto& hfp = db.get_hardfork_property_object(); -if (hfp.last_hardfork > CHAIN_NUM_HARDFORKS) { - wlog("Snapshot requires hardfork ${hf} which this node doesn't support", - ("hf", hfp.last_hardfork)); -} -``` - -### 4. Snapshot Versioning - -Consider incrementing `SNAPSHOT_FORMAT_VERSION` for breaking changes: - -```cpp -// In snapshot_types.hpp -static const uint32_t SNAPSHOT_FORMAT_VERSION = 2; // Increment for breaking changes -``` - -### 5. Testing Compatibility - -Test these scenarios: -1. Create snapshot with new objects, load on old node -2. Create snapshot without new objects, load on new node -3. Verify hardfork applies correctly after loading old snapshot -4. Verify old node rejects new hardfork blocks appropriately - -## Example: Complete Hardfork Implementation - -Here's a minimal example of adding a simple counter object in hardfork 10: - -**1. Object Definition (`counter_object.hpp`):** -```cpp -#pragma once -#include - -namespace graphene { namespace chain { - -class counter_object : public object { -public: - template - counter_object(Constructor&& c, allocator) { c(*this); } - - id_type id; - account_name_type owner; - uint64_t count = 0; -}; - -typedef multi_index_container< - counter_object, - indexed_by< - ordered_unique, member>, - ordered_unique, member> - >, - allocator -> counter_index; - -}} - -FC_REFLECT((graphene::chain::counter_object), (id)(owner)(count)) -CHAINBASE_SET_INDEX_TYPE(graphene::chain::counter_object, graphene::chain::counter_index) -``` - -**2. Hardfork Initialization:** -```cpp -case CHAIN_HARDFORK_10: -{ - // Initialize counters for existing accounts - const auto& acc_idx = get_index().indices(); - for (const auto& acc : acc_idx) { - create([&](counter_object& c) { - c.owner = acc.name; - c.count = 0; - }); - } - break; -} -``` - -**3. Snapshot Export/Import:** -```cpp -// Export -EXPORT_INDEX(counter_index, counter_object, "counter") - -// Import -if (state.contains("counter")) { - auto n = detail::import_simple_objects( - db, state["counter"].get_array()); - ilog("Imported ${n} counters", ("n", n)); -} -``` - -## Related Documentation - -- [Snapshot Plugin](snapshot-plugin.md) - General snapshot functionality -- [Plugins](plugins.md) - Plugin architecture and development -- [Data Types](data-types.md) - Protocol data types and serialization diff --git a/.qoder/docs/dlt-p2p-network-redesign-review.md b/.qoder/docs/dlt-p2p-network-redesign-review.md deleted file mode 100644 index 7c20fd6123..0000000000 --- a/.qoder/docs/dlt-p2p-network-redesign-review.md +++ /dev/null @@ -1,299 +0,0 @@ -# DLT P2P Network Redesign — Plan vs. Implementation Review - -Review of [implementation status](dlt-p2p-network-redesign.md) against the [design plan](../plans/dlt-p2p-network-redesign_91a7ca29.md). - -## Summary - -The implementation closely follows the plan across all 5 phases. Core architecture, message types, connection management, sync logic, mempool, fork resolution, anti-spam, and in-place replacement are correctly implemented. Snapshot download on empty state is verified as preserved (lives in chain + snapshot plugins, untouched by P2P redesign). **6 unreported gaps** were found beyond the 6 already-documented known limitations. - ---- - -## Items Fully Matching the Plan (29 items) - -| Area | Plan Requirement | Status | -|------|-----------------|--------| -| Message types | 14 types (5100-5113), all structs with exact fields | ✅ Match | -| Delegate pattern | `dlt_p2p_delegate` bridging network→chain | ✅ Match | -| Fiber architecture | Accept loop, read loop, periodic task on `fc::thread` | ✅ Match | -| Wire format | 8-byte header (size+type) + raw data, no STCP | ✅ Match | -| Per-peer state | All fields: lifecycle, chain state, spam, exchange, reconnect | ✅ Match | -| Peer lifecycle | 6 states: connecting(5s)→handshaking(10s)→syncing→active→disconnected→banned | ✅ Match | -| Reconnection | Backoff 30s→…→3600s, ±25% jitter, reset on stable>5min | ✅ Match | -| 8h peer removal | Permanently remove after `dlt-peer-max-disconnect-hours` of non-response | ✅ Match | -| Node status | SYNC / FORWARD, transitions at catchup completion | ✅ Match | -| Hello handshake | `protocol_version` check, fork alignment via `is_block_known()` | ✅ Match | -| Block sync | Bulk range (200 blocks), single block, `not_available` | ✅ Match | -| P2P mempool | Separate index: dedup, expiry check, TaPoS check, size limits | ✅ Match | -| Mempool eviction | Oldest-expiry first when caps hit | ✅ Match | -| Provisional entries | Tagged during SYNC, revalidated on SYNC→FORWARD | ✅ Match | -| Fork threshold | 42 blocks (= `CHAIN_MAX_WITNESSES * 2`) | ✅ Match | -| Fork hysteresis | `CONFIRMATION_BLOCKS = 6`, tracked via `dlt_fork_resolution_state` | ✅ Match | -| Anti-spam | Single `spam_strikes` counter, reset on good, threshold=10, ban=3600s | ✅ Match | -| Spam reset-on-good | Valid block/transaction/hello → reset counter to 0 | ✅ Match | -| Peer exchange rate-limit | 10-min cooldown per peer | ✅ Match | -| Peer exchange subnet diversity | /24 subnet, max 2 per subnet | ✅ Match | -| Peer exchange min uptime | 600s before sharing | ✅ Match | -| Peer exchange cap | Max 10 peers per reply | ✅ Match | -| Color logging | GREEN/WHITE/RED/DGRAY/ORANGE | ✅ Match | -| Sync stagnation | 30s no-block, 3 retries, then FORWARD with warning | ✅ Match | -| Plugin replacement | Same `"p2p"` name, same port, same public API | ✅ Match | -| Old files removed | 12 files (node.cpp, peer_connection.cpp, stcp_socket.cpp, etc.) deleted from build | ✅ Match | -| Config | 9 new DLT options added, 4 old options removed | ✅ Match | -| Plugin startup | Deadlock fixed — `.async([setup]).wait()` instead of infinite loop block | ✅ Match | -| Snapshot download on empty state | Chain plugin detects `head_block_num == 0`, snapshot plugin downloads via raw TCP, P2P starts after import. Entirely in chain + snapshot plugins — untouched by P2P redesign. `trigger_resync()` bridge preserved. | ✅ Verified | - ---- - -## Known Gaps (Documented in implementation status) - -These are acknowledged in `dlt-p2p-network-redesign.md` § "Known Limitations / Future Work": - -| # | Gap | Severity | -|---|-----|----------| -| 1 | `periodic_dlt_prune_check()` is a no-op | P2 | -| 2 | `dlt_delegate::has_emergency_private_key()` returns `false` | P2 | -| 3 | `dlt_delegate::switch_to_fork()` simplified — only pops one block | P1 | -| 4 | `dlt_p2p_node::compute_branch_info()` returns `total_vote_weight=0` | P1 | -| 5 | No unit tests | P2 | -| 6 | Build not verified | P2 | - ---- - -## Unreported Gaps (Not in docs — Discrepancies with Plan) - -### GAP 1: `expected_next_block` tracking never used (P1 Security) - -**Plan**: P1 security hardening (§3.7) — Per-peer `expected_next_block` tracking to reject blocks that skip too far ahead (hole-creation attack prevention). - -**What exists**: The field `expected_next_block` is declared in `dlt_peer_state` ([dlt_p2p_peer_state.hpp:53](file:///d:/Work/viz-cpp-node/libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp#L53)) but **never set, updated, or validated anywhere** in `dlt_p2p_node.cpp`. - -**Impact**: No protection against peers sending blocks out of order or creating gaps. - -**Fix**: In `on_dlt_block_range_reply()` and `on_dlt_block_reply()`, after applying blocks, set `state.expected_next_block = last_applied_block_num + 1`. Before applying new blocks, validate that `first_block.block_num() == state.expected_next_block` (or 0 if unset). Reject with `record_packet_result(peer, false)` on mismatch. - ---- - -### GAP 2: `pending_block_batch` timeout never activated (P1 Security) - -**Plan**: P1 security hardening (§3.7) — Blocks received but not yet validated: track with `pending_block_batch` timeout (30s) — if validation doesn't complete, soft-ban the peer. - -**What exists**: The field `pending_block_batch_time` and helper `has_pending_batch_timeout()` are declared in `dlt_peer_state` ([dlt_p2p_peer_state.hpp:54-55](file:///d:/Work/viz-cpp-node/libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp#L54-L55)) but **never set** when blocks are received (e.g., in `on_dlt_block_range_reply` line 615), and **never checked** in `periodic_task()` (line 1271). - -**Impact**: A slow/malicious peer can send blocks that stall without consequence. - -**Fix**: In `on_dlt_block_range_reply()`, before `_delegate->accept_block()` loop, set `state.pending_block_batch_time = fc::time_point::now()`. Add a `block_validation_timeout()` method. In `periodic_task()`, call `block_validation_timeout()` to check all peers with `has_pending_batch_timeout()` → soft-ban on timeout. - ---- - -### GAP 3: `block_validation_timeout()` handler not implemented (P1 Security) - -**Plan**: Phase 2 (§4) — `block_validation_timeout()` — if `pending_block_batch` not validated within 30s, soft-ban the peer that sent it. - -**What exists**: Not implemented at all. No such function in `dlt_p2p_node.cpp`, not declared in the header. - -**Impact**: Combined with GAP 2, block validation timeout enforcement is completely absent. - -**Fix**: Add method declaration to `dlt_p2p_node.hpp` and implementation to `dlt_p2p_node.cpp`. Call from `periodic_task()`. - ---- - -### GAP 4: Fork resolution resets 42-block window on non-confirmation (P1 Fork) - -**Plan**: P1 hysteresis (§3.7) — After the 42-block window, compute the winner. Winner must maintain lead for 6 consecutive blocks. If lead flips, reset the **confirmation counter** — not the 42-block detection window. - -**What exists**: In `track_fork_state()` ([dlt_p2p_node.cpp:1116-1120](file:///d:/Work/viz-cpp-node/libraries/network/dlt_p2p_node.cpp#L1116-L1120)): - -```cpp -if (_fork_detected && - block.block_num() - _fork_detection_block_num >= FORK_RESOLUTION_BLOCK_THRESHOLD) { - resolve_fork(); - _fork_detected = false; // ← resets the 42-block window too! -} -``` - -When `resolve_fork()` returns early (hysteresis not met), `_fork_detected = false` causes a **fresh 42-block countdown** from the next block. The plan intended continuous retry without resetting the detection window. - -Both the plan's pseudocode and the implementation set `_fork_detected = false` after `resolve_fork()` — but this contradicts the plan's own design intent in section 3.7, which specifies that only the confirmation counter should reset on lead flip, not the 42-block detection window. - -**Impact**: Fork resolution can be delayed by 42 extra blocks per failed confirmation attempt. In the worst case (two forks with rapidly oscillating vote weight), resolution may never complete. - -**Fix**: Move `_fork_detected = false` into `resolve_fork()` — only clear it when resolution actually completes (i.e., `is_confirmed()` returns true and the switch is executed). Keep the confirmation counter reset logic unchanged. - ---- - -### GAP 5: Spam strikes not incremented for all mempool rejections (P0 Anti-Spam) - -**Plan**: P0 DoS protection (§3.7) — "All rejections increment sender's `spam_strikes`". - -**What exists**: In `add_to_mempool()` ([dlt_p2p_node.cpp:960-1012](file:///d:/Work/viz-cpp-node/libraries/network/dlt_p2p_node.cpp#L960-L1012)): - -| Rejection reason | Line | `record_packet_result(sender, false)` | -|-----------------|------|---------------------------------------| -| Already in mempool (dedup) | 964 | Not called (acceptable — duplicates are not malicious) | -| Expired (`expiration < now`) | 967 | ❌ Not called | -| Expiration headroom exceeded | 972 | ✅ Called | -| Size exceeded | 979 | ✅ Called | -| TaPoS invalid (wrong fork) | 984 | ❌ Not called | - -**Impact**: Peers can spam expired or wrong-fork transactions without accumulating strikes. - -**Fix**: Add `record_packet_result(sender, false)` calls at lines 967 and 984 when `from_peer && sender != INVALID_PEER_ID`. - ---- - -### GAP 6: Fork resolution winner always picks first branch (P0 Fork) - -**Plan**: §2.2 — Fork resolution uses `compare_fork_branches()` (database.cpp line 1359-1417) which does vote-weighted comparison with +10% longer-chain bonus. - -**What exists**: `compute_branch_info()` ([dlt_p2p_node.cpp:1172-1181](file:///d:/Work/viz-cpp-node/libraries/network/dlt_p2p_node.cpp#L1172-L1181)) returns `total_vote_weight = 0` and `block_count = 1` for every branch. In `resolve_fork()`, the comparison `info.total_vote_weight > winner.total_vote_weight` always compares 0 > 0, so the **first branch in the `tips` vector always wins**. - -The delegate already provides `compare_fork_branches(a, b)` which returns the correct vote-weighted comparison — but `resolve_fork()` calls `compute_branch_info()` instead. - -**Impact**: Fork resolution is non-functional — it picks the first branch arbitrarily, not the vote-weighted winner. This directly contradicts the plan's fork resolution design. - -**Fix**: Replace `compute_branch_info()` iterations in `resolve_fork()` with calls to `_delegate->compare_fork_branches()`: - -```cpp -void dlt_p2p_node::resolve_fork() { - auto tips = _delegate->get_fork_branch_tips(); - if (tips.size() < 2) { _fork_status = DLT_FORK_STATUS_NORMAL; return; } - - block_id_type winner = tips[0]; - for (size_t i = 1; i < tips.size(); ++i) { - if (_delegate->compare_fork_branches(tips[i], winner) > 0) { - winner = tips[i]; - } - } - // ... hysteresis and switch logic using 'winner' -} -``` - ---- - -## Minor Observations (Non-Blocking) - -| # | Observation | -|---|-------------| -| 1 | `dlt_range_request` / `dlt_range_reply` messages (5102/5103) are implemented but the sync flow uses bulk `get_block_range` directly after hello — the plan's improvement note says "range query step could be skipped". These messages exist but are not on the main code path. | -| 2 | `broadcast_block_post_validation()` sends a `dlt_fork_status_message` with `head_block_num = 0` — the receiver stores this as `peer_head_num = 0`, corrupting peer state tracking. This is a functional bug, not just semantic imprecision. | -| 3 | `dlt_delegate::accept_block()` (p2p_plugin.cpp:139-151) ignores the `sync_mode` parameter — always calls `push_block()` the same way, discards the return value with `return false`. | -| 4 | `dlt_delegate::is_head_on_branch()` (p2p_plugin.cpp:203-206) does a simple equality check against `head_block_id()` — will miss the case where our head IS on the branch but not at its tip. | -| 5 | `resync_from_lib()` in `dlt_delegate` (p2p_plugin.cpp:215-217) is empty — documented as "handled at plugin level", but the plugin-level `resync_from_lib()` (p2p_plugin.cpp:437-441) simply calls `node->resync_from_lib()` which just calls `transition_to_sync()` + re-requests blocks. No actual LIB-level resync logic. | - ---- - -## Severity Summary - -| Priority | Gaps | -|----------|------| -| **P0 (must fix)** | GAP 5 — incomplete spam strikes (plan rates this P0); GAP 6 — Fork resolution non-functional (picks wrong branch) | -| **P1 (should fix)** | GAP 4 — Fork window reset; GAP 1 — missing block ordering validation; GAP 2/3 — missing block validation timeout | -| **P2 (nice to fix)** | Known gaps 1-6 (already documented) | - ---- - -## Fixes Applied - -All gaps and minor observations identified in this review have been fixed in code. Below is a summary of each fix and the files modified. - -### Fix 1: Compile error — `peer_dlt_latest_block` field name mismatch (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`peer_dlt_latest_block` referenced a non-existent field; the actual field is `peer_dlt_latest`. Replaced at two call sites. - -### Fix 2: `head_block_num = 0` corrupts peer state (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`broadcast_block_post_validation()` set `msg.head_block_num = 0` with comment "filled by receiver from block_id". But the receiver stores it as `peer_head_num = 0`, corrupting peer state. Fixed by extracting the block number from the `block_id` using `block_header::num_from_id(block_id)`. - -### Fix 3: Fork resolution always picks first branch (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`compute_branch_info()` returned `total_vote_weight = 0` for every branch, so `0 > 0` was always false and the first branch always won. Replaced the `compute_branch_info()` loop in `resolve_fork()` with `_delegate->compare_fork_branches()` which correctly performs vote-weighted comparison with +10% longer-chain bonus. - -### Fix 4: `expected_next_block` tracking never used (P1) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -The field existed but was never set or validated. Added ordering validation in `on_dlt_block_range_reply()` and `on_dlt_block_reply()`: before `accept_block()`, check `state.expected_next_block != 0 && block.block_num() != state.expected_next_block` — reject out-of-order blocks with `record_packet_result(peer, false)`. After successful accept, set `state.expected_next_block = block.block_num() + 1`. Reset to 0 on disconnect in `handle_disconnect()`. - -### Fix 5: `pending_block_batch` timeout + `block_validation_timeout()` (P1) - -**Files**: `libraries/network/include/graphene/network/dlt_p2p_node.hpp`, `libraries/network/dlt_p2p_node.cpp` - -`pending_block_batch_time` and `has_pending_batch_timeout()` were declared but never used. Added: (1) set `pending_block_batch_time = fc::time_point::now()` before block processing loop in `on_dlt_block_range_reply()`, clear it after; (2) declared `block_validation_timeout()` in the header; (3) implemented it — iterates all peer states, soft-bans peers whose batch timeout exceeded 30s; (4) wired into `periodic_task()` after `sync_stagnation_check()`. - -### Fix 6: Fork window reset on non-confirmation (P1) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`track_fork_state()` set `_fork_detected = false` after every `resolve_fork()` call, including when hysteresis was not met — causing a fresh 42-block countdown instead of continuous retry. Moved `_fork_detected = false` into `resolve_fork()` at the two points where resolution actually completes: (1) when `tips.size() < 2` (fork is over), (2) after hysteresis is confirmed and fork switch is executed. NOT set at the early return where hysteresis is not confirmed. - -### Fix 7: `switch_to_fork()` only pops one block (P1) - -**File**: `plugins/p2p/p2p_plugin.cpp` - -Original implementation called `pop_block()` once but never re-pushed fork blocks. Replaced with `chain.db().push_block(*block)` where `block` is fetched from `fork_db`. The chain's `push_block()` already contains the full fork-switch implementation: pop-until-common-ancestor, re-apply new branch, LIB guard, DLT crash prevention. - -### Fix 8: `is_head_on_branch()` too simplistic (P1) - -**File**: `plugins/p2p/p2p_plugin.cpp` - -Original did `tip == head_block_id()` — missed the case where our head IS on the branch but not at its tip. Replaced with `fork_db.fetch_branch_from(tip, head_block_id())` to check if our head is an ancestor of the tip. Returns true if the "old" branch is non-empty (shared ancestry). - -### Fix 9: Spam strikes not incremented for expired/TaPoS-invalid rejections (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -In `add_to_mempool()`, expired transactions (line 967) and TaPoS-invalid transactions (line 984) returned false without calling `record_packet_result(sender, false)`. Added the call (guarded by `from_peer && sender != INVALID_PEER_ID`) at both locations so peers accumulate strikes for these rejections. - -### Fix 10: `periodic_dlt_prune_check()` is a no-op (P2) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -Implemented the body: checks if DLT block log range exceeds `_dlt_block_log_max_blocks`, batches pruning in increments of `DLT_PRUNE_BATCH_SIZE` (10000), logs the intent. The actual pruning requires a delegate method `prune_dlt_block_log()` not yet added to the chain — marked with TODO. - -### Fix 11: `has_emergency_private_key()` returns false (P2) - -**Files**: `plugins/p2p/p2p_plugin.cpp`, `plugins/validator/include/graphene/plugins/validator/validator.hpp`, `plugins/validator/validator.cpp` - -Cross-plugin fix. (1) Added `is_emergency_key_configured()` declaration to `witness_plugin` public API — returns true if `CHAIN_EMERGENCY_WITNESS_ACCOUNT` is in `_witnesses` set (which only happens when `--emergency-private-key` is configured). (2) Implemented in validator.cpp with try/catch guard. (3) Updated `has_emergency_private_key()` in `dlt_delegate` to call `appbase::app().find_plugin()->is_emergency_key_configured()` instead of returning `false`. Added include for `witness_plugin.hpp`. - -### Fix 12: `accept_block()` ignores `sync_mode` parameter (P2) - -**File**: `plugins/p2p/p2p_plugin.cpp` - -Original always called `push_block(block)` regardless of `sync_mode`. Fixed to pass `skip` flags: in sync mode, sets `skip = skip_witness_signature | skip_transaction_signatures` for faster bulk sync. In normal mode, uses `skip_nothing`. This is safe because only fork-aligned peers exchange blocks. - -### Fix 13: `resync_from_lib()` is shallow (P2) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -Original just called `transition_to_sync()` and re-requested blocks. Fixed to: (1) reset all fork tracking state (`_fork_detected = false`, `_fork_detection_block_num = 0`, `_fork_resolution_state = dlt_fork_resolution_state()`, `_fork_status = DLT_FORK_STATUS_NORMAL`); (2) transition to sync; (3) re-send hello messages to all active/syncing peers for updated chain state; (4) then request blocks. The delegate-level `resync_from_lib()` remains empty since the P2P node handles logic internally. - -### Fix 14: Review document corrections - -**File**: `.qoder/docs/dlt-p2p-network-redesign-review.md` - -- **14a**: Corrected factual error in GAP 4 — both the plan's pseudocode and the implementation set `_fork_detected = false` after `resolve_fork()` (previously claimed the plan did not). -- **14b**: Upgraded GAP 5 to P0 in severity summary — the plan rates mempool DoS protection as P0. -- **14c**: Upgraded GAP 6 heading from P1 to P0 — fork resolution is non-functional. -- **14d**: Upgraded minor observation #2 from "semantically imprecise" to functional bug — `head_block_num = 0` corrupts `peer_head_num` in the receiver. - -### Fix 15: Per-IP connection deduplication — broadcast spam prevention (P0) - -**Files**: `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp` - -**Root cause**: When Node A connects outbound to Node B (port 2001) and Node B also connects outbound to Node A (port 2001), both sides also accept the other's inbound connection. Each connection gets a separate `peer_state` entry with a different `peer_id`. The `send_to_all_our_fork_peers()` broadcast function sends to ALL exchange-enabled active entries individually — so one block gets sent N times to the same physical node. With reconnect storms or multiple retries, this accumulates to 4-6 entries per node pair. - -Additionally, `on_dlt_peer_exchange_request()` shared `s.endpoint` for ALL peers including incoming connections with ephemeral ports (e.g., `62.231.188.129:44712`). Other nodes tried connecting to these dead ports, creating ghost entries that multiplied the problem across the network. - -**Fix** (5 changes): -1. Added `find_active_peer_by_ip()` helper — scans `_peer_states` for any CONNECTING/HANDSHAKING/SYNCING/ACTIVE peer with matching IP address. -2. `accept_loop()` — rejects incoming connections from IPs that already have an active peer entry (closes socket, cleans up partial state). -3. `connect_to_peer()` — skips outbound connection if target IP already has an active entry, preventing cross-direction duplication. -4. `send_to_all_our_fork_peers()` — belt-and-suspenders IP dedup: tracks `std::set` of IPs already sent to, skipping duplicates. -5. `on_dlt_peer_exchange_request()` — skips `is_incoming` peers to prevent ephemeral port propagation through the network. diff --git a/.qoder/docs/dlt-p2p-network-redesign.md b/.qoder/docs/dlt-p2p-network-redesign.md deleted file mode 100644 index 5d40fa4da4..0000000000 --- a/.qoder/docs/dlt-p2p-network-redesign.md +++ /dev/null @@ -1,623 +0,0 @@ -# DLT P2P Network Redesign — Implementation Status - -Implementation of the [design plan](../plans/dlt-p2p-network-redesign_91a7ca29.md). - -## Architecture - -In-place replacement of the old Graphene synopsis-based P2P (`node.cpp`, 6978 lines) with a new DLT-specific protocol. Same plugin name, same port, same public API — only the internal implementation changes. - -``` -Before: p2p_plugin → graphene::network::node (node.cpp, STCP, synopsis, inventory gossip) -After: p2p_plugin → dlt_p2p_node (dlt_p2p_node.cpp, raw TCP, DLT hello/range/exchange) -``` - -### Delegate Pattern - -The network library only links `fc` and `graphene_protocol` — NOT `graphene_chain`. So `dlt_p2p_node` cannot directly access the database, `dlt_block_log`, or `fork_db`. The `dlt_p2p_delegate` abstract interface bridges this gap: - -``` -dlt_p2p_node (network lib) ←→ dlt_p2p_delegate (abstract interface) ←→ dlt_delegate (p2p_plugin) -``` - -This matches the old `node_delegate` pattern. - -### Fiber Architecture - -All I/O runs on the p2p thread using fc's cooperative fiber model: - -- **Accept loop fiber**: `_thread->async(accept_loop)` — blocks on `tcp_server::accept()`, yields while waiting -- **Read loop fibers**: one per peer via `_thread->async(read_loop)` — blocks on `tcp_socket::readsome()`, yields while waiting -- **Periodic task fiber**: `_thread->async(periodic_loop)` — sleeps 5s between iterations -- All fibers run cooperatively on the same `fc::thread` — no mutexes needed for shared state -- `close()` cancels all fibers via `fc::future::cancel_and_wait()` - -### Wire Format - -Raw TCP (no STCP encryption). Each message on the wire: - -``` -[4 bytes: data size (uint32_t)] [4 bytes: msg_type (uint32_t)] [size bytes: fc::raw::pack(T)] -``` - -This matches the old `message_oriented_connection` format without 16-byte padding (no encryption layer). The `send_message()` method writes the header and data separately to avoid `fc::raw::pack(message)` which adds a varint length prefix to the data vector. - -## File Map - -### New Files (Created) - -| File | Lines | Purpose | -|------|-------|---------| -| `libraries/network/include/graphene/network/dlt_p2p_messages.hpp` | 319 | All DLT message types (5100-5116), enums, structs, FC_REFLECT macros | -| `libraries/network/dlt_p2p_messages.cpp` | 21 | Static `type` constants for each message struct | -| `libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp` | 123 | `dlt_peer_state`, `dlt_known_peer`, `dlt_mempool_entry`, `dlt_fork_resolution_state`, `dlt_fork_branch_info` | -| `libraries/network/include/graphene/network/dlt_p2p_node.hpp` | 350 | `dlt_p2p_delegate` interface + `dlt_p2p_node` class declaration | -| `libraries/network/dlt_p2p_node.cpp` | 2627 | Full `dlt_p2p_node` implementation | - -### Modified Files - -| File | Change | -|------|--------| -| `libraries/network/CMakeLists.txt` | Removed 6 old source files and 6 old headers; added new DLT files | -| `plugins/p2p/p2p_plugin.cpp` | Replaced `node.cpp`-based impl with `dlt_p2p_node` wrapper + `dlt_delegate` | -| `plugins/p2p/CMakeLists.txt` | Removed `graphene::snapshot` dependency | -| `plugins/p2p/include/.../p2p_plugin.hpp` | **Unchanged** — same public API preserved | - -### Deleted Files (12 total) - -| Type | Files | -|------|-------| -| Source | `node.cpp`, `peer_connection.cpp`, `peer_database.cpp`, `stcp_socket.cpp`, `message_oriented_connection.cpp`, `core_messages.cpp` | -| Headers | `node.hpp`, `peer_connection.hpp`, `peer_database.hpp`, `stcp_socket.hpp`, `message_oriented_connection.hpp`, `core_messages.hpp` | - -### Kept Files (still in network lib) - -| File | Reason | -|------|--------| -| `config.hpp` | Defines `MAX_MESSAGE_SIZE`, `GRAPHENE_NET_MAX_BLOCKS_PER_PEER_DURING_SYNCING` used by DLT code | -| `exceptions.hpp` | Defines `unlinkable_block_exception` etc. used by chain and plugins | -| `message.hpp` | Core `message` / `message_header` structs — wire format foundation | - -## Plan Phase → Implementation Mapping - -### Phase 1: New Message Types ✅ - -`dlt_p2p_messages.hpp` implements all 17 message types (5100-5116) exactly as specified: - -| Message Type | ID | Struct | -|---|---|---| -| `dlt_hello_message_type` | 5100 | `dlt_hello_message` — protocol_version, head/LIB, DLT range, emergency, fork/node status | -| `dlt_hello_reply_message_type` | 5101 | `dlt_hello_reply_message` — exchange_enabled, fork_alignment, recognized blocks | -| `dlt_range_request_message_type` | 5102 | `dlt_range_request_message` | -| `dlt_range_reply_message_type` | 5103 | `dlt_range_reply_message` | -| `dlt_get_block_range_message_type` | 5104 | `dlt_get_block_range_message` — start/end + prev_block_id | -| `dlt_block_range_reply_message_type` | 5105 | `dlt_block_range_reply_message` — blocks vector + is_last | -| `dlt_get_block_message_type` | 5106 | `dlt_get_block_message` | -| `dlt_block_reply_message_type` | 5107 | `dlt_block_reply_message` — block + next_available + is_last | -| `dlt_not_available_message_type` | 5108 | `dlt_not_available_message` | -| `dlt_fork_status_message_type` | 5109 | `dlt_fork_status_message` | -| `dlt_peer_exchange_request_type` | 5110 | `dlt_peer_exchange_request` (empty body) | -| `dlt_peer_exchange_reply_type` | 5111 | `dlt_peer_exchange_reply` — peers vector | -| `dlt_peer_exchange_rate_limited_type` | 5112 | `dlt_peer_exchange_rate_limited` — wait_seconds | -| `dlt_transaction_message_type` | 5113 | `dlt_transaction_message` — signed_transaction | -| `dlt_soft_ban_message_type` | 5114 | `dlt_soft_ban_message` — ban_duration_sec, reason (sent before disconnecting a banned peer) | -| `dlt_gap_fill_request_type` | 5115 | `dlt_gap_fill_request` — block_nums (gap fill in both SYNC and FORWARD modes) | -| `dlt_gap_fill_reply_type` | 5116 | `dlt_gap_fill_reply` — blocks (gap fill in both SYNC and FORWARD modes) | - -Enums: `dlt_node_status` (SYNC/FORWARD), `dlt_fork_status` (NORMAL/LOOKING_RESOLUTION/MINORITY), `dlt_peer_lifecycle_state` (6 states). - -All FC_REFLECT macros defined for serialization. - -### Phase 2: DLT P2P Node ✅ - -`dlt_p2p_node.hpp` + `dlt_p2p_node.cpp` implement the full node: - -**Connection management**: -- `find_active_peer_by_ip()` — per-IP dedup helper: returns peer_id of any existing active connection from the same IP address, or INVALID_PEER_ID if none -- `connect_to_peer()` — per-IP dedup check before connecting (skips if same IP already has active connection), then synchronous connect on p2p thread, sends hello, starts read loop -- `accept_loop()` — fiber that accepts incoming connections, **per-IP dedup check rejects duplicate connections from same IP** (prevents broadcast amplification), creates peer state, sends hello, starts read loop -- `start_read_loop()` — per-peer fiber that reads message_header + data, dispatches to `on_message()` -- `handle_disconnect()` — cancels read fiber, closes socket, calculates backoff with jitter -- Periodic reconnect/backoff/expire logic - -**Hello handshake**: -- `build_hello_message()` — queries delegate for all chain state -- `build_hello_reply()` — checks fork alignment via `delegate->is_block_known()` -- `on_dlt_hello()` — stores peer chain state, sends reply, transitions lifecycle, starts sync if SYNC mode -- `on_dlt_hello_reply()` — processes exchange_enabled/fork_alignment, starts block fetch - -**Block sync (SYNC mode)**: -- `request_blocks_from_peer()` — requests up to 200 blocks after our head -- `on_dlt_get_block_range()` — reads blocks from dlt_block_log via delegate, sends reply -- `on_dlt_block_range_reply()` — validates prev_hash, applies blocks, transitions to FORWARD when `is_last` -- `on_dlt_get_block()` / `on_dlt_block_reply()` — single-block fetch variant -- `sync_stagnation_check()` — 30s no-block timeout, 3 retries, then FORWARD with warning -- `check_sync_catchup()` — compares our head against all peers' heads, transitions to FORWARD if caught up (P26 fix). Guards against isolation with 60s emergency reset (P53 fix). -- `emergency_peer_reset()` — clears soft bans and resets backoffs when all peers are isolated for 60s (P53 fix) -- `transition_to_forward()` — revalidates provisional mempool entries, re-evaluates `exchange_enabled` for all peers (P25 fix) - -**Mempool** (separate from chain's `_pending_tx`): -- `add_to_mempool()` — dedup by tx_id, check expiry/size/TaPoS, enforce limits with oldest-expiry eviction, retranslate to our-fork peers -- `remove_transactions_in_block()` — prune on block receipt -- `prune_mempool_on_fork_switch()` — remove TaPoS-invalid entries on fork -- `periodic_mempool_cleanup()` — prune expired + TaPoS-invalid entries -- Provisional entries tagged during SYNC, revalidated on transition to FORWARD - -**Fork resolution**: -- `track_fork_state()` — 42-block threshold (2 full rounds), triggers `resolve_fork()` -- `resolve_fork()` — finds heaviest branch, hysteresis with 6-block confirmation -- `dlt_fork_resolution_state` — tracks `current_winner_tip` and `consecutive_blocks_as_winner` - -**Anti-spam**: -- `record_packet_result()` — single `spam_strikes` counter per peer, reset on good packet, soft-ban at threshold=10 -- `soft_ban_peer()` — sets BANNED state for 3600s, sends `dlt_soft_ban_message` notification, then closes connection -- **Per-IP connection dedup** (sender-side broadcast spam prevention): - - `find_active_peer_by_ip()` — scans `_peer_states` for any CONNECTING/HANDSHAKING/SYNCING/ACTIVE peer with matching IP address - - `accept_loop()` — rejects incoming connections from IPs that already have an active peer entry, preventing N connections from the same node via different ephemeral ports - - `connect_to_peer()` — skips outbound connection if target IP already has an active entry, preventing cross-direction duplication (inbound + outbound to same node) - - `send_to_all_our_fork_peers()` — belt-and-suspenders IP dedup in broadcast: tracks `std::set` of IPs already sent to, skipping duplicates - -**Peer exchange** (rate-limited): -- `on_dlt_peer_exchange_request()` — sliding window rate limit (3 requests per 5 min per peer), subnet diversity filter, min uptime 600s, **skips `is_incoming` peers to prevent ephemeral port propagation** -- `on_dlt_peer_exchange_reply()` — adds to known peers, connects if under max_connections -- Subnet diversity via `/24` prefix comparison - -**Peer lifecycle** (connecting→handshaking→syncing→active→disconnected→banned): -- Timeouts: connecting=5s, handshaking=10s -- Reconnection: backoff 30s→60s→…→3600s with ±25% jitter, reset on stable >5min -- Permanent removal after 8h non-response - -**Color-coded logging**: GREEN=sync/production, WHITE=normal block exchange, RED=fork, DARK_GRAY=transactions, ORANGE=warnings, CYAN=peer stats - -### Phase 3: P2P Plugin Replacement ✅ - -`p2p_plugin.cpp` rewritten from 1951 lines (node.cpp-based) to 487 lines (dlt_p2p_node wrapper): - -**`dlt_delegate` class** (implements `dlt_p2p_delegate`): -- Bridges chain state queries using `chain.db()` with appropriate read locks -- `read_block_by_num()` — checks dlt_block_log first, then fork_db -- `accept_block()` — calls `push_block()`, catches `unlinkable_block_exception` → stores in fork_db; 60s startup grace period for near-head blocks (P22 fix) -- `get_fork_branch_tips()` — fetches from fork_db at head_num through head_num+5 -- `is_tapos_block_known()` — delegates to `chain.db().is_known_block()` - -**Config options** (new DLT-specific): -| Option | Default | Purpose | -|--------|---------|---------| -| `dlt-block-log-max-blocks` | 100000 | Max blocks in DLT block log | -| `dlt-peer-max-disconnect-hours` | 8 | Remove peer after this many hours non-response | -| `dlt-mempool-max-tx` | 10000 | Hard cap on mempool entries | -| `dlt-mempool-max-bytes` | 104857600 (100MB) | Hard cap on total mempool memory | -| `dlt-mempool-max-tx-size` | 65536 (64KB) | Reject oversized transactions | -| `dlt-mempool-max-expiration-hours` | 24 | Reject far-future expiration | -| `dlt-peer-exchange-max-per-reply` | 10 | Cap peers per exchange reply | -| `dlt-peer-exchange-max-per-subnet` | 2 | Anti-sybil: max 2 per /24 | -| `dlt-peer-exchange-min-uptime-sec` | 600 | Min uptime before sharing | -| `dlt-stats-interval-sec` | 300 (5 min) | Interval between P2P peer stats log output (min 30) | - -**Removed old config**: `p2p-stats-enabled`, `p2p-stats-interval`, `p2p-stale-sync-detection`, `p2p-stale-sync-timeout-seconds` (replaced by `dlt-stats-interval-sec` and P2P-level stale sync detection) - -**Plugin startup** (deadlock fix): -- Old: `p2p_thread.async([...infinite loop...]).wait()` — blocks forever -- New: `p2p_thread.async([create node, set_thread, configure, start]).wait()` — returns after setup -- `dlt_p2p_node::start()` internally spawns accept loop + periodic task as fibers -- Thread reference passed via `node->set_thread(fc::thread::current())` - -**Soft-ban notification**: -- `soft_ban_peer()` sends `dlt_soft_ban_message` (type 5114) before closing the connection -- Receiving peer enters BANNED state with the specified duration and logs an orange/yellow notice -- Prevents wasted bandwidth — both sides stop sending data immediately - -**Peer stats**: -- `log_peer_stats()` outputs cyan-colored peer statistics at configurable interval -- Shows: node status, fork state, head/LIB, per-peer details (flags, ranges, spam strikes, ban time) -- Interval configured via `dlt-stats-interval-sec` (default 300s = 5 min) - -**Out-of-order/duplicate block handling**: -- Duplicate blocks (already applied) from peers are silently skipped, not counted as spam -- Out-of-order blocks in range replies fall through to fork_db/push_block instead of soft-banning -- Deserialization errors no longer increment spam strikes -- Oversized messages from old-protocol peers disconnect with `skip_backoff_increase=true` - -### Phase 4: Fork Resolution ✅ - -Implemented in `dlt_p2p_node.cpp`: -- `FORK_RESOLUTION_BLOCK_THRESHOLD = 42` (matches `CHAIN_MAX_WITNESSES * 2`) -- `dlt_fork_resolution_state::CONFIRMATION_BLOCKS = 6` (hysteresis) -- `track_fork_state()` called after each block application -- `resolve_fork()` with vote-weight winner + consecutive-block confirmation -- `_fork_status` exposed via `is_on_majority_fork()` for Validator Plugin - -### Phase 5: In-Place Replacement ✅ - -- Same plugin name `"p2p"`, same `p2p-endpoint` port (2001/4243) -- Same public API — zero changes to validator, witness_guard, snapshot plugins -- Old `node.cpp` and all related files removed from build and deleted from disk -- `p2p_plugin.hpp` completely unchanged - -## Key Design Decisions - -| Decision | Rationale | -|----------|-----------| -| Delegate pattern instead of direct chain access | Network lib only links `fc` + `graphene_protocol`, not `graphene_chain`. Delegate avoids circular dependency. | -| Raw TCP instead of STCP encryption | DLT emergency mode means all validators switch simultaneously — no need for backward-compatible encryption. Simpler wire protocol. | -| fc::thread fibers instead of per-peer threads | All I/O uses fc's cooperative fiber model. `readsome()`/`writesome()` yield the fiber, allowing multiple peers on one thread without mutexes. | -| Manual header+data writes instead of `fc::raw::pack(msg)` | `fc::raw::pack(message)` adds varint length prefix to the data vector, creating mismatched wire format. Writing header and data separately matches the read side. | -| Single `spam_strikes` counter | Simpler and more effective than old multi-counter system (`unlinkable_block_strikes`, `sync_spam_strikes`, etc.). Reset-on-good naturally recovers from transient issues. | -| Separate P2P mempool | Chain's `_pending_tx` only applies after acceptance. P2P mempool provides earlier filtering (expiry, TaPoS, size limits) before pushing to chain. | -| In-place replacement, no dual-mode | Old and new protocols are incompatible. Dual-mode creates isolated sub-networks. Emergency mode means all validators can switch simultaneously. | - -## Subsequent Enhancements & Fixes (2026-05-05) - -### DLT-Range-Aware Fork Alignment (P1-P16 fixes) - -The original `check_fork_alignment` only called `is_block_known()` on peer head/LIB IDs. In DLT mode, old blocks are pruned from the rolling block log, so peers on the same chain were falsely flagged as "different fork" and disconnected. - -**Fix:** `check_fork_alignment` now accepts the full `dlt_hello_message` and performs multi-tier alignment: - -| Check | Condition | Result | -|-------|-----------|--------| -| Empty peer | `head_block_num == 0` | Aligned (new node, no fork to be on) | -| Range overlap | `head_num >= our_earliest && head_num <= our_latest` | Uses `is_block_known(head_id)` | -| Boundary link | `head_num + 1 == our_earliest` | Reads `our_earliest_block`, checks `previous == head_id` | -| LIB fallback | Always | `is_block_known(lib_id)` as before | - -**Peer lifecycle fix:** `on_dlt_hello()` now transitions SYNC peers to ACTIVE regardless of `exchange_enabled`: -```cpp -// OLD: if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC) -// NEW: -if (reply.exchange_enabled || _node_status == DLT_NODE_STATUS_SYNC - || hello.node_status == DLT_NODE_STATUS_SYNC) -``` - -This eliminates the HANDSHAKING timeout → disconnect → reconnect loop for same-chain peers whose blocks were pruned. - -Full details in [DLT 4-Node Sync Scenarios](./dlt-4-node-sync-scenarios.md). - -### Soft-Ban Notification (type 5114) - -`dlt_soft_ban_message` is sent before disconnecting a banned peer: -- Contains `ban_duration_sec` and human-readable `reason` -- Receiving peer enters BANNED state with the specified duration -- Logged as orange/yellow notice on both sides -- Prevents wasted bandwidth — both sides stop sending immediately - -### Peer Stats Logging - -`log_peer_stats()` outputs cyan-colored peer statistics at configurable interval (`dlt-stats-interval-sec`, default 300s). Shows node status, fork state, head/LIB, per-peer details (flags, ranges, spam strikes, ban time). - -### Out-of-Order / Duplicate Block Tolerance - -- Duplicate blocks (already applied) from peers are silently skipped, not counted as spam -- Out-of-order blocks in range replies fall through to fork_db instead of soft-banning -- Deserialization errors no longer increment spam strikes -- Oversized messages from old-protocol peers disconnect with `skip_backoff_increase=true` - -### Block Processing Pause/Resume - -`pause_block_processing()` / `resume_block_processing()` with `_block_processing_paused` flag allows the snapshot or other plugins to temporarily halt P2P block intake during critical operations. - -### Additional Public API - -| Method | Purpose | -|--------|---------| -| `broadcast_block_post_validation()` | Broadcast block by ID+validator+signature after validation | -| `broadcast_chain_status()` | Send hello to all connected peers | -| `trigger_resync()` | Force re-enter SYNC mode and re-request blocks | -| `reconnect_seeds()` | Re-connect to all seed nodes | -| `pause_block_processing()` / `resume_block_processing()` | Temporarily halt P2P block intake | -| `set_stats_log_interval()` | Configure periodic peer stats output interval | - -### C++14 constexpr ODR-use Fix - -`static constexpr` members that are ODR-used (e.g., `MAX_RECONNECT_BACKOFF_SEC`) now have out-of-line definitions in `dlt_p2p_node.cpp`: -```cpp -constexpr uint32_t dlt_peer_state::PEER_EXCHANGE_MAX_REQUESTS; -constexpr uint32_t dlt_peer_state::PEER_EXCHANGE_WINDOW_SEC; -constexpr uint32_t dlt_peer_state::PENDING_BATCH_TIMEOUT_SEC; -constexpr uint32_t dlt_peer_state::INITIAL_RECONNECT_BACKOFF_SEC; -constexpr uint32_t dlt_peer_state::MAX_RECONNECT_BACKOFF_SEC; -``` - -### `dlt_block_accept_result` Enum - -New enum replaces the old `bool` return from `accept_block()`: -```cpp -enum class dlt_block_accept_result { - ACCEPTED, // pushed to chain (became head or fork_db head) - FORK_DB_ONLY, // stored in fork_db but not applied (unlinkable / competing fork) - DEAD_FORK, // block from a dead fork (parent not in fork_db, at/below head) - REJECTED // failed validation entirely -}; -``` - ---- - -## Subsequent Enhancements & Fixes (2026-05-06) - -### Dead Fork Block Crash Protection (P20/P21) - -Added `DEAD_FORK` to `dlt_block_accept_result` enum. When `push_block()` throws `unlinkable_block_exception` and the block is at/below our head (`block.block_num() <= head_block_num()`), the delegate returns `DEAD_FORK` instead of pushing to `fork_db._unlinked_index`. The P2P layer soft-bans peers sending dead-fork blocks and breaks out of the block processing loop. `transition_to_forward()` is now guarded by `any_block_applied` — a range full of dead-fork rejects does NOT end sync mode. - -**Files:** `dlt_p2p_node.hpp`, `p2p_plugin.cpp`, `dlt_p2p_node.cpp` - -### DLT Block Log Corruption Recovery (P17) - -New `dlt_block_log::is_consistent_with(db_head_block_num)` method detects corruption on startup: single-block log with thousands in DB, DLT head exceeding DB head, or far-behind with few blocks. In `database::open()`, corrupted DLT block logs are auto-reset before fork_db seeding. P2P sync rebuilds the log naturally after reset. - -**Files:** `dlt_block_log.hpp`, `dlt_block_log.cpp`, `database.cpp` - -### Snapshot Lock Isolation Prevention (P24) - -When `_block_processing_paused` is true (snapshot in progress), `periodic_task()` skips operations that need database read locks: `sync_stagnation_check()`, `periodic_peer_exchange()`, `log_peer_stats()`. Non-DB housekeeping (reconnect, lifecycle, validation, mempool cleanup, banned-peer unban) still runs. `check_stalled_sync_loop()` skips stall detection when `snapshot_in_progress` is true and resets the timer. `serialize_state()` now logs progress every 5s during long serialization. - -**Files:** `dlt_p2p_node.cpp`, `snapshot/plugin.cpp` - -### Write Lock Diagnostic Logging (P27) - -`notify_applied_block()` now times the overall signal notification and logs a warning if it exceeds 200ms (with block number, duration, and connected plugin count). Self-timing added to the 3 most likely slow handlers: `mongo_db::on_block()`, `operation_history::purge_old_history()`, `account_history::purge_old_history()` — each logs if >100ms. The chainbase `with_strong_write_lock` macro already captures `__FILE__`/`__LINE__`/`__func__` so lock timeout messages identify the call site. - -**Files:** `database.cpp`, `mongo_db_plugin.cpp`, `operation_history/plugin.cpp`, `account_history/plugin.cpp` - ---- - -## Known Limitations / Future Work - -- `has_emergency_private_key()` **now queries Validator Plugin** (was hardcoded `false`) -- `switch_to_fork()` **now has full implementation** with fork_db fetch + `push_block()` -- `resync_from_lib()` is handled at plugin level (by design — delegate returns early) -- `compute_branch_info()` returns simplified info — detailed vote-weight computation needs fork_db traversal -- `dlt_block_log` batch pruning (10000 at a time) not yet connected — `periodic_dlt_prune_check()` is a no-op -- No unit tests yet for the new message types or node logic -- `dlt_delegate::is_tapos_block_known()` uses `find_block_id_for_num()` — may need chain index access - ---- - -## Build Issues (GCC 13 / Docker) - -The following compilation/linking issues block building with newer GCC (13+) in Docker: - -| # | Issue | File | Fix | -|---|-------|------|-----| -| P28 | `multimap::erase` with `std::pair` — C++17 removed value-erase overload | `dlt_p2p_node.cpp` | Use iterator-erase: `_mempool_by_expiry.erase(it_by_expiry)` | -| P28b | `ip::address::data()` doesn't exist in fc | `dlt_p2p_node.cpp` | Use `fc::raw::pack()` | -| P29 | Missing `witness_plugin.hpp` — actual file is `validator.hpp` | `p2p_plugin.cpp` | Fix include path | -| P30 | 6+ API mismatches in `p2p_plugin.cpp` (see below) | `p2p_plugin.cpp` | Update delegate calls | -| P31 | Linker error: `static constexpr` ODR-use | `dlt_p2p_peer_state.hpp` | **Fixed** — out-of-line definitions added | - -**P30 API mismatch details:** -| Error | Fix Needed | -|-------|------------| -| `with_read_lock([&]{...})` — expects 6 args, 1 provided | Add `lock_type, timeout_ms, file, line, func` params | -| `is_emergency_consensus` is not a member | Field renamed; find new name in `dynamic_global_property_object` | -| `blocks.front()->id()` — `id` is field, not method | Change to `blocks.front()->id` | -| `catch (const unlinkable_block_exception&)` — missing var name | Add variable: `catch (const unlinkable_block_exception& e)` | -| `accept_transaction` doesn't exist | Renamed to `apply_transaction` or similar | -| `push_block(*block)` with `fork_item` — not `signed_block` | Use `fork_item->data` | -| `is_known_block(ref_block_num)` with `uint32_t` — expects `block_id_type` | Fetch block ID by number first | - ---- - -## Known Runtime Issues - -Post-implementation issues observed in production (4-node DLT emergency consensus network): - -| # | Severity | Problem | -|---|----------|--------| -| P17 | ~~CRITICAL~~ **Fixed** | DLT block log corruption on crash → auto-detected and reset | -| P18 | ~~CRITICAL~~ **Fixed** | Master stops producing blocks for minutes (`slot=0` loop) → stall detector + NTP force-sync | -| P19 | ~~HIGH~~ **Fixed** | Slave stuck in SYNC → gap detection + multi-peer fallback + snapshot warning | -| P20 | ~~CRITICAL~~ **Fixed** | Dead fork blocks → DEAD_FORK result, soft-ban, no crash | -| P21 | ~~CRITICAL~~ **Fixed** | Dead fork crash loop → blocks rejected, fork_db protected | -| P22 | ~~HIGH~~ **Fixed** | fork_db rejection cascade on restart → seed 100 blocks + 60s grace period | -| P23 | ~~HIGH~~ **Fixed** | `fetch_branch_from` assertion failure → graceful empty-branch return | -| P24 | ~~CRITICAL~~ **Fixed** | Snapshot lock isolation → periodic tasks skip DB, stall check aware | -| P25 | ~~HIGH~~ **Fixed** | Slave-produced block ignored → exchange_enabled re-evaluated on block accept + FORWARD transition | -| P26 | ~~MED~~ **Fixed** | Sync state confusion → `check_sync_catchup()` on block accept + periodic task | -| P27 | ~~CRITICAL~~ **Fixed** (diag) | Write lock diagnostic — overall + per-plugin timing, lock-holder ID | -| P36 | ~~HIGH~~ **Fixed** | `block_too_old_exception` during SYNC range processing + FORWARD mode gap fill | -| P37 | ~~HIGH~~ **Fixed** | Gap fill never triggers: stale peer_head_num + no FORWARD stagnation detection | -| P39 | ~~CRITICAL~~ **Fixed** | `_push_next` cascade blocks not applied to database + gap fill requires exchange peers | -| P40 | ~~HIGH~~ **Fixed** | FORWARD transition not announced to peers + exchange status not visible in stats | -| P41 | ~~HIGH~~ **Fixed** | Stale peer state on reconnect: exchange_enabled, spam_strikes, peer_head_num leak from old session | -| P53 | ~~HIGH~~ **Fixed** | Peer isolation oscillation: emergency_peer_reset() clears bans/backoffs after 60s isolation | -| P54 | ~~HIGH~~ **Fixed** | Gap fill disabled in SYNC mode + large gaps silently ignored: mode-agnostic gap fill + chunked requests | - -Full analysis in [DLT 4-Node Sync Scenarios](./dlt-4-node-sync-scenarios.md#new-problems-discovered-post-implementation). - ---- - -## Subsequent Enhancements & Fixes (2026-05-07) - -### P23: fetch_branch_from Assertion Safety - -**Files:** `libraries/chain/fork_database.cpp` - -**Root cause:** `fetch_branch_from()` had 6 `FC_ASSERT` calls that crashed the node when block IDs weren't in the fork_db index. In production, peers on different forks triggered these assertions, crashing the node. - -**Fix:** Replaced all `FC_ASSERT` calls with graceful early returns (empty branches + `wlog`). Callers already handle empty branches (e.g., `is_head_on_branch()` catches exceptions, `compare_fork_branches()` has try-catch with fork_db reset). - -### P26: SYNC→FORWARD Transition Fix - -**Files:** `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp` - -**Root cause:** `transition_to_forward()` was only called in `on_dlt_block_range_reply()` and `sync_stagnation_check()`. If a slave caught up via individual block replies, the transition never triggered. - -**Fix:** Added `check_sync_catchup()` that compares `our_head` against all active peers' `peer_head_num`. Called from `on_dlt_block_reply()` after accepting a block, and from `periodic_task()`. - -### P25: exchange_enabled Re-evaluation - -**Files:** `libraries/network/dlt_p2p_node.cpp` - -**Root cause:** `exchange_enabled` was set once during hello handshake and never updated. Slaves that caught up still had `exchange_enabled=false` on the master side, so their block broadcasts were ignored. - -**Fix:** Three re-evaluation triggers: (1) in `transition_to_forward()` re-check `is_block_known(peer_head_id)`, (2) in `on_dlt_block_range_reply()` enable exchange when a non-exchange-enabled peer's block is ACCEPTED, (3) same in `on_dlt_block_reply()`. - -### P22: fork_db Restart Recovery - -**Files:** `libraries/chain/database.cpp`, `plugins/p2p/p2p_plugin.cpp` - -**Root cause:** After restart, fork_db was seeded with only the head block. Peers sending sync blocks near the head were rejected as "dead fork" because their parent chain wasn't in fork_db. - -**Fix:** (1) Seed the last 100 blocks from block_log/dlt_block_log into fork_db on startup. (2) Dead-fork grace period: for the first 60s after startup, blocks within 10 of the head are treated as `FORK_DB_ONLY` instead of `DEAD_FORK`. - -### P18: slot=0 Production Stall Detector - -**Files:** `plugins/validator/validator.cpp` - -**Root cause:** `get_slot_at_time()` returns 0 when NTP time is behind `head_block_time()`. After crash/restart with NTP desync, the master could loop on `not_time_yet` for minutes. - -**Fix:** Added `_slot_zero_streak` counter: at streak=10 (~3s) logs warning + forces NTP resync; at streak=120 (~30s) logs CRITICAL error. Counter resets on any non-stall result. - -### P19: Sync Gap Detection + Multi-Peer Fallback - -**Files:** `libraries/network/dlt_p2p_node.cpp` - -**Root cause:** When `our_head + 1 < peer_dlt_earliest` (gap between our head and what the peer can serve), blocks were clamped but didn't link to our head. No attempt was made to find a peer with the missing blocks. - -**Fix:** When a gap is detected in `request_blocks_from_peer()`: (1) search other peers for one whose DLT range covers the missing blocks, (2) if found, defer current peer and sync from the bridging peer, (3) if no peer can bridge, log "Snapshot may be required" warning and still attempt the clamped request. - ---- - -## Subsequent Enhancements & Fixes (2026-05-08) - -### P36: block_too_old_exception During SYNC Range Processing + Gap Fill Exchange Packet - -**Files:** `plugins/p2p/p2p_plugin.cpp`, `libraries/network/include/graphene/network/dlt_p2p_messages.hpp`, `libraries/network/dlt_p2p_messages.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp`, `libraries/network/dlt_p2p_node.cpp` - -**Problem B — Root cause:** When processing a block range reply in SYNC mode, the first block can trigger `fork_db._push_next()` which cascades and links previously-deferred blocks from a competing fork. This advances `fork_db._head` far beyond the database head. Subsequent blocks in the range (from a different fork or the same chain) are then rejected with `block_too_old_exception` because they fall outside fork_db's `_max_size=2` sliding window. The exception fell through to the generic `catch (const fc::exception&)` which returned `REJECTED`, causing the P2P layer to skip updating `expected_next_block`. This made every subsequent block in the range appear "out of order", creating an unresolvable gap. - -**Problem B — Fix:** Added `catch (const graphene::chain::block_too_old_exception& e)` in `dlt_delegate::accept_block()` before the generic `fc::exception` catch. Returns `ALREADY_KNOWN` instead of `REJECTED`. This is correct because fork_db already has a better chain at that height (that's why it considers the block "too old"). The `ALREADY_KNOWN` result allows `expected_next_block` to be updated properly, preventing the cascading gap. - -**Gap fill — Root cause:** When transitioning SYNC→FORWARD with a 1-2 block gap, the only recovery mechanism was the FORWARD→SYNC fallbehind detection (threshold=2 blocks), causing oscillation between modes. Broadcast blocks arrive out-of-order and get deferred to fork_db._unlinked_index, but there's no way to proactively request the specific missing blocks. - -**Gap fill — Fix:** Added two new exchange-only message types: - -| Type | ID | Purpose | -|------|----|---------| -| `dlt_gap_fill_request` | 5115 | Request specific block numbers from exchange-enabled peers | -| `dlt_gap_fill_reply` | 5116 | Return requested blocks from dlt_block_log or fork_db | - -Protocol: -- Only exchanged between exchange-enabled peers (`on_dlt_gap_fill_request` rejects non-exchange peers) -- Maximum 100 blocks per request (`GAP_FILL_MAX_BLOCKS`); larger gaps are served in 100-block chunks -- 5-second cooldown between requests (`GAP_FILL_COOLDOWN_SEC`) -- Works in both SYNC and FORWARD modes (not FORWARD-only) -- SYNCING lifecycle peers are also eligible as candidates (not just ACTIVE) -- Requesting peer selects the exchange-enabled peer with the highest head block -- Requested blocks must be within the serving peer's DLT log range - -Gap fill is triggered in three places: -1. `on_dlt_block_reply()` — when an out-of-order block is detected (any mode) -2. `periodic_task()` — proactive gap detection every 5s cycle (any mode) -3. `resume_block_processing()` — after snapshot pause, tries gap fill before falling back to SYNC - -### P37: Gap Fill Never Triggers — Stale peer_head_num + No FORWARD Stagnation Detection - -**Files:** `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp` - -**Root cause (3 bugs):** - -1. **`peer_head_num` never updated from received blocks.** Only set during hello/fork_status exchange. When peers broadcast blocks #79678587+ but their recorded `peer_head_num` stays at #79678585, `request_gap_fill()` sees `max_peer_head <= our_head` and silently returns — the gap grows forever. - -2. **`check_forward_behind()` depends on stale `peer_head_num`.** The fallbehind detection checks `peer_head_num > our_head + FORWARD_FALLBEHIND_THRESHOLD`, which never triggers for the same reason. - -3. **No FORWARD-mode head-progress stagnation detection.** There was no "our head hasn't advanced in N seconds" check — the node stays stuck in FORWARD mode indefinitely. - -**Fix 1 — Update `peer_head_num` from received blocks:** In both `on_dlt_block_reply()` and `on_dlt_block_range_reply()`, when a block with number N is received from a peer, update `state.peer_head_num = max(state.peer_head_num, N)`. A peer that can send us block #N must have applied it, so its head is ≥ N. - -**Fix 2 — Track `_highest_seen_block_num`:** Global high-water mark updated whenever we see any block with a higher number. Used in `request_gap_fill()` as a fallback gap ceiling when no peer reports a higher head: `gap_ceiling = max(max_peer_head, _highest_seen_block_num)`. Also sends gap fill to ANY exchange-enabled peer if none has a higher reported head. - -**Fix 3 — Gap fill timeout:** `_gap_fill_in_progress` now times out after 15s (`GAP_FILL_TIMEOUT_SEC`). Prevents the flag from getting permanently stuck if the target peer disconnects. - -**Fix 4 — FORWARD stagnation detection:** New `check_forward_stagnation()` called from `periodic_task()`. If in FORWARD mode and our head hasn't advanced in 30 seconds (`FORWARD_STAGNATION_SEC`), transitions to SYNC mode and requests blocks from all exchange-enabled peers. This is the safety net when gap fill fails (no peer has the missing blocks). - -### P39: `_push_next` Cascade Blocks Not Applied to Database + Gap Fill Requires Exchange Peers - -**Files:** `libraries/chain/database.cpp`, `plugins/p2p/p2p_plugin.cpp`, `libraries/network/dlt_p2p_node.cpp` - -**Root cause (2 bugs):** - -1. **`_push_block` doesn't apply `_push_next` cascade blocks after linear extension.** When a block that directly extends `head_block_id()` is pushed to fork_db, `_push_next` may link previously-deferred blocks from `_unlinked_index`, advancing `fork_db._head` far beyond the database head. But `_push_block` only applies the original block — the cascaded blocks are never applied to the database. Subsequent blocks in the range reply are rejected as "too old" by fork_db's sliding window (`max_size=2`), the P36 fix returns ALREADY_KNOWN, `expected_next_block` advances past them, and the node thinks it's caught up while the database head is stuck behind. This causes FORWARD\u2192SYNC oscillation. - -2. **Gap fill requires exchange-enabled peers on both sides.** Right after SYNC\u2192FORWARD transition, no peer may have `exchange_enabled=true` yet (the hello exchange may not have re-evaluated fork alignment). The gap fill request fails with "no exchange-enabled peer available", the gap grows, and the node must wait for stagnation detection (30s) before transitioning to SYNC. - -**Fix 1 — Apply cascade blocks in `_push_block`:** After the linear extension block is applied, check if `new_head` (returned by `fork_db.push_block()`) is ahead of the applied block. If so, `fetch_branch_from` to get the cascade blocks and apply them as linear extensions. On failure, reset fork_db to database head to prevent subsequent "too old" rejections. - -**Fix 2 — Gap fill uses any active peer:** `request_gap_fill()` now prefers exchange-enabled peers but falls back to any active peer with a higher head. The serving side (`on_dlt_gap_fill_request`) also accepts requests from any peer (not just exchange-enabled), since gap fill is a lightweight block_log read. - -**Fix 3 — Gap fill failure transitions to SYNC:** When no peer at all is available for gap fill, immediately transition to SYNC mode instead of waiting for stagnation detection. - -**Fix 4 — Belt-and-suspenders in `accept_block`:** When `block_too_old_exception` is caught and the database is behind fork_db._head, reset fork_db to the database head and retry the push. This handles edge cases where the primary cascade fix (Fix 1) doesn't apply (e.g., non-linear cascade). - -### P40: FORWARD Transition Peer Notification + Exchange Status Visibility - -**Files:** `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp` - -**Root cause:** When a node transitions from SYNC→FORWARD, it locally re-evaluates `exchange_enabled` for its peers (P25 fix), but does NOT notify peers. The peer still sees this node as SYNC with `exchange_enabled=false`, and won't send blocks/transactions to it. This delays exchange activation until the next periodic `broadcast_chain_status()` cycle (which only targets exchange-enabled peers — a catch-22). - -**Fix 1 — Notify ALL peers on FORWARD transition:** `transition_to_forward()` now sends a `dlt_fork_status_message` with `node_status=FORWARD` to ALL active/syncing peers, not just exchange-enabled ones. This ensures peers know we're ready for exchange. - -**Fix 2 — Re-evaluate exchange on received FORWARD status:** `on_dlt_fork_status()` now detects SYNC→FORWARD transitions in the peer's status. When a peer transitions to FORWARD, it re-checks `is_block_known(peer_head_id)` and enables exchange if the peer's head is now recognized. - -**Fix 3 — Exchange status in peer stats:** `log_peer_stats()` now shows `exch=YES/no` explicitly in the per-peer stats line, making it easy to see which peers are exchange-enabled at a glance. - -**Fix 4 — Document stale `peer_head_num`:** Added comments in `dlt_peer_state` and `log_peer_stats()` clarifying that `peer_head_num` is a stale snapshot (from hello/fork_status/block relay), NOT real-time. The peer's actual head may be significantly higher. This prevents AI assistants and developers from misinterpreting the stats table as showing real-time peer state. - -### P41: Stale Peer State on Reconnect — exchange_enabled, spam_strikes, peer_head_num Leak - -**Files:** `libraries/network/dlt_p2p_node.cpp` - -**Root cause:** When `connect_to_peer()` reuses a `DISCONNECTED` peer state entry for reconnection, it only overwrites `endpoint`, `lifecycle_state`, and `state_entered_time`. All other fields from the previous session persist: -- `exchange_enabled=true` leaks — combined with the OR in `on_dlt_hello_reply`, this makes exchange appear enabled even if the peer switched forks while disconnected. -- `peer_head_num` / `peer_head_id` are stale — used by `check_forward_behind()`, `check_sync_catchup()`, `request_gap_fill()` with outdated data. -- `spam_strikes` carries over — unfair penalty for the new connection. -- `fork_alignment`, `peer_fork_status`, `peer_node_status`, `expected_next_block` are all stale. - -**Fix — Full state reset on reconnect:** `connect_to_peer()` now saves only cross-session fields (`reconnect_backoff_sec`, `last_connection_duration`, `node_id`) and then resets the entire `dlt_peer_state` via `state = dlt_peer_state()`. All per-session fields start fresh. The hello handshake re-establishes `exchange_enabled`, `peer_head_num`, etc. from scratch. - -### P53: Peer Isolation Oscillation — Emergency Peer Reset - -**Files:** `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp` - -**Root cause:** After a snapshot pause, all peers could be in DISCONNECTED state with high backoffs (up to 3600s). `check_sync_catchup()` treated zero active peers as vacuously "all caught up" → transitioned to FORWARD. Then `check_forward_stagnation()` detected 30s without progress → transitioned to SYNC. Then `check_sync_catchup()` again saw zero peers → FORWARD. This oscillation loop prevented the node from ever reconnecting. - -**Fix 1 — Isolation guard in `check_sync_catchup()`:** When zero active peers exist, the function returns early without claiming caught up. It tracks `_isolation_detected_time` and after 60 seconds (`ISOLATION_RESET_SEC`) calls `emergency_peer_reset()`. - -**Fix 2 — Isolation-aware `check_forward_stagnation()`:** When the head is stuck AND zero active peers exist, the function does NOT transition to SYNC (useless without peers). Instead, it starts the same 60s isolation timer and calls `emergency_peer_reset()` when it expires. - -**Fix 3 - `emergency_peer_reset()` method:** Iterates all `_peer_states`: clears all soft bans (BANNED to DISCONNECTED, resets `spam_strikes`), resets all DISCONNECTED peer backoffs to `INITIAL_RECONNECT_BACKOFF_SEC` with `next_reconnect_attempt = now` (immediate). Also clears `_sync_stagnation_retries` and `_isolation_detected_time`. - -### P54: Gap Fill Disabled in SYNC Mode + Large Gaps Silently Ignored - -**Files:** `libraries/network/dlt_p2p_node.cpp` - -**Root cause (2 bugs):** - -1. **`request_gap_fill()` gated to FORWARD mode only.** The function had `if (_node_status != DLT_NODE_STATUS_FORWARD) return;` at the top, so when a node was stuck in SYNC mode with a growing gap (e.g., head=79737668, network at 79738507, gap=839), gap fill never fired. Blocks arrived via broadcast, were stored in fork_db as unlinkable, and the gap kept growing. - -2. **Gaps > `GAP_FILL_MAX_BLOCKS` (100) silently ignored.** When `gap > 100`, the function returned with no log, no request, and no fallback. Combined with Bug 1, even after a SYNC to FORWARD transition, the gap (still >100) would prevent gap fill from doing anything. - -Additionally, the peer candidate loop only considered `DLT_PEER_LIFECYCLE_ACTIVE` peers, but in SYNC mode the best candidate is typically in `DLT_PEER_LIFECYCLE_SYNCING` state (set by `request_blocks_from_peer`). - -**Fix 1 - Remove FORWARD-only guard:** Gap fill now works in both SYNC and FORWARD modes. In SYNC mode, when `request_blocks_from_peer()` cannot bridge a gap (blocks below the syncing peer's DLT range), gap fill provides an alternative path. - -**Fix 2 - Chunked requests for large gaps:** Instead of silently returning when `gap > GAP_FILL_MAX_BLOCKS`, the function now requests the first 100 blocks. Subsequent chunks are requested on the next periodic call after the current chunk completes or times out. - -**Fix 3 - Include SYNCING peers:** The peer candidate loop now includes `DLT_PEER_LIFECYCLE_SYNCING` peers alongside `DLT_PEER_LIFECYCLE_ACTIVE`. - -**Fix 4 - Mode-agnostic out-of-order trigger:** In `on_dlt_block_reply()`, the gap fill trigger for out-of-order blocks no longer requires FORWARD mode. Any mode with a real gap triggers gap fill. - -### P55: SYNC↔FORWARD Oscillation When No Peer Is Ahead - -**Files:** `libraries/network/dlt_p2p_node.cpp` - -**Root cause (2 bugs):** - -1. **`transition_to_sync()` did not reset `_last_block_received_time`.** When `check_forward_stagnation()` triggered a FORWARD→SYNC transition after 30s without head progress, the sync stagnation timer inherited a stale `_last_block_received_time` (set when the last block was received in FORWARD mode, ~30s ago). On the very next periodic tick (~5s later), `sync_stagnation_check()` saw the timestamp was already 35s old (> `SYNC_STAGNATION_SEC` 30s) and immediately triggered a stagnation retry. - -2. **`check_forward_stagnation()` transitioned to SYNC even when no peer was ahead.** When head was stuck at block N and all connected peers also reported head=N, transitioning to SYNC mode was pointless — there was nothing to sync. `check_sync_catchup()` would immediately detect `our_head >= all peers` on the next tick and transition back to FORWARD, completing the oscillation loop in a single tick cycle. - -**Observed behavior:** Node at block #79740459 with 5 active peers all at #79740459. At 444006ms, `check_forward_stagnation` transitions to SYNC. At 449006ms (next tick), `sync_stagnation_check` fires retry 1/3 and `check_sync_catchup` transitions back to FORWARD. No actual sync attempt occurs. - -**Fix 1 — Reset stagnation timer on SYNC entry:** `transition_to_sync()` now sets `_last_block_received_time = fc::time_point::now()`. This gives the sync phase a full 30s window to receive blocks before stagnation detection kicks in. - -**Fix 2 — Peer-ahead guard in `check_forward_stagnation()`:** Before transitioning to SYNC, the function now checks whether at least one active/SYNCING peer has `peer_head_num > our_head`. If no peer is ahead, SYNC mode cannot help, so the function logs the situation and resets the stagnation timer (`_last_forward_head_num` and `_last_forward_progress_time`) instead of oscillating. diff --git a/.qoder/docs/dlt-p2p-stats-reference-ru.md b/.qoder/docs/dlt-p2p-stats-reference-ru.md deleted file mode 100644 index da2b18d5b3..0000000000 --- a/.qoder/docs/dlt-p2p-stats-reference-ru.md +++ /dev/null @@ -1,375 +0,0 @@ -# Справочник по статистике DLT P2P - -Этот документ объясняет вывод статистики DLT P2P — что означает каждое поле, почему оно имеет текущее значение и какие действия (если нужны) должен предпринять оператор. - -`dlt_p2p_node` выводит **две различных строки** в лог периодически: - -| Префикс лога | Частота | Назначение | -|---|---|---| -| `DLT Status \|` | Каждые ~30с | Компактная строка для оперативного мониторинга | -| `=== DLT P2P Stats \|` | Каждые ~120с | Детальная статистика с данными по каждому пиру | - ---- - -## DLT Status Log (компактная строка) - -``` -DLT Status | FORWARD | head=#79881136 lib=#79881130 | dlt_range=79000000-79881136 | peers=6active/8conn | uptime=2h15m43s | flags=... -``` - -Выводится каждые ~30 секунд. Предназначена для мониторинга через `tail`/`grep` без лишнего шума. - -### Поля - -| Поле | Пример | Описание | -|---|---|---| -| Режим | `FORWARD` | Режим работы ноды (`SYNC` или `FORWARD`) | -| `head=#N` | `head=#79881136` | Номер текущего head-блока | -| `lib=#N` | `lib=#79881130` | Номер последнего необратимого блока | -| `dlt_range=A-B` | `dlt_range=79000000-79881136` | Диапазон блоков в DLT block log | -| `peers=Xactive/Yconn` | `peers=6active/8conn` | Активных (обменивающихся) / всего подключённых пиров | -| `uptime=XhYmZs` | `uptime=2h15m43s` | Время с момента запуска ноды | -| `flags=...` | Различные | Активные флаги состояния (snapshot, pause, catchup и т.д.) | - -**`uptime`** вычисляется как `(now - _node_start_time)`, где `_node_start_time` фиксируется в конструкторе `dlt_p2p_node`. Используйте это поле для корреляции событий в логе с возрастом ноды — особенно полезно при диагностике проблем с продакшеном: началась ли проблема сразу после запуска или через некоторое время работы. - ---- - -## Сводка на уровне ноды (заголовочная строка) - -``` -=== DLT P2P Stats | status=FWD fork=NORMAL head=79881136 lib=79881130 peers=6 conn=4 paused=no uptime=0h20m30s === -``` - -### `status` — Режим работы ноды - -| Значение | Описание | -|----------|----------| -| `SYNC` | Нода синхронизируется — загружает и применяет блоки от пиров. Транзакции в этом режиме не транслируются. | -| `FWD` | Нода синхронизирована и работает в режиме forward — производит/ретранслирует блоки и транзакции в реальном времени. | - -**Почему может быть `SYNC`:** -- Нода только запустилась и загружает блокчейн -- Нода отстала от сети (пропустила блоки во время простоя или потери соединения) -- Нода обнаружила, что находится на миноритарном форке, и пересинхронизируется с мажоритарной цепью -- Стагнация обработки блоков — head не продвигается в течение настроенного периода - -**Почему может быть `FWD`:** -- Нода догнала сеть и работает нормально -- Все блоки принимаются через вещание в реальном времени от пиров - -### `fork` — Состояние форка - -| Значение | Описание | -|----------|----------| -| `NORMAL` | Нода находится на мажоритарном форке — конфликтов форков не обнаружено. | -| `LOOKING` | Нода обнаружила несколько конкурирующих вершин форка и активно сравнивает ветки, чтобы определить мажоритарную. | -| `MINORITY` | Нода определила, что находится на миноритарном форке (меньше свидетелей производят на этой ветке). Вероятен переключением на другой форк. | - -**Почему может быть не `NORMAL`:** -- Два или более свидетеля произвели блоки в одном слоте, создав временный форк -- Сетевой разраздел вызвал то, что разные подмножества свидетелей строили разные вершины -- Нода только что получила блок из альтернативного форка, который не связывается с её текущим head - -### `head` / `lib` - -- **head** — Номер блока текущей вершины цепи ноды (последний блок в цепи). -- **lib** — Номер последнего необратимого блока (Last Irreversible Block). Блоки на уровне LIB или ниже являются финализированными и не могут быть отменены. - -Разрыв между head и lib показывает, сколько блоков находится в обратимой части цепи. При нормальной работе с DLT этот разрыв небольшой (обычно 1-10 блоков). - -### `peers` / `conn` - -- **peers** — Общее количество известных ноде пиров (включает активных, подключающихся и отключенных пиров, отслеживаемых для переподключения). -- **conn** — Количество активных TCP-соединений, открытых в данный момент. - -Если `peers` значительно выше, чем `conn`, у ноды есть отключенные пиры, к которым она ожидает переподключиться (с экспоненциальной задержкой). - -### `paused` - -| Значение | Описание | -|----------|----------| -| `no` | Обработка блоков активна — входящие блоки применяются немедленно. | -| `YES` | Обработка блоков временно приостановлена. Входящие блоки ставятся в очередь и будут обработаны при возобновлении. | - -**Почему может быть `YES`:** -- Создается снимок (snapshot) — база данных заблокирована для экспорта согласованного состояния -- Внутренняя операция требует исключительного доступа к базе данных - -Когда обработка приостановлена, нода продолжает принимать P2P-соединения и получать сообщения, но блоки не применяются к цепи до возобновления обработки. - -### `uptime` - -Время с момента запуска P2P-ноды. Формат: `XhYmZs`. - ---- - -## Статистика по каждому пиру - -Каждый пир отображается на отдельной строке с детальной информацией о состоянии. - -### Отключенные пиры - -``` -138.201.117.201:2001 | DISC | disconnected=74s | backoff=480s | reconnect_in=502s | spam=0 -``` - -| Поле | Описание | -|------|----------| -| `DISC` | Пир в данный момент отключен. Нода попытается переподключиться. | -| `disconnected` | Секунд с момента потери соединения. | -| `backoff` | Текущий интервал задержки переподключения в секундах. Начинается с 30s и удваивается при каждой неудачной попытке, до 3600s (1 час). | -| `reconnect_in` | Секунд до следующей попытки переподключения. | -| `spam` | Счётчик spam-ударов. Сбрасывается при успешном переподключении. | - -**Поведение backoff:** -- Первое отключение: задержка 30s -- Каждая последующая неудачная попытка удваивает задержку (30 → 60 → 120 → 240 → 480 → ... → 3600) -- Если соединение остаётся стабильным более 5 минут, задержка сбрасывается до 30s -- Максимальная задержка — 3600s (1 час) - -### Активные пиры - -``` -62.109.17.82:2001 | ACTIVE | exch=YES | head=79881136 lib=79880729 | range=79869724-79880729 | peer_fork=NORM peer_node=FWD | spam=0 | +align+emrg+sync -``` - -#### Состояние жизненного цикла - -| Состояние | Описание | -|-----------|----------| -| `CONNECT` | Устанавливается TCP-соединение (таймаут: 5s). | -| `HANDSHAKE` | Идёт обмен hello/hello-reply (таймаут: 10s). | -| `SYNCING` | Активно загружается диапазон блоков от этого пира. | -| `ACTIVE` | Handshake завершён, exchange установлен, пир работает. | -| `DISC` | Отключён — см. формат отключенных пиров выше. | -| `BANNED` | Временно заблокирован — пир не будет контактировать до истечения бана (по умолчанию: 1 час). | - -#### `exch` — Статус обмена - -| Значение | Описание | -|----------|----------| -| `YES` | Обмен блоками и транзакциями включён с этим пиром. Обе стороны распознают друг друга как находящиеся на одном форке. | -| `no` | Обмен отключён. Нода не знает, находится ли этот пир на том же форке, поэтому не отправляет и не запрашивает блоки. | - -**Почему exchange может быть `no`:** -- Handshake только завершился, и выравнивание форка ещё не проверено -- Head/LIB пира не распознаётся нашей нодой (разные форки) -- Пир явно сообщил, что наша цепь не на его форке во время handshake -- Пир прислал блок из нераспознанного форка - -**Как exchange становится `YES`:** -- Во время handshake: если наша нода распознаёт head-блок пира, или пир распознаёт наш head-блок -- После принятия блока от пира: если блок применяется к нашей цепи, exchange включается автоматически -- Когда пир переходит из SYNC в FWD и его head становится распознанным - -#### `head` / `lib` (пира) - -Сообщённые пиrom номера head и LIB. **Это снимки** с последней коммуникации (hello, сообщение fork_status или ретрансляция блоков), а не значения в реальном времени. Фактический head цепи пира может быть значительно выше, особенно если пир работает в режиме FWD и быстро производит блоки. - -#### `range` — Диапазон блоков DLT - -Диапазон блоков, доступных этому пиру в его DLT block log: `earliest-latest`. - -- **earliest** — Номер самого старого блока, всё ещё сохранённого в DLT-логе пира -- **latest** — Номер самого нового блока в DLT-логе пира - -Если нашей ноде нужны блоки ниже `earliest` пира, этот пир не может их предоставить. Это важно при операциях gap fill, когда нужны исторические блоки. - -#### `peer_fork` — Статус форка пира - -Что пир сообщает о своей ситуации с форком: - -| Значение | Описание | -|----------|----------| -| `NORM` | Пир считает, что находится на мажоритарном форке. | -| `LOOK` | Пир активно разрешает конфликт форков. | -| `MINO` | Пир считает, что находится на миноритарном форке. | - -Это самоотчет пира через сообщения fork_status. Если пир сообщает `MINO`, он вероятно в процессе переключения на мажоритарный форк и скоро будет иметь другой head. - -#### `peer_node` — Режим работы пира - -| Значение | Описание | -|----------|----------| -| `SYNC` | Пир синхронизируется — загружает блоки. Не будет транслировать транзакции. | -| `FWD` | Пир синхронизирован — работает в режиме forward, производит и ретранслирует блоки. | - -**Почему это важно:** -- Если наша нода в режиме FWD, а пир в SYNC, мы не ожидаем вещания блоков в реальном времени от этого пира -- Если наша нода в режиме SYNC, мы запрашиваем блоки от всех пиров с enabled exchange независимо от их режима -- Если пир переходит из SYNC в FWD, он может пересмотреть exchange и начать отправлять нам блоки - -#### `spam` — Счётчик анти-спам ударов - -Количество spam-ударов, накопленных этим пиром. Каждое недействительное или malformed сообщение увеличивает этот счётчик. Когда он достигает 10, пир мягко блокируется на 1 час. - -**Что вызывает spam strike:** -- Malformed сообщения, которые не проходят десериализацию -- Сообщения, нарушающие правила протокола (например, блоки вне порядка вне ожидаемой синхронизации) -- Повторяющиеся недействительные данные от пира - -**Как сбрасывается:** -- При получении валидного пакета счётчик сбрасывается до 0 -- При успешном переподключении после отключения -- Когда бан снимается - -#### Флаги - -| Флаг | Описание | -|------|----------| -| `+align` | Выравнивание форка проверено — цепь этого пира связывается с нашей. Блоки от этого пира применяются к нашей цепи чисто. | -| `+emrg` | У пира активен emergency consensus — он производит блоки используя механизм emergency key. | -| `+ekey` | Пир владеет emergency private key — он может участвовать в emergency consensus при необходимости. | -| `+sync` | Диапазон блоков синхронизации в данный момент ожидается или в процессе с этим пиром. Нода запросила блоки и ждёт ответ. | - -**Почему флаги важны:** -- `+align` самый важный — подтверждает, что пир является валидным источником для блоков -- `+emrg` + `+ekey` вместе указывают, что пир является участником emergency validator -- `+sync` указывает на активную синхронизацию — пир используется как источник блоков - -### Заблокированные пиры - -``` -1.2.3.4:2001 | BANNED | ban_remaining=1800s | reason=spam strike threshold exceeded -``` - -| Поле | Описание | -|------|----------| -| `BANNED` | Пир временно заблокирован. Попытки соединения не будут предприниматься. | -| `ban_remaining` | Секунд осталось до истечения бана. Длительность бана по умолчанию — 3600s (1 час). | -| `reason` | Почему пир был заблокирован. Распространённые причины: превышен порог spam, нарушение протокола. | - -После истечения бана состояние пира сбрасывается на DISCONNECTED и начинается нормальная задержка переподключения. - ---- - -## Распространённые сценарии и интерпретации - -### Сценарий 1: Все пиры показывают `exch=no` - -**Что это значит:** Нода не распознаёт цепь любого пира как находящуюся на том же форке. - -**Вероятные причины:** -- Нода только запустилась и ещё не завершила handshake ни с одним пиром -- Нода находится на другом форке, чем все подключённые пиры -- Пиры подключились, пока нода была в режиме SYNC, и их head ещё не были распознаны - -**Что делать:** -- Дождитесь завершения handshake — exchange может включиться автоматически -- Проверьте статус `fork` в заголовке — если там `MINORITY` или `LOOKING`, нода разрешает конфликт форков -- Если нода остаётся в этом состоянии долго, возможно, ей нужно пересинхронизироваться с другим набором пиров - -### Сценарий 2: `status=SYNC` со многими активными пирами - -**Что это значит:** Нода активно загружает блоки от нескольких пиров. - -**Вероятные причины:** -- Запуск ноды после offline -- Нода отстала от сети -- Нода пересинхронизируется после переключения форка - -**Что делать:** -- Нормальное поведение — дождитесь завершения синхронизации -- Проверьте прогресс `head` в последовательных выводах статистики, чтобы подтвердить применение блоков -- Если `head` не продвигается в течение длительного периода, проверьте ошибки валидации блоков в логах - -### Сценарий 3: `peer_fork=MINO` у нескольких пиров - -**Что это значит:** Несколько пиров считают, что находятся на миноритарном форке. - -**Вероятные причины:** -- Общесетевое событие форка — свидетели разделены между двумя конкурирующими цепями -- Мажоритарный форк строится другим набором свидетелей - -**Что делать:** -- Мониторьте статус `fork` в заголовке — если он перейдёт в `MINORITY`, наша нода также переключит форк -- Дождитесь разрешения форка — протокол в конечном итоге сойдётся на одной цепи -- Если это сохраняется, проверьте активность свидетелей и сетевое подключение - -### Сценарий 4: Высокие значения `backoff` у отключённых пиров - -**Что это значит:** Пиры отключались несколько раз, и интервал переподключения вырос. - -**Вероятные причины:** -- Нестабильность сети между нашей нодой и пирами -- Пиры перезапускаются или испытывают downtime -- Проблемы с фаерволом или NAT, блокирующие постоянные соединения - -**Что делать:** -- Проверьте сетевое подключение к адресам пиров -- Убедитесь, что правила фаервола разрешают исходящие соединения на порт 2001 -- Если пиры известны как онлайн, высокий backoff нормален и сбросится при успешном соединении - -### Сценарий 5: `paused=YES` - -**Что это значит:** Обработка блоков временно приостановлена. - -**Вероятные причины:** -- Создание снимка в процессе — база данных заблокирована для экспорта согласованного состояния -- Внутренняя операция обслуживания, требующая исключительного доступа к базе данных - -**Что делать:** -- Нормально во время операций снимка — дождитесь завершения -- Блоки, полученные во время паузы, ставятся в очередь и будут обработаны при возобновлении -- Если пауза сохраняется неожиданно, проверьте застрявшие операции снимка - -### Сценарий 6: Rate-limiting обмена пирами в логах - -**Сообщение в логе:** `Peer rate-limited our exchange request, wait s` - -**Что это значит:** Наша нода отправила `dlt_peer_exchange_request` пиру, но этот пир ответил `dlt_peer_exchange_rate_limited`, потому что удалённый пир уже обслужил 3 запроса обмена от нас за последние 5 минут. - -**Механизм:** -- Каждый пир отслеживает `peer_exchange_request_count` и `peer_exchange_window_start` для каждого удалённого пира. -- Когда приходит `dlt_peer_exchange_request`, принимающий пир проверяет `is_peer_exchange_rate_limited()` — если получено 3 или более запросов в течение 5-минутного окна (`PEER_EXCHANGE_WINDOW_SEC`), он отвечает `dlt_peer_exchange_rate_limited{wait_seconds}` вместо списка пиров. -- На нашей стороне получение этого ответа помечает нас как rate-limited локально (`peer_exchange_request_count = MAX`), что предотвращает выбор этого пира в `periodic_peer_exchange()` до истечения окна. -- Это двусторонний механизм: обе ноды независимо обеспечивают одно и то же скользящее окно (3 запроса за 5 минут). - -**Зачем это нужно:** -- Предотвращает избыточный трафик обнаружения пиров в стабильных сетях -- Снижает излишнюю нагрузку сообщениями, когда топология пиров не меняется -- Дополняет фильтр `dlt-peer-exchange-min-uptime-sec` (600с), который гарантирует передачу только стабильных пиров - -**Что делать:** -- Это нормальное, ожидаемое поведение — никаких действий не требуется -- Сообщение появляется максимум после 4-го запроса в 5-минутном окне на пира -- Если сообщение появляется очень часто для множества пиров, это может указывать на слишком агрессивный интервал периодического обмена или слишком малое количество уникальных пиров в сети - ---- - -## Быстрый справочник - -### Перечисления - -**Статус ноды:** -- `DLT_NODE_STATUS_SYNC` (0) = Синхронизация -- `DLT_NODE_STATUS_FORWARD` (1) = Синхронизирована, работа в реальном времени - -**Статус форка:** -- `DLT_FORK_STATUS_NORMAL` (0) = На мажоритарном форке -- `DLT_FORK_STATUS_LOOKING_RESOLUTION` (1) = Разрешение конфликта форков -- `DLT_FORK_STATUS_MINORITY` (2) = На миноритарном форке - -**Состояния жизненного цикла пира:** -- `DLT_PEER_LIFECYCLE_CONNECTING` (0) = Установка TCP-соединения -- `DLT_PEER_LIFECYCLE_HANDSHAKING` (1) = Обмен сообщениями hello -- `DLT_PEER_LIFECYCLE_SYNCING` (2) = Загрузка диапазона блоков -- `DLT_PEER_LIFECYCLE_ACTIVE` (3) = Работает, exchange установлен -- `DLT_PEER_LIFECYCLE_DISCONNECTED` (4) = Отключён, будет переподключён -- `DLT_PEER_LIFECYCLE_BANNED` (5) = Временно заблокирован - -### Пороги и константы - -| Константа | Значение | Описание | -|-----------|----------|----------| -| `SPAM_STRIKE_THRESHOLD` | 10 | Spam-ударов до мягкого бана | -| `BAN_DURATION_SEC` | 3600 | Длительность бана по умолчанию (1 час) | -| `INITIAL_RECONNECT_BACKOFF_SEC` | 30 | Начальная задержка переподключения | -| `MAX_RECONNECT_BACKOFF_SEC` | 3600 | Максимальная задержка переподключения (1 час) | -| `PEER_EXCHANGE_MAX_REQUESTS` | 3 | Максимум запросов обмена пирами к одному пиру в рамках скользящего окна | -| `PEER_EXCHANGE_WINDOW_SEC` | 300 | Длительность скользящего окна обмена пирами (5 мин) — обе стороны обеспечивают ограничение; ответ rate-limited содержит `wait_seconds` с оставшимся временем окна | -| `SEND_QUEUE_MAX_DEPTH` | 100 | Максимум queued сообщений на пира | -| `KNOWN_BLOCKS_WINDOW` | 20 | Размер кольцевого буфера ID блоков для подавления эха | -| `CONNECTING_TIMEOUT` | 5s | Таймаут установления TCP-соединения | -| `HANDSHAKING_TIMEOUT` | 10s | Таймаут обмена hello/hello-reply | diff --git a/.qoder/docs/dlt-p2p-stats-reference.md b/.qoder/docs/dlt-p2p-stats-reference.md deleted file mode 100644 index 62bc173fa0..0000000000 --- a/.qoder/docs/dlt-p2p-stats-reference.md +++ /dev/null @@ -1,375 +0,0 @@ -# DLT P2P Statistics Reference - -This document explains the DLT P2P statistics output — what each field means, why it has its current value, and what actions (if any) an operator should take. - -There are **two distinct log lines** emitted periodically by `dlt_p2p_node`: - -| Log prefix | Frequency | Purpose | -|---|---|---| -| `DLT Status \|` | Every ~30s | Compact one-liner for quick health monitoring | -| `=== DLT P2P Stats \|` | Every ~120s | Detailed stats including per-node fork/peer data | - ---- - -## DLT Status Log (Compact Line) - -``` -DLT Status | FORWARD | head=#79881136 lib=#79881130 | dlt_range=79000000-79881136 | peers=6active/8conn | uptime=2h15m43s | flags=... -``` - -Emitted every ~30 seconds. Intended for tail/grep monitoring without noise. - -### Fields - -| Field | Example | Meaning | -|---|---|---| -| Mode | `FORWARD` | Node operating mode (`SYNC` or `FORWARD`) | -| `head=#N` | `head=#79881136` | Current head block number | -| `lib=#N` | `lib=#79881130` | Last irreversible block number | -| `dlt_range=A-B` | `dlt_range=79000000-79881136` | Block range stored in DLT block log | -| `peers=Xactive/Yconn` | `peers=6active/8conn` | Active (exchanging) / total connected peers | -| `uptime=XhYmZs` | `uptime=2h15m43s` | Time since node startup | -| `flags=...` | Various | Active operational flags (snapshot, pause, catchup, etc.) | - -**`uptime`** is computed as `(now - _node_start_time)` where `_node_start_time` is recorded in the `dlt_p2p_node` constructor. Use this to correlate log events with node age — particularly useful when checking if a production issue started immediately after startup vs. after running for a while. - ---- - -## Node-Level Summary (Header Line) - -``` -=== DLT P2P Stats | status=FWD fork=NORMAL head=79881136 lib=79881130 peers=6 conn=4 paused=no uptime=0h20m30s === -``` - -### `status` — Node Operating Mode - -| Value | Meaning | -|-------|---------| -| `SYNC` | Node is catching up — downloading and applying blocks from peers. Transactions are not broadcast during this mode. | -| `FWD` | Node is caught up and in forward mode — producing/relaying blocks and transactions in real-time. | - -**Why it might be `SYNC`:** -- Node just started and is downloading the blockchain -- Node fell behind the network (missed blocks during downtime or connection loss) -- Node detected it is on a minority fork and is re-syncing from the majority chain -- Block processing stagnation — head hasn't advanced for a configured period - -**Why it might be `FWD`:** -- Node has caught up to the network and is operating normally -- All blocks are being received via real-time broadcast from peers - -### `fork` — Fork Status - -| Value | Meaning | -|-------|---------| -| `NORMAL` | Node is on the majority fork — no fork conflict detected. | -| `LOOKING` | Node detected multiple competing fork tips and is actively comparing branches to determine which is the majority. | -| `MINORITY` | Node determined it is on a minority fork (fewer validators producing on this branch). A fork switch is likely pending. | - -**Why it might not be `NORMAL`:** -- Two or more validators produced blocks at the same slot, creating a temporary fork -- Network partition caused different subsets of validators to build on different tips -- Node just received a block from an alternative fork that doesn't link to its current head - -### `head` / `lib` - -- **head** — Block number of the node's current head (latest block in the chain). -- **lib** — Last Irreversible Block number. Blocks at or below LIB are finalized and cannot be reverted. - -The gap between head and lib indicates how many blocks are on the reversible part of the chain. In normal operation with DLT, this gap is small (typically 1-10 blocks). - -### `peers` / `conn` - -- **peers** — Total number of peer entries known to the node (includes active, connecting, and disconnected peers tracked for reconnection). -- **conn** — Number of active TCP connections currently open. - -If `peers` is significantly higher than `conn`, the node has disconnected peers it is waiting to reconnect to (with exponential backoff). - -### `paused` - -| Value | Meaning | -|-------|---------| -| `no` | Block processing is active — incoming blocks are being applied immediately. | -| `YES` | Block processing is temporarily paused. Incoming blocks are queued and will be processed when resumed. | - -**Why it might be `YES`:** -- A snapshot is being created — the database is locked for consistent state export -- An internal operation requires exclusive database access - -When paused, the node continues to accept P2P connections and receive messages, but blocks are not applied to the chain until processing resumes. - -### `uptime` - -Time since the P2P node was started. Format: `XhYmZs`. - ---- - -## Per-Peer Statistics - -Each peer is shown on a separate line with detailed state information. - -### Disconnected Peers - -``` -138.201.117.201:2001 | DISC | disconnected=74s | backoff=480s | reconnect_in=502s | spam=0 -``` - -| Field | Meaning | -|-------|---------| -| `DISC` | Peer is currently disconnected. The node will attempt to reconnect. | -| `disconnected` | Seconds since the connection was lost. | -| `backoff` | Current reconnection backoff interval in seconds. Starts at 30s and doubles on each failed attempt, up to 3600s (1 hour). | -| `reconnect_in` | Seconds until the next reconnection attempt. | -| `spam` | Spam strike counter. Reset on successful reconnection. | - -**Backoff behavior:** -- First disconnect: 30s backoff -- Each subsequent failed reconnect doubles the backoff (30 → 60 → 120 → 240 → 480 → ... → 3600) -- If a connection stays stable for more than 5 minutes, the backoff resets to 30s -- Maximum backoff is 3600s (1 hour) - -### Active Peers - -``` -62.109.17.82:2001 | ACTIVE | exch=YES | head=79881136 lib=79880729 | range=79869724-79880729 | peer_fork=NORM peer_node=FWD | spam=0 | +align+emrg+sync -``` - -#### Lifecycle State - -| State | Meaning | -|-------|---------| -| `CONNECT` | TCP connection is being established (timeout: 5s). | -| `HANDSHAKE` | Hello/hello-reply exchange is in progress (timeout: 10s). | -| `SYNCING` | Actively downloading a block range from this peer. | -| `ACTIVE` | Handshake complete, exchange is established, peer is operational. | -| `DISC` | Disconnected — see disconnected peer format above. | -| `BANNED` | Temporarily banned — peer will not be contacted until ban expires (default: 1 hour). | - -#### `exch` — Exchange Status - -| Value | Meaning | -|-------|---------| -| `YES` | Block and transaction exchange is enabled with this peer. Both sides recognize each other as being on the same fork. | -| `no` | Exchange is disabled. The node does not know if this peer is on the same fork, so it does not send or request blocks. | - -**Why exchange might be `no`:** -- Handshake just completed and fork alignment has not been verified yet -- Peer's head/LIB is not recognized by our node (different forks) -- Peer explicitly reported that our chain is not on its fork during handshake -- Peer sent a block from an unrecognized fork - -**How exchange becomes `YES`:** -- During handshake: if our node recognizes the peer's head block, or the peer recognizes our head block -- After accepting a block from the peer: if the block applies to our chain, exchange is automatically enabled -- When a peer transitions from SYNC to FWD and its head becomes recognized - -#### `head` / `lib` (peer) - -The peer's reported head and LIB block numbers. **These are snapshots** from the last communication (hello, fork_status message, or block relay), not real-time values. The peer's actual chain head may be significantly higher, especially if the peer is in FWD mode and producing blocks rapidly. - -#### `range` — DLT Block Range - -The block range this peer has available in its DLT block log: `earliest-latest`. - -- **earliest** — Oldest block number still retained in the peer's DLT log -- **latest** — Newest block number in the peer's DLT log - -If our node needs blocks below the peer's `earliest`, this peer cannot serve them. This is relevant during gap fill operations when historical blocks are needed. - -#### `peer_fork` — Peer's Fork Status - -What the peer reports about its own fork situation: - -| Value | Meaning | -|-------|---------| -| `NORM` | Peer believes it is on the majority fork. | -| `LOOK` | Peer is actively resolving a fork conflict. | -| `MINO` | Peer believes it is on a minority fork. | - -This is self-reported by the peer via fork_status messages. If a peer reports `MINO`, it is likely in the process of switching to the majority fork and may soon have a different head. - -#### `peer_node` — Peer's Operating Mode - -| Value | Meaning | -|-------|---------| -| `SYNC` | Peer is catching up — downloading blocks. It will not broadcast transactions. | -| `FWD` | Peer is caught up — operating in forward mode, producing and relaying blocks. | - -**Why this matters:** -- If our node is in FWD mode and a peer is in SYNC, we do not expect real-time block broadcasts from that peer -- If our node is in SYNC mode, we request blocks from all exchange-enabled peers regardless of their mode -- If a peer transitions from SYNC to FWD, it may re-evaluate exchange and start sending us blocks - -#### `spam` — Anti-Spam Strike Counter - -Number of spam strikes accumulated by this peer. Each invalid or malformed message increments this counter. When it reaches 10, the peer is soft-banned for 1 hour. - -**What triggers a spam strike:** -- Malformed messages that fail deserialization -- Messages that violate protocol rules (e.g., out-of-order blocks outside of expected sync) -- Repeated invalid data from the peer - -**How it resets:** -- On receiving a valid packet, the counter resets to 0 -- On successful reconnection after a disconnect -- When a ban is lifted - -#### Flags - -| Flag | Meaning | -|------|---------| -| `+align` | Fork alignment verified — this peer's chain links to ours. Blocks from this peer apply cleanly to our chain. | -| `+emrg` | Peer has emergency consensus active — it is producing blocks using the emergency key mechanism. | -| `+ekey` | Peer possesses an emergency private key — it can participate in emergency consensus if needed. | -| `+sync` | A block range sync is currently pending or in progress with this peer. The node has requested blocks and is waiting for the response. | - -**Why flags matter:** -- `+align` is the most important — it confirms the peer is a valid source for blocks -- `+emrg` + `+ekey` together indicate the peer is an emergency validator participant -- `+sync` indicates active synchronization — the peer is being used as a block source - -### Banned Peers - -``` -1.2.3.4:2001 | BANNED | ban_remaining=1800s | reason=spam strike threshold exceeded -``` - -| Field | Meaning | -|-------|---------| -| `BANNED` | Peer is temporarily banned. No connection attempts will be made. | -| `ban_remaining` | Seconds remaining until the ban expires. Default ban duration is 3600s (1 hour). | -| `reason` | Why the peer was banned. Common reasons: spam threshold exceeded, protocol violation. | - -After the ban expires, the peer state resets to DISCONNECTED and normal reconnection backoff begins. - ---- - -## Common Scenarios and Interpretations - -### Scenario 1: All Peers Show `exch=no` - -**What it means:** The node does not recognize any peer's chain as being on the same fork. - -**Likely causes:** -- Node just started and hasn't completed handshake with any peer -- Node is on a different fork than all connected peers -- Peers connected while the node was in SYNC mode and their heads were not yet recognized - -**What to do:** -- Wait for handshake to complete — exchange may enable automatically -- Check the `fork` status in the header — if it says `MINORITY` or `LOOKING`, the node is resolving a fork conflict -- If the node stays in this state for a long time, it may need to re-sync from a different peer set - -### Scenario 2: `status=SYNC` with Many Active Peers - -**What it means:** The node is actively downloading blocks from multiple peers. - -**Likely causes:** -- Node startup after being offline -- Node fell behind the network -- Node is re-syncing after a fork switch - -**What to do:** -- Normal behavior — wait for sync to complete -- Check `head` progression in successive stats outputs to confirm blocks are being applied -- If `head` does not advance for an extended period, check for block validation errors in logs - -### Scenario 3: `peer_fork=MINO` on Multiple Peers - -**What it means:** Multiple peers believe they are on a minority fork. - -**Likely causes:** -- Network-wide fork event — validators are split between two competing chains -- The majority fork is being built by a different set of validators - -**What to do:** -- Monitor the `fork` status in the header — if it transitions to `MINORITY`, our node will also switch forks -- Wait for fork resolution — the protocol will eventually converge on a single chain -- If this persists, check validator activity and network connectivity - -### Scenario 4: High `backoff` Values on Disconnected Peers - -**What it means:** Peers have disconnected multiple times and the reconnection interval has grown. - -**Likely causes:** -- Network instability between our node and the peers -- Peers are restarting or experiencing downtime -- Firewall or NAT issues blocking persistent connections - -**What to do:** -- Check network connectivity to the peer addresses -- Verify firewall rules allow outbound connections on port 2001 -- If peers are known to be online, high backoff is normal and will reset on successful connection - -### Scenario 5: `paused=YES` - -**What it means:** Block processing is temporarily suspended. - -**Likely causes:** -- Snapshot creation in progress — database is locked for consistent state export -- Internal maintenance operation requiring exclusive database access - -**What to do:** -- Normal during snapshot operations — wait for completion -- Blocks received during pause are queued and will be processed when resumed -- If pause persists unexpectedly, check for stuck snapshot operations - -### Scenario 6: Peer Exchange Rate-Limiting in Logs - -**Log message:** `Peer rate-limited our exchange request, wait s` - -**What it means:** Our node sent a `dlt_peer_exchange_request` to a peer, but that peer responded with a `dlt_peer_exchange_rate_limited` message because the remote peer has already served 3 exchange requests from us within the last 5-minute window. - -**Mechanism:** -- Each peer tracks `peer_exchange_request_count` and `peer_exchange_window_start` per remote peer. -- When a `dlt_peer_exchange_request` arrives, the receiving peer checks `is_peer_exchange_rate_limited()` — if 3 or more requests were received within the 5-minute window (`PEER_EXCHANGE_WINDOW_SEC`), it responds with `dlt_peer_exchange_rate_limited{wait_seconds}` instead of a peer list. -- On our side, receiving this response marks us as rate-limited locally (`peer_exchange_request_count = MAX`), which prevents `periodic_peer_exchange()` from selecting this peer for future requests until the window expires. -- This is a two-sided mechanism: both nodes independently enforce the same sliding window (3 requests per 5 minutes). - -**Why this exists:** -- Prevents excessive peer discovery traffic on stable networks -- Reduces unnecessary message overhead when peer topology is not changing -- Complements the `dlt-peer-exchange-min-uptime-sec` (600s) filter which ensures only stable peers are shared - -**What to do:** -- This is normal, expected behavior — no action required -- The message appears at most after the 4th request within a 5-minute window per peer -- If this message appears very frequently for many peers, it may indicate that the periodic exchange interval is configured too aggressively or the network has very few unique peers - ---- - -## Quick Reference - -### Enumerations - -**Node Status:** -- `DLT_NODE_STATUS_SYNC` (0) = Catching up -- `DLT_NODE_STATUS_FORWARD` (1) = Caught up, real-time operation - -**Fork Status:** -- `DLT_FORK_STATUS_NORMAL` (0) = On majority fork -- `DLT_FORK_STATUS_LOOKING_RESOLUTION` (1) = Resolving fork conflict -- `DLT_FORK_STATUS_MINORITY` (2) = On minority fork - -**Peer Lifecycle States:** -- `DLT_PEER_LIFECYCLE_CONNECTING` (0) = Establishing TCP connection -- `DLT_PEER_LIFECYCLE_HANDSHAKING` (1) = Exchanging hello messages -- `DLT_PEER_LIFECYCLE_SYNCING` (2) = Downloading block range -- `DLT_PEER_LIFECYCLE_ACTIVE` (3) = Operational, exchange established -- `DLT_PEER_LIFECYCLE_DISCONNECTED` (4) = Disconnected, will reconnect -- `DLT_PEER_LIFECYCLE_BANNED` (5) = Temporarily banned - -### Thresholds and Constants - -| Constant | Value | Description | -|----------|-------|-------------| -| `SPAM_STRIKE_THRESHOLD` | 10 | Spam strikes before soft-ban | -| `BAN_DURATION_SEC` | 3600 | Default ban duration (1 hour) | -| `INITIAL_RECONNECT_BACKOFF_SEC` | 30 | Initial reconnection delay | -| `MAX_RECONNECT_BACKOFF_SEC` | 3600 | Maximum reconnection delay (1 hour) | -| `PEER_EXCHANGE_MAX_REQUESTS` | 3 | Maximum peer exchange requests allowed per peer within the sliding window | -| `PEER_EXCHANGE_WINDOW_SEC` | 300 | Peer exchange sliding window duration (5 min) — both requesting and serving sides enforce this; a rate-limited response carries `wait_seconds` indicating remaining window time | -| `SEND_QUEUE_MAX_DEPTH` | 100 | Maximum queued messages per peer | -| `KNOWN_BLOCKS_WINDOW` | 20 | Block ID ring buffer size for echo suppression | -| `CONNECTING_TIMEOUT` | 5s | Timeout for TCP connection establishment | -| `HANDSHAKING_TIMEOUT` | 10s | Timeout for hello/hello-reply exchange | diff --git a/.qoder/docs/emergency-consensus-review.md b/.qoder/docs/emergency-consensus-review.md deleted file mode 100644 index 859d5becf0..0000000000 --- a/.qoder/docs/emergency-consensus-review.md +++ /dev/null @@ -1,613 +0,0 @@ -# Emergency Consensus Recovery — Implementation Review - -## Status: Implemented (Hardfork 12, version 3.1.0) — Bugs Found and Fixed (B1–B17) - -Research source: [consensus-emergency-recovery.md](../research/consensus-emergency-recovery.md) - ---- - -## System Overview - -Hardfork 12 adds an on-chain **Emergency Consensus Mode** that activates automatically when the VIZ network stalls for >1 hour (no LIB advancement). The activation check is fully deterministic — it uses only block timestamps from the chain state (`b.timestamp - lib_block.timestamp`), ensuring identical results on every node and during every replay. A well-known committee key (`VIZ75CRHVHPwYiUESy1bgN3KhVFbZCQQRA9jT6TnpzKAmpxMPD6Xv`) becomes the block producer, keeping the chain alive until real validators return. - -On activation, **all real validators are disabled** (`signing_key` set to null, penalties reset to zero, `current_run` reset). Only the committee produces blocks initially. Operators must manually re-enable validators via `witness_update_operation` transactions. This ensures a clean start where only intentionally re-registered validators participate. - -The committee validator is a **neutral voter**: it copies the current median chain properties and votes for the currently applied hardfork version (not a future one). This ensures that committee slots in the schedule don't skew governance parameters or push unvoted hardforks. - -### Key Files Modified - -| File | Role | -|---|---| -| `libraries/chain/hardfork.d/12.hf` | Hardfork 12 definition | -| `libraries/protocol/include/graphene/protocol/config.hpp` | Emergency constants, version 3.1.0 | -| `libraries/chain/include/graphene/chain/database.hpp` | DGP fields, skip flags | -| `libraries/chain/database.cpp` | Activation, hybrid schedule, LIB advancement (capped), startup recovery, vote-weighted fork comparison | -| `libraries/chain/include/graphene/chain/fork_database.hpp` | Emergency mode flag, size increase 1024→2400 | -| `libraries/chain/fork_database.cpp` | Hash tie-breaking, `set_emergency_mode()` | -| `plugins/validator/validator.cpp` | Three-state safety, emergency key config, fork collision | -| `libraries/network/include/graphene/network/peer_connection.hpp` | `fork_rejected_until` soft-ban field, `sync_spam_strikes` counter | -| `libraries/network/node.cpp` | P2P anti-spam (soft-ban vs disconnect), sync ping-pong loop fix, sync spam soft-ban | -| `plugins/snapshot/plugin.cpp` | Forward-compatible DGP import | -| `share/vizd/config/config_witness.ini` | `emergency-private-key` option | - ---- - -## Architecture Diagram - -``` - ┌──────────────────────────────┐ - │ update_global_dynamic_data │ - │ (every block) │ - │ │ - │ HF12 active? │ - │ emergency_active == false? │ - │ ├── NO ─────────────────│── Skip check - │ └── YES │ - │ lib_block available? │ - │ ├── NO ─────────────────│── Skip check (snapshot restore) - │ └── YES │ - │ seconds_since_lib │ - │ = b.timestamp - │ - │ lib_block.timestamp │ - │ ≥ 3600? │ - │ ├── YES ─────────────│── Activate Emergency - │ │ │ • emergency_consensus_active = true - │ │ │ • Create/update committee validator - │ │ │ • Disable ALL real validators - │ │ │ (signing_key = null, penalties = 0) - │ │ │ • Override schedule → committee - │ │ │ • next_shuffle_block_num = now+N - │ │ │ • fork_db.set_emergency_mode(true) - │ └── NO │ - └──────────────────────────────┘ - │ - ▼ - ┌──────────────────────────────┐ - │ update_witness_schedule │ - │ (every round) │ - │ │ - │ 1. Normal schedule build │ - │ (may zero all slots if no │ - │ validators have valid keys) │ - │ 2. Hybrid schedule override: │ - │ • Real validators keep slots │ - │ • Committee fills gaps │ - │ • Expand to full 21 slots │ - │ • Sync committee props/vote │ - │ 3. update_median_witness_props │ - │ │ - │ Skip committee in: │ - │ • Hardfork vote tally │ - │ • Median props computation │ - │ │ - │ Exit check: │ - │ real_witness_slots >= 75% │ - │ of CHAIN_MAX_WITNESSES? │ - │ ├── YES ─────────────►│── Deactivate Emergency - │ │ │ • emergency_consensus_active = false - │ │ │ • fork_db.set_emergency_mode(false) - │ └── NO │ - └──────────────────────────────┘ - │ - ▼ - ┌──────────────────────────────┐ - │ update_last_irreversible_block│ - │ │ - │ During emergency: │ - │ • All schedule validators │ - │ used (including committee) │ - │ • 75% nth_element threshold │ - │ • LIB capped at HEAD−1 │ - │ (preserves undo session │ - │ for current block) │ - │ • LIB advances every block │ - │ (1 block behind head) │ - └──────────────────────────────┘ - │ - ▼ - ┌──────────────────────────────┐ - │ Startup Recovery │ - │ (database::open) │ - │ │ - │ If schedule has empty slots: │ - │ • Fill all with committee │ - │ • Ensure emergency active │ - │ • Restore fork_db flag │ - └──────────────────────────────┘ -``` - ---- - -## Failure & Rollback Procedures - -### F1: Emergency Activated Erroneously - -**When**: A bug or time desync causes `seconds_since_lib >= 3600` while the network is actually healthy. - -**Why this is extremely unlikely**: Emergency activation is fully deterministic: `seconds_since_lib = b.timestamp - lib_block.timestamp`. For a false trigger, LIB must genuinely stall for 1 hour (1200 blocks at 3s intervals). No config flags or skip-flags gate the check — it relies solely on signed block timestamps embedded in the chain, ensuring identical results on every node and during every replay. - -**Special case — snapshot restore**: After `open_from_snapshot()`, the block_log is empty, so `fetch_block_by_number(LIB)` returns invalid. If we fell back to `genesis_time`, emergency would activate immediately. This is now prevented: when the LIB block is unavailable, the emergency check is skipped entirely (B7 fix). - -**If it happens** (legitimate false activation): -1. Emergency activates, all real validators are **disabled** (`signing_key` zeroed). -2. Committee produces blocks alone initially. -3. Since all validators had valid keys before, operators quickly re-register via `witness_update_operation`. -4. Once **16+ real validators** (75% of 21) have re-registered with valid signing keys in the hybrid schedule, **emergency exits automatically**. -5. **Manual intervention required**: operators must re-register validators via transactions. - -**Worst case**: If all 21 validator operators are available, recovery takes as fast as they can broadcast `witness_update_operation` transactions. - -### F2: Emergency Exit Does Not Trigger - -**When**: Emergency is active but the exit condition (75% real validators in schedule) never becomes true. - -**Root cause**: Fewer than 75% of the 21 schedule slots (i.e., <16) are occupied by real validators with valid `signing_key`. Since all validators are disabled on activation, operators must manually re-enable them. - -**Recovery procedure**: -1. **Check how many validators are active**: `get_dynamic_global_properties` → `participation_count`, plus inspect `witness_schedule` to see how many non-committee slots exist. -2. **Activate more validators**: Each validator operator re-registers via `witness_update_operation` from CLI wallet or service. The validator only needs a valid `signing_key` — the hybrid schedule will automatically assign their slot on the next schedule update. -3. **No config changes needed**: The `enable-stale-production` and `required-participation` settings are auto-bypassed during emergency. validators just need to be connected to P2P and have their signing key registered. -4. **Threshold**: Once 16+ validators have valid signing keys in the schedule, emergency exits on the next `update_witness_schedule()` call. - -**If validators cannot re-register** (e.g., lost master keys): The network remains in emergency mode indefinitely but still produces blocks. Governance intervention (committee proposals) would be needed to resolve validator account recovery. - -### F3: Committee Chain Split (Multiple Emergency Producers) - -**When**: Multiple nodes with the emergency private key produce competing blocks at the same slot during emergency. - -**Why this is expected and handled**: -1. **Hash tie-breaking** (`fork_database::_push_block()`): When two blocks are at the same height during emergency, the one with the lower `block_id` (SHA256 hash) wins deterministically. All nodes converge to the same block within 1 P2P propagation round. -2. **Fork collision check** (`validator.cpp`): After the first slot, nodes detect that a competing block already exists at the target height and skip production. This reduces multi-producer collisions to a transient 1–2 slot artifact. -3. **No permanent split**: Because all emergency blocks use the same `committee` validator account and the schedule is identical on all nodes, there is no ongoing disagreement. Convergence is guaranteed within seconds. - -**If a persistent split occurs** (e.g., network partition during emergency): -- LIB is 1 block behind head on all partitions → most emergency blocks are irreversible. -- When partitions reconnect, **vote-weighted chain comparison** (`push_block()`) resolves the fork: - - Branches with real validators (non-committee) win over pure-committee branches. - - Among branches with only committee blocks, the longer chain wins, with hash tie-breaking as the final tiebreaker. -- The losing partition unwinds its reversible blocks and syncs from the winner. - -### F4: Emergency Lasts Longer Than Undo Window - -**When**: This failure mode is now **largely mitigated**. LIB advances every block during emergency (capped at HEAD−1), so the gap between HEAD and LIB stays at exactly 1 block. The 10,000-block undo limit cannot be reached. - -**Previous behavior (before LIB advancement fix)**: LIB was frozen during emergency, and the gap grew at 1 block per 3 seconds. After ~8.3 hours (10,000 blocks), the undo limit was hit and block production halted. - -**Current behavior**: LIB = HEAD−1 at all times during emergency. `fork_db` size stays at 2 blocks. Emergency can run indefinitely without hitting any undo limits. - -**Remaining risk**: If a bug prevents LIB from advancing despite the cap, the old failure mode would resurface. The startup recovery mechanism (B12) provides an additional safety net. - -### F5: validators Disabled On Emergency Activation - -**When**: On emergency activation, **all real validators are disabled**: `signing_key` is set to `public_key_type()` (null), `penalty_percent` reset to 0, `counted_votes` restored to `votes`, `current_run` reset to 0. All `witness_penalty_expire_object` entries are removed. - -**Emergency behavior**: -1. On activation, **all real validators are immediately disabled** by zeroing their `signing_key`. This is intentional — it ensures a clean start where only the committee produces blocks. Operators must explicitly re-register validators. -2. **During emergency, offline validators do NOT accumulate new missed-block penalties**. The `update_global_dynamic_data()` penalty/shutdown logic is skipped for validators that are not the block producer and not the committee account. -3. validators must broadcast `witness_update_operation` to re-register their signing key. - -**Recovery**: Emergency blocks **allow transactions** (not forced empty). So validators can: -1. Connect their node to the P2P network. -2. Use CLI wallet or web services to broadcast `witness_update_operation` with their signing key. -3. The transaction enters the next emergency block. -4. On the next schedule update, the validator gets their slot back in the hybrid schedule. - -**This is intentional**: Disabling all validators on activation ensures that only intentionally re-registered validators participate. This prevents stale/crashed validators from being included in the schedule and causing production failures. - ---- - -## Bugs Found and Fixed - -The following bugs were discovered during code review of the emergency consensus implementation, specifically for the scenario of **1 node running 11 top validators** with other validators expected to join later. - -### B1 (Critical): Hybrid Schedule Doesn't Expand `num_scheduled_witnesses` - -**Problem**: `update_witness_schedule()` sets `num_scheduled_witnesses` to the count of validators with valid signing keys (e.g., 11). The hybrid override loop only iterated up to `num_scheduled_witnesses`, so empty slots at indices 11-20 were never visited and never assigned to committee. After the first schedule round, committee disappeared from production entirely. - -**Fix**: The hybrid override now iterates the full `CHAIN_MAX_WITNESSES` range, reads entries beyond `num_scheduled_witnesses` as empty, assigns committee to all empty/unavailable slots, and sets `num_scheduled_witnesses = CHAIN_MAX_WITNESSES * CHAIN_BLOCK_WITNESS_REPEAT`. - -### B2 (Critical): Committee Over-Counted in Hardfork Vote Tally - -**Problem**: With `CHAIN_BLOCK_WITNESS_REPEAT = 1`, the hardfork vote tally iterates every schedule slot. Committee filling 10 slots caused `get_witness("committee")` to be called 10 times, incrementing the committee's vote count by 10. The committee's default `hardfork_version_vote = 0.0.0` dominated the tally and blocked any hardfork from reaching `CHAIN_HARDFORK_REQUIRED_WITNESSES = 17`. - -**Fix**: The hardfork vote tally now skips `CHAIN_EMERGENCY_WITNESS_ACCOUNT` during emergency mode. Only real validators' votes count toward hardfork adoption. - -### B3 (High): Committee Skews Median Chain Properties - -**Problem**: `update_median_witness_props()` collected all schedule entries including 10 committee copies. The committee's default `chain_properties` (zero fees, zero sizes, zero penalties) skewed the median, enabling spam attacks and removing miss penalties. - -**Fix** (two-part): -1. The committee validator is initialized with `props = median_props` (current median), and re-synced every schedule update. This makes committee entries neutral — they reinforce the existing median rather than distorting it. -2. As defense-in-depth, `update_median_witness_props()` skips committee entries during emergency mode. This ensures the median reflects only real validators' preferences. - -### B4 (High): Offline validators Accumulate Penalties During Emergency - -**Problem**: When committee produced a block, the `missed_blocks` loop in `update_global_dynamic_data()` applied penalties to offline validators for every missed slot. After 200 missed blocks (~10 minutes), their `signing_key` was set to null again — the same problem that emergency activation's penalty reset tried to solve. - -**Fix** (consensus-based, deterministic): During emergency mode, the penalty/shutdown logic is split: -- **Skipped**: `total_missed++`, `penalty_percent` increment, and `counted_votes` recalculation for offline validators. Only `current_run` is reset. -- **Applied (consensus check)**: Key-blanking uses `head_block_num() - last_confirmed_block_num > CHAIN_EMERGENCY_MAX_WITNESS_MISSED_BLOCKS` (105 blocks = 5 full rounds). Both `head_block_num()` and `last_confirmed_block_num` are on-chain consensus fields stored in `witness_object` shared memory, so all nodes compute identical results. This replaces the old non-consensus approach that used a local `_emergency_round_start_gap` map (which could diverge between nodes). The threshold (105) is tighter than the normal-mode threshold (200) because real validators should re-enable faster during emergency recovery. - -### B5 (Medium): Committee Could Be Selected as Top/Support validator - -**Problem**: The top/support validator selection iterated by `counted_votes`. If the committee validator ever received votes, it could compete for a production slot, displacing a real validator. - -**Fix**: Both top and support validator selection loops now explicitly exclude `CHAIN_EMERGENCY_WITNESS_ACCOUNT`. - -### B6 (Medium): Committee Hardfork Vote Auto-Injected via Block Extensions - -**Problem**: `_generate_block()` auto-injects a `hardfork_version_vote` extension when the validator's on-chain vote doesn't match the binary's configured next hardfork. For the committee validator (which votes for `current_hardfork_version`), this extension overwrote the on-chain vote to the next hardfork version via `process_header_extensions()`, defeating the neutral-voter design. - -**Fix**: When the block producer is the emergency committee, hardfork vote auto-injection is skipped entirely. The committee's on-chain vote stays at `current_hardfork_version` and is re-synced every schedule update. - -### B7 (Critical): False Emergency Activation After Snapshot Restore - -**Problem**: In `update_global_dynamic_data()`, when `fetch_block_by_number(LIB)` returns invalid (block_log empty after `open_from_snapshot()`), `lib_time` fell back to `_dgp.genesis_time`. This made `seconds_since_lib = block_timestamp - genesis_time` — millions of seconds — causing emergency activation on the very first block after snapshot restore. - -The false activation triggers catastrophic side effects: -1. Schedule overridden to all-committee, but `next_shuffle_block_num` not updated → hybrid override can't run until the next shuffle boundary. -2. Blocks from real validators (via p2p) are rejected because the schedule expects `committee` → `head_block_num()` doesn't advance. -3. `next_shuffle_block_num` is never reached → **deadlock: the node permanently stops syncing**. Probability: ~20/21 (~95%) depending on how close the next shuffle was. -4. Side effects: all validator penalties reset, committee validator object created, consensus state corrupted. - -**Fix** (two-part): -1. When `lib_block` is not found (block_log empty after snapshot restore), `lib_time_available` stays `false` and the emergency check is skipped entirely. Emergency cannot activate without a valid LIB timestamp. -2. On emergency activation, `next_shuffle_block_num` is now set to `head_block_num() + num_scheduled_witnesses`, ensuring the hybrid override runs on the next schedule update even after a legitimate activation. - -### B8 (Medium): `inhibit_fetching_sync_blocks` Never Reset After Soft-Ban Expires - -**Problem**: In `node.cpp`, when a soft-ban is applied (`fork_rejected_until = now + 1h`), `inhibit_fetching_sync_blocks` is also set to `true`. After 1 hour, `fork_rejected_until` expires and blocks are accepted again, but `inhibit_fetching_sync_blocks` remains `true` forever — the node never requests sync inventory from that peer again. During extended emergency operation, the number of peers available for sync gradually decreases as each soft-banned peer's inhibit flag becomes permanent. - -**Fix**: In `process_block_during_normal_operation()`, after the `fork_rejected_until` check passes (ban expired), if `inhibit_fetching_sync_blocks` is `true` and `fork_rejected_until` is set and has expired, reset `inhibit_fetching_sync_blocks = false`. The check is targeted: it only resets the flag when `fork_rejected_until` is non-default (i.e., was set by a soft-ban), so `inhibit_fetching_sync_blocks` set for other reasons (missing sync items, old fork) is not affected. - -### B9 (Medium): `unlinkable_block_exception` Causes Infinite Resync Instead of Soft-Ban - -**Problem**: In `process_block_during_normal_operation()` (`node.cpp`), `unlinkable_block_exception` inherits from `fc::exception` but is caught by a more specific `catch` handler before the general `fc::exception` handler. The specific handler unconditionally sets `restart_sync_exception`, which triggers `start_synchronizing_with_peer()`. The `e.code() == unlinkable_block_exception::code_enum::code_value` check in the `fc::exception` handler was dead code — it could never be reached for unlinkable blocks. - -When a peer on a stale fork sends an unlinkable block at or below our head block number, the node enters an infinite resync loop: it requests blocks from the stale peer, cannot link them, requests again, etc. - -**Fix** (two-part): -1. In the `unlinkable_block_exception` catch handler, compare the peer's block number against our head. If the block is at or below our head, the peer is on a stale fork — soft-ban for 1 hour and set `inhibit_fetching_sync_blocks = true`. If the block is ahead of us, resync is justified (keep original behavior). -2. Remove the dead `unlinkable_block_exception::code_enum::code_value` check from the `fc::exception` handler, leaving only the `block_num <= head` comparison for the soft-ban decision. - -### B10 (Critical): All Real validators Must Be Disabled On Emergency Activation - -**Problem**: When emergency consensus activated, real validators retained their `signing_key` values. If they had valid signing keys but were offline, the hybrid schedule assigned them slots — but they could never produce blocks at those slots. The schedule had a mix of online committee and offline real validators, making block production unreliable. - -**Fix**: On emergency activation, **all real validators are immediately disabled**: `signing_key` set to `public_key_type()` (null), `penalty_percent` reset to 0, `counted_votes` restored to `votes`, `current_run` reset to 0. All `witness_penalty_expire_object` entries are removed. This ensures the initial schedule is all-committee (100% available). Operators must explicitly re-register validators via `witness_update_operation` transactions. - -### B11 (Critical): Schedule Crash — `get_witness("")` on Empty Schedule - -**Problem**: During emergency, the normal schedule build in `update_witness_schedule()` iterates all validators but skips any with null `signing_key`. Since B10 zeroes all keys, `sum_witnesses_count = 0` → all 21 slots are set to `account_name_type()` (empty string). The execution order was: -1. `modify(wso, ...)` — builds normal schedule (all slots zeroed) -2. `update_median_witness_props()` — iterates schedule, calls `get_witness("")` → **crash: `unknown key`** -3. Emergency hybrid override — would have filled empty slots with committee, but runs too late - -**Fix**: Moved the emergency hybrid schedule override to execute **before** `update_median_witness_props()`. The hybrid override fills empty/unavailable slots with committee first, so by the time `update_median_witness_props()` runs, all 21 slots contain valid validator names. - -### B12 (Critical): Permanently Corrupted Schedule After LIB=HEAD Commit - -**Problem**: During emergency, all 21 schedule slots point to the same committee validator. LIB computation via `nth_element` yields `last_supported_block_num == HEAD`. In `_apply_block`, the execution order is: -1. `update_last_irreversible_block()` (line ~4455) — calls `commit(HEAD)`, which **destroys the undo session** for the current block -2. `update_witness_schedule()` (line ~4466) — zeros all slots (pre-B11 fix), then crashes at `get_witness("")` - -Since `commit(HEAD)` already consumed the undo session, the zeroed schedule from step 2 was **permanently written** to shared memory with no rollback possible. On node restart, the schedule contained all empty slots, emergency mode was not re-entered, and the node couldn't produce blocks. - -**Fix** (three-part): -1. **LIB cap to HEAD−1**: During emergency, `new_last_irreversible_block_num` is capped to `head_block_number - 1`. This ensures `commit()` never catches up to the current block, preserving the undo session. -2. **Schedule override execution order** (B11 fix): Hybrid override runs before `update_median_witness_props()`, preventing the crash entirely. -3. **Startup schedule recovery**: In `database::open()`, after `init_hardforks()`, the schedule is scanned for empty slots. If found: all 21 slots are filled with committee, `emergency_consensus_active` is set to `true`, and `fork_db.set_emergency_mode(true)` is called. If the schedule is OK but emergency is active, the fork_db flag is restored (it's in-memory only and lost on restart). - -### B13 (Critical): Stack Buffer Overflow in `get_block_post_validations()` - -**Problem**: During emergency mode, the committee account fills 18 of 21 schedule slots. `get_block_post_validations()` iterates all `block_post_validation_object` entries and matches each against the schedule. For each match, it writes an entry to a fixed-size array of `CHAIN_MAX_BLOCK_POST_VALIDATION_COUNT = 20`. With the committee occupying 18 slots, each validation object generates up to 18 matches — a single object with its matching validators could write up to 18 entries per iteration. With 20 objects, this produced up to 360 writes into a 20-element array, causing a stack buffer overflow and silent segfault. - -**Fix** (two-part): -1. **Bounds check**: Break the inner loop when the result array reaches `CHAIN_MAX_BLOCK_POST_VALIDATION_COUNT`. -2. **One match per object**: Once a `block_post_validation_object` matches any schedule slot, skip remaining slots for that object. Each validation object contributes at most one entry. - -### B14 (High): P2P Sync Ping-Pong Loop in Emergency Mode - -**Problem**: In `on_fetch_blockchain_item_ids_message()` (`node.cpp`), when node A responds to node B's sync request, it checks whether it has B's last block. During emergency mode, competing forks produce different blocks at the same height — so A doesn't have B's block (and vice versa). Both nodes then call `start_synchronizing_with_peer()` for each other, which resets all tracking state and sends a new request, creating an infinite ping-pong loop. This generated hundreds of `get_block_ids()` calls per second, flooding logs and wasting CPU. - -**Fix**: Before calling `start_synchronizing_with_peer()`, compare the peer's block number (extracted via `block_header::num_from_id()`) against our head block number. Only restart sync if `peer_block_num > our_head_num` (peer is genuinely ahead). When `peer_block_num <= our_head_num`, the peer is on a competing fork at the same height — skip the restart. - -### B15 (Medium): Sync Spam Soft-Ban for Old Peers - -**Problem**: After the B14 fix, the local node no longer amplifies the sync loop. However, old peers (without the B14 fix) continue flooding the node with `fetch_blockchain_item_ids_message` requests from their own unpatched ping-pong loops. Each request triggers `get_block_ids()` on the server side — harmless but wasteful (CPU, log noise). - -**Fix**: Added sync spam detection with soft-ban in `on_fetch_blockchain_item_ids_message()`: -1. At the top of the handler, check `fork_rejected_until` — silently discard requests from already-banned peers (skips `get_block_ids()` entirely). -2. In both competing-fork branches (where `peer_block_num <= our_head_num`), increment a per-peer `sync_spam_strikes` counter. -3. After 50 strikes, set `fork_rejected_until = now + 300s` (5 minute soft-ban). Reset strikes on legitimate sync (peer genuinely ahead). -4. At the observed spam rate (~23 requests per 4ms burst), the threshold is hit in under 1 second. - -### B16 (High): Null validator Signing Key Crashes Block Validation - -**Problem**: When a validator has a null/empty `signing_key` (disabled via `shutdown_witness_operation` or emergency activation), and a block from that validator arrives via P2P, `validate_block_header()` calls `validate_signee(validator.signing_key)` with the empty key. The elliptic curve library crashes with `my->_key != empty_pub` deep inside `serialize()` — an opaque assertion that gives no indication of the root cause. The node then enters an infinite retry loop: gap fill requests the same block, receives it, rejects it with the crash, requests it again. - -**Fix** (two parts): -1. **Clear error message**: Added a pre-check in `validate_block_header()` before `validate_signee()` that catches `validator.signing_key == public_key_type()` and throws a descriptive `FC_ASSERT` naming the validator and block number. -2. **Gap fill blacklist**: Added rejection tracking in the DLT P2P node. When the same block is rejected 3 times (from any combination of broadcast + gap fill), gap fill is blacklisted for 120 seconds, breaking the infinite retry loop. - -### B17 (Critical): Emergency validator Blanking Was Non-Consensus - -**Problem**: The emergency validator blanking logic in `update_witness_schedule()` used `_emergency_round_start_gap` — a local `std::map` that is NOT consensus state. It was populated at runtime and not stored in shared memory. Different nodes could compute different values depending on startup timing, replay history, and when they entered emergency mode. This meant two nodes could reach different conclusions about whether to blank a validator's signing key, causing chain divergence. - -**Fix**: Replaced the non-consensus approach with the same deterministic pattern used in normal mode. Key-blanking now happens in `update_global_dynamic_data()` (the consensus path) and checks `head_block_num() - last_confirmed_block_num > CHAIN_EMERGENCY_MAX_WITNESS_MISSED_BLOCKS` (105). Both values are on-chain consensus fields in `witness_object` shared memory — all nodes compute identical results. Removed `_emergency_round_start_gap` entirely. - -### Committee Neutral Voter Design - -After all fixes, the committee validator has these properties: - -| Field | Value | Rationale | -|---|---|---| -| `signing_key` | `CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY` | Required for block production | -| `running_version` | `CHAIN_VERSION` | Matches the binary | -| `hardfork_version_vote` | `current_hardfork_version` | Votes for status quo, not future hardforks | -| `hardfork_time_vote` | `processed_hardforks[last_hardfork]` | Time the current hardfork was applied | -| `props` | `median_props` (current) | Copies current median, doesn't skew it | -| `schedule` | `top` | Required for hybrid schedule assignment | - -The committee's props and hardfork vote are re-synced every schedule update (`update_witness_schedule()`) to stay aligned with the latest median and hardfork state. - ---- - -## Emergency Key Threat Model - -### Key Distribution - -The emergency private key is **publicly known**. It is not a secret. Any node operator can configure it via `emergency-private-key` in their config. The corresponding public key is hardcoded in `config.hpp`: - -``` -VIZ75CRHVHPwYiUESy1bgN3KhVFbZCQQRA9jT6TnpzKAmpxMPD6Xv -``` - -### Who Has the Key - -**Everyone who wants it.** The key is published in: -- Source code (`config.hpp`) -- Config template (`config_witness.ini`) -- Documentation - -Any node running the Validator Plugin with `emergency-private-key` configured will attempt to produce blocks during emergency mode. This is by design — the goal is maximum availability during a network stall, not access control. - -### How Many Nodes Have It - -In practice: **every public validator node** should have it configured. During emergency: -- Multiple nodes may attempt to produce at the same slot. -- Hash tie-breaking (lowest `block_id` wins) ensures deterministic convergence. -- Fork collision check causes all but one node to back off after the first slot. -- The result is functionally equivalent to a single producer, achieved through distributed consensus rather than central coordination. - -### Compromise Scenario - -**The key cannot be "compromised" in the traditional sense** because it is already public. However, there are attack scenarios: - -| Attack | Impact | Mitigation | -|---|---|---| -| Attacker produces emergency blocks during normal operation | **None.** Emergency mode only activates when `seconds_since_lib >= 3600`. During normal operation, the schedule does not contain `committee`, so the attacker's blocks are invalid (wrong scheduled validator). | Consensus-level gating | -| Attacker produces blocks during real emergency | Blocks are valid but **compete equally** with other emergency producers. Hash tie-breaking resolves conflicts deterministically. The attacker cannot produce *more* blocks than any other node with the key. | Hash tie-breaking + fork collision check | -| Attacker produces blocks with invalid transactions | **Rejected.** Full consensus validation still applies to emergency blocks. Invalid operations, double-spends, etc. are caught by `apply_block()`. | Standard block validation | -| Attacker floods P2P with emergency blocks | **Mitigated.** P2P anti-spam (`fork_rejected_until`) soft-bans peers sending blocks on rejected forks for 15 minutes (5 minutes for trusted peers). Sync request spam is detected separately: 50 repeated competing-fork sync requests trigger a 5-minute soft-ban, silently discarding further requests. Fork collision check limits production to 1 block per slot. After soft-ban expires, `inhibit_fetching_sync_blocks` is automatically reset (B8 fix) so the peer remains available for sync. | P2P soft-ban + sync spam ban + fork collision + auto-reset | - -### Key Rotation - -**No rotation needed or supported.** Rationale: -- The key has no value outside emergency mode (it cannot sign normal blocks). -- Rotation would require a hardfork (the public key is in `config.hpp` as a consensus constant). -- There is zero security benefit from rotation — the key is public by design. -- All nodes must agree on the same key, so any change requires coordinated network upgrade. - -### Can Emergency Produce Non-Empty Blocks? - -**Yes, and this is required.** Emergency blocks must allow transactions because: -1. validators need to broadcast `witness_update_operation` to re-register their signing key during recovery. -2. If emergency blocks were forced empty, validators couldn't re-activate → deadlock where emergency never exits. -3. In practice, most emergency blocks will be empty (low transaction volume during a stall), but the mechanism **must not** prohibit transactions. - -### Summary - -The emergency key is a **public coordination mechanism**, not a secret. Its security model is: -- **Deterministic activation**: Uses only signed block timestamps (`b.timestamp - lib_block.timestamp ≥ 3600`), no config flags or wall-clock time — identical results on every node and during every replay -- **Activation gating**: Only usable when `emergency_consensus_active == true` (requires 1-hour LIB stall) -- **Snapshot safety**: When LIB block is unavailable (post-snapshot restore), emergency check is skipped to prevent false activation -- **Convergence**: Hash tie-breaking + fork collision → single effective producer -- **Validation**: Full consensus rules apply to emergency blocks -- **Deactivation**: Automatic when 75% (16/21) of schedule slots are real validators with valid signing keys -- **Scope**: Delegates can immediately re-activate through wallets/services once their nodes reconnect to the P2P network, because the emergency chain is public and accepts transactions - ---- - -## Test Matrix - -All scenarios should be tested before deployment. Each test specifies preconditions, actions, expected outcomes, and the emergency subsystem components exercised. - -### T1: Simple Stall → Emergency → Recovery - -| | | -|---|---| -| **Precondition** | 21 validators active, network healthy | -| **Action** | Shut down all 21 validators. Wait >1 hour. Start 1 node with emergency key. Gradually restart validators. | -| **Expected** | Emergency activates at LIB+3600s. All real validators disabled (signing_key zeroed). Committee produces blocks (full 21-slot schedule). LIB advances every block (capped at HEAD−1). Offline validators do NOT accumulate penalties. Committee props synced to median, hardfork vote synced to current version. validators re-register via `witness_update_operation`. When 16+ real validators have valid signing keys in schedule (75%) → emergency exits automatically. | -| **Components** | Activation, validator disabling, hybrid schedule (full expansion), LIB advancement (capped at HEAD−1), penalty skip, committee neutral voter, exit condition (75% real validators) | - -### T2: 2-Way Partition (Majority/Minority) - -| | | -|---|---| -| **Precondition** | 21 validators, healthy network | -| **Action** | Partition: 16 validators on side A, 5 on side B. | -| **Expected** | Side A: participation >75% → continues normally, no emergency. Side B: participation drops to ~24% → production stops (below 33% threshold). After 1 hour, emergency activates on side B. On reconnect, side A's chain wins (higher vote weight from 16 real validators). Side B unwinds emergency blocks. | -| **Components** | Three-state safety (healthy vs distressed), vote-weighted comparison, fork resolution | - -### T3: 2-Way Partition (Even Split, Both Enter Emergency) - -| | | -|---|---| -| **Precondition** | 21 validators, healthy network | -| **Action** | Partition: 10 validators on A, 11 on B. Neither side has 75% → both stall. Wait 1 hour → both enter emergency. Reconnect after 2 hours. | -| **Expected** | Both sides produce emergency+hybrid blocks. LIB advances (capped at HEAD−1) on both. On reconnect, vote-weighted comparison: side with higher total `votes` wins. Losing side unwinds. Emergency exits when 16+ real validators have valid keys in the merged schedule. | -| **Components** | LIB advancement (capped), vote-weighted comparison, fork_db expansion, partition merge | - -### T4: 3-Way Partition - -| | | -|---|---| -| **Precondition** | 21 validators, healthy network | -| **Action** | Partition into 3 groups: 7+7+7 validators. All stall → all enter emergency. Reconnect sequentially (A↔B first, then AB↔C). | -| **Expected** | Each partition produces emergency blocks independently. LIB advances (capped at HEAD−1) on all. First merge (A↔B): vote-weighted comparison picks winner. Second merge (AB↔C): vote-weighted comparison again. Final chain has highest cumulative vote weight. | -| **Components** | Multi-partition merge, vote-weighted comparison, cascading fork resolution, LIB advancement (capped) | - -### T5: Late Peer Rejoin - -| | | -|---|---| -| **Precondition** | Emergency active for 2 hours. 10 validators already back. | -| **Action** | validator #11 comes online with stale chain (2 hours behind). | -| **Expected** | Peer syncs from the emergency chain. Once synced, validator re-registers via `witness_update_operation`. Their slot appears in hybrid schedule on next update. validator produces at its assigned slot. LIB on the emergency chain is at HEAD−1, so only 1 reversible block exists — sync is fast. | -| **Components** | P2P sync during emergency, hybrid schedule, LIB advancement (capped), validator re-registration | - -### T6: Conflicting Emergency Producers - -| | | -|---|---| -| **Precondition** | Emergency active. 5 nodes with emergency key, well-connected. | -| **Action** | All 5 attempt to produce at slot N simultaneously. | -| **Expected** | Each produces a valid block with different `block_id`. Nodes receive competing blocks. Hash tie-breaking: lowest `block_id` wins on all nodes. Fork collision check: at slot N+1, nodes see existing block → only 1 (or 0) produces. By slot N+2, a single producer dominates. | -| **Components** | Hash tie-breaking, fork collision check, deterministic convergence | - -### T7: Long Emergency > Undo Horizon - -| | | -|---|---| -| **Precondition** | All validators offline. Emergency active. | -| **Action** | Let emergency run for 8+ hours (well beyond old undo limit). | -| **Expected** | LIB advances every block (capped at HEAD−1), so HEAD−LIB gap stays at exactly 1. fork_db size stays at 2 blocks. Emergency runs indefinitely without hitting any undo limits. No degradation over time. | -| **Components** | LIB advancement (capped at HEAD−1), fork_db sizing, indefinite emergency operation | - -### T8: validator Shutdown + Re-registration During Emergency - -| | | -|---|---| -| **Precondition** | Emergency active. All validators had `signing_key` nullified by missed-block shutdown. | -| **Action** | validator operator broadcasts `witness_update_operation` via CLI wallet during emergency. | -| **Expected** | Transaction included in emergency block. validator object updated with new signing key. Next schedule update: validator gets their slot in hybrid schedule instead of committee. validator begins producing. Offline validators do NOT get `signing_key` nullified again during emergency (penalty/shutdown skipped). | -| **Components** | Transaction processing during emergency, hybrid schedule update, penalty skip during emergency | - -### T9: Snapshot Restore + Emergency Interaction - -| | | -|---|---| -| **Precondition** | Snapshot taken during emergency mode (`emergency_consensus_active = true`). | -| **Action** | Restore snapshot on a fresh node. Start node with Validator Plugin and emergency key. | -| **Expected** | Snapshot import reads `emergency_consensus_active` and `emergency_consensus_start_block` from DGP (forward-compatible). Node resumes in emergency mode. Produces emergency blocks. Standard exit condition applies. **No false activation**: block_log is empty after snapshot restore, so `fetch_block_by_number(LIB)` returns invalid, but the emergency check is skipped (not triggered by fallback to genesis_time). | -| **Components** | Snapshot import (forward-compatible fields), emergency state persistence, B7 fix (no false activation on empty block_log) | - -### T10: Snapshot From Pre-HF12 Node - -| | | -|---|---| -| **Precondition** | Snapshot taken before HF12 (no emergency fields in DGP). | -| **Action** | Restore on HF12 node. | -| **Expected** | Snapshot import defaults `emergency_consensus_active = false`, `emergency_consensus_start_block = 0`. Node starts in normal mode. Emergency detection works normally after HF12 activation. | -| **Components** | Snapshot forward-compatibility, default field handling | - -### T11: Healthy Network After HF12 (No Regression) - -| | | -|---|---| -| **Precondition** | HF12 active. All 21 validators online. Network healthy. | -| **Action** | Normal operation for extended period. Occasional validator restarts. | -| **Expected** | Emergency never activates (LIB advances every few seconds). Three-state safety: healthy mode enforces safe defaults regardless of `enable-stale-production` config. Vote-weighted comparison active but functionally equivalent to longest-chain (same validators on both sides of any micro-fork). Committee exclusion in hardfork tally and median props is a no-op (committee not in schedule). | -| **Components** | No-regression, three-state safety (healthy mode), vote-weighted comparison | - -### T12: `enable-stale-production` Ignored in Healthy Mode - -| | | -|---|---| -| **Precondition** | HF12 active. All validators online. Operator has `enable-stale-production = true` (forgot to revert from pre-HF12). | -| **Action** | Network partition isolates this validator. | -| **Expected** | Participation rate ≥33% → healthy mode → `enable-stale-production` is **ignored**. validator stops producing when it detects it's isolated (no recent blocks). **This is the core micro-fork prevention feature.** | -| **Components** | Three-state safety (healthy mode auto-enforces safe defaults) | - -### T13: Partial validator Set (11 Top validators on 1 Node) - -| | | -|---|---| -| **Precondition** | Network stalled >1 hour. 1 node with 11 top validators + emergency key. 10 other validators offline. | -| **Action** | Emergency activates. 11 real validators produce at their slots. Committee fills the other 10 slots. Over time, other validators re-join. | -| **Expected** | All validators initially disabled (signing_key zeroed). 11 validators re-register via `witness_update_operation`. Hybrid schedule expands to full 21 slots (11 real + 10 committee). Committee validator has `props = median_props` and `hardfork_version_vote = current_hardfork_version` — neutral voter. Hardfork vote tally excludes committee (only 11 real votes counted). Median props computed from real validators only. Offline validators don't accumulate penalties. When 16+ real validators have valid signing keys in schedule (75% of 21) → emergency exits automatically. | -| **Components** | validator disabling, hybrid schedule expansion, committee neutral voter, hardfork tally exclusion, median props exclusion, penalty skip, exit condition (75% real validators) | - -### T14: Committee Hardfork Vote Neutrality - -| | | -|---|---| -| **Precondition** | Emergency active. Binary version includes a pending hardfork (e.g., HF13) that has not been applied on-chain yet. 11 real validators running HF13 binary. | -| **Action** | Committee produces blocks. Verify committee's on-chain `hardfork_version_vote` stays at the current applied version. | -| **Expected** | Committee's block headers do NOT contain `hardfork_version_vote` extensions. `process_header_extensions()` does not update the committee's on-chain vote. Committee vote stays at `current_hardfork_version` (e.g., HF12). Only real validators' votes count toward HF13 adoption (need 17 of them). Committee props/hardfork vote re-synced every schedule update. | -| **Components** | Hardfork vote auto-injection skip, process_header_extensions, committee props sync | - -### T15: Snapshot Restore Does Not False-Activate Emergency - -| | | -|---|---| -| **Precondition** | Network healthy. Snapshot taken from a healthy state (`emergency_consensus_active = false`). | -| **Action** | Restore snapshot on a fresh node (block_log empty). Start syncing from p2p. | -| **Expected** | First block from p2p: `fetch_block_by_number(LIB)` returns invalid (block_log empty). `lib_time_available = false`. Emergency check is **skipped**. Node processes the block normally. No false activation, no committee validator created, no penalties reset. Node syncs normally. | -| **Components** | B7 fix (lib_time_available guard), snapshot restore, block_log interaction | - -### T16: Soft-Ban `inhibit_fetching_sync_blocks` Reset After Expiry - -| | | -|---|---| -| **Precondition** | Emergency active. Node soft-banned a peer 1 hour ago (`fork_rejected_until` set, `inhibit_fetching_sync_blocks = true`). | -| **Action** | The soft-ban expires. Peer sends a valid block. | -| **Expected** | `fork_rejected_until` is in the past → block is processed (not discarded). `inhibit_fetching_sync_blocks` is reset to `false` (B8 fix). Node resumes requesting sync inventory from this peer. Gradual peer loss during extended emergency is prevented. | -| **Components** | B8 fix (inhibit flag reset on soft-ban expiry), P2P soft-ban lifecycle, sync operations | - -### T17: Startup Schedule Recovery (B12 Fix) - -| | | -|---|---| -| **Precondition** | Node crashed during emergency with corrupted schedule (all empty validator slots in shared memory). | -| **Action** | Restart the node. | -| **Expected** | `database::open()` detects empty slots in schedule. Fills all 21 slots with committee. Sets `emergency_consensus_active = true` if not already set. Restores `fork_db.set_emergency_mode(true)`. Node resumes producing emergency blocks. LIB advances normally (capped at HEAD−1). | -| **Components** | Startup recovery (B12), schedule repair, fork_db flag restoration | - -### T18: Emergency fork_db Flag Restored On Normal Restart - -| | | -|---|---| -| **Precondition** | Emergency active, schedule is healthy (all committee slots). Node restarted cleanly. | -| **Action** | Restart the node. | -| **Expected** | `database::open()` sees schedule is OK but `emergency_consensus_active == true` in DGP. Calls `fork_db.set_emergency_mode(true)` to restore the in-memory flag. Node continues in emergency mode without interruption. | -| **Components** | Startup recovery (fork_db flag), DGP state persistence | - -### T19: Block Post-Validation During Emergency (B13 Fix) - -| | | -|---|---| -| **Precondition** | Emergency active. Committee fills 18/21 schedule slots. Multiple `block_post_validation_object` entries exist. | -| **Action** | Call `get_block_post_validations()` (triggered by P2P block validation). | -| **Expected** | Result array stays within `CHAIN_MAX_BLOCK_POST_VALIDATION_COUNT = 20` bounds. Each validation object produces at most one entry (no duplicate committee matches). No stack overflow, no segfault. | -| **Components** | B13 fix (bounds check + one-match-per-object), `get_block_post_validations()` | - -### T20: P2P Sync Ping-Pong Loop Prevention (B14 Fix) - -| | | -|---|---| -| **Precondition** | Emergency active. Two nodes (A, B) with competing forks at the same height. Both have the B14 fix. | -| **Action** | A sends sync request to B. B responds. Observe whether `start_synchronizing_with_peer()` is called. | -| **Expected** | B sees A's last block is at the same height as B's head (`peer_block_num == our_head_num`). B does NOT call `start_synchronizing_with_peer()`. No ping-pong loop. `get_block_ids()` is called once per request, not hundreds of times per second. | -| **Components** | B14 fix (block-number comparison guard), `on_fetch_blockchain_item_ids_message()` | - -### T21: Sync Spam Soft-Ban (B15 Fix) - -| | | -|---|---| -| **Precondition** | Emergency active. Node has B14+B15 fixes. Connected to old peers without B14 fix. | -| **Action** | Old peers flood the node with `fetch_blockchain_item_ids_message` requests (competing fork at same height). | -| **Expected** | First 50 requests are processed normally (each incrementing `sync_spam_strikes`). At strike 50, peer is soft-banned for 5 minutes (`fork_rejected_until` set). Subsequent requests are silently discarded at the top of `on_fetch_blockchain_item_ids_message()` — no `get_block_ids()` calls. After 5 minutes, ban expires and strikes reset if peer sends legitimate sync requests. | -| **Components** | B15 fix (sync spam strikes + soft-ban), `fork_rejected_until` reuse, `on_fetch_blockchain_item_ids_message()` | diff --git a/.qoder/docs/emergency-consensus-workflow.md b/.qoder/docs/emergency-consensus-workflow.md deleted file mode 100644 index 35a4662a1f..0000000000 --- a/.qoder/docs/emergency-consensus-workflow.md +++ /dev/null @@ -1,711 +0,0 @@ -# Emergency Consensus Mode — Full Workflow Tree - -Comprehensive analysis of the emergency consensus system introduced in Hardfork 12. Covers all processes, code paths, component interactions, and guard conditions across the entire node codebase. - ---- - -## 1. Overview - -Emergency consensus mode activates when the network has stalled for 1 hour (no blocks have been accepted since the Last Irreversible Block timestamp). During emergency, a special "committee" validator produces blocks to maintain chain continuity. Once enough real validators re-enable their signing keys (\(\ge\) 75% of schedule slots), emergency mode auto-deactivates. - -### Key Constants - -| Constant | Value | Meaning | -|----------|-------|---------| -| `CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC` | 3600 | Seconds since LIB before activation | -| `CHAIN_EMERGENCY_WITNESS_ACCOUNT` | `"committee"` | Emergency block producer | -| `CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY` | `VIZ75CR...` | Deterministic signing key | -| `CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS` | 21 | Consecutive real-validator blocks for exit | -| `CHAIN_IRREVERSIBLE_THRESHOLD` | 75% (`75 * CHAIN_1_PERCENT`) | Required to advance LIB / exit emergency | -| `CHAIN_MAX_WITNESSES` | 21 | Maximum unique validator slots | -| `CHAIN_HARDFORK_12` | Hardfork #12 | Gates all emergency logic | - -### System State - -Two dynamic global property fields track emergency state: - -| Field | Type | Default | Meaning | -|-------|------|---------|---------| -| `emergency_consensus_active` | `bool` | `false` | Is emergency mode active? | -| `emergency_consensus_start_block` | `uint32_t` | `0` | Block number at activation | - ---- - -## 2. Complete Workflow Trees - -### 2A. Emergency Activation - -**Location:** [`database::update_global_dynamic_data()`](file://libraries/chain/database.cpp#L5059-L5200) — runs on every applied block. - -``` -Block applied (update_global_dynamic_data) - │ - ├── Gate: has_hardfork(CHAIN_HARDFORK_12)? - │ └── No → RETURN (emergency mode not possible) - │ - ├── Gate: _dgp.emergency_consensus_active? - │ └── Yes → RETURN (already active, skip re-activation) - │ - ├── Gate: LIB block available in block_log? - │ ├── LIB num == 0 → skip (no LIB) - │ ├── fetch_block_by_number(LIB) invalid → skip (snapshot restore) - │ └── LIB block found in block_log → proceed - │ Reason: DLT nodes with empty block_log after snapshot would - │ see millions of seconds since genesis → false activation → deadlock - │ - ├── Compute: seconds_since_lib = b.timestamp - lib_block.timestamp - │ - ├── Gate: seconds_since_lib >= CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC (3600)? - │ └── No → RETURN (network still within grace period) - │ - └── === ACTIVATION SEQUENCE === - │ - ├── 1. Set emergency flags on DGP: - │ dgp.emergency_consensus_active = true - │ dgp.emergency_consensus_start_block = b.block_num() - │ - ├── 2. Create/Update emergency validator object: - │ ├── validator "committee" exists? - │ │ ├── No → create: - │ │ │ owner = "committee" - │ │ │ signing_key = CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY - │ │ │ running_version = CHAIN_VERSION - │ │ │ hardfork votes = current applied hf version (neutral) - │ │ │ props = current median_props - │ │ └── Yes → modify existing: - │ │ signing_key = CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY - │ │ schedule = top - │ │ sync version + hardfork votes + props - │ │ - │ ├── 3. Disable ALL real validators: - │ │ For each validator (except committee): - │ │ signing_key = zero (public_key_type()) - │ │ penalty_percent = 0 - │ │ counted_votes = votes - │ │ current_run = 0 - │ │ - │ ├── 4. Remove ALL penalty expiration objects - │ │ - │ ├── 5. Override validator schedule: - │ │ All num_scheduled_witnesses slots → "committee" - │ │ next_shuffle_block_num = head + num_scheduled - │ │ - │ ├── 6. Notify fork_db: - │ │ _fork_db.set_emergency_mode(true) - │ │ → enables deterministic hash tie-breaking - │ │ - │ └── 7. Log: - │ "EMERGENCY CONSENSUS MODE activated at block #N. - │ No blocks for X seconds since LIB Y." - │ - └── Determinism guarantee: uses ONLY block-embedded data - (b.timestamp, lib_block.timestamp). No wall-clock, no skip flags. -``` - ---- - -### 2B. Emergency Deactivation (Exit Condition) - -**Location:** [`database::update_witness_schedule()`](file://libraries/chain/database.cpp#L2689-L2791) — runs on every schedule boundary. - -``` -update_witness_schedule() - │ - ├── 1. Build normal validator schedule - │ (may have empty slots if validators have zero signing_key) - │ - ├── Gate: has_hardfork(HF12) && emergency_consensus_active? - │ └── No → skip hybrid override, proceed with normal schedule - │ - └── === HYBRID SCHEDULE OVERRIDE === - │ - ├── For each slot i in [0, CHAIN_MAX_WITNESSES) (by CHAIN_BLOCK_WITNESS_REPEAT): - │ ├── Slot name == "" ? - │ │ └── Fill slot + repeats with "committee" → committee_slots++ - │ ├── validator has signing_key != zero ? - │ │ └── Keep validator → real_witness_slots++ - │ └── validator unavailable (key=0 or not found)? - │ └── Fill slot + repeats with "committee" → committee_slots++ - │ - ├── Expand: num_scheduled_witnesses = CHAIN_MAX_WITNESSES × REPEAT - ├── Set: next_shuffle_block_num = head + num_scheduled - ├── Log: "Emergency hybrid schedule: R real, C committee slots" - │ - ├── Sync committee validator: - │ props = current median_props - │ hardfork votes = current applied version (neutral voter) - │ - └── === EXIT CHECK === - ├── exit_threshold = (CHAIN_MAX_WITNESSES × 75%) / 100 (= 15) - ├── real_witness_slots >= exit_threshold? - │ ├── No → emergency continues (not enough real validators) - │ └── Yes → DEACTIVATE: - │ ├── dgp.emergency_consensus_active = false - │ ├── _fork_db.set_emergency_mode(false) - │ └── Log: "EMERGENCY CONSENSUS MODE deactivated at block #N. - │ R real validators active (threshold: T)." - │ - └── After deactivation: validators with restored keys produce normally -``` - ---- - -### 2C. validator Block Production in Emergency Mode - -**Location:** [`witness_plugin::maybe_produce_block()`](file://plugins/validator/validator.cpp#L468-L870) - -``` -maybe_produce_block() {now = NTP + 250ms} - │ - ├── === DLT MODE SYNC CHECK === - │ │ - │ ├── NOT DLT mode OR NOT syncing? → continue - │ │ - │ └── DLT mode AND syncing? - │ ├── IS emergency master? (emergency key in _witnesses) - │ │ └── Yes → BYPASS sync check (deadlock prevention — p18.log) - │ └── NOT emergency master (slave) - │ └── Return not_synced (producing on stale head creates - │ double-production collisions — p32.log) - │ - ├── === HARDFORK 12 THREE-STATE SAFETY === - │ │ - │ ├── emergency_consensus_active? - │ │ └── Yes → EMERGENCY PATH: - │ │ ├── IS emergency master? (emergency key in _witnesses) - │ │ │ └── Yes → _production_enabled = true (bypass stale + participation) - │ │ ├── NOT emergency master (slave): - │ │ │ ├── _production_enabled already? → continue - │ │ │ └── Else: check get_slot_time(1) >= now - │ │ │ ├── Yes → _production_enabled = true - │ │ │ └── No → return not_synced - │ │ └── _witnesses.empty()? - │ │ └── Yes → ERROR: "no validators configured" - │ │ - │ ├── Not emergency, participation >= 33%? - │ │ └── Yes → HEALTHY PATH: - │ │ ├── Clear stale-production skip flag - │ │ └── Enable production if slot_time(1) >= now - │ │ - │ └── Not emergency, participation < 33%? - │ └── DISTRESSED PATH: - │ ├── Honor enable-stale-production override - │ └── Else: check sync + participation normally - │ - ├── Block post-validation broadcast (every validator we have, scheduled only) - │ - ├── === MINORITY FORK DETECTION === - │ │ - │ ├── NOT emergency: standard 21-block check - │ │ └── All 21 blocks from our validators? - │ │ ├── stale-production enabled → continue - │ │ └── stale-production disabled → resync_from_lib() - │ │ - │ ├── Emergency + DLT + IS MASTER: - │ │ └── SKIP minority fork check entirely - │ │ (all blocks being "ours" is expected for master) - │ │ - │ └── Emergency + DLT + NOT MASTER (follower): - │ └── 21-block check (1 full round via CHAIN_MAX_WITNESSES) - │ └── All 21 blocks from our validators? - │ └── Yes → DLT EMERGENCY MINORITY FORK: - │ resync_from_lib() [but see guard in §2G below] - │ - ├── Slot assignment check: - │ ├── get_slot_at_time(now) == 0? → not_time_yet - │ ├── scheduled_witness not ours? → not_my_turn - │ ├── scheduled_key == zero? → not_my_turn - │ └── Don't have private key? → no_private_key - │ - ├── Timing: |scheduled_time - now| > 500ms? → lag - │ - ├── === FORK COLLISION === - │ │ - │ ├── Emergency mode: ANY block at this height IS competing - │ │ → defer to fork_db deterministic hash resolution - │ │ - │ └── Normal mode: only different validator + different parent - │ → vote-weight comparison - │ - └── generate_block() with committee private key -``` - -#### Deferred Block Notifications - -`notify_applied_block()` is deferred outside the write-lock scope in `push_block()`: - -``` -push_block(new_block) - │ - ├── _defer_block_notifications = true - │ - ├── with_strong_write_lock(): - │ └── _push_block() → _apply_block() - │ └── notify_applied_block deferred: - │ _pending_block_notifications.push_back(block) - │ - ├── [on exception]: - │ └── Clear pending, re-throw - │ - ├── _defer_block_notifications = false - │ - └── flush_pending_block_notifications() - └── For each pending block: - notify_applied_block(block) ← no write lock held -``` - -**Why:** Plugin callbacks (MongoDB, operation_history, account_history) can take -seconds. Holding the write lock during notification blocks ALL P2P and RPC -threads (p32.log: 13.8s lock hold). Deferring releases the lock first, allowing -concurrent reads while plugins process at their own pace. - -**Replay path:** `apply_block()` (public, called during replay) does NOT set -`_defer_block_notifications`, so notifications are delivered immediately — same -as before (no contention during replay). - -**Exception safety:** If `push_block()` throws, pending notifications are discarded -(those blocks were rolled back by the undo stack). - -#### Master/Follower Detection (DLT Emergency) - -``` -Is this node the DLT emergency master? - │ - ├── Condition A: CHAIN_EMERGENCY_WITNESS_ACCOUNT ("committee") in _witnesses? - │ └── Only true when --emergency-private-key is configured - │ - ├── Condition B: "committee" is in the current schedule? - │ (check current_shuffled_witnesses for committee account) - │ - └── A AND B → IS MASTER (produces blocks, others sync from us) - NOT A OR NOT B → IS FOLLOWER (relies on P2P sync from master) -``` - ---- - -### 2D. Fork Database — Emergency Deterministic Tie-Breaking - -**Location:** [`fork_database::_push_block()`](file://libraries/chain/fork_database.cpp#L77-L88) - -``` -fork_db._push_block(item) - │ - ├── Validate linkage (parent must be in _index) - ├── Insert into _index - │ - └── Update _head: - ├── item->num > _head->num? - │ └── Yes → _head = item (longer chain wins, normal) - │ - └── item->num == _head->num AND _emergency_consensus_active? - ├── item->id < _head->id? - │ └── Yes → _head = item (lower hash wins, deterministic) - └── No → keep current _head -``` - -**Purpose:** When multiple emergency nodes produce at the same height (all using the same committee key), arrival order varies by P2P topology. Deterministic hash comparison ensures all nodes converge on the same chain tip regardless of which block they saw first. - ---- - -### 2E. LIB Advancement During Emergency - -**Location:** [`database::update_last_irreversible_block()`](file://libraries/chain/database.cpp#L5686-L5740) - -``` -update_last_irreversible_block() - │ - ├── Normal LIB computation: - │ ├── Collect validator objects for all schedule slots - │ ├── nth_element by last_supported_block_num - │ └── new_lib = wit_objs[offset]->last_supported_block_num - │ where offset = (100% - 75%) × num_witnesses / 100% - │ - ├── === EMERGENCY LIB CAP === - │ │ - │ └── emergency AND new_lib >= head_block_num? - │ ├── Yes → cap to head - 1 - │ │ Reason: During emergency all slots = committee. - │ │ Committee's last_supported_block_num == HEAD. - │ │ nth_element returns HEAD → commit(HEAD) destroys - │ │ current block's undo session → crash during _apply_block - │ │ would leave permanently corrupted state (zeroed schedule). - │ └── No → use computed value - │ - ├── Committee validator: current_run advances by CHAIN_BLOCK_WITNESS_REPEAT each block - │ → after 3 blocks (CHAIN_IRREVERSIBLE_SUPPORT_MIN_RUN), LIB moves every block - │ → gap between LIB and HEAD stays small → fork_db won't overflow - │ - └── === BLOCK POST VALIDATION CHAIN === - └── emergency? → return early (don't advance LIB via BPV during emergency) -``` - ---- - -### 2F. Startup Recovery — Schedule Repair - -**Location:** [`database::open()`](file://libraries/chain/database.cpp#L315-L356) - -``` -database::open() — after replay/reindex - │ - ├── Read startup DGP + witness_schedule_object - │ - ├── Scan schedule for empty slots: - │ └── Any current_shuffled_witnesses[i] == "" ? - │ │ - │ ├── Yes → EMERGENCY SCHEDULE RECOVERY: - │ │ ├── If !emergency_active → activate emergency + fork_db flag - │ │ ├── Fill ALL slots (CHAIN_MAX_WITNESSES × REPEAT) with "committee" - │ │ ├── num_scheduled_witnesses = CHAIN_MAX_WITNESSES × REPEAT - │ │ ├── next_shuffle_block_num = head + num_scheduled - │ │ └── Log: "schedule repaired, all N slots set to committee" - │ │ - │ └── No, but emergency_active → restore fork_db.set_emergency_mode(true) - │ - └── Continue normal startup -``` - ---- - -### 2G. P2P Stale Sync Detection — Emergency Awareness - -**Location:** [`p2p_plugin::stale_sync_check_task()`](file://plugins/p2p/p2p_plugin.cpp#L1056-L1090) - -``` -stale_sync_check_task() {every 30s} - │ - ├── elapsed = now - _last_block_received_time - ├── elapsed > 120s? - │ └── No → reschedule - │ - ├── === EMERGENCY GUARD === - │ │ - │ ├── Read emergency_consensus_active from DGP - │ │ - │ └── emergency active? - │ ├── Yes + current_head > _last_stale_check_head: - │ │ └── Head is advancing → MASTER is producing - │ │ ├── Reset _last_block_received_time = now - │ │ ├── _last_stale_check_head = current_head - │ │ └── skip_recovery = true - │ │ - │ └── Yes + head is STUCK: - │ └── FOLLOWER lost sync with master - │ └── Allow recovery to proceed - │ (logs warning: "head is stuck — triggering recovery") - │ - └── Recovery (if !skip_recovery): - ├── sync_from(LIB block ID) - ├── resync() → full peer state reset + start_synchronizing() - └── Reconnect seed nodes -``` - ---- - -### 2H. `resync_from_lib()` Emergency Guard - -**Location:** [`p2p_plugin::resync_from_lib()`](file://plugins/p2p/p2p_plugin.cpp#L1458-L1484) - -``` -resync_from_lib() — called from minority fork detection - │ - ├── === EMERGENCY GUARD === - │ │ - │ └── emergency_consensus_active? - │ ├── Yes → SKIP entirely, log warning: - │ │ "SKIPPING during emergency consensus mode. - │ │ Emergency fork must not be unwound." - │ │ - │ │ Reason: During emergency, LIB is close to HEAD. - │ │ Popping blocks + fork_db reset → peer blocks from - │ │ real network may link to re-seeded LIB → fork switch - │ │ → pop below committed LIB → infinite loop or crash. - │ │ - │ └── No → continue with normal resync flow - │ - └── Normal flow: - ├── Pop all reversible blocks back to LIB - ├── Reset fork_db, seed with LIB block - ├── sync_from(LIB block ID) - ├── resync() → peer state reset - └── Reconnect seed nodes -``` - ---- - -### 2I. Block Validation — Relaxed Slot Mapping - -**Location:** [`database::verify_signing_witness()`](file://libraries/chain/database.cpp#L4884-L4896) - -``` -verify_signing_witness(next_block) - │ - ├── Normal mode: FC_ASSERT(validator.owner == scheduled_witness) - │ └── "validator produced block at wrong time" - │ - └── Emergency mode: - └── If block.validator != scheduled_witness: - └── dlog (debug, not assertion) - "Emergency mode: accepting block from BW at slot scheduled for SW" - → Block accepted regardless of slot-to-validator mapping - → Signature still validated against block.validator's signing_key -``` - ---- - -### 2J. Snapshot Plugin — Emergency State Handling - -**Location:** [`snapshot::plugin.cpp`](file://plugins/snapshot/plugin.cpp#L127-L181) and stalled sync detection - -``` -=== SNAPSHOT IMPORT === - -dynamic_global_property_object from snapshot JSON: - ├── emergency_consensus_active field present? → use value - ├── emergency_consensus_active field absent? → default false - ├── emergency_consensus_start_block present? → use value - └── emergency_consensus_start_block absent? → default 0 - -This is forward-compatible: older snapshots without these fields -import correctly (no emergency), and new snapshots with emergency -state preserve it. - - -=== STALLED SYNC DETECTION (snapshot plugin) === - -check_stalled_sync_loop() {every 30s} - │ - ├── elapsed > stalled_sync_timeout_minutes (default 5 min)? - │ └── No → continue - │ - ├── === EMERGENCY GUARD === - │ │ - │ ├── emergency AND head advancing? → skip + reset timer - │ └── emergency AND head stuck? → allow recovery (follower) - │ - ├── First trigger: P2P recovery (trigger_resync + reconnect seeds) - └── Second trigger: download new snapshot from trusted peers -``` - ---- - -### 2K. P2P Block Handling — DLT Emergency Near-Caught-Up - -**Location:** [`p2p_plugin::handle_block()`](file://plugins/p2p/p2p_plugin.cpp#L202-L226) - -``` -handle_block(blk_msg, sync_mode) - │ - ├── Track _last_block_received_time + _last_stale_check_head - │ - ├── === DLT EMERGENCY NEAR-CAUGHT-UP === - │ │ - │ └── sync_mode AND gap 0-2 AND dlt_mode AND block_age < 30s? - │ ├── Yes → treat as NORMAL block (sync_mode = false) - │ │ Reason: Prevents "Syncing Blockchain started" triggers - │ │ when only a few blocks behind. Emergency validators must - │ │ continue producing — entering full sync mode would set - │ │ currently_syncing=true and disrupt the production loop. - │ └── No → keep sync_mode - │ - ├── Skip dead-fork blocks (>100 behind head in DLT sync mode) - │ - └── chain.accept_block() with appropriate skip flags -``` - ---- - -### 2L. validator guard — Emergency-Aware Key Restoration - -**Location:** [`witness_guard::plugin.cpp`](file://plugins/witness_guard/witness_guard.cpp#L87-L107) - -``` -validator key auto-restore check: - │ - ├── stale_production_config override active? - │ ├── Non-emergency + participation >= 33% → auto-clear stale flag - │ ├── Non-emergency + participation < 33% → skip restoration - │ └── Emergency → do NOT skip - │ "Emergency consensus handles its own recovery and key - │ restoration may still be needed." - │ - ├── Node synced? (head_time within 2 × CHAIN_BLOCK_INTERVAL) - ├── LIB not too old? (< 200s) - └── Proceed with key restoration if conditions met -``` - ---- - -### 2M. Hardfork Voting — Committee Exclusion - -**Location:** [`database::update_witness_schedule()`](file://libraries/chain/database.cpp#L2553-L2564) - -``` -During emergency mode, committee validator is excluded from: - ├── running_version (majority_version) tally - └── hardfork_version_vote tally - -Reason: Committee occupies many slots but is a single entity. -Counting it per-slot would inflate its vote weight and drag -majority_version to 0.0.0, blocking hardfork progression. -``` - ---- - -### 2N. Median validator Props — Committee Exclusion - -**Location:** [`database::update_median_witness_props()`](file://libraries/chain/database.cpp#L2796-L2820) - -``` -update_median_witness_props(): - └── Excludes CHAIN_EMERGENCY_WITNESS_ACCOUNT from the active set - when emergency_consensus_active is true. - -Reason: Committee validator copies current median_props and should -not skew the median computation. Its entries are invisible to -the median — they reinforce the existing value. -``` - ---- - -## 3. Full State Diagram - -```mermaid -graph TB - subgraph "NORMAL OPERATION" - N1[Blocks produced by validators] - N2[LIB advances normally] - N3[validator schedule normal] - end - - subgraph "ACTIVATION TRIGGER" - A1[Block applied] - A2{seconds_since_LIB >= 3600?} - A3{LIB block available?} - end - - subgraph "ACTIVATION SEQUENCE" - AS1[Set emergency_consensus_active=true] - AS2[Create/Update committee validator] - AS3[Disable all real validators] - AS4[Reset all penalties] - AS5[Override schedule → all committee] - AS6[Notify fork_db] - AS7[Log activation] - end - - subgraph "EMERGENCY OPERATION" - E1[Committee produces blocks] - E2[Hybrid schedule: real + committee] - E3[LIB capped HEAD-1] - E4[Fork DB hash tie-breaking] - E5[Relaxed slot validation] - E6[Stale sync guards active] - end - - subgraph "EXIT CONDITION" - X1[Build hybrid schedule] - X2{real_witness_slots >= 75%?} - X3[Set emergency_consensus_active=false] - X4[Notify fork_db] - X5[Log deactivation] - end - - subgraph "RECOVERY GUARDS" - RG1[resync_from_lib: skip during emergency] - RG2[stale_sync_check: skip if head advancing] - RG3[minority_fork: DLT master skips check] - RG4[startup: repair empty schedule] - end - - N1 --> A1 - A1 --> A2 - A1 --> A3 - A2 -->|Yes| AS1 - A2 -->|No| N1 - A3 -->|No| N1 - AS1 --> AS2 --> AS3 --> AS4 --> AS5 --> AS6 --> AS7 - AS7 --> E1 - E1 --> E2 --> E3 --> E4 --> E5 --> E6 - E2 --> X1 - X1 --> X2 - X2 -->|Yes| X3 --> X4 --> X5 --> N1 - X2 -->|No| E1 - E6 --> RG1 - E6 --> RG2 - E6 --> RG3 - RG4 --> E1 -``` - ---- - -## 4. Component Interaction Map - -``` - ┌──────────────────────┐ - │ P2P Plugin │ - │ • stale sync check │ - │ • resync_from_lib │ - │ • block handling │ - │ • near-caught-up │ - └──────┬───────────────┘ - │ emergency guards - ▼ - ┌──────────┐ ┌──────────────────────┐ ┌──────────────┐ - │ validator │◄───│ Database (chain) │───►│ Fork DB │ - │ Plugin │ │ • activation │ │ • hash tie- │ - │ │ │ • deactivation │ │ breaking │ - │ • prod. │ │ • hybrid schedule │ │ • emergency │ - │ loop │ │ • LIB cap │ │ flag │ - │ • master/│ │ • slot validation │ └──────────────┘ - │ follr │ │ • startup recovery │ - │ • min.fk │ │ • hardfork voting │ - └────┬─────┘ │ • median props │ ┌──────────────┐ - │ └──────────┬───────────┘ │ Snapshot │ - │ │ │ Plugin │ - ┌────┴─────┐ ┌────┴──────┐ │ • import │ - │ validator │ │ Dynamic │ │ • stall │ - │ Guard │ │ Global │ │ detection │ - │ • key │ │ Properties│ └──────────────┘ - │ rest. │ │ • flags │ - └──────────┘ └───────────┘ -``` - ---- - -## 5. Guard Summary — All Emergency Checks - -| # | Location | File | Guard | -|---|----------|------|-------| -| 1 | `update_global_dynamic_data` | `database.cpp` | Only activate if HF12 + !already_active + LIB available | -| 2 | `update_witness_schedule` | `database.cpp` | Hybrid override + exit check via 75% real validator slots | -| 3 | `update_last_irreversible_block` | `database.cpp` | Cap LIB to HEAD-1 during emergency | -| 4 | `check_block_post_validation_chain` | `database.cpp` | Skip BPV-based LIB advancement during emergency | -| 5 | `verify_signing_witness` | `database.cpp` | Relax slot-to-validator mapping during emergency | -| 6 | `fork_db._push_block` | `fork_database.cpp` | Deterministic hash tie-breaking during emergency | -| 7 | `maybe_produce_block` | `validator.cpp` | Emergency master: bypass sync+stale+participation, skip minority fork; slave: must sync first, standard production gate | -| 8 | `resync_from_lib` | `p2p_plugin.cpp` | SKIP entirely during emergency (prevent crash) | -| 9 | `stale_sync_check_task` | `p2p_plugin.cpp` | Skip recovery if master's head advancing; allow if follower stuck | -| 10 | `handle_block` | `p2p_plugin.cpp` | Near-caught-up blocks treated as normal in DLT emergency | -| 11 | `database::open` | `database.cpp` | Startup schedule repair: fill empty slots, re-activate emergency if needed | -| 12 | `witness_guard` | `witness_guard.cpp` | Don't skip key restoration during emergency | -| 13 | `snapshot import` | `plugin.cpp` | Forward-compatible emergency field handling | -| 14 | `snapshot stalled sync` | `plugin.cpp` | Skip if master's head advancing | -| 15 | `update_witness_schedule` | `database.cpp` | Exclude committee from hardfork version voting | -| 16 | `update_median_witness_props` | `database.cpp` | Exclude committee from median computation | -| 17 | `_push_block` fork switch | `database.cpp` | Direct-extension bypass + fork_db head-seeding (protects emergency after stale sync resets) | -| 18 | `update_global_dynamic_data` | `database.cpp` | Skip emergency activation if LIB block not in block_log (DLT snapshot safety) | -| 19 | `push_block` | `database.cpp` | Deferred applied_block notification: plugin callbacks run outside write lock to avoid blocking P2P/RPC | - ---- - -## 6. Key Invariants - -1. **Deterministic activation**: `seconds_since_lib` uses only block-embedded timestamps — identical on every node, every replay. -2. **DLT snapshot safety**: Activation skipped when LIB block is unavailable in block_log (empty after snapshot restore). -3. **Emergency fork immutability**: `resync_from_lib()` refuses to unwind during emergency, protecting against LIB-close-to-HEAD crashes. -4. **Master/Follower distinction**: DLT nodes with `--emergency-private-key` are masters (bypass sync checks, skip minority fork detection); followers must sync before producing and run 21-block isolation check (1 round). -5. **Fork DB convergence**: Deterministic hash tie-breaking ensures all nodes pick the same block when multiple emergency producers compete. -6. **LIB safety**: Capped at HEAD-1 to preserve undo protection for the current `_apply_block`. -7. **Neutral committee voting**: Committee votes for currently-applied hardfork version (not binary version), copies median props — does not skew governance or chain properties. -8. **Stale sync protection**: Master nodes skip stale sync recovery while head is advancing; followers trigger recovery when head is stuck. diff --git a/.qoder/docs/expected-next-block.md b/.qoder/docs/expected-next-block.md deleted file mode 100644 index 29886a3290..0000000000 --- a/.qoder/docs/expected-next-block.md +++ /dev/null @@ -1,303 +0,0 @@ -# DLT P2P `expected_next_block` — Design, Data Flow, and Fixes - -## 1. Overview - -`expected_next_block` is a per-peer tracking field in `dlt_peer_state` that records the next sequential block number we expect to receive **from this specific peer**. Its purpose is: - -1. **Detect out-of-order blocks** — when a peer sends a block whose `block_num` doesn't match `expected_next_block`, something unexpected happened (duplicate, gap, competing fork). -2. **Distinguish harmless duplicates from suspicious out-of-order** — if the block is a known duplicate from another peer, it's harmless; otherwise it may indicate a fork or gap. - -**Key invariant (design intent):** `expected_next_block` should always equal `head_block_num + 1` for peers that are in sync with us. In practice, it only tracks what *this peer* has sent us, not our global chain head. - -**Field definition:** `dlt_p2p_peer_state.hpp:65` -```cpp -uint32_t expected_next_block = 0; // 0 = "not tracking" (no active sync session) -``` - ---- - -## 2. Lifecycle — Every Write Site - -### 2.1 Initialization to 0 (tracking disabled) - -| Site | File:Line | When | -|------|-----------|------| -| Struct default | `dlt_p2p_peer_state.hpp:65` | Peer state constructed | -| `connect_to_peer` | `dlt_p2p_node.cpp:222` | `state = dlt_peer_state()` — full zero-init on reconnect | -| `handle_disconnect` | `dlt_p2p_node.cpp:321` | `state.expected_next_block = 0` on disconnect | -| `request_blocks_from_peer` | `dlt_p2p_node.cpp:945` | Reset before sending range request | - -**Meaning of `0`:** We are not actively tracking block ordering from this peer. The out-of-order check is skipped entirely (see §3.1). - -### 2.2 Write: `expected_next_block = max(expected_next_block, block_num + 1)` - -This is the **per-peer advance** pattern. It appears in two places: - -| Site | File:Line | Context | -|------|-----------|--------| -| `on_dlt_block_range_reply` | `dlt_p2p_node.cpp:1150` | After processing each block in a range reply | -| `on_dlt_block_reply` | `dlt_p2p_node.cpp:1381` | After processing a single block reply | - -Both use `std::max()` so the value only moves forward, never backward. - -### 2.3 Write: Bulk advance for ALL peers in `on_block_applied()` (Fix 8.1) - -**File:** `dlt_p2p_node.cpp:2457-2469` - -After any block is applied (from any source), all peers whose `expected_next_block` is behind the new chain head are advanced: - -```cpp -uint32_t next = block.block_num() + 1; -for (auto& item : _peer_states) { - if (item.second.expected_next_block != 0 && - item.second.expected_next_block < next) { - item.second.expected_next_block = next; - } -} -``` - -This is called from: -- `on_dlt_block_range_reply` (SYNC mode) — `dlt_p2p_node.cpp:1117` -- `on_dlt_block_reply` (FORWARD mode) — `dlt_p2p_node.cpp:1345` -- `on_dlt_gap_fill_reply` (gap fill) — `dlt_p2p_node.cpp:1678` -- `broadcast_block()` (self-produced blocks) — `dlt_p2p_node.cpp:1860` (Fix 8.2) - ---- - -## 3. Lifecycle — Every Read Site (Decision Points) - -### 3.1 Out-of-order check in `on_dlt_block_range_reply` (SYNC mode) - -**File:** `dlt_p2p_node.cpp:1070-1094` - -``` -if (state.expected_next_block != 0 && block.block_num() != state.expected_next_block) -``` - -**Branches:** -- `expected_next_block == 0` → skip check (no tracking active) -- `block_num == expected_next_block` → in order, proceed normally -- `block_num < expected_next_block && block is known` → duplicate, skip with debug log -- `block_num != expected_next_block && (not duplicate)` → **3-tier log** (Fix 8.3, see §6): - - `block_num <= head` → `dlog` (stale tracking) - - `block_num == head + 1` → `dlog` (stale tracking) - - `block_num > head + 1` → `wlog` (genuine gap) - -### 3.2 Out-of-order check in `on_dlt_block_reply` (FORWARD mode single-block) - -**File:** `dlt_p2p_node.cpp:1225-1291` - -Same 3-tier log structure as 3.1 (Fix 8.3), plus additional logic: - -- **Gap fill trigger (P36/P40/P54):** If `block_num > head + 1`, request gap fill. Works in both SYNC and FORWARD modes. If `block_num == head + 1`, there's no real gap - it's just stale `expected_next_block`. -- **Competing fork detection:** If the block's `previous` hash differs from our head at the same height, request the competing parent block. - ---- - -## 4. Data Flow Diagram - -``` - ┌──────────────────────────────────────────┐ - │ Peer Connect / Reconnect │ - │ expected_next_block = 0 │ - └─────────────┬────────────────────────────┘ - │ - ┌─────────────▼────────────────────────────┐ - │ request_blocks_from_peer() │ - │ expected_next_block = 0 (reset again) │ - └─────────────┬────────────────────────────┘ - │ - ┌──────────────────┴──────────────────┐ - │ │ - ┌──────────▼──────────┐ ┌────────────▼───────────┐ - │ Range Reply (SYNC) │ │ Single Block Reply │ - │ (batch of blocks) │ │ (FORWARD / broadcast) │ - └──────────┬──────────┘ └────────────┬───────────┘ - │ │ - For each block: 1. Out-of-order check (3-tier log) - 1. Out-of-order check (3-tier) - duplicate? → return - 2. accept_block() - gap? → request_gap_fill() - 3. on_block_applied() ◄── Fix 8.1 - competing fork? → request parent - └─ advances ALL peers' enb 2. accept_block() - 4. expected_next_block = 3. on_block_applied() ◄── Fix 8.1 - max(enb, block_num + 1) └─ advances ALL peers' enb - 4. expected_next_block = - max(enb, block_num + 1) - │ │ - └──────────────────┬──────────────────┘ - │ - ┌──────────────────┴──────────────────┐ - │ │ - ┌──────────▼──────────┐ ┌────────────▼───────────┐ - │ broadcast_block() │ │ on_dlt_gap_fill_reply │ - │ (self-produced) │ │ (gap fill blocks) │ - │ Fix 8.2: calls │ │ │ - │ on_block_applied() │ │ on_block_applied() │ - └──────────┬──────────┘ └────────────┬───────────┘ - │ │ - └──────────────────┬──────────────────┘ - │ - ┌─────────────▼────────────────────────────┐ - │ handle_disconnect() │ - │ expected_next_block = 0 │ - └──────────────────────────────────────────┘ -``` - ---- - -## 5. Residual Gaps (after Fixes 8.1–8.3) - -Fixes 8.1, 8.2, and 8.3 eliminate the primary sources of false "out of order" warnings. The following gaps still exist but have reduced impact: - -### 5.1 ~~Self-produced blocks~~ FIXED (Fix 8.2) - -`broadcast_block()` now calls `on_block_applied()`, which advances all peers' `expected_next_block`. - -### 5.2 ~~Blocks received from other peers~~ FIXED (Fix 8.1) - -`on_block_applied()` now iterates all peers and advances stale `expected_next_block` values. - -### 5.3 ~~`on_block_applied()` does not touch peer states~~ FIXED (Fix 8.1) - -`on_block_applied()` now includes the peer advancement loop at `dlt_p2p_node.cpp:2457-2469`. - -### 5.4 Fork switches - -When a fork switch happens (minority → majority), the fix 8.1 loop in `on_block_applied()` will advance peers to the new head **if** `on_block_applied()` is called during the fork switch path. This is handled by the chain layer calling `broadcast_block` or the P2P accept path after switch_to_fork. - -### 5.5 `transition_to_forward()` / `transition_to_sync()` - -Neither transition function updates `expected_next_block` for any peer. This is mitigated by fix 8.1 since any block application during/after transition will correct stale values. - -### 5.6 Narrow race window - -There is a small race between when a block is applied and when the next block arrives from another peer. If both blocks arrive nearly simultaneously (before the first block's `on_block_applied()` completes the peer iteration), a single stale "out of order" may still fire. Fix 8.3 demotes this to `dlog`. - ---- - -## 6. Active Mitigations - -| Mitigation | File:Line | Description | -|-----------|-----------|-------------| -| Bulk advance all peers (8.1) | `dlt_p2p_node.cpp:2457-2469` | `on_block_applied()` advances stale `expected_next_block` for all peers | -| `broadcast_block` → `on_block_applied` (8.2) | `dlt_p2p_node.cpp:1860` | Self-produced blocks trigger peer advancement | -| 3-tier log demotion (8.3) | `dlt_p2p_node.cpp:1083-1092, 1240-1249` | Stale tracking → `dlog`; genuine gap → `wlog` | -| Reset to 0 on range request | `dlt_p2p_node.cpp:945` | Fresh range request resets tracking | -| Duplicate detection | `dlt_p2p_node.cpp:1071,1227` | If block_num < expected and block is known → skip silently | -| P40 gap fill guard | `dlt_p2p_node.cpp:1258` | Only trigger gap fill if block_num > head + 1 (not just stale tracking) | -| std::max on write | `dlt_p2p_node.cpp:1150,1381` | Value only moves forward, never backward | - ---- - -## 7. Concrete Bug Scenario (from production logs) - -``` -206774ms validator.cpp:431 Generated block #79720273 ... by creativity -... -209818ms dlt_p2p_node.cpp:1208 Block #79720274 from 80.87.202.57 out of order (expected #79720273) -209822ms dlt_p2p_node.cpp:1298 Got block #79720274 ... by validator m0ssa99 [80.87.202.57] -``` - -**Trace:** -1. Peer 80.87.202.57 sent us block #79720272 → its `expected_next_block` = 79720273 -2. We generated #79720273 ourselves → `expected_next_block` for this peer stays at 79720273 -3. Peer sends #79720274 → `79720274 != 79720273` → false "out of order" -4. Block is still accepted (no real gap, `block_num == head + 1`) — but the warning is misleading noise - ---- - -## 8. Implemented Fixes - -### 8.1 IMPLEMENTED: Update all peers' `expected_next_block` in `on_block_applied()` - -After any block is applied to our chain (from any source), advance `expected_next_block` for all peers whose value is behind our new head. - -**Location:** `dlt_p2p_node.cpp:2457-2469` (`on_block_applied`) - -```cpp -// Advance stale expected_next_block for all peers. -uint32_t next = block.block_num() + 1; -for (auto& item : _peer_states) { - if (item.second.expected_next_block != 0 && - item.second.expected_next_block < next) { - item.second.expected_next_block = next; - } -} -``` - -**Call sites:** `on_dlt_block_range_reply:1117`, `on_dlt_block_reply:1345`, `on_dlt_gap_fill_reply:1678`, `broadcast_block:1860`. - -### 8.2 IMPLEMENTED: Call `on_block_applied()` from `broadcast_block()` - -Self-produced blocks now trigger mempool cleanup, fork state tracking, and peer `expected_next_block` advancement. - -**Location:** `dlt_p2p_node.cpp:1856-1860` - -```cpp -// Track our own block application: clean mempool of included -// transactions, advance fork state, and update all peers' -// expected_next_block so the next incoming block from any peer -// is not falsely flagged as "out of order". -on_block_applied(block, /*caused_fork_switch=*/false); -``` - -### 8.3 IMPLEMENTED: Demote stale "out of order" to debug level - -Replaced unconditional `wlog` with 3-tier logic at both out-of-order check sites: - -| Condition | Log level | Meaning | -|-----------|-----------|---------| -| `block_num <= head` | `dlog` | Block already applied — stale per-peer tracker | -| `block_num == head + 1` | `dlog` | Block links to head — stale per-peer tracker, no gap | -| `block_num > head + 1` | `wlog` | Genuine gap — real out-of-order concern | - -**Locations:** `dlt_p2p_node.cpp:1083-1092` (SYNC), `dlt_p2p_node.cpp:1240-1249` (FORWARD) - ---- - -## 9. Remaining Proposals (Not Yet Implemented) - -### 9.1 Reset `expected_next_block` on `transition_to_forward()` - -When we complete SYNC and transition to FORWARD, all peers' `expected_next_block` is based on the last range reply. But in FORWARD mode, blocks arrive via broadcast from any peer, not in sequence from one peer. Resetting to 0 (or to `head + 1`) on transition would eliminate stale values: - -```cpp -// In transition_to_forward(): -for (auto& item : _peer_states) { - item.second.expected_next_block = 0; // broadcast mode = no sequential tracking -} -``` - -### 9.2 Long-term: Replace per-peer `expected_next_block` with global head comparison - -The fundamental design issue is that `expected_next_block` tries to track per-peer sequential ordering, but in FORWARD mode blocks come from multiple peers simultaneously. The real question is: "does this block follow our chain head?" — not "does this block follow what we last received from this peer?" - -A simpler and more robust approach: - -```cpp -// Replace out-of-order check with: -bool is_out_of_order = (block_num > _delegate->get_head_block_num() + 1); -bool is_behind = (block_num <= _delegate->get_head_block_num()); -``` - -This eliminates the per-peer tracking entirely for FORWARD mode and uses the only authoritative source of truth — our chain head. - ---- - -## 10. Source File Reference - -| File | Relevance | -|------|-----------| -| `libraries/network/include/graphene/network/dlt_p2p_peer_state.hpp:65` | Field definition | -| `libraries/network/dlt_p2p_node.cpp:321` | Reset on disconnect | -| `libraries/network/dlt_p2p_node.cpp:945` | Reset on range request | -| `libraries/network/dlt_p2p_node.cpp:1070-1094` | Out-of-order check (range reply, 3-tier log) | -| `libraries/network/dlt_p2p_node.cpp:1117` | `on_block_applied()` call in range reply | -| `libraries/network/dlt_p2p_node.cpp:1150` | Per-peer advance after range block | -| `libraries/network/dlt_p2p_node.cpp:1225-1291` | Out-of-order check (single block, 3-tier log) | -| `libraries/network/dlt_p2p_node.cpp:1345` | `on_block_applied()` call in single block reply | -| `libraries/network/dlt_p2p_node.cpp:1381` | Per-peer advance after single block | -| `libraries/network/dlt_p2p_node.cpp:1678` | `on_block_applied()` call in gap fill reply | -| `libraries/network/dlt_p2p_node.cpp:1849-1861` | `broadcast_block()` — now calls `on_block_applied()` (Fix 8.2) | -| `libraries/network/dlt_p2p_node.cpp:2457-2469` | `on_block_applied()` — bulk peer advance (Fix 8.1) | -| `plugins/validator/validator.cpp:1092-1099` | Block production → broadcast | diff --git a/.qoder/docs/fork-collision-hardfork-proposal.md b/.qoder/docs/fork-collision-hardfork-proposal.md deleted file mode 100644 index 0c50a1d30e..0000000000 --- a/.qoder/docs/fork-collision-hardfork-proposal.md +++ /dev/null @@ -1,282 +0,0 @@ -# Fork Collision Reduction Hardfork Proposal - -## Problem Statement - -The VIZ blockchain experiences recurring "block num collision" events — situations where two validators produce blocks at the same height on different chain tips, creating a fork. With a 3-second block interval (`CHAIN_BLOCK_INTERVAL = 3`), there is minimal margin for block propagation, making collisions frequent during periods of network latency or clock drift. - -### Observed Pattern (Block 79162800–79162802) - -``` -Block 79162800: mad-max @ 11:53:12 (latency 10160ms) | jackvote @ 11:53:15 (latency 7160ms) -Block 79162801: lexai @ 11:53:24 (latency 47ms) | denis-skripnik @ 11:53:21 (latency 8357ms) -Block 79162802: micu @ 11:53:30 (latency 78ms) | creativity @ 11:53:27 (latency 4044ms) -``` - -Three consecutive blocks had collisions, indicating a sustained network partition between two validator subsets. The high latency values (7–10 seconds) on one fork branch confirm severe propagation delay. - -### Root Causes - -1. **Tight block interval with no propagation margin** — 3-second slots leave no buffer for cross-region propagation (typical P2P propagation is 1–4 seconds for a global network). - -2. **Deterministic validator ordering without shuffling** — The validator shuffle was [commented out](../libraries/chain/database.cpp) (`// VIZ remove randomization`), making the schedule predictable. If two consecutive validators have poor connectivity, collisions recur every round. - -3. **No on-chain fork telemetry** — The current `_maybe_warn_multiple_production()` only logs a console warning. There is no on-chain metric for fork frequency, making it impossible to monitor network health programmatically. - -4. **No production-time fork awareness** — validators produce blocks on whatever chain tip they see, even if a competing block already exists in their fork database for the same height. - -5. **Clock drift susceptibility** — `get_slot_at_time()` uses wall-clock time. NTP drift between validator nodes can cause slot mismatches. API load can indirectly degrade NTP precision due to thread contention. - ---- - -## Proposal: Hardfork 12 — Fork Resilience Improvements - -### Change 1: Fork Collision Counter in `dynamic_global_property_object` - -**Type**: Consensus-breaking (new serialized field) - -Add a rolling fork collision counter to `dynamic_global_property_object`, making fork frequency observable via the `get_dynamic_global_properties` API. - -**File**: `libraries/chain/include/graphene/chain/global_property_object.hpp` - -```cpp -class dynamic_global_property_object - : public object { -public: - // ... existing fields ... - - /** - * Total number of fork collisions (block num collisions) detected - * since genesis. Incremented each time _maybe_warn_multiple_production() - * finds multiple blocks at the same height in the fork database. - * This counter never decreases, providing a cumulative metric - * for monitoring network fork health. - */ - uint32_t fork_collision_count = 0; - - /** - * Block number of the most recent fork collision. - * Zero if no collision has ever occurred. - * Useful for detecting recent fork events via API polling. - */ - uint32_t last_fork_collision_block_num = 0; -}; -``` - -**FC_REFLECT update**: - -```cpp -FC_REFLECT((graphene::chain::dynamic_global_property_object), - // ... existing fields ... - (fork_collision_count) - (last_fork_collision_block_num) -) -``` - -**Increment logic** in `database::_maybe_warn_multiple_production()`: - -```cpp -void database::_maybe_warn_multiple_production(uint32_t height) const { - auto blocks = _fork_db.fetch_block_by_number(height); - if (blocks.size() > 1) { - // Increment on-chain counter (non-const via modify) - const auto& dgp = get_dynamic_global_properties(); - modify(dgp, [&](dynamic_global_property_object& obj) { - obj.fork_collision_count++; - obj.last_fork_collision_block_num = height; - }); - - // ... diagnostic logging (already implemented) ... - } -} -``` - -**Why this requires a hardfork**: Adding new fields to `dynamic_global_property_object` changes its serialized representation. All nodes must agree on the object layout for consensus. The snapshot plugin's export/import must also be updated. - -**Consensus benefit**: Enables monitoring dashboards, alerting, and data-driven decisions about network topology. validators with high collision rates can be identified and their connectivity improved. - ---- - -### Change 2: Fork-Aware Block Production Deferral - -**Type**: Non-consensus-breaking (Validator Plugin behavior only) - -Already implemented in `plugins/validator/validator.cpp` — before producing a block, check if a competing block already exists in the fork database for the target height. If so, defer production to allow fork resolution. - -This does **not** require a hardfork because: -- It only affects the Validator Plugin's production timing -- It does not change block validation rules -- A deferred block will be produced in the next available slot - -However, the hardfork proposal could make this behavior **mandatory** by adding a consensus rule: if a validator observes a fork collision for the current slot, they MUST wait for the competing block's next validator to produce before building on top. This would formalize the deferral as a consensus rule rather than a best-effort optimization. - -**Formalized version** (requires hardfork): - -Add to `validate_block_header()`: - -```cpp -if (has_hardfork(CHAIN_HARDFORK_12)) { - // After a fork collision at height H, the next block must be - // built on top of the longest chain's block at height H. - // validators must not produce on the shorter fork's tip. - auto existing = _fork_db.fetch_block_by_number(next_block.block_num()); - if (existing.size() > 1) { - // There was a collision at this height; verify this block - // builds on the winner (longest chain) - auto winner = _fork_db.head(); - FC_ASSERT(next_block.previous == winner->data.previous || - next_block.block_num() > winner->num, - "Block produced on losing fork after collision"); - } -} -``` - -**Consensus benefit**: Prevents validators from extending a minority fork after a collision is detected, reducing the duration and depth of forks. - ---- - -### Change 2a: Minority Fork Detection & Auto-Resync - -**Type**: Non-consensus-breaking (validator + P2P plugin behavior only) - -Implemented in `plugins/validator/validator.cpp` and `plugins/p2p/p2p_plugin.cpp` — before producing a block, the Validator Plugin walks back the last `CHAIN_MAX_WITNESSES` (21) blocks in fork_db and checks if ALL were produced by the node's own configured validators. If so, the node is stuck on a minority fork (no external validators are participating on this chain). - -**Behavior by configuration:** - -| Condition | Action | -|---|---| -| `enable-stale-production=false` (default) | Trigger recovery: pop blocks to LIB, reset fork_db, re-initiate P2P sync, reconnect seed nodes | -| `enable-stale-production=true` | Log and continue producing (operator override for bootstrap/testnet/recovery) | -| Emergency consensus active | Skip detection entirely (emergency mode blocks are all from committee account) | - -**Recovery flow (`resync_from_lib()`):** - -1. Pop all reversible blocks from head back to LIB via `pop_block()` loop -2. Clear pending transactions -3. Reset fork_db and re-seed with LIB block -4. Call `node->sync_from()` + `node->resync()` to re-initiate P2P sync -5. Reconnect all configured seed nodes -6. Set `_production_enabled = false` (node must receive a recent block to re-enable) - -This replicates the effect of a manual docker stop/start without node downtime. - -**Files modified:** `validator.hpp` (new enum value `minority_fork`), `validator.cpp` (detection logic + switch case), `p2p_plugin.hpp` (new `resync_from_lib()` method), `p2p_plugin.cpp` (implementation) - ---- - -### Change 3: Production Delay Buffer - -**Type**: Consensus-breaking (changes block timing expectations) - -Add a configurable production delay of `CHAIN_PRODUCTION_DELAY_MS` milliseconds (e.g., 500ms) that a validator must wait after receiving a new block before producing its own. This gives the network time to propagate the latest block before the next validator builds on it. - -**Implementation**: - -```cpp -// In config.hpp: -#define CHAIN_PRODUCTION_DELAY_MS 500 // Wait 500ms after receiving block before producing - -// In validator.cpp maybe_produce_block(): -fc::time_point_sec earliest_production_time = db.head_block_time() + - fc::milliseconds(CHAIN_PRODUCTION_DELAY_MS); -if (now < earliest_production_time) { - capture("earliest", earliest_production_time)("now", now); - return block_production_condition::not_time_yet; -} -``` - -**Why this requires a hardfork**: Changes the timing semantics of when blocks are expected. The current consensus assumes validators produce as close to their scheduled slot time as possible. A mandatory delay effectively shortens the usable production window. - -**Consensus benefit**: A 500ms delay on a 3-second interval gives the P2P network 500ms to propagate the previous block to all validators before the next one starts building. This dramatically reduces the probability of two validators building on different chain tips simultaneously. - -**Trade-off**: Block latency increases by up to 500ms per block. Over a day (28,800 blocks), this adds ~4 hours of total latency, but the actual user-perceived latency increase is only 500ms per transaction confirmation. - ---- - -## Implementation Plan - -### Phase 1: Non-Breaking Changes (No Hardfork Required) - -These changes are already implemented and can be deployed immediately: - -| Change | File | Status | -|--------|------|--------| -| Enhanced collision diagnostics with fork topology classification | `database.cpp` `_maybe_warn_multiple_production()` | Done | -| Rate-limited collision warnings (prevent log spam) | `database.cpp` `_maybe_warn_multiple_production()` | Done | -| Parent block ID logging for fork topology analysis | `database.cpp` `_maybe_warn_multiple_production()` | Done | -| Pre-production fork collision check in Validator Plugin | `validator.cpp` `maybe_produce_block()` | Done | -| `fork_collision` block production condition | `validator.hpp` enum, `validator.cpp` handler | Done | -| NTP re-sync on fork collision detection | `validator.cpp` `block_production_loop()` | Done | -| Minority fork detection & auto-resync | `validator.cpp`, `p2p_plugin.cpp/.hpp`, `validator.hpp` | Done | - -### Phase 2: Hardfork 12 (Requires Network-Wide Upgrade) - -| Change | Breaking | Files Modified | -|--------|----------|----------------| -| Fork collision counter in DGP | Yes (serialized object) | `global_property_object.hpp`, `database.cpp`, `snapshot/plugin.cpp` | -| Production delay buffer | Yes (timing) | `config.hpp`, `validator.cpp` | -| Mandatory fork deferral rule | Yes (validation) | `database.cpp` `validate_block_header()` | - -### Hardfork 12 Definition - -**File**: `libraries/chain/hardfork.d/12.hf` - -```cpp -// 12 Hardfork — Fork Resilience Improvements -#ifndef CHAIN_HARDFORK_12 -#define CHAIN_HARDFORK_12 12 -#define CHAIN_HARDFORK_12_TIME // To be determined by validator vote -#define CHAIN_HARDFORK_12_VERSION hardfork_version( version(3, 1, 0) ) -#endif -``` - -**Update**: `0-preamble.hf` → `#define CHAIN_NUM_HARDFORKS 12` - ---- - -## Impact Analysis - -### Fork Collision Rate Reduction (Estimated) - -| Scenario | Current | After HF12 | Reduction | -|----------|---------|------------|-----------| -| Consecutive validator pair with poor connectivity | ~95% collision/round | ~5% collision/round | ~19× | -| Random single-slot collision (network hiccup) | 100% produces fork | ~30% (delay absorbs transient) | ~3× | -| Sustained partition (2+ round) | 100% collision every block | 100% (delay can't help) | 0× | -| NTP drift <500ms | ~50% collision | ~10% (delay + re-sync) | ~5× | - -### API Compatibility - -The `get_dynamic_global_properties` API will return two additional fields. Clients that ignore unknown fields (most JSON parsers) will be unaffected. Clients with strict schema validation must be updated. - -### Snapshot Compatibility - -Snapshots created before HF12 will not contain `fork_collision_count` or `last_fork_collision_block_num`. The snapshot import logic must handle missing fields with defaults (0 for both). See [dlt-hardfork-new-objects.md](dlt-hardfork-new-objects.md) for the standard procedure. - ---- - -## Alternative Approaches Considered - -### A. Increase Block Interval to 5 Seconds - -Would eliminate most collisions by giving 2+ seconds of propagation margin. **Rejected** because it increases transaction confirmation latency by 67% and reduces throughput proportionally. - -### B. Batch Block Production (Produce 2+ Blocks per Slot) - -Similar to EOS's approach where a validator produces a batch of consecutive blocks. **Rejected** because it increases centralization (longer production windows favor better-connected validators) and complicates missed-block accounting. - -### C. Fork Choice by validator Priority - -Instead of longest-chain, use validator priority (e.g., higher-voted validator's block wins). **Rejected** because it breaks the fundamental longest-chain consensus rule and could enable voting attacks. - -### D. P2P Block Prefetch / Fast Relay Network - -A dedicated relay network for block propagation (similar to Bitcoin's FIBRE). **Not a hardfork** — can be implemented as a P2P plugin improvement. Recommended as a complementary non-consensus change. - ---- - -## Related Documentation - -- [DLT Hardfork New Objects](dlt-hardfork-new-objects.md) — Procedure for adding consensus objects in hardforks -- [Block Processing](block-processing.md) — Block application flow and fork resolution -- [validator Operations](op-validator.md) — validator update, vote, chain properties -- [Plugins](plugins.md) — Plugin architecture including validator and P2P plugins diff --git a/.qoder/docs/hardfork-guide.md b/.qoder/docs/hardfork-guide.md deleted file mode 100644 index 7d140aefbb..0000000000 --- a/.qoder/docs/hardfork-guide.md +++ /dev/null @@ -1,259 +0,0 @@ -# Hardfork Implementation Guide - -Checklist and rules for implementing a new hardfork in the VIZ node. -Covers protocol, chain, plugins, deployment, and schema versioning. - ---- - -## 1. Define the hardfork - -### 1.1. Hardfork `.hf` file - -Create `libraries/chain/hardfork.d/N.hf`: - -```cpp -#ifndef CHAIN_HARDFORK_N -#define CHAIN_HARDFORK_N N -#define CHAIN_HARDFORK_N_TIME 1234567890 // Unix timestamp — must be in the future -#define CHAIN_HARDFORK_N_VERSION hardfork_version(3, N, 0) -#endif -``` - -### 1.2. Bump CHAIN_NUM_HARDFORKS - -In `libraries/chain/hardfork.d/0-preamble.hf`: -```cpp -#define CHAIN_NUM_HARDFORKS N // was N-1 -``` - -### 1.3. Bump CHAIN_VERSION (if protocol-visible) - -In `libraries/protocol/include/graphene/protocol/config.hpp`: -```cpp -#define CHAIN_VERSION (version(3, N, 0)) -``` - ---- - -## 2. Protocol changes - -### 2.1. New operation - -Add to `libraries/protocol/include/graphene/protocol/chain_operations.hpp`: -- Struct definition with `validate()` and authority getters -- Forward-declare any new `chain_properties_hfN` struct - -Add to `libraries/protocol/include/graphene/protocol/operations.hpp`: -- Entry in the `static_variant` for the new op -- Guard comment `// VIZ HF N: ...` - -Implement `validate()` in `libraries/protocol/chain_operations.cpp`. - -### 2.2. New virtual operation - -Add to `libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp`: -```cpp -struct my_new_virtual_operation : public virtual_operation { - my_new_virtual_operation() {} - my_new_virtual_operation(args...) : ... {} - // fields -}; -FC_REFLECT(...) -``` - -Add to `libraries/protocol/include/graphene/protocol/operations.hpp` in the virtual op section. - ---- - -## 3. Chain objects - -### 3.1. Adding fields to existing chainbase objects - -> **⚠ SCHEMA RULE — mandatory step:** -> Whenever you add, remove, or resize a field in any chainbase-managed struct -> (`witness_object`, `account_object`, etc.), you MUST increment -> `CHAIN_SCHEMA_VERSION` in `config.hpp`. -> -> ```cpp -> // config.hpp — increment this for every field layout change: -> #define CHAIN_SCHEMA_VERSION uint32_t(N) -> ``` -> -> The chain plugin reads `/schema_version` at startup and compares it with -> `CHAIN_SCHEMA_VERSION`. A mismatch triggers proactive `shared_memory.bin` wipe -> before `db.open()` is called, preventing corrupt reads. Without this, old shared -> memory can be opened with incorrect object sizes, leading to silent data corruption -> or crashes. -> -> **History format** — add a comment entry: -> ```cpp -> /// N — HFN: describe every affected object and field -> ``` - -New fields should always have zero-value defaults: -```cpp -uint16_t my_new_field = 0; -share_type my_reward = 0; -``` - -Zero defaults mean `apply_hardfork(N)` requires no migration — all existing objects -are in a valid pre-HF state without any extra writes. - -Add new fields to `FC_REFLECT`. - -### 3.2. Adding new chainbase objects - -Follow [dlt-hardfork-new-objects.md](dlt-hardfork-new-objects.md) for: -- `object_type` enum entry -- Object + index header -- `initialize_indexes()` registration -- Snapshot plugin `serialize_state` / `load_snapshot` support - -> **Schema rule applies here too**: adding a new index is a layout change. -> Increment `CHAIN_SCHEMA_VERSION`. - ---- - -## 4. Evaluators - -### 4.1. Declare evaluator - -In `libraries/chain/include/graphene/chain/chain_evaluator.hpp`: -```cpp -DEFINE_EVALUATOR(my_new_op) -``` - -### 4.2. Implement evaluator - -In `libraries/chain/chain_properties_evaluators.cpp` (or a dedicated file): -```cpp -void my_new_op_evaluator::do_apply(const my_new_op_operation& o) { - ASSERT_REQ_HF(CHAIN_HARDFORK_N, "my_new_op_operation"); - // ... -} -``` - -### 4.3. Register evaluator - -In `libraries/chain/database.cpp`, `initialize_evaluators()`: -```cpp -_my->_evaluator_registry.register_evaluator(); -``` - ---- - -## 5. database.cpp wiring - -### 5.1. Register hardfork - -In `init_hardforks()` (or hardfork array initialisation): -```cpp -FC_ASSERT(CHAIN_HARDFORK_N == N); -_hardfork_times[N] = fc::time_point_sec(CHAIN_HARDFORK_N_TIME); -_hardfork_versions[N] = hardfork_version(CHAIN_HARDFORK_N_VERSION); -``` - -### 5.2. apply_hardfork case - -```cpp -case CHAIN_HARDFORK_N: { - // Migration for any data that cannot be expressed via field defaults. - // If all new fields default to zero → leave this block empty with a comment. - break; -} -``` - -### 5.3. chain_properties median (if new consensus property) - -Add the new property to the median computation in `update_witness_schedule()` or the -equivalent location where `wso.median_props` is built: -```cpp -wso.median_props.my_new_param = median_value; -``` - ---- - -## 6. Plugins - -### 6.1. account_history - -Add impact extractor for any new virtual operation: -```cpp -void operator()(const my_new_virtual_operation& op) { - impacted.insert(op.sender); - impacted.insert(op.receiver); -} -``` - -### 6.2. witness_api - -If new fields appear on `witness_object` → add them to `witness_api_object`: -- `libraries/api/include/graphene/api/witness_api_object.hpp` — field declaration + `FC_REFLECT` -- `libraries/api/witness_api_object.cpp` — initialise in constructor - -### 6.3. chain_properties_update visitor - -In `chain_properties_evaluators.cpp`, add the new `chain_properties_hfN` visitor: -```cpp -result_type operator()(const chain_properties_hfN& p) const { - FC_ASSERT(_db.has_hardfork(CHAIN_HARDFORK_N), "chain_properties_hfN"); - _wprops = p; -} -``` - ---- - -## 7. Deployment checklist - -Before merging / deploying: - -- [ ] `CHAIN_NUM_HARDFORKS` incremented -- [ ] `CHAIN_VERSION` bumped if protocol-visible change -- [ ] `CHAIN_SCHEMA_VERSION` incremented if ANY chainbase object layout changed -- [ ] Hardfork `.hf` file created with future timestamp -- [ ] All new fields have zero defaults; `apply_hardfork` comment explains why no migration needed -- [ ] New evaluator registered in `initialize_evaluators()` -- [ ] New virtual op registered in `account_history` plugin -- [ ] `witness_api_object` updated if `witness_object` changed -- [ ] Snapshot plugin updated if new chainbase objects added - ---- - -## 8. Schema version — full lifecycle - -``` -First run (fresh node or missing schema_version file): - stored = 0, compiled = N → mismatch - wipe shared_memory (no-op if not present) - write schema_version = N - db.open() → init_genesis → revision=0, head=0 → no exception - -Upgrade (old binary had schema version M < N): - stored = M, compiled = N → mismatch - wipe shared_memory.bin - write schema_version = N - db.open() → init_genesis → revision=0, head=head_block_log - → database_revision_exception - → auto-recovery: snapshot import + dlt_block_log replay - OR replay-if-corrupted: full block_log replay - -Normal restart (schema unchanged): - stored = N, compiled = N → match - db.open() proceeds normally - write schema_version = N (confirms success) -``` - -**Key files:** -- `libraries/protocol/include/graphene/protocol/config.hpp` — `CHAIN_SCHEMA_VERSION` -- `plugins/chain/plugin.cpp` — `read_schema_version()`, `write_schema_version()`, - schema check block in `plugin_startup()` -- `/schema_version` — plain text file, single `uint32_t` - ---- - -## 9. Related documentation - -- [dlt-hardfork-new-objects.md](dlt-hardfork-new-objects.md) — adding new chainbase indexes -- [hf13-validator-reward-sharing.md](hf13-validator-reward-sharing.md) — reference implementation (HF13) -- [snapshot-plugin.md](snapshot-plugin.md) — snapshot format and import/export -- [shared-memory.md](shared-memory.md) — chainbase shared memory internals diff --git a/.qoder/docs/hf13-validator-reward-sharing.md b/.qoder/docs/hf13-validator-reward-sharing.md deleted file mode 100644 index bacacc166a..0000000000 --- a/.qoder/docs/hf13-validator-reward-sharing.md +++ /dev/null @@ -1,423 +0,0 @@ -# HF13: Validator Reward Sharing - -## Overview - -Hardfork 13 introduces **stakeholder reward sharing**: validators can configure a percentage of -their block reward to be accumulated and periodically distributed among the accounts that voted -for them (stakeholders). - -**Key design principle**: Stakeholder rewards are accumulated and distributed in **TOKEN (VIZ)** -atomic units, not SHARES. Stakeholders receive SHARES only after `create_vesting()` converts -their token share at the time of distribution. The `witness_reward_operation` virtual op for the -validator itself continues to carry SHARES as before, but only for the validator's own portion. - ---- - -## New Chain Property: `distribution_epoch_length` - -| Property | Type | Default | Range | -|---|---|---|---| -| `distribution_epoch_length` | `uint32_t` | `28800` (1 day) | `[21, ~10.5M]` | - -Validators vote on this parameter via `versioned_chain_properties_update_operation` using the new -`chain_properties_hf13` struct. The median across all scheduled validators becomes the consensus -value. At every block whose number is divisible by `distribution_epoch_length`, accumulated -stakeholder rewards are paid out. - ---- - -## New Operation: `set_reward_sharing_operation` - -Validators use this operation to set their **sharing rate** — the fraction of their block reward -that will be set aside for stakeholder distribution. - -```json -{ - "type": "set_reward_sharing_operation", - "value": { - "owner": "alice", - "sharing_rate": 5000 - } -} -``` - -| Field | Type | Description | -|---|---|---| -| `owner` | `account_name_type` | Validator account name | -| `sharing_rate` | `uint16_t` | Basis points: 0 = 0%, 10000 = 100% | - -**Required authority**: active key of `owner`. -**Requires HF13**: the operation is rejected before HF13 activates. -**Validator must exist**: account must have a registered `witness_object`. - ---- - -## Block Reward Split (process_funds) - -With HF13 active, when a validator (`sharing_rate > 0`) produces a block: - -``` -witness_reward = CHAIN_DIGITAL_ASSET_ISSUED_PER_BLOCK * inflation_witness_percent - (TOKEN, computed in process_funds) - -stakeholder_token = witness_reward * sharing_rate / CHAIN_100_PERCENT -validator_token = witness_reward - stakeholder_token - -# Validator receives their SHARES immediately: -create_vesting(validator_account, validator_token) -→ emits witness_reward_operation(validator, validator_shares) - -# Stakeholder pool accumulates TOKEN: -witness_object.pending_stakeholder_reward += stakeholder_token -``` - -When `sharing_rate == 0`, the full reward goes to the validator as usual (no change). - ---- - -## Epoch Distribution (process_validator_epoch_distribution) - -Called at the end of `_apply_block` on every block where -`head_block_num % distribution_epoch_length == 0`. - -For each `witness_object` with `pending_stakeholder_reward > 0`: - -``` -epoch_start_block = head_block_num - epoch_length + 1 - -# Time-weighted contribution per stakeholder: -for each stakeholder: - first_block = max(stakeholder.vote_created_block, epoch_start_block) - blocks_in_epoch = head_block_num - first_block + 1 - weighted[stakeholder] = stakeholder.witness_vote_weight() * blocks_in_epoch - -total_weighted = Σ weighted[stakeholder] - -# Distribution: -for each stakeholder: - stakeholder_token = total_token * weighted[stakeholder] / total_weighted - - if stakeholder_token < CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT: - skip (dust) - else: - stakeholder_shares = create_vesting(stakeholder_account, stakeholder_token) - emit stakeholder_reward_operation(validator, stakeholder, stakeholder_shares) - -dust_token = total_token - Σ(distributed stakeholder_token) -if dust_token > 0: - dust_shares = create_vesting(validator_account, dust_token) - emit witness_reward_operation(validator, dust_shares) - -wit.pending_stakeholder_reward = 0 -``` - -### Important notes - -- **Vote weight** used: `stakeholder.validator_vote_fair_weight()` — total stake (own vesting - shares + shares proxied by accounts that delegated voting to this stakeholder) divided by - `validators_voted_for`. This matches the per-validator weight used in consensus scheduling: - a stakeholder who splits their vote across N validators contributes 1/N of their stake to - each validator's distribution pool. -- **Time-weighted distribution**: each stakeholder's weight is multiplied by the number of blocks - they were actually voting for this validator within the current epoch (see `vote_created_block` - on `validator_vote_object`). A stakeholder who joined mid-epoch receives a proportionally smaller - share. -- **Pre-HF13 votes** (`vote_created_block == 0`) are treated as having voted since epoch start - (`first_block = epoch_start_block`), so they receive a full-epoch weight. No penalty for - existing stakeholders. -- **Min payout**: `CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT = 1` TOKEN atomic unit (0.001 VIZ). - Stakeholders with a computed share below this threshold receive nothing; their portion is - returned to the validator as dust (see design rationale below). -- **No-stakeholder case**: if a validator has no stakeholders, the entire accumulated pool is - returned to the validator via `validator_reward_operation`. - -#### Dust design rationale - -The accumulated reward pool belongs to the validator — sharing it with stakeholders is entirely -the validator's voluntary decision, expressed via `sharing_rate`. A stakeholder who fails to -accumulate a share above `CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT` (e.g. they hold very little stake, -or voted mid-epoch) has simply not earned a viable payout. The responsibility for that outcome -lies with the stakeholder, not with the validator. - -Consequently, unclaimed dust is **not burned**. After all eligible stakeholders are paid, any -remainder (dust from integer rounding, plus skipped sub-threshold shares) is transferred back to -the validator via `validator_reward_operation`. The validator retains what their stakeholders -collectively failed to claim — no TOKEN leaves the system, and the validator is not penalised for -stakeholders with negligible weight. - ---- - -## Mid-Epoch Sharing Rate Change - -If a validator calls `set_reward_sharing_operation` while an epoch is in progress, the new rate -takes effect **immediately on the next block**. The accumulated `pending_stakeholder_reward` is -NOT retroactively recalculated. - -Concretely, if an epoch spans N blocks and the rate changes after block K: - -``` -pending_stakeholder_reward = - Σ(block 1..K) reward_i * old_rate / CHAIN_100_PERCENT - + Σ(block K+1..N) reward_i * new_rate / CHAIN_100_PERCENT -``` - -The pool that stakeholders receive at epoch end is thus a weighted mix of both rates. This is the -intended behaviour: the validator controls their own split on a per-block basis, and stakeholders -observe the change immediately on-chain via the `sharing_rate` field of the `validator_object`. - ---- - -## Flash-Voter Protection - -Flash-voting (voting just before epoch end to capture the full accumulated pool) is mitigated by -the **time-weighted distribution** described above. - -### How it works - -`validator_vote_object` stores `vote_created_block` — the block number when the vote was cast. At -epoch end, each stakeholder's effective weight is scaled by: - -``` -blocks_in_epoch = head_block_num - max(vote_created_block, epoch_start_block) + 1 -``` - -A flash voter who votes in the last `k` blocks of a `N`-block epoch receives only `k/N` of their -stake-proportional share. For a 1-day epoch (28800 blocks), voting in the last block yields -`1/28800 ≈ 0.003%` of their proportional share — economically insignificant. - -### Residual risk - -The protection covers **new votes** only. If a stakeholder already held a vote from a previous -epoch, they receive a full-epoch weight regardless of their stake changes within the epoch. This -is acceptable: they were genuine stakeholders. - -Vote removal before epoch end results in the stakeholder not appearing in `validator_vote_index` at -distribution time, so they receive nothing — no exploit in this direction. - ---- - -## New Virtual Operation: `stakeholder_reward_operation` - -Emitted once per stakeholder per distribution epoch when they receive a non-dust reward. - -| Field | Type | Description | -|---|---|---| -| `validator` | `account_name_type` | Validator that produced the accumulated rewards | -| `stakeholder` | `account_name_type` | Stakeholder account receiving the reward | -| `shares` | `asset` | SHARES credited to the stakeholder | - ---- - -## Token Accounting - -``` -Before HF13: - current_supply += witness_reward (TOKEN) [issued] - total_vesting_fund += witness_reward (TOKEN) [via create_vesting] - validator.vesting_shares += validator_shares [via create_vesting] - -After HF13 with sharing_rate > 0: - current_supply += witness_reward (TOKEN) [issued, same as before] - total_vesting_fund += validator_token (TOKEN) [via create_vesting — immediate] - validator.vesting_shares += validator_shares [via create_vesting — immediate] - wit.pending_stakeholder_reward += stakeholder_token [TOKEN, pending] - - ...at epoch end: - total_vesting_fund += stakeholder_token (TOKEN) [via create_vesting per stakeholder] - stakeholder.vesting_shares += stakeholder_shares [via create_vesting per stakeholder] - wit.pending_stakeholder_reward = 0 [cleared] -``` - -The floating `pending_stakeholder_reward` TOKEN is already counted in `current_supply`. The -`total_vesting_fund` balance is updated when the TOKEN converts to SHARES via `create_vesting` at -distribution time. - ---- - -## Configuration Example - -```ini -# Set sharing rate to 30% (3000 basis points) -# Submit set_reward_sharing_operation via API or wallet - -# Set epoch length to 5 days via versioned_chain_properties_update_operation: -# chain_properties_hf13.distribution_epoch_length = 144000 (5 * 28800 blocks) -``` - ---- - -## Deployment: Shared Memory Compatibility and Replay - -### Why replay is required - -HF13 adds three new fields to chainbase-managed objects: - -| Object | New field | Default | -|---|---|---| -| `witness_object` | `sharing_rate` (`uint16_t`) | `0` | -| `witness_object` | `pending_stakeholder_reward` (`share_type`) | `0` | -| `witness_vote_object` | `vote_created_block` (`uint32_t`) | `0` | - -Chainbase stores objects as raw binary in a memory-mapped file (`shared_memory.bin`). -Adding a field changes `sizeof()`, so the old shared memory is **binary-incompatible** with -the new binary. If the new binary opens old shared memory, chainbase reads objects at -incorrect offsets, producing corrupt data and ultimately a `database_revision_exception` -(revision counter in shared memory will not match `head_block_num`). - -**No apply_hardfork migration is needed**: the new fields default to `0`, which is the -correct pre-HF13 state. Once the node replays or restores from snapshot, all objects -are initialised correctly. - ---- - -### Automatic recovery (existing mechanism) - -The chain plugin already handles this case. On `database_revision_exception` at startup, -it executes one of two recovery paths depending on config: - -``` -Startup - └─ db.open(shared_memory) - └─ EXCEPTION: database_revision_exception - │ - ├─ [auto-recover-from-snapshot = true AND snapshot exists] - │ wipe shared_memory - │ → import latest snapshot (state restored to block N) - │ → replay dlt_block_log blocks N+1..dlt_head - │ (bridges gap between snapshot and last known block) - │ → continue P2P sync for remaining blocks - │ - └─ [replay-if-corrupted = true, no snapshot] - → replay from block_log (slow, may take hours) -``` - -The dlt_block_log replay step (handled in `snapshot_plugin.cpp:2104–2121`) is automatic: -after the snapshot is imported, the node calls `db.reindex_from_dlt(snapshot_head + 1)` -to re-apply any local blocks that are newer than the snapshot. This minimises P2P sync -work after upgrade. - -**Recommended config for production validators:** - -```ini -# config.ini (or config_witness.ini) -replay-if-corrupted = true -replay-from-snapshot = true -snapshot-auto-latest = true -snapshot-dir = /path/to/snapshots -``` - -With this config, upgrading to the HF13 binary requires no manual intervention: -1. Stop the node. -2. Replace the binary. -3. Start the node — auto-recovery fires, wipes shared memory, loads the latest snapshot, - replays `dlt_block_log`, then syncs the remaining blocks via P2P. - ---- - -### Manual recovery procedure - -If auto-recovery is not configured, or the recovery path fails, perform the following: - -```bash -# 1. Stop vizd -systemctl stop vizd - -# 2. Delete shared memory (forces clean open on next start) -rm -f /path/to/node_data_dir/shared_memory.bin - -# Option A — restore from snapshot + replay dlt_block_log: -./vizd --replay-from-snapshot /path/to/snapshot-block-XXXXXXXX.json \ - --data-dir /path/to/node_data_dir - -# Option B — full replay from block_log (slow): -./vizd --replay --data-dir /path/to/node_data_dir -``` - -After Option A the node replays `dlt_block_log` automatically (same path as auto-recovery), -then syncs remaining blocks via P2P. Typical recovery time with a recent snapshot: a few -minutes. Full replay (Option B) may take several hours depending on blockchain height. - ---- - -### How chainbase detects the mismatch - -Chainbase does **not** compare `sizeof()` at open time — it opens the memory-mapped file -and begins reading. The mismatch surfaces as a revision inconsistency: - -``` -database::open() - chainbase::database::open(shared_mem_dir) ← objects read at wrong offsets - undo_all() ← traverses corrupt undo state - revision() != head_block_num() ← counter mismatch detected here - → throws database_revision_exception -``` - -Alternatively, `undo_all()` may trigger a `boost::interprocess::lock_exception` if the -process crashed while holding a shared-memory mutex (unrelated to HF13, but the same -recovery path applies). - -**Implication**: deleting `shared_memory.bin` before starting is the safest option. The -file is always rebuilt from snapshot or block_log; nothing of value is lost. - ---- - -### Proactive schema version check (implemented in HF13) - -Rather than waiting for a corrupt read to surface as a `database_revision_exception`, -the chain plugin now performs a **proactive schema version check** before calling -`db.open()`: - -``` -plugin_startup() - │ - ├─ read /schema_version (0 if file absent = pre-HF13 node) - ├─ compare with CHAIN_SCHEMA_VERSION (compile-time constant, currently 13) - │ - ├─ MISMATCH → wipe shared_memory.bin immediately (no corrupt read occurs) - │ write new schema_version to disk - │ → fall through to normal db.open() - │ → revision=0 ≠ head_block_num → database_revision_exception - │ → existing recovery: auto-snapshot or replay - │ - └─ MATCH → proceed normally - db.open() succeeds → write schema_version (confirm success) -``` - -**Key constant** (`config.hpp`): -```cpp -// Increment whenever a chainbase-managed object gains, loses, or resizes a field. -#define CHAIN_SCHEMA_VERSION uint32_t(13) -``` - -**Key file**: `/schema_version` — a plain text file containing a single -`uint32_t`. Absent file is treated as version `0` (pre-HF13). - -This mechanism is completely transparent: nodes that don't have `schema_version` -(old deployments upgrading to HF13 for the first time) automatically get `stored=0`, -mismatch is detected, shared memory is wiped, and recovery proceeds. - -See [hardfork-guide.md](hardfork-guide.md) for the rule: **increment -`CHAIN_SCHEMA_VERSION` in every hardfork that adds, removes, or resizes a field in -any chainbase-managed object**. - ---- - -## Files Changed - -| File | Change | -|---|---| -| `libraries/chain/hardfork.d/13.hf` | New hardfork definition | -| `libraries/chain/hardfork.d/0-preamble.hf` | `CHAIN_NUM_HARDFORKS` 12 → 13 | -| `libraries/protocol/include/graphene/protocol/config.hpp` | `CHAIN_VERSION` 3.2.0; `CHAIN_VALIDATOR_MAX_SHARING_RATE`, `CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT`, `CHAIN_SCHEMA_VERSION` | -| `libraries/protocol/include/graphene/protocol/chain_operations.hpp` | `chain_properties_hf13`, `set_reward_sharing_operation` | -| `libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp` | `stakeholder_reward_operation` | -| `libraries/protocol/include/graphene/protocol/operations.hpp` | New ops in variant | -| `libraries/protocol/chain_operations.cpp` | `validate()` for `set_reward_sharing_operation` | -| `libraries/chain/include/graphene/chain/witness_objects.hpp` | `chain_properties` alias → `hf13`; `sharing_rate`, `pending_stakeholder_reward` fields; `vote_created_block` on `witness_vote_object` | -| `libraries/chain/include/graphene/chain/chain_evaluator.hpp` | `DEFINE_EVALUATOR(set_reward_sharing)` | -| `libraries/chain/include/graphene/chain/database.hpp` | `process_validator_epoch_distribution()` declaration | -| `libraries/chain/chain_properties_evaluators.cpp` | HF13 visitor case; `set_reward_sharing_evaluator::do_apply` | -| `libraries/chain/chain_evaluator.cpp` | Set `vote_created_block` in all `create` paths | -| `libraries/chain/database.cpp` | Hardfork registration; evaluator registration; median; `process_funds` split; `process_validator_epoch_distribution` (time-weighted); `_apply_block` call; `apply_hardfork` case | -| `plugins/account_history/plugin.cpp` | Impacted accounts for `stakeholder_reward_operation` | -| `plugins/chain/plugin.cpp` | `CHAIN_SCHEMA_VERSION` check + proactive wipe before `db.open()`; `read_schema_version` / `write_schema_version` helpers; `#include ` | diff --git a/.qoder/docs/index.md b/.qoder/docs/index.md deleted file mode 100644 index 75f63249e3..0000000000 --- a/.qoder/docs/index.md +++ /dev/null @@ -1,175 +0,0 @@ -# VIZ Blockchain — Operations & Structures Spec - -Full specification and implementation checklist for building VIZ blockchain client libraries in PHP, Node.js, and other languages. - ---- - -## Files in This Directory - -### Research (`../research/`) - -| File | Contents | -|---|---| -| [consensus-emergency-recovery.md](../research/consensus-emergency-recovery.md) | Research: automatic emergency consensus mode for network stall recovery & micro-fork prevention | - -### Documentation (`./`) - -| File | Contents | -|---|---| -| [cli-wallet.md](cli-wallet.md) | Complete CLI wallet command reference with examples | -| [data-types.md](data-types.md) | Primitive types, `asset`, `authority`, `public_key_type`, operation type index | -| [plugins.md](plugins.md) | All node plugins, dependencies, status, JSON-RPC method tables | -| [block-processing.md](block-processing.md) | Block application flow, pending transactions, postponed tx mechanism | -| [shared-memory.md](shared-memory.md) | Shared memory architecture, locking model, resize workflow, config parameters, corruption risks | -| [block-log-spec.md](block-log-spec.md) | Block log binary format, index files, operation serialization, **tools: reader/viewer, bitmask, search & export** | -| [fork-collision-hardfork-proposal.md](fork-collision-hardfork-proposal.md) | Fork collision analysis, HF12 proposal for consensus improvements | -| [consensus-emergency-params.md](consensus-emergency-params.md) | Emergency restart parameters (enable-stale-production, required-participation, fork_db) & micro-fork risks | -| [emergency-consensus-review.md](emergency-consensus-review.md) | HF12 implementation review: failure/rollback procedures, threat model, test matrix | -| [op-account.md](op-account.md) | Account create, update, metadata operations | -| [op-transfer-vesting.md](op-transfer-vesting.md) | Transfer, transfer_to_vesting, withdraw_vesting, set route, delegate | -| [op-validator.md](op-validator.md) | validator update, vote, proxy, chain properties | -| [op-content.md](op-content.md) | Content, vote, delete_content (deprecated), custom | -| [op-recovery.md](op-recovery.md) | Request/recover account, change recovery account | -| [op-escrow.md](op-escrow.md) | Escrow transfer, approve, dispute, release | -| [op-committee.md](op-committee.md) | Committee worker create/cancel request, vote | -| [op-invite.md](op-invite.md) | Create invite, claim balance, register, use balance | -| [op-award.md](op-award.md) | Award, fixed_award operations | -| [op-subscription.md](op-subscription.md) | Set paid subscription, paid subscribe | -| [op-account-market.md](op-account-market.md) | Set account/subaccount price, buy account, target sale | -| [op-proposal.md](op-proposal.md) | Proposal create, update, delete (multi-sig) | -| [virtual-operations.md](virtual-operations.md) | All virtual operations (read-only, blockchain-generated) | - ---- - -## Quick Reference: All Operations - -### Regular Operations (user-broadcast) - -| ID | Name | Auth | Key File | -|---|---|---|---| -| 0 | `vote_operation` *(deprecated)* | regular | op-content.md | -| 1 | `content_operation` *(deprecated)* | regular | op-content.md | -| 2 | `transfer_operation` | active (VIZ) / master (SHARES) | op-transfer-vesting.md | -| 3 | `transfer_to_vesting_operation` | active | op-transfer-vesting.md | -| 4 | `withdraw_vesting_operation` | active | op-transfer-vesting.md | -| 5 | `account_update_operation` | master/active | op-account.md | -| 6 | `witness_update_operation` | active | op-validator.md | -| 7 | `account_witness_vote_operation` | active | op-validator.md | -| 8 | `account_witness_proxy_operation` | active | op-validator.md | -| 9 | `delete_content_operation` *(deprecated)* | regular | op-content.md | -| 10 | `custom_operation` | active/regular | op-content.md | -| 11 | `set_withdraw_vesting_route_operation` | active | op-transfer-vesting.md | -| 12 | `request_account_recovery_operation` | active | op-recovery.md | -| 13 | `recover_account_operation` | master (×2) | op-recovery.md | -| 14 | `change_recovery_account_operation` | master | op-recovery.md | -| 15 | `escrow_transfer_operation` | active | op-escrow.md | -| 16 | `escrow_dispute_operation` | active | op-escrow.md | -| 17 | `escrow_release_operation` | active | op-escrow.md | -| 18 | `escrow_approve_operation` | active | op-escrow.md | -| 19 | `delegate_vesting_shares_operation` | active | op-transfer-vesting.md | -| 20 | `account_create_operation` | active | op-account.md | -| 21 | `account_metadata_operation` | regular | op-account.md | -| 22 | `proposal_create_operation` | active | op-proposal.md | -| 23 | `proposal_update_operation` | varies | op-proposal.md | -| 24 | `proposal_delete_operation` | active | op-proposal.md | -| 25 | `chain_properties_update_operation` | active | op-validator.md | -| 35 | `committee_worker_create_request_operation` | regular | op-committee.md | -| 36 | `committee_worker_cancel_request_operation` | regular | op-committee.md | -| 37 | `committee_vote_request_operation` | regular | op-committee.md | -| 43 | `create_invite_operation` | active | op-invite.md | -| 44 | `claim_invite_balance_operation` | active | op-invite.md | -| 45 | `invite_registration_operation` | active | op-invite.md | -| 46 | `versioned_chain_properties_update_operation` | active | op-validator.md | -| 47 | `award_operation` | regular | op-award.md | -| 50 | `set_paid_subscription_operation` | active | op-subscription.md | -| 51 | `paid_subscribe_operation` | active | op-subscription.md | -| 54 | `set_account_price_operation` | master | op-account-market.md | -| 55 | `set_subaccount_price_operation` | master | op-account-market.md | -| 56 | `buy_account_operation` | active | op-account-market.md | -| 58 | `use_invite_balance_operation` | active | op-invite.md | -| 60 | `fixed_award_operation` | regular | op-award.md | -| 61 | `target_account_sale_operation` | master | op-account-market.md | - -### Virtual Operations (read-only, not broadcastable) - -| ID | Name | Trigger | Key File | -|---|---|---|---| -| 26 | `author_reward_operation` | Content payout | virtual-operations.md | -| 27 | `curation_reward_operation` | Content payout | virtual-operations.md | -| 28 | `content_reward_operation` | Content payout | virtual-operations.md | -| 29 | `fill_vesting_withdraw_operation` | Withdrawal interval | virtual-operations.md | -| 30 | `shutdown_witness_operation` | validator deactivated | virtual-operations.md | -| 31 | `hardfork_operation` | Hardfork activation | virtual-operations.md | -| 32 | `content_payout_update_operation` | Content payout update | virtual-operations.md | -| 33 | `content_benefactor_reward_operation` | Content payout | virtual-operations.md | -| 34 | `return_vesting_delegation_operation` | Delegation limbo ends | virtual-operations.md | -| 38 | `committee_cancel_request_operation` | Request expires | virtual-operations.md | -| 39 | `committee_approve_request_operation` | Request approved | virtual-operations.md | -| 40 | `committee_payout_request_operation` | Payout processed | virtual-operations.md | -| 41 | `committee_pay_request_operation` | Worker paid | virtual-operations.md | -| 42 | `witness_reward_operation` | Block produced | virtual-operations.md | -| 48 | `receive_award_operation` | Award given | virtual-operations.md | -| 49 | `benefactor_award_operation` | Award with beneficiary | virtual-operations.md | -| 52 | `paid_subscription_action_operation` | Subscription payment | virtual-operations.md | -| 53 | `cancel_paid_subscription_operation` | Subscription ends | virtual-operations.md | -| 57 | `account_sale_operation` | Account sold | virtual-operations.md | -| 59 | `expire_escrow_ratification_operation` | Escrow deadline missed | virtual-operations.md | -| 62 | `bid_operation` | Bid placed (HF11) | virtual-operations.md | -| 63 | `outbid_operation` | Outbid (HF11) | virtual-operations.md | - ---- - -## Library Implementation Master Checklist - -### Serialization -- [ ] Operations serialized as `[type_id, object]` (2-element array) -- [ ] `asset` values as string `"10.000 VIZ"` or as `{"amount": int, "symbol": int}` depending on API -- [ ] `authority` serialized with `weight_threshold`, `account_auths`, `key_auths` -- [ ] `public_key_type` as VIZ-prefixed base58check string -- [ ] `time_point_sec` as ISO 8601 UTC string `"2024-01-15T12:00:00"` (no timezone suffix) -- [ ] `optional` as `null` when absent, or the value when present -- [ ] `extensions_type` always `[]` -- [ ] `flat_set` and `vector` as JSON arrays -- [ ] `flat_map` as JSON array of `[key, value]` pairs - -### Transaction Construction -- [ ] Fetch current block header for `ref_block_num` and `ref_block_prefix` -- [ ] Set `expiration` = current time + desired TTL (max 60 seconds recommended) -- [ ] Sign transaction with required keys (see each operation's authority requirements) -- [ ] `ref_block_num` = `head_block_number & 0xFFFF` -- [ ] `ref_block_prefix` = first 4 bytes (little-endian uint32) of `block_id` starting at byte 4 -- [ ] Chain ID must match target network (mainnet vs testnet) - -### Key Management -- [ ] Private keys in WIF format (Base58Check with version byte 0x80) -- [ ] Public keys in VIZ-prefixed compressed base58 format -- [ ] Derive public key from private key using secp256k1 -- [ ] Sign: sha256d(chain_id + serialized_tx) → compact ECDSA signature - -### Energy System -- [ ] Energy is in basis points (0–10000 = 0%–100%) -- [ ] Energy regenerates at 100% per day (`CHAIN_ENERGY_REGENERATION_SECONDS = 86400`) -- [ ] Formula: `current_energy = min(10000, last_energy + elapsed_seconds / REGEN_RATE)` -- [ ] Spending 1000 energy (10%) costs proportional share of reward pool - -### Asset Formatting -- [ ] VIZ: 3 decimal places, e.g. `"10.000 VIZ"` -- [ ] SHARES: 6 decimal places, e.g. `"10.000000 SHARES"` -- [ ] Parse: split on space, parse amount with decimal, check symbol - -### Account Name Validation -- [ ] Length: 3–16 characters -- [ ] Only lowercase letters, digits, hyphens, dots -- [ ] Each segment (dot-separated) starts with letter, ends with letter/digit -- [ ] Each segment >= 3 characters - -### Authority Validation -- [ ] `weight_threshold` must be satisfiable (sum of weights >= threshold) -- [ ] `key_auths` entries: `[public_key_string, uint16]` -- [ ] `account_auths` entries: `[account_name_string, uint16]` - -### Bandwidth & Fees -- [ ] Operations consume bandwidth proportional to their serialized byte size -- [ ] Data operations (`custom_operation.json` etc.) have additional bandwidth cost -- [ ] Account creation requires `fee` >= chain `account_creation_fee` -- [ ] Committee/invite/subscription operations charge network fees from chain properties diff --git a/.qoder/docs/jsonrpc-api-spec.json b/.qoder/docs/jsonrpc-api-spec.json deleted file mode 100644 index 4d821d5bdf..0000000000 --- a/.qoder/docs/jsonrpc-api-spec.json +++ /dev/null @@ -1,1353 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "VIZ Blockchain JSON-RPC API Specification", - "description": "Complete specification of all JSON-RPC methods exposed by VIZ node plugins. Intended as a machine-readable spec for API explorer generation.", - "version": "1.0.0", - "plugins": [ - { - "name": "validator_api", - "description": "Provides read-only access to validator (witness) data: schedules, votes, and validator registration info.", - "methods": [ - { - "method": "get_active_validators", - "description": "Returns the list of currently active validator account names that are participating in block production.", - "aliases": ["get_active_witnesses"], - "params": [], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Array of account names of currently active validators." - } - }, - { - "method": "get_validator_schedule", - "description": "Returns the current validator schedule object, including the shuffled list of validators and their timeshares.", - "aliases": ["get_witness_schedule"], - "params": [], - "returns": { - "type": "object", - "description": "The validator_schedule_object containing current_shuffled_validators, timeshare, and related scheduling data." - } - }, - { - "method": "get_validators", - "description": "Returns a list of validator objects by their database IDs. For each ID, returns either the validator_api_object or null if not found.", - "aliases": ["get_witnesses"], - "params": [ - { - "name": "validator_ids", - "caption": "Validator IDs", - "description": "Array of validator object database IDs to look up.", - "type": "array", - "items": { "type": "integer" }, - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of optional validator_api_object entries, one per requested ID." - } - }, - { - "method": "get_validator_by_account", - "description": "Returns the validator object registered under a specific account name, or null if the account is not a validator.", - "aliases": ["get_witness_by_account"], - "params": [ - { - "name": "account_name", - "caption": "Account Name", - "description": "The account name to look up as a validator.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The validator_api_object for the account, or null if not a validator.", - "nullable": true - } - }, - { - "method": "get_validators_by_vote", - "description": "Returns validators sorted by total votes (descending). Starts from a given account name. Only returns validators with votes > 0. Maximum 100 results.", - "aliases": ["get_witnesses_by_vote"], - "params": [ - { - "name": "from", - "caption": "From Account", - "description": "The account name to start from. Use empty string to start from the top.", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 100.", - "type": "integer", - "required": true, - "maximum": 100 - } - ], - "returns": { - "type": "array", - "description": "Array of validator_api_object entries sorted by vote count." - } - }, - { - "method": "get_validators_by_counted_vote", - "description": "Returns validators sorted by counted votes (descending). Starts from a given account name. Only returns validators with counted_votes > 0. Maximum 100 results.", - "aliases": ["get_witnesses_by_counted_vote"], - "params": [ - { - "name": "from", - "caption": "From Account", - "description": "The account name to start from. Use empty string to start from the top.", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 100.", - "type": "integer", - "required": true, - "maximum": 100 - } - ], - "returns": { - "type": "array", - "description": "Array of validator_api_object entries sorted by counted vote." - } - }, - { - "method": "get_validator_count", - "description": "Returns the total number of registered validators on the blockchain.", - "aliases": ["get_witness_count"], - "params": [], - "returns": { - "type": "integer", - "description": "Total count of registered validators." - } - }, - { - "method": "lookup_validator_accounts", - "description": "Looks up validator account names starting from a lower bound. Returns up to 1000 results alphabetically.", - "aliases": ["lookup_witness_accounts"], - "params": [ - { - "name": "lower_bound_name", - "caption": "Lower Bound Name", - "description": "The lower bound of the first account name to return. Use empty string to start from the beginning.", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Set of validator account names matching the query." - } - } - ] - }, - { - "name": "account_history", - "description": "Tracks operations by account and provides per-account operation history queries.", - "methods": [ - { - "method": "get_account_history", - "description": "Returns a map of operations for a given account in the sequence range [from-limit, from]. Each account operation has a sequence number starting from 0. Use from=-1 (4294967295) to get the most recent operations.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name whose operation history to retrieve.", - "type": "string", - "required": true - }, - { - "name": "from", - "caption": "From Sequence", - "description": "The absolute sequence number. Use -1 (4294967295) for the most recent operation.", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of operations to return. Must be between 1 and 1000. Must be less than 'from' unless from is -1.", - "type": "integer", - "required": true, - "minimum": 1, - "maximum": 1000 - } - ], - "returns": { - "type": "object", - "description": "Map of sequence number to applied_operation objects for the account." - } - } - ] - }, - { - "name": "operation_history", - "description": "Tracks all blockchain operations and provides block-level and transaction-level operation queries.", - "methods": [ - { - "method": "get_ops_in_block", - "description": "Returns the sequence of operations included or generated within a particular block. Virtual operations are generated by the blockchain (e.g. rewards) as opposed to user-submitted operations.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block whose operations should be returned.", - "type": "integer", - "required": true - }, - { - "name": "only_virtual", - "caption": "Only Virtual", - "description": "Whether to only include virtual operations in the returned results.", - "type": "boolean", - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of applied_operation objects from the specified block." - } - }, - { - "method": "get_transaction", - "description": "Returns a transaction by its ID, including block number and transaction index within the block.", - "params": [ - { - "name": "id", - "caption": "Transaction ID", - "description": "The hash (SHA-256 / ripemd160) of the transaction to retrieve.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "annotated_signed_transaction with block_num and transaction_num fields added." - } - } - ] - }, - { - "name": "database_api", - "description": "The core read-only API for the blockchain database. Provides access to blocks, accounts, chain properties, authority validation, vesting delegations, and more.", - "methods": [ - { - "method": "get_block_header", - "description": "Retrieves a block header by block number.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block whose header should be returned.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The block header, or null if no matching block was found.", - "nullable": true - } - }, - { - "method": "get_block", - "description": "Retrieves a full, signed block by block number.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block to be returned.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The full signed block, or null if no matching block was found.", - "nullable": true - } - }, - { - "method": "get_irreversible_block_header", - "description": "Retrieves a block header only if the block is irreversible. Returns null if the block has not yet been finalized.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block whose header should be returned.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The block header if the block is irreversible, or null.", - "nullable": true - } - }, - { - "method": "get_irreversible_block", - "description": "Retrieves a full, signed block only if it is irreversible. Returns null if the block has not yet been finalized.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block to be returned.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The full signed block if irreversible, or null.", - "nullable": true - } - }, - { - "method": "set_block_applied_callback", - "description": "Sets a callback function that is triggered on each newly generated block. Used for real-time block notifications via WebSocket.", - "params": [ - { - "name": "callback", - "caption": "Callback", - "description": "Callback function to invoke when a new block is applied.", - "type": "function", - "required": true - } - ], - "returns": { - "type": "null", - "description": "No return value (callback-based)." - } - }, - { - "method": "get_config", - "description": "Retrieves compile-time constants and configuration values of the blockchain (e.g., chain ID, symbol, precision).", - "params": [], - "returns": { - "type": "object", - "description": "Object containing blockchain compile-time configuration constants." - } - }, - { - "method": "get_dynamic_global_properties", - "description": "Retrieves the current dynamic global properties object, which contains real-time chain state such as head block number, total supply, and other dynamic metrics.", - "params": [], - "returns": { - "type": "object", - "description": "The dynamic_global_property_api_object with current chain state." - } - }, - { - "method": "get_chain_properties", - "description": "Retrieves the chain properties as set by the median validator schedule (chain-wide constraints like account creation fee, maximum block size, etc.).", - "params": [], - "returns": { - "type": "object", - "description": "chain_api_properties object with median chain parameters." - } - }, - { - "method": "get_hardfork_version", - "description": "Returns the current hardfork version of the blockchain.", - "params": [], - "returns": { - "type": "string", - "description": "The current hardfork version string (e.g. '0.23.0')." - } - }, - { - "method": "get_next_scheduled_hardfork", - "description": "Returns the next scheduled hardfork version and the time it is planned to go live.", - "params": [], - "returns": { - "type": "object", - "description": "Object with hf_version (string) and live_time (ISO timestamp)." - } - }, - { - "method": "get_accounts", - "description": "Returns full account objects for a list of account names. Includes balances, vesting, authority, and validator votes.", - "params": [ - { - "name": "names", - "caption": "Account Names", - "description": "Array of account names to look up.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of account_api_object entries. Only accounts that exist are returned." - } - }, - { - "method": "lookup_account_names", - "description": "Looks up accounts by their names. Returns an optional account object for each name; null if the account does not exist.", - "params": [ - { - "name": "account_names", - "caption": "Account Names", - "description": "Array of account names to look up.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of optional account_api_object entries. Each element may be null." - } - }, - { - "method": "lookup_accounts", - "description": "Looks up account names starting from a lower bound. Returns a set of account names in alphabetical order.", - "params": [ - { - "name": "lower_bound_name", - "caption": "Lower Bound Name", - "description": "The lower bound of the first account name to return.", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Set of account names matching the query." - } - }, - { - "method": "get_account_count", - "description": "Returns the total number of accounts registered on the blockchain.", - "params": [], - "returns": { - "type": "integer", - "description": "Total number of registered accounts." - } - }, - { - "method": "get_master_history", - "description": "Returns the master authority change history for a given account, useful for account recovery audits.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name whose master authority history to retrieve.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of master_authority_history_api_object entries." - } - }, - { - "method": "get_recovery_request", - "description": "Returns the current account recovery request for an account, if one exists.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name whose recovery request to check.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The account_recovery_request_api_object, or null if no request exists.", - "nullable": true - } - }, - { - "method": "get_escrow", - "description": "Returns the escrow object for a given sender and escrow ID.", - "params": [ - { - "name": "from", - "caption": "From Account", - "description": "The account name of the escrow sender.", - "type": "string", - "required": true - }, - { - "name": "escrow_id", - "caption": "Escrow ID", - "description": "The numeric escrow ID to look up.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "The escrow_api_object, or null if not found.", - "nullable": true - } - }, - { - "method": "get_withdraw_routes", - "description": "Returns vesting withdrawal routes for a given account. Can filter by direction (incoming, outgoing, or all).", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name whose withdrawal routes to retrieve.", - "type": "string", - "required": true - }, - { - "name": "type", - "caption": "Route Type", - "description": "Filter direction: 'incoming', 'outgoing', or 'all'.", - "type": "string", - "enum": ["incoming", "outgoing", "all"], - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of withdraw_route objects with from_account, to_account, percent, auto_vest." - } - }, - { - "method": "get_vesting_delegations", - "description": "Returns vesting delegation objects for a given account. Supports pagination and filtering by delegated or received.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The delegator or delegatee account name.", - "type": "string", - "required": true - }, - { - "name": "from", - "caption": "From", - "description": "The account name to start from for pagination.", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results. Defaults to 100. Must not exceed 1000.", - "type": "integer", - "required": false, - "default": 100, - "maximum": 1000 - }, - { - "name": "type", - "caption": "Delegation Type", - "description": "Filter type: 'delegated' (sent) or 'received'. Defaults to 'delegated'.", - "type": "string", - "enum": ["delegated", "received"], - "required": false, - "default": "delegated" - } - ], - "returns": { - "type": "array", - "description": "Array of vesting_delegation_api_object entries." - } - }, - { - "method": "get_expiring_vesting_delegations", - "description": "Returns expiring vesting delegation objects for a given account, starting from a given date.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The delegator account name.", - "type": "string", - "required": true - }, - { - "name": "from", - "caption": "From Date", - "description": "Start date/time for expiration lookup (ISO timestamp).", - "type": "string", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results. Defaults to 100. Must not exceed 1000.", - "type": "integer", - "required": false, - "default": 100, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "description": "Array of vesting_delegation_expiration_api_object entries." - } - }, - { - "method": "get_transaction_hex", - "description": "Returns a hexadecimal dump of the serialized binary form of a transaction.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction object to serialize.", - "type": "object", - "required": true - } - ], - "returns": { - "type": "string", - "description": "Hex-encoded serialized transaction." - } - }, - { - "method": "get_required_signatures", - "description": "Given a partially signed transaction and a set of available public keys, returns the minimal subset of public keys that should add signatures to authorize the transaction.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to analyze.", - "type": "object", - "required": true - }, - { - "name": "available_keys", - "caption": "Available Keys", - "description": "Array/set of public keys that the caller can sign with.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Set of public keys that are required to sign the transaction." - } - }, - { - "method": "get_potential_signatures", - "description": "Returns the set of all public keys that could possibly sign for a given transaction. Useful for wallets to filter their key set before calling get_required_signatures.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to analyze.", - "type": "object", - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Set of all public keys that could potentially authorize the transaction." - } - }, - { - "method": "verify_authority", - "description": "Verifies that a transaction has all of the required signatures. Returns true if valid, otherwise throws an exception.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to verify.", - "type": "object", - "required": true - } - ], - "returns": { - "type": "boolean", - "description": "true if the transaction has all required signatures." - } - }, - { - "method": "verify_account_authority", - "description": "Verifies that a set of public keys has sufficient authority to authorize actions on behalf of an account.", - "params": [ - { - "name": "name_or_id", - "caption": "Account Name", - "description": "The account name to check authority for.", - "type": "string", - "required": true - }, - { - "name": "signers", - "caption": "Signer Keys", - "description": "Array/set of public keys to verify against the account's authority.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "boolean", - "description": "true if the signers have enough authority to authorize the account." - } - }, - { - "method": "get_database_info", - "description": "Returns database shared memory usage information including total size, free size, reserved size, used size, and per-index record counts.", - "params": [], - "returns": { - "type": "object", - "description": "Object with total_size, free_size, reserved_size, used_size, and index_list (array of {name, record_count})." - } - }, - { - "method": "get_proposed_transactions", - "description": "Returns proposed transactions (proposals) associated with a given account, both authored and requiring approval.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name whose proposals to retrieve.", - "type": "string", - "required": true - }, - { - "name": "from", - "caption": "From Offset", - "description": "Offset for pagination (number of results to skip).", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of proposals to return. Must not exceed 100.", - "type": "integer", - "required": true, - "maximum": 100 - } - ], - "returns": { - "type": "array", - "description": "Array of proposal_api_object entries." - } - }, - { - "method": "get_accounts_on_sale", - "description": "Returns a list of accounts currently on sale (direct sale, not auction). Only accounts whose sale start time has passed are included.", - "params": [ - { - "name": "from", - "caption": "From Offset", - "description": "Number of results to skip for pagination.", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "description": "Array of account_on_sale_api_object entries." - } - }, - { - "method": "get_accounts_on_auction", - "description": "Returns a list of accounts currently on auction (no target buyer set). Only accounts whose sale start time has passed are included.", - "params": [ - { - "name": "from", - "caption": "From Offset", - "description": "Number of results to skip for pagination.", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "description": "Array of account_on_sale_api_object entries for auction listings." - } - }, - { - "method": "get_subaccounts_on_sale", - "description": "Returns a list of subaccounts currently on sale.", - "params": [ - { - "name": "from", - "caption": "From Offset", - "description": "Number of results to skip for pagination.", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "description": "Array of subaccount_on_sale_api_object entries." - } - } - ] - }, - { - "name": "account_by_key", - "description": "Provides a lookup from public keys to the accounts that reference those keys in their authority.", - "methods": [ - { - "method": "get_key_references", - "description": "Returns all account names that reference the given public keys in their master, active, or regular authority.", - "params": [ - { - "name": "keys", - "caption": "Public Keys", - "description": "Array of public keys to look up.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of arrays of account names. Each inner array corresponds to one input key and contains all accounts referencing that key." - } - } - ] - }, - { - "name": "network_broadcast_api", - "description": "Provides transaction and block broadcasting capabilities. This is the write API for submitting transactions to the network.", - "methods": [ - { - "method": "broadcast_transaction", - "description": "Broadcasts a signed transaction to the network. The transaction is accepted into the pending pool and propagated to P2P peers. Optionally checks that the blockchain is not too far behind.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to broadcast.", - "type": "object", - "required": true - }, - { - "name": "max_block_age", - "caption": "Max Block Age", - "description": "Optional. Maximum allowed age of the head block in seconds. If the blockchain is behind by more than this, the call will fail. Use -1 to disable.", - "type": "integer", - "required": false - } - ], - "returns": { - "type": "null", - "description": "No return value on success." - } - }, - { - "method": "broadcast_transaction_synchronous", - "description": "Broadcasts a signed transaction and waits for confirmation. Returns the transaction ID, block number, and transaction index once included in a block. The callback includes whether the transaction expired.", - "params": [ - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to broadcast.", - "type": "object", - "required": true - }, - { - "name": "max_block_age", - "caption": "Max Block Age", - "description": "Optional. Maximum allowed age of the head block in seconds. Use -1 to disable.", - "type": "integer", - "required": false - } - ], - "returns": { - "type": "object", - "description": "Object with id (transaction hash), block_num, trx_num, and expired fields." - } - }, - { - "method": "broadcast_block", - "description": "Broadcasts a signed block to the network. Typically used by validators to propagate newly produced blocks.", - "params": [ - { - "name": "block", - "caption": "Block", - "description": "The signed block to broadcast.", - "type": "object", - "required": true - } - ], - "returns": { - "type": "null", - "description": "No return value on success." - } - }, - { - "method": "broadcast_transaction_with_callback", - "description": "Broadcasts a signed transaction with a confirmation callback. The first argument is the callback, followed by the transaction. Similar to broadcast_transaction_synchronous but with custom callback handling.", - "params": [ - { - "name": "callback", - "caption": "Callback", - "description": "Confirmation callback function.", - "type": "function", - "required": true - }, - { - "name": "trx", - "caption": "Transaction", - "description": "The signed transaction to broadcast.", - "type": "object", - "required": true - }, - { - "name": "max_block_age", - "caption": "Max Block Age", - "description": "Optional. Maximum allowed age of the head block in seconds. Use -1 to disable.", - "type": "integer", - "required": false - } - ], - "returns": { - "type": "null", - "description": "No direct return; result delivered via callback." - } - } - ] - }, - { - "name": "committee_api", - "description": "Provides access to committee worker proposal requests and their voting state.", - "methods": [ - { - "method": "get_committee_request", - "description": "Returns a committee request by its ID, optionally including votes.", - "params": [ - { - "name": "request_id", - "caption": "Request ID", - "description": "The numeric ID of the committee request to retrieve.", - "type": "integer", - "required": true - }, - { - "name": "votes_count", - "caption": "Votes Count", - "description": "Number of votes to include. Use 0 for no votes, -1 for all votes, or a positive number to limit.", - "type": "integer", - "required": false, - "default": 0 - } - ], - "returns": { - "type": "object", - "description": "committee_api_object with optional embedded votes array." - } - }, - { - "method": "get_committee_request_votes", - "description": "Returns all votes for a specific committee request.", - "params": [ - { - "name": "request_id", - "caption": "Request ID", - "description": "The numeric ID of the committee request whose votes to retrieve.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "array", - "description": "Array of committee_vote_state objects." - } - }, - { - "method": "get_committee_requests_list", - "description": "Returns a list of committee request IDs filtered by status.", - "params": [ - { - "name": "status", - "caption": "Status", - "description": "The status code to filter by (e.g. 0=pending, 1=approved, etc.).", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "integer" }, - "description": "Array of committee request IDs matching the given status." - } - } - ] - }, - { - "name": "invite_api", - "description": "Provides access to invite objects used for account registration via invite keys.", - "methods": [ - { - "method": "get_invites_list", - "description": "Returns a list of invite IDs filtered by status.", - "params": [ - { - "name": "status", - "caption": "Status", - "description": "The status code to filter invites by.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "integer" }, - "description": "Array of invite database IDs matching the given status." - } - }, - { - "method": "get_invite_by_id", - "description": "Returns an invite object by its database ID.", - "params": [ - { - "name": "id", - "caption": "Invite ID", - "description": "The database ID of the invite to retrieve.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "invite_api_object with invite details (key, creator, balance, etc.)." - } - }, - { - "method": "get_invite_by_key", - "description": "Returns an invite object by its public key.", - "params": [ - { - "name": "key", - "caption": "Invite Key", - "description": "The public key associated with the invite.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "invite_api_object matching the given key." - } - } - ] - }, - { - "name": "paid_subscription_api", - "description": "Provides access to paid subscription data: subscription options set by content creators, subscription status of subscribers, and active/inactive subscription lists.", - "methods": [ - { - "method": "get_paid_subscription_options", - "description": "Returns the paid subscription settings for a given account (creator).", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name of the subscription creator.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "paid_subscription_state with subscription details (price, period, etc.)." - } - }, - { - "method": "get_paid_subscriptions", - "description": "Returns a paginated list of all paid subscription objects.", - "params": [ - { - "name": "from", - "caption": "From Offset", - "description": "Number of results to skip for pagination.", - "type": "integer", - "required": true - }, - { - "name": "limit", - "caption": "Limit", - "description": "Maximum number of results to return. Must not exceed 1000.", - "type": "integer", - "required": true, - "maximum": 1000 - } - ], - "returns": { - "type": "array", - "description": "Array of paid_subscription_object entries." - } - }, - { - "method": "get_paid_subscription_status", - "description": "Returns the subscription status of a specific subscriber for a given creator account.", - "params": [ - { - "name": "subscriber", - "caption": "Subscriber", - "description": "The account name of the subscriber.", - "type": "string", - "required": true - }, - { - "name": "account", - "caption": "Creator Account", - "description": "The account name of the subscription creator.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "paid_subscribe_state with subscription status details." - } - }, - { - "method": "get_active_paid_subscriptions", - "description": "Returns a list of creator account names that a given subscriber has active subscriptions to.", - "params": [ - { - "name": "subscriber", - "caption": "Subscriber", - "description": "The account name of the subscriber.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Array of creator account names with active subscriptions." - } - }, - { - "method": "get_inactive_paid_subscriptions", - "description": "Returns a list of creator account names that a given subscriber has inactive (expired) subscriptions to.", - "params": [ - { - "name": "subscriber", - "caption": "Subscriber", - "description": "The account name of the subscriber.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Array of creator account names with inactive subscriptions." - } - } - ] - }, - { - "name": "custom_protocol_api", - "description": "Provides access to account data enriched with custom protocol sequence information. Custom protocols allow third-party applications to track per-account custom operations.", - "methods": [ - { - "method": "get_account", - "description": "Returns an account object enriched with custom protocol sequence data for a specific custom protocol ID. Populates custom_sequence and custom_sequence_block_num fields.", - "params": [ - { - "name": "account", - "caption": "Account Name", - "description": "The account name to look up.", - "type": "string", - "required": true - }, - { - "name": "custom_protocol_id", - "caption": "Custom Protocol ID", - "description": "The custom protocol ID string to retrieve the sequence for. Use empty string to skip custom protocol lookup.", - "type": "string", - "required": true - } - ], - "returns": { - "type": "object", - "description": "account_api_object with custom_sequence and custom_sequence_block_num populated for the given protocol." - } - } - ] - }, - { - "name": "auth_util", - "description": "Provides utility methods for verifying account authority signatures against arbitrary data digests.", - "methods": [ - { - "method": "check_authority_signature", - "description": "Verifies that the provided signatures are valid for the given account's authority at a specified level (master, active, or regular). Returns the public keys derived from the signatures.", - "params": [ - { - "name": "account_name", - "caption": "Account Name", - "description": "The account name whose authority to check.", - "type": "string", - "required": true - }, - { - "name": "level", - "caption": "Authority Level", - "description": "The authority level to verify against: 'master' (or 'm'), 'active' (or 'a'), 'regular' (or 'r'). Empty string defaults to 'active'.", - "type": "string", - "required": true - }, - { - "name": "dig", - "caption": "Digest", - "description": "The SHA-256 hash of the data that was signed.", - "type": "string", - "required": true - }, - { - "name": "sigs", - "caption": "Signatures", - "description": "Array of signatures to verify.", - "type": "array", - "items": { "type": "string" }, - "required": true - } - ], - "returns": { - "type": "array", - "items": { "type": "string" }, - "description": "Array of public keys recovered from the valid signatures." - } - } - ] - }, - { - "name": "block_info", - "description": "Tracks block metadata (size, average block size, slot info) and provides queries to retrieve this information for ranges of blocks.", - "methods": [ - { - "method": "get_block_info", - "description": "Returns block metadata (block_id, block_size, average_block_size, aslot, last_irreversible_block_num) for a range of blocks starting from start_block_num.", - "params": [ - { - "name": "start_block_num", - "caption": "Start Block Number", - "description": "The first block number to return info for. Must be greater than 0.", - "type": "integer", - "required": true, - "minimum": 1 - }, - { - "name": "count", - "caption": "Count", - "description": "Number of blocks to return info for. Must not exceed 10000.", - "type": "integer", - "required": true, - "maximum": 10000 - } - ], - "returns": { - "type": "array", - "description": "Array of block_info objects. Entries may be empty if no info is stored (e.g. blocks before snapshot)." - } - }, - { - "method": "get_blocks_with_info", - "description": "Returns full signed blocks with attached metadata for a range. Limits total response size to 8 MB. Stops early if no info is stored for a block.", - "params": [ - { - "name": "start_block_num", - "caption": "Start Block Number", - "description": "The first block number to return. Must be greater than 0.", - "type": "integer", - "required": true, - "minimum": 1 - }, - { - "name": "count", - "caption": "Count", - "description": "Maximum number of blocks to return. Must not exceed 10000. Response is capped at 8 MB total.", - "type": "integer", - "required": true, - "maximum": 10000 - } - ], - "returns": { - "type": "array", - "description": "Array of block_with_info objects, each containing a signed block and its block_info metadata." - } - } - ] - }, - { - "name": "raw_block", - "description": "Provides access to raw (base64-encoded) serialized block data for low-level block inspection or re-import.", - "methods": [ - { - "method": "get_raw_block", - "description": "Returns a raw block by block number, including the base64-encoded serialized binary, block ID, previous block ID, and timestamp.", - "params": [ - { - "name": "block_num", - "caption": "Block Number", - "description": "Height of the block to retrieve in raw form.", - "type": "integer", - "required": true - } - ], - "returns": { - "type": "object", - "description": "Object with block_id, previous, timestamp, and raw_block (base64-encoded string) fields." - } - } - ] - } - ] -} diff --git a/.qoder/docs/onix-protocol-paper-ru.md b/.qoder/docs/onix-protocol-paper-ru.md deleted file mode 100644 index 3fd104a67e..0000000000 --- a/.qoder/docs/onix-protocol-paper-ru.md +++ /dev/null @@ -1,769 +0,0 @@ ---- -title: "Объединение тотализаторного расчёта с автоматическими маркет-мейкерами для рынков предсказаний с гарантией ликвидности: протокол Onix" -author: | - Анатолий Пискунов\ - Независимый исследователь — распределённый реестр VIZ\ - anatoly.piskunov@gmail.com\ - ORCID: [0009-0000-8883-4111](https://orcid.org/0009-0000-8883-4111) -date: Июнь 2026 -lang: ru-RU -header-includes: | - \usepackage{titling} - \pretitle{\begin{center}\LARGE\bfseries} - \posttitle{\par\end{center}\vspace{1.4em}} - \setlength{\droptitle}{-1.5em} - \setlength{\abovedisplayskip}{8pt} - \setlength{\belowdisplayskip}{8pt} -abstract: | - Рынки предсказаний агрегируют рассеянную информацию в вероятностные прогнозы, которые устойчиво превосходят опросы и экспертные панели, однако их распространение сдерживается структурной проблемой ликвидности: поставщики рыночной глубины несут риск неблагоприятного отбора, отпугивающий розничных участников. Мы представляем **протокол Onix** — гибридную архитектуру, которая разделяет функцию *ценообразования* и функцию *расчёта* на рынках предсказаний. Сочетая ценообразование автоматического маркет-мейкера — маркет-мейкера с постоянным произведением (CPMM) для бинарных исходов и логарифмического правила рыночного скоринга (LMSR) для многоисходных рынков — с тотализаторным (parimutuel) расчётом, мы достигаем **структурной гарантии** того, что основной капитал поставщика ликвидности никогда не подвергается риску из-за исходов ставок. Мы формализуем экономические инварианты протокола, доказываем гарантию основного капитала LP для обоих типов рынков, описываем «ленивый» пул ликвидности, обеспечивающий пассивное участие розничных пользователей, анализируем механизм разрешения споров под управлением DAO и обсуждаем экспериментальные гипотезы, для проверки которых спроектирована эта система. Протокол реализован как операции консенсусного уровня в распределённом реестре VIZ. - - \vspace{0.9\baselineskip}\noindent - **Ключевые слова:** рынки предсказаний, автоматические маркет-мейкеры, тотализатор, LMSR, предоставление ликвидности, управление через DAO, дизайн механизмов ---- - -\clearpage - -\tableofcontents - -\clearpage - -## 1. Введение - -### 1.1 Проблема ликвидности рынков предсказаний - -Рынки предсказаний — одни из наиболее надёжных механизмов агрегирования рассеянной информации в применимые вероятностные прогнозы. Эмпирические данные из политического прогнозирования (Berg, Forsythe, Nelson & Rietz, 2008), спортивных ставок (Levitt, 2004) и внутрикорпоративных рынков (Cowgill, Wolfers & Zitzewitz, 2009) показывают, что рыночные цены устойчиво превосходят альтернативные методы прогнозирования. - -Несмотря на этот послужной список, развёртывание рынков предсказаний остаётся ограниченным. Фундаментальное ограничение — не спрос на прогнозы, а *предложение ликвидности*. Каждая существующая архитектура рынка предсказаний требует, чтобы поставщики ликвидности (LP) приняли один из трёх профилей риска: - -1. **Непостоянные потери** (impermanent loss) на рынках на основе AMM (Adams, Zinsmeister & Robinson, 2020; Adams et al., 2021), где LP систематически проигрывают информированным трейдерам; -2. **Неблагоприятный отбор** на рынках с книгой лимитных заявок, где маркет-мейкеры несут инвентарный риск против лучше информированных контрагентов; -3. **Ограниченные потери субсидии** на рынках LMSR (Hanson, 2003), где маркет-мейкер рискует суммой до $b \ln N$ против корректно информированной «толпы». - -Эти профили риска ограничивают предоставление ликвидности кругом искушённых участников со способностью к активному управлению, порождая тонкие рынки с высоким проскальзыванием, которые отпугивают игроков, — самоподдерживающийся цикл: - -$$\text{тонкие рынки} \rightarrow \text{высокое проскальзывание} \rightarrow \text{плохой UX} \rightarrow \text{мало игроков} \rightarrow \text{низкие комиссии} \rightarrow \text{нет стимула для LP} \rightarrow \text{тонкие рынки}$$ - -### 1.2 Исследовательские вопросы - -Эта работа ставит и стремится ответить на следующие вопросы через развёрнутую экспериментальную систему: - -**Q1.** *Можно ли архитектурно разделить функции ценообразования и расчёта рынка предсказаний так, чтобы основной капитал LP был структурно изолирован от исходов ставок?* - -**Q2.** *Устраняет ли тотализаторный механизм расчёта, где проигравшие исключительно финансируют выигравших, проблему неблагоприятного отбора, присущую рынкам предсказаний на основе AMM и LMSR?* - -**Q3.** *Способно ли автоматическое размещение ликвидности через пуловый механизм («ленивый» пул) снизить барьер входа для LP настолько, чтобы запустить рыночную глубину без активного выбора рынков отдельными LP?* - -**Q4.** *Является ли механизм разрешения споров под управлением DAO, со взвешенным по стейку публичным голосованием и оракулами с залогом, жизнеспособной альтернативой централизованному арбитражу или оптимистичным оракулам?* - -**Q5.** *Какая полезность токена управления возникает в протоколе рынка предсказаний, где позиции LP несут вес голоса, и создаёт ли это устойчивую петлю обратной связи спроса на токен?* - -### 1.3 Вклад - -Наш вклад состоит в следующем: - -1. **Формальное доказательство** того, что сочетание ценообразования AMM с тотализаторным расчётом даёт структурную гарантию основного капитала LP для обоих типов рынков — бинарного (CPMM) и многоисходного (LMSR). -2. **Механизм «ленивого» пула** — система автоматического размещения капитала с градуированным отзывом и защитой от издержек упущенных возможностей, обеспечивающая пассивное участие розничных LP, плюс опциональная, выключенная по умолчанию подсистема кредитного плеча, финансируемая из пула, чья экспозиция *ограничена* (худший случай недостачи ограничен залогом заёмщика) и изолирована от гарантии LP по Теореме 1. -3. **Двухрежимная система разрешения споров**, сочетающая оракулов с залогом с арбитражем комитета DAO, включая полный теоретико-игровой анализ совместимости стимулов оракула. -4. **Экспериментальный протокол**, реализованный как операции консенсусного уровня в продакшен-реестре, с явными гипотезами и измеримыми результатами. - ---- - -## 2. Связанные работы - -### 2.1 Правила рыночного скоринга - -Hanson (2003) ввёл логарифмическое правило рыночного скоринга (LMSR), в котором маркет-мейкер котирует цены через функцию softmax над параметрами количеств. LMSR гарантирует ограниченные потери маркет-мейкера в размере $b \ln N$ и обеспечивает сумму цен, равную единице. Однако эта граница одновременно является и максимальным риском LP: если «толпа» верно предсказывает исход, маркет-мейкер теряет всю субсидию. Это ограничило применение LMSR корпоративными средами (Microsoft, Inkling), где оператор поглощает потери. - -### 2.2 Маркет-мейкеры с постоянным произведением - -Формула постоянного произведения $x \cdot y = k$, популяризированная Uniswap (Adams, Zinsmeister & Robinson, 2020), обеспечивает непрерывное ценообразование для пар из двух активов. В применении к бинарным рынкам предсказаний резервы представляют противоположные исходы, и инвариант даёт естественное вероятностное ценообразование. Однако стандартные LP в AMM несут непостоянные потери — эмпирический анализ показывает, что более 50% LP в Uniswap v3 уступают стратегии «купи и держи» (Adams et al., 2021). - -### 2.3 Фреймворки условных токенов - -Polymarket использует фреймворк условных токенов Gnosis (CTF), где позиции — это токены ERC-1155 с операциями разделения/слияния для обеспечения согласованности цен ($\sum p_i = 1$). Это добавляет компонуемость, но вносит сложность и требует внешнего арбитражного механизма. Оптимистичный оракул UMA обеспечивает разрешение споров через игру «вызов–ответ» с экономическими залогами. - -### 2.4 Тотализаторные ставки - -Тотализаторная (parimutuel) модель, восходящая к тотализатору Пьера Олле (1865), объединяет все ставки и распределяет ставки проигравших пропорционально между выигравшими. Это гарантирует, что «дом» никогда не платит из собственного капитала. Однако традиционные тотализаторные системы лишены ценообразования в реальном времени — коэффициенты окончательны лишь при закрытии пула, — что делает их непригодными для непрерывного агрегирования информации. - -### 2.5 Наш подход - -Протокол Onix сочетает способность AMM/LMSR к ценообразованию в реальном времени со свойством нулевого риска LP, присущим тотализаторному расчёту. AMM или LMSR служит исключительно *механизмом ценообразования* — определяет подразумеваемые вероятности и назначает веса, — тогда как расчёт следует тотализаторной модели, где проигравшие финансируют выигравших, а основной капитал LP архитектурно отделён от потока выплат. - -Это позиционирует Onix иначе, чем два других гибридных направления в литературе. Во-первых, *чувствительные к ликвидности* маркет-мейкеры (Othman, Pennock, Reeves & Sandholm, 2013; Abernethy, Chen & Vaughan, 2011) сохраняют оператора в роли контрагента, но ограничивают или формируют его потери через геометрию функции издержек; оператор всё ещё может проиграть. Onix же полностью убирает роль контрагента у LP — кривая лишь *ценообразует*, она никогда не *платит*. Во-вторых, гибриды *CLOB+AMM* (например, книги заявок, подстрахованные AMM, как в ряде дизайнов DEX и в CLOB Polymarket с AMM-резервом) смешивают две площадки ценообразования, но наследуют инвентарный риск и неблагоприятный отбор со стороны маркет-мейкинга. Onix сохраняет единую непрерывную площадку ценообразования и полностью выносит несение риска из ценообразования в тотализаторный пул. Насколько нам известно, сочетание непрерывного ценообразователя AMM/LMSR с тотализаторным расчётом (проигравшие финансируют выигравших) для получения безусловной гарантии основного капитала LP ранее не формализовалось. - ---- - -## 3. Модель протокола - -### 3.1 Участники и роли - -Мы определяем следующее множество участников $\mathcal{P}$: - -| Роль | Символ | Функция | -|------|--------|----------| -| Создатель рынка | $c \in \mathcal{P}$ | Задаёт параметры рынка, предоставляет начальную ликвидность | -| Оракул | $o \in \mathcal{P}$ | Вносит страховой залог $I_o$, принимает рынки, разрешает исходы | -| Игрок | $b_i \in \mathcal{P}$ | Делает ставки на исходы, получает токены исхода | -| Поставщик ликвидности | $\ell_j \in \mathcal{P}$ | Вносит капитал в пулы рынков или в «ленивый» пул | -| Арбитр спора | $\mathcal{D}$ | Комитет (взвешенное по стейку голосование) или именованный аккаунт | - -### 3.2 Определение рынка - -Рынок $\mathcal{M}$ — это кортеж: - -$$\mathcal{M} = (o, \tau, \mathbf{O}, t_{\text{bet}}, t_{\text{res}}, \boldsymbol{\theta}, L)$$ - -где $o$ — назначенный оракул, $\tau \in \{0, 1\}$ — тип рынка (бинарный или многоисходный), $\mathbf{O} = \{O_1, \ldots, O_N\}$ — множество исходов ($N = 2$ для бинарного, $3 \leq N \leq 10$ для многоисходного), $t_{\text{bet}}$ и $t_{\text{res}}$ — времена истечения приёма ставок и разрешения, $\boldsymbol{\theta}$ — вектор параметров комиссий, $L$ — начальная ликвидность. - -### 3.3 Структура комиссий - -Все комиссии выражены в базисных пунктах (bp), где $10000 \text{ bp} = 100\%$. Вектор комиссий: - -$$\boldsymbol{\theta} = (\theta_{\text{oracle}}, \theta_{\text{creator}}, \theta_{\text{liq}})$$ - -Комиссии вычисляются исключительно при разрешении из совокупной ставки проигравшей стороны $S_{\text{lose}}$ и никогда не удерживаются в момент размещения ставки: - -$$f_{\text{oracle}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{oracle}} / 10000 \rfloor$$ -$$f_{\text{creator}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{creator}} / 10000 \rfloor$$ -$$f_{\text{liq}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{liq}} / 10000 \rfloor$$ -$$W = S_{\text{lose}} - f_{\text{oracle}} - f_{\text{creator}} - f_{\text{liq}}$$ - -где $W$ — **пул выигрыша**, доступный для распределения выигравшим игрокам. - -### 3.4 Конечный автомат рынка - -Жизненный цикл $\mathcal{M}$ следует конечному автомату: - -$$q_0 \xrightarrow{\text{оракул принимает}} q_1 \xrightarrow{t \geq t_{\text{bet}}} q_2 \xrightarrow{\text{оракул разрешает}} q_3 \xrightarrow{\text{льготный период}} \text{выплачено}$$ - -с путём отклонения $q_0 \xrightarrow{\text{оракул отклоняет}} q_{-1}$ (удалён, ликвидность возвращена). - ---- - -## 4. Механизмы ценообразования - -### 4.1 Бинарные рынки: маркет-мейкер с постоянным произведением - -Для бинарных рынков ($N = 2$) протокол поддерживает два резерва $R_A$ и $R_B$, подчинённых инварианту: - -$$k = R_A \cdot R_B$$ - -**Инициализация.** При начальной ликвидности $L$: - -$$R_A = \lfloor L / 2 \rfloor, \quad R_B = L - R_A, \quad k = R_A \cdot R_B$$ - -**Размещение ставки.** Когда игрок $b_i$ ставит сумму $a$ на исход $A$: - -$$R'_A = R_A + a$$ -$$R'_B = \lfloor k / R'_A \rfloor$$ -$$w_i = R_B - R'_B \quad \text{(полученные токены)}$$ - -Здесь $w_i$ — *вес* игрока. Это **вычисляемая** величина — количество токенов исхода, созданных кривой, — и она в общем случае **не** равна внесённой сумме $a$: в зависимости от текущих резервов $w_i$ может быть больше или меньше $a$. Вес используется исключительно для распределения пула выигрыша при расчёте (§5.1); он никогда не является требованием, выраженным в валюте. - -**Подразумеваемая вероятность.** Подразумеваемая рынком вероятность каждого исхода: - -$$P(A) = \frac{R_A}{R_A + R_B}, \quad P(B) = \frac{R_B}{R_A + R_B}$$ - -Заметим, что $P(A) + P(B) = 1$ по построению, что устраняет необходимость во внешнем арбитражном механизме для обеспечения согласованности цен. - -### 4.2 Многоисходные рынки: LMSR - -Для рынков с $N > 2$ исходами протокол использует логарифмическое правило рыночного скоринга с ценообразованием softmax. - -**Функция издержек:** - -$$C(\mathbf{q}) = b \cdot \ln\left(\sum_{j=1}^{N} \exp(q_j / b)\right)$$ - -где $\mathbf{q} = (q_1, \ldots, q_N)$ — параметры количеств, $b$ — параметр ликвидности. - -**Функция цены (softmax):** - -$$p_i(\mathbf{q}) = \frac{\exp(q_i / b)}{\sum_{j=1}^{N} \exp(q_j / b)}$$ - -По определению softmax, $\sum_{i=1}^{N} p_i = 1$ тождественно. - -**Издержки сделки.** Издержки покупки $\Delta$ токенов на исход $i$: - -$$\text{cost}(\Delta, i) = C(\mathbf{q} + \Delta \cdot \mathbf{e}_i) - C(\mathbf{q})$$ - -**Параметр ликвидности.** Параметр $b$ финансируется субсидией LP $S$: - -$$b = \frac{S}{\ln N}$$ - -**Численная устойчивость.** Вычисление log-sum-exp использует стандартное тождество: - -$$\ln\left(\sum_j \exp(x_j)\right) = \max(\mathbf{x}) + \ln\left(\sum_j \exp(x_j - \max(\mathbf{x}))\right)$$ - ---- - -## 5. Тотализаторный расчёт и гарантия LP - -### 5.1 Единая модель расчёта - -Оба типа рынков используют идентичный механизм расчёта. При разрешении оракул объявляет выигравший исход $O^* \in \mathbf{O}$. Пусть $\mathcal{W}$ — множество ставок на $O^*$, а $\mathcal{L}$ — все остальные ставки. - -$$S_{\text{lose}} = \sum_{b_i \in \mathcal{L}} a_i$$ - -где $a_i$ — сумма ставки. Пул выигрыша $W$ вычисляется как в §3.3. - -Каждый выигравший игрок $b_i \in \mathcal{W}$ получает: - -$$\pi_i = a_i + \frac{w_i}{\sum_{b_j \in \mathcal{W}} w_j} \cdot W - \tau_i$$ - -где $w_i$ — вес игрока (токены из CPMM или LMSR), а $\tau_i$ — временной штраф на прибыль (§5.3). - -### 5.2 Теорема: гарантия основного капитала LP - -**Теорема 1.** *При тотализаторном расчёте суммарная распределённая сумма равна суммарной полученной сумме, причём основной капитал LP $L$ возвращается безусловно. Основной капитал LP никогда не подвергается риску из-за исходов ставок.* - -*Доказательство.* Рассмотрим полный денежный поток через рынок: - -$$\text{Money}_{\text{IN}} = L + \sum_{b_i \in \mathcal{W}} a_i + \sum_{b_i \in \mathcal{L}} a_i = L + \sum_{\text{all bets}} a_i$$ - -где первая сумма $\sum_{b_i \in \mathcal{W}} a_i$ — совокупный основной капитал, поставленный *выигравшими* (возвращается им полностью при расчёте), а $S_{\text{lose}} = \sum_{b_i \in \mathcal{L}} a_i$ — совокупная ставка, утраченная *проигравшими* (единственный источник пула выигрыша и всех комиссий). При разрешении исходящие потоки таковы: - -$$\text{Money}_{\text{OUT}} = L + \sum_{b_i \in \mathcal{W}} a_i + W + f_{\text{oracle}} + f_{\text{creator}} + f_{\text{liq}}$$ - -Подставляя $W = S_{\text{lose}} - f_{\text{oracle}} - f_{\text{creator}} - f_{\text{liq}}$: - -$$\text{Money}_{\text{OUT}} = L + \sum_{b_i \in \mathcal{W}} a_i + S_{\text{lose}}$$ -$$= L + \sum_{b_i \in \mathcal{W}} a_i + \sum_{b_i \in \mathcal{L}} a_i = L + \sum_{\text{all bets}} a_i = \text{Money}_{\text{IN}} \qquad \blacksquare$$ - -**Следствие 1.** *Гарантия основного капитала LP выполняется независимо от механизма назначения весов, числа игроков, распределения ставок по исходам или параметров комиссий. Это свойство архитектуры расчёта, а не кривой ценообразования.* - -**Следствие 2.** *Максимальная суммарная выплата выигравшим равна $S_{\text{lose}}$ (весь пул проигравших), независимо от весов, назначенных AMM или LMSR. Следовательно, выплаты выигравшим никогда не могут черпаться из капитала LP.* - -**Замечание (целочисленная арифметика и платёжеспособность при округлении).** Теорема 1 сформулирована над рациональными числами, но протокол оперирует целыми числами (милли-VIZ), и каждое деление применяет оператор пола $\lfloor \cdot \rfloor$. Покажем, что гарантия переживает дискретизацию. Каждая комиссия и каждая доля выигравшего округляются *вниз*: - -$$f_\bullet = \lfloor S_{\text{lose}} \cdot \theta_\bullet / 10000 \rfloor, \qquad \hat{\pi}_i^{\text{profit}} = \left\lfloor \frac{w_i}{\sum_{j} w_j} \cdot W \right\rfloor$$ - -Поскольку $\lfloor x \rfloor \leq x$, фактическое распределение выигравшим удовлетворяет $\sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} \leq W$, и аналогично $\sum_\bullet f_\bullet \leq S_{\text{lose}} \cdot (\theta_{\text{oracle}}+\theta_{\text{creator}}+\theta_{\text{liq}})/10000 \leq S_{\text{lose}}$. Поэтому фактический отток подчиняется - -$$\text{Money}_{\text{OUT}}^{\text{realized}} = L + \sum_{i \in \mathcal{W}} a_i + \sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} + \sum_\bullet f_\bullet \;\leq\; L + \sum_{\text{all bets}} a_i = \text{Money}_{\text{IN}}$$ - -так что система никогда не становится неплатёжеспособной. Неотрицательный остаток - -$$\epsilon = S_{\text{lose}} - \sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} - \sum_\bullet f_\bullet \;\geq\; 0$$ - -ограничен $\epsilon < |\mathcal{W}| + 3$ милли-VIZ (одна субъединица на каждую округлённую величину) и сметается в фонд DAO как «пыль». Таким образом, округление может лишь *недо*-распределять, но никогда не пере-распределять: основной капитал LP $L$ сохраняется точно, а неравенство $\text{Money}_{\text{OUT}} \leq \text{Money}_{\text{IN}}$ выполняется на гранулярности реестра. $\blacksquare$ - -### 5.3 Временной штраф за поздние ставки - -Чтобы смягчить информационную асимметрию ставок вблизи истечения (когда неопределённость исхода снижена), протокол вводит настраиваемый временной штраф, применяемый *только к прибыли*, никогда — к основному капиталу. - -Пусть $\Delta t = t_{\text{bet}} - t_{\text{now}}$ — время до истечения, а $\omega$ — окно штрафа. Если $\Delta t < \omega$: - -$$r = 1 - \frac{\Delta t}{\omega}$$ - -$$\tau_{\text{rate}} = \begin{cases} r & \text{линейный} \\ r^2 & \text{квадратичный (по умолчанию)} \end{cases}$$ - -$$\tau_i = \lfloor \pi_{\text{profit},i} \cdot \tau_{\text{rate}} \cdot \tau_{\max} / 10^6 \rfloor$$ - -где $\pi_{\text{profit},i}$ — доля прибыли игрока (без основного капитала), а $\tau_{\max}$ — максимальный штраф в микроединицах. - -**Инвариант:** $\pi_i \geq a_i$ для всех выигравших игроков, поскольку штраф применяется исключительно к компоненте прибыли. - -### 5.4 Взвешенное по времени распределение комиссий LP - -Доли комиссий LP распределяются пропорционально произведению суммы вклада на остаточное время до истечения: - -$$\omega_j = \text{amount}_j \cdot \max(1, t_{\text{bet}} - t_{\text{deposit},j})$$ - -$$f_{\text{share},j} = \left\lfloor \frac{f_{\text{pool}} \cdot \omega_j}{\sum_m \omega_m} \right\rfloor$$ - -Это создаёт сильный стимул к раннему предоставлению ликвидности. На рынке длительностью $T$ LP, вносящий депозит в момент $t = 0$, зарабатывает в $T$ раз больше на единицу капитала, чем вносящий в $t = T - 1$. - ---- - -## 6. «Ленивый» пул ликвидности - -### 6.1 Мотивация - -Индивидуальное предоставление ликвидности требует активной оценки и выбора рынков. Для розничных участников это создаёт непрактичный барьер знаний и усилий. «Ленивый» пул (так названный потому, что не требует от вкладчиков активного выбора рынков) решает это, принимая депозиты и автоматически размещая капитал в активируемые рынки. - -### 6.2 Механика пула - -«Ленивый» пул $\mathcal{L}_P$ — это синглтон-контракт, поддерживающий: - -- $B_{\text{free}}$: нераспределённый баланс -- $B_{\text{alloc}}$: капитал, размещённый в активных рынках -- $B_{\text{earned}}$: реализованная прибыль -- $S_{\text{total}}$: общее число выпущенных долей -- $\rho$: накопитель совокупного вознаграждения на долю - -**Депозит.** Когда пользователь $u$ вносит сумму $a$: - -$$\text{shares}_u = \begin{cases} a & \text{if } S_{\text{total}} = 0 \\ a \cdot S_{\text{total}} / B_{\text{free}} & \text{otherwise} \end{cases}$$ - -Депозит блокируется на заданный управлением период $t_{\text{lock}}$. - -**Авто-размещение.** При активации рынка ($q_0 \rightarrow q_1$): - -$$a_{\text{alloc}} = B_{\text{free}} \cdot \alpha / 100$$ - -при условиях $a_{\text{alloc}} \geq a_{\min}$ и $B_{\text{alloc}} + a_{\text{alloc}} \leq B_{\text{total}} \cdot \alpha_{\max} / 100$, где $\alpha$ — процент размещения на рынок, а $\alpha_{\max}$ — потолок суммарного размещения. - -Формула размещения включает поправки на качество оракула: - -$$a_{\text{alloc}} = B_{\text{free}} \cdot \frac{\alpha}{100} \cdot (1 - \beta)^{n_o} \cdot (1 - \gamma)^{f_o}$$ - -где $n_o$ — число активных рынков оракула, $f_o$ — число активных штрафных меток оракула, а $\beta, \gamma$ — заданные управлением коэффициенты затухания. - -### 6.3 Распределение вознаграждений («ленивый» учёт) - -Вознаграждения распределяются с помощью единственного глобального накопителя $\rho$ (вознаграждение на долю) по паттерну MasterChef (SushiSwap, 2020; Leshner & Hayes, 2019): - -Когда рынок разрешается и LP-позиция пула приносит прибыль $\pi_{\text{pool}}$: - -$$\rho \leftarrow \rho + \frac{\pi_{\text{pool}} \cdot \text{PRECISION}}{S_{\text{total}}}$$ - -Накопленное вознаграждение любого пользователя $u$ вычислимо за $O(1)$: - -$$\text{reward}_u = \text{pending}_u + \frac{\text{shares}_u \cdot (\rho - \rho_{\text{snapshot},u})}{\text{PRECISION}}$$ - -Записи пользователя обновляются только при его действии (депозит или вывод), что даёт амортизированную стоимость $O(1)$ независимо от числа участников. - -### 6.4 Защита от издержек упущенных возможностей - -Механизм авто-размещения создаёт вектор атаки: злонамеренный оракул может создавать долгие рынки с нулевым объёмом, чтобы заблокировать капитал пула. Этому противодействуют три градуированных защитных механизма: - -**Градуированный отзыв.** Длительность рынка делится на $n_{\text{steps}}$ интервалов. На каждой контрольной точке $k$, если накопленный объём $V_k$ удовлетворяет: - -$$V_k < a_{\text{alloc}} \cdot \theta_{\text{recall}} / 100$$ - -то доля $\delta_{\text{recall}}$ текущего размещения отзывается в пул. После $n$ подряд идущих низкообъёмных контрольных точек удержанное размещение равно: - -$$a_{\text{retained}} = a_{\text{alloc}} \cdot (1 - \delta_{\text{recall}})^n$$ - -Для параметров по умолчанию ($\delta_{\text{recall}} = 10\%$, $n_{\text{steps}} = 10$) полностью простаивающий рынок удерживает $(0{.}9)^{10} \approx 35\%$ исходного размещения. - -**Штраф за активные рынки.** Каждый активный рынок оракула $o$ мультипликативно снижает новые размещения на множитель $(1 - \beta)$. При $\beta = 5\%$ и 10 активных рынках новые размещения составляют $(0{.}95)^{10} \approx 60\%$ базовой ставки. - -**Штрафные метки.** Плохие исходы (no-contest, пропуск дедлайнов, проигранные споры, разрешения с нулевым объёмом) порождают штрафные метки на оракуле, дополнительно снижающие размещения на множитель $(1 - \gamma)^{f_o}$. Метки автоматически истекают после заданного управлением окна чистой работы. - -### 6.5 Экстренный вывод - -Пользователи могут выйти из пула до истечения блокировки, при штрафе *только на заблокированную прибыль*: - -$$\text{penalty} = \max(0, V_{\text{total}} - P_{\text{deposited}}) \cdot \frac{S_{\text{locked}}}{S_{\text{total}}} \cdot \theta_{\text{emergency}} / 100$$ - -где $V_{\text{total}}$ — общая стоимость пользователя (доли + накопленные вознаграждения), $P_{\text{deposited}}$ — совокупно внесённый основной капитал, а $S_{\text{locked}} / S_{\text{total}}$ — доля ещё заблокированных долей. Штраф перераспределяется оставшимся участникам пула через $\rho$. - -### 6.6 Опциональное кредитное плечо, финансируемое из пула - -«Ленивый» пул играет вторую, опциональную роль из того же $B_{\text{free}}$: он финансирует подсистему кредитного плеча. Эта подсистема **опциональна, выключена по умолчанию и управляется медианным kill-switch**. Мы рассматриваем её отдельно от остальной статьи по важной причине. **Это единственное место, где капитал пула принимает на себя кредитный риск, поэтому оно *не* покрывается безусловной гарантией Теоремы 1.** Теорема 1 касается пула в роли *поставщика рыночной ликвидности*, где основной капитал структурно изолирован от исходов ставок. Кредитное плечо же ставит пул в роль *кредитора*, а кредитование несёт риск, который мы ограничиваем, а не устраняем. - -**Открытие позиции.** Игрок вносит залог $m$. Пул ссужает маржу $\lambda m$ при коэффициенте плеча $\lambda$ из $B_{\text{free}}$, при потолках на размер позиции, долю фонда пула и минимальную ликвидность рынка. Ни один токен не создаётся: суммарная ставка $(1+\lambda)m$ входит в рынок точно так же, как обычная ставка. Вес кривой позиции, её залог и ссуженная сумма записываются в выделенный объект позиции. Обязательство пула по позиции: - -$$\Omega = \lambda m \,(1 + r),$$ - -где $r$ — накопленный процент. Ссуда плюс процент — это то, что пул стремится вернуть. - -**Ликвидация против записанного снимка резервов.** Трудный случай на бинарных рынках с плечом — *скачковый риск* (jump risk): разрывное движение цены может оставить наивную ликвидацию «продать по текущей цене» неспособной покрыть ссуду. Onix не ликвидирует по текущей цене. Он закрывает позицию через обратный CPMM против **состояния резервов, записанного для этой позиции**, так что собственное рыночное воздействие позиции разматывается первым, а не оплачивается дважды. Возврат обеспечивают два пути: - -1. **Каскад встречной ставки** (`pm_place_bet`, причина ликвидации 0) — входящая встречная ставка запускает принудительное закрытие позиции с плечом против её записанного снимка. -2. **Принудительное закрытие при расчёте** (`pm_leverage_resolve`) — при разрешении позиция закрывается, и ссуда погашается из её веса прежде, чем заёмщику начислится прибыль. - -На этих двух путях проектная цель — полный возврат, $\text{recovered} = \min(V_{\text{close}}, \Omega) \ge \lambda m$, с возвратом фактической ссуды и процента в пул. Мы формулируем это как **проектное свойство, а не теорему**: математика расчёта по плечу реализована и проверяется в `consensus_sim`, но замкнутое доказательство возврата при всех траекториях резервов оставлено на будущую работу (§12.2). Остаточная экспозиция сосредоточена на одном пути: - -- **Добровольная отмена той же стороны** (`pm_cancel_bet`, причина 1) — если заёмщик закрывается на той же стороне при неблагоприятном движении, пул может реализовать недостачу. Эта недостача **ограничена залогом заёмщика $m$**, который удерживает протокол; она не может превысить $m$. - -**Kill-switch отвязан от защиты.** Kill-switch отключает только *новые* открытия. Пути ликвидации намеренно **не** ограничены им, поэтому отключение плеча никогда не лишает защиты уже открытые позиции. - -**Изоляция риска и вознаграждение.** Кредитование с плечом ограничено управляемой долей $B_{\text{free}}$ (`leverage_fund_percent`), так что экспозиция пула в худшем случае ограничена на уровне подсистемы и не может достичь основного капитала рыночного LP, защищённого Теоремой 1. Заработанный процент начисляется в пул через тот же накопитель $\rho$ (§6.3). Поэтому вкладчики пула зарабатывают из двух источников — доли комиссий из пула проигравших (без риска, Теорема 1) и процент по плечу (ограниченный кредитный риск, опционально), — и оба учитываются одинаково, но управляются независимо. Честное резюме: *рыночный* основной капитал LP пула никогда не под риском; его *кредитование с плечом* несёт ограниченный, опциональный, выключенный по умолчанию кредитный риск (§12.2). - -### 6.7 Дизайн-решение: только реальная глубина (без виртуальной/фантомной ликвидности) - -Естественное предложение — засеять кривую ценообразования рынка *виртуальной* (фантомной) ликвидностью: оффсетом резерва $\phi$, который уплощает влияние на цену, но не обеспечен реальным капиталом и удаляется при расчёте, опционально настраиваемым управлением. В закрытом цикле «ставка → отмена → резолюция» это сохраняет стоимость (это техника виртуального AMM) и соблазнительно как «стабилизатор» старта для новых тонких рынков. Onix **сознательно этого не внедряет.** Ту же пользу на старте уже даёт авто-аллокация «ленивого» пула (§6.2) — но *реальным* капиталом, который вдобавок зарабатывает комиссии, имеет подотчётного владельца и следует за спросом по каждому рынку. Мы отвергаем фантомную глубину, потому что при неосторожном применении она вредит ровно тому, что протокол призван защищать, — структуре рынка и доверию: - -1. **Подделываемая глубина подрывает доверие.** Глубина значима как сигнал лишь потому, что это дорогой реальный капитал под риском. Бесплатная виртуальная глубина превращает заявление «рынок глубокий и ликвидный» в подделываемое — тонкий или манипулируемый рынок можно нарядить под глубокий. Реальный капитал делает это заявление неподделываемым. -2. **Она тихо искажает агрегирование информации.** Виртуальная глубина уплощает кривую весов, ослабляя награду за раннюю верную информацию и делая отображаемую цену невосприимчивой к новостям («стабильна, потому что её нельзя сдвинуть» = устаревший прогноз). Правильная величина зависит от рынка и объёма; единственная константа управления не может за ней следовать и, заданная слишком высоко, разрушает то самое свойство открытия цены, ради которого существует рынок предсказаний. -3. **Она платёжеспособна, только пока её не выкупают и не используют как залог.** Как только глубина обеспечивает реальный отток — отмены, ранние выводы, ссуды плеча, общие/межрыночные пулы, — виртуальную часть приходится исключать везде, иначе она утекает реальными деньгами (например, ссуда плеча, рассчитанная или возвращаемая против фейковой глубины, превращается в реальный bad debt вкладчикам пула). Каждая ветка «считать против ликвидности / платить LP» становится граблями, требующими «…но не фантомную часть». Реальный капитал устраняет весь этот класс ошибок по построению. -4. **У неё нет владельца, дохода и подотчётности.** Виртуальная глубина не несёт риска и не зарабатывает комиссию никому реальному; это услуга, за которую никто не платит и за которую никто не отвечает. На рынках, которых она касается, она удаляет розничный продукт безрисковой доходности — основную гипотезу протокола (Q3, H1). - -«Ленивый» пул — та же идея, сделанная на реальных числах: авто-аллокация сглаживает запуск новых рынков, но капитал погашаем, безопасен для плеча, зарабатывает комиссии, принадлежит вкладчикам и самокорректируется по каждому рынку через градуированный отзыв (§6.4). Поэтому Onix держит **только реальные числа** — каждая единица глубины есть реальный капитал, который можно вывести, который зарабатывает и который подотчётен. Это осознанный компромисс: мы отказываемся от дешёвого виртуального стабилизатора ради целостности ценового сигнала и платёжеспособности каждого реального денежного пути. - ---- - -## 7. Разрешение споров под управлением DAO - -### 7.1 Модель оракула с залогом - -Каждый оракул $o$ обязан поддерживать страховой залог $I_o \geq I_{\min}$. Залог создаёт подотчётность: у оракулов, которые неверно разрешают рынки, пропускают дедлайны или проигрывают споры, страховка списывается. Доход оракула складывается из: - -1. Фиксированной комиссии за рынок $f_{\text{fixed}}$ (компенсирующей внесение страховки) -2. Процентной комиссии $f_{\text{oracle}}$ из пула проигравших при разрешении - -Эти две комиссии входят в систему в разных точках, и их нельзя смешивать. **Процентная комиссия** $f_{\text{oracle}}$ удерживается из $S_{\text{lose}}$ при разрешении и фигурирует в денежном потоке Теоремы 1 (§5.2). **Фиксированная комиссия** $f_{\text{fixed}}$ — это прямой перевод создатель→оракул, выполняемый при *принятии* рынка, до каких-либо ставок; поэтому она *не* является частью денежного потока ставок/LP — она не добавляется к начальной ликвидности $L$ и не черпается из $S_{\text{lose}}$, а значит не появляется в Теореме 1. (Она опущена в векторе комиссий $\boldsymbol{\theta}$ из §3.3 по той же причине: $\boldsymbol{\theta}$ собирает только процентные комиссии на момент разрешения, финансируемые проигравшими.) Для рынков с самооракулом перевод не происходит и $f_{\text{fixed}} = 0$. - -Процесс принятия оракулом реализует механизм «оферта–котировка»: создатель публикует потолки комиссий, а оракул фиксирует свои фактические условия (ограниченные как потолком создателя, так и потолком управления) при принятии. - -### 7.2 Двухрежимная система споров - -Любой игрок может оспорить разрешение в течение льготного периода $\Delta t_{\text{grace}}$, внеся в эскроу комиссию спора $d$. Во время споров все выплаты заморожены. Протокол поддерживает два режима спора на рынок: - -**Режим комитета ($\delta_{\text{mode}} = 0$).** Весь электорат держателей токена разрешает спор взвешенным по стейку публичным голосованием. Вес каждого голосующего $v$: - -$$w_v = s_v + \text{shares}_{v,\text{pool}} \cdot \text{NAV}_{\text{pool}} / S_{\text{total}}$$ - -где $s_v$ — вестинг-доли голосующего, а второе слагаемое переводит стейк в «ленивом» пуле в эквивалентный вес управления. Голоса публичны и пересматриваемы до закрытия периода голосования — это намеренное проектное решение: споры суть *прозрачные публичные слушания*, а не тайные бюллетени. Новые данные могут изменить голоса. - -Эта прозрачность несёт известную цену. Поскольку текущий подсчёт виден, голосующий может отложить голос на конец окна и обусловить свой бюллетень раскрытыми позициями других (преимущество последнего хода). Протокол принимает этот компромисс намеренно: для DAO аудируемость и легитимность открытого слушания ценнее тайны бюллетеня, а переворот исхода всё равно требует сдвинуть взвешенное по стейку большинство. Манипуляция сдерживается не тайной, а (i) взвешенным по стейку порогом одобрения $\theta_{\text{approve}}$, (ii) многодневным окном голосования, размывающим любое единичное преимущество тайминга, и (iii) согласованием вознаграждения арбитра, анализируемым в §7.4. Бюллетень commit-reveal был явно рассмотрен и **отвергнут** по этой причине — сокрытие голосов разрушило бы свойство публичного слушания, дающее вердикту легитимность. Мы возвращаемся к этому как к честному ограничению в §12.2. - -Спор удовлетворяется, если процент одобрения превышает заданный управлением порог $\theta_{\text{approve}}$: - -$$\frac{\sum_{v: \text{vote}_v = \text{approve}} w_v}{\sum_{v} w_v} \geq \frac{\theta_{\text{approve}}}{10000}$$ - -**Режим аккаунта ($\delta_{\text{mode}} = 1$).** Именованный арбитр спора (рекомендуется: мультиподпись) выносит обязывающий вердикт. - -### 7.3 Исходы спора и совместимость стимулов - -**Оракул неправ (спор удовлетворён):** - -$$\text{reward}_{\text{pool}} = \min(d \cdot \mu, I_o)$$ - -где $\mu$ — множитель вознаграждения. Пул вознаграждения делится так: - -- Заявитель получает $d$ (возврат комиссии) + $\text{reward}_{\text{pool}} / \mu$ -- Арбитр/голосующие получают $\text{reward}_{\text{pool}} - \text{reward}_{\text{pool}} / \mu$ -- Остаток страховки: дополнительный штраф $\rightarrow$ фонд DAO - -**Оракул прав (спор отклонён):** - -$$d \rightarrow \text{50\% арбитру, 50\% оракулу}$$ - -**Оракул не отвечает (авто-закрытие на 14-й день):** - -- Заявитель: комиссия возвращена -- Оракул: $d$ списывается из страховки -- Все ставки и позиции LP: полный возврат -- Списанная сумма распределяется пропорционально всем участникам - -### 7.4 Теоретико-игровой анализ - -**Совместимость стимулов оракула.** Ожидаемый выигрыш оракула от честного разрешения против манипуляции: - -$$\mathbb{E}[\pi_{\text{honest}}] = f_{\text{fixed}} + f_{\text{oracle}} \quad \text{(за рынок)}$$ - -$$\mathbb{E}[\pi_{\text{dishonest}}] = p_{\text{detect}} \cdot (-I_o \cdot \theta_{\text{penalty}} - B_{\text{ban}}) + (1 - p_{\text{detect}}) \cdot g_{\text{manipulation}}$$ - -где $p_{\text{detect}}$ — вероятность спора, $\theta_{\text{penalty}}$ — доля списания страховки, $B_{\text{ban}}$ — приведённая стоимость бана (упущенный будущий доход), а $g_{\text{manipulation}}$ — разовый выигрыш от манипуляции. - -Честное поведение является равновесием Нэша, когда: - -$$f_{\text{fixed}} + f_{\text{oracle}} > (1 - p_{\text{detect}}) \cdot g_{\text{manipulation}} - p_{\text{detect}} \cdot (I_o \cdot \theta_{\text{penalty}} + B_{\text{ban}})$$ - -Протокол обеспечивает это, требуя $I_o \gg g_{\text{manipulation}}$ и поддерживая высокий $p_{\text{detect}}$ через публичную видимость споров и стимулы участия комитета. - -**Стимул заявителя.** Рациональный игрок подаёт спор, когда ожидаемое вознаграждение превышает комиссию спора: - -$$\mathbb{E}[\text{reward}_{\text{dispute}}] = p_{\text{upheld}} \cdot (d + d \cdot (\mu - 1) / \mu) > d$$ - -Это упрощается до $p_{\text{upheld}} > 1/\mu$, задавая естественный порог подачи спора. - -**Стимул голосования комитета.** В режиме комитета голосующие участвуют, потому что их стейк в «ленивом» пуле (и, следовательно, вес управления) напрямую зарабатывает долю пула вознаграждения арбитра. Ожидаемое вознаграждение голосующего $v$: - -$$\mathbb{E}[\pi_v] = \frac{w_v}{\sum w_j} \cdot \text{voter\_reward\_pool} \cdot p_{\text{upheld}}$$ - -### 7.5 Объявление no-contest - -Оракул, неспособный верифицировать исход, может объявить no-contest по сниженной стоимости ($50\%$ штрафа спора из страховки). Это создаёт трёхуровневый градиент стимулов: - -| Действие | Стоимость для оракула | Риск бана | -|--------|------------|----------| -| Добровольный no-contest | $0{.}5 \cdot d$ из страховки | Нет | -| Проигрыш спора | $I_o \cdot \theta_{\text{penalty}} + \text{доп.}$ | Да | -| Пропуск дедлайна | $I_o \cdot \theta_{\text{miss}}$ | Нет | - -Само объявление no-contest можно оспорить, причём арбитр выбирает из трёх исходов (победил A, победил B или подтвердить no-contest), что предотвращает злоупотребление. - ---- - -## 8. Токен VIZ в эксперименте рынка предсказаний - -### 8.1 Полезность токена - -Токен VIZ выполняет четыре различные функции в экосистеме протокола Onix: - -1. **Средство обмена.** Все ставки, депозиты LP, страховка оракулов и комиссии споров номинированы в VIZ. Протокол никогда не эмитирует токены — он строго нулевой по сумме на уровне консенсуса. - -2. **Вес управления.** VIZ, застейканный как вестинг-доли (или внесённый в «ленивый» пул), даёт право голоса в спорах комитета DAO и в управлении параметрами цепи. Это создаёт прямую полезность владения токеном помимо спекуляции. - -3. **Залог оракула.** Страховые залоги оракулов номинированы в VIZ. Залог должен превышать потенциальную прибыль оракула от манипуляции, создавая спрос на накопление токена операторами оракулов. - -4. **Эскроу спора.** Комиссии споров блокируются в эскроу в VIZ, создавая издержку для несерьёзных споров и механизм вознаграждения для обоснованных вызовов. - -### 8.2 Петля обратной связи спроса на токен - -Протокол создаёт структурный цикл спроса: - -$$\text{депозиты LP} \xrightarrow{\text{блокировка}} \text{снижение оборотного предложения}$$ -$$\text{страховка оракулов} \xrightarrow{\text{блокировка}} \text{снижение оборотного предложения}$$ -$$\text{активные ставки} \xrightarrow{\text{блокировка}} \text{снижение оборотного предложения}$$ -$$\text{вес управления} \xrightarrow{\text{полезность}} \text{спрос на стейкинг}$$ - -Суммарное заблокированное предложение в любой момент: - -$$S_{\text{locked}} = S_{\text{pool}} + \sum_o I_o + \sum_{\text{active bets}} a_i + \sum_{\text{disputes}} d_k$$ - -где $S_{\text{pool}}$ — суммарный заблокированный для вывода баланс «ленивого» пула (как свободная, так и размещённая части заблокированы на период блокировки депозита), $I_o$ — страховка оракулов, $a_i$ — ставки активных позиций, а $d_k$ — комиссии споров в эскроу. Это заблокированное предложение снижает доступное оборотное предложение, потенциально создавая повышательное давление на цену по мере роста использования протокола — та же ставка, что делает любой нативный токен протокола, здесь явно привязанная к измеримой полезности. - -### 8.3 Экспериментальная ценность токена - -Токен VIZ в этом эксперименте служит **измерительным инструментом**: - -- **Цена как сигнал.** Движения цены токена в ответ на события протокола (запуски рынков, разрешения с высоким объёмом, исходы споров) дают непрерывную рыночную оценку воспринимаемой ценности протокола. -- **Уровень участия в управлении.** Доля держателей токена, участвующих в голосованиях по спорам, измеряет жизнеспособность арбитража на основе DAO. -- **Скорость накопления «ленивого» пула.** Темп депозитов в пул измеряет розничный спрос на безрисковую доходность LP, напрямую проверяя гипотезу Q3. - ---- - -## 9. Полный цикл рынка: подробный пример - -Проследим полный жизненный цикл бинарного рынка, чтобы проиллюстрировать работу протокола. - -### 9.1 Постановка - -- **Рынок:** «Произойдёт ли событие X к дате Y?» (Бинарный: Да/Нет) -- **Оракул:** $o$ со страховкой $I_o = 5000$ VIZ -- **Начальная ликвидность:** $L = 200$ VIZ от создателя -- **Параметры комиссий:** $\theta_{\text{oracle}} = 50$ bp, $\theta_{\text{creator}} = 50$ bp, $\theta_{\text{liq}} = 100$ bp -- **«Ленивый» пул:** $B_{\text{free}} = 10{,}000$ VIZ, $\alpha = 2\%$, размещает $a_{\text{alloc}} = 200$ VIZ - -> **Единицы.** Суммы показаны в VIZ для читаемости, но протокол хранит и вычисляет их как **целые милли-VIZ (mVIZ)**, где $1\text{ VIZ} = 1000\text{ mVIZ}$, и каждое деление округляется вниз (ср. замечание из §5.2). Строки комиссий ниже показаны в mVIZ, чтобы $\lfloor\cdot\rfloor$ был точен; эквивалент в VIZ приведён рядом. Это устраняет кажущееся несоответствие округления, возникающее при округлении над целыми VIZ (например, $\lfloor 80\times 50/10000\rfloor$ равно $0$ в VIZ, но $400$ mVIZ $=0{.}4$ VIZ в реальных единицах). - -### 9.2 Инициализация - -$$R_A = 100, \quad R_B = 100, \quad k = 10{,}000$$ - -«Ленивый» пул авто-размещает 200 VIZ как дополнительный LP: - -$$R_A = 200, \quad R_B = 200, \quad k = 40{,}000$$ - -### 9.3 Фаза ставок - -- **Алиса** ставит $a_1 = 50$ VIZ на «Да» (сторона A): - $$R'_A = 250, \quad R'_B = \lfloor 40000/250 \rfloor = 160, \quad w_1 = 200 - 160 = 40$$ - -- **Боб** ставит $a_2 = 80$ VIZ на «Нет» (сторона B): - $$R'_B = 240, \quad R'_A = \lfloor 40000/240 \rfloor = 166, \quad w_2 = 250 - 166 = 84$$ - -Подразумеваемая вероятность: $P(\text{Да}) = 166 / 406 \approx 41\%$, $P(\text{Нет}) = 240 / 406 \approx 59\%$. - -### 9.4 Разрешение - -Оракул объявляет победу **«Да»**. Алиса — единственный победитель; Боб теряет 80 VIZ. - -$$S_{\text{lose}} = 80{,}000 \text{ mVIZ} \;(80 \text{ VIZ})$$ -$$f_{\text{oracle}} = \lfloor 80{,}000 \times 50 / 10000 \rfloor = 400 \text{ mVIZ} \;(0{.}4 \text{ VIZ})$$ -$$f_{\text{creator}} = \lfloor 80{,}000 \times 50 / 10000 \rfloor = 400 \text{ mVIZ} \;(0{.}4 \text{ VIZ})$$ -$$f_{\text{liq}} = \lfloor 80{,}000 \times 100 / 10000 \rfloor = 800 \text{ mVIZ} \;(0{.}8 \text{ VIZ})$$ -$$W = 80{,}000 - 400 - 400 - 800 = 78{,}400 \text{ mVIZ} \;(78{.}4 \text{ VIZ})$$ - -**Выплата Алисе** (единственный победитель, $w_1 / w_1 = 1$): - -$$\pi_1 = 50{,}000 + \lfloor 78{,}400 \times 40/40 \rfloor - \tau_1 = 128{,}400 \text{ mVIZ} - \tau_1 \;(128{.}4 \text{ VIZ} - \tau_1)$$ - -**Возврат LP:** - -- LP создателя: $200 \text{ VIZ основного капитала} + \text{взвешенная по времени доля пула комиссий } 0{.}8 \text{ VIZ}$ -- LP «ленивого» пула: $200 \text{ VIZ основного капитала} + \text{взвешенная по времени доля пула комиссий } 0{.}8 \text{ VIZ}$ - -**Проверка** (Теорема 1): - -$$\text{Money}_{\text{IN}} = 200 + 200 + 50 + 80 = 530$$ -$$\text{Money}_{\text{OUT}} = 200 + 200 + 50 + 78{.}4 + 0{.}4 + 0{.}4 + 0{.}8 = 530 \quad \checkmark$$ - -### 9.5 Сценарий спора - -Если Боб оспаривает в течение $\Delta t_{\text{grace}} = 12\text{ч}$, заплатив $d = 10$ VIZ: - -1. Все выплаты замораживаются. -2. Оракул должен ответить в течение 12 часов. -3. В режиме комитета все держатели токена голосуют (взвешенно по стейку, публично, пересматриваемо). -4. Если спор удовлетворён: выплаты пересчитываются с исправленным исходом, страховка оракула списывается. -5. Если спор отклонён: исходные выплаты идут как есть, Боб теряет 10 VIZ (делятся 50/50 между оракулом и арбитром). -6. Если за 14 дней нет разрешения: авто-закрытие с полными возвратами. - ---- - -## 10. Анти-MEV: пакетные и commit-reveal ставки - -### 10.1 MEV на рынках предсказаний - -На рынках предсказаний в непрерывном времени опережающее исполнение (front-running) и сэндвич-атаки извлекают ценность у игроков. Когда крупная ставка транслируется в mempool, атакующий может: - -1. Опередить: разместить ставку на той же стороне перед крупной ставкой, наживаясь на движении цены -2. Сэндвич: разместить ставки на обеих сторонах вокруг крупной ставки - -### 10.2 Пакетный расчёт - -Протокол поддерживает опциональные пакетные ставки (бинарные рынки). Ставки, поданные в пределах эпохи из $E$ блоков, ставятся в очередь и рассчитываются по **единой цене** на границе эпохи. Только чистый остаток (разница совокупного спроса) сдвигает AMM: - -$$\Delta R_A = \sum_{\text{batch}} a_{i,A} - \sum_{\text{batch}} a_{i,B}$$ - -Это устраняет преимущество порядка внутри пакета: все ставки пакета получают идентичное ценообразование независимо от порядка подачи. - -### 10.3 Commit-reveal - -Для более сильной защиты от MEV игроки могут использовать двухфазную схему commit-reveal: - -1. **Commit:** Подать $H(\text{bet} \| \text{nonce})$ с эскроу. Направление и сумма ставки скрыты. -2. **Reveal:** После закрытия эпохи подать $(\text{bet}, \text{nonce})$ для исполнения по пакетной цене. - -Нераскрытые обязательства теряют заданный управлением процент штрафа от эскроу, что предотвращает спам-обязательства. - ---- - -## 11. Реализация - -### 11.1 Операции консенсусного уровня в VIZ DLT - -Протокол реализован как первоклассные операции, валидируемые консенсусом, в распределённом реестре VIZ — не смарт-контракты, не пользовательские полезные нагрузки. VIZ DLT обеспечивает время блока ~3 секунды, консенсус Delegated Proof of Stake и именованные аккаунты (в стиле Graphene) без виртуальной машины общего назначения. - -Каждое финансовое действие (создание рынка, размещение ставки, разрешение оракулом, подача спора, депозит/вывод LP) — это операция `pm_*`, валидируемая каждым узлом-валидатором. Невалидные операции отклоняются до включения в блок. - -| Слой | Примеры | Валидируется консенсусом | -|-------|---------|---------------------| -| Операции протокола | `pm_create_market`, `pm_place_bet`, `pm_resolve_market`, `pm_dispute_create`, `pm_lazy_deposit` | Да — валидирует каждый узел | -| Виртуальные операции | `pm_payout`, `pm_dispute_finalize`, `pm_lazy_recall`, `pm_batch_settle` | Да — детерминированно, на момент блока | -| Метаданные | Описания рынков, доказательства споров | Нет — только на клиенте | - -### 11.2 Состояние в цепи - -Всё состояние протокола хранится в индексированных объектах chainbase. Ключевые объекты: - -- `pm_market_object`: конфигурация рынка, резервы CPMM, параметры комиссий, состояние -- `pm_bet_object`: позиции игроков с весом и временным штрафом -- `pm_liquidity_object`: позиции LP с весом по времени -- `pm_lazy_pool_object`: состояние синглтон-пула (балансы, доли, накопитель вознаграждения) -- `pm_oracle_object`: регистрация оракула, страховка, счётчики репутации -- `pm_dispute_object`: состояние и разрешение спора - -Метрики репутации вычисляются при чтении (не хранятся), что обеспечивает согласованность без дополнительных операций записи. - -### 11.3 Параметры управления - -Все экономические параметры (комиссии, штрафы, требования к страховке, окна споров, настройки «ленивого» пула) выбираются медианным голосованием делегатов. Каждый избранный валидатор публикует предпочтительные значения; сеть вычисляет медиану. Параметры меняются без хардфорков и развёртываний. Kill-switch позволяют управлению отключать подсистемы (плечо, commit-reveal) медианным голосованием. - -### 11.4 Масштабируемость - -Поскольку каждая операция валидируется консенсусом, модель издержек протокола важна при масштабе (тысячи одновременных рынков и ставок). Дизайн удерживает работу на блок и на операцию ограниченной: - -- **Операции пользователя за $O(1)$.** Размещение ставки, отмена и депозит/вывод LP затрагивают фиксированное число индексированных объектов (рынок, позицию игрока и — для пула — синглтон-накопитель). Ни одна не итерирует по всем участникам. Распределение вознаграждений использует накопитель MasterChef $\rho$ (§6.3), так что пул с $n$ вкладчиками рассчитывает вознаграждения за $O(1)$ на участника, а не за $O(n)$ на разрешение. -- **Ограниченная отложенная работа на блок.** Расчёт — единственный шаг с разветвлением (рынок с $m$ выигравшими ставками порождает $m$ виртуальных операций `pm_payout`). Чтобы одно крупное разрешение не раздувало блок, обработка выплат и cron ограничена медианным параметром `pm_processing_cap_per_block`: за блок обрабатывается не более фиксированного числа выплат/cron-элементов, а остаток переносится на последующие блоки. Поэтому работа на блок в худшем случае — $O(\text{cap})$, независимо от того, сколько рынков разрешается в одном интервале. -- **Нет усиления записи от репутации.** 14 метрик оракула — счётчики, обновляемые только при собственных действиях оракула; составной балл надёжности вычисляется **при чтении**, а не пишется каждый блок (§11.2). Метаданные обнаружения рынков строятся неконсенсусным плагином и никогда не входят в валидацию блока. -- **Рост состояния.** Состояние линейно по числу живых объектов (рынки, открытые позиции, активные споры). Разрешённые рынки и оплаченные позиции терминальны и обрезаемы клиентами; консенсус хранит лишь то, что требуют открытые обязательства. - -Связывающее ограничение при очень большом числе рынков — это пространство блока для разветвления расчётов, которое `pm_processing_cap_per_block` превращает из всплеска задержки в ограниченную, амортизированную пропускную способность, а не в стоимость, останавливающую консенсус. Количественная стресс-симуляция по многим одновременным рынкам разного объёма и волатильности входит в экспериментальную программу (§12.3, H4). - ---- - -## 12. Обсуждение - -### 12.1 Сравнение с существующими подходами - -| Измерение | Протокол Onix | Polymarket (CLOB+UMA) | Стандартный LMSR | AMM в стиле Uniswap | -|-----------|---------------|----------------------|---------------|-------------------| -| Риск LP | **Нулевой** (структурно) | Инвентарный риск | До $b \ln N$ | Непостоянные потери | -| Требуемые знания LP | Низкие (внести депозит) | Высокие (управлять заявками) | Средние | Средние-высокие | -| Непрерывность цены | Непрерывная (AMM/LMSR) | Дискретная (книга заявок) | Непрерывная | Непрерывная | -| Извлечение комиссий | Только у проигравших, при разрешении | Спред bid-ask | Спред | Каждая сделка | -| Модель оракула | Залог + спор DAO | Оптимистичный оракул UMA | Оператор | — | -| Согласованность цен | Математический инвариант | Зависит от арбитража | Математический инвариант | Математический инвариант | -| Нужны split/merge CTF | Нет | Да | Нет | Нет | - -### 12.2 Ограничения и честные компромиссы - -1. **Доходность LP зависит от объёма, а не от глубины.** Рынок с высокой субсидией и низким объёмом зарабатывает столько же абсолютных комиссий, сколько рынок с низкой субсидией и равным объёмом. Субсидия даёт глубину (меньше проскальзывания), но не доходность. - -2. **Прибыль LP не гарантирована.** Если рынок разрешается с нулевыми проигравшими ставками, комиссии не образуются. Основной капитал LP возвращается, но доходность может быть нулевой. - -3. **Тотализаторные токены — не инструменты с фиксированной стоимостью.** В отличие от стандартного LMSR, где 1 выигрышный токен = 1 единице валюты, токены Onix — пропорциональные требования на пул проигравших. Если все игроки выбрали победителя, все выходят «в ноль». - -4. **Компромиссы управления DPoS.** Модель параметров, выбираемых делегатами, имеет известные риски концентрации, присущие DPoS (общие с EOS, Hive, Tron). Механизм веса управления «ленивого» пула частично смягчает это, расширяя эффективный электорат. - -5. **Зависимость от ликвидности токена.** Экономические гарантии (страховые залоги, комиссии споров) масштабируются с рыночной стоимостью токена. Протокол предполагает, что полезность движет спросом, — стандартное допущение для нативных токенов протоколов. - -6. **Плечо добавляет ограниченный кредитный риск пулу.** Опциональная подсистема плеча (§6.6) — единственный компонент, *не* покрытый Теоремой 1. Будучи включённой, пул действует как кредитор и может понести недостачу на пути отмены той же стороны, ограниченную залогом заёмщика и изолированную в управляемой доле фонда. Мы заявляем полный возврат ссуды на путях каскада и расчёта как *проектное свойство, проверенное в симуляции*, а не как доказанную теорему; замкнутое доказательство возврата при произвольных траекториях резервов — открытая задача. Подсистема выключена по умолчанию и отключаема медианным голосованием, поэтому безусловная гарантия LP всегда может быть восстановлена. - -7. **Публичное голосование по спорам имеет компромисс тайминга.** Открытые, пересматриваемые бюллетени комитета (§7.2) допускают преимущество последнего хода и выбраны намеренно вместо commit-reveal ради аудируемости. Это ценностное суждение (прозрачность важнее тайны), а не доказательство, что открытое голосование оптимально против манипуляций; развёртывания, ставящие тайну в приоритет, должны вместо этого использовать режим аккаунта. - -### 12.3 Экспериментальные гипотезы - -Развёрнутый протокол спроектирован для проверки следующих гипотез: - -**H1 (Маховик ликвидности).** *Безрисковое предоставление ликвидности привлекает розничный капитал, достаточный для создания рыночной глубины, которая ощутимо снижает проскальзывание относительно сопоставимых платформ.* - -Измеримо: суммарные депозиты «ленивого» пула, средняя глубина рынка (отношения резервов), проскальзывание на единицу размера ставки. - -**H2 (Агрегирование информации).** *Ценообразование AMM/LMSR с тотализаторным расчётом даёт вероятностные оценки точности, сопоставимой с рынками предсказаний на основе CLOB при эквивалентных информационных условиях.* - -Измеримо: баллы Бриера, кривые калибровки, сравнение с внешними бенчмарками (опросы, модели, другие рынки). - -**H3 (Надёжность оракула под управлением DAO).** *Оракулы с залогом при разрешении споров в режиме комитета достигают точности разрешения, сопоставимой с централизованными оракульными сервисами, при уровне споров ниже устойчивого порога.* - -Измеримо: уровень споров оракула, уровень проигрыша споров, среднее время разрешения, распределение баллов надёжности. - -**H4 (Устойчивость «ленивого» пула).** *Механизмы градуированного отзыва и штрафных меток предотвращают эксплуатацию «ленивого» пула оракулами, поддерживая положительную чистую доходность вкладчиков пула по разнообразным портфелям рынков.* - -Измеримо: NAV пула во времени, частота отзыва, распределение штрафных меток, чистая доходность на долю. - -**H5 (Корреляция спроса на токен).** *Использование протокола (объём, число рынков, депозиты LP) положительно коррелирует со спросом на стейкинг токена и уровнем участия в управлении.* - -Измеримо: уровень стейкинга токена, участие в голосованиях по спорам, темп депозитов «ленивого» пула, корреляционный анализ. - -**H6 (Эффективность анти-MEV).** *Пакетный расчёт и механизмы commit-reveal снижают измеримое извлечение MEV по сравнению с непрерывными мгновенными ставками.* - -Измеримо: асимметрия влияния на цену (пакет против мгновенной), частота сэндвич-атак, качество исполнения для игрока. - -**H7 (Платёжеспособность плеча).** *При живых траекториях ликвидация на основе снимка возвращает ссуду на путях каскада и расчёта, ограничивая реализованную недостачу пула путём отмены той же стороны и в пределах залога заёмщика, так что процент по плечу чисто-приращивает доходность пула.* (Это эмпирически проверяет проектное свойство из §6.6 вместо замкнутого доказательства возврата.) - -Измеримо: фактический коэффициент возврата ссуды на событие ликвидации ($\text{recovered}/\lambda m$), частота и величина недостач отмены той же стороны относительно внесённого залога, доля процента по плечу в общей доходности пула, NAV пула с включённой и выключенной подсистемой плеча. - ---- - -## 13. Заключение - -Мы представили протокол Onix — архитектуру рынка предсказаний, которая достигает структурной гарантии основного капитала LP, разделяя функцию ценообразования (CPMM для бинарного, LMSR для многоисходного) и функцию расчёта (тотализатор, проигравшие финансируют выигравших). Мы доказали, что эта гарантия выполняется для обоих типов рынков независимо от назначения весов, параметров комиссий или распределения ставок. - -Механизм «ленивого» пула обеспечивает пассивное участие розничных LP с автоматическим размещением капитала и градуированной защитой от издержек упущенных возможностей. Двухрежимная система споров — сочетающая оракулов с залогом со взвешенным по стейку голосованием комитета DAO — даёт жизнеспособную альтернативу централизованному арбитражу, сохраняя совместимость стимулов оракула. - -Протокол реализован как операции консенсусного уровня в распределённом реестре VIZ и спроектирован как эксперимент, проверяющий семь явных гипотез о запуске ликвидности, точности агрегирования информации, жизнеспособности управления DAO, платёжеспособности плеча и динамике спроса на токен. Опциональная подсистема плеча — единственный компонент, который меняет безусловную гарантию LP на ограниченный, выключенный по умолчанию кредитный риск пула; всё остальное сохраняет структурную гарантию Теоремы 1. - -Математические свойства проверяемы. Экономические гипотезы будут проверены участием рынка. - ---- - -## Литература - -[1] Hanson, R. (2003). Combinatorial Information Market Design. *Information Systems Frontiers*, 5(1), 107–119. - -[2] Adams, H., Zinsmeister, N., & Robinson, D. (2020). *Uniswap v2 Core.* Uniswap Labs. - -[3] Adams, H., Zinsmeister, N., Salem, M., Keefer, R., & Robinson, D. (2021). *Uniswap v3 Core.* Uniswap Labs. - -[4] Berg, J., Forsythe, R., Nelson, F., & Rietz, T. (2008). Results from a Dozen Years of Election Futures Markets Research. In *Handbook of Experimental Economics Results* (Vol. 1, pp. 742–751). Elsevier. - -[5] Cowgill, B., Wolfers, J., & Zitzewitz, E. (2009). Using Prediction Markets to Track Information Flows: Evidence from Google. In *Auctions, Market Mechanisms and Their Applications (AMMA 2009)*, LNICST Vol. 14. Springer. - -[6] Levitt, S. D. (2004). Why Are Gambling Markets Organised So Differently from Financial Markets? *The Economic Journal*, 114(495), 223–246. - -[7] Gnosis. *Conditional Tokens Framework (CTF) Documentation.* - -[8] UMA Protocol. *Optimistic Oracle Documentation.* - -[9] Leshner, R., & Hayes, G. (2019). *Compound: The Money Market Protocol.* Compound Labs. - -[10] SushiSwap. (2020). *MasterChef Contract.* - -[11] Piskunov, A. *VIZ: Distributed Ledger Technical Description, Fair DPoS, and Governance.* VIZ-Blockchain. - -[12] Arrow, K. J., Forsythe, R., Gorham, M., Hahn, R., Hanson, R., Ledyard, J. O., et al. (2008). The Promise of Prediction Markets. *Science*, 320(5878), 877–878. - -[13] Wolfers, J., & Zitzewitz, E. (2004). Prediction Markets in Theory and Practice. *NBER Working Paper* No. 10248 (also *Journal of Economic Perspectives*, 18(2), 107–126). - -[14] Othman, A., Pennock, D. M., Reeves, D. M., & Sandholm, T. (2013). A Practical Liquidity-Sensitive Automated Market Maker. *ACM Transactions on Economics and Computation*, 1(3), Article 14. - -[15] Abernethy, J., Chen, Y., & Vaughan, J. W. (2011). An Optimization-Based Framework for Automated Market-Making. In *Proceedings of the 12th ACM Conference on Electronic Commerce (EC '11)* (pp. 297–306). diff --git a/.qoder/docs/onix-protocol-paper-ru.pdf b/.qoder/docs/onix-protocol-paper-ru.pdf deleted file mode 100644 index 95a7b4a9ae..0000000000 Binary files a/.qoder/docs/onix-protocol-paper-ru.pdf and /dev/null differ diff --git a/.qoder/docs/onix-protocol-paper.md b/.qoder/docs/onix-protocol-paper.md deleted file mode 100644 index 55cdb2f0ef..0000000000 --- a/.qoder/docs/onix-protocol-paper.md +++ /dev/null @@ -1,767 +0,0 @@ ---- -title: "Combining Parimutuel Settlement with Automated Market Makers for Liquidity-Guaranteed Prediction Markets: The Onix Protocol" -author: | - Anatoly Piskunov\ - Independent Researcher — VIZ Distributed Ledger\ - anatoly.piskunov@gmail.com\ - ORCID: [0009-0000-8883-4111](https://orcid.org/0009-0000-8883-4111) -date: June 2026 -header-includes: | - \usepackage{titling} - \pretitle{\begin{center}\LARGE\bfseries} - \posttitle{\par\end{center}\vspace{1.4em}} - \setlength{\droptitle}{-1.5em} - \setlength{\abovedisplayskip}{8pt} - \setlength{\belowdisplayskip}{8pt} -abstract: | - Prediction markets aggregate dispersed information into probabilistic forecasts that consistently outperform polls and expert panels, yet their adoption is constrained by a structural liquidity problem: providers of market depth bear adverse selection risk that deters retail participation. We present the **Onix Protocol**, a hybrid architecture that decouples the *pricing* function from the *settlement* function in prediction markets. By pairing automated market maker pricing — a Constant Product Market Maker (CPMM) for binary outcomes and a Logarithmic Market Scoring Rule (LMSR) for multi-outcome markets — with parimutuel (totalizator) settlement, we achieve a **structural guarantee** that liquidity-provider principal is never at risk from betting outcomes. We formalize the protocol's economic invariants, prove the LP principal guarantee for both market types, describe a "Lazy" liquidity pool enabling passive retail participation, analyze the dispute resolution mechanism under DAO governance, and discuss the experimental hypotheses this system is designed to test. The protocol is implemented as consensus-level operations on the VIZ distributed ledger. - - \vspace{0.9\baselineskip}\noindent - **Keywords:** prediction markets, automated market makers, parimutuel betting, LMSR, liquidity provision, DAO governance, mechanism design ---- - -\clearpage - -\tableofcontents - -\clearpage - -## 1. Introduction - -### 1.1 The Prediction Market Liquidity Problem - -Prediction markets are among the most reliable mechanisms for aggregating dispersed information into actionable probabilistic forecasts. Empirical evidence from political forecasting (Berg, Forsythe, Nelson & Rietz, 2008), sports betting (Levitt, 2004), and internal corporate markets (Cowgill, Wolfers & Zitzewitz, 2009) demonstrates that market prices consistently outperform alternative forecasting methods. - -Despite this track record, prediction market deployment remains limited. The fundamental constraint is not demand for forecasts but *supply of liquidity*. Every existing prediction market architecture requires liquidity providers (LPs) to accept one of three risk profiles: - -1. **Impermanent loss** in AMM-based markets (Adams, Zinsmeister & Robinson, 2020; Adams et al., 2021), where LPs systematically lose to informed traders; -2. **Adverse selection** in limit-order-book markets, where market makers bear inventory risk against better-informed counterparties; -3. **Bounded subsidy loss** in LMSR markets (Hanson, 2003), where the market maker risks up to $b \ln N$ against correctly-informed crowds. - -These risk profiles restrict liquidity provision to sophisticated actors with active management capabilities, creating thin markets with high slippage that deter bettor participation — a self-reinforcing cycle: - -$$\text{thin markets} \rightarrow \text{high slippage} \rightarrow \text{poor UX} \rightarrow \text{few bettors} \rightarrow \text{low fees} \rightarrow \text{no LP incentive} \rightarrow \text{thin markets}$$ - -### 1.2 Research Questions - -This work poses and seeks to answer the following questions through a deployed experimental system: - -**Q1.** *Can the pricing and settlement functions of a prediction market be architecturally separated such that LP principal is structurally insulated from betting outcomes?* - -**Q2.** *Does a parimutuel settlement mechanism, where losers exclusively fund winners, eliminate the adverse selection problem inherent in AMM-based and LMSR-based prediction markets?* - -**Q3.** *Can automated liquidity deployment via a pooled mechanism ("Lazy Pool") reduce the barrier to LP entry sufficiently to bootstrap market depth without active market selection by individual LPs?* - -**Q4.** *Is a DAO-governed dispute resolution mechanism, with stake-weighted public voting and bonded oracles, a viable alternative to centralized arbitration or optimistic oracle schemes?* - -**Q5.** *What governance-token utility emerges from a prediction market protocol where LP positions carry voting weight, and does this create a sustainable token-demand feedback loop?* - -### 1.3 Contributions - -Our contributions are: - -1. **A formal proof** that combining AMM pricing with parimutuel settlement yields a structural LP principal guarantee for both binary (CPMM) and multi-outcome (LMSR) prediction markets. -2. **The "Lazy Pool" mechanism** — an automated capital deployment system with graduated recall and opportunity-cost protection that enables passive retail LP participation, plus an opt-in, default-off pool-funded leverage subsystem whose pool exposure is *bounded* (worst-case shortfall capped by borrower collateral) and isolated from the Theorem 1 LP guarantee. -3. **A two-mode dispute resolution framework** combining bonded oracles with DAO committee arbitration, including a full game-theoretic analysis of oracle incentive compatibility. -4. **An experimental protocol** implemented as consensus-level operations on a production distributed ledger, with explicit hypotheses and measurable outcomes. - ---- - -## 2. Related Work - -### 2.1 Market Scoring Rules - -Hanson (2003) introduced the Logarithmic Market Scoring Rule (LMSR), in which a market maker quotes prices via a softmax function over quantity parameters. The LMSR guarantees a bounded loss to the market maker of $b \ln N$ and ensures prices sum to unity. However, this bound is also the LP's maximum risk — if the crowd correctly predicts the outcome, the market maker loses the entire subsidy. This has limited LMSR adoption to corporate environments (Microsoft, Inkling) where the operator absorbs losses. - -### 2.2 Constant Product Market Makers - -The constant product formula $x \cdot y = k$, popularized by Uniswap (Adams, Zinsmeister & Robinson, 2020), provides continuous pricing for two-asset pairs. When applied to binary prediction markets, the reserves represent opposing outcomes and the invariant provides natural probability pricing. However, standard AMM LPs suffer impermanent loss — empirical analysis shows over 50% of Uniswap v3 LPs underperform buy-and-hold (Adams et al., 2021). - -### 2.3 Conditional Token Frameworks - -Polymarket employs the Gnosis Conditional Tokens Framework (CTF), where positions are ERC-1155 tokens with split/merge operations to enforce price coherence ($\sum p_i = 1$). This adds composability but introduces complexity and requires an external arbitrage mechanism. UMA's Optimistic Oracle provides dispute resolution through a challenge-response game with economic bonds. - -### 2.4 Parimutuel Betting - -The parimutuel (totalizator) model, originating from Pierre Oller's totalisator (1865), pools all bets and distributes the losers' stakes proportionally among winners. This guarantees the house never pays from its own capital. However, traditional parimutuel systems lack real-time pricing — odds are only final at pool close — making them unsuitable for continuous information aggregation. - -### 2.5 Our Approach - -The Onix Protocol combines the real-time pricing capability of AMMs/LMSR with the zero-LP-risk property of parimutuel settlement. The AMM or LMSR serves exclusively as a *pricing engine* — determining implied probabilities and assigning weights — while settlement follows the parimutuel model where losers fund winners and LP principal is architecturally separated from the payout flow. - -This positions Onix differently from two other hybrid directions in the literature. First, *liquidity-sensitive* market makers (Othman, Pennock, Reeves & Sandholm, 2013; Abernethy, Chen & Vaughan, 2011) keep the operator as counterparty but bound or shape its loss via the cost-function geometry; the operator can still lose. Onix instead removes the counterparty role from the LP altogether — the curve only *prices*, it never *pays*. Second, *CLOB+AMM* hybrids (e.g. order books backstopped by an AMM, as explored in several DEX designs and in Polymarket's CLOB with AMM-style fallbacks) blend two pricing venues but inherit inventory/adverse-selection risk from the market-making side. Onix keeps a single continuous pricing venue and moves the risk-bearing entirely out of pricing and into the parimutuel pool. To our knowledge, pairing a continuous AMM/LMSR pricer with parimutuel (losers-fund-winners) settlement to obtain an unconditional LP-principal guarantee has not previously been formalized. - ---- - -## 3. Protocol Model - -### 3.1 Participants and Roles - -We define the following participant set $\mathcal{P}$: - -| Role | Symbol | Function | -|------|--------|----------| -| Market Creator | $c \in \mathcal{P}$ | Defines market parameters, provides seed liquidity | -| Oracle | $o \in \mathcal{P}$ | Registers insurance bond $I_o$, accepts markets, resolves outcomes | -| Bettor | $b_i \in \mathcal{P}$ | Places bets on outcomes, receives outcome tokens | -| Liquidity Provider | $\ell_j \in \mathcal{P}$ | Deposits capital into market pools or the Lazy Pool | -| Dispute Resolver | $\mathcal{D}$ | Committee (stake-weighted vote) or named account | - -### 3.2 Market Definition - -A market $\mathcal{M}$ is a tuple: - -$$\mathcal{M} = (o, \tau, \mathbf{O}, t_{\text{bet}}, t_{\text{res}}, \boldsymbol{\theta}, L)$$ - -where $o$ is the designated oracle, $\tau \in \{0, 1\}$ is the market type (binary or multi), $\mathbf{O} = \{O_1, \ldots, O_N\}$ is the outcome set ($N = 2$ for binary, $3 \leq N \leq 10$ for multi), $t_{\text{bet}}$ and $t_{\text{res}}$ are betting and resolution expiration times, $\boldsymbol{\theta}$ is the fee parameter vector, and $L$ is the initial liquidity. - -### 3.3 Fee Structure - -All fees are expressed in basis points (bp), where $10000 \text{ bp} = 100\%$. The fee vector is: - -$$\boldsymbol{\theta} = (\theta_{\text{oracle}}, \theta_{\text{creator}}, \theta_{\text{liq}})$$ - -Fees are computed exclusively at resolution from the losing side's aggregate stake $S_{\text{lose}}$ and are never deducted at bet placement time: - -$$f_{\text{oracle}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{oracle}} / 10000 \rfloor$$ -$$f_{\text{creator}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{creator}} / 10000 \rfloor$$ -$$f_{\text{liq}} = \lfloor S_{\text{lose}} \cdot \theta_{\text{liq}} / 10000 \rfloor$$ -$$W = S_{\text{lose}} - f_{\text{oracle}} - f_{\text{creator}} - f_{\text{liq}}$$ - -where $W$ is the **winners' pool** available for distribution to winning bettors. - -### 3.4 Market State Machine - -The lifecycle of $\mathcal{M}$ follows a finite state machine: - -$$q_0 \xrightarrow{\text{oracle accepts}} q_1 \xrightarrow{t \geq t_{\text{bet}}} q_2 \xrightarrow{\text{oracle resolves}} q_3 \xrightarrow{\text{grace period}} \text{paid}$$ - -with a rejection path $q_0 \xrightarrow{\text{oracle rejects}} q_{-1}$ (deleted, liquidity returned). - ---- - -## 4. Pricing Mechanisms - -### 4.1 Binary Markets: Constant Product Market Maker - -For binary markets ($N = 2$), the protocol maintains two reserves $R_A$ and $R_B$ subject to the invariant: - -$$k = R_A \cdot R_B$$ - -**Initialization.** Given seed liquidity $L$: - -$$R_A = \lfloor L / 2 \rfloor, \quad R_B = L - R_A, \quad k = R_A \cdot R_B$$ - -**Bet placement.** When bettor $b_i$ wagers amount $a$ on outcome $A$: - -$$R'_A = R_A + a$$ -$$R'_B = \lfloor k / R'_A \rfloor$$ -$$w_i = R_B - R'_B \quad \text{(tokens received)}$$ - -Here $w_i$ is the bettor's *weight*. It is a **computed** quantity — the number of outcome tokens minted by the curve — and is in general **not** equal to the staked amount $a$: depending on the current reserves, $w_i$ may be larger or smaller than $a$. The weight is used solely to apportion the winners' pool at settlement (§5.1); it is never a currency-denominated claim. - -**Implied probability.** The market-implied probability for each outcome is: - -$$P(A) = \frac{R_A}{R_A + R_B}, \quad P(B) = \frac{R_B}{R_A + R_B}$$ - -Note that $P(A) + P(B) = 1$ by construction, eliminating the need for any external arbitrage mechanism to enforce price coherence. - -### 4.2 Multi-Outcome Markets: LMSR - -For markets with $N > 2$ outcomes, the protocol uses the Logarithmic Market Scoring Rule with softmax pricing. - -**Cost function:** - -$$C(\mathbf{q}) = b \cdot \ln\left(\sum_{j=1}^{N} \exp(q_j / b)\right)$$ - -where $\mathbf{q} = (q_1, \ldots, q_N)$ are quantity parameters and $b$ is the liquidity parameter. - -**Price function (softmax):** - -$$p_i(\mathbf{q}) = \frac{\exp(q_i / b)}{\sum_{j=1}^{N} \exp(q_j / b)}$$ - -By the definition of softmax, $\sum_{i=1}^{N} p_i = 1$ identically. - -**Cost of a trade.** The cost to purchase $\Delta$ tokens on outcome $i$: - -$$\text{cost}(\Delta, i) = C(\mathbf{q} + \Delta \cdot \mathbf{e}_i) - C(\mathbf{q})$$ - -**Liquidity parameter.** The parameter $b$ is funded by the LP subsidy $S$: - -$$b = \frac{S}{\ln N}$$ - -**Numerical stability.** The log-sum-exp computation uses the standard identity: - -$$\ln\left(\sum_j \exp(x_j)\right) = \max(\mathbf{x}) + \ln\left(\sum_j \exp(x_j - \max(\mathbf{x}))\right)$$ - ---- - -## 5. Parimutuel Settlement and LP Guarantee - -### 5.1 Unified Settlement Model - -Both market types share an identical settlement mechanism. At resolution, the oracle declares winning outcome $O^* \in \mathbf{O}$. Let $\mathcal{W}$ be the set of bets on $O^*$ and $\mathcal{L}$ be all other bets. - -$$S_{\text{lose}} = \sum_{b_i \in \mathcal{L}} a_i$$ - -where $a_i$ is the bet amount. The winners' pool $W$ is computed as in §3.3. - -Each winning bettor $b_i \in \mathcal{W}$ receives: - -$$\pi_i = a_i + \frac{w_i}{\sum_{b_j \in \mathcal{W}} w_j} \cdot W - \tau_i$$ - -where $w_i$ is the bettor's weight (tokens from CPMM or LMSR) and $\tau_i$ is the time penalty on profit (§5.3). - -### 5.2 Theorem: LP Principal Guarantee - -**Theorem 1.** *Under parimutuel settlement, the total money distributed equals the total money received, with LP principal $L$ returned unconditionally. The LP principal is never at risk from betting outcomes.* - -*Proof.* Consider the full money flow through a market: - -$$\text{Money}_{\text{IN}} = L + \sum_{b_i \in \mathcal{W}} a_i + \sum_{b_i \in \mathcal{L}} a_i = L + \sum_{\text{all bets}} a_i$$ - -where the first sum $\sum_{b_i \in \mathcal{W}} a_i$ is the aggregate principal staked by *winners* (returned to them in full at settlement) and $S_{\text{lose}} = \sum_{b_i \in \mathcal{L}} a_i$ is the aggregate stake forfeited by *losers* (the sole source of the winners' pool and all fees). At resolution, the outgoing flows are: - -$$\text{Money}_{\text{OUT}} = L + \sum_{b_i \in \mathcal{W}} a_i + W + f_{\text{oracle}} + f_{\text{creator}} + f_{\text{liq}}$$ - -Substituting $W = S_{\text{lose}} - f_{\text{oracle}} - f_{\text{creator}} - f_{\text{liq}}$: - -$$\text{Money}_{\text{OUT}} = L + \sum_{b_i \in \mathcal{W}} a_i + S_{\text{lose}}$$ -$$= L + \sum_{b_i \in \mathcal{W}} a_i + \sum_{b_i \in \mathcal{L}} a_i = L + \sum_{\text{all bets}} a_i = \text{Money}_{\text{IN}} \qquad \blacksquare$$ - -**Corollary 1.** *The LP principal guarantee holds regardless of the weight assignment mechanism, the number of bettors, the distribution of bets across outcomes, or the fee parameters. It is a property of the settlement architecture, not the pricing curve.* - -**Corollary 2.** *The maximum total payout to winners is $S_{\text{lose}}$ (the entire losing pool), regardless of weights assigned by the AMM or LMSR. Therefore, winner payouts can never draw from LP capital.* - -**Remark (integer arithmetic and solvency under rounding).** Theorem 1 is stated over the rationals, but the protocol operates on integers (milli-VIZ), and every division applies the floor operator $\lfloor \cdot \rfloor$. We show the guarantee survives discretization. Each fee and each winner share is rounded *down*: - -$$f_\bullet = \lfloor S_{\text{lose}} \cdot \theta_\bullet / 10000 \rfloor, \qquad \hat{\pi}_i^{\text{profit}} = \left\lfloor \frac{w_i}{\sum_{j} w_j} \cdot W \right\rfloor$$ - -Since $\lfloor x \rfloor \leq x$, the realized winners' distribution satisfies $\sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} \leq W$, and likewise $\sum_\bullet f_\bullet \leq S_{\text{lose}} \cdot (\theta_{\text{oracle}}+\theta_{\text{creator}}+\theta_{\text{liq}})/10000 \leq S_{\text{lose}}$. Therefore the realized outflow obeys - -$$\text{Money}_{\text{OUT}}^{\text{realized}} = L + \sum_{i \in \mathcal{W}} a_i + \sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} + \sum_\bullet f_\bullet \;\leq\; L + \sum_{\text{all bets}} a_i = \text{Money}_{\text{IN}}$$ - -so the system is never insolvent. The non-negative residual - -$$\epsilon = S_{\text{lose}} - \sum_{i \in \mathcal{W}} \hat{\pi}_i^{\text{profit}} - \sum_\bullet f_\bullet \;\geq\; 0$$ - -is bounded by $\epsilon < |\mathcal{W}| + 3$ milli-VIZ (one sub-unit per floored quantity) and is swept to the DAO fund as dust. Thus rounding can only *under*-distribute, never over-distribute: LP principal $L$ remains exactly conserved and the inequality $\text{Money}_{\text{OUT}} \leq \text{Money}_{\text{IN}}$ holds at the granularity of the ledger. $\blacksquare$ - -### 5.3 Time Penalty on Late Bets - -To mitigate information asymmetry from bets placed near expiration (when outcome uncertainty is reduced), the protocol imposes a configurable time penalty applied *only to profit*, never to principal. - -Let $\Delta t = t_{\text{bet}} - t_{\text{now}}$ be the time to expiration and $\omega$ be the penalty window. If $\Delta t < \omega$: - -$$r = 1 - \frac{\Delta t}{\omega}$$ - -$$\tau_{\text{rate}} = \begin{cases} r & \text{linear} \\ r^2 & \text{quadratic (default)} \end{cases}$$ - -$$\tau_i = \lfloor \pi_{\text{profit},i} \cdot \tau_{\text{rate}} \cdot \tau_{\max} / 10^6 \rfloor$$ - -where $\pi_{\text{profit},i}$ is the bettor's profit share (excluding principal) and $\tau_{\max}$ is the maximum penalty in micro-units. - -**Invariant:** $\pi_i \geq a_i$ for all winning bettors, since the penalty is applied exclusively to the profit component. - -### 5.4 LP Time-Weighted Fee Distribution - -LP fee shares are distributed proportionally to the product of deposit amount and remaining time to expiration: - -$$\omega_j = \text{amount}_j \cdot \max(1, t_{\text{bet}} - t_{\text{deposit},j})$$ - -$$f_{\text{share},j} = \left\lfloor \frac{f_{\text{pool}} \cdot \omega_j}{\sum_m \omega_m} \right\rfloor$$ - -This creates a strong incentive for early liquidity provision. In a market of duration $T$, an LP depositing at time $t = 0$ earns $T$ times more per unit capital than one depositing at $t = T - 1$. - ---- - -## 6. "Lazy" Liquidity Pool - -### 6.1 Motivation - -Individual LP provision requires active market evaluation and selection. For retail participants, this creates an impractical knowledge and effort barrier. The "Lazy" Pool (so named because it requires no active market selection from depositors) solves this by accepting deposits and automatically allocating capital to activated markets. - -### 6.2 Pool Mechanics - -The Lazy Pool $\mathcal{L}_P$ is a singleton contract maintaining: -- $B_{\text{free}}$: unallocated balance -- $B_{\text{alloc}}$: capital deployed to active markets -- $B_{\text{earned}}$: realized profits -- $S_{\text{total}}$: total outstanding shares -- $\rho$: cumulative reward-per-share accumulator - -**Deposit.** When user $u$ deposits amount $a$: - -$$\text{shares}_u = \begin{cases} a & \text{if } S_{\text{total}} = 0 \\ a \cdot S_{\text{total}} / B_{\text{free}} & \text{otherwise} \end{cases}$$ - -The deposit is locked for a governance-defined period $t_{\text{lock}}$. - -**Auto-allocation.** On market activation ($q_0 \rightarrow q_1$): - -$$a_{\text{alloc}} = B_{\text{free}} \cdot \alpha / 100$$ - -subject to $a_{\text{alloc}} \geq a_{\min}$ and $B_{\text{alloc}} + a_{\text{alloc}} \leq B_{\text{total}} \cdot \alpha_{\max} / 100$, where $\alpha$ is the per-market allocation percentage and $\alpha_{\max}$ is the maximum total allocation cap. - -The allocation formula includes oracle quality adjustments: - -$$a_{\text{alloc}} = B_{\text{free}} \cdot \frac{\alpha}{100} \cdot (1 - \beta)^{n_o} \cdot (1 - \gamma)^{f_o}$$ - -where $n_o$ is the oracle's active market count, $f_o$ is the oracle's active fault stamp count, and $\beta, \gamma$ are governance-defined decay factors. - -### 6.3 Reward Distribution (Lazy Accounting) - -Rewards are distributed using a single global accumulator $\rho$ (reward-per-share), following the MasterChef pattern (SushiSwap, 2020; Leshner & Hayes, 2019): - -When a market resolves and the pool's LP position returns profit $\pi_{\text{pool}}$: - -$$\rho \leftarrow \rho + \frac{\pi_{\text{pool}} \cdot \text{PRECISION}}{S_{\text{total}}}$$ - -Any user $u$'s pending reward is computable in $O(1)$: - -$$\text{reward}_u = \text{pending}_u + \frac{\text{shares}_u \cdot (\rho - \rho_{\text{snapshot},u})}{\text{PRECISION}}$$ - -User records are updated only when that user acts (deposit or withdraw), giving $O(1)$ amortized cost regardless of participant count. - -### 6.4 Opportunity-Cost Protection - -The auto-allocation mechanism creates an attack vector: a malicious oracle could create long-duration zero-volume markets to lock pool capital. Three graduated defense mechanisms address this: - -**Graduated Recall.** The market duration is divided into $n_{\text{steps}}$ intervals. At each checkpoint $k$, if cumulative volume $V_k$ satisfies: - -$$V_k < a_{\text{alloc}} \cdot \theta_{\text{recall}} / 100$$ - -then a fraction $\delta_{\text{recall}}$ of the current allocation is recalled to the pool. After $n$ consecutive low-volume checkpoints, the retained allocation is: - -$$a_{\text{retained}} = a_{\text{alloc}} \cdot (1 - \delta_{\text{recall}})^n$$ - -For the default parameters ($\delta_{\text{recall}} = 10\%$, $n_{\text{steps}} = 10$), a completely idle market retains $(0.9)^{10} \approx 35\%$ of its original allocation. - -**Active Market Penalty.** Each active market from oracle $o$ multiplicatively reduces new allocations by factor $(1 - \beta)$. With $\beta = 5\%$ and 10 active markets, new allocations are $(0.95)^{10} \approx 60\%$ of the base rate. - -**Fault Stamps.** Bad outcomes (no-contest, missed deadlines, dispute losses, zero-volume resolutions) generate penalty stamps on the oracle that further reduce allocations by factor $(1 - \gamma)^{f_o}$. Stamps auto-expire after a governance-defined clean-operation window. - -### 6.5 Emergency Withdrawal - -Users may exit the pool before lock expiration, subject to a penalty on *locked profit only*: - -$$\text{penalty} = \max(0, V_{\text{total}} - P_{\text{deposited}}) \cdot \frac{S_{\text{locked}}}{S_{\text{total}}} \cdot \theta_{\text{emergency}} / 100$$ - -where $V_{\text{total}}$ is the user's total value (shares + pending rewards), $P_{\text{deposited}}$ is cumulative principal deposited, and $S_{\text{locked}} / S_{\text{total}}$ is the fraction of shares still locked. The penalty is redistributed to remaining pool participants via $\rho$. - -### 6.6 Opt-In Leverage Funded by the Pool - -The Lazy Pool plays a second, optional role from the same $B_{\text{free}}$: it funds a leverage subsystem. This subsystem is **opt-in, default-off, and governed by a median kill-switch**. We treat it separately from the rest of the paper for an important reason. **It is the one place where pool capital takes on credit risk, so it is *not* covered by the unconditional guarantee of Theorem 1.** Theorem 1 concerns the pool acting as a *market liquidity provider*, where principal is structurally insulated from betting outcomes. Leverage instead has the pool act as a *lender*, and lending carries risk that we bound rather than eliminate. - -**Position opening.** A bettor posts collateral $m$. The pool lends margin $\lambda m$ at leverage factor $\lambda$ from $B_{\text{free}}$, subject to caps on per-position size, pool fund fraction, and minimum market liquidity. No token is minted: the total stake $(1+\lambda)m$ enters the market exactly as an ordinary bet would. The position's curve weight, its collateral, and the lent amount are recorded on a dedicated position object. The pool's obligation on the position is - -$$\Omega = \lambda m \,(1 + r),$$ - -where $r$ is the accrued interest. The loan plus interest is what the pool seeks to recover. - -**Liquidation against the recorded reserve snapshot.** The hard case in leveraged binary markets is *jump risk*: a discontinuous price move can leave a naive "sell at the current price" liquidation unable to cover the loan. Onix does not liquidate at the current price. It closes the position via reverse-CPMM against the **reserve state recorded for that position**, so the position's own market impact is unwound first rather than being paid for twice. Two paths drive recovery: - -1. **Opposing-bet cascade** (`pm_place_bet`, liquidation reason 0) — an incoming opposing bet triggers a forced close of the leveraged position against its recorded snapshot. -2. **Settlement force-close** (`pm_leverage_resolve`) — at resolution the position is closed and the loan repaid from its weight before any profit accrues to the borrower. - -On these two paths the design target is full recovery, $\text{recovered} = \min(V_{\text{close}}, \Omega) \ge \lambda m$, with the realized loan-and-interest returning to the pool. We state this as a **design property, not a theorem**: the leverage settlement math is implemented and exercised in `consensus_sim`, but a closed-form proof of recovery under all reserve trajectories is left to future work (§12.2). The residual exposure is concentrated on one path: - -- **Same-side voluntary cancel** (`pm_cancel_bet`, reason 1) — if the borrower closes on the same side under an adverse move, the pool can realize a shortfall. This shortfall is **bounded by the borrower's collateral $m$**, which the protocol holds; it cannot exceed $m$. - -**Kill-switch decoupled from protection.** The kill-switch disables *new* openings only. The liquidation paths are deliberately **not** gated by it, so disabling leverage never strips protection from already-open positions. - -**Risk isolation and reward.** Leverage lending is confined to a governed fraction of $B_{\text{free}}$ (`leverage_fund_percent`), so worst-case pool exposure is capped at the subsystem level and cannot reach the market-LP principal that Theorem 1 protects. Interest earned accrues to the pool through the same $\rho$ accumulator (§6.3). Pool depositors therefore earn from two sources — losers'-pool fee shares (risk-free, Theorem 1) and leverage interest (bounded credit risk, opt-in) — and the two are accounted identically but governed independently. The honest summary: the pool's *market-LP* principal is never at risk; its *leverage lending* carries bounded, opt-in, default-off credit risk (§12.2). - -### 6.7 Design Decision: Real Depth Only (No Virtual/Phantom Liquidity) - -A natural proposal is to seed a market's pricing curve with *virtual* (phantom) liquidity — a reserve offset $\phi$ added to flatten price impact but backed by no real capital and deleted at settlement, optionally tuned by governance. In the closed bet→cancel→settle loop this is value-conservative (it is the virtual-AMM technique), and it is tempting as a cold-start "stabilizer" for new, thin markets. Onix **deliberately does not implement it.** The same cold-start benefit is already delivered by Lazy-Pool auto-allocation (§6.2) — but with *real* capital, which additionally earns fees, has an accountable owner, and follows demand per market. We reject phantom depth because, applied carelessly, it damages the two things the protocol exists to protect — market structure and trust: - -1. **Forgeable depth erodes trust.** Depth is meaningful as a signal only because it is costly real capital at risk. Free virtual depth makes "this market is deep and liquid" a forgeable claim — a thin or manipulated market can be dressed to look deep. Real capital makes the claim unforgeable. -2. **It silently distorts information aggregation.** Virtual depth flattens the weight curve, weakening the reward for early, correct information and making the displayed price unresponsive to news ("stable because unmovable" = a stale forecast). The right magnitude is per-market and volume-dependent; a single governance constant cannot track it and, set too high, degrades the very price-discovery property a prediction market provides. -3. **It is solvent only while never redeemed or used as collateral.** The moment depth backs a real outflow — cancellations, early withdrawals, leverage loans, shared/cross-market pools — the virtual part must be excluded everywhere or it leaks real money (e.g. a leverage loan sized or recovered against fake depth becomes real bad debt to pool depositors). Every "size against liquidity / pay the LP" branch becomes a footgun requiring "…but not the phantom part." Real capital removes this entire class of excludability bugs by construction. -4. **It has no owner, no yield, no accountability.** Virtual depth bears no risk and earns no fee for anyone real; it is a service nobody is paid for and nobody answers for. For the markets it touches, it deletes the retail safe-yield product that is the protocol's core hypothesis (Q3, H1). - -The Lazy Pool is the same idea done with real numbers: auto-allocation smooths the launch of new markets, but the capital is redeemable, leverage-safe, fee-earning, owned by depositors, and self-correcting per market via graduated recall (§6.4). Onix therefore keeps **only real numbers** — every unit of depth is real capital that can be withdrawn, earns, and is accountable. This is a conscious tradeoff: we forgo a cheap virtual stabilizer to preserve the integrity of the price signal and the solvency of every real-money path. - ---- - -## 7. Dispute Resolution Under DAO Governance - -### 7.1 Bonded Oracle Model - -Each oracle $o$ must maintain an insurance bond $I_o \geq I_{\min}$. The bond creates accountability: oracles who misresolve markets, miss deadlines, or lose disputes have their insurance slashed. Oracle revenue derives from: - -1. A fixed per-market fee $f_{\text{fixed}}$ (compensating insurance staking) -2. A percentage fee $f_{\text{oracle}}$ from the losers' pool at resolution - -These two fees enter the system at different points and must not be conflated. The **percentage fee** $f_{\text{oracle}}$ is deducted from $S_{\text{lose}}$ at resolution and appears in the money flow of Theorem 1 (§5.2). The **fixed fee** $f_{\text{fixed}}$ is a direct creator→oracle transfer executed at market *acceptance*, before any betting; it is therefore *not* part of the betting/LP money flow — it neither adds to the seed liquidity $L$ nor draws from $S_{\text{lose}}$, and so does not appear in Theorem 1. (It is omitted from the fee vector $\boldsymbol{\theta}$ of §3.3 for the same reason: $\boldsymbol{\theta}$ collects only the resolution-time, losers-funded percentage fees.) For self-oracle markets no transfer occurs and $f_{\text{fixed}} = 0$. - -The oracle acceptance flow implements an offer-quote mechanism: the creator publishes fee ceilings, and the oracle freezes its actual terms (bounded by both the creator ceiling and a governance cap) at acceptance. - -### 7.2 Two-Mode Dispute System - -Any bettor may challenge a resolution within a grace period $\Delta t_{\text{grace}}$ by escrowing a dispute fee $d$. During disputes, all payouts are frozen. The protocol supports two dispute modes per market: - -**Committee mode ($\delta_{\text{mode}} = 0$).** The entire token-holder electorate resolves the dispute via stake-weighted public vote. Each voter $v$'s weight is: - -$$w_v = s_v + \text{shares}_{v,\text{pool}} \cdot \text{NAV}_{\text{pool}} / S_{\text{total}}$$ - -where $s_v$ is the voter's vesting shares and the second term converts Lazy Pool stake into equivalent governance weight. Votes are public and revisable until the voting period closes — this is a deliberate design choice: disputes are *transparent public hearings*, not secret ballots. New evidence can change votes. - -This transparency carries a known cost. Because the running tally is visible, a voter can defer until late in the window and condition its ballot on others' revealed positions (a last-mover advantage). The protocol accepts this tradeoff on purpose: for a DAO, the auditability and legitimacy of an open hearing are judged more valuable than ballot secrecy, and a flipped outcome still requires moving a stake-weighted majority. Manipulation is deterred not by secrecy but by (i) the stake-weighted approval threshold $\theta_{\text{approve}}$, (ii) a multi-day voting window that dilutes any single timing edge, and (iii) the resolver-reward alignment analyzed in §7.4. A commit-reveal ballot was explicitly considered and **rejected** for this reason — concealing votes would defeat the public-hearing property that gives the verdict its legitimacy. We revisit this as an honest limitation in §12.2. - -The dispute is upheld if the approval percentage exceeds a governance threshold $\theta_{\text{approve}}$: - -$$\frac{\sum_{v: \text{vote}_v = \text{approve}} w_v}{\sum_{v} w_v} \geq \frac{\theta_{\text{approve}}}{10000}$$ - -**Account mode ($\delta_{\text{mode}} = 1$).** A named dispute resolver (recommended: multisig) issues a binding verdict. - -### 7.3 Dispute Outcomes and Incentive Compatibility - -**Oracle wrong (dispute upheld):** - -$$\text{reward}_{\text{pool}} = \min(d \cdot \mu, I_o)$$ - -where $\mu$ is the reward multiplier. The reward pool is split: - -- Disputer receives $d$ (fee refund) + $\text{reward}_{\text{pool}} / \mu$ -- Resolver/voters receive $\text{reward}_{\text{pool}} - \text{reward}_{\text{pool}} / \mu$ -- Remaining insurance: additional penalty $\rightarrow$ DAO fund - -**Oracle right (dispute rejected):** - -$$d \rightarrow \text{50\% resolver, 50\% oracle}$$ - -**Oracle non-responsive (auto-close at 14 days):** - -- Disputer: fee refunded -- Oracle: $d$ slashed from insurance -- All bets and LP positions: full refund -- Slashed amount distributed proportionally to all participants - -### 7.4 Game-Theoretic Analysis - -**Oracle incentive compatibility.** The oracle's expected payoff from honest resolution vs. manipulation is: - -$$\mathbb{E}[\pi_{\text{honest}}] = f_{\text{fixed}} + f_{\text{oracle}} \quad \text{(per market)}$$ - -$$\mathbb{E}[\pi_{\text{dishonest}}] = p_{\text{detect}} \cdot (-I_o \cdot \theta_{\text{penalty}} - B_{\text{ban}}) + (1 - p_{\text{detect}}) \cdot g_{\text{manipulation}}$$ - -where $p_{\text{detect}}$ is the probability of dispute, $\theta_{\text{penalty}}$ is the insurance slash fraction, $B_{\text{ban}}$ is the present value of a ban (lost future revenue), and $g_{\text{manipulation}}$ is the one-time manipulation gain. - -Honest behavior is a Nash equilibrium when: - -$$f_{\text{fixed}} + f_{\text{oracle}} > (1 - p_{\text{detect}}) \cdot g_{\text{manipulation}} - p_{\text{detect}} \cdot (I_o \cdot \theta_{\text{penalty}} + B_{\text{ban}})$$ - -The protocol ensures this by requiring $I_o \gg g_{\text{manipulation}}$ and maintaining high $p_{\text{detect}}$ through public dispute visibility and committee participation incentives. - -**Disputer incentive.** A rational bettor files a dispute when the expected reward exceeds the dispute fee: - -$$\mathbb{E}[\text{reward}_{\text{dispute}}] = p_{\text{upheld}} \cdot (d + d \cdot (\mu - 1) / \mu) > d$$ - -This simplifies to $p_{\text{upheld}} > 1/\mu$, establishing a natural threshold for dispute filing. - -**Committee voting incentive.** In committee mode, voters participate because their Lazy Pool stake (and thus governance weight) directly earns a share of the resolver reward pool. The expected reward for voter $v$ is: - -$$\mathbb{E}[\pi_v] = \frac{w_v}{\sum w_j} \cdot \text{voter\_reward\_pool} \cdot p_{\text{upheld}}$$ - -### 7.5 No-Contest Declaration - -An oracle unable to verify an outcome may declare no-contest at reduced cost ($50\%$ of the dispute penalty from insurance). This creates a three-tier incentive gradient: - -| Action | Oracle Cost | Ban Risk | -|--------|------------|----------| -| Voluntary no-contest | $0.5 \cdot d$ from insurance | None | -| Dispute loss | $I_o \cdot \theta_{\text{penalty}} + \text{extra}$ | Yes | -| Missed deadline | $I_o \cdot \theta_{\text{miss}}$ | None | - -A no-contest declaration is itself disputable, with the resolver choosing from three outcomes (A wins, B wins, or confirm no-contest), preventing abuse. - ---- - -## 8. The VIZ Token in the Prediction Market Experiment - -### 8.1 Token Utility - -The VIZ token serves four distinct functions within the Onix Protocol ecosystem: - -1. **Medium of exchange.** All bets, LP deposits, oracle insurance, and dispute fees are denominated in VIZ. The protocol never mints tokens — it is strictly zero-sum at the consensus level. - -2. **Governance weight.** VIZ staked as vesting shares (or deposited in the Lazy Pool) confers voting power in DAO committee disputes and chain parameter governance. This creates direct utility for token holding beyond speculation. - -3. **Oracle collateral.** Oracle insurance bonds are denominated in VIZ. The bond must exceed the oracle's potential manipulation profit, creating a demand for token accumulation by oracle operators. - -4. **Dispute escrow.** Dispute fees are escrowed in VIZ, creating a cost for frivolous disputes and a reward mechanism for valid challenges. - -### 8.2 Token Demand Feedback Loop - -The protocol creates a structural demand cycle: - -$$\text{LP deposits} \xrightarrow{\text{lock}} \text{reduced circulating supply}$$ -$$\text{Oracle insurance} \xrightarrow{\text{lock}} \text{reduced circulating supply}$$ -$$\text{Active bets} \xrightarrow{\text{lock}} \text{reduced circulating supply}$$ -$$\text{Governance weight} \xrightarrow{\text{utility}} \text{demand for staking}$$ - -The total locked supply at any time is: - -$$S_{\text{locked}} = S_{\text{pool}} + \sum_o I_o + \sum_{\text{active bets}} a_i + \sum_{\text{disputes}} d_k$$ - -where $S_{\text{pool}}$ is the total withdrawal-locked Lazy-Pool balance (free *and* market-allocated portions are both locked for the deposit lock period), $I_o$ is oracle insurance, $a_i$ are active bet stakes, and $d_k$ are escrowed dispute fees. This locked supply reduces available circulating supply, potentially creating upward price pressure as protocol usage grows — the same bet every protocol-native token makes, here explicitly tied to measurable utility. - -### 8.3 Experimental Value of the Token - -The VIZ token in this experiment serves as a **measurement instrument**: - -- **Price as signal.** Token price movements in response to protocol events (market launches, high-volume resolutions, dispute outcomes) provide a continuous market-based assessment of the protocol's perceived value. -- **Governance participation rate.** The fraction of token holders participating in dispute votes measures the viability of DAO-based arbitration. -- **Lazy Pool accumulation rate.** The rate of pool deposits measures retail demand for risk-free LP yield, directly testing hypothesis Q3. - ---- - -## 9. Full Market Cycle: A Worked Example - -We trace a complete binary market lifecycle to illustrate the protocol's operation. - -### 9.1 Setup - -- **Market:** "Will event X occur by date Y?" (Binary: Yes/No) -- **Oracle:** $o$ with insurance $I_o = 5000$ VIZ -- **Seed liquidity:** $L = 200$ VIZ from creator -- **Fee parameters:** $\theta_{\text{oracle}} = 50$ bp, $\theta_{\text{creator}} = 50$ bp, $\theta_{\text{liq}} = 100$ bp -- **Lazy Pool:** $B_{\text{free}} = 10{,}000$ VIZ, $\alpha = 2\%$, allocates $a_{\text{alloc}} = 200$ VIZ - -> **Units.** Amounts are displayed in VIZ for readability, but the protocol stores and computes them as **integer milli-VIZ (mVIZ)**, with $1\text{ VIZ} = 1000\text{ mVIZ}$, and every division is floored (cf. the §5.2 remark). The fee lines below are shown in mVIZ so that $\lfloor\cdot\rfloor$ is exact; the VIZ equivalent is given alongside. This resolves the apparent rounding mismatch that arises if one floors over whole-VIZ quantities (e.g. $\lfloor 80\times 50/10000\rfloor$ is $0$ in VIZ but $400$ mVIZ $=0.4$ VIZ in the real units). - -### 9.2 Initialization - -$$R_A = 100, \quad R_B = 100, \quad k = 10{,}000$$ - -Lazy Pool auto-allocates 200 VIZ as additional LP: - -$$R_A = 200, \quad R_B = 200, \quad k = 40{,}000$$ - -### 9.3 Betting Phase - -- **Alice** bets $a_1 = 50$ VIZ on Yes (side A): - $$R'_A = 250, \quad R'_B = \lfloor 40000/250 \rfloor = 160, \quad w_1 = 200 - 160 = 40$$ - -- **Bob** bets $a_2 = 80$ VIZ on No (side B): - $$R'_B = 240, \quad R'_A = \lfloor 40000/240 \rfloor = 166, \quad w_2 = 250 - 166 = 84$$ - -Implied probability: $P(\text{Yes}) = 166 / 406 \approx 41\%$, $P(\text{No}) = 240 / 406 \approx 59\%$. - -### 9.4 Resolution - -Oracle declares **Yes** wins. Alice is the sole winner; Bob forfeits 80 VIZ. - -$$S_{\text{lose}} = 80{,}000 \text{ mVIZ} \;(80 \text{ VIZ})$$ -$$f_{\text{oracle}} = \lfloor 80{,}000 \times 50 / 10000 \rfloor = 400 \text{ mVIZ} \;(0.4 \text{ VIZ})$$ -$$f_{\text{creator}} = \lfloor 80{,}000 \times 50 / 10000 \rfloor = 400 \text{ mVIZ} \;(0.4 \text{ VIZ})$$ -$$f_{\text{liq}} = \lfloor 80{,}000 \times 100 / 10000 \rfloor = 800 \text{ mVIZ} \;(0.8 \text{ VIZ})$$ -$$W = 80{,}000 - 400 - 400 - 800 = 78{,}400 \text{ mVIZ} \;(78.4 \text{ VIZ})$$ - -**Alice's payout** (sole winner, $w_1 / w_1 = 1$): - -$$\pi_1 = 50{,}000 + \lfloor 78{,}400 \times 40/40 \rfloor - \tau_1 = 128{,}400 \text{ mVIZ} - \tau_1 \;(128.4 \text{ VIZ} - \tau_1)$$ - -**LP return:** - -- Creator LP: $200 \text{ VIZ principal} + \text{time-weighted share of } 0.8 \text{ VIZ fee pool}$ -- Lazy Pool LP: $200 \text{ VIZ principal} + \text{time-weighted share of } 0.8 \text{ VIZ fee pool}$ - -**Verification** (Theorem 1): - -$$\text{Money}_{\text{IN}} = 200 + 200 + 50 + 80 = 530$$ -$$\text{Money}_{\text{OUT}} = 200 + 200 + 50 + 78.4 + 0.4 + 0.4 + 0.8 = 530 \quad \checkmark$$ - -### 9.5 Dispute Scenario - -If Bob disputes within $\Delta t_{\text{grace}} = 12\text{h}$, paying $d = 10$ VIZ: - -1. All payouts freeze. -2. Oracle must respond within 12 hours. -3. In committee mode, all token holders vote (stake-weighted, public, revisable). -4. If dispute upheld: payouts recalculated with corrected outcome, oracle insurance slashed. -5. If dispute rejected: original payouts proceed, Bob loses 10 VIZ (split 50/50 to oracle and resolver). -6. If no resolution within 14 days: auto-close with full refunds. - ---- - -## 10. Anti-MEV: Batch and Commit-Reveal Betting - -### 10.1 MEV in Prediction Markets - -In continuous-time prediction markets, front-running and sandwich attacks extract value from bettors. When a large bet is broadcast to the mempool, an attacker can: - -1. Front-run: place a bet on the same side before the large bet, profiting from the price movement -2. Sandwich: place bets on both sides around the large bet - -### 10.2 Batch Settlement - -The protocol supports opt-in batch betting (binary markets). Bets submitted within an epoch of $E$ blocks are queued and settled at a **uniform price** at the epoch boundary. Only the net residual (aggregate demand difference) moves the AMM: - -$$\Delta R_A = \sum_{\text{batch}} a_{i,A} - \sum_{\text{batch}} a_{i,B}$$ - -This eliminates intra-batch ordering advantage: all bets in a batch receive identical pricing regardless of submission order. - -### 10.3 Commit-Reveal - -For stronger MEV protection, bettors may use a two-phase commit-reveal scheme: - -1. **Commit:** Submit $H(\text{bet} \| \text{nonce})$ with escrow. The bet's direction and amount are hidden. -2. **Reveal:** After the epoch closes, submit $(\text{bet}, \text{nonce})$ to execute at the batch price. - -Unrevealed commitments forfeit a governance-defined penalty percentage of the escrow, preventing spam commitments. - ---- - -## 11. Implementation - -### 11.1 Consensus-Level Operations on VIZ DLT - -The protocol is implemented as first-class consensus-validated operations on the VIZ distributed ledger — not smart contracts, not custom payloads. VIZ DLT provides ~3-second block times, Delegated Proof of Stake consensus, and named accounts (Graphene-style) with no general-purpose virtual machine. - -Every financial action (market creation, bet placement, oracle resolution, dispute filing, LP deposit/withdrawal) is a `pm_*` operation validated by every validator node. Invalid operations are rejected before block inclusion. - -| Layer | Examples | Consensus-Validated | -|-------|---------|---------------------| -| Protocol operations | `pm_create_market`, `pm_place_bet`, `pm_resolve_market`, `pm_dispute_create`, `pm_lazy_deposit` | Yes — every node validates | -| Virtual operations | `pm_payout`, `pm_dispute_finalize`, `pm_lazy_recall`, `pm_batch_settle` | Yes — deterministic, block-time | -| Metadata | Market descriptions, dispute evidence | No — client-side only | - -### 11.2 On-Chain State - -All protocol state resides in chainbase indexed objects. Key objects include: - -- `pm_market_object`: market configuration, CPMM reserves, fee parameters, state -- `pm_bet_object`: bettor positions with weight and time penalty -- `pm_liquidity_object`: LP positions with time-weight -- `pm_lazy_pool_object`: singleton pool state (balances, shares, reward accumulator) -- `pm_oracle_object`: oracle registration, insurance, reputation counters -- `pm_dispute_object`: dispute state and resolution - -Reputation metrics are computed on read (not stored), ensuring consistency without additional write operations. - -### 11.3 Governance Parameters - -All economic parameters (fees, penalties, insurance requirements, dispute windows, lazy pool settings) are delegate median-voted. Each elected validator publishes preferred values; the network computes the median. Parameters change without hard forks or deployments. Kill-switches allow governance to disable subsystems (leverage, commit-reveal) by median vote. - -### 11.4 Scalability - -Because every operation is consensus-validated, the protocol's cost model matters at scale (thousands of concurrent markets and bets). The design keeps per-block and per-operation work bounded: - -- **$O(1)$ user-facing operations.** Bet placement, cancellation, and LP deposit/withdraw touch a fixed number of indexed objects (the market, the bettor's position, and — for the pool — the singleton accumulator). None iterates over all participants. Reward distribution uses the MasterChef accumulator $\rho$ (§6.3), so a pool with $n$ depositors settles rewards in $O(1)$ per actor rather than $O(n)$ per resolution. -- **Bounded deferred work per block.** Settlement is the only fan-out step (a market with $m$ winning bets generates $m$ `pm_payout` virtual operations). To prevent a single large resolution from bloating a block, payout and cron processing are rate-limited by the median parameter `pm_processing_cap_per_block`: at most a fixed number of payouts/cron items are processed per block, and the remainder carry to subsequent blocks. Worst-case per-block work is therefore $O(\text{cap})$, independent of how many markets resolve in the same interval. -- **No write amplification from reputation.** The 14 oracle metrics are counters updated only on the oracle's own actions; the composite reliability score is computed **on read**, not written each block (§11.2). Market discovery metadata is built by a non-consensus plugin and never enters block validation. -- **State growth.** State is linear in live objects (markets, open positions, active disputes). Resolved markets and paid positions are terminal and prunable by clients; consensus retains only what open obligations require. - -The binding constraint at very high market counts is thus block space for settlement fan-out, which `pm_processing_cap_per_block` converts from a latency spike into bounded, amortized throughput rather than a consensus-halting cost. A quantitative stress simulation across many concurrent markets of varying volume and volatility is part of the experimental program (§12.3, H4). - ---- - -## 12. Discussion - -### 12.1 Comparison with Existing Approaches - -| Dimension | Onix Protocol | Polymarket (CLOB+UMA) | Standard LMSR | Uniswap-style AMM | -|-----------|---------------|----------------------|---------------|-------------------| -| LP risk | **Zero** (structural) | Inventory risk | Up to $b \ln N$ | Impermanent loss | -| LP knowledge required | Low (deposit) | High (manage orders) | Medium | Medium-High | -| Pricing continuity | Continuous (AMM/LMSR) | Discrete (order book) | Continuous | Continuous | -| Fee extraction | Losers only, at resolution | Bid-ask spread | Spread | Every trade | -| Oracle model | Bonded + DAO dispute | UMA Optimistic Oracle | Operator | N/A | -| Price coherence | Mathematical invariant | Arbitrage-dependent | Mathematical invariant | Mathematical invariant | -| CTF split/merge needed | No | Yes | No | No | - -### 12.2 Limitations and Honest Tradeoffs - -1. **LP yield is volume-dependent, not depth-dependent.** A market with high subsidy and low volume earns the same absolute fees as one with low subsidy and equal volume. The subsidy provides depth (lower slippage) but not yield. - -2. **LP profit is not guaranteed.** If a market resolves with zero losing bets, no fees are generated. LP principal is returned, but yield may be zero. - -3. **Parimutuel tokens are not fixed-value instruments.** Unlike standard LMSR where 1 winning token = 1 currency unit, Onix tokens are proportional claims on the losers' pool. If all bettors pick the winner, everyone breaks even. - -4. **DPoS governance tradeoffs.** The delegate-voted parameter model has known concentration risks inherent to DPoS (shared with EOS, Hive, Tron). The Lazy Pool governance-weight mechanism partially mitigates this by broadening the effective electorate. - -5. **Token liquidity dependency.** Economic guarantees (insurance bonds, dispute fees) scale with token market value. The protocol assumes utility drives demand — the standard assumption for protocol-native tokens. - -6. **Leverage adds bounded credit risk to the pool.** The opt-in leverage subsystem (§6.6) is the one component *not* covered by Theorem 1. When enabled, the pool acts as a lender and can incur a shortfall on the same-side-cancel path, bounded by borrower collateral and isolated to a governed fund fraction. We claim full loan recovery on the cascade and settlement paths as a *design property verified in simulation*, not as a proven theorem; a closed-form recovery proof under arbitrary reserve trajectories is open work. The subsystem is default-off and disableable by median vote, so the unconditional LP guarantee can always be restored. - -7. **Public dispute voting has a timing tradeoff.** Open, revisable committee ballots (§7.2) admit a last-mover advantage and were chosen deliberately over commit-reveal for auditability. This is a value judgment (transparency over secrecy), not a proof that open voting is manipulation-optimal; deployments that prioritize secrecy would need account-mode resolution instead. - -### 12.3 Experimental Hypotheses - -The deployed protocol is designed to test the following hypotheses: - -**H1 (Liquidity flywheel).** *Zero-risk LP provision attracts retail capital sufficient to produce market depth that meaningfully reduces slippage relative to comparable platforms.* - -Measurable: Lazy Pool total deposits, average market depth (reserve ratios), slippage per unit bet size. - -**H2 (Information aggregation).** *AMM/LMSR pricing with parimutuel settlement produces probability estimates of comparable accuracy to CLOB-based prediction markets for equivalent information conditions.* - -Measurable: Brier scores, calibration curves, comparison with external benchmarks (polls, models, other markets). - -**H3 (Oracle reliability under DAO governance).** *Bonded oracles with committee-mode dispute resolution achieve resolution accuracy comparable to centralized oracle services, with dispute rates below a sustainable threshold.* - -Measurable: Oracle dispute rate, dispute loss rate, average resolution time, reliability score distribution. - -**H4 (Lazy Pool sustainability).** *The graduated recall and fault stamp mechanisms prevent oracle exploitation of the Lazy Pool, maintaining positive net yield for pool depositors across diverse market portfolios.* - -Measurable: Pool NAV over time, recall frequency, fault stamp distribution, net yield per share. - -**H5 (Token demand correlation).** *Protocol usage (volume, market count, LP deposits) positively correlates with token staking demand and governance participation rate.* - -Measurable: Token staking rate, dispute vote participation, Lazy Pool deposit rate, correlation analysis. - -**H6 (Anti-MEV effectiveness).** *Batch settlement and commit-reveal mechanisms reduce measurable MEV extraction compared to continuous instant betting.* - -Measurable: Price impact asymmetry (batch vs. instant), sandwich attack frequency, bettor execution quality. - -**H7 (Leverage solvency).** *Under live trajectories, snapshot-based liquidation recovers the loan on the cascade and settlement paths, confining realized pool shortfall to the same-side-cancel path and within borrower collateral, so that leverage interest is net-accretive to pool yield.* (This tests the design property of §6.6 empirically, in lieu of a closed-form recovery proof.) - -Measurable: Realized loan-recovery ratio per liquidation event ($\text{recovered}/\lambda m$), frequency and magnitude of same-side-cancel shortfalls relative to posted collateral, leverage interest as a share of total pool yield, pool NAV with vs. without the leverage subsystem enabled. - ---- - -## 13. Conclusion - -We have presented the Onix Protocol, a prediction market architecture that achieves a structural LP principal guarantee by decoupling the pricing function (CPMM for binary, LMSR for multi-outcome) from the settlement function (parimutuel, losers-fund-winners). We proved that this guarantee holds for both market types regardless of weight assignment, fee parameters, or betting distribution. - -The "Lazy" Pool mechanism enables passive retail LP participation with automated capital deployment and graduated opportunity-cost protection. The two-mode dispute system — combining bonded oracles with stake-weighted DAO committee voting — provides a viable alternative to centralized arbitration while maintaining oracle incentive compatibility. - -The protocol is implemented as consensus-level operations on the VIZ distributed ledger and is designed as an experiment testing seven explicit hypotheses about liquidity bootstrapping, information aggregation accuracy, DAO governance viability, leverage solvency, and token demand dynamics. The opt-in leverage subsystem is the single component that trades the unconditional LP guarantee for bounded, default-off pool credit risk; everything else preserves the structural guarantee of Theorem 1. - -The mathematical properties are verifiable. The economic hypotheses will be tested by market participation. - ---- - -## References - -[1] Hanson, R. (2003). Combinatorial Information Market Design. *Information Systems Frontiers*, 5(1), 107–119. - -[2] Adams, H., Zinsmeister, N., & Robinson, D. (2020). *Uniswap v2 Core.* Uniswap Labs. - -[3] Adams, H., Zinsmeister, N., Salem, M., Keefer, R., & Robinson, D. (2021). *Uniswap v3 Core.* Uniswap Labs. - -[4] Berg, J., Forsythe, R., Nelson, F., & Rietz, T. (2008). Results from a Dozen Years of Election Futures Markets Research. In *Handbook of Experimental Economics Results* (Vol. 1, pp. 742–751). Elsevier. - -[5] Cowgill, B., Wolfers, J., & Zitzewitz, E. (2009). Using Prediction Markets to Track Information Flows: Evidence from Google. In *Auctions, Market Mechanisms and Their Applications (AMMA 2009)*, LNICST Vol. 14. Springer. - -[6] Levitt, S. D. (2004). Why Are Gambling Markets Organised So Differently from Financial Markets? *The Economic Journal*, 114(495), 223–246. - -[7] Gnosis. *Conditional Tokens Framework (CTF) Documentation.* - -[8] UMA Protocol. *Optimistic Oracle Documentation.* - -[9] Leshner, R., & Hayes, G. (2019). *Compound: The Money Market Protocol.* Compound Labs. - -[10] SushiSwap. (2020). *MasterChef Contract.* - -[11] Piskunov, A. *VIZ: Distributed Ledger Technical Description, Fair DPoS, and Governance.* VIZ-Blockchain. - -[12] Arrow, K. J., Forsythe, R., Gorham, M., Hahn, R., Hanson, R., Ledyard, J. O., et al. (2008). The Promise of Prediction Markets. *Science*, 320(5878), 877–878. - -[13] Wolfers, J., & Zitzewitz, E. (2004). Prediction Markets in Theory and Practice. *NBER Working Paper* No. 10248 (also *Journal of Economic Perspectives*, 18(2), 107–126). - -[14] Othman, A., Pennock, D. M., Reeves, D. M., & Sandholm, T. (2013). A Practical Liquidity-Sensitive Automated Market Maker. *ACM Transactions on Economics and Computation*, 1(3), Article 14. - -[15] Abernethy, J., Chen, Y., & Vaughan, J. W. (2011). An Optimization-Based Framework for Automated Market-Making. In *Proceedings of the 12th ACM Conference on Electronic Commerce (EC '11)* (pp. 297–306). diff --git a/.qoder/docs/onix-protocol-paper.pdf b/.qoder/docs/onix-protocol-paper.pdf deleted file mode 100644 index e146fd777f..0000000000 Binary files a/.qoder/docs/onix-protocol-paper.pdf and /dev/null differ diff --git a/.qoder/docs/op-account-market.md b/.qoder/docs/op-account-market.md deleted file mode 100644 index b084bae2c2..0000000000 --- a/.qoder/docs/op-account-market.md +++ /dev/null @@ -1,236 +0,0 @@ -# VIZ Blockchain — Account Market Operations - -Spec for implementing account sale operations in PHP/Node.js libraries. - -Account market operations allow accounts to be bought and sold. An account owner sets their account for sale, and a buyer can purchase it. - ---- - -## `set_account_price_operation` - -**Type ID:** `54` -**Required authority:** `master` of `account` - -Sets an account for sale or updates its sale parameters. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account being listed for sale | -| `account_seller` | `account_name_type` | yes | Account to receive payment | -| `account_offer_price` | `asset` (VIZ) | yes | Asking price | -| `account_on_sale` | `bool` | yes | `true` to list, `false` to delist | - -### JSON Example - -```json -[54, { - "account": "alice", - "account_seller": "alice", - "account_offer_price": "1000.000 VIZ", - "account_on_sale": true -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'set_account_price_operation', - 'value' => [ - 'account' => 'alice', - 'account_seller' => 'alice', - 'account_offer_price' => '1000.000 VIZ', - 'account_on_sale' => true, - ], -]; -``` - -### Node.js Example - -```js -const op = ['set_account_price', { - account: 'alice', - account_seller: 'alice', - account_offer_price: '1000.000 VIZ', - account_on_sale: true, -}]; -``` - -### Checklist -- [ ] `account_offer_price.symbol` must be `VIZ` -- [ ] `account_offer_price.amount` > 0 -- [ ] `account_on_sale: false` delists the account -- [ ] Fee (`account_on_sale_fee`) is charged when listing -- [ ] `account_seller` can differ from `account` (payment redirected) -- [ ] Sign with `account`'s master key - ---- - -## `set_subaccount_price_operation` - -**Type ID:** `55` -**Required authority:** `master` of `account` - -Lists the right to create subaccounts of `account` for sale. A "subaccount" of `alice` would be `alice.bob`. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Parent account | -| `subaccount_seller` | `account_name_type` | yes | Account to receive payment | -| `subaccount_offer_price` | `asset` (VIZ) | yes | Price per subaccount creation | -| `subaccount_on_sale` | `bool` | yes | `true` to list, `false` to delist | - -### JSON Example - -```json -[55, { - "account": "alice", - "subaccount_seller": "alice", - "subaccount_offer_price": "50.000 VIZ", - "subaccount_on_sale": true -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'set_subaccount_price_operation', - 'value' => [ - 'account' => 'alice', - 'subaccount_seller' => 'alice', - 'subaccount_offer_price' => '50.000 VIZ', - 'subaccount_on_sale' => true, - ], -]; -``` - -### Checklist -- [ ] `subaccount_offer_price.symbol` must be `VIZ` -- [ ] `subaccount_on_sale: false` delists -- [ ] Fee (`subaccount_on_sale_fee`) is charged when listing -- [ ] Sign with `account`'s master key - ---- - -## `buy_account_operation` - -**Type ID:** `56` -**Required authority:** `active` of `buyer` - -Purchases an account that is listed for sale. All authorities are transferred to the buyer. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `buyer` | `account_name_type` | yes | Purchasing account | -| `account` | `account_name_type` | yes | Account being purchased | -| `account_offer_price` | `asset` (VIZ) | yes | Purchase price (must match listing) | -| `account_authorities_key` | `public_key_type` | yes | New key set as all authorities of purchased account | -| `tokens_to_shares` | `asset` (VIZ) | yes | Additional VIZ to convert to SHARES for bought account | - -### JSON Example - -```json -[56, { - "buyer": "bob", - "account": "alice", - "account_offer_price": "1000.000 VIZ", - "account_authorities_key": "VIZ5newowner...", - "tokens_to_shares": "0.000 VIZ" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'buy_account_operation', - 'value' => [ - 'buyer' => 'bob', - 'account' => 'alice', - 'account_offer_price' => '1000.000 VIZ', - 'account_authorities_key' => 'VIZ5newowner...', - 'tokens_to_shares' => '0.000 VIZ', - ], -]; -``` - -### Node.js Example - -```js -const op = ['buy_account', { - buyer: 'bob', - account: 'alice', - account_offer_price: '1000.000 VIZ', - account_authorities_key: 'VIZ5newowner...', - tokens_to_shares: '0.000 VIZ', -}]; -``` - -### Checklist -- [ ] `account` must be currently listed for sale (`account_on_sale: true`) -- [ ] `account_offer_price` must exactly match the listed price -- [ ] `account_authorities_key` is set as master, active, regular, and memo key -- [ ] `tokens_to_shares.symbol` must be `VIZ` -- [ ] `tokens_to_shares.amount` >= 0 (can be 0) -- [ ] Payment goes to `account_seller` as specified in the listing -- [ ] Virtual `account_sale_operation` fires on successful purchase -- [ ] Sign with `buyer`'s active key - ---- - -## `target_account_sale_operation` - -**Type ID:** `61` -**Required authority:** `master` of `account` - -Lists an account for sale to a specific buyer only (private/targeted sale). Added in HF11. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account being listed | -| `account_seller` | `account_name_type` | yes | Account to receive payment | -| `target_buyer` | `account_name_type` | yes | Only this account can buy | -| `account_offer_price` | `asset` (VIZ) | yes | Asking price | -| `account_on_sale` | `bool` | yes | `true` to list, `false` to delist | - -### JSON Example - -```json -[61, { - "account": "alice", - "account_seller": "alice", - "target_buyer": "charlie", - "account_offer_price": "500.000 VIZ", - "account_on_sale": true -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'target_account_sale_operation', - 'value' => [ - 'account' => 'alice', - 'account_seller' => 'alice', - 'target_buyer' => 'charlie', - 'account_offer_price' => '500.000 VIZ', - 'account_on_sale' => true, - ], -]; -``` - -### Checklist -- [ ] Only `target_buyer` can purchase this account via `buy_account_operation` -- [ ] `account_offer_price.symbol` must be `VIZ` -- [ ] `account_on_sale: false` delists the targeted sale -- [ ] Sign with `account`'s master key diff --git a/.qoder/docs/op-account.md b/.qoder/docs/op-account.md deleted file mode 100644 index 397d8288a0..0000000000 --- a/.qoder/docs/op-account.md +++ /dev/null @@ -1,199 +0,0 @@ -# VIZ Blockchain — Account Operations - -Spec for implementing account-related operations in PHP/Node.js libraries. - ---- - -## `account_create_operation` - -**Type ID:** `20` -**Required authority:** `active` of `creator` - -Creates a new blockchain account. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `fee` | `asset` (VIZ) | yes | Creation fee (converted to SHARES for new account) | -| `delegation` | `asset` (SHARES) | yes | Initial SHARES delegation to new account | -| `creator` | `account_name_type` | yes | Account paying the fee and creating | -| `new_account_name` | `account_name_type` | yes | Name for the new account | -| `master` | `authority` | yes | Master authority for new account | -| `active` | `authority` | yes | Active authority for new account | -| `regular` | `authority` | yes | Regular authority for new account | -| `memo_key` | `public_key_type` | yes | Memo public key | -| `json_metadata` | `string` | yes | JSON metadata (may be empty `""`) | -| `referrer` | `account_name_type` | yes | Referrer account name (may be empty `""`) | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[20, { - "fee": "1.000 VIZ", - "delegation": "10.000000 SHARES", - "creator": "alice", - "new_account_name": "bob", - "master": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9", 1]] - }, - "active": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9", 1]] - }, - "regular": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9", 1]] - }, - "memo_key": "VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9", - "json_metadata": "", - "referrer": "", - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'account_create_operation', - 'value' => [ - 'fee' => '1.000 VIZ', - 'delegation' => '10.000000 SHARES', - 'creator' => 'alice', - 'new_account_name' => 'bob', - 'master' => ['weight_threshold' => 1, 'account_auths' => [], 'key_auths' => [['VIZ5hq...', 1]]], - 'active' => ['weight_threshold' => 1, 'account_auths' => [], 'key_auths' => [['VIZ5hq...', 1]]], - 'regular' => ['weight_threshold' => 1, 'account_auths' => [], 'key_auths' => [['VIZ5hq...', 1]]], - 'memo_key' => 'VIZ5hq...', - 'json_metadata' => '', - 'referrer' => '', - 'extensions' => [], - ], -]; -``` - -### Node.js Example - -```js -const op = ['account_create', { - fee: '1.000 VIZ', - delegation: '10.000000 SHARES', - creator: 'alice', - new_account_name: 'bob', - master: { weight_threshold: 1, account_auths: [], key_auths: [['VIZ5hq...', 1]] }, - active: { weight_threshold: 1, account_auths: [], key_auths: [['VIZ5hq...', 1]] }, - regular: { weight_threshold: 1, account_auths: [], key_auths: [['VIZ5hq...', 1]] }, - memo_key: 'VIZ5hq...', - json_metadata: '', - referrer: '', - extensions: [], -}]; -``` - -### Checklist -- [ ] `fee.symbol` must be `VIZ` -- [ ] `delegation.symbol` must be `SHARES` -- [ ] `new_account_name` must pass `is_valid_create_account_name` validation -- [ ] All three authorities must be provided (even if identical) -- [ ] `memo_key` must be a valid VIZ public key -- [ ] `fee` >= chain `account_creation_fee` property -- [ ] Sign with `creator`'s active key - ---- - -## `account_update_operation` - -**Type ID:** `5` -**Required authority:** `master` of `account` (if changing master key), else `active` - -Updates account keys and metadata. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account to update | -| `master` | `optional` | no | New master authority (triggers master-auth requirement) | -| `active` | `optional` | no | New active authority | -| `regular` | `optional` | no | New regular authority | -| `memo_key` | `public_key_type` | yes | New memo key | -| `json_metadata` | `string` | yes | New JSON metadata | - -### JSON Example - -```json -[5, { - "account": "alice", - "active": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5new...", 1]] - }, - "memo_key": "VIZ5new...", - "json_metadata": "{\"profile\":\"updated\"}" -}] -``` - -### Checklist -- [ ] `master` field is **optional** — omit (or set to `null`) if not changing master key -- [ ] If `master` is present → sign with current **master** key -- [ ] If `master` is absent → sign with current **active** key -- [ ] `memo_key` is always required (even if unchanged) - ---- - -## `account_metadata_operation` - -**Type ID:** `21` -**Required authority:** `regular` of `account` - -Updates only the account's JSON metadata. Cheaper in bandwidth than full `account_update`. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account to update | -| `json_metadata` | `string` | yes | New JSON metadata string | - -### JSON Example - -```json -[21, { - "account": "alice", - "json_metadata": "{\"name\":\"Alice\",\"about\":\"Hello!\"}" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'account_metadata_operation', - 'value' => [ - 'account' => 'alice', - 'json_metadata' => json_encode(['name' => 'Alice', 'about' => 'Hello!']), - ], -]; -``` - -### Node.js Example - -```js -const op = ['account_metadata', { - account: 'alice', - json_metadata: JSON.stringify({ name: 'Alice', about: 'Hello!' }), -}]; -``` - -### Checklist -- [ ] `json_metadata` must be valid UTF-8 -- [ ] Max metadata size limited by bandwidth -- [ ] Sign with `account`'s regular key -- [ ] Faster/cheaper than `account_update` for metadata-only changes diff --git a/.qoder/docs/op-award.md b/.qoder/docs/op-award.md deleted file mode 100644 index 4a914c605f..0000000000 --- a/.qoder/docs/op-award.md +++ /dev/null @@ -1,162 +0,0 @@ -# VIZ Blockchain — Award Operations - -Spec for implementing award operations in PHP/Node.js libraries. - -Awards are the primary social reward mechanism in VIZ. An account spends "energy" to award SHARES directly to another account (and optionally to beneficiaries). - ---- - -## `award_operation` - -**Type ID:** `47` -**Required authority:** `regular` of `initiator` - -Awards SHARES to `receiver` from the reward pool, proportional to the initiator's energy expenditure and SHARES stake. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `initiator` | `account_name_type` | yes | Account giving the award | -| `receiver` | `account_name_type` | yes | Account receiving the award | -| `energy` | `uint16_t` | yes | Energy to spend (basis points: 1–10000) | -| `custom_sequence` | `uint64_t` | yes | Application-defined sequence number | -| `memo` | `string` | yes | Optional message/reason | -| `beneficiaries` | `vector` | yes | Optional beneficiaries receiving a share | - -### JSON Example - -```json -[47, { - "initiator": "alice", - "receiver": "bob", - "energy": 1000, - "custom_sequence": 0, - "memo": "great article!", - "beneficiaries": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'award_operation', - 'value' => [ - 'initiator' => 'alice', - 'receiver' => 'bob', - 'energy' => 1000, - 'custom_sequence' => 0, - 'memo' => 'great article!', - 'beneficiaries' => [], - ], -]; -``` - -### Node.js Example - -```js -const op = ['award', { - initiator: 'alice', - receiver: 'bob', - energy: 1000, - custom_sequence: 0, - memo: 'great article!', - beneficiaries: [], -}]; -``` - -### Checklist -- [ ] `energy` range: 1–10000 (1 = 0.01%, 10000 = 100%) -- [ ] Energy regenerates at 100%/day (CHAIN_ENERGY_REGENERATION_SECONDS) -- [ ] Beneficiary weights sum must be <= 10000 (100%) -- [ ] Beneficiaries list must be sorted by account name ascending -- [ ] If beneficiaries are present, `receiver` gets `(1 - sum_beneficiary_weights/10000)` share -- [ ] `custom_sequence` is app-defined, can be 0 -- [ ] Sign with `initiator`'s regular key -- [ ] Virtual `receive_award_operation` fires for `receiver` -- [ ] Virtual `benefactor_award_operation` fires for each beneficiary - ---- - -## `fixed_award_operation` - -**Type ID:** `60` -**Required authority:** `regular` of `initiator` - -Awards a **fixed amount** of SHARES to `receiver`, spending energy proportionally based on the desired amount. Added in HF11. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `initiator` | `account_name_type` | yes | Account giving the award | -| `receiver` | `account_name_type` | yes | Account receiving the award | -| `reward_amount` | `asset` (SHARES) | yes | Fixed amount of SHARES to award | -| `max_energy` | `uint16_t` | yes | Maximum energy to spend (0 = no limit) | -| `custom_sequence` | `uint64_t` | yes | Application-defined sequence number | -| `memo` | `string` | yes | Optional message/reason | -| `beneficiaries` | `vector` | yes | Optional beneficiaries | - -### JSON Example - -```json -[60, { - "initiator": "alice", - "receiver": "bob", - "reward_amount": "10.000000 SHARES", - "max_energy": 5000, - "custom_sequence": 1, - "memo": "fixed reward", - "beneficiaries": [ - {"account": "charlie", "weight": 1000} - ] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'fixed_award_operation', - 'value' => [ - 'initiator' => 'alice', - 'receiver' => 'bob', - 'reward_amount' => '10.000000 SHARES', - 'max_energy' => 5000, - 'custom_sequence' => 1, - 'memo' => 'fixed reward', - 'beneficiaries' => [ - ['account' => 'charlie', 'weight' => 1000], - ], - ], -]; -``` - -### Node.js Example - -```js -const op = ['fixed_award', { - initiator: 'alice', - receiver: 'bob', - reward_amount: '10.000000 SHARES', - max_energy: 5000, - custom_sequence: 1, - memo: 'fixed reward', - beneficiaries: [ - { account: 'charlie', weight: 1000 }, - ], -}]; -``` - -### Checklist -- [ ] `reward_amount.symbol` must be `SHARES` -- [ ] `reward_amount.amount` must be > 0 -- [ ] `max_energy` = 0 means no energy cap (spend as much as needed) -- [ ] `max_energy` = 1–10000 limits maximum energy expenditure -- [ ] Actual energy spent depends on initiator's stake and current reward pool -- [ ] Beneficiary weights sum must be <= 10000 (100%) -- [ ] Beneficiaries list must be sorted by account name ascending -- [ ] Sign with `initiator`'s regular key -- [ ] Virtual `receive_award_operation` fires for `receiver` -- [ ] Virtual `benefactor_award_operation` fires for each beneficiary diff --git a/.qoder/docs/op-committee.md b/.qoder/docs/op-committee.md deleted file mode 100644 index 2f4c18191c..0000000000 --- a/.qoder/docs/op-committee.md +++ /dev/null @@ -1,193 +0,0 @@ -# VIZ Blockchain — Committee Operations - -Spec for implementing committee (worker proposal) operations in PHP/Node.js libraries. - -The committee mechanism allows community governance: anyone can create worker requests for funding, and VIZ SHARES holders vote to approve or reject them. - ---- - -## `committee_worker_create_request_operation` - -**Type ID:** `35` -**Required authority:** `regular` of `creator` - -Creates a new committee worker request (funding proposal). - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `creator` | `account_name_type` | yes | Account creating the request | -| `url` | `string` | yes | URL describing the work/proposal | -| `worker` | `account_name_type` | yes | Account that will receive the payout | -| `required_amount_min` | `asset` (VIZ) | yes | Minimum acceptable payout | -| `required_amount_max` | `asset` (VIZ) | yes | Maximum acceptable payout | -| `duration` | `uint32_t` | yes | Request duration in seconds | - -### Constraints - -| Parameter | Value | Description | -|---|---|---| -| `COMMITTEE_MIN_DURATION` | 5 days | Minimum duration | -| `COMMITTEE_MAX_DURATION` | 30 days | Maximum duration | -| `COMMITTEE_MAX_REQUIRED_AMOUNT` | chain configured | Max tokens per request | - -### JSON Example - -```json -[35, { - "creator": "alice", - "url": "https://alice.example.com/proposal", - "worker": "alice", - "required_amount_min": "100.000 VIZ", - "required_amount_max": "500.000 VIZ", - "duration": 604800 -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'committee_worker_create_request_operation', - 'value' => [ - 'creator' => 'alice', - 'url' => 'https://alice.example.com/proposal', - 'worker' => 'alice', - 'required_amount_min' => '100.000 VIZ', - 'required_amount_max' => '500.000 VIZ', - 'duration' => 604800, - ], -]; -``` - -### Node.js Example - -```js -const op = ['committee_worker_create_request', { - creator: 'alice', - url: 'https://alice.example.com/proposal', - worker: 'alice', - required_amount_min: '100.000 VIZ', - required_amount_max: '500.000 VIZ', - duration: 604800, -}]; -``` - -### Checklist -- [ ] `url.size()` must be > 0 and < 256 characters -- [ ] `required_amount_min.symbol` must be `VIZ` -- [ ] `required_amount_max.symbol` must be `VIZ` -- [ ] `required_amount_min.amount` >= 0 -- [ ] `required_amount_max.amount` > `required_amount_min.amount` -- [ ] `duration` in range `[COMMITTEE_MIN_DURATION, COMMITTEE_MAX_DURATION]` -- [ ] Fee (`committee_create_request_fee`) is charged to creator -- [ ] Sign with `creator`'s regular key - ---- - -## `committee_worker_cancel_request_operation` - -**Type ID:** `36` -**Required authority:** `regular` of `creator` - -Cancels an existing committee worker request before it expires. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `creator` | `account_name_type` | yes | Creator of the request | -| `request_id` | `uint32_t` | yes | ID of the request to cancel | - -### JSON Example - -```json -[36, { - "creator": "alice", - "request_id": 42 -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'committee_worker_cancel_request_operation', - 'value' => [ - 'creator' => 'alice', - 'request_id' => 42, - ], -]; -``` - -### Node.js Example - -```js -const op = ['committee_worker_cancel_request', { - creator: 'alice', - request_id: 42, -}]; -``` - -### Checklist -- [ ] Only the `creator` of the request can cancel it -- [ ] `request_id` must refer to an existing active request -- [ ] Sign with `creator`'s regular key - ---- - -## `committee_vote_request_operation` - -**Type ID:** `37` -**Required authority:** `regular` of `voter` - -Votes on a committee worker request. Positive = support, negative = oppose. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `voter` | `account_name_type` | yes | Account casting the vote | -| `request_id` | `uint32_t` | yes | ID of the request to vote on | -| `vote_percent` | `int16_t` | yes | Vote weight (-10000 to 10000) | - -### JSON Example - -```json -[37, { - "voter": "bob", - "request_id": 42, - "vote_percent": 10000 -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'committee_vote_request_operation', - 'value' => [ - 'voter' => 'bob', - 'request_id' => 42, - 'vote_percent' => 10000, - ], -]; -``` - -### Node.js Example - -```js -const op = ['committee_vote_request', { - voter: 'bob', - request_id: 42, - vote_percent: 10000, -}]; -``` - -### Checklist -- [ ] `vote_percent` range: -10000 (strong oppose) to 10000 (strong support) -- [ ] `vote_percent == 0` removes vote -- [ ] Voting power weighted by voter's SHARES -- [ ] Request is approved when net vote percent >= `committee_request_approve_min_percent` -- [ ] Sign with `voter`'s regular key diff --git a/.qoder/docs/op-content.md b/.qoder/docs/op-content.md deleted file mode 100644 index 8229f47611..0000000000 --- a/.qoder/docs/op-content.md +++ /dev/null @@ -1,157 +0,0 @@ -# VIZ Blockchain — Content & Custom Operations - -Spec for implementing content and custom operations in PHP/Node.js libraries. - -> **Note:** `vote_operation` (ID 0), `content_operation` (ID 1), and `delete_content_operation` (ID 9) are **deprecated**. They remain in the operation variant for historical compatibility but should not be used in new code. Shown here for completeness. - ---- - -## `content_operation` *(deprecated)* - -**Type ID:** `1` -**Required authority:** `regular` of `author` - -Creates or updates content (post or comment). - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `parent_author` | `account_name_type` | yes | Author of parent content (empty `""` for root post) | -| `parent_permlink` | `string` | yes | Permlink of parent (category/tag for root posts) | -| `author` | `account_name_type` | yes | Content author | -| `permlink` | `string` | yes | Unique identifier per author | -| `title` | `string` | yes | Post title | -| `body` | `string` | yes | Post body (Markdown) | -| `curation_percent` | `int16_t` | yes | Curation reward share in basis points (0–10000) | -| `json_metadata` | `string` | yes | JSON metadata | -| `extensions` | `content_extensions_type` | yes | Optional beneficiaries | - -### Beneficiaries Extension - -To add beneficiaries, add to `extensions`: -```json -[ - [0, { - "beneficiaries": [ - {"account": "bob", "weight": 2500} - ] - }] -] -``` - -### Checklist -- [ ] `permlink` must be unique per author -- [ ] `parent_author == ""` → root post; otherwise comment -- [ ] `curation_percent` range 0–10000 (must be within chain min/max) -- [ ] Beneficiary weights sum must be <= 10000 (100%) -- [ ] Beneficiaries list must be sorted by account name ascending -- [ ] **Deprecated** — avoid creating new content with this operation - ---- - -## `vote_operation` *(deprecated)* - -**Type ID:** `0` -**Required authority:** `regular` of `voter` - -Casts a vote on content. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `voter` | `account_name_type` | yes | Voting account | -| `author` | `account_name_type` | yes | Content author | -| `permlink` | `string` | yes | Content permlink | -| `weight` | `int16_t` | yes | Vote weight (-10000 to 10000) | - -### Checklist -- [ ] `weight` > 0 → upvote; `weight` < 0 → flag/downvote -- [ ] `weight == 0` → remove vote -- [ ] Flag votes may cost extra energy (see `flag_energy_additional_cost` chain property) -- [ ] **Deprecated** — avoid in new code - ---- - -## `delete_content_operation` *(deprecated)* - -**Type ID:** `9` -**Required authority:** `regular` of `author` - -Deletes a piece of content. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `author` | `account_name_type` | yes | Content author | -| `permlink` | `string` | yes | Content permlink to delete | - -### Checklist -- [ ] Content must have no pending payout to be deletable -- [ ] **Deprecated** — avoid in new code - ---- - -## `custom_operation` - -**Type ID:** `10` -**Required authority:** `active` or `regular` of signers - -Posts arbitrary JSON data to the blockchain. Used by applications for custom logic/protocols. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `required_active_auths` | `flat_set` | yes | Accounts requiring active auth | -| `required_regular_auths` | `flat_set` | yes | Accounts requiring regular auth | -| `id` | `string` | yes | Application-defined ID (max 32 characters) | -| `json` | `string` | yes | Valid UTF-8 JSON string | - -### JSON Example - -```json -[10, { - "required_active_auths": [], - "required_regular_auths": ["alice"], - "id": "my_app", - "json": "{\"action\":\"follow\",\"target\":\"bob\"}" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'custom_operation', - 'value' => [ - 'required_active_auths' => [], - 'required_regular_auths' => ['alice'], - 'id' => 'my_app', - 'json' => json_encode(['action' => 'follow', 'target' => 'bob']), - ], -]; -``` - -### Node.js Example - -```js -const op = ['custom', { - required_active_auths: [], - required_regular_auths: ['alice'], - id: 'my_app', - json: JSON.stringify({ action: 'follow', target: 'bob' }), -}]; -``` - -### Checklist -- [ ] `id` must be <= 32 characters -- [ ] `json` must be valid UTF-8 JSON -- [ ] At least one of `required_active_auths` or `required_regular_auths` must be non-empty -- [ ] `required_active_auths` entries → sign with those accounts' active keys -- [ ] `required_regular_auths` entries → sign with those accounts' regular keys -- [ ] Both `required_active_auths` and `required_regular_auths` may be populated simultaneously -- [ ] Data operations may cost additional bandwidth (see `data_operations_cost_additional_bandwidth`) -- [ ] `json` field is considered a "data operation" for bandwidth purposes diff --git a/.qoder/docs/op-escrow.md b/.qoder/docs/op-escrow.md deleted file mode 100644 index 26e99f18df..0000000000 --- a/.qoder/docs/op-escrow.md +++ /dev/null @@ -1,224 +0,0 @@ -# VIZ Blockchain — Escrow Operations - -Spec for implementing escrow-related operations in PHP/Node.js libraries. - -Escrow allows conditional transfers: funds are held in escrow until approved by both parties, or resolved by an agent in case of dispute. - ---- - -## Escrow Flow - -``` -escrow_transfer → escrow_approve (by agent & to) - → [escrow_dispute] → escrow_release (by agent) - → escrow_release (by from or to) - (expire) → expire_escrow_ratification_operation [virtual] -``` - ---- - -## `escrow_transfer_operation` - -**Type ID:** `15` -**Required authority:** `active` of `from` - -Creates an escrow transfer proposal. Funds leave `from` into escrow balance. Both `agent` and `to` must approve before funds can be released. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Sender | -| `to` | `account_name_type` | yes | Intended recipient | -| `agent` | `account_name_type` | yes | Escrow agent (arbitrator) | -| `escrow_id` | `uint32_t` | yes | Unique ID (chosen by sender), default 30 | -| `token_amount` | `asset` (VIZ) | yes | Amount held in escrow | -| `fee` | `asset` (VIZ) | yes | Agent fee (paid on approval) | -| `ratification_deadline` | `time_point_sec` | yes | Deadline for agent & to to approve | -| `escrow_expiration` | `time_point_sec` | yes | When escrow expires if not released | -| `json_metadata` | `string` | yes | Optional metadata / terms | - -### JSON Example - -```json -[15, { - "from": "alice", - "to": "bob", - "agent": "charlie", - "escrow_id": 1001, - "token_amount": "100.000 VIZ", - "fee": "1.000 VIZ", - "ratification_deadline": "2024-06-01T00:00:00", - "escrow_expiration": "2024-07-01T00:00:00", - "json_metadata": "{\"description\":\"payment for work\"}" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'escrow_transfer_operation', - 'value' => [ - 'from' => 'alice', - 'to' => 'bob', - 'agent' => 'charlie', - 'escrow_id' => 1001, - 'token_amount' => '100.000 VIZ', - 'fee' => '1.000 VIZ', - 'ratification_deadline' => '2024-06-01T00:00:00', - 'escrow_expiration' => '2024-07-01T00:00:00', - 'json_metadata' => json_encode(['description' => 'payment for work']), - ], -]; -``` - -### Node.js Example - -```js -const op = ['escrow_transfer', { - from: 'alice', - to: 'bob', - agent: 'charlie', - escrow_id: 1001, - token_amount: '100.000 VIZ', - fee: '1.000 VIZ', - ratification_deadline: '2024-06-01T00:00:00', - escrow_expiration: '2024-07-01T00:00:00', - json_metadata: JSON.stringify({ description: 'payment for work' }), -}]; -``` - -### Checklist -- [ ] `token_amount.symbol` must be `VIZ` -- [ ] `fee.symbol` must be `VIZ` -- [ ] `token_amount.amount` must be > 0 -- [ ] `ratification_deadline` must be before `escrow_expiration` -- [ ] Both deadlines must be in the future at time of broadcast -- [ ] `escrow_id` must be unique for the `from` account -- [ ] If not approved before `ratification_deadline`, virtual `expire_escrow_ratification_operation` fires and funds return -- [ ] Sign with `from`'s active key - ---- - -## `escrow_approve_operation` - -**Type ID:** `18` -**Required authority:** `active` of `who` - -Approves (or rejects) an escrow transfer. Both `to` and `agent` must approve. Once approved, approval cannot be revoked. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Original escrow sender | -| `to` | `account_name_type` | yes | Original escrow recipient | -| `agent` | `account_name_type` | yes | Escrow agent | -| `who` | `account_name_type` | yes | Who is approving (`to` or `agent`) | -| `escrow_id` | `uint32_t` | yes | Escrow ID | -| `approve` | `bool` | yes | `true` to approve, `false` to reject | - -### JSON Example - -```json -[18, { - "from": "alice", - "to": "bob", - "agent": "charlie", - "who": "bob", - "escrow_id": 1001, - "approve": true -}] -``` - -### Checklist -- [ ] `who` must be either `to` or `agent` -- [ ] Once approved, cannot be undone -- [ ] If `approve: false` → escrow is cancelled, funds returned to `from` -- [ ] Escrow is only active once both `to` and `agent` have approved -- [ ] Must be done before `ratification_deadline` -- [ ] Sign with `who`'s active key - ---- - -## `escrow_dispute_operation` - -**Type ID:** `16` -**Required authority:** `active` of `who` - -Raises a dispute on an approved escrow. Once disputed, only the `agent` can release funds. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Original escrow sender | -| `to` | `account_name_type` | yes | Original escrow recipient | -| `agent` | `account_name_type` | yes | Escrow agent | -| `who` | `account_name_type` | yes | Who is raising the dispute (`from` or `to`) | -| `escrow_id` | `uint32_t` | yes | Escrow ID | - -### JSON Example - -```json -[16, { - "from": "alice", - "to": "bob", - "agent": "charlie", - "who": "alice", - "escrow_id": 1001 -}] -``` - -### Checklist -- [ ] Dispute can only be raised on an **approved** escrow (both parties approved) -- [ ] Dispute can be raised before or on the `escrow_expiration` deadline -- [ ] `who` must be `from` or `to` -- [ ] Once disputed, only `agent` can release via `escrow_release_operation` -- [ ] Sign with `who`'s active key - ---- - -## `escrow_release_operation` - -**Type ID:** `17` -**Required authority:** `active` of `who` - -Releases escrow funds to `receiver`. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Original escrow sender | -| `to` | `account_name_type` | yes | Original escrow recipient | -| `agent` | `account_name_type` | yes | Escrow agent | -| `who` | `account_name_type` | yes | Account releasing funds | -| `receiver` | `account_name_type` | yes | Account that receives the funds | -| `escrow_id` | `uint32_t` | yes | Escrow ID | -| `token_amount` | `asset` (VIZ) | yes | Amount to release | - -### JSON Example - -```json -[17, { - "from": "alice", - "to": "bob", - "agent": "charlie", - "who": "alice", - "receiver": "bob", - "escrow_id": 1001, - "token_amount": "100.000 VIZ" -}] -``` - -### Checklist -- [ ] `token_amount.symbol` must be `VIZ` -- [ ] Release permission rules: - - No dispute, before expiration: `from` can release to `to`; `to` can release to `from` - - No dispute, after expiration: either party can release to either party - - Disputed: only `agent` can release to either party -- [ ] `receiver` must be `from` or `to` -- [ ] `token_amount` can be partial — remaining stays in escrow -- [ ] Sign with `who`'s active key diff --git a/.qoder/docs/op-invite.md b/.qoder/docs/op-invite.md deleted file mode 100644 index f73d3b93f9..0000000000 --- a/.qoder/docs/op-invite.md +++ /dev/null @@ -1,219 +0,0 @@ -# VIZ Blockchain — Invite Operations - -Spec for implementing invite-related operations in PHP/Node.js libraries. - -Invites allow existing VIZ users to onboard new users without requiring them to have an existing account. An invite is a one-time-use key with a VIZ balance. - ---- - -## `create_invite_operation` - -**Type ID:** `43` -**Required authority:** `active` of `creator` - -Creates an invite link by generating a key and funding it with VIZ tokens. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `creator` | `account_name_type` | yes | Account creating the invite | -| `balance` | `asset` (VIZ) | yes | Amount of VIZ to lock in the invite | -| `invite_key` | `public_key_type` | yes | Public key of the invite (secret = private key) | - -### JSON Example - -```json -[43, { - "creator": "alice", - "balance": "5.000 VIZ", - "invite_key": "VIZ5invite..." -}] -``` - -### PHP Example - -```php -// Generate invite key pair first: -// $privateKey = '...' // keep secret, share as invite link -// $publicKey = derived from privateKey - -$op = [ - 'type' => 'create_invite_operation', - 'value' => [ - 'creator' => 'alice', - 'balance' => '5.000 VIZ', - 'invite_key' => 'VIZ5invite...', - ], -]; -``` - -### Node.js Example - -```js -const op = ['create_invite', { - creator: 'alice', - balance: '5.000 VIZ', - invite_key: 'VIZ5invite...', -}]; -``` - -### Checklist -- [ ] `balance.symbol` must be `VIZ` -- [ ] `balance.amount` >= chain `create_invite_min_balance` property -- [ ] Generate a random secp256k1 key pair for the invite -- [ ] Private key = invite secret (share in invite link) -- [ ] Public key = `invite_key` field -- [ ] Sign with `creator`'s active key - ---- - -## `claim_invite_balance_operation` - -**Type ID:** `44` -**Required authority:** `active` of `initiator` - -Claims the VIZ balance from an invite, transferring it to `receiver`. The invite is consumed. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `initiator` | `account_name_type` | yes | Account claiming the invite | -| `receiver` | `account_name_type` | yes | Account to receive the VIZ balance | -| `invite_secret` | `string` | yes | WIF private key of the invite | - -### JSON Example - -```json -[44, { - "initiator": "bob", - "receiver": "bob", - "invite_secret": "5Ky1MXn..." -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'claim_invite_balance_operation', - 'value' => [ - 'initiator' => 'bob', - 'receiver' => 'bob', - 'invite_secret' => '5Ky1MXn...', - ], -]; -``` - -### Node.js Example - -```js -const op = ['claim_invite_balance', { - initiator: 'bob', - receiver: 'bob', - invite_secret: '5Ky1MXn...', -}]; -``` - -### Checklist -- [ ] `invite_secret` is the WIF (Wallet Import Format) private key of the invite -- [ ] `initiator` must be an existing account -- [ ] `receiver` may differ from `initiator` (can redirect balance to another account) -- [ ] Invite is consumed after claiming — cannot be reused -- [ ] Sign with `initiator`'s active key - ---- - -## `invite_registration_operation` - -**Type ID:** `45` -**Required authority:** `active` of `initiator` - -Uses an invite to create a new account. The invite balance is used to fund the new account. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `initiator` | `account_name_type` | yes | Existing account triggering registration | -| `new_account_name` | `account_name_type` | yes | Name for the new account | -| `invite_secret` | `string` | yes | WIF private key of the invite | -| `new_account_key` | `public_key_type` | yes | Master/active/regular/memo key for new account | - -### JSON Example - -```json -[45, { - "initiator": "bob", - "new_account_name": "carol", - "invite_secret": "5Ky1MXn...", - "new_account_key": "VIZ5newacct..." -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'invite_registration_operation', - 'value' => [ - 'initiator' => 'bob', - 'new_account_name' => 'carol', - 'invite_secret' => '5Ky1MXn...', - 'new_account_key' => 'VIZ5newacct...', - ], -]; -``` - -### Node.js Example - -```js -const op = ['invite_registration', { - initiator: 'bob', - new_account_name: 'carol', - invite_secret: '5Ky1MXn...', - new_account_key: 'VIZ5newacct...', -}]; -``` - -### Checklist -- [ ] `invite_secret` is the WIF private key of the invite -- [ ] `new_account_name` must pass account name validation -- [ ] `new_account_key` is set as all four keys (master, active, regular, memo) for the new account -- [ ] Invite balance is converted to SHARES for the new account -- [ ] Invite is consumed after use -- [ ] Sign with `initiator`'s active key - ---- - -## `use_invite_balance_operation` - -**Type ID:** `58` -**Required authority:** `active` of `initiator` - -Alternative to `claim_invite_balance_operation` — transfers invite balance to receiver. The difference from `claim_invite_balance_operation` is that this one may convert balance to SHARES. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `initiator` | `account_name_type` | yes | Account using the invite | -| `receiver` | `account_name_type` | yes | Account receiving the balance | -| `invite_secret` | `string` | yes | WIF private key of the invite | - -### JSON Example - -```json -[58, { - "initiator": "bob", - "receiver": "bob", - "invite_secret": "5Ky1MXn..." -}] -``` - -### Checklist -- [ ] `invite_secret` is the WIF private key -- [ ] `receiver` must be an existing account -- [ ] Invite is consumed after use -- [ ] Sign with `initiator`'s active key diff --git a/.qoder/docs/op-proposal.md b/.qoder/docs/op-proposal.md deleted file mode 100644 index c43d340e3c..0000000000 --- a/.qoder/docs/op-proposal.md +++ /dev/null @@ -1,229 +0,0 @@ -# VIZ Blockchain — Proposal Operations - -Spec for implementing multi-signature proposal operations in PHP/Node.js libraries. - -Proposals allow a group of accounts to jointly approve and execute a set of operations. Any account can create a proposal; signatories approve via `proposal_update_operation`. - ---- - -## `proposal_create_operation` - -**Type ID:** `22` -**Required authority:** `active` of `author` - -Creates a transaction proposal containing one or more operations that require multi-sig approval. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `author` | `account_name_type` | yes | Account creating the proposal | -| `title` | `string` | yes | Unique title per author (used as proposal ID) | -| `memo` | `string` | yes | Description of the proposal | -| `expiration_time` | `time_point_sec` | yes | Proposal expiration time | -| `proposed_operations` | `vector` | yes | Operations in the proposal | -| `review_period_time` | `optional` | no | Optional review period | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### `operation_wrapper` - -Each entry in `proposed_operations` is an `operation_wrapper`: -```json -{"op": [type_id, operation_object]} -``` - -### JSON Example - -```json -[22, { - "author": "alice", - "title": "transfer-proposal-001", - "memo": "Joint transfer to shared fund", - "expiration_time": "2024-12-31T23:59:59", - "proposed_operations": [ - { - "op": [2, { - "from": "multisig-wallet", - "to": "fund", - "amount": "1000.000 VIZ", - "memo": "" - }] - } - ], - "review_period_time": null, - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'proposal_create_operation', - 'value' => [ - 'author' => 'alice', - 'title' => 'transfer-proposal-001', - 'memo' => 'Joint transfer to shared fund', - 'expiration_time' => '2024-12-31T23:59:59', - 'proposed_operations' => [ - ['op' => [2, [ - 'from' => 'multisig-wallet', - 'to' => 'fund', - 'amount' => '1000.000 VIZ', - 'memo' => '', - ]]], - ], - 'review_period_time' => null, - 'extensions' => [], - ], -]; -``` - -### Node.js Example - -```js -const op = ['proposal_create', { - author: 'alice', - title: 'transfer-proposal-001', - memo: 'Joint transfer to shared fund', - expiration_time: '2024-12-31T23:59:59', - proposed_operations: [ - { op: ['transfer', { - from: 'multisig-wallet', - to: 'fund', - amount: '1000.000 VIZ', - memo: '', - }] }, - ], - review_period_time: null, - extensions: [], -}]; -``` - -### Checklist -- [ ] `title` must be unique per `author` (together they form the proposal ID) -- [ ] `expiration_time` must be in the future -- [ ] `review_period_time` if set, must be before `expiration_time` -- [ ] `proposed_operations` may contain multiple operations -- [ ] Operations inside a proposal follow the same rules as normal operations -- [ ] Sign with `author`'s active key - ---- - -## `proposal_update_operation` - -**Type ID:** `23` -**Required authority:** Depends on which approval sets are modified - -Adds or removes approvals from a proposal. Proposal executes automatically when enough approvals are collected. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `author` | `account_name_type` | yes | Author of the proposal | -| `title` | `string` | yes | Title of the proposal | -| `active_approvals_to_add` | `flat_set` | yes | Accounts adding active approval | -| `active_approvals_to_remove` | `flat_set` | yes | Accounts removing active approval | -| `master_approvals_to_add` | `flat_set` | yes | Accounts adding master approval | -| `master_approvals_to_remove` | `flat_set` | yes | Accounts removing master approval | -| `regular_approvals_to_add` | `flat_set` | yes | Accounts adding regular approval | -| `regular_approvals_to_remove` | `flat_set` | yes | Accounts removing regular approval | -| `key_approvals_to_add` | `flat_set` | yes | Keys adding approval | -| `key_approvals_to_remove` | `flat_set` | yes | Keys removing approval | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[23, { - "author": "alice", - "title": "transfer-proposal-001", - "active_approvals_to_add": ["bob"], - "active_approvals_to_remove": [], - "master_approvals_to_add": [], - "master_approvals_to_remove": [], - "regular_approvals_to_add": [], - "regular_approvals_to_remove": [], - "key_approvals_to_add": [], - "key_approvals_to_remove": [], - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'proposal_update_operation', - 'value' => [ - 'author' => 'alice', - 'title' => 'transfer-proposal-001', - 'active_approvals_to_add' => ['bob'], - 'active_approvals_to_remove'=> [], - 'master_approvals_to_add' => [], - 'master_approvals_to_remove'=> [], - 'regular_approvals_to_add' => [], - 'regular_approvals_to_remove'=> [], - 'key_approvals_to_add' => [], - 'key_approvals_to_remove' => [], - 'extensions' => [], - ], -]; -``` - -### Checklist -- [ ] Transaction must be signed by keys satisfying the authorities being added/removed -- [ ] If proposal requires only active authority, do NOT add master authority -- [ ] If both master and active are required, only master can approve -- [ ] Proposal executes automatically when approval threshold is reached -- [ ] After successful execution, proposal is resolved and further updates are rejected -- [ ] All `*_to_add` and `*_to_remove` arrays default to `[]` if not needed - ---- - -## `proposal_delete_operation` - -**Type ID:** `24` -**Required authority:** `active` of `requester` - -Vetoes and permanently deletes a proposal. Can be done by any required authority. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `author` | `account_name_type` | yes | Author of the proposal | -| `title` | `string` | yes | Title of the proposal | -| `requester` | `account_name_type` | yes | Account requesting deletion | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[24, { - "author": "alice", - "title": "transfer-proposal-001", - "requester": "bob", - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'proposal_delete_operation', - 'value' => [ - 'author' => 'alice', - 'title' => 'transfer-proposal-001', - 'requester' => 'bob', - 'extensions' => [], - ], -]; -``` - -### Checklist -- [ ] `requester` must be a required authority on the proposal -- [ ] Permanently removes the proposal — cannot be undone -- [ ] Sign with `requester`'s active key diff --git a/.qoder/docs/op-recovery.md b/.qoder/docs/op-recovery.md deleted file mode 100644 index 8c9c279161..0000000000 --- a/.qoder/docs/op-recovery.md +++ /dev/null @@ -1,188 +0,0 @@ -# VIZ Blockchain — Account Recovery Operations - -Spec for implementing account recovery operations in PHP/Node.js libraries. - -The recovery mechanism allows a trusted recovery account to help restore access to a compromised account using a previous valid master authority. - ---- - -## Recovery Flow - -``` -request_account_recovery → recover_account (within 24 hours) -change_recovery_account (30-day delay) -``` - ---- - -## `request_account_recovery_operation` - -**Type ID:** `12` -**Required authority:** `active` of `recovery_account` - -Initiates an account recovery request. The recovery account proposes a new master authority for the compromised account. The account holder has 24 hours to confirm. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `recovery_account` | `account_name_type` | yes | The trusted recovery account | -| `account_to_recover` | `account_name_type` | yes | Compromised account to recover | -| `new_master_authority` | `authority` | yes | The new master authority to assign | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[12, { - "recovery_account": "recover-service", - "account_to_recover": "alice", - "new_master_authority": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5newkey...", 1]] - }, - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'request_account_recovery_operation', - 'value' => [ - 'recovery_account' => 'recover-service', - 'account_to_recover' => 'alice', - 'new_master_authority' => [ - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [['VIZ5newkey...', 1]], - ], - 'extensions' => [], - ], -]; -``` - -### Node.js Example - -```js -const op = ['request_account_recovery', { - recovery_account: 'recover-service', - account_to_recover: 'alice', - new_master_authority: { - weight_threshold: 1, - account_auths: [], - key_auths: [['VIZ5newkey...', 1]], - }, - extensions: [], -}]; -``` - -### Checklist -- [ ] Only the listed recovery account of `account_to_recover` can send this -- [ ] Only one active recovery request per account at any time -- [ ] Sending again updates the request to a new authority and resets the 24h timer -- [ ] To cancel: set `new_master_authority.weight_threshold` to `0` -- [ ] Sign with `recovery_account`'s active key - ---- - -## `recover_account_operation` - -**Type ID:** `13` -**Required authority:** Both `new_master_authority` AND `recent_master_authority` signatures - -Confirms account recovery. The account holder proves past ownership via a recent master authority, and takes the new master authority. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account_to_recover` | `account_name_type` | yes | Account being recovered | -| `new_master_authority` | `authority` | yes | New master authority (must match recovery request) | -| `recent_master_authority` | `authority` | yes | A previous valid master authority (within last 30 days) | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[13, { - "account_to_recover": "alice", - "new_master_authority": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5newkey...", 1]] - }, - "recent_master_authority": { - "weight_threshold": 1, - "account_auths": [], - "key_auths": [["VIZ5oldkey...", 1]] - }, - "extensions": [] -}] -``` - -### Checklist -- [ ] Must be broadcast within 24 hours of the recovery request -- [ ] `new_master_authority` must exactly match the one in the recovery request -- [ ] `recent_master_authority` must have been valid in the past 30 days -- [ ] Transaction must be signed by keys satisfying **both** authorities -- [ ] After recovery, the old master key is invalidated - ---- - -## `change_recovery_account_operation` - -**Type ID:** `14` -**Required authority:** `master` of `account_to_recover` - -Changes the recovery account for an account. Takes effect after a 30-day delay. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account_to_recover` | `account_name_type` | yes | Account changing its recovery account | -| `new_recovery_account` | `account_name_type` | yes | New recovery account name | -| `extensions` | `extensions_type` | yes | Always `[]` | - -### JSON Example - -```json -[14, { - "account_to_recover": "alice", - "new_recovery_account": "new-recovery-service", - "extensions": [] -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'change_recovery_account_operation', - 'value' => [ - 'account_to_recover' => 'alice', - 'new_recovery_account' => 'new-recovery-service', - 'extensions' => [], - ], -]; -``` - -### Node.js Example - -```js -const op = ['change_recovery_account', { - account_to_recover: 'alice', - new_recovery_account: 'new-recovery-service', - extensions: [], -}]; -``` - -### Checklist -- [ ] 30-day delay between submitting the change and it taking effect -- [ ] This prevents attackers from changing the recovery account during an active attack -- [ ] `new_recovery_account` must be an existing account -- [ ] If `new_recovery_account == ""`, top-voted validator becomes recovery account -- [ ] Sign with `account_to_recover`'s master key diff --git a/.qoder/docs/op-subscription.md b/.qoder/docs/op-subscription.md deleted file mode 100644 index e274ac9ab4..0000000000 --- a/.qoder/docs/op-subscription.md +++ /dev/null @@ -1,146 +0,0 @@ -# VIZ Blockchain — Paid Subscription Operations - -Spec for implementing paid subscription operations in PHP/Node.js libraries. - -Paid subscriptions allow accounts to offer tiered subscription services payable in VIZ tokens, with optional auto-renewal. - ---- - -## `set_paid_subscription_operation` - -**Type ID:** `50` -**Required authority:** `active` of `account` - -Creates or updates a paid subscription offering for an account. Subscribers can then subscribe via `paid_subscribe_operation`. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account offering the subscription | -| `url` | `string` | yes | URL with subscription details | -| `levels` | `uint16_t` | yes | Number of subscription tiers (1–N) | -| `amount` | `asset` (VIZ) | yes | Price per period per unit level | -| `period` | `uint16_t` | yes | Subscription period in days | - -### JSON Example - -```json -[50, { - "account": "alice", - "url": "https://alice.example.com/subscribe", - "levels": 3, - "amount": "10.000 VIZ", - "period": 30 -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'set_paid_subscription_operation', - 'value' => [ - 'account' => 'alice', - 'url' => 'https://alice.example.com/subscribe', - 'levels' => 3, - 'amount' => '10.000 VIZ', - 'period' => 30, - ], -]; -``` - -### Node.js Example - -```js -const op = ['set_paid_subscription', { - account: 'alice', - url: 'https://alice.example.com/subscribe', - levels: 3, - amount: '10.000 VIZ', - period: 30, -}]; -``` - -### Checklist -- [ ] `amount.symbol` must be `VIZ` -- [ ] `amount.amount` must be > 0 -- [ ] `levels` must be >= 1 -- [ ] `period` must be >= 1 (days) -- [ ] Fee (`create_paid_subscription_fee`) charged on first creation -- [ ] Actual subscription cost = `amount * level` per period -- [ ] Sign with `account`'s active key - ---- - -## `paid_subscribe_operation` - -**Type ID:** `51` -**Required authority:** `active` of `subscriber` - -Subscribes to or renews a paid subscription. Tokens are transferred from `subscriber` to `account`. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `subscriber` | `account_name_type` | yes | Subscribing account | -| `account` | `account_name_type` | yes | Account offering the subscription | -| `level` | `uint16_t` | yes | Subscription tier (1–max_levels) | -| `amount` | `asset` (VIZ) | yes | Payment amount | -| `period` | `uint16_t` | yes | Number of periods to subscribe | -| `auto_renewal` | `bool` | yes | Whether to auto-renew | - -### JSON Example - -```json -[51, { - "subscriber": "bob", - "account": "alice", - "level": 2, - "amount": "20.000 VIZ", - "period": 1, - "auto_renewal": true -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'paid_subscribe_operation', - 'value' => [ - 'subscriber' => 'bob', - 'account' => 'alice', - 'level' => 2, - 'amount' => '20.000 VIZ', - 'period' => 1, - 'auto_renewal' => true, - ], -]; -``` - -### Node.js Example - -```js -const op = ['paid_subscribe', { - subscriber: 'bob', - account: 'alice', - level: 2, - amount: '20.000 VIZ', - period: 1, - auto_renewal: true, -}]; -``` - -### Checklist -- [ ] `amount.symbol` must be `VIZ` -- [ ] `amount` must match `subscription_amount * level * period` -- [ ] `level` must be in range [1, subscription.levels] -- [ ] `period` >= 1 -- [ ] `auto_renewal: true` → tokens deducted automatically each period -- [ ] `auto_renewal: false` → one-time subscription -- [ ] If already subscribed: upgrading level requires matching payment for remaining time difference -- [ ] Virtual `paid_subscription_action_operation` fires on payment -- [ ] Virtual `cancel_paid_subscription_operation` fires on cancellation/expiry -- [ ] Sign with `subscriber`'s active key diff --git a/.qoder/docs/op-transfer-vesting.md b/.qoder/docs/op-transfer-vesting.md deleted file mode 100644 index fcee224f73..0000000000 --- a/.qoder/docs/op-transfer-vesting.md +++ /dev/null @@ -1,224 +0,0 @@ -# VIZ Blockchain — Transfer & Vesting Operations - -Spec for implementing transfer and vesting-related operations in PHP/Node.js libraries. - ---- - -## `transfer_operation` - -**Type ID:** `2` -**Required authority:** `active` of `from` (for VIZ tokens), `master` of `from` (for SHARES) - -Transfers tokens (VIZ or SHARES) from one account to another. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Sending account | -| `to` | `account_name_type` | yes | Receiving account | -| `amount` | `asset` | yes | Amount to transfer (VIZ or SHARES) | -| `memo` | `string` | yes | Optional memo (plain text or encrypted) | - -### JSON Example - -```json -[2, { - "from": "alice", - "to": "bob", - "amount": "10.000 VIZ", - "memo": "payment for services" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'transfer_operation', - 'value' => [ - 'from' => 'alice', - 'to' => 'bob', - 'amount' => '10.000 VIZ', - 'memo' => 'payment for services', - ], -]; -``` - -### Node.js Example - -```js -const op = ['transfer', { - from: 'alice', - to: 'bob', - amount: '10.000 VIZ', - memo: 'payment for services', -}]; -``` - -### Checklist -- [ ] `amount.symbol` must be `VIZ` or `SHARES` -- [ ] If `amount.symbol == SHARES` → sign with **master** key -- [ ] If `amount.symbol == VIZ` → sign with **active** key -- [ ] `amount.amount` must be > 0 -- [ ] `memo` may be empty string `""` -- [ ] Encrypted memo format starts with `#` followed by base58 ciphertext - ---- - -## `transfer_to_vesting_operation` - -**Type ID:** `3` -**Required authority:** `active` of `from` - -Converts liquid VIZ tokens into SHARES (staking/vesting). Can vest into another account's balance. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from` | `account_name_type` | yes | Account providing VIZ | -| `to` | `account_name_type` | yes | Account receiving SHARES (same as `from` if empty) | -| `amount` | `asset` (VIZ) | yes | Amount of VIZ to convert to SHARES | - -### JSON Example - -```json -[3, { - "from": "alice", - "to": "alice", - "amount": "100.000 VIZ" -}] -``` - -### Checklist -- [ ] `amount.symbol` must be `VIZ` -- [ ] `amount.amount` must be > 0 -- [ ] `to` can equal `from` (self-vesting) or be a different account -- [ ] Sign with `from`'s active key - ---- - -## `withdraw_vesting_operation` - -**Type ID:** `4` -**Required authority:** `active` of `account` - -Initiates a vesting withdrawal — schedules gradual conversion of SHARES back to VIZ over multiple intervals. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account initiating withdrawal | -| `vesting_shares` | `asset` (SHARES) | yes | Total SHARES to withdraw (0 to cancel) | - -### JSON Example - -```json -[4, { - "account": "alice", - "vesting_shares": "1000.000000 SHARES" -}] -``` - -### Checklist -- [ ] `vesting_shares.symbol` must be `SHARES` -- [ ] Set `vesting_shares` to `"0.000000 SHARES"` to **cancel** an active withdrawal -- [ ] Withdrawal is spread over `withdraw_intervals` intervals (default 28 days) -- [ ] Each interval: `vesting_shares / withdraw_intervals` SHARES are withdrawn -- [ ] Sign with `account`'s active key - ---- - -## `set_withdraw_vesting_route_operation` - -**Type ID:** `11` -**Required authority:** `active` of `from_account` - -Routes a percentage of vesting withdrawals to another account (optionally re-vesting immediately). - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `from_account` | `account_name_type` | yes | Account whose withdrawals are being routed | -| `to_account` | `account_name_type` | yes | Account receiving routed funds | -| `percent` | `uint16_t` | yes | Percentage to route (0–10000, basis points) | -| `auto_vest` | `bool` | yes | If true, immediately re-vest the routed tokens | - -### JSON Example - -```json -[11, { - "from_account": "alice", - "to_account": "bob", - "percent": 5000, - "auto_vest": false -}] -``` - -### Checklist -- [ ] `percent` range: 0 (remove route) to 10000 (100%) -- [ ] Multiple routes allowed, but total percent across all routes must be <= 10000 -- [ ] `auto_vest: true` means Bob receives SHARES, not VIZ -- [ ] Set `percent: 0` to delete the route to `to_account` -- [ ] Sign with `from_account`'s active key - ---- - -## `delegate_vesting_shares_operation` - -**Type ID:** `19` -**Required authority:** `active` of `delegator` - -Delegates SHARES from one account to another. The delegator retains ownership but the delegatee gains bandwidth and voting power. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `delegator` | `account_name_type` | yes | Account delegating SHARES | -| `delegatee` | `account_name_type` | yes | Account receiving delegation | -| `vesting_shares` | `asset` (SHARES) | yes | Amount to delegate (0 removes delegation) | - -### JSON Example - -```json -[19, { - "delegator": "alice", - "delegatee": "bob", - "vesting_shares": "500.000000 SHARES" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'delegate_vesting_shares_operation', - 'value' => [ - 'delegator' => 'alice', - 'delegatee' => 'bob', - 'vesting_shares' => '500.000000 SHARES', - ], -]; -``` - -### Node.js Example - -```js -const op = ['delegate_vesting_shares', { - delegator: 'alice', - delegatee: 'bob', - vesting_shares: '500.000000 SHARES', -}]; -``` - -### Checklist -- [ ] `vesting_shares.symbol` must be `SHARES` -- [ ] Set `vesting_shares` to `"0.000000 SHARES"` to **remove** delegation -- [ ] `vesting_shares` must be >= chain `min_delegation` property (unless 0) -- [ ] When delegation is removed, SHARES enter a 1-week limbo period before returning -- [ ] Virtual operation `return_vesting_delegation_operation` fires when limbo period ends -- [ ] Sign with `delegator`'s active key diff --git a/.qoder/docs/op-validator.md b/.qoder/docs/op-validator.md deleted file mode 100644 index 8849d2ed59..0000000000 --- a/.qoder/docs/op-validator.md +++ /dev/null @@ -1,252 +0,0 @@ -# VIZ Blockchain — validator Operations - -Spec for implementing validator-related operations in PHP/Node.js libraries. - ---- - -## `witness_update_operation` - -**Type ID:** `6` -**Required authority:** `active` of `owner` - -Registers or updates a validator. Setting `block_signing_key` to the null key removes the validator from block production contention. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `owner` | `account_name_type` | yes | validator account name | -| `url` | `string` | yes | validator website or info URL | -| `block_signing_key` | `public_key_type` | yes | Key used to sign blocks (set to null key to deactivate) | - -**Null key** (deactivate validator): `"VIZ1111111111111111111111111111111114T1Anm"` - -### JSON Example - -```json -[6, { - "owner": "alice", - "url": "https://alice.example.com", - "block_signing_key": "VIZ5hqSa4NkEZGAMUpoH5EaEr64mBJuMcPpGjvk8qb7hcPFTbXSQ9" -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'witness_update_operation', - 'value' => [ - 'owner' => 'alice', - 'url' => 'https://alice.example.com', - 'block_signing_key' => 'VIZ5hq...', - ], -]; -``` - -### Node.js Example - -```js -const op = ['witness_update', { - owner: 'alice', - url: 'https://alice.example.com', - block_signing_key: 'VIZ5hq...', -}]; -``` - -### Checklist -- [ ] `block_signing_key` must be a valid VIZ public key or the null key -- [ ] Null key = `VIZ1111111111111111111111111111111114T1Anm` (deactivates validator) -- [ ] `url` must be non-empty and < `CHAIN_MAX_URL_LENGTH` (256) bytes -- [ ] Requires `witness_declaration_fee` paid to committee (see chain properties) -- [ ] Sign with `owner`'s active key - ---- - -## `chain_properties_update_operation` - -**Type ID:** `25` -**Required authority:** `active` of `owner` - -validator votes on base chain properties (`chain_properties_init` format only). Use `versioned_chain_properties_update_operation` for extended properties. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `owner` | `account_name_type` | yes | validator account voting | -| `props` | `chain_properties_init` | yes | Proposed chain properties | - -### JSON Example - -```json -[25, { - "owner": "alice", - "props": { - "account_creation_fee": "1.000 VIZ", - "maximum_block_size": 65536, - "create_account_delegation_ratio": 10, - "create_account_delegation_time": 2592000, - "min_delegation": "1.000 VIZ", - "min_curation_percent": 0, - "max_curation_percent": 10000, - "bandwidth_reserve_percent": 1000, - "bandwidth_reserve_below": "1.000000 SHARES", - "flag_energy_additional_cost": 1000, - "vote_accounting_min_rshares": 0, - "committee_request_approve_min_percent": 1000 - } -}] -``` - -### Checklist -- [ ] `account_creation_fee.symbol` must be `VIZ` -- [ ] `min_delegation.symbol` must be `VIZ` -- [ ] `bandwidth_reserve_below.symbol` must be `SHARES` -- [ ] `min_curation_percent` <= `max_curation_percent` -- [ ] All percent fields in basis points (0–10000) -- [ ] Median of all active validator values is used as actual chain property - ---- - -## `versioned_chain_properties_update_operation` - -**Type ID:** `46` -**Required authority:** `active` of `owner` - -validator votes on versioned chain properties (supports all hardfork extensions). - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `owner` | `account_name_type` | yes | validator account voting | -| `props` | `versioned_chain_properties` | yes | Versioned props variant | - -### JSON Example (using hf9 = index 3) - -```json -[46, { - "owner": "alice", - "props": [3, { - "account_creation_fee": "1.000 VIZ", - "maximum_block_size": 65536, - "create_account_delegation_ratio": 10, - "create_account_delegation_time": 2592000, - "min_delegation": "1.000 VIZ", - "min_curation_percent": 0, - "max_curation_percent": 10000, - "bandwidth_reserve_percent": 1000, - "bandwidth_reserve_below": "1.000000 SHARES", - "flag_energy_additional_cost": 1000, - "vote_accounting_min_rshares": 0, - "committee_request_approve_min_percent": 1000, - "inflation_witness_percent": 2000, - "inflation_ratio_committee_vs_reward_fund": 1000, - "inflation_recalc_period": 28800, - "data_operations_cost_additional_bandwidth": 0, - "witness_miss_penalty_percent": 100, - "witness_miss_penalty_duration": 86400, - "create_invite_min_balance": "1.000 VIZ", - "committee_create_request_fee": "1.000 VIZ", - "create_paid_subscription_fee": "1.000 VIZ", - "account_on_sale_fee": "10.000 VIZ", - "subaccount_on_sale_fee": "1.000 VIZ", - "witness_declaration_fee": "1.000 VIZ", - "withdraw_intervals": 28 - }] -}] -``` - -### Checklist -- [ ] `props` is serialized as a static_variant: `[index, object]` -- [ ] Use index `3` for `chain_properties_hf9` (current latest) -- [ ] See `data-types.md` for full field list per version - ---- - -## `account_witness_vote_operation` - -**Type ID:** `7` -**Required authority:** `active` of `account` - -Votes for or against a validator to be included in block production. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Voting account | -| `validator` | `account_name_type` | yes | validator to vote for/against | -| `approve` | `bool` | yes | `true` to add vote, `false` to remove vote | - -### JSON Example - -```json -[7, { - "account": "alice", - "validator": "bob", - "approve": true -}] -``` - -### PHP Example - -```php -$op = [ - 'type' => 'account_witness_vote_operation', - 'value' => [ - 'account' => 'alice', - 'validator' => 'bob', - 'approve' => true, - ], -]; -``` - -### Node.js Example - -```js -const op = ['account_witness_vote', { - account: 'alice', - validator: 'bob', - approve: true, -}]; -``` - -### Checklist -- [ ] Account must have SHARES to have meaningful voting weight -- [ ] `approve: false` removes a previously cast vote -- [ ] Top 21 validators by vote weight produce blocks -- [ ] Sign with `account`'s active key - ---- - -## `account_witness_proxy_operation` - -**Type ID:** `8` -**Required authority:** `active` of `account` - -Assigns a proxy account for validator voting. All existing votes are removed when a proxy is set. - -### Fields - -| Field | Type | Required | Description | -|---|---|---|---| -| `account` | `account_name_type` | yes | Account setting the proxy | -| `proxy` | `account_name_type` | yes | Proxy account (empty string `""` to remove proxy) | - -### JSON Example - -```json -[8, { - "account": "alice", - "proxy": "bob" -}] -``` - -### Checklist -- [ ] Setting `proxy` to `""` (empty string) removes the proxy -- [ ] Cannot set proxy to self -- [ ] Proxy chains are resolved (A→B→C); max depth is limited -- [ ] Setting a proxy removes all direct validator votes -- [ ] Sign with `account`'s active key diff --git a/.qoder/docs/p2p-messages.md b/.qoder/docs/p2p-messages.md deleted file mode 100644 index 334d9ee45f..0000000000 --- a/.qoder/docs/p2p-messages.md +++ /dev/null @@ -1,837 +0,0 @@ -# VIZ P2P Message Protocol Reference - -Complete reference for all P2P network message types, their structures, flow diagrams, and the transaction exchange pipeline through JSON-RPC, chain, and network broadcast plugins. - ---- - -## Overview - -The VIZ P2P network uses a binary protocol over TCP with ECDH key exchange. Messages are serialized using FC reflection. Each message carries a type tag (`core_message_type_enum`) used for dispatch. - -Messages fall into three categories: - -| Category | Range | Purpose | -|----------|-------|---------| -| Item messages | 1000-1099 | Block and transaction data payloads | -| Core protocol | 5000-5099 | Sync, handshake, peer discovery, diagnostics | -| Extension | 6000+ | Block post-validation | - -**Key files:** -- [core_messages.hpp](file:///d:/Work/viz-cpp-node/libraries/network/include/graphene/network/core_messages.hpp) — message type enum, all message structs, FC_REFLECT serialization -- [core_messages.cpp](file:///d:/Work/viz-cpp-node/libraries/network/core_messages.cpp) — static type constant definitions -- [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) — message dispatch, sync state machine, peer management -- [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) — bridge between P2P network and blockchain - ---- - -## Message Type Enum - -```cpp -// core_messages.hpp:72-95 -enum core_message_type_enum { - trx_message_type = 1000, - block_message_type = 1001, - - core_message_type_first = 5000, - item_ids_inventory_message_type = 5001, - blockchain_item_ids_inventory_message_type = 5002, - fetch_blockchain_item_ids_message_type = 5003, - fetch_items_message_type = 5004, - item_not_available_message_type = 5005, - hello_message_type = 5006, - connection_accepted_message_type = 5007, - connection_rejected_message_type = 5008, - address_request_message_type = 5009, - address_message_type = 5010, - closing_connection_message_type = 5011, - current_time_request_message_type = 5012, - current_time_reply_message_type = 5013, - check_firewall_message_type = 5014, - check_firewall_reply_message_type = 5015, - get_current_connections_request_message_type = 5016, - get_current_connections_reply_message_type = 5017, - chain_status_announcement_message_type = 5018, - core_message_type_last = 5018, - - block_post_validation_message_type = 6009, -}; -``` - ---- - -## Detailed Message Reference - -### 1000 — trx_message - -**Purpose:** Carries a signed transaction between peers. - -**Structure:** -```cpp -struct trx_message { - static const core_message_type_enum type; // = trx_message_type (1000) - signed_transaction trx; -}; -``` - -**FC_REFLECT:** `(trx)` - -**Dispatch path:** -1. [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `process_ordinary_message()` (line 5099) — checks `items_requested_from_peer` set -2. If `msg_type == trx_message_type`: calls `_delegate->handle_transaction(trx_msg)` -3. [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `handle_transaction()` (line 287) — calls `chain.accept_transaction(trx_msg.trx)` -4. On success: the message is broadcast to all other connected peers via `broadcast()` (node.cpp line 5146) - -**Usage sites:** -| Caller | File | Line | -|--------|------|------| -| JSON-RPC `broadcast_transaction` | [network_broadcast_api.cpp](file:///d:/Work/viz-cpp-node/plugins/network_broadcast_api/network_broadcast_api.cpp) | 50 | -| validator block production (contained txs) | [validator.cpp](file:///d:/Work/viz-cpp-node/plugins/validator/validator.cpp) | — | -| P2P relay (incoming tx → other peers) | [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) | 5146 | - ---- - -### 1001 — block_message - -**Purpose:** Carries a full signed block between peers. - -**Structure:** -```cpp -struct block_message { - static const core_message_type_enum type; // = block_message_type (1001) - signed_block block; - block_id_type block_id; // cached block.id() for quick ID lookup -}; -``` - -**FC_REFLECT:** `(block)(block_id)` - -**Dispatch path:** -1. [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `process_block_message()` (line 4773) — routes to sync or normal handler -2. Sync path: `process_block_during_sync()` → `send_sync_block_to_node_delegate()` → `_delegate->handle_block(blk_msg, sync_mode=true, ...)` -3. Normal path: `process_block_during_normal_operation()` → `_delegate->handle_block(blk_msg, sync_mode=false, ...)` -4. [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `handle_block()` (line 145) — calls `chain.accept_block(blk_msg.block, ...)` -5. On success: broadcast to other peers - -**DLT emergency near-caught-up logic** (p2p_plugin.cpp:219): When `sync_mode && gap <= 2 && dlt_mode && block_age < 30s`, treats the sync block as a normal block to avoid triggering "Syncing Blockchain started" and disrupting validator production. - -**Usage sites:** -| Caller | File | Line | -|--------|------|------| -| JSON-RPC `broadcast_block` | [network_broadcast_api.cpp](file:///d:/Work/viz-cpp-node/plugins/network_broadcast_api/network_broadcast_api.cpp) | 88 | -| validator block production | [validator.cpp](file:///d:/Work/viz-cpp-node/plugins/validator/validator.cpp) | — | -| P2P relay | [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) | 5146 | - ---- - -### 5001 — item_ids_inventory_message - -**Purpose:** Gossip advertisement. Tells a peer "I have these items available" so the peer can request them. - -This is the **push-based broadcast** mechanism — when a node receives a new block or transaction, it advertises it to all other connected peers (except the one it came from). - -**Structure:** -```cpp -struct item_ids_inventory_message { - static const core_message_type_enum type; // = 5001 - uint32_t item_type; // trx_message_type or block_message_type - std::vector item_hashes_available; -}; -``` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_item_ids_inventory_message()` (line 3339) - -**Gate conditions** (message is skipped if): -- `we_need_sync_items_from_peer == true` (we're syncing from this peer) -- Any peer has `we_need_sync_items_from_peer == true` (global sync in progress) -- Head block time is >30 seconds behind real time - -**Inventory Gate Deadlock Breaker** (node.cpp:3480-3513): If head is >30s behind AND no sync is in progress with ANY peer, triggers `start_synchronizing_with_peer()` to break the stalemate. - ---- - -### 5002 — blockchain_item_ids_inventory_message - -**Purpose:** Response to a `fetch_blockchain_item_ids_message`. Contains a sequential list of block IDs after the common ancestor point identified by the synopsis. Used in **pull-based sync mode**. - -**Structure:** -```cpp -struct blockchain_item_ids_inventory_message { - static const core_message_type_enum type; // = 5002 - uint32_t total_remaining_item_count; // how many more block IDs the peer has beyond this batch - uint32_t item_type; // always block_message_type - std::vector item_hashes_available; // sequential block IDs -}; -``` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_blockchain_item_ids_inventory_message()` (line 2787) - -**Validation:** Checks that IDs are sequential block numbers, links to the synopsis, and the first ID is in our fork history or synopsis. On failure → disconnects with "invalid response". - -**Done condition:** When `total_remaining_item_count == 0` and all items are already known, sets `we_need_sync_items_from_peer = false` (transitions to broadcast mode). - -**Server-side generation:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `get_block_ids()` (line 337) - ---- - -### 5003 — fetch_blockchain_item_ids_message - -**Purpose:** Request from a syncing node to a peer. Sends a "blockchain synopsis" (logarithmically-spaced block IDs from our chain) so the peer can find the most recent common block and respond with `blockchain_item_ids_inventory_message`. - -**Structure:** -```cpp -struct fetch_blockchain_item_ids_message { - static const core_message_type_enum type; // = 5003 - uint32_t item_type; // always block_message_type - std::vector blockchain_synopsis; -}; -``` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_fetch_blockchain_item_ids_message()` (line 2748) - -**Synopsis generation:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `get_blockchain_synopsis()` (line 568) - -**Synopsis format (logarithmic fall-off):** -- First entry: highest non-undoable block (LIB) -- Second: ~1/2 way through undoable segment -- Third: ~3/4 way through -- Fourth: ~7/8 way through -- Last: head block (guaranteed by post-loop guard) - ---- - -### 5004 — fetch_items_message - -**Purpose:** Request actual block or transaction data from a peer. Contains a list of item hashes to fetch. The peer responds with `block_message` or `trx_message` (one per item) or `item_not_available_message`. - -**Structure:** -```cpp -struct fetch_items_message { - static const core_message_type_enum type; // = 5004 - uint32_t item_type; - std::vector items_to_fetch; -}; -``` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_fetch_items_message()` - -**Server-side serving:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `get_item()` (line 528) — fetches block or transaction from chain database. - ---- - -### 5005 — item_not_available_message - -**Purpose:** Response when a peer requests an item we don't have. The requesting peer may soft-ban or apply a strike counter. - -**Structure:** -```cpp -struct item_not_available_message { - static const core_message_type_enum type; // = 5005 - item_id requested_item; // { item_type, item_hash } -}; -``` - ---- - -### 5006 — hello_message - -**Purpose:** Initial handshake message sent immediately after TCP connection. Exchanges node identity, protocol version, chain state, and capabilities. - -**Structure:** -```cpp -struct hello_message { - static const core_message_type_enum type; // = 5006 - std::string user_agent; - uint32_t core_protocol_version; - fc::ip::address inbound_address; - uint16_t inbound_port; - uint16_t outbound_port; - node_id_t node_public_key; - fc::ecc::compact_signature signed_shared_secret; - fc::variant_object user_data; // extensible key-value metadata -}; -``` - -**FC_REFLECT:** `(user_agent)(core_protocol_version)(inbound_address)(inbound_port)(outbound_port)(node_public_key)(signed_shared_secret)(user_data)` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_hello_message()` (line 2299) - -**user_data fields** (generated by `generate_hello_user_data()`, node.cpp:2231): - -| Key | Type | Description | -|-----|------|-------------| -| `fc_git_revision_sha` | string | FC library git revision | -| `fc_git_revision_unix_timestamp` | uint32 | FC library build timestamp | -| `platform` | string | `"osx"`, `"linux"`, `"win32"`, or `"other"` | -| `bitness` | uint32 | `32` or `64` | -| `node_id` | node_id_t | Node public key as hex | -| `last_known_block_hash` | block_id_type | Head block hash | -| `last_known_block_number` | uint32 | Head block number | -| `last_known_block_time` | time_point_sec | Head block timestamp | -| `last_known_fork_block_number` | uint32 | Latest hardfork block known to this node | -| `chain_id` | chain_id_type | Blockchain chain ID | -| `dlt_mode` | bool | Node is in DLT (rolling block log) mode | -| `dlt_earliest_block` | uint32 | Earliest available block in DLT window (only present if dlt_mode=true) | -| `emergency_consensus_active` | bool | Emergency consensus is active on this node | -| `has_emergency_key` | bool | Node holds the emergency committee private key (block_producer heuristic) | - -**Validation checks performed on hello:** -1. ECDH signature validation (line 2338) -2. Hardfork compatibility check (line 2353) -3. Chain ID match (line 2386) -4. Duplicate connection check (line 2407) - -**Rejection reasons** (`rejection_reason_code` enum): -- `unspecified` — generic -- `different_chain` — chain ID mismatch -- `already_connected` — duplicate node_id -- `connected_to_self` — connected to own node_id -- `not_accepting_connections` — node is full -- `blocked` — in allowed_peers list but blocked -- `invalid_hello_message` — signature validation failed -- `client_too_old` — hardfork version too old - ---- - -### 5007 — connection_accepted_message - -**Purpose:** Empty message sent by the receiving node to confirm it has accepted the hello handshake and the connection is fully established. - -**Structure:** -```cpp -struct connection_accepted_message { - static const core_message_type_enum type; // = 5007 - // empty -}; -``` - -**Handler:** [node.cpp](file:///d:/Work/viz-cpp-node/libraries/network/node.cpp) `on_connection_accepted_message()` (line 2502) - -Takes the peer from `peer_connection::their_connection_state::connection_accepted` to `connection_established`. Calls `new_peer_just_added()` which starts sync. - ---- - -### 5008 — connection_rejected_message - -**Purpose:** Sent when a node rejects the hello handshake. The connection is closed after this message. - -**Structure:** -```cpp -struct connection_rejected_message { - static const core_message_type_enum type; // = 5008 - std::string user_agent; - uint32_t core_protocol_version; - fc::ip::endpoint remote_endpoint; - std::string reason_string; - fc::enum_type reason_code; -}; -``` - ---- - -### 5009/5010 — address_request_message / address_message - -**Purpose:** Peer discovery. A node requests known peer addresses from a connected peer, and receives a list of `address_info` records. - -**address_info structure:** -```cpp -struct address_info { - fc::ip::endpoint remote_endpoint; - fc::time_point_sec last_seen_time; - fc::microseconds latency; - node_id_t node_id; - fc::enum_type direction; // unknown, inbound, outbound - fc::enum_type firewalled; // unknown, firewalled, not_firewalled -}; -``` - ---- - -### 5011 — closing_connection_message - -**Purpose:** Graceful disconnect. Sent before a peer closes the connection, with an optional reason. - -**Structure:** -```cpp -struct closing_connection_message { - static const core_message_type_enum type; // = 5011 - std::string reason_for_closing; - bool closing_due_to_error; - fc::oexception error; -}; -``` - ---- - -### 5012/5013 — current_time_request_message / current_time_reply_message - -**Purpose:** NTP-style clock synchronization. A node requests the peer's current time for clock offset calculation. - -**current_time_reply_message structure:** -```cpp -struct current_time_reply_message { - static const core_message_type_enum type; // = 5013 - fc::time_point request_sent_time; // our timestamp when we sent the request - fc::time_point request_received_time; // peer's timestamp when they received our request - fc::time_point reply_transmitted_time; // peer's timestamp when they sent the reply -}; -``` - -Clock offset is computed as: `((T2 - T1) + (T3 - T4)) / 2` (standard NTP formula). - -Sent on every new connection in `new_peer_just_added()` (node.cpp:5186). - ---- - -### 5014/5015 — check_firewall_message / check_firewall_reply_message - -**Purpose:** NAT/firewall detection. A node asks a peer to try connecting to a specified endpoint to test if the requesting node is reachable from the internet. - ---- - -### 5016/5017 — get_current_connections_request_message / get_current_connections_reply_message - -**Purpose:** Network diagnostics. Request a peer's list of current connections, upload/download rates. - ---- - -### 6009 — block_post_validation_message - -**Purpose:** Block signing validator verification (Hardfork 11+). Sent after a block is applied to confirm the signing validator identity. The receiving node validates the signature against the validator's signing key on-chain and triggers `apply_block_post_validation()`. - -**Structure:** -```cpp -struct block_post_validation_message { - static const core_message_type_enum type; // = 6009 - block_id_type block_id; - std::string witness_account; - signature_type witness_signature; -}; -``` - -**Handler:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `handle_message()` (line 304) - -**Validation:** Recovers the public key from the signature, compares against the validator's on-chain `signing_key`. If matched, calls `apply_block_post_validation()`. - -**Broadcast:** Sent by validators after producing a block. Also emitted via [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `broadcast_block_post_validation()` (line 1470). - ---- - -### 5018 — chain_status_announcement_message - -**Purpose:** Announces a node's chain state — head block, irreversible block, DLT mode window, and emergency consensus status — to all connected peers. Sent automatically when a new peer joins (via `connection_count_changed`) and can also be broadcast manually via `p2p_plugin::broadcast_chain_status()`. - -This message complements the hello handshake (5006): the hello provides a **snapshot** of chain state at connection time, while chain_status_announcement provides **live updates** when DLT window shifts or emergency consensus activates/deactivates during an ongoing connection. - -**Structure:** -```cpp -struct chain_status_announcement_message { - static const core_message_type_enum type; // = 5018 - - block_id_type head_block_id; // hash of our head block - uint32_t head_block_num; // height of our head block - uint32_t last_irreversible_block_num; // LIB height - bool dlt_mode; // true if rolling block log mode - uint32_t dlt_earliest_block; // lowest block number we can serve - bool emergency_consensus_active; // true if emergency consensus is on - bool has_emergency_key; // true if we hold committee private key -}; -``` - -**Handler:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `handle_message()` (line 326) — logs the received chain state at debug level. The peer's prior hello `user_data` already stores this info; this message serves as a refresh. - -**Broadcast trigger:** [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp) `connection_count_changed()` (line 793) — when the connection count increases (new peer joined), a `chain_status_announcement_message` is built from the chain database and broadcast to all peers. - -**Manual call site:** `p2p_plugin::broadcast_chain_status()` — can be called from any plugin (e.g., validator or snapshot) when chain state materially changes. - ---- - -## Message Flow Diagrams - -### Handshake Flow - -``` -Client (Initiator) Server (Acceptor) - | | - | TCP connect | - |----------------------------------------->| - | | - | hello_message (5006) | - | [user_agent, protocol_version, | - | node_public_key, signed_shared_secret, | - | user_data{...chain state...}] | - |----------------------------------------->| - | | validate signature - | | check chain ID - | | check hardfork version - | | check duplicate connection - | | - | connection_accepted_message (5007) | - |<-----------------------------------------| - | | - | hello_message (5006) | - | [server's chain state] | - |<-----------------------------------------| - | validate | - | | - | connection_accepted_message (5007) | - |----------------------------------------->| - | | - | current_time_request_message (5012) | - |<-----------------------------------------| - | current_time_reply_message (5013) | - |----------------------------------------->| - -Both sides now call new_peer_just_added() → start_synchronizing_with_peer() -``` - ---- - -### Sync Mode Flow (Pull-Based) - -``` -Our Node (needs blocks) Peer (has blocks) - | | - | fetch_blockchain_item_ids_msg (5003) | - | [blockchain_synopsis: LIB,...head] | - |--------------------------------------->| - | | Server finds common ancestor - | | via get_block_ids() - | | - | blockchain_item_ids_inventory (5002) | - | [remaining=N, item_hashes=[...]] | - |<---------------------------------------| - | | - | fetch_items_message (5004) | - | [items_to_fetch=[id1, id2, ...]] | - |--------------------------------------->| - | | Server calls get_item() - | block_message (1001) | - | [signed_block data] | - |<---------------------------------------| - | push_block() | - | ... repeat for each block ... | - | | - | fetch_blockchain_item_ids_msg (5003) | - | (next batch if remaining > 0) | - |--------------------------------------->| - | ... repeat until remaining == 0 ... | - -When remaining == 0 and all items known: - we_need_sync_items_from_peer = false (transition to broadcast mode) -``` - ---- - -### Broadcast/Inventory Mode Flow (Push-Based) - -``` -validator Node Peer A Peer B (us) Peer C - | | | | - | 1. generate_block | - | 2. broadcast_block| | | - | [block_message] | | | - |------------------>| | | - | | | | - | | 3. item_ids_inventory| | - | | [block #N hash] | | - | |--------------------->| | - | | | | - | | 4. fetch_items_msg | | - | | [request block] | | - | |<---------------------| | - | | | | - | | 5. block_message | | - | | [block data] | | - | |--------------------->| | - | | | | - | | | 6. push_block() | - | | | 7. item_ids_inv | - | | | [block #N hash] | - | | |------------------->| - | | | | - | | | 8. fetch + block | - | | |<------------------>| -``` - -**Broadcast suppression during sync:** When `we_need_sync_items_from_peer == true` for ANY peer, incoming inventory from ALL peers is skipped (node.cpp:3358). This prevents inventory-request timeouts from killing sync connections. - ---- - -### Block Post-Validation Flow - -``` -validator Node Other Peers - | | - | 1. produce_block() + broadcast | - | 2. broadcast_block_post_validation() | - | [block_id, witness_account, sig] | - |--------------------------------------->| - | | 3. handle_message() in p2p_plugin - | | - recover public key from signature - | | - compare with validator on-chain signing_key - | | - if match: apply_block_post_validation() -``` - ---- - -## Transaction Exchange Flow - -### JSON-RPC → Chain → P2P Broadcast - -This is how a transaction submitted via the JSON-RPC API reaches the P2P network: - -``` -External Client - | - | HTTP/WS POST {"jsonrpc":"2.0", "method":"call", - | "params":["network_broadcast_api","broadcast_transaction", - | [signed_transaction]]} - v -[webserver plugin] → [json_rpc plugin] → dispatch to registered API - | -[network_broadcast_api_plugin::broadcast_transaction] - | - | 1. pimpl->_chain.accept_transaction(trx) - | → chain_plugin::accept_transaction() - | → database::push_transaction() - | → validates, pushes to _pending_tx - | - | 2. pimpl->_p2p.broadcast_transaction(trx) - | → p2p_plugin::broadcast_transaction() - | → node->broadcast(trx_message(trx)) - | → sends trx_message (1000) to all connected peers - | - | 3. Peers receive → process_ordinary_message() - | → _delegate->handle_transaction(trx_msg) - | → chain.accept_transaction() - | → broadcast() to their OTHER peers (relay) - | - v - Transaction propagates through the network via gossip - (each peer that accepts it broadcasts to its other peers) - -Eventually included in a block by a validator. -``` - -### Callback-Based Variant - -`broadcast_transaction_synchronous` (network_broadcast_api.cpp:55): -- Registers a callback keyed by `transaction_id` -- Accepts and broadcasts the transaction -- When a block containing the transaction is applied (`on_applied_block`, line 159), fires the callback with `(txid, block_num, trx_num, expired=false)` -- When the transaction expires before inclusion, fires callback with `expired=true` - -### P2P Receive → Chain → Relay - -``` -Remote Peer - | - | trx_message (1000) arrives - v -[node.cpp] process_ordinary_message() - | - | Check: items_requested_from_peer contains this item? - | No → "received a message I didn't ask for" → disconnect - | Yes → erase from items_requested_from_peer - | - | msg_type == trx_message_type? - | Yes → _delegate->handle_transaction(trx_msg) - | No → _delegate->handle_message(msg) [for block_post_validation, etc.] - | - v -[p2p_plugin.cpp] handle_transaction() - | - | chain.accept_transaction(trx_msg.trx) - | → database::push_transaction() - | → validates, pushes to _pending_tx - | - | On success: node.cpp broadcast() to all OTHER peers - v - Transaction relayed to rest of network -``` - ---- - -## Dispatch Decision Tree (node.cpp) - -``` -message received - | - +-- connection_accepted (5007) → on_connection_accepted_message() - | - +-- connection_rejected (5008) → disconnect - | - +-- address_request (5009) → send address_message - +-- address_message (5010) → add to potential_peer_db - +-- closing_connection (5011) → disconnect - | - +-- current_time_request (5012)→ send current_time_reply - +-- current_time_reply (5013) → update clock_offset - | - +-- check_firewall (5014) → try connecting, send result - +-- check_firewall_reply (5015)→ update firewalled state - | - +-- get_current_connections_req (5016) → send reply - +-- get_current_connections_reply (5017) → diagnostics - | - +-- chain_status_announcement (5018) → handle_message() - | → log DLT/emergency state from peer - | - +-- hello_message (5006) → on_hello_message() - | → validate, accept or reject - | - +-- fetch_blockchain_item_ids (5003) - | → on_fetch_blockchain_item_ids() - | → build synopsis, find common ancestor - | → send blockchain_item_ids_inventory - | - +-- blockchain_item_ids_inventory (5002) - | → on_blockchain_item_ids_inventory() - | → validate sequential IDs - | → add unknown IDs to ids_of_items_to_get - | - +-- fetch_items (5004) → on_fetch_items() - | → get_item() for each requested hash - | → send block_message or trx_message - | - +-- item_not_available (5005) → soft-ban / strike - | - +-- item_ids_inventory (5001) - | → on_item_ids_inventory() - | → if not syncing: request unknown blocks - | - +-- block_message (1001) OR trx_message (1000) - → process_ordinary_message() - → was this item requested? (items_requested_from_peer) - → delegate to handle_block() or handle_transaction() - → on success: broadcast to other peers -``` - ---- - -## DLT Mode Considerations for P2P Messages - -### Synopsis Handling - -When a DLT node (rolling window of blocks) receives a `fetch_blockchain_item_ids_message`: - -1. **Synopsis below DLT range**: If ALL synopsis entries are below `earliest_available_block_num()`, the peer is NOT on a fork — it simply has older blocks than we store. Use the highest synopsis entry as anchor and serve from our earliest block. (Implemented in [p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp#L412-L442)) - -2. **Synopsis above head**: If ALL synopsis entries are above our head, the peer is ahead of us. Return empty — nothing to serve. - -3. **Synopsis matched below range**: When the matched anchor is below `earliest_available_block_num()`, include it in the response as a known anchor, then continue from earliest. Prevents "invalid response" disconnections. - -### Block Serving - -`get_item()` (p2p_plugin.cpp:528) in DLT mode: when a block is not found, logs the full context (available range, DLT range) and throws `key_not_found_exception` instead of the generic "Couldn't find block" error. This gives visibility into whether the block is genuinely missing or just outside the DLT window. - -### Near-Caught-Up Sync Blocks - -[p2p_plugin.cpp](file:///d:/Work/viz-cpp-node/plugins/p2p/p2p_plugin.cpp#L202-L226): When a sync block arrives with `gap <= 2 && dlt_mode && block_age < 30s`, it's treated as a normal (non-sync) block. This prevents "Syncing Blockchain started" from firing when the node is only 1-2 blocks behind, which would set `currently_syncing=true` and disrupt validator block production. - ---- - -## How `chain_status_announcement_message` (5018) Makes DLT Mode Safer - -### Problem: The Hello Handshake Alone Is Not Enough - -The hello message (5006) sends chain state **once** at connection time. In DLT mode with emergency consensus, the chain state can change dramatically *during* an active connection: - -- **DLT window slides forward** every block (the rolling window of ~350 blocks advances by 1 each time). -- **Emergency consensus can activate or deactivate** at any time (1-hour timeout triggers; exit after 21 normal blocks). -- **The emergency master can change** (blank key after 5 missed rounds). - -Without live updates, peers make decisions based on **stale connection-time data**, leading to: - -1. **False `peer_is_on_an_unreachable_fork`**: A peer sends a synopsis with entries from block numbers we *used* to have but which have now aged out of our DLT window. Without knowing our DLT `earliest_available_block_num()`, the peer can't adjust its synopsis to use entries inside our window. Result: we throw the fork exception, disconnect the peer, and create a sync oscillation. - -2. **Sync ping-pong in emergency mode**: During emergency consensus, competing forks at the same height cause both nodes to restart sync. Without knowing the peer is also in emergency mode, a node treats the peer's blocks as "normal" fork blocks and triggers full sync restarts instead of recognizing the emergency situation and treating it as a committee-led recovery. - -3. **Inventory flooding during DLT window mismatch**: A peer in broadcast mode may advertise block IDs that are below our DLT window. We can't serve them, but we don't know the peer has stale information. This generates spurious `fetch_items` → `item_not_available` cycles that increment the peer's strike counter and lead to soft-bans. - -### Solution: The Chain Status Announcement - -The `chain_status_announcement_message` (5018) solves these problems by providing: - -#### 1. Live DLT Window Information (`dlt_mode`, `dlt_earliest_block`) - -When a peer receives a `chain_status_announcement` showing the sender is in DLT mode with `dlt_earliest_block = 79632101`, it knows: - -- **Don't use block numbers below 79632101 in synopses** sent to this peer — those blocks are no longer in their rolling window. -- **Don't request blocks below 79632101** — they'll get `item_not_available` responses and risk soft-ban strikes. -- **Expected result**: Eliminates the entire class of `peer_is_on_an_unreachable_fork` errors caused by below-DLT-range synopses. - -#### 2. Live Emergency Consensus Status (`emergency_consensus_active`, `has_emergency_key`) - -When a peer receives a `chain_status_announcement` with `emergency_consensus_active = true`: - -- **Don't treat competing blocks at the same height as forks** — they may be emergency committee blocks from a legitimate committee recovery. -- **If `has_emergency_key = true`**: This peer is the emergency master — prioritize syncing from it. -- **If `has_emergency_key = false`**: This peer is an emergency follower — don't soft-ban it for producing blocks we disagree with (the committee decides). -- **Expected result**: Eliminates sync ping-pong loops and false fork detections during emergency consensus recovery. - -#### 3. Continuous Refresh on New Connections - -The message is automatically broadcast via `connection_count_changed()` whenever a new peer joins. This means: - -- **Every new peer immediately learns** our current DLT window and emergency status, even if we connected hours ago. -- **No polling needed** — push-based, not pull-based. -- **Zero protocol breakage** — old peers simply ignore message type 5018 (it goes to `handle_message()` which, pre-5018, would throw `Invalid Message Type`, but since old peers never send this message to begin with, the throw never fires). - -### Error Classes Eliminated - -| Error Class | Root Cause | Fixed By | -|---|---|---| -| `peer_is_on_an_unreachable_fork` (below-range) | Peer synopsis entries below our DLT `earliest_available_block_num()` | Peer sees `dlt_earliest_block` and adjusts synopsis | -| Sync restart oscillation | Both nodes think the other is on a fork in emergency mode | Both see `emergency_consensus_active=true` and relax fork detection | -| `item_not_available` soft-bans | Peer requests blocks we can't serve (below window) | Peer skips below-DLT block requests | -| `unlinkable_block_exception` spamming | Dead-fork sync blocks from before our head | Peer sees `dlt_mode` and avoids sending ancient blocks | -| Emergency follower disconnection | Master treats follower blocks as invalid fork blocks | `has_emergency_key` flag identifies master vs follower roles | - -### Integration with Existing Protections - -The `chain_status_announcement` works **alongside** (not instead of) the existing server-side protections: - -| Protection | Side | When It Helps | -|---|---|---| -| `chain_status_announcement` info | Client (peer) | **Before** sending — avoids problematic requests entirely | -| `get_block_ids()` below-range check | Server | **During** synopsis processing — catches what the client missed | -| `get_block_ids()` above-head check | Server | **During** synopsis processing — handles ahead-of-us peers | -| DLT near-caught-up logic | Server | **During** block receiving — prevents sync mode disruption | -| Soft-ban strike counters | Server | **After** repeated errors — last-resort penalty | - -**Key insight**: The server-side protections handle errors reactively (strikes, disconnection), while `chain_status_announcement` prevents errors proactively (peers know what not to do before they do it). Both layers together create defense-in-depth. - -### Backward Compatibility - -| Peer Combination | Behavior | -|---|---| -| Old ↔ Old | No change. Works as before. | -| New ↔ New | Both exchange DLT/emergency info via hello user_data AND chain_status_announcement (5018). Full benefits. | -| New → Old | New peer sends hello with DLT fields (old peer ignores unknown keys). New peer may send 5018 (old peer's handle_message throws `Invalid Message Type`). This is a one-time benign throw since old peers don't understand the type. The new peer's code handles this gracefully. | -| Old → New | Old peer sends hello without DLT fields. New peer defaults `peer_dlt_mode=false`, `peer_emergency_active=false` — assumes the old peer operates in normal (non-DLT, non-emergency) mode. The new peer does NOT send 5018 to the old peer because `connection_count_changed` broadcasts to ALL peers, which includes the old one. This is a known limitation — old peers will see one `Invalid Message Type` throw per new-peer connection. To mitigate, future work could add per-peer capability tracking based on hello user_data fields. | - ---- - -## Key Type Definitions - -| Type | Underlying | Size | Defined In | -|------|-----------|------|------------| -| `node_id_t` | `fc::ecc::public_key_data` | 33 bytes | core_messages.hpp:51 | -| `item_hash_t` | `fc::ripemd160` | 20 bytes | core_messages.hpp:52 | -| `item_id` | `{ uint32_t item_type; item_hash_t item_hash; }` | 24 bytes | core_messages.hpp:54 | -| `block_id_type` | `fc::ripemd160` | 20 bytes | protocol/types.hpp | -| `transaction_id_type` | `fc::ripemd160` | 20 bytes | protocol/types.hpp | - ---- - -## Key Configuration Constants - -| Constant | File | Default | Description | -|----------|------|---------|-------------| -| `GRAPHENE_NET_PROTOCOL_VERSION` | config.hpp | — | Version sent in hello_message | -| `GRAPHENE_NET_DEFAULT_PEER_CONNECTION_RETRY_TIME` | config.hpp | 30s | Base retry interval | -| `GRAPHENE_NET_MAX_FAILED_CONNECTION_ATTEMPTS` | config.hpp | 5 | Cap on failure counter (max backoff = 180s) | -| `GRAPHENE_NET_DEFAULT_DESIRED_CONNECTIONS` | config.hpp | 20 | Target active connections | -| `GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH` | config.hpp | 10000 | Min IDs to collect before block fetching during concurrent sync | -| `DISCONNECT_RECONNECT_COOLDOWN_SEC` | node.cpp | 30s | Per-IP cooldown after disconnect | diff --git a/.qoder/docs/p2p-sync-workflow.md b/.qoder/docs/p2p-sync-workflow.md deleted file mode 100644 index a6293bb044..0000000000 --- a/.qoder/docs/p2p-sync-workflow.md +++ /dev/null @@ -1,699 +0,0 @@ -# P2P Synchronization & Block Push Workflow - -## Overview - -The VIZ P2P network uses two distinct modes for block propagation between nodes: - -1. **Sync Mode** — Active pull-based synchronization for catching up with the network -2. **Broadcast/Inventory Mode** — Passive push-based delivery of new blocks in real-time - -A node transitions from sync mode to broadcast mode once it catches up to the network head. Both modes operate per-peer — a node can be syncing from one peer while receiving broadcasts from another. - ---- - -## Architecture - -### Key Components - -| Component | File | Role | -|-----------|------|------| -| `node_impl` | `libraries/network/node.cpp` | Core P2P engine: sync state machine, message handlers, peer management | -| `peer_connection` | `libraries/network/include/graphene/network/peer_connection.hpp` | Per-peer state: sync flags, item queues, soft-ban timers | -| `p2p_plugin_impl` | `plugins/p2p/p2p_plugin.cpp` | Bridge between P2P network and blockchain: block handling, sync initiation | -| `chain::database` | `libraries/chain/database.cpp` | Blockchain state: push_block, fork_db, block validation | - -### Per-Peer Sync State Flags - -Each `peer_connection` carries two critical boolean flags: - -``` -peer_needs_sync_items_from_us — Does the peer need blocks from us? (controls our OUTBOUND sync) -we_need_sync_items_from_peer — Do we need blocks from them? (controls our INBOUND sync) -``` - -These flags determine which protocol mode is active for each peer. - ---- - -## Mode 1: Sync Mode (Pull-Based) - -### When Active - -`we_need_sync_items_from_peer = true` - -Active when: -- A new peer connection is established (`new_peer_just_added()` → `start_synchronizing_with_peer()`) -- After minority fork recovery (`resync()` resets all peers) -- When a peer is detected to be ahead of us - -### Flow - -``` -Our Node Peer - | | - | 1. fetch_blockchain_item_ids | - | (our blockchain synopsis) | - |----------------------------------->| - | | - | 2. blockchain_item_ids_inventory | - | (list of block IDs + remaining) | - |<-----------------------------------| - | | - | 3. fetch_items_message | - | (request actual block data) | - |----------------------------------->| - | | - | 4. block_message | - | (signed block data) | - |<-----------------------------------| - | | - | [repeat 3-4 for each block] | - | | - | 5. fetch_blockchain_item_ids | - | (request next batch of IDs) | - |----------------------------------->| - | | - | [repeat until remaining=0] | -``` - -### Detailed Steps - -#### Step 1: Build and Send Synopsis -**Function:** `fetch_next_batch_of_item_ids_from_peer()` (node.cpp L2748) - -The node builds a "blockchain synopsis" — a logarithmically-spaced list of block IDs from its chain — and sends it to the peer via `fetch_blockchain_item_ids_message`. The synopsis allows the peer to find the most recent common block efficiently. - -#### Step 2: Receive Block ID Inventory -**Handler:** `on_blockchain_item_ids_inventory_message()` (node.cpp L2787) - -The peer responds with: -- `item_hashes_available` — sequential list of block IDs the peer has after the common point -- `total_remaining_item_count` — how many more block IDs the peer can provide beyond this batch - -The node validates the response (sequential block numbers, valid link to synopsis) and adds unknown block IDs to `peer->ids_of_items_to_get`. - -#### Step 3-4: Fetch Actual Blocks -**Function:** `fetch_sync_items_loop()` (node.cpp ~L1100) - -Runs periodically. For each peer with `we_need_sync_items_from_peer = true` and `inhibit_fetching_sync_blocks = false`: -- Picks blocks from `ids_of_items_to_get` that aren't already requested from other peers -- Sends `fetch_items_message` to request the block data -- Tracks requests in `_active_sync_requests` to avoid duplicate fetches - -#### Step 5: Batch Continuation -If `total_remaining_item_count > 0`, the node sends another `fetch_blockchain_item_ids_message` to get the next batch of block IDs. This continues until the peer reports `remaining = 0`. - -### Sync Completion - -When the peer responds with `remaining = 0` and all offered items are already known: - -```cpp -// node.cpp L2967 or L3181 -originating_peer->we_need_sync_items_from_peer = false; -``` - -The node transitions this peer to **broadcast mode**. - ---- - -## Mode 2: Broadcast/Inventory Mode (Push-Based) - -### When Active - -`we_need_sync_items_from_peer = false` - -Active after sync completes — the node is caught up and receives new blocks in real-time. - -### Flow: Block Production and Propagation - -``` -validator Node Peer A Peer B (us) - | | | - | 1. generate_block() | | - | 2. broadcast_block() | | - |--------------------------->| | - | | | - | | 3. item_ids_inventory_msg | - | | ("I have block #N") | - | |--------------------------->| - | | | - | | 4. fetch_items_message | - | | ("send me block #N") | - | |<---------------------------| - | | | - | | 5. block_message | - | | (signed block data) | - | |--------------------------->| - | | | - | | 6. push_block() - | | 7. broadcast to - | | other peers -``` - -### Detailed Steps - -#### Step 1-2: Block Production -A validator node produces a block and calls `p2p_plugin::broadcast_block()`, which sends the block to all connected peers via `node::broadcast()`. - -#### Step 3: Inventory Advertisement -When a peer receives a new block (either via broadcast or sync), it advertises it to all its OTHER connected peers via `item_ids_inventory_message`. This is the gossip protocol — blocks propagate through the network hop by hop. - -#### Step 4-5: Block Request and Delivery -**Handler:** `on_item_ids_inventory_message()` (node.cpp L3339) - -When we receive an inventory message: -1. Check we're NOT in sync mode (skip if `we_need_sync_items_from_peer = true`) -2. Check no global sync in progress (skip if ANY peer has sync flag) -3. Check our head block is recent (skip if >30 seconds behind) -4. For each advertised item we don't have, request it via `fetch_items_message` -5. Peer responds with `block_message` containing the actual block - -#### Step 6-7: Block Application -**Handler:** `p2p_plugin_impl::handle_block()` (p2p_plugin.cpp L145) - -The block is pushed to the chain via `chain.accept_block()` → `database::push_block()`. If accepted, the node broadcasts it to its other peers, continuing propagation. - -### Broadcast Gate (Critical) - -At L3358 of node.cpp: -```cpp -if (originating_peer->we_need_sync_items_from_peer) { - // skip broadcast inventory — we're syncing from this peer - return; -} -``` - -**Broadcast inventory is completely suppressed during sync mode.** This prevents the 1-second inactivity timeout from killing sync connections (requesting tip-of-chain items during sync would time out before they arrive, disconnecting the peer). - ---- - -## Peer Blocking Mechanisms - -### Soft-Ban (`fork_rejected_until`) - -A time-based ban that silently discards incoming sync requests from the peer: - -```cpp -// node.cpp L2462 -if (originating_peer->fork_rejected_until > fc::time_point::now()) { - // silently discard sync request - return; -} -``` - -**Triggered by:** -- 50 competing-fork sync spam strikes → 300 second ban (L2600, L2637) -- 20 unlinkable block strikes → dynamic duration ban (L3721, L3837) -- Peer on a dead/old fork → dynamic duration ban (L3823) -- Item not available from peer → 30 second ban (L3311, L3325) - -### Sync Inhibition (`inhibit_fetching_sync_blocks`) - -Prevents fetching sync blocks from a specific peer without fully banning them: - -```cpp -// node.cpp L1158 -if (!peer->inhibit_fetching_sync_blocks) { - // fetch sync blocks from this peer -} -``` - -**Triggered by:** -- Peer can't advance our sync (returns only known blocks) — L3152 -- Item not available from peer — L3310, L3324 -- During soft-ban (always set alongside `fork_rejected_until`) - -### 30-Second Stuck Flag Auto-Clear - -**Location:** `terminate_inactive_connections_loop()` (node.cpp L1547-1556) - -Runs every 1 second. If `peer_needs_sync_items_from_us = true` but the peer hasn't sent a sync request in 30+ seconds, auto-clears the flag to `false`. This prevents inventory starvation when a race condition leaves the flag stuck. - -**Important:** A matching auto-clear for `we_need_sync_items_from_peer` was added as a safety net — see "Stuck `we_need_sync_items_from_peer` Auto-Clear" below. - -### Stuck `we_need_sync_items_from_peer` Auto-Clear - -**Location:** `terminate_inactive_connections_loop()` (node.cpp L1624-1638) - -If a peer has `we_need_sync_items_from_peer = true` but ALL sync-related lists are empty: -- `ids_of_items_to_get` empty -- `ids_of_items_being_processed` empty -- `sync_items_requested_from_peer` empty -- `number_of_unfetched_item_ids == 0` -- No pending `item_ids_requested_from_peer` - -AND this state has persisted for **30+ seconds** (measured via `last_sync_item_received_time`), the flag is auto-cleared to `false`. This is a safety net for edge cases where sync completes but the flag isn't properly reset (e.g., fork-switch race conditions — see "Gap/Fork Block Sync Stall Recovery" below). - -**Important:** This does NOT touch `sync_items_requested_from_peer` — clearing in-flight requests would cause arriving responses to be treated as "unsolicited block" and disconnect the peer. - ---- - -## Minority Fork Recovery - -### Detection - -In `witness_plugin::impl::maybe_produce_block()` (validator.cpp), if the last 21 blocks in `fork_db` were ALL produced by the node's own configured validators, the node is likely on a minority fork (isolated from the network). - -### Recovery Flow - -``` -1. MINORITY FORK DETECTED - ↓ -2. resync_from_lib() (p2p_plugin.cpp) - ├── Pop all reversible blocks back to LIB - ├── Reset fork_db, seed with LIB block - ├── node->sync_from(LIB block ID) - ├── node->resync() ← full peer state reset - └── Reconnect seed nodes - ↓ -3. _production_enabled = false - ↓ -4. Production loop returns not_synced every 250ms - (waiting for get_slot_time(1) >= now) - ↓ -5. P2P sync delivers blocks from peers - (head advances toward real time) - ↓ -6. Once head catches up: get_slot_time(1) >= now - → _production_enabled = true - ↓ -7. Block production resumes -``` - -### Full Peer State Reset - -The peer state reset logic lives in `node_impl::reset_active_peer_states()` (node.cpp) and is shared by two callers: - -1. **`resync()`** — called during minority fork recovery via `resync_from_lib()`. Resets all peer state, clears `_active_sync_requests`, then calls `start_synchronizing()`. -2. **`reconnect_seeds()`** — called by the Validator Plugin when producing a block with <2 peers. Resets all peer state, then force-reconnects seed nodes. - -The `resync()` function calls `reset_active_peer_states()` which clears per-peer state: - -``` -For each active peer: - - fork_rejected_until = epoch (lift soft-ban) - - unlinkable_block_strikes = 0 (clear strike counter) - - sync_spam_strikes = 0 (clear spam counter) - - inhibit_fetching_sync_blocks = false - - peer_needs_sync_items_from_us = true - - we_need_sync_items_from_peer = true - - Clear: ids_of_items_to_get, ids_of_items_being_processed, - sync_items_requested_from_peer - - Reset: last_block_delegate_has_seen -``` - -Then `resync()` also clears global sync state: - -``` - - _active_sync_requests.clear() (stale in-flight request tracking) - - _received_sync_items.clear() (accumulated blocks that failed to link) - - _new_received_sync_items.clear() (recently arrived blocks not yet tried) - - _most_recent_blocks_accepted → reset to [current head block ID] - (prevents "already seen" skip of gap blocks) -``` - -Without clearing `_received_sync_items` and `_new_received_sync_items`, `have_already_received_sync_item()` would skip re-requesting blocks that arrived but failed to link (e.g., unlinkable blocks during a gap), leaving permanent gaps — especially critical in DLT emergency mode. Without resetting `_most_recent_blocks_accepted`, `process_backlog_of_sync_blocks()` would skip blocks that were accepted before the gap but need re-evaluation after resync. - -> **Note:** The DLT P2P node (`dlt_p2p_node.cpp`) has an analogous mechanism called `emergency_peer_reset()` (P53 fix) that handles peer isolation — when all peers are disconnected/banned for 60+ seconds, it clears soft bans, resets backoffs, and forces immediate reconnection. See [DLT Forward Mode — Peer Isolation Recovery](./dlt-forward-mode.md#peer-isolation-recovery) for details. - ---- - -## Connection Retry & Seed Reconnection - -### Connection Loop - -`p2p_network_connect_loop()` (node.cpp) runs continuously, every **10 seconds**. It: - -1. Processes `_add_once_node_list` — priority peers (seeds added via `add_node()`) that bypass connection limits -2. Checks `is_wanting_new_connections()` — true if `active_connections < desired_connections` (default 20) -3. Iterates `_potential_peer_db` with exponential backoff: `(failed_attempts + 1) * 30s` -4. Skips peers in disconnect cooldown (30 seconds after disconnect) - -### Backoff Cap - -`number_of_failed_connection_attempts` is capped at `GRAPHENE_NET_MAX_FAILED_CONNECTION_ATTEMPTS` (5) in `config.hpp`. This limits the maximum retry delay to `(5+1) * 30 = 180 seconds = 3 minutes`. - -When a peer reaches the maximum failure count and still fails to connect, an info-level log is emitted: -``` -P2P seed node not responding (5 consecutive failures), check config and remove if not needed -``` - -### Low-Peer Seed Reconnection - -The Validator Plugin checks the connection count after each successfully produced block. If fewer than 2 peers are connected: - -``` -1. validator produces block, broadcasts it -2. Check: get_connections_count() < 2? -3. YES → p2p_plugin::reconnect_seeds() - ├── node->reset_active_peer_states() (clear all blocking state) - └── For each seed: add_node() + connect_to_endpoint() - (bypasses exponential backoff via timer reset) -``` - -`add_node()` resets the `last_connection_attempt_time` to allow immediate retry, and adds the peer to `_add_once_node_list` for priority processing in the next connect loop iteration. This means the node retries seeds every block interval (~3 seconds) when isolated, rather than waiting for backoff. - ---- - -## State Diagram - -``` - ┌─────────────────────────┐ - │ Connection Established │ - └────────────┬────────────┘ - │ - ▼ - ┌─────────────────────────┐ - │ start_synchronizing_ │ - │ with_peer() │ - │ we_need_sync = true │ - └────────────┬────────────┘ - │ - ▼ - ┌─────────────────────────┐ - │ SYNC MODE │ - │ Pull block IDs + data │◄──── resync() on - │ from peer │ minority fork - └────────────┬────────────┘ recovery - │ - │ remaining=0 && - │ all items known - ▼ - ┌─────────────────────────┐ - │ we_need_sync = false │ - └────────────┬────────────┘ - │ - ▼ - ┌─────────────────────────┐ - │ BROADCAST MODE │ - │ Receive inventory ads │ - │ Request unknown blocks │ - └─────────────────────────┘ -``` - ---- - -## DLT Mode Considerations - -In DLT mode (node loaded from snapshot), several sync behaviors are adjusted: - -1. **Block serving is clamped** to the available range (dlt_block_log + fork_db). The node won't advertise blocks it can't serve. -2. **Synopsis matching** tolerates gaps between the anchor block and continuation blocks (a DLT node may not have all historical blocks). -3. **Peer ahead detection**: If all peer synopsis entries are above our head, return empty (peer is ahead, not on a fork). -4. **Broadcast inventory** is suppressed when head block is >30 seconds behind real time, even if no peer has `we_need_sync_items_from_peer = true`. -5. **Sync oscillation prevention**: When sync blocks arrive ahead of head (gap between head and arriving blocks), a progressive cooldown (5s→10s max) prevents thundering-herd restarts, and `resync()` clears all stale sync state so missing gap blocks can be re-fetched. See "DLT Emergency Sync Oscillation Prevention" below. -6. **Synopsis head-block guarantee**: `get_blockchain_synopsis()` ensures the reference point (`high_block_num`) is always included in the returned synopsis. When `true_high_block_num >> high_block_num` (which happens when IDs have already been queued), the logarithmic step can skip over `high_block_num` in a single jump; a post-loop guard appends it if missing. Without this, peer responses starting at our head fail validation ("invalid response"). See "Synopsis High-Block Guarantee" below. -7. **Concurrent ID + block fetching**: Block fetching is allowed while block IDs are still being collected from a peer, once at least `GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH` (10000) IDs are available. This prevents the "NOT IDLE (ids_req=true)" stall where a peer is perpetually busy fetching IDs and blocks are never requested. See "Concurrent ID and Block Fetching" below. -8. **Duplicate sync-start guards**: `start_synchronizing_with_peer()` and `new_peer_just_added()` both guard against duplicate sync initiation for the same peer, preventing duplicate synopsis requests that cause "invalid response" disconnections. See "Duplicate Sync-Start Guards" below. - ---- - -## Stale Sync Detection - -A background safety mechanism that detects when the node has stopped receiving blocks from the network and automatically triggers recovery. - -### Configuration - -| Option | Default | Description | -|--------|---------|-------------| -| `p2p-stale-sync-detection` | `true` | Enable/disable the feature | -| `p2p-stale-sync-timeout-seconds` | `120` | Seconds without any block before triggering recovery | - -### How It Works - -A scheduled task runs every **30 seconds** (`stale_sync_check_task()` in p2p_plugin.cpp L935): - -1. Computes `elapsed = now - _last_block_received_time` -2. If `elapsed > timeout` (default 120s = 2 minutes): - -``` -Stale sync detected! - │ - ├── 1. Get LIB number from database - ├── 2. node->sync_from(LIB block ID) ← reset sync start point - ├── 3. node->resync() ← full peer state reset + start_synchronizing() - ├── 4. For each seed node: - │ add_node() + connect_to_endpoint() ← force reconnect - └── 5. Reset _last_block_received_time ← prevent immediate retry -``` - -3. Reschedules itself for another check in 30 seconds - -### Timer Reset Points - -The `_last_block_received_time` is reset to `now` in these situations: - -| Location | When | -|----------|------| -| `handle_block()` (L148) | Every time a block is received from any peer | -| `stale_sync_check_task()` (L984) | After recovery triggers (prevents immediate re-trigger) | -| `resync_from_lib()` (L1361) | After minority fork recovery | -| `trigger_resync()` (L1422) | After snapshot hot-reload | -| Plugin startup (L1236) | Initial value when node starts | - -### Interaction with Other Recovery Mechanisms - -The stale sync detector acts as a **last-resort safety net**. It complements: - -- **Minority fork detection** (Validator Plugin) — triggers faster (after 21 own-validator blocks), but only if the node is actively producing. Stale sync covers the case where the node is NOT a validator or production is already disabled. -- **Low-peer seed reconnection** (Validator Plugin) — triggers per-block when <2 peers, but only while producing. Stale sync covers periods when production is halted. -- **Connection loop backoff** (node.cpp) — handles normal reconnection with exponential backoff. Stale sync overrides this by calling `resync()` which does a full peer state reset + `add_node()` on seeds. -- **Snapshot stalled sync detection** (snapshot plugin) — a separate, heavier mechanism described below. - ---- - -## Snapshot Stalled Sync Detection - -A separate stalled sync detector lives in the **snapshot plugin** (`plugins/snapshot/plugin.cpp`). Unlike the P2P-level detector (which resets sync and reconnects seeds), this one downloads a **newer snapshot** from trusted peers — a much heavier recovery action designed for DLT mode nodes that are hopelessly behind. - -### Configuration - -| Option | Default | Description | -|--------|---------|-------------| -| `enable-stalled-sync-detection` | `false` | Enable/disable snapshot-level stall detection | -| `stalled-sync-timeout-minutes` | `5` | Minutes without any block before triggering snapshot re-download | -| `trusted-snapshot-peer` | (none) | Trusted peer endpoints for snapshot download (can specify multiple) | - -Requires `trusted-snapshot-peer` to be configured — without trusted peers, the detection won't start even if enabled. - -### How It Works - -A background thread runs `check_stalled_sync_loop()` (plugin.cpp L1682), checking every **30 seconds**: - -1. Computes `elapsed = now - last_block_received_time` -2. If `elapsed > stalled_sync_timeout_minutes` (default 5 min), uses a two-stage escalation: - -``` -Stalled sync detected! - │ - ├── First trigger (P2P recovery): - │ ├── p2p_plugin->trigger_resync() ← resync + reconnect seeds - │ ├── Set _p2p_recovery_attempted = true - │ └── Delay timer by 1 minute (give P2P recovery time to work) - │ - └── Second trigger (snapshot download): - ├── 1. Query trusted peers for a newer snapshot - │ download_snapshot_from_peers() - │ - ├── 2a. Newer snapshot found: - │ ├── load_snapshot() ← replace chain state - │ ├── set_dlt_mode(true) - │ ├── initialize_hardforks() - │ ├── Replay dlt_block_log ← apply local blocks beyond snapshot - │ ├── p2p_plugin->trigger_resync() ← resync + reconnect seeds - │ └── Reset timer + guard, restart loop - │ - └── 2b. No newer snapshot available: - └── Reset timer, continue with P2P sync -``` - -The `_p2p_recovery_attempted` guard resets to `false` whenever a block is received (`on_applied_block`), so each new stall starts fresh with P2P recovery. - -### Difference from P2P Stale Sync Detection - -| | P2P Stale Sync (p2p_plugin) | Snapshot Stalled Sync (snapshot plugin) | -|---|---|---| -| **Default** | Enabled (`true`) | Disabled (`false`) | -| **Timeout** | 120 seconds (2 min) | 5 minutes | -| **Recovery action** | Reset sync to LIB + reconnect seeds | Download entire snapshot from trusted peer | -| **Requires** | Nothing (works with any peers) | `trusted-snapshot-peer` configured | -| **Severity** | Lightweight (P2P-level reset) | Heavy (full chain state replacement) | -| **Use case** | Temporary network issues, soft-bans | Node hopelessly behind, DLT mode bootstrap | - -The P2P detector fires first (2 min) and attempts a soft recovery. If that doesn't work and blocks still don't arrive, the snapshot detector fires later (5 min) and does a hard recovery by re-downloading state. - ---- - -## Gap/Fork Block Sync Stall Recovery - -A three-layer defense against a sync stall that occurs when a broadcast block with a missing parent triggers sync, and the fork switch during sync applies both the gap-filling block AND the deferred broadcast block to the chain. - -### Problem Scenario - -``` -1. Block #N+2 arrives via broadcast, deferred to fork_db (parent #N+1 missing). - Added to _most_recent_blocks_accepted. -2. Sync starts with peer. ids_of_items_to_get = [#N+1, #N+2]. -3. Block #N+1 arrives via sync, fork switch applies both #N+1 and #N+2. -4. send_sync_block_to_node_delegate for #N+1 cleans its own - ids_of_items_being_processed, but NOT #N+2's entry in ids_of_items_to_get. -5. fetch_sync_items_loop re-requests #N+2 from peer. Peer becomes NOT IDLE. -6. When #N+2 arrives again, process_backlog_of_sync_blocks finds it in - _most_recent_blocks_accepted — originally just logged and broke WITHOUT - cleaning ids_of_items_being_processed. -7. Orphaned ids_of_items_being_processed entry prevents sync completion. - we_need_sync_items_from_peer stays permanently true. -8. All broadcast inventory from the peer is silently suppressed. -9. Peer eventually disconnects on inactivity timeout. -``` - -### Layer 1: Stale `ids_of_items_to_get` Cleanup (Defensive) - -**Location:** `fetch_sync_items_loop()` (node.cpp L1154-1196) - -At the start of each loop iteration, before requesting blocks from peers, scan each syncing peer's `ids_of_items_to_get` and remove blocks that are already on the chain (`_delegate->has_item()` returns true AND block number <= head). This catches blocks applied via fork switch that the sync layer never "received". - -Peers whose lists become fully empty (all four sync lists empty) are collected. After the `ASSERT_TASK_NOT_PREEMPTED` block, `fetch_next_batch_of_item_ids_from_peer()` is called for each to confirm sync completion (L1251-1257). This call yields, so it must be outside the non-preemptable section. - -**Does NOT** clean `sync_items_requested_from_peer` — those are in-flight requests. Task 2 handles them when the response arrives. - -### Layer 2: Proper `_most_recent_blocks_accepted` Handling (Primary Fix) - -**Location:** `process_backlog_of_sync_blocks()` (node.cpp L4173-4201) - -When a sync block is found in `_most_recent_blocks_accepted` (already applied via broadcast + fork switch), the block has already been moved from `ids_of_items_to_get` into `ids_of_items_being_processed` (at L4130-4136). The fix properly cleans up: - -1. Erases the block from `_received_sync_items` (fixes memory leak) -2. Decrements `_total_number_of_unfetched_items` -3. For each peer: erases the block from `ids_of_items_being_processed`, updates `last_block_delegate_has_seen` -4. If peer's sync lists are now all empty, adds to `peers_with_newly_empty_item_lists` -5. Sets `block_processed_this_iteration = true` so the do-while loop continues - -After the do-while loop (L4228-4234), `fetch_next_batch_of_item_ids_from_peer()` is called for peers in `peers_with_newly_empty_item_lists`. The response handler at `on_blockchain_item_ids_inventory` (L2953) clears `we_need_sync_items_from_peer` when the peer reports `remaining = 0` with all items known. - -### Layer 3: Stuck Flag Safety Net - -**Location:** `terminate_inactive_connections_loop()` (node.cpp L1624-1638) - -Described above in "Stuck `we_need_sync_items_from_peer` Auto-Clear". Acts as a 30-second last-resort timeout if Layers 1 and 2 both miss the cleanup. - -### Other Related Fixes - -#### Gap Block Sync Trigger - -**Location:** `process_block_during_normal_operation()` (node.cpp L4316-4331) - -When a broadcast block's number is ahead of head+1 (parent missing) and `handle_block()` returns false, the block is stored in fork_db's unlinked index. If no sync is in progress (`!we_need_sync_items_from_peer`), sync is restarted with the originating peer to fetch the missing parent blocks. Without this, the node would stall permanently after receiving a gap block in broadcast mode. - -#### Inventory Gate Deadlock Breaker - -**Location:** `on_item_ids_inventory_message()` (node.cpp L3480-3513) - -When head is >30 seconds behind real time, broadcast inventory is normally suppressed. But if NO sync is in progress with ANY peer, the node is stuck — it ignores inventory AND doesn't sync. The fix detects this state and triggers `start_synchronizing_with_peer()` with the first peer that advertises blocks, breaking the deadlock. - -#### DLT Emergency Sync Oscillation Prevention - -**Location:** `send_sync_block_to_node_delegate()` (node.cpp L4141-4171) - -When a DLT emergency follower node loses sync with its master and reconnects, sync blocks ahead of the current head arrive but fail with `unlinkable_block_exception` (parent missing from `fork_db`). This triggers a sync restart, but the old implementation had two critical flaws: - -1. **Thundering herd**: Multiple concurrent async `send_sync_block_to_node_delegate` tasks fail simultaneously. Each slept 2s then called `start_synchronizing_with_peer()` for all peers — causing N concurrent full sync restarts at the same time. -2. **Incomplete state reset**: `start_synchronizing_with_peer()` cleared `ids_of_items_to_get` but NOT `sync_items_requested_from_peer`, `ids_of_items_being_processed`, `_active_sync_requests`, `_received_sync_items`, or `_most_recent_blocks_accepted`. Old failed blocks remained, causing `have_already_received_sync_item()` to skip re-requesting the missing gap blocks. - -The fix replaces the per-peer `start_synchronizing_with_peer()` loop with a single `resync()` call (which does a complete state reset — see "Full Peer State Reset" above) protected by a **progressive cooldown**: - -``` -First restart: 5s cooldown -Second restart: 7s cooldown -Third restart: 9s cooldown -Fourth+: 10s cooldown (max) - -Cooldown resets to 5s on any successful block acceptance. -``` - -The cooldown is tracked by `_last_deferred_resize_time` and `_consecutive_deferred_resize_count`. When a duplicate restart is attempted within the cooldown window, it is skipped entirely (early `return`), preventing the thundering herd. - -#### Synopsis High-Block Guarantee - -**Location:** `get_blockchain_synopsis()` (p2p_plugin.cpp, after the do-while loop) - -When the node has already collected block IDs (`ids_of_items_to_get` non-empty), subsequent synopsis requests pass `number_of_blocks_after_reference_point > 0`. Inside `get_blockchain_synopsis`, `true_high_block_num = high_block_num + number_of_blocks_after_reference_point`. The do-while loop steps logarithmically using `true_high_block_num` but exits when `low_block_num > high_block_num`. When `true_high_block_num >> high_block_num`, a single step can jump past `high_block_num`, producing a synopsis that omits the node's own head block entirely. - -When the peer responds with blocks starting near our head, the validation in `on_blockchain_item_ids_inventory` checks if the first block ID is in the synopsis. Since our head block is missing, validation fails and the peer is disconnected with "invalid response". - -The fix adds a guard after the do-while loop that appends `high_block_num` if the synopsis is empty or its last entry isn't `high_block_num`. The entry is looked up from the main chain (if within `non_fork_high_block_num`) or from `fork_history` (if on a fork). - -#### Duplicate Sync-Start Guards - -**Locations:** `start_synchronizing_with_peer()` (node.cpp) and `new_peer_just_added()` (node.cpp) - -When a peer connects, two code paths both call `start_synchronizing_with_peer` for the same peer: -- `on_fetch_blockchain_item_ids` handler — fires when processing the peer's initial synopsis request -- `new_peer_just_added` — fires when the peer finishes handshaking - -The second call clears the state set by the first (including `ids_of_items_to_get`) and sends a duplicate synopsis. The peer responds to both, and the second response triggers "invalid response" disconnection (exacerbated by the missing `high_block_num` from the synopsis bug). - -Two guards prevent this: -1. **`start_synchronizing_with_peer`**: Skips if `item_ids_requested_from_peer` is already set (a pending ID request already exists for this peer). Logs the skip at debug level. -2. **`new_peer_just_added`**: Checks both `we_need_sync_items_from_peer` and `item_ids_requested_from_peer` before calling `start_synchronizing_with_peer`. If either is set, sync was already started by the `on_fetch_blockchain_item_ids` handler and is skipped. - -#### Concurrent ID and Block Fetching - -**Location:** `fetch_sync_items_loop()` (node.cpp ~L1244) - -Previously, `fetch_sync_items_loop` required `peer->idle()` to schedule block requests. The `idle()` method returns false when `item_ids_requested_from_peer` is set — meaning blocks could never be fetched while IDs were being collected. During ID fetching, `fetch_next_batch_of_item_ids_from_peer` is called immediately after each batch, keeping `item_ids_requested_from_peer` permanently set. The loop logged "NOT IDLE (ids_req=true)" and skipped block fetching entirely. - -The fix replaces `peer->idle()` with a condition that only blocks on block-level requests: - -```cpp -(!peer->item_ids_requested_from_peer || // not fetching IDs, OR - peer->ids_of_items_to_get.size() >= GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH) // have enough IDs -&& peer->items_requested_from_peer.empty() // no pending block requests -&& peer->sync_items_requested_from_peer.empty() // no pending sync block requests -``` - -This allows block fetching once at least 10,000 IDs are available, even while more IDs are being fetched. The peer can serve both block data and ID responses simultaneously. - -The "NOT IDLE" diagnostic log was also updated to distinguish between "busy with blocks" (genuinely busy, can't fetch more) vs "skipped-other" (blocked by non-block state like ID requests with insufficient IDs). - -#### Emergency Consensus Head-Advancement Checks - -Both stale sync detectors skip recovery during emergency consensus if head is still advancing: - -- **P2P stale sync** (`p2p_plugin.cpp` L1021-1038): Compares `current_head > _last_stale_check_head`. If advancing, resets timer and skips recovery. -- **Snapshot stalled sync** (`plugin.cpp` L1772-1786): Same logic with `_last_stalled_check_head`. If advancing, resets timer and continues loop. - -This prevents false recovery triggers when the node is receiving emergency blocks from a master but not through the normal P2P sync path. - -### Fork DB State After Stale Sync Recovery - -Stale sync recovery (`resync()`) resets peer state and sync queues but does **not** reset `fork_db`. This means `fork_db._head` can point to a stale higher block accumulated from previous failed sync cycles. - -Without mitigation, this causes a permanent sync stall: - -1. `fork_db._head` points to block #N+5 from a previous cycle -2. Database head is at block #N (the actual applied chain tip) -3. Block #N+1 arrives from peer — its `previous` (#N) may not be in `fork_db` -4. If #N is missing from `fork_db`: `unlinkable_block_exception` → block silently rejected -5. If #N+1 is a duplicate in `fork_db`: returns stale `_head` (#N+5) → fork switch logic rejects -6. Head never advances → node re-enters sync → peer says "up-to-date" → repeat - -**Mitigation in `_push_block()`:** -- **Fork DB head-seeding:** Before pushing to `fork_db`, if the incoming block extends `head_block_id()` and the head is not in `fork_db`, the head block is seeded via `fork_db.start_block()`. This ensures the block can link. -- **Direct-extension bypass:** After pushing to `fork_db`, if `new_block.previous == head_block_id()`, the fork switch logic is bypassed entirely and the block is applied directly. This handles the stale `_head` pointing to a higher block. - -See [block-processing.md](block-processing.md) for details. - ---- - -## Key Configuration Constants - -| Constant | File | Default | Description | -|----------|------|---------|-------------| -| `GRAPHENE_NET_DEFAULT_PEER_CONNECTION_RETRY_TIME` | `config.hpp` | 30s | Base retry interval per failed attempt | -| `GRAPHENE_NET_MAX_FAILED_CONNECTION_ATTEMPTS` | `config.hpp` | 5 | Cap on failure counter (max backoff = 180s) | -| `GRAPHENE_NET_DEFAULT_DESIRED_CONNECTIONS` | `config.hpp` | 20 | Target number of active connections | -| `GRAPHENE_NET_DEFAULT_MAX_CONNECTIONS` | `config.hpp` | 200 | Maximum allowed connections | -| `DISCONNECT_RECONNECT_COOLDOWN_SEC` | `node.cpp` | 30s | Per-IP cooldown after disconnect | -| `GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH` | `config.hpp` | 10000 | Minimum IDs to collect before requesting blocks during concurrent ID+block fetch | -| `GRAPHENE_PEER_DATABASE_RETRY_DELAY` | `config.hpp` | 15s | (unused, replaced by 10s sleep) | diff --git a/.qoder/docs/plugins.md b/.qoder/docs/plugins.md deleted file mode 100644 index 9ec2a3d2a1..0000000000 --- a/.qoder/docs/plugins.md +++ /dev/null @@ -1,1079 +0,0 @@ -# VIZ Blockchain — Plugins Reference - -Complete specification of all VIZ node plugins: what they do, dependencies, status (active/deprecated), and JSON-RPC API methods. - ---- - -## Plugin Architecture Overview - -VIZ uses a modular plugin architecture based on Appbase. Plugins can: -- Provide JSON-RPC API methods -- Store additional data in the chainbase database -- React to blockchain events (applied blocks, operations, etc.) -- Depend on other plugins - -### Plugin Categories - -| Category | Description | -|---|---| -| **Core** | Essential for node operation | -| **API** | Expose JSON-RPC endpoints | -| **Index** | Index blockchain data for queries | -| **Infrastructure** | Networking, web server | -| **External** | Integration with external systems | -| **Debug/Test** | Development and testing only | - ---- - -## Core Plugins - -### `chain` -**Status:** Active (Required) -**Category:** Core -**Dependencies:** `json_rpc` - -The fundamental plugin that manages the blockchain database, block validation, and transaction processing. - -**Purpose:** -- Maintains the blockchain state database (chainbase) -- Validates and applies blocks and transactions -- Provides database access to other plugins -- Emits signals on block application - -**JSON-RPC:** None (internal only) - -**CLI options:** -| Option | Type | Description | -|--------|------|-------------| -| `--replay-blockchain` | `bool` | Clear chain database and replay all blocks | -| `--replay-if-corrupted` | `bool` (default: `true`) | Replay all blocks if shared memory is corrupted | -| `--force-replay-blockchain` | `bool` | Force clear chain database and replay all blocks | -| `--replay-from-snapshot` | `bool` | Crash recovery: import snapshot and replay dlt_block_log | -| `--auto-recover-from-snapshot` | `bool` (default: `true`) | Automatic runtime recovery from shared memory corruption via snapshot | -| `--resync-blockchain` | `bool` | Clear chain database and block log | - -**Config options:** -```ini -shared-file-size = 2G -shared-file-dir = /path/to/blockchain -flush-state-interval = 0 -``` - -| Option | Default | Description | -|--------|---------|-------------| -| `shared-file-size` | `2G` | Start size of the shared memory file | -| `shared-file-dir` | `state` | Location of the shared memory files | -| `inc-shared-file-size` | `2G` | Size increment when shared memory runs low | -| `min-free-shared-file-size` | `500M` | Minimum free space before auto-grow | -| `block-num-check-free-size` | `1000` | Check free space every N blocks | -| `flush-state-interval` | `10000` | Flush shared memory to disk every N blocks | -| `single-write-thread` | `false` | Push blocks/transactions from one thread | -| `skip-virtual-ops` | `false` | Skip virtual operations (saves memory) | -| `enable-plugins-on-push-transaction` | `false` | Notify plugins on push_transaction | -| `dlt-block-log-max-blocks` | `100000` | Blocks to keep in the DLT rolling block_log | - ---- - -### `json_rpc` -**Status:** Active (Required) -**Category:** Core -**Dependencies:** None - -Provides the JSON-RPC 2.0 framework for API method registration and dispatching. - -**Purpose:** -- Registers API methods from all plugins -- Parses JSON-RPC requests -- Dispatches to appropriate handlers -- Returns formatted responses - -**JSON-RPC:** None (framework only) - ---- - -### `webserver` -**Status:** Active (Required for API access) -**Category:** Infrastructure -**Dependencies:** `json_rpc` - -HTTP/WebSocket server that accepts JSON-RPC requests with built-in response caching. - -**Purpose:** -- Serves HTTP and WebSocket connections -- Routes requests to `json_rpc` plugin -- Handles CORS, timeouts, connection limits -- Caches read-only JSON-RPC responses with id-independent cache keys -- Patches response IDs to match request IDs per JSON-RPC 2.0 spec -- Clears cache on each new block to maintain consistency -- Filters out mutating APIs (`network_broadcast_api.*`, `debug_node.*`) from cache - -**JSON-RPC:** None (transport only) - -**Config options:** -```ini -webserver-http-endpoint = 0.0.0.0:8090 -webserver-ws-endpoint = 0.0.0.0:8091 -webserver-thread-pool-size = 32 -webserver-cache-enabled = true -webserver-cache-size = 10000 -``` - -**Cache behavior:** -- Cache keys are derived from `method` + `params` only (excluding `id`), preventing bypass via ID rotation spam -- Uses `fc::json::from_string` for robust JSON parsing — invalid JSON bypasses cache -- Mutating APIs are detected in both direct (`"method":"network_broadcast_api.xxx"`) and call-style (`"method":"call","params":["network_broadcast_api",...]`) formats -- Cached responses have their `id` field patched before sending to match the client's request ID - ---- - -### `p2p` -**Status:** Active (Required for network sync) -**Category:** Infrastructure -**Dependencies:** `chain` - -Peer-to-peer networking for block and transaction propagation. - -**Purpose:** -- Discovers and connects to peers -- Syncs blockchain from the network -- Broadcasts blocks and transactions -- Maintains peer database -- Minority fork auto-recovery (`resync_from_lib()`) - -**JSON-RPC:** None (internal only) - -**Config options:** -```ini -p2p-endpoint = 0.0.0.0:2001 -p2p-seed-node = seed1.viz.world:2001 -p2p-max-connections = 200 -p2p-stats-enabled = true -p2p-stats-interval = 300 -p2p-stale-sync-detection = false -p2p-stale-sync-timeout-seconds = 120 -``` - -**P2P stats task:** When `p2p-stats-enabled = true`, every `p2p-stats-interval` seconds the plugin logs: -- Per-peer stats (IP, port, latency, bytes received, blocked status) -- Failed/rejected peers from the peer database -- **Block storage diagnostics:** head, LIB, earliest available block, DLT block log range, regular block log end, fork_db linked/unlinked counts and ranges, DLT mode flag, and total `resize()` count -- In DLT mode, also runs `dlt_block_log::verify_mapping()` to detect and self-heal stale memory-mapped file state - -**Minority fork auto-recovery:** The P2P plugin exposes `resync_from_lib()` which is called by the Validator Plugin when a minority fork is detected (last 21 blocks all from our own validators). It pops all reversible blocks back to LIB, resets fork_db, re-initiates P2P sync, and reconnects seed nodes. This replicates the effect of a manual node restart. See [fork-collision-hardfork-proposal.md](fork-collision-hardfork-proposal.md) for details. - -**Post-snapshot `trigger_resync()`:** The P2P plugin exposes `trigger_resync()` which is called by the snapshot plugin after a hot-reload (snapshot import while the node is running). It re-initiates P2P sync from the new head block so the P2P layer picks up the chain state change. Without this, the P2P layer would continue advertising stale block IDs. - -**Sync deadlock prevention:** Two mechanisms prevent the P2P sync from stalling permanently: - -1. **Early inventory-mode transition (`remaining == 0`):** When the master responds to a peer's `fetch_blockchain_item_ids` request, it checks `total_remaining_item_count`. If `remaining == 0` (all blocks sent in this reply), the master sets `peer_needs_sync_items_from_us = false` immediately, enabling inventory advertisements. This prevents an infinite chase loop where the peer is almost caught up but the master keeps producing blocks faster than the sync round-trips can converge — especially on live chains with `deferred_resize_exception` slowing the peer. - -2. **Auto-clear safety net (30-second timeout):** In `terminate_inactive_connections_loop`, if `peer_needs_sync_items_from_us` has been `true` for >30 seconds without the peer sending any `fetch_blockchain_item_ids` request, the flag is force-cleared. This handles edge cases where the sync state becomes inconsistent (e.g., `deferred_resize_exception` prevents the seed from sending the final synopsis that would normally clear the flag). The `last_peer_sync_request_time` field on `peer_connection` tracks the last request time. - -**DEFERRED_RESIZE diagnostic logging:** When `deferred_resize_exception` interrupts sync block processing, diagnostic messages (`DEFERRED_RESIZE:`) are logged via the sync logger, including the deferred block number and the subsequent sync restart. This helps diagnose stalls caused by shared memory resizes during catch-up. - ---- - -### `validator` -**Status:** Active -**Category:** Producer -**Dependencies:** `chain`, `p2p` - -Block production and validator scheduling. - -**Purpose:** -- Produces blocks when scheduled -- Manages validator signing keys -- Detects fork collisions and defers production -- Detects minority fork (last 21 blocks all from own validators) and triggers auto-recovery -- Supports emergency consensus block production - -**JSON-RPC:** None (internal only) - -**Config options:** -```ini -validator = "mywitness" -private-key = 5K... -enable-stale-production = false -required-participation = 3300 -fork-collision-timeout-blocks = 21 -``` - -| Option | Default | Description | -|---|---|---| -| `validator` | (none) | validator account name(s) to produce blocks for | -| `private-key` | (none) | WIF private key(s) for block signing | -| `emergency-private-key` | (none) | WIF key for emergency consensus production | -| `enable-stale-production` | `false` | Allow production even if chain is stale or on a minority fork | -| `required-participation` | `3300` (33%) | Minimum validator participation rate (basis points) | -| `fork-collision-timeout-blocks` | `21` | Deferrals before forcing production past a fork collision | - -**Minority fork detection:** Before producing a block, the Validator Plugin walks the last `CHAIN_MAX_WITNESSES` (21) blocks in fork_db. If ALL were produced by the node's own configured validators, the node is stuck on a minority fork. With `enable-stale-production=false` (default), the plugin calls `p2p.resync_from_lib()` to pop back to LIB and resync. With `enable-stale-production=true`, production continues (for bootstrap/testnet scenarios). Detection is skipped during emergency consensus mode. - -**Emergency consensus:** When `emergency-private-key` is configured, the committee account is added to the validator set. During emergency consensus mode (`dgp.emergency_consensus_active`), the node produces blocks using the committee account's schedule. - -See [block-processing.md](block-processing.md) for production timing details and [fork-collision-hardfork-proposal.md](fork-collision-hardfork-proposal.md) for fork handling. - ---- - -### `snapshot` -**Status:** Active -**Category:** Infrastructure -**Dependencies:** `chain` - -Snapshot creation, loading, and P2P sync for fast node bootstrap and crash recovery in DLT mode. - -**Purpose:** -- Create JSON snapshots of blockchain state -- Load state from snapshots (near-instant startup) -- Serve snapshots to other nodes over TCP -- Download snapshots from trusted peers -- Crash recovery via snapshot + dlt_block_log replay -- Detect stale snapshots at startup (snapshot block < DLT start block) and create urgent fresh snapshots - -**JSON-RPC:** None - -**Non-blocking snapshot creation:** Snapshot creation runs asynchronously on a dedicated background thread. Only the database read phase (serialization) holds a read lock (~1 second); compression and file I/O run without any lock. This eliminates read-lock timeouts and `unlinkable_block_exception` errors that occurred when snapshots ran synchronously inside the write-lock scope. - -**CLI options:** -| Option | Type | Description | -|--------|------|-------------| -| `--snapshot ` | `string` | Load state from a snapshot file (DLT mode) | -| `--snapshot-auto-latest` | `bool` | Auto-discover latest snapshot in `snapshot-dir` | -| `--replay-from-snapshot` | `bool` | Crash recovery: import snapshot + replay dlt_block_log | -| `--auto-recover-from-snapshot` | `bool` (default: `true`) | Automatic runtime recovery from shared memory corruption | -| `--create-snapshot ` | `string` | Create a snapshot and exit | -| `--sync-snapshot-from-trusted-peer` | `bool` | Download snapshot from trusted peers on empty state | - -**Config options:** -```ini -snapshot-dir = /data/snapshots -snapshot-every-n-blocks = 28800 -snapshot-max-age-days = 90 -allow-snapshot-serving = false -trusted-snapshot-peer = seed1.viz.world:8092 -dlt-block-log-max-blocks = 100000 -``` - -See [snapshot-plugin.md](snapshot-plugin.md) for full documentation. - ---- - -## API Plugins - -### `database_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Primary read API for blockchain state queries. - -**Purpose:** -- Query blocks, transactions, accounts -- Query chain properties, hardfork status -- Validate transactions and signatures -- Query escrows, delegations, proposals - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `database_api.get_block_header` | Get block header by height | -| `database_api.get_block` | Get full signed block | -| `database_api.get_irreversible_block_header` | Get irreversible block header | -| `database_api.get_irreversible_block` | Get irreversible block | -| `database_api.set_block_applied_callback` | Subscribe to new blocks | -| `database_api.get_config` | Get compile-time chain constants | -| `database_api.get_dynamic_global_properties` | Get current chain state | -| `database_api.get_chain_properties` | Get median validator properties | -| `database_api.get_hardfork_version` | Get current hardfork version | -| `database_api.get_next_scheduled_hardfork` | Get next hardfork info | -| `database_api.get_accounts` | Get accounts by names | -| `database_api.lookup_account_names` | Lookup accounts (nullable) | -| `database_api.lookup_accounts` | List accounts by prefix | -| `database_api.get_account_count` | Get total account count | -| `database_api.get_master_history` | Get account master key history | -| `database_api.get_recovery_request` | Get pending recovery request | -| `database_api.get_escrow` | Get escrow by ID | -| `database_api.get_withdraw_routes` | Get vesting withdraw routes | -| `database_api.get_vesting_delegations` | Get active delegations | -| `database_api.get_expiring_vesting_delegations` | Get expiring delegations | -| `database_api.get_transaction_hex` | Get transaction as hex | -| `database_api.get_required_signatures` | Get required signatures | -| `database_api.get_potential_signatures` | Get all potential signers | -| `database_api.verify_authority` | Verify transaction authority | -| `database_api.verify_account_authority` | Verify account authority | -| `database_api.get_database_info` | Get database statistics | -| `database_api.get_proposed_transactions` | Get proposals for account | -| `database_api.get_accounts_on_sale` | List accounts for sale | -| `database_api.get_accounts_on_auction` | List accounts on auction | -| `database_api.get_subaccounts_on_sale` | List subaccounts for sale | - ---- - -### `network_broadcast_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain`, `p2p` - -Broadcasts transactions and blocks to the network. - -**Purpose:** -- Broadcast signed transactions -- Broadcast signed blocks (for validators) -- Synchronous transaction confirmation - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `network_broadcast_api.broadcast_transaction` | Broadcast transaction (async) | -| `network_broadcast_api.broadcast_transaction_synchronous` | Broadcast and wait for inclusion | -| `network_broadcast_api.broadcast_transaction_with_callback` | Broadcast with callback | -| `network_broadcast_api.broadcast_block` | Broadcast a signed block | - ---- - -### `witness_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Query validator information. - -**Purpose:** -- List active/scheduled validators -- Query validator by account or vote rank -- Get validator schedule - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `witness_api.get_active_witnesses` | Get current active validator set | -| `witness_api.get_witness_schedule` | Get validator schedule object | -| `witness_api.get_witnesses` | Get validators by IDs | -| `witness_api.get_witness_by_account` | Get validator by account name | -| `witness_api.get_witnesses_by_vote` | Get validators ranked by votes | -| `witness_api.get_witnesses_by_counted_vote` | Get validators by counted votes | -| `witness_api.get_witness_count` | Get total validator count | -| `witness_api.lookup_witness_accounts` | List validator accounts by prefix | - ---- - -### `account_by_key` -**Status:** Active -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain` - -Indexes accounts by their public keys for reverse lookup. - -**Purpose:** -- Find accounts that use a given public key -- Useful for wallet applications - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `account_by_key.get_key_references` | Get accounts using given public keys | - ---- - -### `account_history` -**Status:** Active -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain`, `operation_history` - -Indexes operation history per account. - -**Purpose:** -- Query operation history for a specific account -- Paginated access to account activity - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `account_history.get_account_history` | Get operations for an account | - -#### `get_account_history` - -**Parameters:** - -| # | Name | Type | Description | -|---|---|---|---| -| 1 | `account` | string | Account name to query | -| 2 | `from` | uint32 | Starting sequence number, or `-1` for newest | -| 3 | `limit` | uint32 | Max entries to return (1-1000) | - -**Behavior:** -- `from = -1` (or `4294967295`): Start from the most recent operation -- Returns entries in descending order (newest first) -- If `limit` exceeds available entries, returns all available without error -- Example: Account has 5 entries, request `from=-1, limit=10` → returns all 5 entries - -**Request:** -```json -{ - "jsonrpc": "2.0", - "method": "account_history.get_account_history", - "params": ["on1x", -1, 10], - "id": 1 -} -``` - -**Response:** -```json -{ - "jsonrpc": "2.0", - "result": { - "4": {"trx_id": "abc...", "block": 1234, "op": [...]}, - "3": {"trx_id": "def...", "block": 1233, "op": [...]}, - "2": {"trx_id": "ghi...", "block": 1232, "op": [...]} - }, - "id": 1 -} -``` - -**Config options:** -```ini -track-account-range = ["", "zzzzzzzzzzzzzzzz"] -history-count-blocks = 4294967295 -``` - -**Memory Management:** -- Old history entries are automatically purged based on `history-count-blocks` -- Coordinates with `operation_history` plugin to avoid dangling references -- Uses the more aggressive purge threshold between both plugins -- Signal handlers are properly disconnected on shutdown to prevent memory leaks - ---- - -### `operation_history` -**Status:** Active -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain` - -Indexes all operations in blocks. - -**Purpose:** -- Query operations within a block -- Lookup transactions by ID -- Provides base operation storage for `account_history` plugin - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `operation_history.get_ops_in_block` | Get operations in a block | -| `operation_history.get_transaction` | Get transaction by ID | - -**Config options:** -```ini -history-whitelist-ops = [] # Only store these operations (exclusive with blacklist) -history-blacklist-ops = [] # Don't store these operations -history-start-block = 0 # Start recording from this block -history-count-blocks = 4294967295 # How many blocks of history to keep -``` - -**Memory Management:** -- Old operations are automatically purged based on `history-count-blocks` -- `account_history` plugin coordinates purging with this plugin -- Signal handlers are properly disconnected on shutdown to prevent memory leaks -- Exposes `get_min_keep_block()` for dependent plugins to coordinate purging - ---- - -### `committee_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Query committee worker requests. - -**Purpose:** -- Get committee request details -- List all committee requests -- Get votes on requests - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `committee_api.get_committee_request` | Get request by ID | -| `committee_api.get_committee_request_votes` | Get votes on a request | -| `committee_api.get_committee_requests_list` | List all request IDs | - ---- - -### `invite_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Query invite codes. - -**Purpose:** -- List active invites -- Lookup invite by ID or public key - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `invite_api.get_invites_list` | List all invite IDs | -| `invite_api.get_invite_by_id` | Get invite by database ID | -| `invite_api.get_invite_by_key` | Get invite by public key | - ---- - -### `paid_subscription_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Query paid subscriptions. - -**Purpose:** -- List subscription offerings -- Check subscription status between accounts - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `paid_subscription_api.get_paid_subscriptions` | List all subscription offerings | -| `paid_subscription_api.get_paid_subscription_options` | Get subscription config for account | -| `paid_subscription_api.get_paid_subscription_status` | Get subscription status subscriber→account | -| `paid_subscription_api.get_active_paid_subscriptions` | List active subscriptions for subscriber | -| `paid_subscription_api.get_inactive_paid_subscriptions` | List expired subscriptions | - ---- - -### `follow` -**Status:** Deprecated -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain` - -Indexes follow relationships and content feeds. - -**Purpose:** -- Track followers/following -- Build personalized feeds -- Track reblogs - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `follow.get_followers` | Get followers of an account | -| `follow.get_following` | Get accounts followed by an account | -| `follow.get_follow_count` | Get follower/following counts | -| `follow.get_feed_entries` | Get feed entries (references only) | -| `follow.get_feed` | Get feed with full content | -| `follow.get_blog_entries` | Get blog entries (references) | -| `follow.get_blog` | Get blog with full content | -| `follow.get_reblogged_by` | Get accounts that reblogged content | -| `follow.get_blog_authors` | Get authors reblogged on a blog | - ---- - -### `tags` -**Status:** Deprecated -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain`, `follow` - -Indexes content by tags and provides content discovery. - -**Purpose:** -- Query trending/hot/new content by tag -- Track tag statistics -- Content discovery APIs - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `tags.get_trending_tags` | Get tags sorted by activity | -| `tags.get_tags_used_by_author` | Get tags used by an author | -| `tags.get_discussions_by_trending` | Get trending discussions | -| `tags.get_discussions_by_created` | Get newest discussions | -| `tags.get_discussions_by_active` | Get recently active discussions | -| `tags.get_discussions_by_cashout` | Get discussions by cashout time | -| `tags.get_discussions_by_payout` | Get discussions by payout | -| `tags.get_discussions_by_votes` | Get discussions by vote count | -| `tags.get_discussions_by_children` | Get discussions by reply count | -| `tags.get_discussions_by_hot` | Get hot discussions | -| `tags.get_discussions_by_feed` | Get discussions from feed | -| `tags.get_discussions_by_blog` | Get discussions from blog | -| `tags.get_discussions_by_contents` | Get discussions by content | -| `tags.get_discussions_by_author_before_date` | Get author's posts before date | -| `tags.get_languages` | Get available content languages | - ---- - -### `social_network` -**Status:** Deprecated -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -High-level content and social queries (combines multiple data sources). - -**Purpose:** -- Query content discussions -- Get votes on content -- Committee and invite queries (convenience) - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `social_network.get_content` | Get discussion by author/permlink | -| `social_network.get_content_replies` | Get direct replies | -| `social_network.get_all_content_replies` | Get all nested replies | -| `social_network.get_account_votes` | Get votes cast by account | -| `social_network.get_active_votes` | Get votes on content | -| `social_network.get_replies_by_last_update` | Get replies sorted by update | -| `social_network.get_committee_request` | Get committee request | -| `social_network.get_committee_request_votes` | Get committee request votes | -| `social_network.get_committee_requests_list` | List committee requests | -| `social_network.get_invites_list` | List invites | -| `social_network.get_invite_by_id` | Get invite by ID | -| `social_network.get_invite_by_key` | Get invite by key | - ---- - -### `private_message` -**Status:** Deprecated -**Category:** Index/API -**Dependencies:** `json_rpc`, `chain` - -Indexes encrypted private messages sent via `custom_operation`. - -**Purpose:** -- Track inbox/outbox messages -- Encrypted message protocol support - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `private_message.get_inbox` | Get received messages | -| `private_message.get_outbox` | Get sent messages | - -**Config options:** -```ini -pm-account-range = ["", "zzzzzzzzzzzzzzzz"] -``` - ---- - -### `custom_protocol_api` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Tracks custom protocol sequences from `custom_operation`. - -**Purpose:** -- Get account info with custom protocol metadata -- Useful for apps using custom_operation - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `custom_protocol_api.get_account` | Get account with custom protocol reference | - ---- - -### `auth_util` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Authority verification utilities. - -**Purpose:** -- Check signatures against account authority - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `auth_util.check_authority_signature` | Verify signature satisfies authority | - ---- - -### `block_info` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Detailed block information queries. - -**Purpose:** -- Get extended block information -- Block statistics - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `block_info.get_block_info` | Get block info for range | -| `block_info.get_blocks_with_info` | Get blocks with extended info | - ---- - -### `raw_block` -**Status:** Active -**Category:** API -**Dependencies:** `json_rpc`, `chain` - -Get raw serialized blocks. - -**Purpose:** -- Export blocks in raw binary format -- Useful for block archival/replication - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `raw_block.get_raw_block` | Get raw block by height | - ---- - -## validator/Producer Plugins - -### `validator` -**Status:** Active -**Category:** Core (for block producers) -**Dependencies:** `chain`, `p2p` - -Block production plugin for validators. - -**Purpose:** -- Sign and produce blocks on schedule -- Manage validator private keys - -**JSON-RPC:** None - -**Config options:** -```ini -validator = "your-validator-account" -private-key = 5K... -enable-stale-production = true # Produce blocks even on a stale chain (default: false) -required-participation = 3300 # Min validator participation in basis points to produce (default: 33% = 3300) -``` - -**Bug Fix: `enable-stale-production` and `required-participation` option parsing** - -Two bugs were fixed in the Validator Plugin option definitions ([validator.cpp](../../plugins/validator/validator.cpp)): - -| Bug | Before | After | -|---|---|---| -| `enable-stale-production` used `implicit_value(false)` | `--enable-stale-production` without a value set production to `false` (same as not using the flag at all) | `implicit_value(true)` — using the flag alone now correctly enables stale production | -| `required-participation` used `implicit_value(33)` then multiplied by `CHAIN_1_PERCENT` | Config file value `required-participation = 50` was interpreted as 50×100=5000 basis points (500%) | Now uses `default_value(33 * CHAIN_1_PERCENT)` and reads the raw value directly — config value is in basis points | - -The `required-participation` value is now always in **basis points** (0–10000 = 0%–100%): -- Default: `3300` = 33% -- Config: `required-participation = 5000` = 50% -- CLI: `--required-participation 5000` = 50% - -**Optimization: Block Production Timing** - -The Validator Plugin's production loop uses a timer + look-ahead mechanism to determine when to produce a block. The timer ticks at regular intervals and the look-ahead shifts `now` forward so the slot boundary is detected earlier. - -Source: [validator.cpp](../../plugins/validator/validator.cpp) — `schedule_production_loop()`, `maybe_produce_block()` - -| Parameter | Value | Meaning | -|---|---|---| -| Timer tick interval | 250ms | How often the production loop wakes up | -| Look-ahead | +250ms | `now = ntp_time + 250ms` — shifts current time forward | -| Lag threshold | 500ms | If `|scheduled_time - now| > 500ms`, block is NOT produced (LAG condition) | - -The look-ahead compensates for OS timer jitter. With 250ms ticks + 250ms look-ahead, the tick at `T_slot - 250ms` aligns `now` exactly to the slot boundary, achieving near-zero-lag production: - -``` -Slot at T=6.000: - Tick at T=5.750 → now=6.000 → slot matched → lag=0ms → PRODUCE -``` - -If the tick fires late (OS jitter), the next tick 250ms later still has comfortable margin: -``` - Tick at T=6.000 → now=6.250 → lag=250ms → PRODUCE (within 500ms threshold) - Tick at T=6.250 → now=6.500 → lag=500ms → borderline LAG -``` - -**Previous behavior** (before optimization): 1000ms tick + 500ms look-ahead → best-case lag was 500ms (exactly at the threshold), and even 50ms of OS jitter caused a LAG condition. - ---- - -## Debug/Test Plugins - -### `debug_node` -**Status:** Active (Development only) -**Category:** Debug -**Dependencies:** `chain` - -Development and testing utilities. **NOT for production use.** - -**Purpose:** -- Generate test blocks -- Push blocks from files -- Set hardforks manually - -**JSON-RPC Methods:** - -| Method | Description | -|---|---| -| `debug_node.debug_generate_blocks` | Generate N test blocks | -| `debug_node.debug_generate_blocks_until` | Generate blocks until time | -| `debug_node.debug_push_blocks` | Push blocks from database | -| `debug_node.debug_push_json_blocks` | Push blocks from JSON file | -| `debug_node.debug_pop_block` | Pop and return last block | -| `debug_node.debug_get_witness_schedule` | Get validator schedule | -| `debug_node.debug_set_hardfork` | Force set hardfork | -| `debug_node.debug_has_hardfork` | Check if hardfork applied | - ---- - -### `test_api` -**Status:** Active (Testing only) -**Category:** Test -**Dependencies:** `json_rpc` - -Test API plugin for connectivity testing. - -**JSON-RPC Methods:** None documented (internal testing) - ---- - -## External Integration Plugins - -### `mongo_db` -**Status:** Active -**Category:** External -**Dependencies:** `chain` - -Exports blockchain data to MongoDB. - -**Purpose:** -- Real-time export of blocks, transactions, operations -- Enable MongoDB-based queries and analytics - -**JSON-RPC:** None - -**Config options:** -```ini -mongodb-uri = mongodb://localhost:27017 -mongodb-db-name = viz -``` - ---- - -## Plugin Status Summary - -| Plugin | Status | Has API | Category | -|---|---|---|---| -| `chain` | Active | No | Core | -| `json_rpc` | Active | No | Core | -| `webserver` | Active | No | Infrastructure | -| `p2p` | Active | No | Infrastructure | -| `snapshot` | Active | No | Infrastructure | -| `database_api` | Active | Yes | API | -| `network_broadcast_api` | Active | Yes | API | -| `witness_api` | Active | Yes | API | -| `account_by_key` | Active | Yes | Index/API | -| `account_history` | Active | Yes | Index/API | -| `operation_history` | Active | Yes | Index/API | -| `committee_api` | Active | Yes | API | -| `invite_api` | Active | Yes | API | -| `paid_subscription_api` | Active | Yes | API | -| `follow` | Deprecated | Yes | Index/API | -| `tags` | Deprecated | Yes | Index/API | -| `social_network` | Deprecated | Yes | API | -| `private_message` | Deprecated | Yes | Index/API | -| `custom_protocol_api` | Active | Yes | API | -| `auth_util` | Active | Yes | API | -| `block_info` | Active | Yes | API | -| `raw_block` | Active | Yes | API | -| `validator` | Active | No | Producer | -| `debug_node` | Dev only | Yes | Debug | -| `test_api` | Test only | Yes | Test | -| `mongo_db` | Active | No | External | - ---- - -## JSON-RPC Quick Reference - -All methods use JSON-RPC 2.0 format: - -```json -{ - "jsonrpc": "2.0", - "method": "api_name.method_name", - "params": {}, - "id": 1 -} -``` - -### Complete API Method Index - -| API | Method | Description | -|---|---|---| -| `database_api` | `get_block_header` | Block header by height | -| `database_api` | `get_block` | Full block by height | -| `database_api` | `get_irreversible_block_header` | Irreversible block header | -| `database_api` | `get_irreversible_block` | Irreversible block | -| `database_api` | `set_block_applied_callback` | Subscribe to blocks | -| `database_api` | `get_config` | Chain constants | -| `database_api` | `get_dynamic_global_properties` | Current chain state | -| `database_api` | `get_chain_properties` | Median validator props | -| `database_api` | `get_hardfork_version` | Current HF version | -| `database_api` | `get_next_scheduled_hardfork` | Next HF info | -| `database_api` | `get_accounts` | Accounts by names | -| `database_api` | `lookup_account_names` | Lookup accounts | -| `database_api` | `lookup_accounts` | List accounts | -| `database_api` | `get_account_count` | Total accounts | -| `database_api` | `get_master_history` | Key history | -| `database_api` | `get_recovery_request` | Recovery request | -| `database_api` | `get_escrow` | Escrow by ID | -| `database_api` | `get_withdraw_routes` | Withdraw routes | -| `database_api` | `get_vesting_delegations` | Delegations | -| `database_api` | `get_expiring_vesting_delegations` | Expiring delegations | -| `database_api` | `get_transaction_hex` | TX as hex | -| `database_api` | `get_required_signatures` | Required sigs | -| `database_api` | `get_potential_signatures` | Potential signers | -| `database_api` | `verify_authority` | Verify TX auth | -| `database_api` | `verify_account_authority` | Verify account auth | -| `database_api` | `get_database_info` | DB stats | -| `database_api` | `get_proposed_transactions` | Proposals | -| `database_api` | `get_accounts_on_sale` | Accounts for sale | -| `database_api` | `get_accounts_on_auction` | Accounts on auction | -| `database_api` | `get_subaccounts_on_sale` | Subaccounts for sale | -| `network_broadcast_api` | `broadcast_transaction` | Broadcast TX | -| `network_broadcast_api` | `broadcast_transaction_synchronous` | Broadcast TX (sync) | -| `network_broadcast_api` | `broadcast_transaction_with_callback` | Broadcast TX (callback) | -| `network_broadcast_api` | `broadcast_block` | Broadcast block | -| `witness_api` | `get_active_witnesses` | Active validators | -| `witness_api` | `get_witness_schedule` | validator schedule | -| `witness_api` | `get_witnesses` | validators by ID | -| `witness_api` | `get_witness_by_account` | validator by account | -| `witness_api` | `get_witnesses_by_vote` | validators by votes | -| `witness_api` | `get_witnesses_by_counted_vote` | validators by counted votes | -| `witness_api` | `get_witness_count` | validator count | -| `witness_api` | `lookup_witness_accounts` | List validators | -| `account_by_key` | `get_key_references` | Accounts by key | -| `account_history` | `get_account_history` | Account operations | -| `operation_history` | `get_ops_in_block` | Block operations | -| `operation_history` | `get_transaction` | TX by ID | -| `committee_api` | `get_committee_request` | Request by ID | -| `committee_api` | `get_committee_request_votes` | Request votes | -| `committee_api` | `get_committee_requests_list` | All requests | -| `invite_api` | `get_invites_list` | All invites | -| `invite_api` | `get_invite_by_id` | Invite by ID | -| `invite_api` | `get_invite_by_key` | Invite by key | -| `paid_subscription_api` | `get_paid_subscriptions` | All subscriptions | -| `paid_subscription_api` | `get_paid_subscription_options` | Subscription config | -| `paid_subscription_api` | `get_paid_subscription_status` | Subscription status | -| `paid_subscription_api` | `get_active_paid_subscriptions` | Active subscriptions | -| `paid_subscription_api` | `get_inactive_paid_subscriptions` | Inactive subscriptions | -| `follow` | `get_followers` | Followers | -| `follow` | `get_following` | Following | -| `follow` | `get_follow_count` | Follow counts | -| `follow` | `get_feed_entries` | Feed entries | -| `follow` | `get_feed` | Feed content | -| `follow` | `get_blog_entries` | Blog entries | -| `follow` | `get_blog` | Blog content | -| `follow` | `get_reblogged_by` | Rebloggers | -| `follow` | `get_blog_authors` | Blog authors | -| `tags` | `get_trending_tags` | Trending tags | -| `tags` | `get_tags_used_by_author` | Author's tags | -| `tags` | `get_discussions_by_trending` | Trending posts | -| `tags` | `get_discussions_by_created` | New posts | -| `tags` | `get_discussions_by_active` | Active posts | -| `tags` | `get_discussions_by_cashout` | Posts by cashout | -| `tags` | `get_discussions_by_payout` | Posts by payout | -| `tags` | `get_discussions_by_votes` | Posts by votes | -| `tags` | `get_discussions_by_children` | Posts by replies | -| `tags` | `get_discussions_by_hot` | Hot posts | -| `tags` | `get_discussions_by_feed` | Feed posts | -| `tags` | `get_discussions_by_blog` | Blog posts | -| `tags` | `get_discussions_by_contents` | Content posts | -| `tags` | `get_discussions_by_author_before_date` | Author posts | -| `tags` | `get_languages` | Languages | -| `social_network` | `get_content` | Discussion | -| `social_network` | `get_content_replies` | Replies | -| `social_network` | `get_all_content_replies` | All replies | -| `social_network` | `get_account_votes` | Account's votes | -| `social_network` | `get_active_votes` | Votes on content | -| `social_network` | `get_replies_by_last_update` | Replies by update | -| `private_message` | `get_inbox` | Inbox | -| `private_message` | `get_outbox` | Outbox | -| `custom_protocol_api` | `get_account` | Account + custom | -| `auth_util` | `check_authority_signature` | Check sig | -| `block_info` | `get_block_info` | Block info | -| `block_info` | `get_blocks_with_info` | Blocks + info | -| `raw_block` | `get_raw_block` | Raw block | -| `debug_node` | `debug_generate_blocks` | Generate blocks | -| `debug_node` | `debug_generate_blocks_until` | Generate until | -| `debug_node` | `debug_push_blocks` | Push blocks | -| `debug_node` | `debug_push_json_blocks` | Push JSON blocks | -| `debug_node` | `debug_pop_block` | Pop block | -| `debug_node` | `debug_get_witness_schedule` | validator schedule | -| `debug_node` | `debug_set_hardfork` | Set hardfork | -| `debug_node` | `debug_has_hardfork` | Check hardfork | - ---- - -## Recommended Plugin Sets - -### Minimal API Node -```ini -plugin = chain -plugin = json_rpc -plugin = webserver -plugin = p2p -plugin = database_api -plugin = network_broadcast_api -``` - -### Full API Node -```ini -plugin = chain -plugin = json_rpc -plugin = webserver -plugin = p2p -plugin = database_api -plugin = network_broadcast_api -plugin = witness_api -plugin = account_by_key -plugin = account_history -plugin = operation_history -plugin = committee_api -plugin = invite_api -plugin = paid_subscription_api -plugin = follow -plugin = tags -plugin = social_network -plugin = private_message -``` - -### validator Node -```ini -plugin = chain -plugin = p2p -plugin = validator -plugin = json_rpc -plugin = webserver -plugin = database_api -plugin = network_broadcast_api -plugin = witness_api -plugin = snapshot - -snapshot-every-n-blocks = 28800 -snapshot-dir = /data/snapshots -dlt-block-log-max-blocks = 100000 -``` diff --git a/.qoder/docs/shared-memory.md b/.qoder/docs/shared-memory.md deleted file mode 100644 index 8d9e50d923..0000000000 --- a/.qoder/docs/shared-memory.md +++ /dev/null @@ -1,499 +0,0 @@ -# Shared Memory Architecture - -The VIZ node stores all blockchain state in a memory-mapped file (`shared_memory.bin`) managed by the **chainbase** library, which wraps Boost.Interprocess `managed_mapped_file`. This is the sole database for chain state — the node **cannot operate without shared memory**. - ---- - -## Overview - -``` -┌─────────────────────────────────────────────────────────────┐ -│ vizd process │ -│ │ -│ ┌──────────────┐ ┌──────────────────────────────────┐ │ -│ │ block_log │ │ shared_memory.bin (mmap) │ │ -│ │ dlt_block_log│ │ │ │ -│ │ (raw blocks) │ │ ┌────────────────────────────┐ │ │ -│ │ │ │ │ chainbase::database │ │ │ -│ └──────┬───────┘ │ │ ┌──────────────────────┐ │ │ │ -│ │ │ │ │ account_index │ │ │ │ -│ │ replay/ │ │ │ witness_index │ │ │ │ -│ │ sync │ │ │ transaction_index │ │ │ │ -│ ▼ │ │ │ ... (all objects) │ │ │ │ -│ ┌──────────────┐ │ │ └──────────────────────┘ │ │ │ -│ │ database │────▶ │ boost::shared_mutex _mutex│ │ │ -│ │ (chainbase) │ │ └────────────────────────────┘ │ │ -│ └──────────────┘ └──────────────────────────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────────────────────────┐ │ -│ │ API threads │────▶│ read_lock (shared, multiple) │ │ -│ │ (webserver │ │ write_lock (exclusive) │ │ -│ │ pool=256) │ └──────────────────────────────────┘ │ -│ └──────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -### Key Source Files - -| File | Role | -|------|------| -| `thirdparty/chainbase/include/chainbase/chainbase.hpp` | Core chainbase database class, lock wrappers, index types | -| `thirdparty/chainbase/src/chainbase.cpp` | `open()`, `close()`, `resize()`, `flush()`, `wipe()` implementations | -| `libraries/chain/database.cpp` | Chain-level `open()`, `_resize()`, `check_free_memory()`, `push_block()`, `_generate_block()` | -| `libraries/chain/include/graphene/chain/database.hpp` | Chain database class declaration, resize/memory parameters | -| `plugins/chain/plugin.cpp` | Config option definitions, initialization, snapshot loading | -| `plugins/validator/validator.cpp` | Lockless reads in `maybe_produce_block()` and `is_witness_scheduled_soon()`, guarded by `operation_guard` | -| `plugins/p2p/p2p_plugin.cpp` | Lockless reads in block post-validation (`get_witness_key()`), guarded by `operation_guard` | - ---- - -## Memory-Mapped File Internals - -### File Format - -The `shared_memory.bin` file is a Boost.Interprocess `managed_mapped_file`: - -- **On create**: file is allocated at `shared-file-size` bytes, OS maps it into process address space -- **On open (write)**: if file exists and `shared-file-size` > current size, `managed_mapped_file::grow()` extends it -- **On open (read-only)**: mapped read-only, no growth possible -- **File lock**: when opened for writing, a `boost::interprocess::file_lock` ensures **only one process** can write - -### Internal Structure - -All chainbase objects (accounts, validators, transactions, etc.) are stored as C++ objects allocated inside the mapped segment using Boost.Interprocess allocators: - -```cpp -template -using allocator = boost::interprocess::allocator; - -using shared_string = boost::interprocess::basic_string, allocator>; -``` - -Objects are organized into **indices** (Boost.MultiIndex containers) that live inside the mapped segment. Pointers within these structures are **offset-based** (managed by the segment manager), which is why the file can be re-mapped at a different virtual address and still function — provided the remapping is done correctly. - ---- - -## Locking Model - -### Lock Types - -Chainbase uses a single `boost::shared_mutex _mutex` per database instance: - -| Lock Type | Wrapper Method | Concurrency | -|-----------|---------------|-------------| -| **Read lock** (`boost::shared_lock`) | `with_read_lock()`, `with_weak_read_lock()`, `with_strong_read_lock()` | Multiple readers can hold simultaneously | -| **Write lock** (`boost::unique_lock`) | `with_write_lock()`, `with_weak_write_lock()`, `with_strong_write_lock()` | Exclusive — blocks all readers AND other writers | - -### Lock Variants - -| Variant | Wait Time | Retries | Use Case | -|---------|-----------|---------|----------| -| **weak** | `_read_wait_micro` / `_write_wait_micro` (default 500ms) | `_max_read_wait_retries` / `_max_write_wait_retries` (default 3) | Normal API calls | -| **strong** | 1,000,000 μs (1 sec) | 100,000 | Critical operations (block apply, genesis init, replay) | - -### Read Lock Guarantees - -A read lock guarantees that **no write lock is held at the moment of acquisition** and that **no write lock can be acquired while any read lock is held**. However: - -- A pending write lock request will **block** new read lock acquisitions (writer priority prevents starvation) -- The read lock does **not** prevent the segment from being destroyed by `resize()` if the resize happens from the same thread or while no read locks are held - -### Write Lock Behavior - -The write lock is **exclusive**: while held, no other thread can acquire either a read or write lock. All block processing, state modifications, and memory resizing occur under write lock. - ---- - -## Configuration Parameters - -All parameters are defined in `plugins/chain/plugin.cpp` and read from `config.ini`. - -### Size Parameters - -| Parameter | Default | Description | -|-----------|---------|-------------| -| `shared-file-dir` | `state` | Directory for `shared_memory.bin` (relative to data dir or absolute) | -| `shared-file-size` | `2G` | Initial size of the shared memory file. If file exists and this value is larger, the file grows. If smaller, no change. Does **not** require replay. | -| `inc-shared-file-size` | `2G` | Step size for auto-growth. When free space drops below `min-free-shared-file-size`, the file grows by this amount. | -| `min-free-shared-file-size` | `500M` | Free space threshold that triggers auto-growth. | - -### Lock Timeout Parameters - -| Parameter | Default | Description | -|-----------|---------|-------------| -| `read-wait-micro` | `500000` (500ms) | Timeout per read lock acquisition attempt | -| `max-read-wait-retries` | `3` | Maximum read lock retry attempts before throwing `"Unable to acquire READ lock"` | -| `write-wait-micro` | `500000` (500ms) | Timeout per write lock acquisition attempt | -| `max-write-wait-retries` | `3` | Maximum write lock retry attempts before throwing `"Unable to acquire WRITE lock"` | - -### Operational Parameters - -| Parameter | Default | Description | -|-----------|---------|-------------| -| `single-write-thread` | `false` | Serialize all block/transaction pushes through one thread. Reduces write lock contention but limits throughput. | -| `block-num-check-free-size` | `1000` | Check free space in shared memory every N blocks. Lower values = more frequent checks = earlier resize detection but more overhead. | -| `flush-state-interval` | (unset) | Flush shared memory changes to disk every N blocks | -| `clear-votes-before-block` | `0` | Remove votes older than this block number (0 = keep all). Reduces memory usage. | -| `skip-virtual-ops` | `false` | Skip virtual operation plugin notifications. Saves memory and processing. | -| `enable-plugins-on-push-transaction` | `false` | Enable plugin notifications for pushed transactions (not applied blocks). Safe to disable for performance. | - -### Recommended Configurations - -**validator node (production):** -```ini -shared-file-size = 4G -inc-shared-file-size = 2G -min-free-shared-file-size = 500M -block-num-check-free-size = 1000 -single-write-thread = true -``` - -**API node (high read throughput):** -```ini -shared-file-size = 8G -inc-shared-file-size = 2G -min-free-shared-file-size = 500M -block-num-check-free-size = 1000 -single-write-thread = true -read-wait-micro = 1000000 -max-read-wait-retries = 10 -webserver-thread-pool-size = 256 -``` - -**Replay/sync:** -```ini -shared-file-size = 8G -inc-shared-file-size = 4G -min-free-shared-file-size = 500M -block-num-check-free-size = 10 -clear-votes-before-block = 0 -skip-virtual-ops = true -``` - ---- - -## Auto-Resize Workflow - -### Trigger Conditions - -Resize is triggered in two places: - -1. **Periodic check** — `check_free_memory()` called after each `_push_block()` in `push_block()`: - ``` - if (current_block_num % block_num_check_free_size == 0 - && free_memory < min_free_shared_file_size) - → _resize() - ``` - -2. **bad_alloc fallback** — if `_push_block()` throws `boost::interprocess::bad_alloc`: - ``` - catch bad_alloc → set_reserved_memory(free_memory()) → _resize() → retry _push_block() - ``` - -### Resize Sequence - -The resize is implemented in `chainbase::database::resize()` (`thirdparty/chainbase/src/chainbase.cpp`): - -``` -1. Assert no undo sessions active (_undo_session_count == 0) -2. _segment.reset() ← DESTROY the memory mapping -3. open(_data_dir, read_write, new_size) ← Re-open with larger size - ├── managed_mapped_file::grow() ← Extend file on disk - └── new managed_mapped_file(...) ← Re-map into address space -4. _index_list.clear() ← Clear cached index pointers -5. _index_map.clear() -6. for each index_type: - index_type->add_index(*this) ← Rebuild index pointers from new mapping -``` - -### Resize Barrier - -Because `_segment.reset()` invalidates **all** pointers/references into shared memory, the resize must ensure that **no thread** — whether holding a lock or reading locklessly — has any live reference into the mapped segment. A simple write lock is insufficient because several code paths read chainbase indices without holding any lock ("lockless reads"). - -The **resize barrier** (`chainbase::database`) solves this with an atomic operation counter, a flag, and a condition variable: - -``` -┌──────────────────────────────────────────────────────────────────┐ -│ Resize Barrier Protocol │ -│ │ -│ Normal operation: │ -│ enter_operation() ── wait while _resize_in_progress │ -│ ── increment _active_operations │ -│ ... access shared memory ... │ -│ exit_operation() ── decrement _active_operations │ -│ ── notify resize thread if last op │ -│ │ -│ Resize: │ -│ begin_resize_barrier() ── set _resize_in_progress = true │ -│ ── wait until _active_operations == 0 │ -│ ... _segment.reset() + open() + rebuild indices ... │ -│ end_resize_barrier() ── set _resize_in_progress = false │ -│ ── notify all waiting threads │ -└──────────────────────────────────────────────────────────────────┘ -``` - -**Participation points:** - -| Code Path | How It Participates | -|-----------|--------------------| -| `with_read_lock()` / `with_write_lock()` | `operation_guard` acquired automatically inside the lock wrapper before the `boost::shared_mutex` lock | -| `_generate_block()` lockless reads (pre-write-lock) | Explicit scoped `operation_guard` around `get_slot_at_time()`, `get_scheduled_witness()`, `get_witness()`, `find_account()` | -| `_generate_block()` lockless reads (post-write-lock) | Second `operation_guard` (`op_guard2`) around `get_dynamic_global_properties()`, `head_block_id()`, `get_witness()`, `get_hardfork_property_object()`; released via `release()` before `push_block()` | -| Validator Plugin `maybe_produce_block()` | Explicit `operation_guard` around `get_slot_at_time()`, `get_scheduled_witness()`, index lookups; released via `release()` before `generate_block()` | -| Validator Plugin `is_witness_scheduled_soon()` | Explicit `operation_guard` around `get_slot_at_time()`, `get_scheduled_witness()`, index lookups; released via `release()` before return | -| P2P plugin block post-validation | Explicit `operation_guard` around `get_witness_key()` calls; released via `release()` before `apply_block_post_validation()` | - -**Key classes:** - -- `chainbase::database::operation_guard` — RAII guard that calls `enter_operation()` on construction and `exit_operation()` on destruction. Supports early release via `release()`. Move-only (non-copyable). -- `chainbase::database::make_operation_guard()` — Factory method returning an `operation_guard`. -- `chainbase::database::begin_resize_barrier()` / `end_resize_barrier()` — Called by `apply_pending_resize()` to establish exclusive access for the resize. - -**Immediate resize (reindex) does NOT use the barrier.** During reindex, the caller already holds an exclusive write lock and no API threads are running. Using the barrier would deadlock because the write lock itself holds an operation guard. - -### Historical Context: Pre-Barrier Race Condition - -Before the resize barrier was added, the resize used `with_strong_write_lock()` which only blocked threads holding or waiting for a `boost::shared_mutex` lock. This left lockless reads unprotected: - -- `boost::shared_mutex` does **not** protect against segment destruction — a read lock only prevents concurrent writes, but the resize **is** the write -- Threads performing lockless reads (Validator Plugin, `_generate_block()`) could hold stale pointers into the old mapping after `_segment.reset()` - -This was the root cause of shared memory corruption symptoms like `CRITICAL: validator X account object MISSING from database!`. - -### Corruption Symptoms - -Typical corruption indicators (should not occur with the resize barrier in place, but listed for historical reference and diagnostics): - -- `CRITICAL: validator X account object MISSING from database!` — account index entry not found despite `account_index_size` showing entries exist -- `Could not modify object, most likely a uniqueness constraint was violated` — internal index pointers corrupted, uniqueness check fails -- Node crashes and restarts in an infinite loop — each restart opens the corrupted file, fails to produce/apply blocks, crashes again - -### Why Misconfigured Thresholds Make It Worse - -If `min-free-shared-file-size > inc-shared-file-size`: -``` -shared-file-size = 500M -inc-shared-file-size = 500M -min-free-shared-file-size = 1000M ← THRESHOLD > INCREMENT! -``` - -After one resize (500M → 1000M), free space is still below 1000M, triggering **another resize on the next check**, causing cascading resizes. While the resize barrier prevents corruption, frequent resizes still cause latency spikes as all operations are paused during each resize. - ---- - -## Concurrency Architecture - -### Thread Model - -``` -th_0 ─── Main thread: block production loop, block application -th_180+ ─── Webserver thread pool (default 256 threads): JSON-RPC API calls - Each API call acquires read_lock (weak) or write_lock (for broadcast) -th_? ─── P2P thread: block/transaction reception -``` - -### Read Path (API Calls) - -Most `database_api` methods use `with_weak_read_lock()`: - -```cpp -// Example: get_accounts -auto result = with_weak_read_lock([&]() { - // Read from chainbase indices — operation_guard acquired automatically - return accounts; -}); -``` - -If the read lock cannot be acquired within `read-wait-micro × max-read-wait-retries`, the API returns error: `"Unable to acquire READ lock"`. If a resize barrier is active, the `operation_guard` inside `with_weak_read_lock()` will block until the resize completes before attempting the lock. - -### Write Path (Block Application) - -All state modifications go through `with_strong_write_lock()`: - -```cpp -// push_block -apply_pending_resize(); // uses resize barrier (begin/end) -with_strong_write_lock([&]() { // operation_guard acquired inside - _push_block(new_block, skip); - check_free_memory(false, new_block.block_num()); -}); -``` - -### Lockless Reads (Validator Plugin, Block Generation, P2P) - -Some code paths read from chainbase indices **without** holding a `boost::shared_mutex` lock. These must explicitly use an `operation_guard` to participate in the resize barrier: - -```cpp -// validator.cpp — maybe_produce_block() -auto op_guard = db.make_operation_guard(); -uint32_t slot = db.get_slot_at_time(now); // lockless read -string scheduled = db.get_scheduled_witness(slot); // lockless read -// ... more lockless reads ... -op_guard.release(); // release before generate_block() which has its own guard -``` - -```cpp -// validator.cpp — is_witness_scheduled_soon() -auto op_guard = db.make_operation_guard(); -uint32_t slot = db.get_slot_at_time(now); -string scheduled = db.get_scheduled_witness(s); -// ... -op_guard.release(); // release before returning true -``` - -```cpp -// database.cpp — _generate_block() (pre-write-lock reads) -{ - auto op_guard = make_operation_guard(); - uint32_t slot_num = get_slot_at_time(when); - string scheduled_witness = get_scheduled_witness(slot_num); - const auto& witness_obj = get_witness(witness_owner); - const auto* witness_acct = find_account(witness_owner); -} // op_guard released before with_strong_write_lock -``` - -```cpp -// database.cpp — _generate_block() (post-write-lock reads) -auto op_guard2 = make_operation_guard(); -auto maximum_block_size = get_dynamic_global_properties().maximum_block_size; -// ... with_strong_write_lock, then post-lock reads ... -pending_block.previous = head_block_id(); -const auto& validator = get_witness(witness_owner); -const auto& hfp = get_hardfork_property_object(); -const auto& dgp_block = get_dynamic_global_properties(); -op_guard2.release(); // release before push_block() -``` - -```cpp -// p2p_plugin.cpp — block post-validation -auto op_guard = chain.db().make_operation_guard(); -fc::ecc::public_key w_signing_key = chain.db().get_witness_key(account); -op_guard.release(); // release before apply_block_post_validation() -``` - -### single-write-thread Mode - -When `single-write-thread = true`, all `push_block()` and `push_transaction()` calls are serialized through a single `fc::async()` queue. This: - -- Prevents concurrent write lock contention -- Reduces the chance of read lock timeouts for API threads -- Is **recommended for all production nodes** - -When `single-write-thread = false`, blocks and transactions can be pushed from multiple threads simultaneously, causing frequent write lock contention and `"Unable to acquire READ lock"` errors for API clients. - ---- - -## Startup and Recovery - -### Normal Startup - -``` -1. chainbase::database::open(shared_mem_dir, read_write, shared_file_size) - ├── If file exists and shared_file_size > file_size → grow() - ├── Map file into process address space - └── Acquire file lock (exclusive write access) -2. Initialize indices -3. If no dynamic_global_property_object → init_genesis() -4. Open block_log / dlt_block_log -5. undo_all() → rewind to last irreversible block -6. Verify head_block matches block_log -``` - -### Snapshot Import Startup - -``` -1. chainbase::database::wipe(shared_mem_dir) ← Delete old shared memory -2. chainbase::database::open(shared_mem_dir, read_write, shared_file_size) ← Create fresh -3. init_genesis() ← Write genesis state -4. Load snapshot data via callback -5. Replay dlt_block_log blocks on top (if recovery mode) -``` - -### Replay - -``` -1. Open existing shared memory -2. with_strong_write_lock(): - ├── set_reserved_memory(1GB) ← Protect from fragmentation - ├── For each block in block_log: - │ ├── apply_block() - │ └── check_free_memory() ← May trigger _resize() - └── set_reserved_memory(0) -``` - -### Crash Recovery - -If the node crashes due to shared memory corruption: - -1. **Automatic restart** (Docker/systemd) will try to open the corrupted file -2. If the file is corrupted, the node will likely crash again (infinite loop) -3. **Manual recovery options:** - - `--replay-blockchain` — Delete shared memory, replay from block_log - - `--resync-blockchain` — Delete shared memory AND block_log, sync from network - - `--snapshot ` — Load from snapshot file, then replay dlt_block_log - ---- - -## File Layout - -``` -/ -├── shared_memory.bin ← Main memory-mapped file (all chain state) -``` - -The `shared_memory.bin` file size grows in steps of `inc-shared-file-size`. The OS may not actually allocate physical memory until pages are touched (sparse file / lazy allocation), but the virtual address space reservation equals the file size. - -### Size Planning - -Approximate memory usage for a VIZ mainnet node at ~79M blocks: - -| Component | Estimated Size | -|-----------|---------------| -| Account index (~14K accounts) | ~50 MB | -| validator index | ~5 MB | -| Transaction history (operation_history plugin) | ~200–500 MB | -| Account history (account_history plugin) | ~100–300 MB | -| Follow/social indexes | ~50–100 MB | -| Other indexes | ~100–200 MB | -| **Total recommended starting size** | **4–8 GB** | - ---- - -## Diagnostic Commands - -### Check shared memory file size -```bash -ls -lh /var/lib/vizd/blockchain/shared_memory.bin -``` - -### Monitor free memory (from logs) -``` -Free memory is now XmM -Memory is almost full on block N, increasing to XmM -``` - -### Detect corruption -``` -CRITICAL: validator X account object MISSING from database! -Could not modify object, most likely a uniqueness constraint was violated -``` - -### Lock timeout monitoring -``` -Read lock timeout -No more retries for read lock -Write lock timeout -FATAL write lock timeout!!! -``` - ---- - -## Safety Rules - -1. **`min-free-shared-file-size` must be less than `inc-shared-file-size`** — otherwise cascading resizes occur, causing frequent operation pauses -2. **Pre-allocate generously** — set `shared-file-size` large enough that resize is rare. Each resize pauses all operations while the segment is remapped. -3. **Use `single-write-thread = true`** in production — prevents write lock contention -4. **Avoid resize during validator production** — a validator node should have enough pre-allocated memory that resize never triggers during block generation. The resize barrier guarantees safety but introduces latency. -5. **After corruption, always replay** — there is no safe way to repair a corrupted `shared_memory.bin`. Use `--replay-blockchain` or `--snapshot` to rebuild state from block_log/dlt_block_log. -6. **Backup before config changes** — changing `shared-file-size` to a larger value triggers `grow()` on next startup, which is safe. Reducing it has no effect (file doesn't shrink). -7. **Any new lockless read path must use `operation_guard`** — if you add code that reads from chainbase indices without `with_read_lock()`/`with_write_lock()`, wrap it with `make_operation_guard()` to participate in the resize barrier. Failing to do so can cause stale pointer access during resize. diff --git a/.qoder/docs/snapshot-pause-workflow.md b/.qoder/docs/snapshot-pause-workflow.md deleted file mode 100644 index 76688f89b5..0000000000 --- a/.qoder/docs/snapshot-pause-workflow.md +++ /dev/null @@ -1,369 +0,0 @@ -# Snapshot Pause Block Workflow - -## Overview - -When the snapshot plugin creates a snapshot, it **pauses P2P block processing** to -prevent concurrent database modifications. During this pause, incoming blocks from -peers are **buffered in a queue** instead of being dropped. After the pause ends, -the P2P layer drains the queue (applying all buffered blocks), then checks whether -peers are still ahead. The Validator Plugin defers block production until all queued -blocks are applied and any remaining gap is filled. - -## Sequence Diagram: Snapshot Pause Lifecycle - -```mermaid -sequenceDiagram - participant SP as Snapshot Plugin - participant P2P as P2P Layer - participant W as Validator Plugin - participant Peer as Remote Peer - - Note over SP: Block N applied - SP->>SP: on_applied_block() triggers snapshot - SP->>P2P: pause_block_processing() - Note over P2P: _block_processing_paused = true - Note over P2P: is_catching_up_after_pause() = true - - Peer->>P2P: Block N+1 (from delegate) - P2P->>P2P: QUEUED in _paused_block_queue - Peer->>P2P: Block N+2 (from delegate) - P2P->>P2P: QUEUED in _paused_block_queue - - Note over W: Production loop fires (250ms) - W->>P2P: is_catching_up_after_pause()? - P2P-->>W: true (_block_processing_paused) - W-->>W: return not_synced (deferred) - Note over W: generate_block() NOT called
No write lock attempt - - SP->>SP: create_snapshot() DB read completes - SP->>P2P: resume_block_processing() - Note over P2P: _block_processing_paused = false - Note over P2P: _catchup_after_pause = true - Note over P2P: Posts drain to P2P thread - - Note over P2P: P2P thread: drain_paused_block_queue() - P2P->>P2P: Sort queue by block_num - P2P->>P2P: accept_block(N+1) → applied - P2P->>P2P: accept_block(N+2) → applied - P2P->>P2P: Check peers: no one ahead - Note over P2P: _catchup_after_pause = false - - Note over W: Production loop fires - W->>P2P: is_catching_up_after_pause()? - P2P-->>W: false - W->>W: Normal production resumes -``` - -## Incoming Block Workflow (During Pause) - -```mermaid -flowchart TD - A["Block message received from peer"] --> B{"_block_processing_paused?"} - B -->|Yes| C{"Message type?"} - C -->|hello/hello_reply/fork_status| D["Process normally
(keeps peer_head_num updated)"] - C -->|block_reply, range_reply,
gap_fill_reply| E["Deserialize and push
to _paused_block_queue"] - C -->|other: transaction,
peer exchange, etc.| F["Drop (return true)"] - B -->|No| G{"Queue has pending blocks?
(leftover from recent pause)"} - G -->|Yes| H["drain_paused_block_queue()\nfirst"] - G -->|No| I["Normal processing:
accept_block() → push_block()"] - H --> I - I --> J{"Block accepted?"} - J -->|ACCEPTED| K["on_block_applied()
retransmit to fork peers"] - J -->|FORK_DB_ONLY| L["Store in fork_db
(competing fork)"] - J -->|DEAD_FORK| M["Soft-ban peer"] - J -->|REJECTED| N["Log + track rejections"] -``` - -## validator Production Workflow (With Catchup Gate) - -```mermaid -flowchart TD - Start["maybe_produce_block()"] --> Sync{"DLT mode +
chain.is_syncing()?"} - Sync -->|Yes, not emergency master| Ret1["return not_synced"] - Sync -->|No / emergency master| Gate{"p2p.is_catching_up_after_pause()?"} - Gate -->|Yes| Ret2["return not_synced
(defer production)"] - Gate -->|No| HF12{"Hardfork 12 checks
(prate, emergency)"} - HF12 -->|prate < 33% AND no stale-production override| RetLP["return low_participation
⚠ partition guard"] - HF12 -->|prate >= 33% or override| MinFork{"Minority fork check:
last 21 fork_db blocks
all from our validators?"} - MinFork -->|Yes — isolated| RetMF["resync_from_lib()
return minority_fork"] - MinFork -->|No| Slot{"get_slot_at_time()"} - Slot -->|slot == 0| Ret3["return not_time_yet"] - Slot -->|slot > 0| validator{"Our validator scheduled?"} - validator -->|No| Ret4["return not_my_turn"] - validator -->|Yes| Stale{"scheduled_time <=
head_block_time?"} - Stale -->|Yes| Ret5["return not_time_yet
(slot already filled)"] - Stale -->|No| Fork{"Competing block in fork_db?"} - Fork -->|Yes, weaker fork| Produce - Fork -->|Yes, stronger fork| Ret6["return fork_collision"] - Fork -->|No| Produce["generate_block()"] - Produce --> Broadcast["p2p.broadcast_block()"] - Broadcast --> Done["return produced"] -``` - -### Note: two complementary partition guards - -`low_participation` and `minority_fork` are **not interchangeable** — they protect against -different failure modes and must both be active: - -| Guard | Trigger | Scenario it stops | -|-------|---------|-------------------| -| `low_participation` | `prate < 33%` (< 7 of 21 validators active) | Node in a small isolated segment — stops it from building a chain alone | -| `minority_fork` | Last 21 fork_db blocks are ALL from our validators | Node is producing in isolation despite appearing to have enough validators locally | - -**Why `low_participation` must not be removed:** -If a network partitions into two datacenters and one segment holds fewer than 7 of the -21 scheduled validators, it sees participation drop below 33% within ~85 missed slots -(~4 minutes). Without this guard that segment would keep building a competing chain -that neither side recognises as a minority fork, because `minority_fork` only fires when -**all** recent fork_db blocks are from our validators — possible only once the other -segment's blocks are completely absent from our fork_db. - -The operator escape hatch for legitimate outages (many validators offline but network -not partitioned) is `enable-stale-production = true`, which bypasses the `low_participation` -check explicitly. See `consensus-emergency-params.md` for the full workflow. - -## Post-Pause Catchup State Machine - -```mermaid -stateDiagram-v2 - [*] --> Normal: Node running - Normal --> Paused: pause_block_processing() - Paused --> Queuing: Block arrives - Queuing --> Queuing: Next block queued - Queuing --> Draining: resume_block_processing() - Note right of Draining: _catchup_after_pause = true - Draining --> DrainComplete: Queue empty - DrainComplete --> Normal: No peers ahead → flag cleared - DrainComplete --> GapFill: Peers still ahead - GapFill --> Normal: transition_to_forward()
_catchup_after_pause=false -``` - -## Key Files - -| File | Role | -|------|------| -| `libraries/network/dlt_p2p_node.cpp` | P2P block reception, pause/resume, catchup flag | -| `libraries/network/include/graphene/network/dlt_p2p_node.hpp` | `_catchup_after_pause` flag and getter | -| `plugins/p2p/p2p_plugin.cpp` | Exposes `is_catching_up_after_pause()` to other plugins | -| `plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp` | Public API declaration | -| `plugins/validator/validator.cpp` | Production gate that checks catchup flag | -| `plugins/snapshot/plugin.cpp` | Calls `pause/resume_block_processing()` | - -## The Bug (Before Fix) - -Two interrelated bugs: - -**Bug 1 — Write lock deadlock**: The emergency master's validator production loop -(250ms tick) bypasses all sync checks. During snapshot creation, the snapshot thread -holds a strong DB read lock for 30–120s. The production loop called `generate_block()` -→ `push_block()` → write lock → **deadlocked** behind the read lock, producing -11+ second write lock timeouts (readers=0, waiter spinning). - -**Bug 2 — Fork on stale head**: Without the block queue, blocks arriving during the -pause were silently dropped. After resume, the emergency master produced a block on a -stale head before gap-fill could deliver the real blocks from delegates, creating a -fork that other nodes had to resolve. - -Sequence: -1. Snapshot starts → P2P paused -2. Other delegates produce blocks N+1, N+2 → **dropped** by P2P -3. Emergency master production loop → `generate_block()` → **write lock timeout** (11s+) -4. Snapshot finishes → `resume_block_processing()` requests gap fill → returns immediately -5. Emergency master produces block N+1 with emergency key → **fork conflict** -6. Other nodes see two competing blocks → fork switch chaos - -## The Fix - -**Production gate during pause**: `is_catching_up_after_pause()` returns true when -either `_block_processing_paused` OR `_catchup_after_pause` is set. This prevents the -Validator Plugin from calling `generate_block()` while the snapshot holds the DB read -lock (avoids write-lock deadlock) AND during post-pause catchup (avoids stale-head fork). - -**Block queue**: During the pause, block-carrying messages (block_reply, block_range_reply, -gap_fill_reply) are deserialized and pushed into `_paused_block_queue`. Hello and fork_status -messages are still processed normally to keep `peer_head_num` up to date. - -**Queue drain**: When `resume_block_processing()` is called, it posts `drain_paused_block_queue()` -to the P2P thread. The drain sorts queued blocks by block_num, applies each via -`accept_block()`, and then checks whether peers are still ahead. - -**Catchup flag lifecycle**: `_catchup_after_pause` is set when `resume_block_processing()` -runs and cleared when: -- The drain completes and no peer is ahead (immediate path), or -- `transition_to_forward()` runs after a SYNC gap fill (delayed path), or -- `periodic_task()` confirms no gap exists (5s fallback) - -The Validator Plugin checks `is_catching_up_after_pause()` in `maybe_produce_block()` and -defers production while the flag is set. - ---- - -## Bug 3 — currently_syncing not cleared on SYNC→FORWARD (p72, 570 s silence) - -### Observed symptom - -After a scheduled snapshot the node produced no blocks for **570 seconds** despite -`_catchup_after_pause` being cleared at 10:54:40. WATCHDOG fired at 11:04:01 and -production resumed immediately after it called `chain.clear_syncing()`. - -### Root cause - -`currently_syncing` in the chain plugin (`plugin_impl::currently_syncing`) is set to -`true` by every `accept_block(sync_mode=true)` call — i.e. every block fetched during -SYNC mode. It self-clears **only** when the next `accept_block(sync_mode=false)` runs -(the first FORWARD-mode block). - -The chain of events in p72: - -``` -10:54:38 pause_block_processing() _block_processing_paused=true -10:54:40 resume_block_processing() _catchup_after_pause=true -10:54:40 drain_paused_block_queue() sync_mode=false → currently_syncing=false ✓ -10:54:40 drain: no peers ahead _catchup_after_pause=false ✓ - ← at this point both flags are clear, production should resume - -~10:54:41 periodic_task(): peers still ahead by 1-2 blocks - check_forward_behind() → transition_to_sync() - Fetch missing blocks: call_accept_block(sync_mode=true) - → currently_syncing.store(true) - Sync completes → transition_to_forward() - → currently_syncing NOT cleared ← BUG - -10:54:41–11:04:01 validator loop: - is_syncing()=true → return not_synced (rate-limited, silent) - not_my_turn_streak stays at 0–2 (resets on not_synced) - -11:04:01 WATCHDOG fires → chain.clear_syncing() - → currently_syncing=false → production resumes -``` - -The circular deadlock: `currently_syncing=true` blocks our validators; our validators are -the only remaining producers; no FORWARD block arrives to self-clear the flag. - -### Why the WATCHDOG evidence confirms this - -- `slot_result=2` (`not_my_turn`) at watchdog time — just switched away from `not_synced` -- `not_my_turn_streak=2` — very short; had been returning `not_synced` (resets the streak) - for almost all of the 570 s -- `prod=true`, `minority_recovering=false` — `_production_enabled` was fine; the block on - `_catchup_after_pause` was gone; only `is_syncing()` was blocking production - -### Fix - -`clear_syncing()` added to `dlt_p2p_delegate` and called from `transition_to_forward()` -**before** the early-return guard, so it fires on every SYNC→FORWARD transition -(and is a no-op when `currently_syncing` is already false): - -```cpp -// dlt_p2p_node.cpp — transition_to_forward() -if (_delegate) _delegate->clear_syncing(); // ← added -if (_node_status == DLT_NODE_STATUS_FORWARD) return; -``` - -`dlt_delegate::clear_syncing()` in `p2p_plugin.cpp` delegates to `chain.clear_syncing()`. - -### Files changed - -| File | Change | -|------|--------| -| `libraries/network/include/graphene/network/dlt_p2p_node.hpp` | `clear_syncing()` pure virtual in `dlt_p2p_delegate` | -| `plugins/p2p/p2p_plugin.cpp` | `dlt_delegate::clear_syncing()` → `chain.clear_syncing()` | -| `libraries/network/dlt_p2p_node.cpp` | `transition_to_forward()` calls `_delegate->clear_syncing()` | - ---- - -## Bug 4 — resume_block_processing() deadlock via async().wait() under read lock - -### Observed symptom - -After a snapshot the P2P layer would occasionally stall: the paused block queue never -drained and production never resumed, requiring a node restart. - -### Root cause - -`resume_block_processing()` was implemented by posting a task to the P2P thread via -`async().wait()` — i.e. it **blocked the calling thread** until the P2P thread completed -the task. - -The call chain: - -``` -snapshot completes - → on_applied_block signal - → flush_pending_block_notifications() - → with_weak_read_lock() - → resume_block_processing() - → async(P2P thread).wait() ← blocks here -``` - -A second P2P fiber that had already passed the `_block_processing_paused` check called -`push_block()`, which needed a **write lock** on the database. That write lock was -blocked by our read lock. The OS thread was frozen waiting for the write lock; the -posted async task could never run (it was on the same thread); therefore `wait()` never -returned. Deadlock. - -### Fix - -`resume_block_processing()` split into two phases: - -**Phase 1 (immediate, any thread):** `dlt_p2p_node::set_resume_flags()` atomically sets -`_catchup_after_pause = true` and clears `_block_processing_paused`. Both are -`std::atomic` — no P2P-thread dispatch needed. - -**Critical ordering:** `_catchup_after_pause` is set **before** `snapshot_in_progress` is -cleared. If reversed, the Validator Plugin could observe the snapshot complete while the -catchup flag is still false, misclassify the head as a stale fork, and refuse to produce. - -**Phase 2 (async, P2P thread, no wait):** An async post (fire-and-forget) to the P2P -thread calls `run_resume_on_p2p_thread()` which logs the resume and drains -`_paused_block_queue`. The caller does **not** `.wait()` — it returns immediately after -Phase 1. - -```cpp -void p2p_plugin::resume_block_processing() { - // Phase 1: set atomic flags immediately (thread-safe, no dispatch needed) - if (my && my->node) - my->node->set_resume_flags(); // _catchup_after_pause=true, _block_processing_paused=false - - // Phase 2: post drain to P2P thread (fire-and-forget) - my->p2p_thread.async([this]() { - if (my->node) my->node->run_resume_on_p2p_thread(); - }); - // No .wait() here — caller can proceed and release snapshot_in_progress immediately -} -``` - -### Files changed - -| File | Change | -|------|--------| -| `libraries/network/dlt_p2p_node.cpp` | Block-processing flags changed to `std::atomic`; `set_resume_flags()` / `run_resume_on_p2p_thread()` added | -| `plugins/p2p/p2p_plugin.cpp` | `resume_block_processing()` two-phase refactor; `pause_block_processing()` documented as P2P-thread-only direct call | - ---- - -## Bug 5 — snapshot async task does not reset P2P flags on failure path - -### Observed symptom - -If the snapshot async task encountered an error or was cancelled, `_block_processing_paused` -and `_catchup_after_pause` could remain in their paused state indefinitely, permanently -blocking validator production. - -### Root cause - -The flag reset / `resume_block_processing()` call was only on the happy path of the async -task. Error and early-exit branches fell through without resetting. - -### Fix - -`plugin.cpp` snapshot async task now calls `resume_block_processing()` (via the RAII -guard pattern) unconditionally — even when the task exits via exception or early return. -The snapshot path was also passed correctly into the load callback (it was empty before, -causing the load to fail silently). - -### Files changed - -| File | Change | -|------|--------| -| `plugins/snapshot/plugin.cpp` | Snapshot path passed into async load callback; flag reset moved to a scope guard ensuring it fires on all exit paths | diff --git a/.qoder/docs/snapshot-plugin.md b/.qoder/docs/snapshot-plugin.md deleted file mode 100644 index b9075419dc..0000000000 --- a/.qoder/docs/snapshot-plugin.md +++ /dev/null @@ -1,1209 +0,0 @@ -# Snapshot Plugin (DLT Mode) - -The snapshot plugin enables near-instant node startup by serializing and restoring the full blockchain state as a JSON snapshot file. Instead of replaying millions of blocks from the block log, a node can load a pre-built snapshot and begin syncing from the snapshot's block height via P2P. - -## Plugin Name - -`snapshot` - -## Dependencies - -- `chain` plugin (required, auto-loaded) - -## Config & CLI Options - -### CLI-only options (command line arguments) - -| Option | Type | Description | -|--------|------|-------------| -| `--snapshot ` | `string` | Load state from a snapshot file instead of replaying blockchain. The node opens in DLT mode (no block log). Safe for restarts — skips import if shared_memory already exists, and renames the file to `.used` after successful import. | -| `--snapshot-auto-latest` | `bool` (default: `false`) | Auto-discover the latest snapshot file in `snapshot-dir` by parsing block numbers from filenames (`snapshot-block-NNNNN.vizjson` or `.json`). Typically used with `--replay-from-snapshot` to avoid specifying the file path manually. Ignored if `--snapshot` is already specified. | -| `--replay-from-snapshot` | `bool` (default: `false`) | Crash recovery mode: import a snapshot and then replay blocks from `dlt_block_log` to bring the node up to the latest available state. Unlike `--snapshot`, this always wipes shared memory (assumes corruption), does NOT rename the snapshot to `.used`, and replays subsequent blocks from the DLT rolling block log. Requires `--snapshot ` or `--snapshot-auto-latest`. | -| `--auto-recover-from-snapshot` | `bool` (default: `true`) | Automatic runtime recovery from shared memory corruption. When corruption is detected during block processing or generation (e.g., missing validator account), the node immediately closes the database, finds the latest snapshot, wipes shared memory, imports the snapshot, replays `dlt_block_log`, and resumes P2P sync — all without a restart. Requires `plugin = snapshot` and snapshots in `snapshot-dir`. | -| `--create-snapshot ` | `string` | Create a snapshot file at the given path using the current database state, then exit. | -| `--sync-snapshot-from-trusted-peer` | `bool` (default: `false`) | Download and load snapshot from trusted peers when state is empty (`head_block_num == 0`). Requires `trusted-snapshot-peer` to be configured. Defaults to `false` (opt-in) — must be explicitly enabled to prevent accidental state wipe via `chainbase::wipe()`. | - -### Config file options (snapshot plugin) - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `snapshot-at-block` | `uint32_t` | `0` | Create snapshot when the specified block number is reached (while the node is running). | -| `snapshot-every-n-blocks` | `uint32_t` | `0` | Automatically create a snapshot every N blocks (0 = disabled). | -| `snapshot-dir` | `string` | `""` | Directory for auto-generated snapshot files. Used by `snapshot-at-block` and `snapshot-every-n-blocks`. | -| `snapshot-max-age-days` | `uint32_t` | `90` | Delete snapshots older than N days after creating a new one (0 = disabled). Built-in rotation replaces external cron jobs. | -| `allow-snapshot-serving` | `bool` | `false` | Enable serving snapshots over TCP to other nodes. | -| `allow-snapshot-serving-only-trusted` | `bool` | `false` | Restrict snapshot serving to trusted peers only (from `trusted-snapshot-peer` list). | -| `snapshot-serve-endpoint` | `string` | `0.0.0.0:8092` | TCP endpoint for the snapshot serving listener. | -| `trusted-snapshot-peer` | `string` (multi) | — | Trusted peer endpoint for snapshot sync (`IP:port`). Can be specified multiple times. | - -### Config file options (chain plugin) - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `dlt-block-log-max-blocks` | `uint32_t` | `100000` | Number of recent blocks to keep in the DLT rolling block log (0 = disabled). Only active in DLT mode (after snapshot import). | - -## Enabling the Plugin - -The snapshot plugin is registered by default in `vizd`. To enable it, add it to your `config.ini`: - -```ini -plugin = snapshot -``` - -Or pass it on the command line: - -```bash -vizd --plugin snapshot -``` - -## Creating a Snapshot - -### Method 1: One-shot snapshot (stop node, create, exit) - -Stop the node, then restart it with the `--create-snapshot` flag. The node will open the existing database (block log + shared memory), replay if needed to bring the state up to date, create the snapshot, and exit — **before** P2P or validator plugins activate: - -```bash -vizd --create-snapshot /data/snapshots/viz-snapshot.json --plugin snapshot -``` - -### What happens during `--create-snapshot` - -1. All plugins call `plugin_initialize()`. The **snapshot plugin** registers a `snapshot_create_callback` on the **chain plugin**. -2. The **chain plugin** `plugin_startup()` opens the database normally — block log, shared memory, and replays from block log if the chainbase revision doesn't match the head block. -3. After the database is fully loaded, the chain plugin calls `snapshot_create_callback()` — the **snapshot plugin** serializes all 32 tracked object types as JSON arrays with a SHA-256 checksum, writes the file, and calls `app().quit()`. -4. The chain plugin **never calls `on_sync()`** — P2P and validator plugins never activate. - -All snapshot creation happens **inside** `chain::plugin_startup()`. The database is fully consistent (post-replay) and no new blocks arrive during serialization. - -### Method 2: Snapshot at a specific block (no downtime) - -The node creates a snapshot automatically when the specified block number is applied. Add to `config.ini`: - -```ini -plugin = snapshot -snapshot-at-block = 5000000 -snapshot-dir = /data/snapshots -``` - -Start the node normally: - -```bash -vizd -``` - -When block 5,000,000 is applied, the snapshot is created at `/data/snapshots/snapshot-block-5000000.json` without stopping the node. Snapshot creation runs asynchronously on a dedicated background thread — only the database read phase (serialization) holds a read lock, so block processing is only briefly paused and API/P2P reads are never blocked. - -### Method 3: Periodic automatic snapshots (no downtime, recommended) - -The node creates snapshots automatically every N blocks. This is the recommended approach for production nodes that need regular backups. - -Add to `config.ini`: - -```ini -plugin = snapshot - -# Create a snapshot every 100,000 blocks (~3.5 days at 3s/block) -snapshot-every-n-blocks = 100000 - -# Directory where snapshot files are saved -snapshot-dir = /data/snapshots -``` - -Start the node normally: - -```bash -vizd -``` - -Snapshot files are named automatically: `snapshot-block-.json` - -Example output in the snapshots directory: - -``` -/data/snapshots/ - snapshot-block-100000.json - snapshot-block-200000.json - snapshot-block-300000.json - ... -``` - -**Recommended intervals:** - -| Interval | Blocks | Approximate time (at 3s/block) | -|----------|--------|-------------------------------| -| Frequent | 10,000 | ~8.3 hours | -| Daily | 28,800 | ~24 hours | -| Weekly | 100,000 | ~3.5 days | -| Rare | 1,000,000 | ~34.7 days | - -**Notes on periodic snapshots:** -- **Only triggers on live blocks**: Periodic snapshots are skipped while the node is syncing from P2P (block time >60s behind wall clock). This prevents wasteful snapshot creation during initial sync from genesis or from an older snapshot. Snapshots begin only after the node catches up to the live chain head. -- **Auto-creates directory**: The snapshot directory (`snapshot-dir`) is automatically created if it doesn't exist. No need to `mkdir` before starting the node. -- **Non-blocking snapshot creation**: Snapshot creation runs asynchronously on a dedicated `fc::thread`. The `on_applied_block` callback returns immediately after scheduling the snapshot — the write lock is released and block processing resumes. The snapshot itself is split into two phases: - - **Phase 1 (read lock, ~1 second)**: Serializes all database state into local variables. During this phase, block processing waits (read lock conflicts with write lock), but API/P2P reads proceed concurrently. - - **Phase 2 (no lock, ~2 seconds)**: Compression, checksum computation, and file I/O. Block processing and API reads run normally during this phase. -- This prevents the read-lock timeouts and `unlinkable_block_exception` errors that previously occurred when snapshot creation ran synchronously inside the write-lock scope (which blocked all database access for 3+ seconds). -- For large chains, consider using a longer interval (e.g., `100000` blocks) to minimize the impact on block processing. -- **Built-in rotation**: Old snapshot files are automatically deleted if older than `snapshot-max-age-days` (default 90 days, 0 = disabled). Rotation runs after each new snapshot is created. -- If snapshot creation fails (e.g., disk full), the error is logged but the node continues running normally. - -### Method 4: Combining at-block with periodic - -You can use both `snapshot-at-block` and `snapshot-every-n-blocks` together: - -```ini -plugin = snapshot -snapshot-at-block = 5000000 -snapshot-every-n-blocks = 100000 -snapshot-dir = /data/snapshots -``` - -This creates a snapshot at block 5,000,000 AND every 100,000 blocks. - -### Managing snapshot disk space - -Snapshot rotation is built-in. By default, snapshots older than 90 days are automatically deleted after each new snapshot is created. - -To configure or disable rotation, set `snapshot-max-age-days` in `config.ini`: - -```ini -# Delete snapshots older than 30 days (default: 90) -snapshot-max-age-days = 30 - -# Or disable rotation entirely -# snapshot-max-age-days = 0 -``` - -Alternatively, you can use an external cron job for finer control: - -```bash -# Keep only the 5 most recent snapshots -ls -t /data/snapshots/snapshot-block-*.json | tail -n +6 | xargs rm -f -``` - -## Loading from a Snapshot (DLT Mode) - -To start a node from a snapshot file: - -```bash -vizd --snapshot /path/to/snapshot.json --plugin snapshot -``` - -### What happens during snapshot loading - -1. All plugins call `plugin_initialize()`. The **snapshot plugin** registers a `snapshot_load_callback` on the **chain plugin**. -2. The **chain plugin** `plugin_startup()` detects the `--snapshot` option and checks three conditions in order: - - **shared_memory.bin already exists** → skips import, falls through to normal startup (prevents re-importing on container restart). - - **Snapshot file not found** (e.g., already renamed to `.used`) → skips import, falls through to normal startup. - - **Both checks pass** → proceeds with snapshot import. -3. The chain plugin opens the database using `open_from_snapshot()` — this wipes shared memory, initializes chainbase, indexes, and evaluators. -4. The chain plugin calls `snapshot_load_callback()` — the **snapshot plugin** reads the JSON file, validates the header (format version, chain ID, SHA-256 checksum), imports all 32 tracked object types into the database under a strong write lock, and calls `initialize_hardforks()` to populate the hardfork schedule. -5. **The snapshot file is renamed to `.used`** (e.g., `snapshot.json` → `snapshot.json.used`) to prevent re-import on restart. -6. LIB (Last Irreversible Block) is promoted to `head_block_num` so P2P's blockchain synopsis starts from the snapshot's head — peers will only offer blocks after the snapshot point. -7. The fork database is seeded with the head block from the snapshot. -8. The chain plugin emits `on_sync` so other plugins (webserver, APIs, etc.) know the node is ready. -9. **P2P plugin** starts — sees the snapshot's head block and begins syncing from **LIB + 1** via the P2P network. - -All snapshot loading happens **inside** `chain::plugin_startup()`, before any other plugin starts. P2P and validator never see incomplete/genesis state. - -### Restart safety - -The node is safe to restart with `--snapshot` still on the command line (e.g., via `VIZD_EXTRA_OPTS` in Docker). Three layers of protection prevent accidental re-import: - -| Restart scenario | What happens | -|---|---| -| **1st start** (no shared_memory, file exists) | Imports snapshot, renames file to `.used` | -| **Restart** (shared_memory exists) | Skips import: "Shared memory already exists" | -| **Restart** (shared_memory wiped, file already `.used`) | Skips import: "Snapshot file not found" | -| **Force re-import** | `--resync-blockchain` wipes shared_memory + provide a fresh snapshot file | - -### Important notes - -- **No block log (DLT mode)**: When loaded from a snapshot, the node runs in DLT mode — the main `block_log` remains empty. A separate **DLT rolling block log** stores recent blocks (see below). -- **Automatic DLT mode detection on restart**: After the initial snapshot load, the node detects DLT mode automatically (block_log empty, chainbase has state), skips block_log validation, and continues syncing from P2P. -- **Chain ID validation**: The snapshot's chain ID must match the node's compiled chain ID. Mismatches are rejected. -- **Checksum verification**: The payload checksum is verified before any objects are imported. -- **Restart with `--snapshot` is safe**: See "Restart safety" above — no need to remove the flag after initial import. - -## Snapshot File Format - -The snapshot is a single JSON file with this structure: - -```json -{ - "header": { - "version": 1, - "chain_id": "...", - "snapshot_block_num": 12345678, - "snapshot_block_id": "...", - "snapshot_block_time": "2025-01-01T00:00:00", - "last_irreversible_block_num": 12345660, - "last_irreversible_block_id": "...", - "snapshot_creation_time": "2025-01-01T00:05:00", - "payload_checksum": "sha256...", - "object_counts": { - "account": 50000, - "validator": 100, - "content": 200000, - ... - } - }, - "state": { - "dynamic_global_property": [ ... ], - "witness_schedule": [ ... ], - "hardfork_property": [ ... ], - "account": [ ... ], - "account_authority": [ ... ], - "validator": [ ... ], - ... - "fork_db_head_block": { ... } - } -} -``` - -### Included Object Types (32 total) - -**Critical (11)** — consensus-essential, always required: - -- `dynamic_global_property` — global chain state (singleton) -- `witness_schedule` — current validator schedule (singleton) -- `hardfork_property` — hardfork tracking state (singleton) -- `account` — all accounts -- `account_authority` — master/active/regular authorities -- `validator` — validator registrations -- `witness_vote` — validator votes -- `block_summary` — block ID summaries (65536 entries) -- `content` — content/posts -- `content_vote` — content votes -- `block_post_validation` — block post-validation records - -**Important (15)** — needed for full operation: - -- `transaction` — pending transactions -- `vesting_delegation` — vesting delegations -- `vesting_delegation_expiration` — expiring delegations -- `fix_vesting_delegation` — delegation fix records -- `withdraw_vesting_route` — vesting withdrawal routes -- `escrow` — escrow transfers -- `proposal` — governance proposals -- `required_approval` — proposal approval requirements -- `committee_request` — committee funding requests -- `committee_vote` — committee votes -- `invite` — account invites -- `award_shares_expire` — expiring award shares -- `paid_subscription` — paid subscription offers -- `paid_subscribe` — active subscriptions -- `witness_penalty_expire` — validator penalty expirations - -**Optional (5)** — metadata and recovery: - -- `content_type` — content title/body/metadata -- `account_metadata` — account JSON metadata -- `master_authority_history` — authority change history -- `account_recovery_request` — pending recovery requests -- `change_recovery_account_request` — recovery account change requests - -## Example: Full DLT Node Setup - -### Step 1: Create a snapshot on a synced node - -```bash -# Option A: One-shot (creates and exits) -vizd --create-snapshot /data/snapshots/viz-snapshot-20250101.json --plugin snapshot - -# Option B: Already running with periodic snapshots in config.ini — just grab the latest file -ls -t /data/snapshots/snapshot-block-*.json | head -1 -``` - -### Step 2: Transfer the snapshot file to the new node - -```bash -scp /data/snapshots/viz-snapshot-20250101.json newnode:/data/snapshots/ -``` - -### Step 3: Start the new node from the snapshot - -```bash -vizd \ - --snapshot /data/snapshots/viz-snapshot-20250101.json \ - --plugin snapshot \ - --plugin p2p \ - --p2p-seed-node seed1.viz.world:2001 \ - --shared-file-size 4G -``` - -The node will load the snapshot state in seconds and begin syncing new blocks from the network. - -### Step 4: Subsequent restarts - -The node is safe to restart even with `--snapshot` still on the command line. It detects existing shared_memory and skips re-import automatically: - -```bash -# Just restart — no need to remove --snapshot flag -vizd --plugin p2p --p2p-seed-node seed1.viz.world:2001 -``` - -## DLT Rolling Block Log - -When a node runs in DLT mode (loaded from snapshot), the main `block_log` is empty. However, a separate **DLT rolling block log** (`dlt_block_log`) stores the most recent irreversible blocks. This enables: - -- **P2P block serving**: Peers can request recent blocks from this node (for fork resolution and initial sync catch-up). -- **Local block queries**: API calls like `get_block` work for recent blocks. - -### Configuration - -```ini -# Keep the last 100,000 blocks in the DLT block log (default) -dlt-block-log-max-blocks = 100000 - -# Or disable the DLT block log entirely -# dlt-block-log-max-blocks = 0 -``` - -### How it works - -- The DLT block log is stored in two files: `dlt_block_log.log` and `dlt_block_log.index` in the blockchain data directory. -- The index uses an **offset-aware format**: an 8-byte header stores the start block number, followed by 8-byte position entries for each block. -- When the log exceeds `dlt-block-log-max-blocks`, old blocks are truncated from the front (rolling window). -- On restart, the DLT block log is preserved — blocks are only re-written from where they left off. -- When the DLT block log is empty (fresh snapshot import), the node skips ahead to the last irreversible block number, since snapshot state is already trusted. -- If a block is not found in the fork database during DLT block log writes (normal after restart), the gap is logged via `wlog` and fills naturally as LIB advances past the post-restart head. - -### Mapped file integrity - -The DLT block log uses `boost::iostreams::mapped_file` for both data and index files. Each `append()` calls `resize()` which internally does close→truncate→remap. After thousands of resize cycles during long-running block production, `mapped_file.size()` can return **stale values** (reflecting an older, smaller size), causing `get_block_pos()` to reject valid block numbers and break P2P sync (the node claims to have blocks but fails to look them up). - -**Fix:** The implementation tracks **logical file sizes** (`_logical_block_size`, `_logical_index_size`) independently of `mapped_file.size()`. These are updated after every `resize()` in `append()` and re-synced from the actual mapping on `open()`. All range checks in `get_block_pos()` and `read_block()` use the tracked logical sizes. - -**Self-healing:** A `verify_mapping()` method compares `mapped_file.size()` against the tracked logical size. If a discrepancy is detected, the mapping is closed and reopened (healing the stale state). This is called automatically every 5 minutes by the P2P stats task. - -**Diagnostics:** The P2P stats task (every 5 minutes) logs a `Block storage` line showing: -- `dlt_log: [start..end]` — current DLT block log range -- `dlt_resizes` — total `resize()` calls since open (useful for correlating with staleness) -- `fork_db` — linked/unlinked block counts and ranges - -### P2P block serving path - -When a peer requests a block: -1. `p2p_plugin::get_item()` → `database::fetch_block_by_id()` -2. First checks main `_block_log` (empty in DLT mode) -3. Falls back to `_dlt_block_log` for recent blocks -4. If not found in either → block unavailable - -**Note on `is_known_block()`:** In DLT mode, the `block_summary` table (TAPOS buffer, 65536 entries) survives snapshot import but may reference blocks not actually available on disk. The DLT mode implementation checks `block_summary` as a hint, then verifies the block is on the **preferred chain** via `find_block_id_for_num()`. This two-step check: -- Returns `true` for blocks on our chain (enabling P2P's `has_item()` to work correctly during sync negotiation) -- Returns `false` for blocks not on our chain or blocks where `block_summary` has stale fork entries (preventing the node from lying to P2P peers about being able to serve the block data) -- Falls through to `fetch_block_by_id()` for blocks outside the `block_summary` range - -### P2P sync reliability (DLT mode) - -After snapshot import, the node must sync all subsequent blocks from P2P. Several fixes ensure this works: - -**LIB promotion:** After snapshot import, LIB is set to `head_block_num` so P2P's blockchain synopsis starts from the snapshot's head. Peers will only offer blocks after the snapshot point, which can link correctly in the fork database. - -**Fork database seeding:** -- Fresh snapshot import: `fork_db` is seeded with the head block via `start_block()`. The head block is also appended to `dlt_block_log` so that restart can reconstruct `fork_db` from it. -- DLT mode restart: `fork_db` is in-memory and lost on restart. The node seeds it from `dlt_block_log` if it covers the head block (guaranteed after the fix above). If `dlt_block_log` somehow does not cover the head, the early rejection logic in `_push_block` handles the empty `fork_db` case by always allowing blocks whose `previous == head_block_id()` - -**Block ID advertisement clamping (`get_block_ids`):** After snapshot import, the `block_summary` (TAPOS buffer, 65536 entries) contains block IDs for blocks the node *knows about* but cannot serve (the actual block data only exists in `dlt_block_log` which starts at the snapshot head). Without clamping, `get_block_ids()` would advertise these un-serveable blocks to peers, causing them to request the blocks, receive `item_not_available`, and disconnect with "You are missing a sync item you claim to have, your database is probably corrupted." - -Fix: `database::earliest_available_block_num()` returns the lowest block the node can actually serve (from `dlt_block_log`, `block_log`, or `fork_db`). In DLT mode after snapshot import, this is typically the snapshot head block. `get_block_ids()` in `p2p_plugin.cpp` clamps its start to `earliest_available_block_num()`, ensuring the node only advertises blocks it can deliver. - -**Graceful `item_not_available` handling:** When a peer sends `item_not_available` for a sync block, the node no longer disconnects with a "corrupted database" message. Instead, it sets `inhibit_fetching_sync_blocks = true` on that peer and tries other peers. This allows DLT nodes with limited block history to participate in the network without being aggressively disconnected. - -**Broadcast inventory suppression during sync:** During initial sync (catching up from snapshot), peers send both sync data (block IDs for catch-up) and broadcast items (recent transactions/blocks at chain tip). If the node tries to fetch these broadcast items, the 1-second `active_ignored_request_timeout` in `terminate_inactive_connections()` fires before the items arrive, disconnecting peers and killing sync connections. - -The node suppresses broadcast inventory (`on_item_ids_inventory_message`) with a 3-layer defense: -1. **Per-peer sync check:** Skip if the originating peer has `we_need_sync_items_from_peer = true` -2. **Global sync check:** Skip if *any* active peer has `we_need_sync_items_from_peer = true` — prevents inventory from non-syncing peers from polluting `items_requested_from_peer` -3. **Head block time check:** Skip if the node's head block is >30 seconds behind wall clock — catches the brief window after all peers respond "up to date" but the node is still behind (e.g., when the peer was at the same block and set `we_need_sync_items_from_peer = false`) - -Broadcast items are useless during sync — the node will receive them naturally once caught up. - -**Early block rejection in `_push_block`:** When a node is far behind, it receives sync blocks (sequential, must accept) and broadcast blocks (real-time, potentially thousands ahead, must reject silently). Checks prevent sync disruption: -1. Duplicate blocks at/before head with matching ID → skipped silently -2. Blocks at/before head on a different fork with parent not in fork_db → silently rejected (prevents infinite P2P sync restart loop where each failure triggers another sync attempt with the same peer) -3. Far-ahead blocks whose parent is neither `head_block_id()` nor in `fork_db` → returned false silently (no `unlinkable_block_exception` thrown, preventing P2P sync restart) -4. Blocks with `previous == head_block_id()` → always allowed (critical for the first sync block to be accepted) - -**Fork database bug fixes:** Several bugs in `fork_database` were fixed: -- `_unlinked_index.insert()` was dead code (after `throw`) — moved before the throw -- `_push_next()` was never called after inserting a new block — added the call to resolve previously-unlinkable blocks -- Duplicate block check added in `_push_block` -- `_unlinked_index.clear()` added to `reset()` - -## Stale Snapshot Detection (DLT Mode) - -In DLT mode, the `dlt_block_log` is a rolling window that prunes old blocks. If the node's latest snapshot is older than the DLT block log's start block, downloading nodes would face an unsyncable gap (snapshot at block N, DLT log starts at block M > N, blocks N+1..M-1 missing). - -At startup, the snapshot plugin detects this condition: -1. Checks if in DLT mode with snapshot serving or periodic creation enabled -2. Compares latest snapshot block number against `dlt_block_log.start_block_num()` -3. If snapshot block < DLT start block, logs a `STALE SNAPSHOT DETECTED` warning -4. On the first fully-synced block, creates an urgent fresh snapshot (async, with validator-aware deferral) - -This ensures serving nodes always have a snapshot that peers can actually sync from. The check runs automatically — no configuration needed beyond the existing `snapshot-every-n-blocks` or `allow-snapshot-serving` settings. - -## Crash Recovery: `--replay-from-snapshot` - -When `shared_memory.bin` becomes corrupted (e.g., after an unclean shutdown, disk full, or hardware fault), the node cannot start normally. The standard `--replay-blockchain` replays from `block_log`, which is empty in DLT mode. The `--replay-from-snapshot` option provides a recovery path that combines snapshot import with DLT block log replay. - -### The problem - -| Scenario | Why it fails | -|----------|-------------| -| Normal startup | `shared_memory.bin` has corrupted indices → FC_ASSERT crash | -| `--replay-blockchain` | Reads from `block_log`, which is empty in DLT mode | -| `--snapshot ` alone | Imports snapshot state but does not replay subsequent blocks from `dlt_block_log` | - -### The solution - -`--replay-from-snapshot` performs a three-step recovery: - -1. **Wipe & import snapshot** — Always wipes `shared_memory.bin` (assumes corruption), opens the database from genesis via `open_from_snapshot()`, and imports the snapshot state. -2. **Replay dlt_block_log** — If the `dlt_block_log` contains blocks beyond the snapshot's head, they are replayed via `database::reindex_from_dlt()` to bring the node as close to the chain tip as possible. -3. **Resume P2P sync** — The node emits `on_sync` and begins normal P2P sync from the replayed head block onward. - -Unlike `--snapshot`, the recovery mode: -- Always wipes shared memory (no "already exists" check) -- Does **not** rename the snapshot file to `.used` (the snapshot may be needed again) -- Initializes hardforks after snapshot import (before replay) -- Replays blocks from `dlt_block_log` with standard reindex skip flags - -### Usage - -```bash -# Simple: specify the snapshot path explicitly -vizd --replay-from-snapshot --snapshot /data/snapshots/snapshot-block-79273800.vizjson --plugin snapshot - -# Convenient: auto-discover the latest snapshot -vizd --replay-from-snapshot --snapshot-auto-latest --plugin snapshot -``` - -With `--snapshot-auto-latest`, the node scans `snapshot-dir` for files matching `snapshot-block-*.vizjson` or `snapshot-block-*.json`, parses the block number from each filename, and selects the one with the highest block number. This avoids having to manually find and specify the snapshot path. - -### What happens during recovery - -1. All plugins call `plugin_initialize()`. The **snapshot plugin** registers a `snapshot_load_callback` on the **chain plugin**. -2. The **chain plugin** `plugin_startup()` detects `--replay-from-snapshot` and validates that a snapshot path is available (via `--snapshot` or `--snapshot-auto-latest`). -3. The chain plugin opens the database using `open_from_snapshot()` — this wipes shared memory, initializes chainbase, indexes, and evaluators in DLT mode. -4. The chain plugin calls `snapshot_load_callback()` — the **snapshot plugin** reads the JSON file, validates the header, imports all tracked object types, and calls `initialize_hardforks()`. -5. The chain plugin calls `initialize_hardforks()` to populate the hardfork schedule arrays. -6. The chain plugin checks if `dlt_block_log` has blocks beyond the snapshot head. If yes, it calls `database::reindex_from_dlt(snapshot_head + 1)`. -7. `reindex_from_dlt()` replays each block from the DLT rolling block log with reindex skip flags (no signature checks, no merkle checks, etc.), reporting progress to stderr every 10%. -8. After replay, the fork database is seeded with the last block from `dlt_block_log`. -9. The chain plugin emits `on_sync` — P2P starts syncing from the replayed head block. - -### Example recovery scenario - -A DLT-mode node with periodic snapshots every 100,000 blocks and `dlt-block-log-max-blocks = 100000` crashes at block 79,274,318 with corrupted shared memory: - -``` -/data/viz-snapshots/ - snapshot-block-79273800.vizjson ← latest snapshot (518 blocks behind crash point) - -/blockchain/ - dlt_block_log.log ← contains blocks 79174319..79274318 - dlt_block_log.index - shared_memory.bin ← CORRUPTED -``` - -Recovery command: -```bash -vizd --replay-from-snapshot --snapshot-auto-latest --plugin snapshot -``` - -Recovery log output: -``` -RECOVERY MODE: replaying from snapshot + dlt_block_log... -Opening database for snapshot import. Please wait... -Database opened for snapshot import (DLT mode), elapsed time 2.1 sec -Loading state from snapshot: /data/viz-snapshots/snapshot-block-79273800.vizjson -Snapshot loaded successfully at block 79273800, elapsed time 12.3 sec -Snapshot loaded at block 79273800. Initializing hardforks... -Replaying dlt_block_log from block 79273801 to 79274318... - 10% 52 of 518 (block 79273852, 3840M free, elapsed 0.8 sec) - 20% 104 of 518 (block 79273904, 3839M free, elapsed 1.5 sec) - ... - 100% 518 of 518 (block 79274318, 3830M free, elapsed 7.2 sec) -Done replaying from dlt_block_log, head_block=79274318, elapsed time: 7.3 sec -Recovery complete. Started on blockchain with 79274318 blocks -``` - -The node is now at block 79,274,318 and P2P sync fills the gap to the live chain head. - -### Key differences from `--snapshot` - -| Aspect | `--snapshot` | `--replay-from-snapshot` | -|--------|-------------|--------------------------| -| Purpose | Bootstrap a new node | Recover from corruption | -| Shared memory check | Skips if already exists | Always wipes and re-imports | -| Snapshot file rename | Renames to `.used` | Does NOT rename | -| DLT block log replay | No | Yes, from snapshot_head+1 | -| Hardfork initialization | In callback | In callback + explicit call | -| Typical use case | First-time node setup | Crash recovery | - -## Automatic Runtime Recovery: `--auto-recover-from-snapshot` - -While `--replay-from-snapshot` requires a manual restart, `--auto-recover-from-snapshot` (enabled by default) provides **immediate, automatic recovery** when shared memory corruption is detected at runtime — without any restart. - -### How it works - -When the node detects corruption during normal operation (e.g., a validator account object is missing from the database during block processing or block generation), it throws a `shared_memory_corruption_exception`. This exception is caught at the plugin level: - -1. **Block acceptance path** (P2P sync): `plugin::accept_block()` catches the exception and calls `attempt_auto_recovery()`. -2. **Block generation path** (validator): The Validator Plugin's `generate_block` retry loop catches the exception before the generic `fc::exception` handler, and calls `chain().attempt_auto_recovery()`. - -### Recovery flow (`attempt_auto_recovery`) - -1. **Find snapshot** — Scans `snapshot-dir` for the latest `snapshot-block-*.vizjson` or `.json` file (same logic as `--snapshot-auto-latest`). -2. **Close database** — Calls `db.close(false)` (no rewind — state is corrupted anyway). Errors during close are ignored. -3. **Wipe & import** — Calls `do_snapshot_load(data_dir, true)`, which is the exact same code path as `--replay-from-snapshot`: wipes `shared_memory.bin`, opens from genesis via `open_from_snapshot()`, imports snapshot state via callback, replays `dlt_block_log` blocks. -4. **Resume** — Calls `on_sync()` to resume P2P sync from the recovered head block. The node continues running. - -If recovery fails at any step (no snapshots found, snapshot plugin not configured, import error), the node logs an error and calls `appbase::app().quit()`. - -### Prerequisites - -- `plugin = snapshot` must be enabled -- Snapshots must exist in `snapshot-dir` (default: `/snapshots/`). Use `--snapshot-every-n-blocks` to create them automatically. -- The `dlt_block_log` should cover blocks beyond the snapshot for minimal data loss. - -### Key differences from `--replay-from-snapshot` - -| Aspect | `--replay-from-snapshot` | `--auto-recover-from-snapshot` | -|--------|--------------------------|-------------------------------| -| Trigger | Manual (restart with CLI flag) | Automatic (runtime exception) | -| Requires restart | Yes | No | -| Snapshot selection | `--snapshot` or `--snapshot-auto-latest` | Always auto-discovers latest | -| Default | `false` (opt-in) | `true` (enabled by default) | -| Database state before recovery | Failed to open | Open but corrupted → closed | -| Startup corruption | Yes (catch blocks in `plugin_startup`) | Yes (catch blocks in `plugin_startup`) | -| Runtime corruption | No | Yes (`accept_block`, `generate_block`) | - -### Disabling - -To disable automatic recovery (e.g., for debugging), pass `--no-auto-recover-from-snapshot` on the command line. - -## P2P Snapshot Sync - -Nodes can download snapshots directly from trusted peers over a custom TCP protocol, enabling fully automated bootstrap without manual file transfers. - -### Server (snapshot provider) - -Add to `config.ini`: - -```ini -plugin = snapshot - -# Enable TCP snapshot serving -allow-snapshot-serving = true - -# TCP endpoint for the snapshot server -snapshot-serve-endpoint = 0.0.0.0:8092 - -# Optional: restrict to trusted peers only -# allow-snapshot-serving-only-trusted = true -# trusted-snapshot-peer = 1.2.3.4:8092 - -# Must have snapshots to serve -snapshot-every-n-blocks = 28800 -snapshot-dir = /data/viz-snapshots -``` - -### Client (new node bootstrap) - -Start a new node that automatically downloads and loads a snapshot from trusted peers: - -```bash -vizd \ - --plugin snapshot \ - --plugin p2p -``` - -With `config.ini`: - -```ini -trusted-snapshot-peer = seed1.viz.world:8092 -trusted-snapshot-peer = seed2.viz.world:8092 -trusted-snapshot-peer = seed3.viz.world:8092 -``` - -Since `sync-snapshot-from-trusted-peer` defaults to `false`, you must explicitly enable it in `config.ini` along with `trusted-snapshot-peer`: - -```ini -trusted-snapshot-peer = seed1.viz.world:8092 -trusted-snapshot-peer = seed2.viz.world:8092 -trusted-snapshot-peer = seed3.viz.world:8092 -sync-snapshot-from-trusted-peer = true -``` - -When the node starts with 0 blocks and sync is enabled, it automatically downloads the snapshot from the best available peer. To disable auto-sync (the default): - -```ini -sync-snapshot-from-trusted-peer = false -``` - -If the node has 0 blocks and no `trusted-snapshot-peer` is configured, a console warning is shown advising the user to configure one. - -### How P2P sync works - -1. **Query phase**: The node connects to each trusted peer (5-second timeout per operation: connect, send, read), sends a `snapshot_info_request`, and collects metadata (block number, checksum, compressed size). Progress is logged to console. -2. **Selection**: Picks the peer with the highest block number. -3. **Download phase**: Downloads the snapshot in 1 MB chunks, writing to a temp file. Download progress is printed to console every 5% (size in MB and percentage). -4. **Verification**: Streams the downloaded file through SHA-256 to verify checksum (without loading into memory). -5. **Import**: Clears database state, loads the verified snapshot, initializes hardforks. Each stage (decompress, parse, validate, import) is logged to console with timing. - -All operations happen during `chain::plugin_startup()`, **before** P2P and validator plugins activate. The node is fully blocked during download and import — no blocks are processed until the snapshot is loaded. - -### Security features - -- **Max snapshot size**: Downloads exceeding 2 GB are rejected. -- **Streaming checksum**: SHA-256 verification uses streaming (1 MB chunks) to avoid loading the entire file into memory. -- **Trusted peer list**: Connections are only accepted from/to configured trusted peers. -- **Anti-spam**: Rate limiting (max connections per hour per IP), max 5 concurrent connections (each in a separate fiber with mutex-protected session tracking), 60-second enforced connection deadline (checked before each I/O operation, not just post-hoc). -- **Payload limits**: Control messages limited to 64 KB, only data replies allow up to 64 MB. -- **Dedicated server thread**: The TCP server runs all fibers (accept loop, watchdog, connection handlers) on a dedicated `fc::thread`, ensuring they are not blocked by the main thread's `io_serv->run()` loop. - -## Recommended Production Config - -A full `config.ini` snippet for a production node with automatic periodic snapshots: - -```ini -# Enable the snapshot plugin -plugin = snapshot - -# Create a snapshot every ~24 hours (28800 blocks * 3 seconds = 86400 sec) -snapshot-every-n-blocks = 28800 - -# Store snapshots in a dedicated directory -snapshot-dir = /data/viz-snapshots - -# Auto-delete snapshots older than 90 days (default) -snapshot-max-age-days = 90 - -# DLT rolling block log: keep last 100k blocks (default) -dlt-block-log-max-blocks = 100000 - -# Standard chain settings -shared-file-size = 4G -plugin = p2p -p2p-seed-node = seed1.viz.world:2001 -``` - -This configuration ensures your node always has a recent snapshot available for quick recovery or for bootstrapping new nodes. - -## Docker Usage - -The standard Docker launch command: - -```bash -docker run \ - -p 8083:2001 \ - -p 9991:8090 \ - -v ~/vizconfig:/etc/vizd \ - -v ~/vizhome:/var/lib/vizd \ - --name vizd -d vizblockchain/vizd:latest -``` - -Volumes: -- `~/vizconfig` → `/etc/vizd` — config files (`config.ini`, `seednodes`) -- `~/vizhome` → `/var/lib/vizd` — blockchain data, shared memory, snapshots - -The entry point script (`vizd.sh`) supports `VIZD_EXTRA_OPTS` environment variable for passing additional CLI arguments. - -### Creating a snapshot (periodic, no downtime) - -Add snapshot options to your config file `~/vizconfig/config.ini`: - -```ini -plugin = snapshot - -# Create a snapshot every ~24 hours (28800 blocks * 3s = ~86400s) -snapshot-every-n-blocks = 28800 - -# Store snapshots inside the data volume -snapshot-dir = /var/lib/vizd/snapshots -``` - -Start (or restart) the container: - -```bash -docker stop vizd && docker rm vizd - -docker run \ - -p 8083:2001 \ - -p 9991:8090 \ - -v ~/vizconfig:/etc/vizd \ - -v ~/vizhome:/var/lib/vizd \ - --name vizd -d vizblockchain/vizd:latest -``` - -Snapshots will appear on the host at `~/vizhome/snapshots/snapshot-block-*.json`. - -### Creating a one-shot snapshot (stop & export) - -Stop the running container, then run a temporary one with `--create-snapshot`: - -```bash -# Stop the running node -docker stop vizd - -# Create a snapshot using VIZD_EXTRA_OPTS -docker run --rm \ - -v ~/vizconfig:/etc/vizd \ - -v ~/vizhome:/var/lib/vizd \ - -e VIZD_EXTRA_OPTS="--create-snapshot /var/lib/vizd/snapshots/viz-snapshot.json --plugin snapshot" \ - vizblockchain/vizd:latest - -# The snapshot is now at ~/vizhome/snapshots/viz-snapshot.json on the host - -# Restart the node normally -docker start vizd -``` - -### Creating a snapshot at a specific block (no downtime) - -Add to `~/vizconfig/config.ini`: - -```ini -plugin = snapshot -snapshot-at-block = 5000000 -snapshot-dir = /var/lib/vizd/snapshots -``` - -Restart the container. When block 5,000,000 is applied, the snapshot file will be created at `/var/lib/vizd/snapshots/snapshot-block-5000000.json` (accessible on host at `~/vizhome/snapshots/`). - -### Loading from a snapshot (new node bootstrap) - -Place the snapshot file on the host: - -```bash -# Copy snapshot to the new server -scp viz-snapshot.json newserver:~/vizhome/snapshots/ -``` - -Start the container with `--snapshot` via `VIZD_EXTRA_OPTS`: - -```bash -docker run \ - -p 8083:2001 \ - -p 9991:8090 \ - -v ~/vizconfig:/etc/vizd \ - -v ~/vizhome:/var/lib/vizd \ - -e VIZD_EXTRA_OPTS="--snapshot /var/lib/vizd/snapshots/viz-snapshot.json --plugin snapshot" \ - --name vizd -d vizblockchain/vizd:latest -``` - -The node loads the snapshot state in seconds and begins syncing new blocks from P2P. - -**Restart safety:** The node is safe to restart with `VIZD_EXTRA_OPTS` still set. On restart: -1. If shared_memory already exists → skips import, uses existing state. -2. If the snapshot file was renamed to `.used` → skips import. -3. No need to remove `VIZD_EXTRA_OPTS` after the first run. - -### Managing snapshot disk space (Docker) - -Snapshot rotation is built-in (default: delete files older than 90 days). Add `snapshot-max-age-days` to `~/vizconfig/config.ini` to customize: - -```ini -# Delete snapshots older than 30 days -snapshot-max-age-days = 30 -``` - -Alternatively, add a cron job on the **host** machine: - -```bash -# Keep only the 5 most recent snapshots -0 0 * * * ls -t ~/vizhome/snapshots/snapshot-block-*.json | tail -n +6 | xargs rm -f -``` - -### Quick reference - -| Task | Command | -|------|---------| -| Start with periodic snapshots | Add `snapshot-every-n-blocks` to `~/vizconfig/config.ini`, restart container | -| One-shot snapshot | `docker run --rm -e VIZD_EXTRA_OPTS="--create-snapshot /var/lib/vizd/snapshots/snap.json --plugin snapshot" ...` | -| Load from snapshot | `docker run -e VIZD_EXTRA_OPTS="--snapshot /var/lib/vizd/snapshots/snap.json --plugin snapshot" ...` | -| Crash recovery | `docker run -e VIZD_EXTRA_OPTS="--replay-from-snapshot --snapshot-auto-latest --plugin snapshot" ...` | -| Auto-recovery (default) | Enabled by default with `--auto-recover-from-snapshot`. Ensure `plugin = snapshot` and `snapshot-every-n-blocks` are set in config. | -| P2P auto-bootstrap | Add `trusted-snapshot-peer = :` to config, start container with `--plugin snapshot` | -| Find snapshots on host | `ls -lt ~/vizhome/snapshots/` | -| Check snapshot creation logs | `docker logs vizd \| grep -i snapshot` | -| Force re-import | `docker run -e VIZD_EXTRA_OPTS="--resync-blockchain --snapshot /path/snap.json --plugin snapshot" ...` | - -## P2P Sync Flow (DLT Mode) - -This section documents the complete P2P sync protocol for a DLT node that loaded from a snapshot. The example uses a snapshot with head block #79504801 — the node has exactly **1 block** in its state, **1 entry** in fork_db, and its blockchain synopsis contains that single block ID. - -### Node state after snapshot import - -| Property | Value | -|----------|-------| -| `head_block_num` | 79504801 | -| `last_irreversible_block_num` (LIB) | 79504801 (promoted to head after snapshot import) | -| `block_log` | Empty | -| `dlt_block_log` | Contains block #79504801 only | -| `fork_db` | Contains 1 item: block #79504801 | -| `block_summary` (TAPOS buffer) | 65536 entries surviving from snapshot (blocks ~79439265..79504801) | -| `earliest_available_block_num()` | 79504801 | -| `_dlt_mode` | `true` | - -### Flow 1: Outbound sync — our node fetches blocks FROM a peer - -This is the primary sync flow. Our DLT node connects to peers and downloads blocks to catch up. - -#### Step 1: Connection & handshake - -``` -connect_to_peer(seed_node) - → TCP connect - → send_hello_message() [our_state = just_connected] - → peer responds: connection_accepted_message - → on_connection_accepted_message() [our_state = connection_accepted] - → send address_request_message - → peer responds: address_message - → on_address_message() - → both our_state and their_state == connection_accepted - → move_peer_to_active_list(peer) ← LOG: "New peer is connected (X.X.X.X:2001), now N active peers" - → new_peer_just_added(peer) -``` - -**Code path:** `node.cpp` lines 4793→4802 (outbound connect), 2287 (connection accepted), 2373→2397 (address message completes handshake). - -#### Step 2: Sync initiation — `new_peer_just_added()` - -Called immediately after handshake completes: - -```cpp -void new_peer_just_added(peer) { - send current_time_request_message; - start_synchronizing_with_peer(peer); // ← triggers sync -} -``` - -#### Step 3: `start_synchronizing_with_peer(peer)` - -Resets peer sync state and begins fetching: - -```cpp -peer->ids_of_items_to_get.clear(); -peer->number_of_unfetched_item_ids = 0; -peer->we_need_sync_items_from_peer = true; // ← marks peer as sync source -peer->last_block_delegate_has_seen = item_hash_t(); // empty — no reference point yet -peer->inhibit_fetching_sync_blocks = false; -fetch_next_batch_of_item_ids_from_peer(peer); -``` - -#### Step 4: `fetch_next_batch_of_item_ids_from_peer(peer)` - -Builds our blockchain synopsis and sends it to the peer: - -``` -create_blockchain_synopsis_for_peer(peer) - → reference_point = peer->last_block_delegate_has_seen = empty (first call) - → ids_of_items_to_get is empty (just cleared) - → calls _delegate->get_blockchain_synopsis(item_hash_t(), 0) -``` - -#### Step 5: `get_blockchain_synopsis()` — what our DLT node sends - -In `p2p_plugin.cpp`, with empty reference point (= "summarize whole chain"): - -``` -high_block_num = head_block_num() = 79504801 -low_block_num = last_non_undoable_block_num() = 79504801 (LIB == head) - -Loop iteration: - push get_block_id_for_num(79504801) → block_id_79504801 - low_block_num += (79504801 - 79504801 + 2) / 2 = 1 - low_block_num = 79504802 > 79504801 → stop - -Result: synopsis = [block_id_79504801] (1 entry) -``` - -LOG: `"DLT mode: get_blockchain_synopsis() returning 1 entries, low=79504801, high=79504801, head=79504801, LIB=79504801, earliest_available=79504801"` - -The node sends `fetch_blockchain_item_ids_message { type=block, synopsis=[block_id_79504801] }` to the peer. - -Also stores: `peer->item_ids_requested_from_peer = (synopsis, timestamp)` — records that we're waiting for a response. - -#### Step 6: Peer processes our synopsis - -The **peer** (a normal full node, e.g. at head #80000000) receives our `fetch_blockchain_item_ids_message` and processes it in their `on_fetch_blockchain_item_ids_message()`: - -``` -peer's get_block_ids(synopsis=[block_id_79504801], remaining): - → iterates synopsis in reverse - → is_known_block(block_id_79504801)? - → block_summary: slot 79504801 & 0xFFFF was overwritten by block ~79570337 → no match - → fetch_block_by_id: read block #79504801 from block_log, check id matches → YES - → is_included_block(block_id_79504801)? - → get_block_id_for_num(79504801): reads from block_log → same id → YES - → found! last_known_block_id = block_id_79504801, start_num = 79504801 - - → Loop from 79504801 to min(peer_head, 79504801 + limit): - result = [block_id_79504801, block_id_79504802, block_id_79504803, ..., block_id_X] - → remaining_item_count = peer_head - X -``` - -Peer sends back `blockchain_item_ids_inventory_message`: -- `item_hashes_available`: [block_id_79504801, block_id_79504802, ..., block_id_X] (up to `limit`, typically 2000) -- `total_remaining_item_count`: N (many thousands more blocks) - -#### Step 7: Our node receives peer's block ID list - -`on_blockchain_item_ids_inventory_message()` processes the response: - -``` -1. Diagnostic log: peer, count, block range, remaining - -2. Check: item_ids_requested_from_peer is set? YES (set in step 4) - -3. Validate: item_hashes_available is sequential? YES - -4. Validate: first item (block_id_79504801) is in our synopsis? YES - -5. Reset: item_ids_requested_from_peer = empty - -6. Check "up to date" condition: - total_remaining_item_count == 0? NO (N > 0) - → NOT up to date, proceed to receive blocks - -7. Dedup: pop blocks we already have from front of list: - - block_id_79504801: has_item() → is_known_block() → YES → pop - - block_id_79504802: has_item() → is_known_block() → NO → stop - -8. Remaining: item_hashes_received = [block_id_79504802, ..., block_id_X] - -9. Append to: peer->ids_of_items_to_get - -10. Since total_remaining_item_count > 0: - if ids_of_items_to_get.size() > GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH: - trigger_fetch_sync_items_loop() ← starts downloading actual blocks - else: - fetch_next_batch_of_item_ids_from_peer() ← get more IDs first -``` - -#### Step 8: Block fetching and application - -`fetch_sync_items_loop()` requests actual block data from peers: - -``` -For each block_id in ids_of_items_to_get: - → send fetch_items_message to peer - → peer responds with block_message containing full signed_block - → process_block_message(): - → _delegate->handle_block() - → chain.accept_block() → database::push_block() → fork_db → apply - → head advances: 79504802, 79504803, ... -``` - -As blocks are applied: -- `dlt_block_log` receives new irreversible blocks -- `block_summary` is updated with new block IDs -- `fork_db` grows with new blocks -- LIB advances as validators produce super-majority - -#### Step 9: Subsequent synopsis rounds - -After all IDs from the first batch are fetched, or when more IDs are needed: - -``` -fetch_next_batch_of_item_ids_from_peer(peer): - → peer->last_block_delegate_has_seen is now set to the last deduped block - → create_blockchain_synopsis_for_peer: - → reference_point = last block peer told us about that we already had - → synopsis includes blocks from our chain + ids_of_items_to_get - → sends next fetch_blockchain_item_ids_message - → peer responds with the next batch of block IDs - → cycle continues until peer says total_remaining_item_count == 0 -``` - -#### Step 10: Sync complete - -When peer responds with `total_remaining_item_count == 0` and all blocks have been fetched: - -``` -on_blockchain_item_ids_inventory_message: - → "up to date" condition is true - → peer->we_need_sync_items_from_peer = false - → LOG: "Sync: peer X says we're up-to-date" - → node transitions to normal operation (receiving broadcast blocks) -``` - -### Flow 2: Inbound sync — peer fetches blocks FROM our DLT node - -This flow describes what happens when another node connects to our DLT node and asks for blocks. - -#### Step 1: Peer connects to us - -The peer initiates a TCP connection. We receive their hello message in `on_hello_message()`: - -``` -Validate: signature, protocol version, chain ID - → all pass → their_state = connection_accepted - → send connection_accepted_message - → exchange address messages - → move_peer_to_active_list() - → new_peer_just_added() ← we also start syncing FROM them (Flow 1) -``` - -Meanwhile, the peer also starts syncing from us (they send their synopsis). - -#### Step 2: Peer sends us their synopsis - -The peer sends `fetch_blockchain_item_ids_message` with their synopsis, e.g. `[..., block_id_79501245]` (their most recent known block). Our `on_fetch_blockchain_item_ids_message()` processes it: - -``` -_delegate->get_block_ids(synopsis=[..., block_id_79501245], remaining): - → iterate synopsis in reverse looking for a known block - → find block_id_79501245 (if it's in our block_summary and on our chain) - → start_num = 79501245 - - DLT mode clamping: - → earliest_available = earliest_available_block_num() = 79504801 - → 79501245 < 79504801 → clamp start_num to 79504801 - - → Loop from 79504801 to head (79504801): - result = [block_id_79504801] - → remaining_item_count = 0 - - LOG: "DLT mode: get_block_ids() clamping start from 79501245 to 79504801" - LOG: "DLT mode: get_block_ids() returning 1 block IDs (start=79504801, head=79504801)" -``` - -We respond with `blockchain_item_ids_inventory_message`: -- `item_hashes_available`: [block_id_79504801] -- `total_remaining_item_count`: 0 - -#### Step 3: Peer processes our response - -On the peer's side, they receive our 1-block response: -- `item_hashes_available.size() == 1` -- `has_item(block_id_79504801)` → YES (peer already has this block) -- `total_remaining_item_count == 0` -- Conclusion: **we're up to date** — the peer marks `we_need_sync_items_from_peer = false` for us - -This is correct — our DLT node only has 1 block, so the peer can't get anything useful from us yet. As our node syncs and accumulates blocks in `dlt_block_log`, future peers will get more blocks from us. - -#### Step 4: Peer determines sync direction - -The peer also checks `peer_needs_sync_items_from_us`: -- Our synopsis had `[block_id_79504801]` -- Peer's `get_block_ids(our_synopsis)` → finds block #79504801, returns blocks after it -- `peer_needs_sync_items_from_us = true` → peer will send us blocks (Flow 1, step 6) - -### Flow 3: Broadcast inventory suppression - -During sync (Flow 1), peers also send real-time broadcast inventory (new transactions/blocks at chain tip). Without suppression, this causes timeout disconnects: - -``` -Peer sends item_ids_inventory_message (broadcast transactions) - → on_item_ids_inventory_message(): - Layer 1: originating_peer->we_need_sync_items_from_peer? → YES → SKIP - (or) - Layer 2: any active peer has we_need_sync_items_from_peer? → YES → SKIP - (or) - Layer 3: head block time > 30s behind wall clock? → YES → SKIP - - → broadcast inventory silently dropped during sync - → prevents items_requested_from_peer pollution - → prevents 1-second active_ignored_request_timeout disconnects -``` - -### Key code locations - -| Function | File | Purpose | -|----------|------|---------| -| `new_peer_just_added()` | node.cpp:4356 | Entry point: triggers sync after handshake | -| `start_synchronizing_with_peer()` | node.cpp:4333 | Sets sync flags, begins ID fetch | -| `fetch_next_batch_of_item_ids_from_peer()` | node.cpp:2580 | Builds synopsis, sends to peer | -| `create_blockchain_synopsis_for_peer()` | node.cpp:2527 | Generates synopsis from chain state | -| `get_blockchain_synopsis()` | p2p_plugin.cpp:370 | DLT-aware synopsis generation | -| `on_blockchain_item_ids_inventory_message()` | node.cpp:2618 | Processes peer's block ID response | -| `on_fetch_blockchain_item_ids_message()` | node.cpp:2403 | Responds to peer's synopsis with block IDs | -| `get_block_ids()` | p2p_plugin.cpp:249 | DLT-aware block ID enumeration with clamping | -| `on_item_ids_inventory_message()` | node.cpp:3048 | Broadcast inventory suppression | -| `fetch_sync_items_loop()` | node.cpp | Requests actual block data from peers | -| `send_sync_block_to_node_delegate()` | node.cpp | Pushes sync blocks to chain; handles `deferred_resize_exception` | -| `terminate_inactive_connections_loop()` | node.cpp | Auto-clears stuck `peer_needs_sync_items_from_us` (30s timeout) | -| `trigger_resync()` | p2p_plugin.cpp | Re-initiates P2P sync after snapshot hot-reload | -| `is_known_block()` | database.cpp:726 | DLT-aware block existence check | -| `earliest_available_block_num()` | database.cpp | Lowest block the node can actually serve | - -### Sync deadlock prevention - -On a live chain producing blocks every 3 seconds, a race condition can cause the sync to stall permanently: - -1. The seed finishes processing sync blocks and sends a "final synopsis" to the master -2. The master has already produced new blocks, so the reply has >1 item -3. `peer_needs_sync_items_from_us` stays `true` on the master → inventory advertisements blocked -4. The seed fetches the new blocks, sends another synopsis, but the master has more blocks again -5. This chase loop repeats — especially when `deferred_resize_exception` slows the seed during catch-up - -**Fix 1: Early inventory-mode transition (`remaining == 0`)** - -In `on_fetch_blockchain_item_ids_message()`, when the master's reply has `total_remaining_item_count == 0` (all blocks sent), the master now sets `peer_needs_sync_items_from_us = false` immediately — even if the reply has multiple items. The peer is close enough that inventory mode can deliver any new blocks produced during the remaining sync processing. - -Flag logic (master-side `on_fetch_blockchain_item_ids_message`): - -| Condition | `peer_needs_sync_items_from_us` | Meaning | -|---|---|---| -| Reply empty | `false` | Our chain is empty | -| Reply = 1 item in synopsis | `false` | Peer is fully caught up | -| Reply >1 item, `remaining == 0` | `false` | Peer is nearly caught up — switch to inventory | -| Reply >1 item, `remaining > 0` | `true` | Peer is far behind, keep sync mode | - -**Fix 2: Auto-clear safety net (30-second timeout)** - -In `terminate_inactive_connections_loop()`, if `peer_needs_sync_items_from_us` has been `true` for >30 seconds without the peer sending any `fetch_blockchain_item_ids` request, the flag is force-cleared. This catches edge cases where `deferred_resize_exception` prevents the seed from sending the final synopsis (because `peers_with_newly_empty_item_lists` is never populated when the block isn't applied). - -**Fix 3: Post-snapshot `trigger_resync()`** - -After the snapshot plugin completes a hot-reload (importing a new snapshot while the node is running), it calls `p2p_plugin::trigger_resync()` to re-initiate P2P sync from the new head block. Without this, the P2P layer would continue with stale state and the peer would never receive new blocks. - -### Diagnostic logging - -All sync negotiation messages use `fc_ilog(fc::logger::get("sync"), ...)` to go through the **"sync" logger**, which must be configured in `config.ini`: - -```ini -[logger.sync] -level = info -appenders = stderr -``` - -Key diagnostic messages: -- `"Starting sync with peer ..."` — sync initiation with peer state flags -- `"sync: sending synopsis to peer ..."` — synopsis details (count, last block) -- `"on_blockchain_item_ids_inventory: ..."` — peer's response (block range, remaining, sync flags) -- `"Sync: peer X says we're up-to-date"` — sync complete for this peer -- `"Sync: received N block IDs from peer ..."` — block ID batch received -- `"sync: peer X nearly caught up (sent N items, remaining=0)"` — early inventory-mode transition -- `"sync: peer X is now in sync with us (peer_needs_sync=false)"` — flag cleared (reply=1 known item) -- `"auto-clearing stuck peer_needs_sync_items_from_us for peer X"` — 30-second safety net fired -- `"DEFERRED_RESIZE: sync block #N deferred due to shared memory resize"` — resize interrupted sync -- `"DEFERRED_RESIZE: restarting sync with all peers"` — sync restart after deferred resize -- `"sync: peer X lists now empty — sending final synopsis"` — all sync blocks processed, checking completion - -**Important:** `node.cpp` defines `#define DEFAULT_LOGGER "p2p"` (line 75), so all `ilog()`/`dlog()`/`wlog()` macros in that file go to the "p2p" logger, NOT the default logger. To make messages visible, either configure the "p2p" logger or use `fc_ilog(fc::logger::get("sync"), ...)` explicitly. - -## Modified Components - -The snapshot plugin required changes to several core components: - -| Component | Change | -|-----------|--------| -| `chainbase::generic_index` | Added `set_next_id()` / `next_id()` for ID preservation during import | -| `fork_database.cpp` | Fixed `_unlinked_index.insert()` dead code (moved before `throw`); added `_push_next(item)` call at end of `_push_block` to resolve previously-unlinkable blocks; added duplicate block check in `_push_block`; added `_unlinked_index.clear()` to `reset()` | -| `database.hpp/cpp` | Added `open_from_snapshot()`, `initialize_hardforks()`, `reindex_from_dlt()`, `get_fork_db()`, `_dlt_mode` flag with `set_dlt_mode()` setter; DLT mode skips block_log writes and detects empty block_log on restart; `is_known_block()` in DLT mode checks block_summary then verifies preferred chain via `find_block_id_for_num()` (prevents both lying to peers and breaking sync negotiation); DLT restart seeds fork_db from dlt_block_log when available; early rejection in `_push_block`: duplicate blocks (at/before head, same ID), blocks at/before head on different fork with unknown parent (prevents P2P sync restart loop), far-ahead broadcast blocks (parent unknown and not head_block_id), with immediate successor (`previous == head_block_id()`) always allowed; DLT block log gap logging via `wlog`; DLT block log empty-skip logic for fresh snapshot imports; corruption detection throws `shared_memory_corruption_exception` (instead of `FC_ASSERT`) from all validator-account-missing checks (generate_block, process_funds, HF4 path) | -| `database_exceptions.hpp` | Added `shared_memory_corruption_exception` (code 4140000) for runtime corruption detection | -| `dlt_block_log.hpp/cpp` | New class: offset-aware rolling block log with 8-byte header index, `truncate_before()` for rotation, read/write with mutex locking | -| `chain plugin` | Added `snapshot_load_callback`, `snapshot_create_callback`, `snapshot_p2p_sync_callback`; restart safety (shared_memory check + `.used` rename + file existence check); LIB promotion after snapshot import (LIB = head_block_num for correct P2P synopsis); `dlt-block-log-max-blocks` config option; diagnostic warning when node has 0 blocks and no snapshot sync configured; `--replay-from-snapshot` crash recovery mode (wipes shared_memory, imports snapshot, replays dlt_block_log via `reindex_from_dlt`, does not rename snapshot); `--snapshot-auto-latest` auto-discovery of latest snapshot in `snapshot-dir`; `--auto-recover-from-snapshot` (default: `true`) immediate runtime recovery — `accept_block` and validator `generate_block` catch `shared_memory_corruption_exception`, call `attempt_auto_recovery()` which closes DB, finds latest snapshot, wipes shared memory, imports snapshot, replays dlt_block_log, and resumes P2P sync without restart | -| `snapshot plugin` | Full implementation: create/load/periodic snapshots; P2P TCP sync (serve + download with concurrent fiber handling on a dedicated `fc::thread`); 5-second peer operation timeout (connect, send, read); anti-spam (rate limiting, mutex-protected session tracking, enforced per-operation connection deadline); cached snapshot info; streaming SHA-256 checksum; built-in rotation (`snapshot-max-age-days`); elapsed time logging for all operations; console progress logging for download/import; `sync-snapshot-from-trusted-peer` defaults to `false` (opt-in); auto-creates snapshot directory; periodic snapshots only trigger on live blocks (skipped during P2P sync); memory optimization: compressed data freed immediately after decompression; `--snapshot-auto-latest` auto-discovery of latest snapshot file by block number; `find_latest_snapshot()` helper; **async snapshot creation**: `on_applied_block` schedules snapshot on a dedicated `fc::thread` (not the main thread's fc scheduler, which is blocked by `io_serv->run()`); `create_snapshot` splits into Phase 1 (read lock for DB serialization only) and Phase 2 (compression + file I/O without lock); `snapshot_in_progress` atomic flag prevents overlapping snapshots; `write_snapshot_to_file` accepts pre-captured header+state (no DB access needed); shutdown waits for in-progress snapshot before quitting thread; **DLT restart safety**: `load_snapshot()` persists the snapshot's head block into `dlt_block_log` so `database::open()` can seed `fork_db` on restart; **stale snapshot detection**: at startup, compares latest snapshot block against `dlt_block_log.start_block_num()` — if snapshot is older than DLT start, creates an urgent fresh snapshot on first synced block to prevent serving a broken snapshot with unsyncable gap | -| `content_object.hpp` | Added missing `FC_REFLECT` for `content_object`, `content_type_object`, `content_vote_object` | -| `witness_objects.hpp` | Added missing `FC_REFLECT` for `witness_vote_object` | -| `proposal_object.hpp` | Added missing `FC_REFLECT` for `required_approval_object` | -| `vizd/main.cpp` | Registered `snapshot_plugin`, linked `graphene::snapshot` | -| `p2p_plugin` | Added `_dlt_block_log` fallback in `get_item()` for serving blocks to peers in DLT mode; added `trigger_resync()` for post-snapshot-reload P2P re-initiation; added `last_peer_sync_request_time` to `peer_connection` for stuck-flag detection | -| `node.cpp` (network library) | Added early inventory-mode transition when `remaining == 0`; auto-clear of stuck `peer_needs_sync_items_from_us` (30s timeout); `DEFERRED_RESIZE` diagnostic logging; final synopsis diagnostic logging | diff --git a/.qoder/docs/staking-and-dao-governance.md b/.qoder/docs/staking-and-dao-governance.md deleted file mode 100644 index 0905c6814d..0000000000 --- a/.qoder/docs/staking-and-dao-governance.md +++ /dev/null @@ -1,291 +0,0 @@ -# VIZ Staking (Vesting Shares) and DAO Self-Governance - -## What is Staking in VIZ - -In VIZ, **staking** means converting liquid VIZ tokens into **SHARES** (vesting shares). Staked tokens are locked and cannot be transferred directly, but they grant the holder **governance power** — the ability to vote, award, delegate, and influence every aspect of the blockchain. - -Every VIZ account has three vesting fields: - -| Field | Meaning | -|---|---| -| `vesting_shares` | SHARES owned by the account | -| `delegated_vesting_shares` | SHARES delegated to other accounts (reduces your power) | -| `received_vesting_shares` | SHARES received via delegation from others (increases your power) | - -**Effective vesting shares** — the actual governance power used everywhere: - -``` -effective_vesting_shares = vesting_shares − delegated_vesting_shares + received_vesting_shares -``` - -This is the number that determines your weight in every vote, award, and governance action. - ---- - -## Staking Operations - -### Stake: `transfer_to_vesting_operation` - -Converts liquid VIZ to SHARES. Can stake to yourself or to another account. - -```json -["transfer_to_vesting", { - "from": "alice", - "to": "bob", - "amount": "1000.000 VIZ" -}] -``` - -### Unstake: `withdraw_vesting_operation` - -Initiates gradual withdrawal of SHARES back to liquid VIZ. The withdrawal happens over **28 daily intervals** (28 days total), where each day `vesting_shares / 28` is converted to liquid tokens. - -```json -["withdraw_vesting", { - "account": "alice", - "vesting_shares": "1000.000000 SHARES" -}] -``` - -Setting `vesting_shares` to 0 cancels the withdrawal. - -### Withdrawal Routes: `set_withdraw_vesting_route_operation` - -Directs withdrawn SHARES to another account, optionally re-staking them automatically (`auto_vest = true`). Up to 10 routes per account. - -```json -["set_withdraw_vesting_route", { - "from_account": "alice", - "to_account": "bob", - "percent": 5000, - "auto_vest": true -}] -``` - -### Delegate: `delegate_vesting_shares_operation` - -Transfers voting power (not ownership) to another account. The delegator keeps ownership, the delegatee gets governance power. - -```json -["delegate_vesting_shares", { - "delegator": "alice", - "delegatee": "bob", - "vesting_shares": "500.000000 SHARES" -}] -``` - -When removing delegation, the SHARES enter a 5-day expiration period (matching energy regeneration time) to prevent "double-spend" of voting energy. - ---- - -## Where Staked VIZ (SHARES) Are Used - -SHARES are the universal governance token. Every meaningful action in VIZ is weighted by `effective_vesting_shares`: - -### 1. validator Voting - -validators produce blocks and set chain parameters. Every account can vote for up to 100 validators. - -```json -["account_witness_vote", { - "account": "alice", - "validator": "node1", - "approve": true -}] -``` - -**Fair-DPOS weighting**: vote weight is divided equally across all validators the account votes for: - -``` -fair_weight = (vesting_shares + proxied_votes) / witnesses_voted_for -``` - -This prevents concentration of power — if you vote for 10 validators, each gets 1/10 of your stake weight, not the full amount. - -Accounts can also set a **proxy** (`account_witness_proxy_operation`), delegating their validator voting to another account. - -### 2. Committee DAO Voting - -Any account can create a **worker request** (funding proposal) and all SHARES holders vote to approve or reject it: - -```json -["committee_vote_request", { - "voter": "alice", - "request_id": 42, - "vote_percent": 7500 -}] -``` - -- `vote_percent` ranges from **−10000** (strong oppose) to **+10000** (strong support) -- Weight: `effective_vesting_shares × vote_percent / 10000` -- The payout amount is proportional to net positive consensus -- Requires minimum participation threshold (% of total staked supply) - -See [committee-dao-and-prediction-markets.md](committee-dao-and-prediction-markets.md) for full details. - -### 3. Awards (Social Capital Distribution) - -The **award operation** is VIZ's unique mechanism for distributing rewards from the shared reward fund. Any account can award any other account, spending regenerating **energy**: - -```json -["award", { - "initiator": "alice", - "receiver": "bob", - "energy": 1000, - "custom_sequence": 0, - "memo": "Great work!", - "beneficiaries": [] -}] -``` - -**How energy works:** -- Every account has energy in range 0–10000 (0%–100%) -- Energy regenerates linearly over 5 days (`CHAIN_ENERGY_REGENERATION_SECONDS = 432000`) -- Each award consumes the specified energy amount - -**How SHARES determine reward size:** - -``` -rshares = effective_vesting_shares × used_energy / 10000 -``` - -The `rshares` value determines how much of the global reward fund is claimed. An account with 10× more SHARES creates 10× more reward for the same energy expenditure. Rewards are distributed as SHARES to the receiver (and beneficiaries). - -A `fixed_award_operation` variant lets you specify an exact reward amount — the system calculates the required energy. - -### 4. Chain Parameter Governance - -validators publish their preferred chain parameters, and the **median** value across all active validators becomes the consensus setting. Since validators are elected by stake-weighted voting, the chain parameters are indirectly controlled by all SHARES holders. - -Parameters governed this way include: -- `account_creation_fee` — cost to create new accounts -- `maximum_block_size` — throughput limit -- `min_delegation` — minimum delegation amount -- `committee_request_approve_min_percent` — participation threshold for DAO proposals -- `vote_accounting_min_rshares` — minimum award impact threshold -- `bandwidth_reserve_percent` — network bandwidth allocation -- `min_curation_percent`, `max_curation_percent` — content reward distribution -- `withdraw_intervals` — vesting withdrawal period -- And others - -### 5. Bandwidth Allocation - -Network bandwidth (transaction throughput) is allocated proportionally to `effective_vesting_shares`. Accounts with more stake can send more transactions per unit of time. Accounts below 500 SHARES get an additional 10% bandwidth reserve. - -### 6. Account Creation via Delegation - -New accounts can be created by delegating SHARES to them (at 10× ratio for 30 days), making account creation accessible without spending liquid tokens. - ---- - -## VIZ as a DAO: Every Member Controls Their Share - -### The DAO Analogy - -VIZ is not just a blockchain — it is a **Decentralized Autonomous Organization** where every SHARES holder is a member with governance rights proportional to their stake. Think of it this way: - -| Traditional DAO | VIZ Blockchain | -|---|---| -| DAO treasury | Committee fund + reward fund | -| DAO shares / governance tokens | SHARES (vesting shares) | -| Proposal voting | Committee worker requests | -| Board of directors | Elected validators | -| Director elections | validator voting (Fair-DPOS) | -| Dividend distribution | Award mechanism (reward fund) | -| Bylaws / parameters | Chain properties (median governance) | -| Delegation of voting rights | `delegate_vesting_shares` + validator proxy | - -### How Each Member "Controls Their Share of the DAO" - -#### 1. Direct Financial Governance - -Every SHARES holder can vote on **how the DAO treasury (committee fund) is spent**. Worker proposals request funding for development, marketing, infrastructure, or any community purpose. Your vote weight is your exact share of the total staked supply. - -If you hold 1% of all SHARES, your vote carries exactly 1% weight in every committee decision. You can vote **for** (up to +100%) or **against** (down to −100%) with fine-grained intensity. You don't just approve or reject — you express **how strongly** you feel. - -#### 2. Electing Leadership - -validators are the "board of directors" — they produce blocks, validate transactions, and **set chain parameters** through median voting. Every SHARES holder votes for validators, and Fair-DPOS ensures your voting power is split equally across your chosen validators, preventing vote concentration. - -If you don't want to vote directly, you can **set a proxy** — delegate your validator voting to someone you trust, just like a proxy vote in a shareholder meeting. - -#### 3. Direct Value Distribution - -The **award mechanism** lets every member distribute value from the shared reward fund to any other member. This is unique to VIZ — there's no proposal process needed, no minimum threshold. If you hold SHARES and have energy, you can reward anyone, anytime. - -The reward is proportional to your stake: more SHARES = more reward per energy unit. This is like having a share of the DAO's dividend pool that you can direct to anyone you choose. - -#### 4. Power Delegation - -Through `delegate_vesting_shares`, you can lend your governance power to another account without transferring ownership. This enables: - -- **Empowering new members**: delegate SHARES to newcomers so they can participate in governance -- **Specialization**: delegate to accounts that focus on specific governance tasks -- **Service providers**: delegate to bots or services that vote on your behalf -- **Account creation**: bootstrap new accounts by delegating the minimum required stake - -The delegatee gains your voting power for awards, committee votes, and bandwidth, while you retain full ownership and can revoke at any time (with a 5-day cooldown). - -#### 5. Rule-Setting - -Chain parameters are set by the **median** of validator-published values. Since you elect validators, you indirectly control: -- How expensive it is to create accounts -- How the reward fund is distributed between content creators and curators -- What the minimum participation threshold is for committee proposals -- How long vesting withdrawals take -- Network capacity and transaction limits - -If the current parameters don't serve your interests, you vote for validators who share your vision. The median mechanism ensures no single validator (or voter) can impose extreme values — only the community consensus prevails. - -### Why This Works as Self-Governance - -1. **Proportional representation**: 1 SHARES = 1 unit of influence everywhere. No special privileges, no tiered membership. - -2. **Bipolar voting**: negative votes are first-class citizens. Opposing a bad proposal is just as powerful as supporting a good one. This prevents apathy-driven approval. - -3. **Continuous governance**: there are no "governance seasons" or "voting periods" for validators — you can change your votes at any time. Committee proposals have time-bounded voting, but you can update your vote throughout. - -4. **Skin in the game**: SHARES are locked tokens. To gain governance power, you must commit capital. To exit, you wait 28 days. This ensures voters have long-term alignment with the ecosystem. - -5. **No trusted intermediaries**: all governance rules are enforced by protocol code, not by humans. Committee payouts, validator elections, parameter changes — everything is automatic and verifiable. - -6. **Delegation without custody**: you can amplify others' power without giving them your tokens. Revocation is always possible. This enables trust hierarchies without centralization. - -### The Governance Cycle - -``` -Stake VIZ → Get SHARES → Governance Power - ├── Vote for validators → Control block production & chain parameters - ├── Vote on committee → Control treasury spending - ├── Award other accounts → Distribute value from reward fund - ├── Delegate to others → Amplify allies' governance power - └── Set chain parameters → Shape the rules (via validator election) - ↓ - validators produce blocks → Rewards generated → Reward fund grows - ↓ - Committee fund grows → Proposals funded → Ecosystem develops - ↓ - VIZ value increases → More staking incentive → Cycle continues -``` - -This is a complete, self-sustaining DAO where every participant's influence is exactly proportional to their committed stake, and every aspect of the system — from treasury spending to network parameters to value distribution — is governed by the collective will of SHARES holders. - ---- - -## Constants Reference - -| Constant | Value | Description | -|---|---|---| -| `CHAIN_VESTING_WITHDRAW_INTERVALS` | 28 | Number of daily withdrawal installments | -| `CHAIN_VESTING_WITHDRAW_INTERVAL_SECONDS` | 86400 (1 day) | Time between withdrawal installments | -| `CHAIN_MAX_WITHDRAW_ROUTES` | 10 | Maximum withdrawal routing destinations | -| `CHAIN_ENERGY_REGENERATION_SECONDS` | 432000 (5 days) | Full energy regeneration period | -| `CHAIN_100_PERCENT` | 10000 | Basis points (100.00%) | -| `CHAIN_MIN_DELEGATION` | 1 VIZ | Minimum delegation amount | -| `CHAIN_CREATE_ACCOUNT_DELEGATION_RATIO` | 10× | Delegation multiplier for account creation | -| `CHAIN_CREATE_ACCOUNT_DELEGATION_TIME` | 30 days | Minimum delegation lock for account creation | -| `CHAIN_MAX_ACCOUNT_WITNESS_VOTES` | 100 | Maximum validators per account | -| `CONSENSUS_VOTE_ACCOUNTING_MIN_RSHARES` | 5000000 | Minimum rshares for award to have effect | -| `CONSENSUS_COMMITTEE_REQUEST_APPROVE_MIN_PERCENT` | 1000 (10%) | Default participation threshold for proposals | -| `CONSENSUS_BANDWIDTH_RESERVE_BELOW` | 500 SHARES | Threshold for bandwidth reserve | -| `CONSENSUS_BANDWIDTH_RESERVE_PERCENT` | 1000 (10%) | Extra bandwidth for small accounts | diff --git a/.qoder/docs/validator-guard.md b/.qoder/docs/validator-guard.md deleted file mode 100644 index 082a14a27f..0000000000 --- a/.qoder/docs/validator-guard.md +++ /dev/null @@ -1,151 +0,0 @@ -# validator guard Plugin - -The `witness_guard` plugin is an automated maintenance tool for VIZ validator node operators. It monitors configured validator accounts and automatically restores their signing keys when they are reset to null (which disables the validator). - -## Purpose - -In VIZ a validator can be disabled (signing key set to null) by manual intervention, security protocols, or certain network conditions. This plugin automates the restore process so the validator stays active without manual monitoring. - -When the plugin detects a null signing key on-chain, it constructs, signs, and broadcasts a `witness_update_operation` to re-enable the validator using the provided private keys. - -## Configuration - -The plugin is configured via `config.ini` or command-line arguments. - -### Options - -| Option | Type | Default | Description | -| :--- | :--- | :--- | :--- | -| `validator-guard-enabled` | boolean | `true` | Enables or disables the plugin logic globally. | -| `validator-guard-interval` | uint32 | `20` | Frequency of periodic checks in blocks (20 blocks ≈ 60 seconds). | -| `validator-guard-validator` | vector\ | N/A | A JSON triplet: validator name, signing WIF, active WIF. Repeatable. | -| `validator-guard-disable` | uint32 | `5` | Number of consecutive blocks produced by the same validator before auto-disabling (setting signing key to null). Set to `0` to disable this feature. | - -The plugin also reads the shared `enable-stale-production` option from the Validator Plugin configuration. - -### Enabling the Plugin - -Add it to the active plugins in `config.ini`: - -```ini -plugin = witness_guard -``` - -## Usage Example - -```ini -# Monitor and auto-restore winet1 -validator-guard-validator = ["winet1", "5K_SIGNING_PRIVATE_WIF", "5K_ACTIVE_PRIVATE_WIF"] - -# Monitor multiple validators by repeating the option -validator-guard-validator = ["winet2", "5J_SIGNING_PRIVATE_WIF", "5J_ACTIVE_PRIVATE_WIF"] - -# Check every 10 blocks instead of 20 -validator-guard-interval = 10 -``` - -## Internal Logic - -### Startup - -1. **Key parsing**: Each `validator-guard-validator` entry is parsed as a JSON array of three strings. Both WIF keys are validated. -2. **Stale production detection**: If `enable-stale-production=true` is set in the validator config, auto-restore is initially disabled (see Safety Guards below). -3. **Disable threshold**: If `validator-guard-disable` is greater than 0, the consecutive-block auto-disable feature is enabled (see below). -4. **Authority validation**: After the chain database is open, the plugin verifies that each configured active key actually has authority on-chain. validators whose accounts are not found are removed from monitoring. -5. **Initial check**: An immediate check is attempted. If the node is already in sync, the result is cached so the plugin switches to its normal periodic schedule. - -### Per-Block Signal Handler (`applied_block`) - -On every new block the plugin: - -0. **Consecutive-block auto-disable**: If `validator-guard-disable > 0` and the block was produced by one of our monitored validators, the plugin increments a per-validator consecutive-block counter. When the counter reaches the configured threshold, a `witness_update_operation` with a null signing key is broadcast to disable the validator, and it is marked as auto-disabled. If the block was produced by a *different* validator, all counters are reset to zero (the streak is broken). -1. **Transaction confirmation**: Scans the block for any pending restore transaction IDs. When found, the restore is marked as confirmed and tracking state is cleared. -2. **Look-ahead scheduling**: If any monitored validator is scheduled to produce within the next 3 slots, an immediate check is triggered so the key can be restored before the slot arrives. -3. **Periodic check**: Otherwise runs `check_and_restore_internal` at the configured interval. While the node is still syncing after startup, checks run every 10 blocks instead. - -### Core Check (`check_and_restore_internal`) - -1. **Stale production guard**: If `enable-stale-production` is active and network participation is below 33%, all checks are skipped. Once participation reaches ≥ 33% the stale flag is auto-cleared (same logic as the Validator Plugin) and auto-restore resumes. During emergency consensus mode the guard is bypassed. -2. **Sync check**: Head block time must be within `2 × CHAIN_BLOCK_INTERVAL` seconds of wall-clock time. -3. **Long fork safety**: If the Last Irreversible Block (LIB) is older than 200 seconds, restoration is skipped to avoid acting on a stale fork. -4. **Expiry cleanup**: Stale entries in `_pending_confirmations` are expired so that failed broadcasts can be retried. -5. **validator iteration**: For each configured validator, the on-chain signing key is checked. If the key is present, any pending restore state and auto-disabled flag are cleared. If null and the validator was auto-disabled by the consecutive-block guard, auto-restore is skipped (the operator must investigate and restart). Otherwise, if no restore is currently in-flight (or the previous one expired), `send_witness_update` is called. - -### Restore Transaction (`send_witness_update`) - -1. Builds a `witness_update_operation` preserving the current on-chain URL and setting the signing key to the configured public key. -2. Wraps it in a `signed_transaction` with a 30-second expiration and head block reference. -3. Signs with the configured active private key. -4. Broadcasts via the P2P plugin. -5. Tracks the transaction ID in `_pending_confirmations` and the validator in `_restore_pending` to prevent duplicate broadcasts. - -### Disable Transaction (`send_witness_disable`) - -1. Builds a `witness_update_operation` preserving the current on-chain URL and setting the signing key to **null** (effectively disabling block production). -2. Wraps it in a `signed_transaction` with a 30-second expiration and head block reference. -3. Signs with the configured active private key. -4. Broadcasts via the P2P plugin. -5. Adds the validator to the `_auto_disabled_witnesses` set so that the auto-restore logic does **not** re-enable it automatically. - -## Safety Guards - -| Guard | Behavior | -| :--- | :--- | -| **Stale production** | When `enable-stale-production=true`, auto-restore is disabled to avoid broadcasting on a minority fork. **Auto-cleared** when participation ≥ 33%. | -| **Emergency mode** | During emergency consensus (`dgp.emergency_consensus_active`), the stale production guard is bypassed — key restoration may still be needed for recovery. | -| **Sync check** | Restoration only runs when the node is synchronized (head block recent). | -| **Long fork detection** | If LIB is older than 200 seconds, restoration is skipped. | -| **Authority validation** | At startup, configured active keys are verified against on-chain authority. | -| **Consecutive-block auto-disable** | When a monitored validator produces `validator-guard-disable` consecutive blocks, it is automatically disabled (signing key set to null). Auto-restore is suppressed until the operator manually restores the key (at which point the flag is cleared). | -| **Duplicate prevention** | In-flight restores are tracked with expiration; no duplicate transactions are sent. | - -## Security Considerations - -> [!CAUTION] -> **Private Key Exposure** -> This plugin requires the **Active Private Key** in plain text in `config.ini`. The active key has significant control over your account (transfers, permission changes). Ensure `config.ini` has strictly restricted file system permissions (e.g., `chmod 600 config.ini` on Linux). - -## Logs - -* **Initialization**: - `witness_guard: monitoring validator 'winet1' (signing key: VIZ...)` -* **Stale production detected**: - `witness_guard: enable-stale-production detected — auto-restore is DISABLED until network participation >= 33%` -* **Stale production auto-cleared**: - `witness_guard: network is healthy (participation XX%), auto-clearing stale production override` -* **Restore triggered**: - `witness_guard: 'winet1' has null signing key on-chain — initiating restore` -* **Broadcast sent**: - `witness_guard: broadcasting witness_update [ID: ...] for 'winet1' — restoring key to VIZ...` -* **Confirmed on-chain**: - `witness_guard: CONFIRMED restoration for 'winet1' in block #N [TX: ...]` -* **Long fork warning**: - `witness_guard: POTENTIAL LONG FORK DETECTED! LIB #N is Xs old. Skipping restoration.` -* **Consecutive-block auto-disable triggered**: - `witness_guard: validator '${w}' produced ${c} consecutive blocks — auto-disabling (threshold=${t})` -* **Disable broadcast sent**: - `witness_guard: broadcasting witness_update [ID: ...] for '${w}' — DISABLING (setting key to null)` -* **Auto-restore skipped (auto-disabled validator)**: - `witness_guard: '${w}' was auto-disabled (consecutive block limit), skipping auto-restore` -* **Failure**: - `witness_guard: witness_update FAILED for 'winet1': [error details]` - -## Troubleshooting - -**Error: validator-guard-validator expects [name, signing_wif, active_wif]** -Ensure each entry is a valid JSON array with exactly 3 strings. Use double quotes inside the brackets. - -**Restore not triggering** -1. Check that `validator-guard-enabled` is `true`. -2. Ensure the node is fully synchronized. -3. Verify the account name is a registered validator on the network. -4. If `enable-stale-production=true` is set, auto-restore is disabled until network participation reaches ≥ 33%. - -**Transaction failed** -Check that the `active_wif` belongs to the validator account. If the account's active authority has been changed, the plugin cannot sign the update. The startup log will warn about mismatched keys. - -**validator auto-disabled and not restoring** -If the log shows `was auto-disabled (consecutive block limit), skipping auto-restore`, the validator produced too many consecutive blocks and was automatically disabled as a safety measure. The operator must investigate, manually restore the signing key (or restart the node), at which point the auto-disabled flag clears. - -**Authority warning at startup** -`WARNING: Configured active key for validator 'X' does NOT have authority on-chain` — the configured active WIF does not match any key in the account's active authority. Update the key in `config.ini`. diff --git a/.qoder/docs/validator-plugin-refactoring-2026-05-14.md b/.qoder/docs/validator-plugin-refactoring-2026-05-14.md deleted file mode 100644 index 1ba5dfbe51..0000000000 --- a/.qoder/docs/validator-plugin-refactoring-2026-05-14.md +++ /dev/null @@ -1,300 +0,0 @@ -# Validator Plugin Refactoring: Remove Cached Flags - -## Date: 2026-05-14 - -## Summary - -Refactored Validator Plugin to eliminate cached internal state flags and instead query actual state directly from database and other plugins on every production tick. - -## Problem - -The Validator Plugin was caching critical state in internal variables: -- `_production_enabled` (bool): Whether production should be active -- Indirect checks via `p2p().is_catching_up_after_pause()` for snapshot status - -This created several issues: -1. **Stale state**: Cached flags could become outdated if other plugins changed state -2. **Race conditions**: Multiple sources of truth (cache vs actual state) -3. **Complexity**: Manual flag management in multiple places (initialization, recovery, error handling) -4. **Hidden dependencies**: Not clear which plugin/database state actually determines production readiness - -## Solution - -### 1. Added Public API to Snapshot Plugin - -**File:** `plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp` -```cpp -/// Returns true if a snapshot creation is currently in progress. -/// Used by the Validator Plugin to defer block production during -/// snapshot serialization (avoids write-lock contention). -bool is_snapshot_in_progress() const; -``` - -**File:** `plugins/snapshot/plugin.cpp` -```cpp -bool snapshot_plugin::is_snapshot_in_progress() const { - if (!my) return false; - return my->snapshot_in_progress.load(std::memory_order_relaxed); -} -``` - -### 2. Added Snapshot Plugin Dependency to Validator Plugin - -**File:** `plugins/validator/include/graphene/plugins/validator/validator.hpp` -```cpp -#include - -class witness_plugin final : public appbase::plugin { -public: - APPBASE_PLUGIN_REQUIRES((chain::plugin) (p2p::p2p_plugin) (snapshot::snapshot_plugin)) -``` - -**File:** `plugins/validator/validator.cpp` -```cpp -struct witness_plugin::impl final { - impl(): - p2p_(appbase::app().get_plugin()), - chain_(appbase::app().get_plugin()), - snapshot_(appbase::app().get_plugin()), - production_timer_(appbase::app().get_io_service()) { - } - - graphene::plugins::snapshot::snapshot_plugin& snapshot() { - return snapshot_; - } - - graphene::plugins::snapshot::snapshot_plugin& snapshot_; -``` - -### 3. Removed `_production_enabled` Cached Flag - -**Deleted:** -```cpp -bool _production_enabled = false; // REMOVED -``` - -**Replaced with direct database queries:** - -#### Before (cached flag): -```cpp -if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; - } else { - return not_synced; - } -} -``` - -#### After (query actual state): -```cpp -// Production readiness determined by: -// 1. DLT sync status: chain().is_syncing() -// 2. Snapshot status: snapshot().is_snapshot_in_progress() -// 3. Emergency mode: dgp.emergency_consensus_active -// 4. Participation rate: db.witness_participation_rate() -// 5. Minority fork recovery: _minority_fork_recovering - -// No cached flag - state queried fresh every tick -``` - -### 4. Updated All Production Readiness Checks - -#### Step 2: DLT Mode Sync Check -**Already correct** - uses `chain().is_syncing()` (no change needed) - -#### Step 3: Snapshot Pause Gate -**Before:** -```cpp -if (p2p().is_catching_up_after_pause()) { - return not_synced; -} -``` - -**After:** -```cpp -// Check snapshot plugin directly for snapshot_in_progress flag -if (snapshot().is_snapshot_in_progress()) { - wlog("Deferring block production: snapshot creation in progress"); - return not_synced; -} - -if (p2p().is_catching_up_after_pause()) { - wlog("Deferring block production: P2P is catching up after snapshot pause"); - return not_synced; -} -``` - -#### Step 4: Hardfork 12 Safety Enforcement -**Before:** -```cpp -if (we_are_emergency_master) { - _production_enabled = true; // Cached flag set -} else if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; // Cached flag set - } else { - return not_synced; - } -} -``` - -**After:** -```cpp -// No flag setting - production allowed to proceed if checks pass -// State determined by actual database values, not cached flags -bool we_are_emergency_master = - _witnesses.find(CHAIN_EMERGENCY_WITNESS_ACCOUNT) != _witnesses.end(); -// Master produces if emergency active, slaves must sync first -``` - -#### Watchdog Recovery -**Before:** -```cpp -if (!_production_enabled) { - _production_enabled = true; // Force-enable cached flag - did_recover = true; - elog("WATCHDOG-RECOVERY: force-enabled _production_enabled"); -} -``` - -**After:** -```cpp -// No flag to set - recovery clears blocking conditions: -// - _minority_fork_recovering = false -// - P2P catchup flag cleared -// - Chain syncing flag cleared -// Production will automatically resume on next tick if state is healthy -``` - -#### Watchdog Silence Detection -**Before:** -```cpp -if (_ever_produced && _production_enabled) { - auto silent_for = fc::time_point::now() - _last_production_time; - // Check if silent too long -} -``` - -**After:** -```cpp -if (_ever_produced) { - // Check if production should be active by querying actual state - bool should_be_producing = false; - try { - const auto& dgp_watch = database().get_dynamic_global_properties(); - if (!_minority_fork_recovering && !_witnesses.empty()) { - if (dgp_watch.emergency_consensus_active) { - // Emergency mode: should produce if we have emergency key - should_be_producing = (_witnesses.count(CHAIN_EMERGENCY_WITNESS_ACCOUNT) > 0); - } else { - // Normal mode: should produce if participation is healthy - uint32_t prate_watch = database().witness_participation_rate(); - should_be_producing = (prate_watch >= 33 * CHAIN_1_PERCENT); - } - } - } catch (...) {} - - if (should_be_producing) { - auto silent_for = fc::time_point::now() - _last_production_time; - // Check if silent too long - } -} -``` - -### 5. Updated Diagnostic Logging - -**Before:** -```cpp -elog("validator-WATCHDOG: ... prod=${pe} ...", - ("pe", _production_enabled)); -``` - -**After:** -```cpp -elog("validator-WATCHDOG: ... skip_flags=${sf} ...", - ("sf", _production_skip_flags)); -``` - -## Benefits - -### 1. Single Source of Truth -All production decisions now query actual state from: -- **Database**: `get_dynamic_global_properties()`, `witness_participation_rate()`, `has_hardfork()` -- **Chain plugin**: `is_syncing()` -- **P2P plugin**: `is_catching_up_after_pause()` -- **Snapshot plugin**: `is_snapshot_in_progress()` (NEW) - -### 2. No Stale State -Every production tick (250ms) queries fresh state - no risk of cached flags becoming outdated. - -### 3. Simplified Recovery -Watchdog recovery no longer needs to manually set `_production_enabled = true`. Instead, it clears blocking conditions: -- `_minority_fork_recovering = false` -- `chain().clear_syncing()` -- `p2p().clear_catchup_flag()` - -Production automatically resumes on next tick if state is healthy. - -### 4. Clearer Dependencies -Plugin dependencies now explicit in `APPBASE_PLUGIN_REQUIRES`: -```cpp -APPBASE_PLUGIN_REQUIRES((chain::plugin) (p2p::p2p_plugin) (snapshot::snapshot_plugin)) -``` - -### 5. Better Observability -Diagnostic logs now show actual skip flags and state from database, not cached boolean. - -## Migration Notes - -### Configuration Changes -**None** - all config options remain the same: -- `--enable-stale-production` still works (sets `skip_undo_history_check` flag) -- `--required-participation` unchanged -- `--validator`, `--private-key`, `--emergency-private-key` unchanged - -### Behavior Changes -**Minimal** - production logic identical, just queries state differently: -1. Production readiness determined by actual database state, not cached flag -2. Snapshot pause detection now checks snapshot plugin directly (more accurate) -3. Watchdog recovery clears blocking conditions instead of setting enable flag - -### API Changes -**New public method in snapshot plugin:** -```cpp -bool snapshot_plugin::is_snapshot_in_progress() const; -``` - -**New dependency in Validator Plugin:** -```cpp -APPBASE_PLUGIN_REQUIRES((chain::plugin) (p2p::p2p_plugin) (snapshot::snapshot_plugin)) -``` - -## Testing Recommendations - -1. **Normal production**: Verify validator produces blocks normally -2. **Snapshot creation**: Verify production defers during snapshot (check logs for "snapshot creation in progress") -3. **Emergency mode**: Verify emergency master produces regardless of sync state -4. **Minority fork recovery**: Verify production resumes after resync completes -5. **Watchdog recovery**: Verify watchdog can recover from stuck state -6. **DLT mode sync**: Verify DLT slaves defer during sync, master produces - -## Files Modified - -1. `plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp` - Added `is_snapshot_in_progress()` declaration -2. `plugins/snapshot/plugin.cpp` - Implemented `is_snapshot_in_progress()` -3. `plugins/validator/include/graphene/plugins/validator/validator.hpp` - Added snapshot plugin dependency -4. `plugins/validator/validator.cpp` - Major refactoring: - - Added snapshot plugin reference - - Removed `_production_enabled` flag - - Updated all production readiness checks - - Updated diagnostic logging - - Simplified watchdog recovery - -## Backward Compatibility - -✅ **Fully backward compatible** -- No config changes required -- No API breaking changes (only additions) -- Production logic identical, just queries state differently -- Existing deployments will work without modification diff --git a/.qoder/docs/validator-plugin.md b/.qoder/docs/validator-plugin.md deleted file mode 100644 index 39e0564b7c..0000000000 --- a/.qoder/docs/validator-plugin.md +++ /dev/null @@ -1,1076 +0,0 @@ -# Validator Plugin Documentation - -## Overview - -The validator plugin is responsible for block production in the VIZ blockchain. It manages validator scheduling, block signing, broadcast, and implements sophisticated safety mechanisms including minority fork detection, emergency consensus support, and production watchdog recovery. - -**Location:** `plugins/validator/validator.cpp`, `plugins/validator/include/graphene/plugins/validator/validator.hpp` - ---- - -## Configuration Options - -### Block Production Options - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `enable-stale-production` | bool | false | Enable block production even if the chain is stale. Overrides sync and participation checks. | -| `required-participation` | uint32_t | 33% (33 * CHAIN_1_PERCENT) | Minimum validator participation percentage required to produce blocks. | -| `validator` / `-w` | string (multi) | - | Name of validator controlled by this node. Can be specified multiple times. | -| `private-key` | string (WIF, multi) | - | WIF private key(s) for signing blocks. | -| `emergency-private-key` | string (WIF, multi) | - | WIF private key for emergency consensus production. Auto-adds `CHAIN_EMERGENCY_WITNESS_ACCOUNT` to validator set. | - -### Fork Collision Resolution - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `fork-collision-timeout-blocks` | uint32_t | 21 | Number of consecutive fork-collision deferrals before forcing production. One full validator round = 21 blocks (63 seconds). | - -### NTP Synchronization - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `ntp-server` | string (multi) | pool.ntp.org, time.google.com, time.cloudflare.com | NTP server(s) for time synchronization. | -| `ntp-request-interval` | uint32_t | 900 | Time update request interval in seconds (15 min). | -| `ntp-retry-interval` | uint32_t | 300 | Retry interval when NTP hasn't replied (5 min). | -| `ntp-round-trip-threshold` | uint32_t | 150 | Round-trip delay threshold in ms; slower replies discarded. | -| `ntp-history-size` | uint32_t | 5 | Moving-average history window for NTP delta smoothing. | -| `ntp-rejection-threshold-pct` | uint32_t | 50 | Rejection threshold as percentage of absolute moving average. | -| `ntp-rejection-min-threshold` | uint32_t | 5 | Minimum rejection threshold in ms (applied regardless of percentage). | - -### Debug Options - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `debug-block-production` | bool | false | Enable verbose debug logging for block production and chain internals. Sets `database::_debug_block_production`. | - ---- - -## Plugin Dependencies - -```cpp -APPBASE_PLUGIN_REQUIRES((chain::plugin) (p2p::p2p_plugin) (snapshot::snapshot_plugin)) -``` - -The validator plugin requires: -- **chain::plugin**: Access to database, fork_db, validator schedule, block generation -- **p2p::p2p_plugin**: Block broadcast, sync status, peer connections, snapshot pause detection -- **snapshot::snapshot_plugin**: Query snapshot creation status via `is_snapshot_in_progress()` - ---- - -## Internal State Variables - -### Timer / Thread -- `production_io_service_` (boost::asio::io_service): **Dedicated** io_service for the production timer — completely separate from the appbase/P2P shared io_service. Declared before `production_timer_` to ensure correct init order. -- `production_io_work_` (unique_ptr\): Keeps the io_service alive while the thread runs. -- `production_io_thread_` (std::thread): Calls `production_io_service_.run()`. Joined in destructor after `production_io_service_.stop()`. -- `production_timer_` (boost::asio::deadline_timer): Timer bound to `production_io_service_`. - -### Production Control -- `_production_skip_flags` (uint32_t): Flags passed to `generate_block()` (e.g., `skip_undo_history_check`) -- `_required_validator_participation` (uint32_t): Participation threshold from config -- `_private_keys` (map): Loaded private keys for signing -- `_validators` (set): Configured validator names (includes `CHAIN_EMERGENCY_VALIDATOR_ACCOUNT` if emergency key configured) -- `_last_lag_slot_time` (fc::time_point_sec): Scheduled time of the most recent `lag` condition. Zero when no lag is active. Used by `schedule_production_loop()` to skip ahead past the missed slot and avoid rechecking it every 250ms. - -### Fork Detection & Recovery -- `fork_collision_defer_count_` (uint32_t): Consecutive fork-collision deferrals -- `_fork_collision_timeout_blocks` (uint32_t): Timeout threshold (default: 21) -- `_minority_fork_recovering` (bool): True when recovering from minority fork rollback -- `_minority_fork_recovery_start` (fc::time_point): When minority fork recovery started - -### Stall Detection -- `_slot_zero_streak` (uint32_t): Consecutive `not_time_yet` returns (NTP/clock issues) -- `_slot_zero_streak_start` (fc::time_point): When slot=0 streak started -- `_not_my_turn_streak` (uint32_t): Consecutive slots assigned to other validators -- `_not_my_turn_streak_start` (fc::time_point): When not_my_turn streak started -- `_last_scheduled_validator` (string): Last validator that got the slot - -### Watchdog & Diagnostics -- `_ever_produced` (bool): Whether we've ever produced a block -- `_last_production_time` (fc::time_point): Timestamp of last successful production -- `_last_slot_result` (int): Last result from slot > 0 iteration (excludes `not_time_yet`) -- `_watchdog_debug_enabled` (bool): Latching flag — set to `true` on first watchdog fire; never reset. Enables `database()._debug_block_production` automatically for post-hoc diagnosis. -- `_slot_hijack_count` (uint32_t): Consecutive blocks where committee filled our scheduled slot -- `_slot_hijack_height` (uint32_t): Last block height where hijack detected -- `_last_applied_block_num` (uint64_t): Last applied block number (for missed slot detection) - ---- - -## Execution Flow - -### 1. Plugin Lifecycle - -#### `plugin_initialize()` -**Called during:** Application startup, before any plugin starts - -**Actions:** -1. Create `impl` instance -2. Load validator names from `--validator` option into `_witnesses` set -3. Load `--enable-stale-production` flag → sets `skip_undo_history_check` in `_production_skip_flags` if true -4. Load `--required-participation` → `_required_witness_participation` -5. Parse `--private-key` WIF strings → `_private_keys` map -6. Parse `--emergency-private-key` WIF strings → `_private_keys` map - - **IMPORTANT**: Auto-adds `CHAIN_EMERGENCY_WITNESS_ACCOUNT` to `_witnesses` -7. Configure NTP service from options and call `graphene::time::configure_ntp()` -8. Load `--fork-collision-timeout-blocks` → `_fork_collision_timeout_blocks` -9. Load `--debug-block-production` → `database::_debug_block_production` - -**Does NOT:** Access database, check sync status, or start production timer - ---- - -#### `plugin_startup()` -**Called during:** Application startup, after all plugins initialized - -**Actions:** -1. Start NTP time client: `graphene::time::now()` -2. **Force NTP sync**: `graphene::time::update_ntp_time()` to minimize startup drift -3. Log validator configuration (count, names) -4. If `_witnesses` is not empty: - - Call `p2p().set_block_production(true)` to enable P2P block production mode - - Connect to `database::applied_block` signal → `on_block_applied()` handler - - Set `_last_applied_block_num = database.head_block_num()` - - If `skip_undo_history_check` set in `_production_skip_flags` (from `--enable-stale-production`): - - If `head_block_num() == 0`: Print new chain banner - - **Start production loop**: `schedule_production_loop()` -5. If no validators configured: Log error message - ---- - -#### `plugin_shutdown()` -**Called during:** Application shutdown - -**Actions:** -1. Shutdown NTP: `graphene::time::shutdown_ntp_time()` -2. Cancel production timer if validators configured - ---- - -### 2. Production Loop - -The production loop runs on a **dedicated `production_io_service_`** (not the shared appbase/P2P io_service) with its own OS thread. This isolation means P2P network activity — peer disconnects, TLS handshakes, send-queue drains — cannot delay the 250ms timer callback and cause missed-slot lag. - -``` -production_io_thread_ → production_io_service_.run() - ↓ - production_timer_.async_wait() - ↓ (250ms boundary) - block_production_loop() - ↓ - maybe_produce_block() - ↓ - [result handling + lag skip] - ↓ - schedule_production_loop() // reschedule -``` - -#### `schedule_production_loop()` - -**Lag skip guard (runs first):** -```cpp -if (_last_lag_slot_time != fc::time_point_sec()) { - int64_t time_since_lag_ms = (fc::time_point::now() - - fc::time_point(_last_lag_slot_time)).count() / 1000; - if (time_since_lag_ms < CHAIN_BLOCK_INTERVAL * 1000) { - int64_t skip_ms = (CHAIN_BLOCK_INTERVAL * 1000) - time_since_lag_ms; - production_timer_.expires_from_now(posix_time::milliseconds(skip_ms)); - production_timer_.async_wait(...); - _last_lag_slot_time = fc::time_point_sec(); - return result; - } -} -``` - -After a `lag` condition the current slot is already missed. Without this guard, the loop would recheck the same slot every 250ms and return `lag` again, spinning at high CPU rate until the full 3s slot interval elapses. The guard skips ahead to the start of the next slot. - -**Sleep calculation (normal path):** -```cpp -int64_t next_microseconds = 250000 - (ntp_microseconds % 250000); -if (next_microseconds < 50000) { - next_microseconds += 250000; // minimum 50ms sleep -} -``` - -This aligns production ticks to 250ms boundaries with a +250ms lookahead in `maybe_produce_block()`. - -**Sanity check:** If `next_microseconds > 500000` (500ms), logs warning about NTP backward jump. - ---- - -#### `block_production_loop()` - -**Exception handling:** -- `fc::canceled_exception`: Re-throw (node shutting down) -- `unknown_hardfork_exception`: Log error, re-throw (node out of date) -- `fc::exception`: Log error, return `exception_producing_block` - -**Result handling:** -- `produced`: Reset fork_collision_defer_count, slot_zero_streak, not_my_turn_streak, slot_hijack_count. Set `_ever_produced`, `_last_production_time`. Clear `_minority_fork_recovering` if set. -- `not_synced`: Reset fork_collision_defer_count, slot_zero_streak, not_my_turn_streak -- `not_my_turn`: Reset fork_collision_defer_count, slot_zero_streak. Track `_not_my_turn_streak` (warning at 500 consecutive ≈ 125s) -- `not_time_yet`: **Track `_slot_zero_streak`** only if `now <= head_block_time()` (NTP behind chain). Warnings at 3 (750ms), 10 (2.5s, force NTP resync), 60 (15s), 120 (30s, critical) -- `no_private_key`, `low_participation`, `lag`, `consecutive`, `exception_producing_block`, `fork_collision`, `minority_fork`: Log appropriate messages - -**Watchdog:** If `_ever_produced` and `should_be_producing` (derived from live state) and silence exceeds threshold: - -```cpp -bool should_be_producing = false; -const auto& dgp_watch = database().get_dynamic_global_properties(); -if (!_minority_fork_recovering && !_witnesses.empty()) { - if (dgp_watch.emergency_consensus_active) { - should_be_producing = (_witnesses.count(CHAIN_EMERGENCY_WITNESS_ACCOUNT) > 0); - } else { - uint32_t prate_watch = database().witness_participation_rate(); - should_be_producing = (prate_watch >= 33 * CHAIN_1_PERCENT); - } -} -``` - -- Emergency master: 60s threshold -- Regular validator: 180s threshold -- Logs every 30s once triggered -- **WATCHDOG-RECOVERY**: If conditions met (head advancing < 30s, not syncing, has peers, has active keys): - - Clear `_minority_fork_recovering` - - Clear P2P catchup flag: `p2p().clear_catchup_flag()` - - Clear chain syncing flag: `chain().clear_syncing()` - - Reset streak counters - - Production resumes automatically on next tick (no cached flag to set) - ---- - -#### `maybe_produce_block()` - Main Production Logic - -**This is the core function with all safety checks. Executes in order:** - ---- - -##### Step 1: Capture Time and DGP - -```cpp -fc::time_point now_fine = graphene::time::now(); -fc::time_point_sec now = now_fine + fc::microseconds(250000); -const auto &dgp = db.get_dynamic_global_properties(); -``` - -**Why +250ms lookahead:** Aligns with timer scheduling to ensure we're at slot boundary when production decision is made. - ---- - -##### Step 2: DLT Mode Sync Check (Line ~1098) - -```cpp -if (db._dlt_mode && chain().is_syncing()) { - bool we_are_emergency_master = - dgp.emergency_consensus_active && - _witnesses.find(CHAIN_EMERGENCY_WITNESS_ACCOUNT) != _witnesses.end(); - if (!we_are_emergency_master) { - return block_production_condition::not_synced; - } - // Emergency master: bypass sync check to avoid deadlock -} -``` - -**What it checks:** -- `chain().is_syncing()`: **YES, calls chain plugin** to check `currently_syncing` atomic flag -- **Why:** In DLT mode, producing during sync creates blocks on stale head conflicting with incoming blocks → oscillation bug - -**Emergency master exception:** -- If emergency consensus active AND we have emergency key → production proceeds -- **Why:** Master is sole producer; waiting for sync would deadlock (no blocks arrive to clear syncing flag) - -**Outside DLT mode:** This check is NOT applied. Normal validators must produce on canonical head even while network catching up. - ---- - -##### Step 3: Snapshot Pause / Post-Pause Catchup Gate (Line ~1118) - -```cpp -// Check snapshot plugin directly for snapshot_in_progress flag -if (snapshot().is_snapshot_in_progress()) { - wlog("Deferring block production: snapshot creation in progress"); - return not_synced; -} - -if (p2p().is_catching_up_after_pause()) { - wlog("Deferring block production: P2P is catching up after snapshot pause"); - return not_synced; -} -``` - -**What it checks:** -- `snapshot().is_snapshot_in_progress()`: **YES, calls snapshot plugin** — `snapshot_in_progress` atomic flag (relaxed load) -- `p2p().is_catching_up_after_pause()`: **YES, calls P2P plugin** — returns true if `_block_processing_paused || _catchup_after_pause` - -**Why two checks:** -1. **Snapshot in progress**: snapshot plugin holds DB read lock; producing would cause write-lock starvation -2. **P2P catchup after pause**: snapshot finished, but queued blocks haven't drained yet; producing on stale head → fork - -**Applies to:** ALL validator types (emergency and normal) - -**Flag cleared when:** -- `snapshot_in_progress`: Cleared by snapshot plugin on completion -- `_catchup_after_pause`: Cleared when drain completes + no peer ahead - ---- - -##### Step 4: Hardfork 12 Three-State Safety Enforcement (Line ~1132) - -```cpp -if (db.has_hardfork(CHAIN_HARDFORK_12)) { - if (dgp.emergency_consensus_active) { - // Emergency mode logic - } else { - // Normal mode with participation check - } -} else { - // Pre-HF12 legacy behavior -} -``` - -**Sub-case 4a: Emergency Consensus Active** - -```cpp -bool we_are_emergency_master = - _witnesses.find(CHAIN_EMERGENCY_WITNESS_ACCOUNT) != _witnesses.end(); -if (!we_are_emergency_master) { - // Slave node: must sync first before producing - if (db.get_slot_time(1) < now) { - return block_production_condition::not_synced; - } -} -// Emergency master proceeds unconditionally — no cached flag, state queried fresh every tick -``` - -**Why:** Master MUST produce to avoid deadlock. Slave nodes must still sync first. - ---- - -**Sub-case 4b: Normal Mode (Participation Check)** - -```cpp -uint32_t prate = db.witness_participation_rate(); -if (prate >= 33 * CHAIN_1_PERCENT) { - // HEALTHY NETWORK - _production_skip_flags &= ~skip_undo_history_check; // Re-enable minority fork detection - // Check sync status directly (no cached flag — queried fresh every tick) - if (db.get_slot_time(1) < now) { - return not_synced; - } - // No participation check needed (already >= 33%) -} else { - // DISTRESSED NETWORK (< 33%) - if (!(_production_skip_flags & skip_undo_history_check)) { - // No stale-production override: require sync - if (db.get_slot_time(1) < now) { - return not_synced; - } - } - // enable-stale-production=true: operator override, proceed regardless of sync status - if (prate < _required_witness_participation) { - if (_production_skip_flags & skip_undo_history_check) { - // Operator override: produce anyway to bootstrap stalled network - } else { - return low_participation; // Network partition guard - } - } -} -``` - -**Why 33% threshold:** Below this, node likely in minority network segment. Producing risks two partitions building chains simultaneously. - -**enable-stale-production override:** If set, bypasses participation and sync checks to allow operator to recover fully stalled network. - ---- - -**Sub-case 4c: Pre-HF12 Legacy** - -```cpp -// Check sync status directly (no cached flag) -if (db.get_slot_time(1) < now) { - return not_synced; -} -// No participation check here (done later before block generation) -``` - ---- - -##### Step 5: Block Post Validation Broadcast (Line ~1228) - -```cpp -if(last_block_post_validation_time < now_fine) { - last_block_post_validation_time = now; - // Build scheduled_witnesses_set from witness_schedule_object - // For each validator in _witnesses: - // - Skip if not in current schedule - // - Get block_post_validations from database - // - Sign with validator private key - // - Broadcast via p2p().broadcast_block_post_validation() -} -``` - -**What it does:** Signs and broadcasts post-validation messages for scheduled validators to contribute to LIB advancement. - -**Optimization:** Skips validators not in current schedule (can't contribute to LIB). - ---- - -##### Step 6: Minority Fork Detection (Non-Emergency) (Line ~1318) - -```cpp -if (!dgp.emergency_consensus_active) { - auto fork_head = db.get_fork_db().head(); - // Walk back CHAIN_MAX_WITNESSES (21) blocks in fork_db - // If ALL from our validators → minority fork - if (all_ours && blocks_checked >= CHAIN_MAX_WITNESSES) { - if (_production_skip_flags & skip_undo_history_check) { - // enable-stale-production: continue - } else { - p2p().resync_from_lib(); - _minority_fork_recovering = true; - return minority_fork; - } - } -} -``` - -**Why skipped in emergency mode:** All blocks produced by committee (which may be in `_witnesses`), would always falsely trigger. - -**enable-stale-production override:** Operator can continue producing on minority fork (testnet/bootstrap scenario). - ---- - -##### Step 7: DLT-Specific Minority Fork Detection in Emergency Mode (Line ~1382) - -```cpp -if (dgp.emergency_consensus_active && db._dlt_mode) { - // Check if we are emergency master - bool we_are_master = false; - if (_witnesses.find(CHAIN_EMERGENCY_WITNESS_ACCOUNT) != _witnesses.end()) { - // Check if committee is in current validator schedule - const witness_schedule_object &wso = db.get_witness_schedule_object(); - for (int i = 0; i < wso.num_scheduled_witnesses; i += CHAIN_BLOCK_WITNESS_REPEAT) { - if (wso.current_shuffled_witnesses[i] == CHAIN_EMERGENCY_WITNESS_ACCOUNT) { - we_are_master = true; - break; - } - } - } - - if (!we_are_master) { - // Slave DLT node: run fork_db isolation scan - // If last 21 blocks all from our validators → isolated from master - p2p().resync_from_lib(true /*force_emergency*/); - _minority_fork_recovering = true; - return minority_fork; - } - // Emergency master: skip to avoid false positives -} -``` - -**Why separate check:** In DLT emergency mode, standard check skipped but slave node can still get isolated from master. Uses same 21-block threshold (one full round). - -**Master skip logic:** If committee in schedule AND we have its key → we ARE the master. All blocks being "ours" is expected. - ---- - -##### Step 8: Acquire Operation Guard (Line ~1443) - -```cpp -auto op_guard = db.make_operation_guard(); -``` - -**Why:** Guards lockless reads into shared memory against concurrent resize. Prevents pointer invalidation while reading validator schedule, slot time, etc. - -**Stall detection:** If guard blocks > 100ms, logs warning. If crosses slot boundary and we lost our slot → critical error. - -**Time refresh:** Re-captures `now` after acquiring guard (if guard blocked on DB resize, original `now` is stale). - ---- - -##### Step 9: Slot Assignment Check (Line ~1477) - -```cpp -uint32_t slot = db.get_slot_at_time(now); -if (slot == 0) { - // NTP drift check: warn if local clock > 250ms behind NTP - return not_time_yet; -} - -string scheduled_witness = db.get_scheduled_witness(slot); -if (_witnesses.find(scheduled_witness) == _witnesses.end()) { - return not_my_turn; -} -``` - -**NTP drift warning:** If `ntp_error() > 250ms`, warns about potential silent slot misses. - ---- - -##### Step 10: validator Validation (Line ~1563) - -```cpp -const auto &witness_by_name = db.get_index().indices().get(); -auto itr = witness_by_name.find(scheduled_witness); - -fc::time_point_sec scheduled_time = db.get_slot_time(slot); -graphene::protocol::public_key_type scheduled_key = itr->signing_key; - -// Check if slot already filled -if (scheduled_time <= db.head_block_time()) { - return not_time_yet; // Slot filled during/after snapshot pause -} - -// Check if validator disabled (zero key) -if (scheduled_key == public_key_type()) { - // Log warning (every 60s for regular, 3s for emergency) - return not_my_turn; -} - -// Check if we have private key -auto private_key_itr = _private_keys.find(scheduled_key); -if (private_key_itr == _private_keys.end()) { - return no_private_key; -} -``` - -**Slot already filled check:** Critical for snapshot pause scenario. Another validator may have filled the slot during pause. - ---- - -##### Step 11: Pre-HF12 Participation Check (Line ~1629) - -```cpp -if (!db.has_hardfork(CHAIN_HARDFORK_12)) { - uint32_t prate = db.witness_participation_rate(); - if (prate < _required_witness_participation) { - if (_production_skip_flags & skip_undo_history_check) { - // Operator override - } else { - return low_participation; - } - } -} -``` - -**Why here for pre-HF12:** HF12 moved participation check earlier (Step 4) for better emergency mode handling. - ---- - -##### Step 12: Lag Check (Line ~1644) - -```cpp -if (llabs((scheduled_time - now).count()) > fc::milliseconds(500).count()) { - return lag; // Woke up too late for this slot -} -``` - -**Threshold:** 500ms tolerance. If we're more than 500ms past slot time, skip. - ---- - -##### Step 13: Fork Collision Resolution (Line ~1661) - -```cpp -auto existing_blocks = db.get_fork_db().fetch_block_by_number(db.head_block_num() + 1); -if (existing_blocks.size() > 0) { - // Determine if competing block exists - // Emergency mode: ANY block at this height is competing - // Normal mode: only different validator + different parent - - if (has_competing_block) { - fork_collision_defer_count_++; - - // LEVEL 2: Timeout after 21 deferrals (stuck-head) - if (fork_collision_defer_count_ > _fork_collision_timeout_blocks) { - // Remove dead-fork competing block, produce on our chain - db.get_fork_db().remove_blocks_by_number(db.head_block_num() + 1); - fork_collision_defer_count_ = 0; - // Fall through to produce - } - // LEVEL 1: Vote-weighted comparison (HF12+) - else if (db.has_hardfork(CHAIN_HARDFORK_12)) { - int weight_cmp = db.compare_fork_branches(competing_block->id, db.head_block_id()); - if (weight_cmp < 0) { - // Our fork has MORE weight → produce, remove competing block - } else if (weight_cmp > 0) { - // Competing fork has MORE weight → defer - return fork_collision; - } else { - // Tied → defer, timeout will kick in - return fork_collision; - } - } - // Pre-HF12: defer, timeout still applies - else { - return fork_collision; - } - } -} -``` - -**Two-level resolution:** -1. **Vote-weighted comparison** (HF12+): Compare fork branches by accumulated vote weight -2. **Stuck-head timeout** (all versions): After 21 deferrals (63s), assume competing block is on dead fork - -**Why 21 blocks:** One full validator round. If head hasn't advanced after 21 slots, longer chain had all scheduled validators produce → canonical chain confirmed. - ---- - -##### Step 14: Second Snapshot Pause Check (Line ~1769) - -```cpp -try { - if (p2p().is_catching_up_after_pause()) { - return not_time_yet; // Snapshot started between checks - } -} catch (...) {} -``` - -**Why second check:** Race window ~1 block interval. If snapshot started after first check (~line 1118), producing would cause 2-11s write-lock starvation. - -**Cost:** One missed slot (3s) — far cheaper than full snapshot read hold time. - ---- - -##### Step 15: Generate and Broadcast Block (Line ~1777) - -```cpp -auto block = db.generate_block( - scheduled_time, - scheduled_witness, - private_key_itr->second, - _production_skip_flags -); - -p2p().broadcast_block(block); - -// Seed reconnect if few peers -auto peer_count = p2p().get_connections_count(); -if (peer_count < 2 && !p2p().is_isolated_peers()) { - p2p().reconnect_seeds(); -} - -return produced; -``` - -**Retry logic:** Up to 2 retries on `fc::exception` (clears pending transactions between retries). - -**Exception handling:** -- `shared_memory_corruption_exception`: Call `chain().attempt_auto_recovery()` -- `unlinkable_block_exception`: Fork DB broken → rollback to LIB, resync from P2P -- `fc::exception`: Clear pending transactions, retry - ---- - -### 3. Signal Handler: `on_block_applied()` - -**Connected to:** `database::applied_block` signal during `plugin_startup()` - -**Purpose:** Detect missed slots and slot hijacks for diagnostics. - ---- - -#### Slot Hijack Detection (Runs for every block) - -```cpp -if (database()._dlt_mode && !_witnesses.empty() - && prev_num > 0 && block_num == prev_num + 1) { - const auto& dgp = database().get_dynamic_global_properties(); - if (dgp.emergency_consensus_active) { - // Slot index for the block just applied - uint64_t slot_idx = dgp.current_aslot % nsw; - const std::string& expected_witness = wso.current_shuffled_witnesses[slot_idx]; - - // True hijack: expected slot is ours AND actual producer is not one of our validators - if (_witnesses.count(expected_witness) > 0 - && _witnesses.count(block.validator) == 0) { - _slot_hijack_count++; // Committee / emergency master filled our slot - // Log first 3 hijacks, then once per minute - } else if (_witnesses.count(block.validator) > 0) { - // ANY of our validators produced → reset (false-positive guard) - if (_slot_hijack_count > 0) { - ilog("Hijack counter reset: our validator '${w}' produced...", ...); - } - _slot_hijack_count = 0; - } - } -} -``` - -**What it detects:** In DLT emergency mode, the emergency master may blank our validator's signing_key and fill our scheduled slots with committee blocks. - -**Important:** The reset condition checks `_witnesses.count(block.validator) > 0` — i.e., ANY of our configured validators produced the block, not just the slot-assigned one. Without this, a legitimate block from a different one of our validators would be mis-counted as a hijack. - ---- - -#### Missed Slot Detection - -```cpp -if (block_num > prev_num + 1) { - uint32_t missed_count = block_num - prev_num - 1; - - // Calculate which validators were scheduled for missed slots - for (uint32_t i = 0; i < missed_count && i < 100; ++i) { - uint64_t abs_slot = cur_aslot - missed_count + i; - const std::string &wname = wso.current_shuffled_witnesses[abs_slot % num_witnesses]; - if (_witnesses.count(wname) > 0) { - our_witness_missed = true; - } - } - - if (our_witness_missed) { - // Dump full diagnostic state: - // - Production flags, NTP offset, sync status - // - On-chain signing key status (blanked?) - // - Next slot time, scheduled validator - // - Streak counters - elog("MISSED-SLOT-OUR-validator: ..."); - } -} -``` - -**Why check missed slots:** When incoming blocks reveal gaps, determines if our validator was scheduled for any missed slots and logs full diagnostic state for troubleshooting. - ---- - -## Public API Methods - -### `is_witness_scheduled_soon()` - -**Returns:** `true` if locally-controlled validator is scheduled to produce in next 4 slots (~12 seconds) - -**Implementation:** -1. Check 4 upcoming slots (covers snapshot creation time ~10s + safety margin) -2. For each slot: - - Get scheduled validator name - - Check if in `_witnesses` set - - Look up validator object in database - - Check if signing key is non-zero - - Check if we have corresponding private key -3. Return `true` if any match found - -**Used by:** Snapshot plugin to defer snapshot creation when validator about to produce (avoids fork on stale head) - ---- - -### `is_emergency_master()` - -**Returns:** `true` if this node is the emergency master - -**Conditions:** -1. Holds `emergency-private-key` (`CHAIN_EMERGENCY_WITNESS_ACCOUNT` in `_witnesses`) -2. Committee account is in current validator schedule - -**Why both conditions:** Multiple nodes can have emergency key, but only the one where committee is scheduled should produce solo. Others are followers that must sync. - -**Used by:** -- P2P plugin: Determines if node should wait for network or produce -- Snapshot plugin: Skips stalled sync recovery for master -- Watchdog: Different silence thresholds (60s vs 180s) - ---- - -### `is_emergency_key_configured()` - -**Returns:** `true` if `emergency-private-key` is configured, regardless of schedule - -**Used by:** External diagnostics, P2P hello messages - ---- - -### `get_production_diagnostics()` - -**Returns:** Compact diagnostic string with key production-state flags - -**Format:** `validator[skip_flags=0x0 catching_up=0 head=#123 last_prod=45s_ago minority_rcv=0 slot_hijacks=2]` - -**Used by:** P2P layer when FORWARD stagnation fires with no peer ahead, so stagnation log shows why master isn't filling gap. - ---- - -## Hardfork Checks - -### CHAIN_HARDFORK_12 - -**Location:** Multiple places in `maybe_produce_block()` - -**Changes introduced:** -1. **Three-state safety enforcement** (Step 4): - - Pre-HF12: Simple sync check - - HF12+: Emergency mode detection, participation-based auto-enable, stale-production override logic - -2. **Minority fork detection** (Step 6): - - Pre-HF12: Standard 21-block check - - HF12+: Skipped during emergency consensus, DLT-specific check added - -3. **Participation check position** (Step 11): - - Pre-HF12: Checked just before block generation - - HF12+: Checked early in Step 4 with emergency mode awareness - -4. **Fork collision resolution** (Step 13): - - Pre-HF12: Defer only, timeout applies - - HF12+: Vote-weighted comparison (Level 1) + timeout (Level 2) - -5. **Block post validation**: - - Pre-HF12: LIB advancement via 2/3 validator signatures - - HF12+: LIB advancement via validator participation rate, emergency mode disables post-validation chain - ---- - -## Database Access Patterns - -### Direct Database Reads (via `database()` reference) - -**Frequent (every production tick ~250ms):** -- `db.get_dynamic_global_properties()` — emergency consensus state, head block number/time, current_aslot -- `db.get_slot_at_time(now)` — determine if slot available -- `db.get_scheduled_witness(slot)` — who should produce -- `db.get_slot_time(slot)` — scheduled slot time -- `db.get_witness_schedule_object()` — shuffled validator list, num_scheduled_witnesses -- `db.head_block_num()`, `db.head_block_time()` — current chain state -- `db.get_fork_db().head()`, `db.get_fork_db().fetch_block_by_number()` — fork detection -- `db.get_index().indices().get().find()` — validator signing key status -- `db.witness_participation_rate()` — network health check -- `db.has_hardfork(CHAIN_HARDFORK_12)` — feature gate - -**Infrequent (on events or diagnostics):** -- `db.get_block_post_validations()` — sign and broadcast validations -- `db.compare_fork_branches()` — vote-weight comparison (HF12+) -- `db.get_fork_db().remove()`, `remove_blocks_by_number()` — fork resolution - -**Write operations:** -- `db.generate_block()` — create and sign new block -- `db.clear_pending()` — clear pending transactions on failure - -### Does NOT cache results - -**All database reads are fresh on every call:** -- No caching of validator schedule -- No caching of DGP state -- No caching of fork_db state -- No caching of signing key status - -**Why:** State changes every block (emergency mode can activate/deactivate, validator schedule changes, signing keys can be blanked). Caching would create race conditions and stale decisions. - -**Exception:** `_witnesses` set and `_private_keys` map are loaded once during `plugin_initialize()` and never refreshed (operator must restart to change configuration). - ---- - -## Sync/Forward Status Checks - -### Chain Plugin: `chain().is_syncing()` - -**Called in:** -1. Step 2 (DLT mode sync check) -2. Watchdog recovery -3. Diagnostic logging (missed slot, stall detection) - -**What it checks:** `chain_plugin::currently_syncing` atomic flag - -**Set by:** Chain plugin when processing P2P sync blocks (`accept_block()` with `currently_syncing_flag=true`) - -**Cleared by:** -- Chain plugin when sync completes -- Watchdog recovery (force-clear) - ---- - -### P2P Plugin: `p2p().is_catching_up_after_pause()` - -**Called in:** -1. Step 3 (snapshot pause gate) -2. Step 14 (second snapshot pause check) -3. Watchdog recovery -4. Diagnostic logging -5. `get_production_diagnostics()` - -**What it checks:** `_block_processing_paused || _catchup_after_pause` flags in `dlt_p2p_node` - -**Set by:** -- `pause_block_processing()`: Sets `_block_processing_paused = true` (snapshot creation starting) -- `resume_block_processing()`: Sets `_block_processing_paused = false`, may set `_catchup_after_pause = true` (drain queued blocks) - -**Cleared by:** -- `resume_block_processing()`: After drain completes -- Watchdog recovery: `p2p().clear_catchup_flag()` - ---- - -### Snapshot Plugin: Direct API `snapshot().is_snapshot_in_progress()` - -**Called in:** -1. Step 3 (snapshot pause gate) — first check before P2P catchup check - -**What it checks:** `snapshot_plugin::snapshot_in_progress` atomic flag (relaxed load) - -**Implementation:** -```cpp -bool snapshot_plugin::is_snapshot_in_progress() const { - if (!my) return false; - return my->snapshot_in_progress.load(std::memory_order_relaxed); -} -``` - -**Set by:** Snapshot plugin when serialization starts - -**Cleared by:** Snapshot plugin on completion - ---- - -### Snapshot Plugin: Indirect check via `is_witness_scheduled_soon()` - -**Called by:** Snapshot plugin in `on_applied_block()` before scheduling snapshot - -**Why:** Defer snapshot if validator about to produce (~12s window). Producing during snapshot → read-lock contention, producing after on stale head → fork. - ---- - -## State Machine Summary - -``` -[Startup] - ↓ plugin_initialize() -[Config loaded] - ↓ plugin_startup() -[Production loop running] - ↓ every 250ms -[maybe_produce_block()] - ├─→ not_synced (DLT sync, snapshot pause) - ├─→ not_time_yet (slot=0, NTP drift, slot already filled) - ├─→ not_my_turn (validator disabled, wrong validator scheduled) - ├─→ no_private_key (missing key) - ├─→ low_participation (< 33%, no override) - ├─→ lag (> 500ms past slot time) - ├─→ fork_collision (competing block, defer) - ├─→ minority_fork (21 blocks from our validators, rollback to LIB) - └─→ produced (success, broadcast block) -``` - ---- - -## Critical Safety Mechanisms - -### 1. Minority Fork Detection -- **Trigger:** Last 21 blocks in fork_db all from our validators -- **Action:** Rollback to LIB, resync from P2P network -- **Override:** `enable-stale-production=true` -- **Emergency mode:** Skipped (committee blocks would always trigger), DLT-specific check for slaves - -### 2. Fork Collision Resolution -- **Level 1 (HF12+):** Vote-weight comparison, produce on heavier fork -- **Level 2:** Timeout after 21 deferrals (63s), assume dead fork -- **Emergency mode:** ANY competing block triggers defer - -### 3. Network Partition Guard -- **Trigger:** validator participation < 33% -- **Action:** Stop production (return `low_participation`) -- **Override:** `enable-stale-production=true` for bootstrap/recovery - -### 4. Slot Already Filled Guard -- **Trigger:** `scheduled_time <= head_block_time()` -- **Why:** Another validator filled slot during/after snapshot pause -- **Action:** Skip production (return `not_time_yet`) - -### 5. Production Watchdog -- **Trigger:** No production for 60s (emergency) or 180s (regular); `should_be_producing` true (derived from live DB state) -- **Conditions:** Head advancing, not syncing, has peers, has active keys -- **Action:** Clear blocking conditions (`_minority_fork_recovering`, P2P catchup, chain syncing); production resumes automatically on next tick - -### 6. NTP Stall Detection -- **Trigger:** `slot=0` streak (NTP behind chain time) -- **Thresholds:** - - 3 (750ms): Warning - - 10 (2.5s): Force NTP resync - - 60 (15s): Prolonged stall warning - - 120 (30s): Critical, action required - -### 7. Slot Hijack Detection (DLT Emergency) -- **Trigger:** Committee fills our scheduled slot -- **Action:** Log diagnostics, increment counter -- **Why:** Emergency master blanked our key, producing in our slots - ---- - -## Key Invariants - -1. **Never produce during sync (DLT mode):** Creates blocks on stale head → oscillation bug -2. **Never produce during snapshot pause:** Write-lock deadlock -3. **Never produce if slot already filled:** Creates micro-fork -4. **Emergency master must always produce:** Sole producer, waiting = deadlock -5. **Slave nodes must sync first:** Producing on stale head = minority fork -6. **Participation < 33% = stop production:** Network partition guard (unless override) -7. **21 consecutive blocks from our validators = minority fork:** Rollback to LIB -8. **All database reads are fresh:** No caching, state changes every block - ---- - -## Troubleshooting Guide - -### Problem: Not producing blocks - -**Check logs for:** -- `not_synced`: DLT sync active or snapshot pause → wait for sync/pause to complete -- `not_time_yet`: NTP drift or slot=0 → check NTP offset in logs -- `not_my_turn`: Wrong validator scheduled or key blanked → check `keys=[...]` in watchdog log -- `no_private_key`: Missing private key → check config -- `low_participation`: Network participation < 33% → set `enable-stale-production=true` -- `fork_collision`: Competing block → wait for resolution (21 blocks max) -- `minority_fork`: On wrong fork → resyncing from LIB - -**Diagnostic command:** Check `get_production_diagnostics()` output in P2P stagnation logs. - ---- - -### Problem: Producing on wrong fork - -**Symptoms:** `MINORITY FORK DETECTED` log, blocks not accepted by network - -**Cause:** Isolated from network, only seeing own blocks - -**Action:** -1. Check peer connections -2. Verify network connectivity -3. Plugin will auto-rollback to LIB and resync - ---- - -### Problem: Emergency master not producing - -**Symptoms:** Network stalled, `EMRG-DIAG slot=0` logs - -**Check:** -1. Is emergency key configured? → `--emergency-private-key` -2. Is committee in validator schedule? → Check `witness_schedule_object` -3. Is NTP synchronized? → Check NTP offset -4. Is sync flag stuck? → Watchdog should auto-clear - -**Watchdog recovery:** If conditions met, watchdog will force-reset flags after 60s silence. - ---- - -### Problem: Slot hijacks detected - -**Symptoms:** `SLOT-HIJACK` logs, `slot_hijacks=N` in watchdog diagnostics - -**Cause:** Emergency master blanked our validator key and producing committee blocks in our slots - -**Normal behavior:** In DLT emergency mode, master may blank offline validators to maintain chain progress - -**Action:** -1. Check validator signing key status: `keys=[validator:key=BLANK]` -2. Send `update_witness` transaction to restore key -3. Wait for emergency mode to end (LIB advances) - ---- - -## Related Files - -- **Chain plugin:** `plugins/chain/plugin.cpp`, `plugins/chain/include/graphene/plugins/chain/plugin.hpp` -- **P2P plugin:** `plugins/p2p/p2p_plugin.cpp`, `plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp` -- **Snapshot plugin:** `plugins/snapshot/plugin.cpp`, `plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp` -- **validator guard plugin:** `plugins/witness_guard/witness_guard.cpp` -- **DLT P2P node:** `libraries/network/dlt_p2p_node.cpp`, `libraries/network/include/graphene/network/dlt_p2p_node.hpp` -- **Database:** `libraries/chain/database.cpp` (emergency consensus, hardfork logic, block generation) -- **NTP time:** `libraries/time/time.cpp` (time synchronization) diff --git a/.qoder/docs/virtual-operations.md b/.qoder/docs/virtual-operations.md deleted file mode 100644 index c62a43e6e6..0000000000 --- a/.qoder/docs/virtual-operations.md +++ /dev/null @@ -1,513 +0,0 @@ -# VIZ Blockchain — Virtual Operations - -Virtual operations are generated by the blockchain itself (not broadcast by users). They appear in operation history and can be tracked via account history or operation history APIs. They **cannot** be included in user transactions. - ---- - -## `author_reward_operation` - -**Type ID:** `26` -**Trigger:** Content payout - -Fired when an author receives their reward share from a content payout. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `author` | `account_name_type` | Content author | -| `permlink` | `string` | Content permlink | -| `token_payout` | `asset` (VIZ) | Liquid token portion of payout | -| `vesting_payout` | `asset` (SHARES) | SHARES portion of payout | - -### JSON Example - -```json -[26, { - "author": "alice", - "permlink": "my-article", - "token_payout": "1.500 VIZ", - "vesting_payout": "0.000000 SHARES" -}] -``` - ---- - -## `curation_reward_operation` - -**Type ID:** `27` -**Trigger:** Content payout - -Fired when a curator receives their curation reward. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `curator` | `account_name_type` | Curator account | -| `reward` | `asset` (SHARES) | Curation reward in SHARES | -| `content_author` | `account_name_type` | Author of the curated content | -| `content_permlink` | `string` | Permlink of the curated content | - -### JSON Example - -```json -[27, { - "curator": "bob", - "reward": "0.500000 SHARES", - "content_author": "alice", - "content_permlink": "my-article" -}] -``` - ---- - -## `content_reward_operation` - -**Type ID:** `28` -**Trigger:** Content payout - -Fired when a content post reaches its payout time. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `author` | `account_name_type` | Content author | -| `permlink` | `string` | Content permlink | -| `payout` | `asset` | Total payout amount | - ---- - -## `fill_vesting_withdraw_operation` - -**Type ID:** `29` -**Trigger:** Each vesting withdrawal interval - -Fired each time a vesting withdrawal interval completes (weekly). - -### Fields - -| Field | Type | Description | -|---|---|---| -| `from_account` | `account_name_type` | Account withdrawing | -| `to_account` | `account_name_type` | Account receiving (may differ via route) | -| `withdrawn` | `asset` (SHARES) | SHARES amount withdrawn this interval | -| `deposited` | `asset` (VIZ) | VIZ tokens deposited to `to_account` | - -### JSON Example - -```json -[29, { - "from_account": "alice", - "to_account": "alice", - "withdrawn": "35.714285 SHARES", - "deposited": "10.000 VIZ" -}] -``` - -### Checklist for listeners -- [ ] Fired once per interval (default: every 1 day) for each active withdrawal -- [ ] `to_account` may differ if `set_withdraw_vesting_route_operation` was used -- [ ] If `auto_vest == true` in route, `deposited` will be SHARES, not VIZ - ---- - -## `shutdown_witness_operation` - -**Type ID:** `30` -**Trigger:** validator removed due to vote weight falling below threshold - -### Fields - -| Field | Type | Description | -|---|---|---| -| `owner` | `account_name_type` | validator that was shut down | - ---- - -## `hardfork_operation` - -**Type ID:** `31` -**Trigger:** Network hardfork activation - -### Fields - -| Field | Type | Description | -|---|---|---| -| `hardfork_id` | `uint32_t` | Hardfork number | - ---- - -## `content_payout_update_operation` - -**Type ID:** `32` -**Trigger:** Content payout update - -Fired when content payout is updated (e.g., after vote changes). - -### Fields - -| Field | Type | Description | -|---|---|---| -| `author` | `account_name_type` | Content author | -| `permlink` | `string` | Content permlink | - ---- - -## `content_benefactor_reward_operation` - -**Type ID:** `33` -**Trigger:** Content payout - -Fired for each beneficiary when content is paid out. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `benefactor` | `account_name_type` | Beneficiary account | -| `author` | `account_name_type` | Content author | -| `permlink` | `string` | Content permlink | -| `reward` | `asset` | Beneficiary's reward share | - ---- - -## `return_vesting_delegation_operation` - -**Type ID:** `34` -**Trigger:** End of vesting delegation limbo period (1 week after delegation removal) - -### Fields - -| Field | Type | Description | -|---|---|---| -| `account` | `account_name_type` | Account receiving the returned SHARES | -| `vesting_shares` | `asset` (SHARES) | SHARES returned from limbo | - -### JSON Example - -```json -[34, { - "account": "alice", - "vesting_shares": "500.000000 SHARES" -}] -``` - ---- - -## `committee_cancel_request_operation` - -**Type ID:** `38` -**Trigger:** Committee request expires without enough votes - -### Fields - -| Field | Type | Description | -|---|---|---| -| `request_id` | `uint32_t` | ID of cancelled request | - ---- - -## `committee_approve_request_operation` - -**Type ID:** `39` -**Trigger:** Committee request reaches required approval threshold - -### Fields - -| Field | Type | Description | -|---|---|---| -| `request_id` | `uint32_t` | ID of approved request | - ---- - -## `committee_payout_request_operation` - -**Type ID:** `40` -**Trigger:** Committee request payout is processed - -### Fields - -| Field | Type | Description | -|---|---|---| -| `request_id` | `uint32_t` | ID of paid request | - ---- - -## `committee_pay_request_operation` - -**Type ID:** `41` -**Trigger:** Worker receives payment from committee - -### Fields - -| Field | Type | Description | -|---|---|---| -| `worker` | `account_name_type` | Worker account receiving payment | -| `request_id` | `uint32_t` | Committee request ID | -| `tokens` | `asset` (VIZ) | Amount paid to worker | - -### JSON Example - -```json -[41, { - "worker": "alice", - "request_id": 42, - "tokens": "250.000 VIZ" -}] -``` - ---- - -## `witness_reward_operation` - -**Type ID:** `42` -**Trigger:** Block production reward - -Fired when a validator receives their block production reward. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `validator` | `account_name_type` | validator account | -| `shares` | `asset` (SHARES) | Reward in SHARES | - -### JSON Example - -```json -[42, { - "validator": "alice", - "shares": "1.234567 SHARES" -}] -``` - ---- - -## `receive_award_operation` - -**Type ID:** `48` -**Trigger:** `award_operation` or `fixed_award_operation` - -Fired when the receiver gets their award. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `initiator` | `account_name_type` | Account that gave the award | -| `receiver` | `account_name_type` | Account that received the award | -| `custom_sequence` | `uint64_t` | App-defined sequence from the award op | -| `memo` | `string` | Memo from the award op | -| `shares` | `asset` (SHARES) | SHARES received | - -### JSON Example - -```json -[48, { - "initiator": "alice", - "receiver": "bob", - "custom_sequence": 0, - "memo": "great article!", - "shares": "5.000000 SHARES" -}] -``` - ---- - -## `benefactor_award_operation` - -**Type ID:** `49` -**Trigger:** `award_operation` or `fixed_award_operation` with beneficiaries - -Fired for each beneficiary when an award is given. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `initiator` | `account_name_type` | Account that gave the award | -| `benefactor` | `account_name_type` | Beneficiary account | -| `receiver` | `account_name_type` | Primary receiver of the award | -| `custom_sequence` | `uint64_t` | App-defined sequence | -| `memo` | `string` | Memo from the award op | -| `shares` | `asset` (SHARES) | SHARES received by beneficiary | - ---- - -## `paid_subscription_action_operation` - -**Type ID:** `52` -**Trigger:** `paid_subscribe_operation` or auto-renewal payment - -Fired on each subscription payment. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `subscriber` | `account_name_type` | Subscriber account | -| `account` | `account_name_type` | Subscription provider | -| `level` | `uint16_t` | Subscription level | -| `amount` | `asset` (VIZ) | Payment amount | -| `period` | `uint16_t` | Number of periods | -| `summary_duration_sec` | `uint64_t` | Total subscription duration in seconds | -| `summary_amount` | `asset` (VIZ) | Total amount paid to date | - -### JSON Example - -```json -[52, { - "subscriber": "bob", - "account": "alice", - "level": 2, - "amount": "20.000 VIZ", - "period": 1, - "summary_duration_sec": 2592000, - "summary_amount": "20.000 VIZ" -}] -``` - ---- - -## `cancel_paid_subscription_operation` - -**Type ID:** `53` -**Trigger:** Subscription expiry without renewal, or insufficient funds for auto-renewal - -### Fields - -| Field | Type | Description | -|---|---|---| -| `subscriber` | `account_name_type` | Subscriber account | -| `account` | `account_name_type` | Subscription provider | - ---- - -## `account_sale_operation` - -**Type ID:** `57` -**Trigger:** `buy_account_operation` completes successfully - -Fired when an account is sold. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `account` | `account_name_type` | Account that was sold | -| `price` | `asset` (VIZ) | Sale price | -| `buyer` | `account_name_type` | Buyer account | -| `seller` | `account_name_type` | Seller (payment recipient) | - -### JSON Example - -```json -[57, { - "account": "alice", - "price": "1000.000 VIZ", - "buyer": "bob", - "seller": "alice" -}] -``` - ---- - -## `expire_escrow_ratification_operation` - -**Type ID:** `59` -**Trigger:** Escrow not ratified by both parties before `ratification_deadline` - -Fired when an escrow expires before being fully approved. Funds are returned to `from`. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `from` | `account_name_type` | Original escrow sender | -| `to` | `account_name_type` | Original intended recipient | -| `agent` | `account_name_type` | Escrow agent | -| `escrow_id` | `uint32_t` | Escrow ID | -| `token_amount` | `asset` (VIZ) | Returned token amount | -| `fee` | `asset` (VIZ) | Fee returned (agent not paid since not approved) | -| `ratification_deadline` | `time_point_sec` | Deadline that was missed | - ---- - -## `bid_operation` - -**Type ID:** `62` -**Trigger:** New bid placed on an account for sale (HF11) - -### Fields - -| Field | Type | Description | -|---|---|---| -| `account` | `account_name_type` | Account being bid on | -| `bidder` | `account_name_type` | Account placing the bid | -| `bid` | `asset` (VIZ) | Bid amount | - ---- - -## `outbid_operation` - -**Type ID:** `63` -**Trigger:** A previous bidder is outbid (HF11) - -Fired when a previous bid is replaced by a higher bid. The outbid amount is returned. - -### Fields - -| Field | Type | Description | -|---|---|---| -| `account` | `account_name_type` | Account being bid on | -| `bidder` | `account_name_type` | Account that was outbid | -| `bid` | `asset` (VIZ) | Returned bid amount | - ---- - -## Implementation Notes for Libraries - -### Listening to Virtual Operations - -```php -// PHP: subscribe to account history -$history = $api->get_account_history('alice', -1, 100); -foreach ($history as [$index, $entry]) { - $opType = $entry['op'][0]; - $opData = $entry['op'][1]; - switch ($opType) { - case 'receive_award_operation': - // handle award received - break; - case 'fill_vesting_withdraw_operation': - // handle withdrawal - break; - } -} -``` - -```js -// Node.js: stream operations -client.database.getAccountHistory('alice', -1, 100).then(history => { - for (const [index, entry] of history) { - const [opType, opData] = entry.op; - switch (opType) { - case 'receive_award': - // handle award - break; - case 'witness_reward': - // handle validator reward - break; - } - } -}); -``` - -### Checklist for Virtual Operation Handling -- [ ] Virtual operations are read-only — never include them in transactions -- [ ] Filter by operation type in account/operation history -- [ ] Virtual ops share the same type variant as regular ops — use the same deserialization -- [ ] `summary_duration_sec` in paid subscriptions may be 0 for first payment -- [ ] Multiple virtual ops may fire in the same block for the same account diff --git a/.qoder/docs/witness-guard-spec.json b/.qoder/docs/witness-guard-spec.json deleted file mode 100644 index b220a0ca8b..0000000000 --- a/.qoder/docs/witness-guard-spec.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "witness-guard-spec.json", - "title": "Witness Guard Plugin Specification", - "description": "Technical specification for the automated witness key restoration plugin", - "version": "2.0.0", - - "definitions": { - "witness_entry": { - "type": "array", - "description": "A JSON array representing a witness configuration triplet", - "items": [ - { "name": "account_name", "type": "string", "description": "The name of the witness account to monitor" }, - { "name": "signing_wif", "type": "string", "description": "The WIF private key to be restored as the signing key" }, - { "name": "active_wif", "type": "string", "description": "The WIF private key with active authority to sign the update transaction" } - ], - "example": "[\"mywitness\", \"5Ksigning...\", \"5Kactive...\"]" - } - }, - - "configuration": { - "options": [ - { - "name": "witness-guard-enabled", - "type": "boolean", - "default": true, - "description": "Global toggle for the plugin logic" - }, - { - "name": "witness-guard-witness", - "type": "vector", - "description": "List of witness triplets in JSON format. Can be specified multiple times.", - "ref": "#/definitions/witness_entry" - }, - { - "name": "witness-guard-interval", - "type": "uint32", - "default": 20, - "description": "Frequency of periodic checks measured in blocks (20 blocks ≈ 60 seconds)" - }, - { - "name": "witness-guard-disable", - "type": "uint32", - "default": 5, - "description": "Number of consecutive blocks produced by the same monitored witness before automatically disabling that witness (setting signing key to null). Set to 0 to disable this feature." - } - ], - "external_options_read": [ - { - "name": "enable-stale-production", - "type": "boolean", - "default": false, - "description": "Read from the shared witness config. When true, auto-restore is disabled until network participation reaches >= 33%, at which point the flag is auto-cleared." - } - ] - }, - - "algorithms": { - "check_and_restore": { - "description": "Core loop: validates preconditions and restores null signing keys", - "steps": [ - { "step": 1, "action": "Stale production guard: if enable-stale-production is active AND participation < 33% AND not emergency mode, skip all checks. If participation >= 33%, auto-clear the stale flag and continue." }, - { "step": 2, "action": "Sync check: head_block_time must be within 2 * CHAIN_BLOCK_INTERVAL seconds of wall clock" }, - { "step": 3, "action": "Long fork safety: if Last Irreversible Block is older than 200 seconds, skip restoration" }, - { "step": 4, "action": "Expire stale pending-confirmation trackers (failed broadcasts) to allow retries" }, - { "step": 5, "action": "For each configured witness: look up witness object by name in witness_index" }, - { "step": 6, "condition": "signing_key is NOT null", "action": "Clear any pending restore state and auto-disabled flag for this witness" }, - { "step": 6.5, "condition": "signing_key IS null AND witness is in _auto_disabled_witnesses", "action": "Skip auto-restore — the witness was disabled by the consecutive-block guard; operator must manually intervene" }, - { "step": 7, "condition": "signing_key IS null AND no in-flight restore (or previous restore expired)", "action": "Invoke send_witness_update" } - ], - "returns": "true if node was in sync and full check was performed, false otherwise" - }, - - "send_witness_update": { - "description": "Constructs, signs, and broadcasts a witness_update_operation to restore the signing key", - "steps": [ - { "step": 1, "action": "Build witness_update_operation: preserve current URL, set block_signing_key to configured public key" }, - { "step": 2, "action": "Create signed_transaction with 30-second expiration and head block reference" }, - { "step": 3, "action": "Sign the transaction with the configured active private key" }, - { "step": 4, "action": "Broadcast via P2P plugin" }, - { "step": 5, "action": "Track transaction ID in _pending_confirmations and witness in _restore_pending" } - ] - }, - - "applied_block_handler": { - "description": "Signal handler connected to database.applied_block, runs on every new block", - "steps": [ - { "step": 0, "action": "Consecutive-block auto-disable: if _disable_threshold > 0 and block was produced by a monitored witness, increment its consecutive counter. If counter >= threshold and witness not already auto-disabled, broadcast send_witness_disable. If block was by a different witness, reset all counters to 0." }, - { "step": 1, "action": "Scan the block's transactions for any pending confirmation IDs; on match, mark witness restore as confirmed and clear tracking state" }, - { "step": 2, "action": "Look-ahead: if any monitored witness is scheduled in the next 3 slots, trigger an immediate check" }, - { "step": 3, "action": "Otherwise: if initial sync not yet done, probe every 10 blocks; else run periodic check every _check_interval blocks" } - ] - }, - - "send_witness_disable": { - "description": "Constructs, signs, and broadcasts a witness_update_operation with null signing key to disable block production", - "steps": [ - { "step": 1, "action": "Build witness_update_operation: preserve current URL, set block_signing_key to null" }, - { "step": 2, "action": "Create signed_transaction with 30-second expiration and head block reference" }, - { "step": 3, "action": "Sign the transaction with the configured active private key" }, - { "step": 4, "action": "Broadcast via P2P plugin" }, - { "step": 5, "action": "Add the witness to _auto_disabled_witnesses set to prevent auto-restore" } - ] - }, - - "startup_authority_validation": { - "description": "Runs at plugin_startup after the chain database is open", - "steps": [ - { "step": 1, "action": "For each configured witness, look up account_authority_object on chain" }, - { "step": 2, "action": "Verify the configured active key is present in the account's active key_auths" }, - { "step": 3, "action": "Log a warning if the key lacks authority; remove the witness from monitoring if the account does not exist" } - ] - } - }, - - "internal_state": { - "_witness_configs": { - "type": "std::map", - "description": "Configured witnesses: maps witness account name to its signing and active key pair" - }, - "_restore_pending": { - "type": "std::map", - "description": "Witnesses with an in-flight restore transaction: maps witness name to the transaction's expiration time. Prevents duplicate broadcasts." - }, - "_pending_confirmations": { - "type": "std::map>", - "description": "Transaction IDs awaiting block inclusion: maps tx_id to (witness_name, expiration). Used to confirm restore transactions landed on-chain. Capped at 1000 entries." - }, - "_stale_production_config": { - "type": "bool", - "default": false, - "description": "Mirrors enable-stale-production from witness config. Auto-cleared to false when network participation reaches >= 33%, re-enabling key restoration." - }, - "_initial_check_done": { - "type": "bool", - "default": false, - "description": "Set to true once the node is confirmed in sync at startup. Until then, the plugin probes every 10 blocks instead of using the configured interval." - }, - "_disable_threshold": { - "type": "uint32_t", - "default": 5, - "description": "Number of consecutive blocks by the same monitored witness before auto-disabling it. Mirrors witness-guard-disable config option. 0 = feature disabled." - }, - "_consecutive_blocks": { - "type": "std::map", - "description": "Per-witness counter of consecutive blocks produced. Reset to 0 for all witnesses when a block from a non-monitored (or different) witness is seen." - }, - "_auto_disabled_witnesses": { - "type": "std::set", - "description": "Witnesses that have been auto-disabled by the consecutive-block guard. Auto-restore is suppressed for these witnesses. Cleared when the on-chain key is manually restored (non-null key detected)." - } - }, - - "safety_guards": { - "stale_production": "When enable-stale-production=true, auto-restore is disabled to avoid broadcasting on a minority fork. Auto-cleared when participation >= 33% (same logic as witness plugin).", - "emergency_mode": "During emergency consensus (dgp.emergency_consensus_active), the stale production guard is bypassed — key restoration may still be needed for recovery.", - "sync_check": "Restoration only runs when head_block_time is within 2 * CHAIN_BLOCK_INTERVAL of wall clock time.", - "long_fork_detection": "If the Last Irreversible Block is older than 200 seconds, restoration is skipped to avoid acting on a stale fork.", - "authority_validation": "At startup, the plugin verifies the configured active key has authority on-chain; warns or removes witnesses that would fail.", - "consecutive_block_auto_disable": "When a monitored witness produces witness-guard-disable consecutive blocks, the plugin auto-disables it by broadcasting a null signing key. Auto-restore is suppressed for that witness until the operator manually restores the key." - } -} diff --git a/.qoder/docs/witness-to-validator-migration-reference.md b/.qoder/docs/witness-to-validator-migration-reference.md deleted file mode 100644 index f98db5e4eb..0000000000 --- a/.qoder/docs/witness-to-validator-migration-reference.md +++ /dev/null @@ -1,501 +0,0 @@ -# VIZ Blockchain — validator → Validator Migration Reference - -## Quick Summary - -The VIZ blockchain is renaming "validator" terminology to "validator" across the entire stack. This document is a reference for JS/PHP library developers to support both old and new names during migration. - -**Key principle: binary wire format uses integer type IDs, not string names. Submitting transactions by integer ID never breaks. Only JSON string names change.** - ---- - -## 0. What Libraries Must Change Themselves vs What They Just Relay - -This distinction is the most important rule for library developers. - -### Must change (library constructs these from scratch): - -| What | Where in library code | -|------|----------------------| -| Operation name→ID mapping table | Serialization/deserialization layer | -| Field names inside type 7 and type 42 operations | Operation builders, schema definitions | -| Chain properties field names (`inflation_witness_percent`, etc.) | `chain_properties_update` builder | -| TypeScript interfaces / PHP classes for operation structs | Type definitions | -| TypeScript interfaces / PHP classes for `validator_schedule_object` | Type definitions | - -### Do NOT need to change (library receives from node and relays): - -| What | Reason | -|------|--------| -| Block header fields | **Done.** Node now returns `validator` / `validator_signature`. Libraries that relay raw block objects with no field-specific code need no changes. Code explicitly accessing `.validator` / `.witness_signature` on a block header must be updated to `.validator` / `.validator_signature`. | -| Raw API response objects (beyond type definitions) | JSON deserialization is dynamic — field access works regardless of name if library doesn't validate field names | -| Historical transaction data from node | Same — the node returns it, library relays it | - -**Practical rule:** if your library has a hardcoded string `"validator"` as a field name when *building* a JSON object to *send* to a node — that string must be updated. If the string `"validator"` only appears in a *comment*, a *display label*, or a *type definition that only affects IDE autocomplete* — it can wait. - ---- - -## Current Status (What Has Been Done vs What Is Planned) - -| Layer | Status | Visible to JS/PHP? | -|-------|--------|---------------------| -| Internal C++ methods (e.g., `is_validator_scheduled_soon`) | **Done** | No | -| Internal enums (`block_validation_condition`) | **Done** | No | -| Internal skip flags (`skip_validator_signature`) | **Done** | No | -| Block header fields (`validator`, `validator_signature`) | **Done** | Yes — block responses | -| Dynamic global property (`current_validator`) | **Done** | Yes — `get_dynamic_global_properties` | -| Protocol operation struct names and JSON names | **Done** | Yes — JSON name in transactions | -| Operation field names inside types 7 and 42 | **Done** | Yes — field names in operation body | -| Chain properties field names | **Done** | Yes — JSON field names in governance ops | -| API method names (`get_active_validators`, etc.) | **Done** | Yes — JSON-RPC calls | -| Chain object types (`validator_object`, etc.) | **Done** | Yes — API response type names | -| CLI wallet commands (`get_active_validators`, etc.) | **Done** | Yes — if using CLI wallet | -| Physical file renames (`.hpp`/`.cpp`, directories) | **Done** | No — internal build only | -| Plugin directory and CMake target renames | **Done** | No — internal build | -| Config key renames (`plugin = validator`, etc.) | **Done** | Yes — node operators must update `config.ini` | -| API namespace (`validator_api`) | **Done** | Yes — JSON-RPC `"api"` field (see Section 2) | -| `account_api_object` fields (`validators_voted_for`, `validators_vote_weight`, `validator_votes`) | **Done** | Yes — `get_accounts` response | -| `get_config` keys (`CHAIN_MAX_VALIDATORS`, `CHAIN_HARDFORK_REQUIRED_VALIDATORS`, etc.) | **Done** | Yes — `get_config` response | -| Config constants (`CHAIN_MAX_VALIDATORS`, `CHAIN_BLOCK_VALIDATOR_REPEAT`, `CHAIN_EMERGENCY_VALIDATOR_ACCOUNT`, etc.) | **Done** | No — internal C++ only | - ---- - -## 1. Protocol Operations (JSON-RPC Transaction Submission) - -These are the operations users submit in transactions. The **integer type ID never changes** — only the JSON string name changes. - -### Operations to Rename - -| Type ID | Current JSON Name (old) | New JSON Name | Virtual? | Fields (unchanged) | -|---------|------------------------|---------------|----------|---------------------| -| `6` | `witness_update` | `validator_update` | no | `owner`, `url`, `block_signing_key` | -| `7` | `account_witness_vote` | `account_validator_vote` | no | `account`, **`validator` → `validator`**, `approve` | -| `8` | `account_witness_proxy` | `account_validator_proxy` | no | `account`, `proxy` | -| `30` | `shutdown_witness` | `shutdown_validator` | **yes** | `owner` | -| `42` | `witness_reward` | `validator_reward` | **yes** | **`validator` → `validator`**, `shares` | - -> **Field renames inside operations:** In type 7 (`account_validator_vote`) the field `validator` (the target account name) is renamed to `validator`. In type 42 (`validator_reward`) the field `validator` is renamed to `validator`. The node accepts both old and new field names in incoming JSON, but responses use new names only. - -### What JS/PHP Developers Must Handle - -**Sending transactions (2 safe approaches):** - -```js -// Approach A: Use integer type ID (always safe, never breaks) -const op = [6, { - owner: 'alice', - url: 'https://alice.example.com', - block_signing_key: 'VIZ5hq...', -}]; - -// Approach B: Use string name (need to support both old and new) -const op = ['validator_update', { // new name - owner: 'alice', - url: 'https://alice.example.com', - block_signing_key: 'VIZ5hq...', -}]; -``` - -**Sending type 7 (vote) with updated field name:** - -```js -// Old (still accepted by node, but deprecated): -const op = [7, { account: 'alice', validator: 'bob', approve: true }]; - -// New (correct): -const op = [7, { account: 'alice', validator: 'bob', approve: true }]; -``` - -**Receiving transactions (operation history, block parsing):** - -```js -// Old server response: -["witness_update", { "owner": "alice", ... }] - -// New server response: -["validator_update", { "owner": "alice", ... }] - -// Your code must accept BOTH names for the same operation -``` - -**Server-side fallback:** The C++ node will accept both old and new JSON names in incoming transactions. But responses will use **new names only**. - -### Implementation Pattern for JS/PHP - -```js -// Operation name mapping (accept both, send new) -const OP_NAME_MAP = { - 'witness_update': 'validator_update', - 'account_witness_vote': 'account_validator_vote', - 'account_witness_proxy': 'account_validator_proxy', - 'shutdown_witness': 'shutdown_validator', - 'witness_reward': 'validator_reward', -}; - -// Reverse map (for receiving — normalize old names to new) -const OP_ALIAS_MAP = { - 'witness_update': 'validator_update', - 'account_witness_vote': 'account_validator_vote', - 'account_witness_proxy': 'account_validator_proxy', - 'shutdown_witness': 'shutdown_validator', - 'witness_reward': 'validator_reward', -}; - -// Type ID constants (never change) -const OP_TYPE_ID = { - validator_update: 6, - account_validator_vote: 7, - account_validator_proxy: 8, - shutdown_validator: 30, - validator_reward: 42, -}; -``` - -```php -// PHP equivalent -const OP_NAME_MAP = [ - 'witness_update' => 'validator_update', - 'account_witness_vote' => 'account_validator_vote', - 'account_witness_proxy' => 'account_validator_proxy', - 'shutdown_witness' => 'shutdown_validator', - 'witness_reward' => 'validator_reward', -]; - -const OP_TYPE_ID = [ - 'validator_update' => 6, - 'account_validator_vote' => 7, - 'account_validator_proxy' => 8, - 'shutdown_validator' => 30, - 'validator_reward' => 42, -]; -``` - ---- - -## 2. API Methods (JSON-RPC Calls) - -### API Namespace - -**Done.** The JSON-RPC namespace is now **`"validator_api"`**. Old clients still using `"witness_api"` will fail — they must update: - -```json -{ "api": "validator_api", "method": "get_active_validators", "params": [] } -``` - -Implementation pattern for dual support during library migration: - -```js -async function callApi(method, params) { - try { - return await rpc({ api: 'validator_api', method, params }); - } catch (e) { - // Fallback for old nodes not yet upgraded - return await rpc({ api: 'witness_api', method, params }); - } -} -``` - -### Methods to Rename - -| Current Name (old) | New Name | Returns (unchanged) | -|-------------------|----------|---------------------| -| `get_active_witnesses` | `get_active_validators` | `vector` | -| `get_witness_schedule` | `get_validator_schedule` | `witness_schedule_object` → `validator_schedule_object` | -| `get_witnesses` | `get_validators` | `vector>` → `validator_api_object` | -| `get_witness_by_account` | `get_validator_by_account` | `optional` → `validator_api_object` | -| `get_witnesses_by_vote` | `get_validators_by_vote` | `vector` → `validator_api_object` | -| `get_witnesses_by_counted_vote` | `get_validators_by_counted_vote` | `vector` → `validator_api_object` | -| `get_witness_count` | `get_validator_count` | `uint64_t` | -| `lookup_witness_accounts` | `lookup_validator_accounts` | `set` | - -### What JS/PHP Developers Must Handle - -**Server-side fallback:** Old method names will remain as deprecated aliases for one release cycle. Calling `get_active_witnesses` will still work but will log a deprecation warning on the server. - -### Implementation Pattern for JS/PHP - -```js -// Dual-support API wrapper -class VizApi { - async getActiveValidators() { - try { - return await this.call('get_active_validators'); - } catch (e) { - // Fallback to old name for older nodes - return await this.call('get_active_witnesses'); - } - } - - async getValidatorByAccount(account) { - try { - return await this.call('get_validator_by_account', [account]); - } catch (e) { - return await this.call('get_witness_by_account', [account]); - } - } - - // ... same pattern for all renamed methods -} -``` - ---- - -## 3. API Response Objects - -### Object Types to Rename - -| Current Name (old) | New Name | Key Fields (unchanged) | -|-------------------|----------|------------------------| -| `witness_object` | `validator_object` | `id`, `owner`, `url`, `signing_key`, `votes`, `schedule` | -| `witness_schedule_object` | `validator_schedule_object` | `current_shuffled_validators[]`, `num_scheduled` | -| `witness_api_object` | `validator_api_object` | All fields same as `witness_object` + computed fields | - -### Field Renames in Response Objects - -| Object | Current Field Name (old) | New Field Name | -|--------|-------------------------|----------------| -| `validator_schedule_object` | `current_shuffled_witnesses` | `current_shuffled_validators` | -| `validator_schedule_object` | `num_scheduled_witnesses` | `num_scheduled_validators` | - -### What JS/PHP Developers Must Handle - -```js -// Old response: -{ - "current_shuffled_witnesses": ["alice", "bob", ...], - "num_scheduled_witnesses": 21 -} - -// New response: -{ - "current_shuffled_validators": ["alice", "bob", ...], - "num_scheduled_validators": 21 -} - -// Safe accessor pattern -function getShuffledValidators(schedule) { - return schedule.current_shuffled_validators - || schedule.current_shuffled_witnesses; // fallback for old nodes -} -``` - ---- - -## 4. Operation Field Names (Changing and Unchanged) - -### Fields Being Renamed - -| Field (old) | Field (new) | Operation | Note | -|-------------|-------------|-----------|------| -| `validator` | `validator` | `account_validator_vote` (type 7) | Target account name | -| `validator` | `validator` | `validator_reward` (type 42) | Virtual op — library receives, not constructs | - -The node accepts both old and new field names in incoming JSON (backward compat). Responses always use new names. - -### Fields That Stay Unchanged - -| Field | Operation | Why It Stays | -|-------|-----------|-------------| -| `owner` | `validator_update` (type 6) | Describes the account, not the role | -| `url` | `validator_update` (type 6) | URL is a URL | -| `block_signing_key` | `validator_update` (type 6) | Describes the cryptographic key purpose | -| `account` | `account_validator_vote` (type 7) | Describes the voting account | -| `proxy` | `account_validator_proxy` (type 8) | Describes the proxy account | -| `approve` | `account_validator_vote` (type 7) | Boolean flag | -| `shares` | `validator_reward` (type 42) | Vesting shares amount | - ---- - -## 5. Chain Properties Field Renames - -**This section is critical for library developers.** The `chain_properties_update_operation` and `versioned_chain_properties_update_operation` carry governance parameters with `validator` in their names. These field names change in JSON. Libraries that construct these operations must update field names. - -**Binary format is safe** — field order is preserved in binary serialization, names are not written. Only JSON field names change. - -### Fields Being Renamed - -| Old Field Name | New Field Name | In Struct | -|----------------|----------------|-----------| -| `inflation_witness_percent` | `inflation_validator_percent` | `chain_properties_hf4` | -| `witness_miss_penalty_percent` | `validator_miss_penalty_percent` | `chain_properties_hf6` | -| `witness_miss_penalty_duration` | `validator_miss_penalty_duration` | `chain_properties_hf6` | -| `witness_declaration_fee` | `validator_declaration_fee` | `chain_properties_hf9` | - -### What JS/PHP Developers Must Handle - -```js -// Old (still accepted by node with compat layer): -const props = { - inflation_witness_percent: 1500, - witness_miss_penalty_percent: 100, - witness_miss_penalty_duration: 86400, - witness_declaration_fee: { amount: '10000', asset: 'VIZ' }, -}; - -// New (correct): -const props = { - inflation_validator_percent: 1500, - validator_miss_penalty_percent: 100, - validator_miss_penalty_duration: 86400, - validator_declaration_fee: { amount: '10000', asset: 'VIZ' }, -}; -``` - -```php -// PHP equivalent -$props = [ - 'inflation_validator_percent' => 1500, - 'validator_miss_penalty_percent' => 100, - 'validator_miss_penalty_duration' => 86400, - 'validator_declaration_fee' => ['amount' => '10000', 'asset' => 'VIZ'], -]; -``` - ---- - -## 6. Config Keys (For Node Operators) - -Not directly relevant to JS/PHP libraries, but included for completeness: - -| Current Config Key (old) | New Config Key | -|--------------------------|----------------| -| `plugin = validator` | `plugin = validator` | -| `plugin = witness_api` | `plugin = validator_api` | -| `plugin = witness_guard` | `plugin = validator_guard` | -| `--validator = "name"` | `--validator = "name"` | -| `validator-guard-enabled` | `validator-guard-enabled` | -| `validator-guard-disable` | `validator-guard-disable` | -| `validator-guard-interval` | `validator-guard-interval` | -| `validator-guard-validator` | `validator-guard-validator` | - ---- - -## 7. CLI Wallet Commands (If Using CLI Wallet) - -| Current Command (old) | New Command | Notes | -|----------------------|-------------|-------| -| `list_witnesses()` | `list_validators()` | Read-only | -| `get_witness()` | `get_validator()` | Read-only | -| `get_active_witnesses()` | `get_active_validators()` | Read-only | -| `update_witness()` | `update_validator()` | Sends type 6 | -| `vote_for_witness()` | `vote_for_validator()` | Sends type 7 | -| `set_voting_proxy()` | `set_voting_proxy()` | Command name stays, sends type 8 | - ---- - -## 8. What NEVER Changes - -| Item | Why | -|------|-----| -| Integer type IDs (6, 7, 8, 30, 42) | Binary wire format uses integer indices | -| Binary serialization of operations | Struct field order is preserved; field names are not written to binary | -| Field names `block_signing_key`, `url`, `approve`, `proxy` | Describe data, not the role | -| Null key for deactivation: `VIZ1111111111111111111111111111111114T1Anm` | Same null key format | -| Signing authority level (`active`) | Operations still require active authority | -| Block interval, slot scheduling, consensus rules | Unchanged | - -> **Block header fields** are now `validator` and `validator_signature` in all node responses. Binary wire format is unchanged — field names are not serialized, only values by position. Libraries relaying raw block objects reflect new names automatically; no version negotiation needed. - ---- - -## 9. Migration Strategy for Library Developers - -### Phase A — Prepare (Before Node Upgrade) - -1. Add dual-name support for operation type identification: - - Accept both `witness_update` and `validator_update` as name for type ID 6 - - Accept both `account_witness_vote` and `account_validator_vote` as name for type ID 7 - - Same for types 8, 30, 42 -2. Update field names in operation builders: - - Type 7: accept both `validator` and `validator` for the target account field; send `validator` - - Chain properties: add new field names; keep old for backward compat with old nodes -3. Add dual-name support for API methods: - - Try new method name first, fall back to old name -4. Add dual field access for response objects: - - Check `current_shuffled_validators` first, fall back to `current_shuffled_witnesses` -5. **Send transactions using integer type IDs** for maximum compatibility - -### Phase B — After Node Upgrade - -1. Default to new names for sending -2. Keep old name acceptance for receiving (history may contain old-format blocks) -3. Release library update with both names supported - -### Phase C — Cleanup (After All Nodes Upgraded) - -1. Remove old name fallbacks -2. Use only new names throughout - ---- - -## 10. Complete Quick-Reference Table - -### Operations - -| Type ID | Old JSON Name | New JSON Name | Field changes | -|---------|--------------|---------------|---------------| -| 6 | `witness_update` | `validator_update` | none | -| 7 | `account_witness_vote` | `account_validator_vote` | `validator` → `validator` | -| 8 | `account_witness_proxy` | `account_validator_proxy` | none | -| 30 | `shutdown_witness` | `shutdown_validator` | none | -| 42 | `witness_reward` | `validator_reward` | `validator` → `validator` | - -### API Methods - -| Old Name | New Name | -|----------|----------| -| `get_active_witnesses` | `get_active_validators` | -| `get_witness_schedule` | `get_validator_schedule` | -| `get_witnesses` | `get_validators` | -| `get_witness_by_account` | `get_validator_by_account` | -| `get_witnesses_by_vote` | `get_validators_by_vote` | -| `get_witnesses_by_counted_vote` | `get_validators_by_counted_vote` | -| `get_witness_count` | `get_validator_count` | -| `lookup_witness_accounts` | `lookup_validator_accounts` | - -### Response Fields - -| Old Field | New Field | In Object | -|-----------|-----------|-----------| -| `current_shuffled_witnesses` | `current_shuffled_validators` | `validator_schedule_object` | -| `num_scheduled_witnesses` | `num_scheduled_validators` | `validator_schedule_object` | - -### Block Header Fields - -| Old Field | New Field | -|-----------|-----------| -| `validator` | `validator` | -| `witness_signature` | `validator_signature` | - -### Dynamic Global Property Fields - -| Old Field | New Field | -|-----------|-----------| -| `current_witness` | `current_validator` | - -### Chain Properties Fields - -| Old Field | New Field | In Struct | -|-----------|-----------|-----------| -| `inflation_witness_percent` | `inflation_validator_percent` | `chain_properties_hf4` | -| `witness_miss_penalty_percent` | `validator_miss_penalty_percent` | `chain_properties_hf6` | -| `witness_miss_penalty_duration` | `validator_miss_penalty_duration` | `chain_properties_hf6` | -| `witness_declaration_fee` | `validator_declaration_fee` | `chain_properties_hf9` | - -### Account Object Fields (`get_accounts` response) - -| Old Field | New Field | Notes | -|-----------|-----------|-------| -| `witnesses_voted_for` | `validators_voted_for` | Count of validators the account voted for | -| `witnesses_vote_weight` | `validators_vote_weight` | Cached voting weight | -| `witness_votes` | `validator_votes` | Set of validator account names voted for | - -### `get_config` Response Keys - -| Old Key | New Key | -|---------|---------| -| `CHAIN_HARDFORK_REQUIRED_WITNESSES` | `CHAIN_HARDFORK_REQUIRED_VALIDATORS` | -| `CHAIN_MAX_ACCOUNT_WITNESS_VOTES` | `CHAIN_MAX_ACCOUNT_VALIDATOR_VOTES` | -| `CHAIN_MAX_WITNESSES` | `CHAIN_MAX_VALIDATORS` | -| `CHAIN_MAX_SUPPORT_WITNESSES` | `CHAIN_MAX_SUPPORT_VALIDATORS` | -| `CHAIN_MAX_TOP_WITNESSES` | `CHAIN_MAX_TOP_VALIDATORS` | -| `CHAIN_MAX_WITNESS_URL_LENGTH` | `CHAIN_MAX_VALIDATOR_URL_LENGTH` | diff --git a/.qoder/docs/witness-to-validator-rename.md b/.qoder/docs/witness-to-validator-rename.md deleted file mode 100644 index 100a1aad34..0000000000 --- a/.qoder/docs/witness-to-validator-rename.md +++ /dev/null @@ -1,402 +0,0 @@ -# Naming Analysis: VIZ "validator" → "Validator" Rename Proposal - -## 1. What VIZ validators Actually Do - -Looking at the codebase, VIZ validators perform two distinct roles: - -**Block production** — scheduled in rotation, they run `block_production_loop()`, sign blocks with `block_signing_key`, and broadcast them via P2P. - -**Block post validation (BPV)** — they sign `block_post_validation_object`s to confirm blocks produced by other validators, which drives LIB (Last Irreversible Block) advancement. - -So validators are both producers and validators — which is exactly why "validator" is semantically weak. It sounds passive ("I saw this happen") and says nothing about their active role in consensus. - ---- - -## 2. What XRPL Calls These Nodes - -XRPL uses: - -| XRPL Term | Meaning | -|-----------|---------| -| **Validator** | A server actively participating in consensus — proposes, votes on, and confirms transaction sets | -| **UNL (Unique Node List)** | The trusted set of validators a node relies on | -| **Validation vote** | A cryptographic fingerprint published post-consensus round | -| **Participant** | Generic term for any consensus node | - -XRPL does not split "producer" from "validator" — validators do both. This matches exactly how VIZ validators work. - -The same pattern holds across other major PoS ecosystems: -- **Ethereum PoS** — validators attest and propose blocks -- **Cosmos / Tendermint** — validators propose and pre-vote/pre-commit blocks -- **Polkadot** — validators produce and attest parachain blocks - ---- - ---- - -## 2b. Current Implementation Status (2026-05-17) - -### Done - -| Item | Notes | -|------|-------| -| Protocol operations (types 6, 7, 8, 30, 42) | Renamed; old-name alias table in `operation_util_impl.cpp` | -| Operation field names (`validator` → `validator` in types 7 and 42) | Node accepts both old and new on input | -| Chain properties fields (`inflation_validator_percent`, etc.) | Old names accepted in snapshot import | -| Chain objects (`validator_object`, `validator_schedule_object`) | C++ types renamed; files not renamed yet | -| Schedule fields (`current_shuffled_validators`, `num_scheduled_validators`) | Done | -| API object (`validator_api_object`) | Done | -| API methods (`get_active_validators`, `get_validator_by_account`, etc.) | Done | -| CLI wallet commands (`get_active_validators`, `vote_for_validator`, etc.) | Done | -| Block header fields (`validator`, `validator_signature`) | Done | -| Dynamic global property (`current_validator`) | Done | -| Internal skip flag (`skip_validator_signature`) | Done | -| P2P function signatures (`validator_signature` parameter) | Done | -| Internal plugin methods (`block_validation_loop`, `maybe_validate_block`, etc.) | Done | -| Internal enum (`block_validation_condition`) | Done | -| Snapshot backward compat | Old field names accepted on import; new names on export | -| Operation name alias table | `resolve_operation_name()` in `operation_util_impl.cpp` | - -### Deferred to Future PR - -Nothing remaining. All renames complete. - -### Explicitly Kept (not renamed) - -- `witness_vote_object` — internal vote-tracking object; not exposed by name in protocol -- `witness_penalty_expire_object` — internal object; not exposed in protocol -- `witness_penalty_expire_object::validator` field — internal back-reference, not a block header field -- `witness_vote_index`, `by_account_witness` — chainbase index tags; tied to `witness_vote_object`, not renamed - ---- - -## 3. How Operations Are Serialized (Critical for Compatibility) - -Understanding the wire format determines what is and is not a breaking change. - -### Binary / wire protocol - -Operations in `fc::static_variant` are serialized as `[integer_index, {fields}]`: - -```cpp -// thirdparty/fc/include/fc/static_variant.hpp -void from_variant(const fc::variant &v, fc::static_variant &s) { - auto ar = v.get_array(); - s.set_which(ar[0].as_uint64()); // INTEGER index — not the struct name - s.visit(to_static_variant(ar[1])); -} -``` - -**Renaming C++ struct names has zero impact on the binary wire format** as long as the order in the `static_variant` list in `operations.hpp` is preserved. - -### JSON-RPC name format - -Operation names exposed via JSON-RPC are derived from the C++ type name by `name_from_type()`: - -```cpp -// libraries/protocol/operation_util_impl.cpp -std::string name_from_type(const std::string &type_name) { - auto start = type_name.find_last_of(':') + 1; - auto end = type_name.find_last_of('_'); - return type_name.substr(start, end - start); - // "graphene::protocol::witness_update_operation" → "witness_update" -} -``` - -**Renaming a struct changes its JSON name.** Any JS/PHP/Python client that submits transactions using string operation names (e.g. `["witness_update", {...}]`) will break if the struct is renamed without a compatibility layer. - ---- - -## 4. Backward-Compatibility Fallback (Old Client Support) - -**Yes, a fallback is feasible without a hardfork.** - -The approach: add a static alias table in the JSON deserialization path that maps old string names to new ones before the type lookup. Clients sending `"witness_update"` would be transparently remapped to `"validator_update"`. - -### Implementation location - -The alias mapping belongs in the operation variant `from_variant` path, in: -- `libraries/protocol/operation_util_impl.cpp` — `name_from_type()` or a new `resolve_operation_name()` wrapper -- Or in the JSON-RPC layer that dispatches incoming transaction broadcasts - -### Alias table (old → new) - -| Old JSON name | New JSON name | -|--------------|---------------| -| `witness_update` | `validator_update` | -| `account_witness_vote` | `account_validator_vote` | -| `account_witness_proxy` | `account_validator_proxy` | -| `shutdown_witness` | `shutdown_validator` | -| `witness_reward` | `validator_reward` | - -### Behavior - -- Nodes running the renamed version accept **both** old and new operation names in incoming JSON. -- Nodes serialize outgoing JSON using **new names only**. -- Binary wire format is unchanged — integer indices are stable. -- No hardfork needed for the fallback layer itself. -- JS/PHP/CLI clients that have not been updated continue to work transparently. -- The fallback can be removed in a future release after all clients are migrated. - ---- - -## 5. Full Rename Tables - -### 5.1 Protocol Operations - -These are the on-chain operations. The C++ struct rename is a code-only change (binary wire index preserved); the JSON name fallback handles old clients. - -| Current struct name | New struct name | JSON old name | JSON new name | Type ID | Virtual? | -|--------------------|-----------------|--------------|---------------|---------|----------| -| `witness_update_operation` | `validator_update_operation` | `witness_update` | `validator_update` | 6 | no | -| `account_witness_vote_operation` | `account_validator_vote_operation` | `account_witness_vote` | `account_validator_vote` | 7 | no | -| `account_witness_proxy_operation` | `account_validator_proxy_operation` | `account_witness_proxy` | `account_validator_proxy` | 8 | no | -| `shutdown_witness_operation` | `shutdown_validator_operation` | `shutdown_witness` | `shutdown_validator` | 50 | yes | -| `witness_reward_operation` | `validator_reward_operation` | `witness_reward` | `validator_reward` | 66 | yes | - -> `chain_properties_update_operation` and `versioned_chain_properties_update_operation` — these are submitted by validators but describe chain property voting, not the validator role itself. **Keep names as-is.** - -### 5.2 Core Objects and Types - -| Current Name | New Name | File | -|-------------|----------|------| -| `witness_object` | `validator_object` | `libraries/chain/include/graphene/chain/witness_objects.hpp` | -| `witness_schedule_object` | `validator_schedule_object` | `libraries/chain/include/graphene/chain/witness_objects.hpp` | -| `witness_schedule_type` | `validator_schedule_type` | `libraries/chain/include/graphene/chain/witness_objects.hpp` | -| `current_shuffled_witnesses[]` | `current_shuffled_validators[]` | field in `validator_schedule_object` | -| `block_post_validation_object` | `validator_confirmation_object` | `libraries/chain/include/graphene/chain/chain_objects.hpp` | -| `witness_api_object` | `validator_api_object` | `libraries/api/include/graphene/api/witness_api_object.hpp` | - -### 5.3 Internal Enum (`block_production_condition`) - -| Current Name | New Name | File | -|-------------|----------|------| -| namespace `block_production_condition` | `block_validation_condition` | `plugins/validator/include/graphene/plugins/validator/validator.hpp` | -| `block_production_condition_enum` | `block_validation_condition_enum` | same | -| `exception_producing_block` | `exception_validating_block` | same | - -All other enum values (`produced`, `not_synced`, `not_my_turn`, `not_time_yet`, `no_private_key`, `low_participation`, `lag`, `consecutive`, `fork_collision`, `minority_fork`) need no rename. - -### 5.4 Plugin Internal Methods - -| Current Name | New Name | File | -|-------------|----------|------| -| `block_production_loop()` | `block_validation_loop()` | `plugins/validator/validator.cpp` | -| `maybe_produce_block()` | `maybe_validate_block()` | `plugins/validator/validator.cpp` | -| `is_witness_scheduled_soon()` | `is_validator_scheduled_soon()` | `plugins/validator/validator.hpp` | - -### 5.5 Plugins (Directories and CMake Targets) - -| Current Name | New Name | -|-------------|----------| -| `witness_plugin` | `validator_plugin` | -| `plugins/validator/` | `plugins/validator/` | -| `witness_api_plugin` | `validator_api_plugin` | -| `plugins/witness_api/` | `plugins/validator_api/` | -| `witness_guard_plugin` | `validator_guard_plugin` | -| `plugins/witness_guard/` | `plugins/validator_guard/` | - -### 5.6 validator API Endpoints (JSON-RPC) - -| Current Name | New Name | -|-------------|----------| -| `get_active_witnesses()` | `get_active_validators()` | -| `get_witness_schedule()` | `get_validator_schedule()` | -| `get_witnesses()` | `get_validators()` | -| `get_witness_by_account()` | `get_validator_by_account()` | -| `get_witnesses_by_vote()` | `get_validators_by_vote()` | -| `get_witnesses_by_counted_vote()` | `get_validators_by_counted_vote()` | -| `get_witness_count()` | `get_validator_count()` | -| `lookup_witness_accounts()` | `lookup_validator_accounts()` | - -> API endpoint fallback: keep old method names as deprecated aliases that forward to new implementations for one release cycle. - -### 5.7 CLI Wallet Commands - -| Current Command | New Command | Operation Used | -|----------------|-------------|----------------| -| `list_witnesses()` | `list_validators()` | — (read) | -| `get_witness()` | `get_validator()` | — (read) | -| `get_active_witnesses()` | `get_active_validators()` | — (read) | -| `update_witness()` | `update_validator()` | `validator_update_operation` | -| `vote_for_witness()` | `vote_for_validator()` | `account_validator_vote_operation` | -| `set_voting_proxy()` | `set_voting_proxy()` | `account_validator_proxy_operation` — command name stays | - -File: `libraries/wallet/wallet.cpp` and `libraries/wallet/include/graphene/wallet/wallet.hpp` - -### 5.8 Configuration Keys - -| Current Key | New Key | File | -|------------|---------|------| -| `plugin = validator` | `plugin = validator` | `config_witness.ini` | -| `plugin = witness_guard` | `plugin = validator_guard` | `config_witness.ini` | -| `plugin = witness_api` | `plugin = validator_api` | `config_witness.ini` | -| `--validator = "name"` | `--validator = "name"` | `config_witness.ini` | -| `validator-guard-enabled` | `validator-guard-enabled` | `config_witness.ini` | -| `validator-guard-disable` | `validator-guard-disable` | `config_witness.ini` | -| `validator-guard-interval` | `validator-guard-interval` | `config_witness.ini` | -| `validator-guard-validator` | `validator-guard-validator` | `config_witness.ini` | - -Config keys fallback: on startup, if an old key is detected emit a warning — `"Config key 'validator' is deprecated, use 'validator'"` — and continue reading the value. - ---- - -## 6. External Client Libraries - -JS and PHP libraries are external repositories not in this codebase. They reference: -- Operation names as strings: `"witness_update"`, `"account_witness_vote"`, `"account_witness_proxy"` -- API method names: `get_active_witnesses()`, `get_witness_by_account()`, etc. - -### Impact without fallback - -| Client action | Breaks without fallback? | -|--------------|--------------------------| -| Submit `witness_update` transaction by string name | Yes | -| Submit transaction by integer type ID (6, 7, 8) | No — wire format unchanged | -| Call `get_active_witnesses()` API | Yes | -| Read operation from block history | No — history uses integer IDs | - -### Impact with fallback (Section 4) - -| Client action | Breaks with fallback? | -|--------------|----------------------| -| Submit `witness_update` by string name | No — alias maps to new name | -| Call `get_active_witnesses()` | No — old endpoint aliased | -| Receive response containing `validator_update` instead of `witness_update` | Yes — clients parsing response type names will see the new name | - -### Required changes in JS/PHP libs - -Even with server-side fallback, clients will receive **responses** with new names. The minimum update per library: - -| What to update | Detail | -|---------------|--------| -| Operation name constants | `"witness_update"` → `"validator_update"` etc. | -| API method names in client code | `getActiveWitnesses()` → `getActiveValidators()` etc. | -| Response field parsing | Any code checking `op[0] === "witness_update"` | -| Type constants / enums | Any named constants for operation types | - ---- - -## 7. Terms to Keep Unchanged - -| Identifier | Why it stays | -|------------|-------------| -| `block_signing_key` / `signing_key` | Accurately describes the cryptographic key used to sign blocks and post-validations | -| `delegate_vesting_shares_operation` | "Delegate" is already taken in VIZ for vesting share delegation — **do not use "delegate" as the consensus-role name** | -| `chain_properties_update_operation` | Describes chain governance, not the validator role | -| `versioned_chain_properties_update_operation` | Same | -| Enum values `top`, `support`, `none` | Scheduling tier names, not role names | - ---- - -## 8. Implementation Phases - -### Phase 1 — Internal rename (zero breaking changes) ✅ Done - -1. ✅ Rename `block_production_condition` namespace, enum, and `exception_producing_block` in `validator.hpp` + `validator.cpp`. -2. ✅ Rename internal method names: `block_production_loop`, `maybe_produce_block`, `is_witness_scheduled_soon`. -3. ⏳ Rename `block_post_validation_object` → `validator_confirmation_object` — deferred with physical file renames. -4. ✅ Rename `current_shuffled_witnesses[]` field. -5. ✅ Build verified. -6. ✅ `.qoder/` documentation updated. - -### Phase 2 — API and config rename (with fallbacks) ✅ Done - -1. ✅ Add operation name alias table in `operation_util_impl.cpp` — old JSON names → new names. -2. ✅ Rename `witness_update_operation` → `validator_update_operation` and the other four operations (Section 5.1). Binary type IDs preserved. -3. ✅ Add deprecated endpoint aliases in `validator_api` plugin for all `get_witness_*` methods. -4. ✅ Rename CLI wallet commands; keep old names as deprecated aliases. -5. ✅ Config keys updated (`plugin = validator`, `plugin = validator_api`, `plugin = validator_guard`). `--validator` kept as deprecated alias for `--validator` in config.ini backward compat. -6. ✅ Plugin directories renamed: `plugins/validator/`, `plugins/validator_api/`, `plugins/validator_guard/`. CMake targets updated. -7. ✅ Rename `witness_object`, `witness_schedule_object`, `witness_api_object` (C++ types and files). -8. ✅ `config_witness.ini` and all other `config*.ini` updated to new plugin names. -9. ✅ Rename block header fields: `validator`, `validator_signature`. -10. ✅ Rename dynamic global property field: `current_validator`. -11. ✅ Rename skip flag: `skip_validator_signature`. -12. ✅ Plugin namespaces: `validator_plugin`, `validator_api`, `validator_guard`. `plugin_name` strings updated. - -### Phase 2 — Additional API-visible fields ✅ Done - -1. ✅ Rename `account_object` fields: `witnesses_voted_for` → `validators_voted_for`, `witnesses_vote_weight` → `validators_vote_weight`; methods `witness_vote_weight()` → `validator_vote_weight()`, `witness_vote_fair_weight()` → `validator_vote_fair_weight()`, `witness_vote_fair_weight_prehf5()` → `validator_vote_fair_weight_prehf5()`. -2. ✅ Rename `account_api_object` fields: `witnesses_voted_for`, `witnesses_vote_weight`, `witness_votes` → `validators_voted_for`, `validators_vote_weight`, `validator_votes`. -3. ✅ Rename `config.hpp`/`config_testnet.hpp` constants: `CHAIN_MAX_WITNESSES` → `CHAIN_MAX_VALIDATORS`, `CHAIN_BLOCK_WITNESS_REPEAT` → `CHAIN_BLOCK_VALIDATOR_REPEAT`, `CHAIN_EMERGENCY_WITNESS_ACCOUNT` → `CHAIN_EMERGENCY_VALIDATOR_ACCOUNT`, `CHAIN_HARDFORK_REQUIRED_WITNESSES` → `CHAIN_HARDFORK_REQUIRED_VALIDATORS`, `CHAIN_MAX_ACCOUNT_WITNESS_VOTES` → `CHAIN_MAX_ACCOUNT_VALIDATOR_VOTES`, `CHAIN_MAX_WITNESS_URL_LENGTH` → `CHAIN_MAX_VALIDATOR_URL_LENGTH`, `CONSENSUS_WITNESS_MISS_PENALTY_*` → `CONSENSUS_VALIDATOR_MISS_PENALTY_*`, `CONSENSUS_WITNESS_DECLARATION_FEE` → `CONSENSUS_VALIDATOR_DECLARATION_FEE` etc. -4. ✅ `get_config.cpp` API key strings updated to new names. -5. ✅ Snapshot `import_accounts` — backward compat for old `witnesses_voted_for` key. - -### Phase 3 — External library updates - -1. Update JS client library: operation name constants, API method names, response parsing, block header field names, `get_config` key names, `account_api_object` field names. -2. Update PHP client library: same scope. -3. After both libraries are released, schedule removal of the server-side fallback aliases. - ---- - -## 9. Files Affected (Source Code) - -| File | Status | Scope | -|------|--------|-------| -| `plugins/validator/include/graphene/plugins/validator/validator.hpp` | ✅ Done | Enum namespace, method declarations | -| `plugins/validator/validator.cpp` | ✅ Done | All enum references, method definitions, block field accesses | -| `plugins/validator_guard/validator_guard.cpp` | ✅ Done | Object types, block field accesses | -| `plugins/validator_guard/include/.../validator_guard.hpp` | ✅ Done | Class names, config declarations | -| `plugins/validator_api/plugin.cpp` | ✅ Done | API method names + deprecated aliases | -| `plugins/validator_api/include/.../plugin.hpp` | ✅ Done | API method declarations | -| `plugins/p2p/p2p_plugin.cpp` | ✅ Done | `validator_signature` parameter | -| `plugins/p2p/include/.../p2p_plugin.hpp` | ✅ Done | `validator_signature` parameter | -| `plugins/chain/plugin.cpp` | ✅ Done | Block field access | -| `plugins/snapshot/plugin.cpp` | ✅ Done | Object types, field accesses, backward compat import | -| `plugins/database_api/api.cpp` | ✅ Done | Object type references | -| `plugins/account_history/plugin.cpp` | ✅ Done | Operation visitor method names | -| `libraries/chain/include/graphene/chain/validator_objects.hpp` | ✅ Done | Object type names, field names, CHAIN_MAX_VALIDATORS array size | -| `libraries/chain/include/graphene/chain/global_property_object.hpp` | ✅ Done | `current_validator` field + FC_REFLECT | -| `libraries/chain/include/graphene/chain/chain_objects.hpp` | ✅ Done | `validator_confirmation_object`, `validator_confirmation_index` | -| `libraries/chain/database.cpp` | ✅ Done | All object and block field references | -| `libraries/chain/database.hpp` | ✅ Done | `skip_validator_signature` flag | -| `libraries/protocol/include/graphene/protocol/block_header.hpp` | ✅ Done | `validator`, `validator_signature` fields | -| `libraries/protocol/block.cpp` | ✅ Done | `validator_signature` references | -| `libraries/protocol/include/graphene/protocol/chain_operations.hpp` | ✅ Done | Operation struct names, field names | -| `libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp` | ✅ Done | Virtual operation struct names | -| `libraries/protocol/include/graphene/protocol/operations.hpp` | ✅ Done | static_variant list — struct names only, order unchanged | -| `libraries/protocol/operation_util_impl.cpp` | ✅ Done | Alias table for old JSON names | -| `libraries/api/include/graphene/api/witness_api_object.hpp` | ✅ Done | `validator_api_object` type | -| `libraries/api/witness_api_object.cpp` | ✅ Done | Constructor, field assignments | -| `libraries/api/include/graphene/api/chain_api_properties.hpp` | ✅ Done | Chain properties field names | -| `libraries/api/chain_api_properties.cpp` | ✅ Done | Field assignments | -| `libraries/network/dlt_p2p_node.cpp` | ✅ Done | Block field accesses, `validator_signature` parameter | -| `libraries/network/include/graphene/network/dlt_p2p_node.hpp` | ✅ Done | `validator_signature` parameter | -| `plugins/validator/CMakeLists.txt` | ✅ Done | Target `graphene_validator`, new source/header paths | -| `plugins/validator_api/CMakeLists.txt` | ✅ Done | Target `graphene_validator_api` | -| `plugins/validator_guard/CMakeLists.txt` | ✅ Done | Target `graphene_validator_guard` | -| `plugins/p2p/CMakeLists.txt` | ✅ Done | Include path `../validator/include` | -| `plugins/snapshot/CMakeLists.txt` | ✅ Done | Link `graphene_validator` | -| `programs/vizd/CMakeLists.txt` | ✅ Done | Links `graphene::validator`, `graphene::validator_api`, `graphene::validator_guard` | -| `programs/cli_wallet/CMakeLists.txt` | ✅ Done | Link `graphene::validator_api` | -| `libraries/wallet/wallet.cpp` | ✅ Done | CLI wallet command implementations | -| `libraries/wallet/include/graphene/wallet/wallet.hpp` | ✅ Done | CLI wallet method declarations | -| `libraries/wallet/include/graphene/wallet/remote_node_api.hpp` | ✅ Done | Remote API method names | -| `libraries/chain/include/graphene/chain/account_object.hpp` | ✅ Done | `witnesses_voted_for`→`validators_voted_for`, `witnesses_vote_weight`→`validators_vote_weight`, methods | -| `libraries/api/include/graphene/api/account_api_object.hpp` | ✅ Done | Same fields + `witness_votes`→`validator_votes` | -| `libraries/api/account_api_object.cpp` | ✅ Done | Field assignments | -| `libraries/protocol/include/graphene/protocol/config.hpp` | ✅ Done | All `validator` constants → `VALIDATOR` | -| `libraries/protocol/include/graphene/protocol/config_testnet.hpp` | ✅ Done | Same | -| `libraries/protocol/get_config.cpp` | ✅ Done | API string keys updated | -| `share/vizd/config/config_witness.ini` | ✅ Done | Plugin names → `validator`, `validator_api`, `validator_guard` | -| `share/vizd/config/config.ini` | ✅ Done | Plugin names | -| `share/vizd/config/config_debug.ini` | ✅ Done | Plugin names | -| `share/vizd/config/config_debug_mongo.ini` | ✅ Done | Plugin names | -| `share/vizd/config/config_mongo.ini` | ✅ Done | Plugin names | -| `share/vizd/config/config_stock_exchange.ini` | ✅ Done | Plugin names | -| `share/vizd/config/config_testnet.ini` | ✅ Done | Plugin names | - ---- - -## 10. Summary - -`validator` → `validator` is the right rename. It: - -- Matches XRPL, Ethereum PoS, Cosmos, and Polkadot terminology -- Accurately describes both the block production and post-validation duties -- Removes the passive/observational connotation of "validator" -- Makes `block_post_validation_object` → `validator_confirmation_object` semantically clear - -**The rename is safe for unupdated JS/PHP clients** — the binary wire format uses integer type IDs, not string names, so old clients submitting transactions continue to work. A server-side name alias table handles the JSON string name fallback at zero cost. The only visible breakage for old clients is in response parsing, where they may encounter new names (`validator_update` instead of `witness_update`) in block history reads. diff --git a/.qoder/plan/dlt-snapshot-plugin.md b/.qoder/plan/dlt-snapshot-plugin.md deleted file mode 100644 index cc69c8fbd8..0000000000 --- a/.qoder/plan/dlt-snapshot-plugin.md +++ /dev/null @@ -1,862 +0,0 @@ -# DLT Snapshot Plugin — Research Document - -## 1. Overview - -This document defines the design for a **trust state / snapshot plugin** that enables the VIZ blockchain node to operate in **DLT mode** — starting instantly from a serialized state snapshot without replaying the entire block history. - -### Motivation - -Currently, starting a VIZ node requires either: -- Full sync from genesis (replay all blocks) -- Reindex from block_log (still replay all blocks) - -Both approaches are slow and resource-intensive. For many use cases (API nodes, witness nodes, monitoring), the full block history is unnecessary. A snapshot of the consensus state at a specific block allows: - -- Near-instant node startup -- Minimal disk usage (no block_log required for historical blocks) -- Fast recovery and deployment -- Ability to skip synchronization of ancient blocks entirely - -### Key Principle - -The snapshot must contain **all state required to continue block processing and validation** from the snapshot block forward. Any object that participates in consensus evaluation, witness scheduling, balance tracking, or authority verification must be included. Objects that exist only for API queries or historical lookup can be excluded. - ---- - -## 2. Object Categories - -### Legend - -| Category | Description | -|----------|-------------| -| **CRITICAL** | Directly required for consensus validation and block processing. Missing = node cannot validate blocks. | -| **IMPORTANT** | Required for correct state transitions during block processing. Missing = incorrect behavior on specific operations. | -| **OPTIONAL** | Useful for completeness but not strictly required for consensus. Can be reconstructed or skipped. | -| **EXCLUDED** | Not needed for DLT mode. Plugin-level, API-only, or purely historical data. | - ---- - -## 3. CRITICAL Objects (Must Be in Snapshot) - -These objects are directly involved in block validation, consensus, and state calculation. Without them, the node cannot process new blocks. - -### 3.1 `dynamic_global_property_object` - -- **File**: `libraries/chain/include/graphene/chain/global_property_object.hpp` -- **Index**: `dynamic_global_property_index` (by_id) -- **Why critical**: The single most important object. Tracks head block number/id, current supply, total vesting, reward fund, participation rate, last irreversible block, reserve ratio, and inflation parameters. All block processing begins by reading this object. -- **Fields to snapshot**: ALL fields - - `id`, `head_block_number`, `head_block_id`, `genesis_time`, `time`, `current_witness` - - `committee_fund`, `committee_requests`, `current_supply`, `total_vesting_fund`, `total_vesting_shares` - - `total_reward_fund`, `total_reward_shares` - - `average_block_size`, `maximum_block_size`, `current_aslot` - - `recent_slots_filled`, `participation_count` - - `last_irreversible_block_num`, `last_irreversible_block_id` - - `last_irreversible_block_ref_num`, `last_irreversible_block_ref_prefix` - - `max_virtual_bandwidth`, `current_reserve_ratio` - - `vote_regeneration_per_day`, `bandwidth_reserve_candidates` - - `inflation_calc_block_num`, `inflation_witness_percent`, `inflation_ratio` -- **Instance count**: Exactly 1 - -### 3.2 `witness_schedule_object` - -- **File**: `libraries/chain/include/graphene/chain/witness_objects.hpp` -- **Index**: `witness_schedule_index` (by_id) -- **Why critical**: Contains the current witness rotation schedule, virtual time for DPOS scheduling, median chain properties, and majority version. Required to determine which witness produces the next block. -- **Fields to snapshot**: ALL fields - - `id`, `current_virtual_time`, `next_shuffle_block_num` - - `current_shuffled_witnesses`, `num_scheduled_witnesses` - - `median_props`, `majority_version` -- **Instance count**: Exactly 1 - -### 3.3 `hardfork_property_object` - -- **File**: `libraries/chain/hardfork.d/0-preamble.hf` -- **Index**: `hardfork_property_index` (by_id) -- **Why critical**: Tracks which hardforks have been applied and the current/next hardfork versions. Determines which code paths are active during block processing. -- **Fields to snapshot**: ALL fields - - `id`, `processed_hardforks`, `last_hardfork` - - `current_hardfork_version`, `next_hardfork`, `next_hardfork_time` -- **Instance count**: Exactly 1 - -### 3.4 `account_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `account_index` (by_id, by_name, by_next_vesting_withdrawal, by_account_on_sale, by_account_on_auction, by_account_on_sale_start_time, by_subaccount_on_sale) -- **Why critical**: Contains all balance information (liquid, vesting, delegated), voting power (energy), witness voting weight (proxied_vsf_votes), bandwidth tracking, and account sale/auction state. Required for every operation involving transfers, voting, vesting, bandwidth. -- **Fields to snapshot**: ALL fields - - `id`, `name`, `memo_key`, `proxy`, `referrer` - - `last_account_update`, `created`, `recovery_account`, `last_account_recovery` - - `subcontent_count`, `vote_count`, `content_count`, `awarded_rshares` - - `custom_sequence`, `custom_sequence_block_num` - - `energy`, `last_vote_time` - - `balance`, `vesting_shares`, `delegated_vesting_shares`, `received_vesting_shares` - - `vesting_withdraw_rate`, `next_vesting_withdrawal`, `withdrawn`, `to_withdraw`, `withdraw_routes` - - `curation_rewards`, `posting_rewards`, `receiver_awards`, `benefactor_awards` - - `proxied_vsf_votes`, `witnesses_voted_for`, `witnesses_vote_weight` - - `last_root_post`, `last_post` - - `average_bandwidth`, `lifetime_bandwidth`, `last_bandwidth_update` - - `valid` - - `account_seller`, `account_offer_price`, `account_on_sale`, `account_on_sale_start_time` - - `reserved_balance` - - `target_buyer`, `account_on_auction`, `current_bid`, `current_bidder`, `current_bidder_key`, `last_bid` - - `subaccount_seller`, `subaccount_offer_price`, `subaccount_on_sale` -- **Instance count**: Equal to total accounts on chain - -### 3.5 `account_authority_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `account_authority_index` (by_id, by_account, by_last_master_update) -- **Why critical**: Contains master/active/regular authorities for every account. Required for transaction signature verification and authority checks. -- **Fields to snapshot**: ALL fields - - `id`, `account`, `master`, `active`, `regular`, `last_master_update` -- **Instance count**: Equal to total accounts on chain - -### 3.6 `witness_object` - -- **File**: `libraries/chain/include/graphene/chain/witness_objects.hpp` -- **Index**: `witness_index` (by_id, by_name, by_vote_name, by_counted_vote_name, by_schedule_time, by_work) -- **Why critical**: Contains witness signing keys, vote counts, virtual scheduling state, and properties. Required for block validation (signing key lookup) and witness scheduling. -- **Fields to snapshot**: ALL fields - - `id`, `owner`, `created`, `url`, `total_missed` - - `last_aslot`, `last_confirmed_block_num`, `current_run`, `last_supported_block_num` - - `signing_key`, `props` - - `votes`, `penalty_percent`, `counted_votes`, `schedule` - - `virtual_last_update`, `virtual_position`, `virtual_scheduled_time` - - `last_work`, `running_version`, `hardfork_version_vote`, `hardfork_time_vote` -- **Instance count**: Equal to registered witnesses - -### 3.7 `witness_vote_object` - -- **File**: `libraries/chain/include/graphene/chain/witness_objects.hpp` -- **Index**: `witness_vote_index` (by_id, by_account_witness, by_witness_account) -- **Why critical**: Links accounts to their witness votes. Required when adjusting witness vote weights on account vesting changes. -- **Fields to snapshot**: ALL fields - - `id`, `witness`, `account` -- **Instance count**: Equal to total witness votes - -### 3.8 `block_summary_object` - -- **File**: `libraries/chain/include/graphene/chain/block_summary_object.hpp` -- **Index**: `block_summary_index` (by_id) -- **Why critical**: Used for TaPOS (Transactions as Proof of Stake) validation. Transactions reference past blocks; without these, TaPOS checks fail. -- **Fields to snapshot**: ALL fields - - `id`, `block_id` -- **Instance count**: 65536 (0x10000, fixed circular buffer) -- **Note**: Only summaries for recent blocks matter. The circular buffer means older entries are overwritten. - -### 3.9 `content_object` - -- **File**: `libraries/chain/include/graphene/chain/content_object.hpp` -- **Index**: `content_index` (by_id, by_cashout_time, by_permlink, by_root, by_parent; plus by_last_update, by_author_last_update in non-low-mem) -- **Why critical**: Content objects track rshares, cashout times, and payout calculations. Active content with pending payouts directly affects inflation and reward distribution. The `by_permlink` and `by_parent` indexes are used by consensus evaluators. -- **Fields to snapshot**: ALL fields - - `id`, `parent_author`, `parent_permlink`, `author`, `permlink` - - `last_update`, `created`, `active`, `last_payout` - - `depth`, `children`, `children_rshares` - - `net_rshares`, `abs_rshares`, `vote_rshares` - - `cashout_time`, `total_vote_weight` - - `curation_percent`, `consensus_curation_percent` - - `payout_value`, `shares_payout_value`, `curator_payout_value`, `beneficiary_payout_value` - - `author_rewards`, `net_votes`, `root_content`, `beneficiaries` - -### 3.10 `content_vote_object` - -- **File**: `libraries/chain/include/graphene/chain/content_object.hpp` -- **Index**: `content_vote_index` (by_id, by_content_voter, by_voter_content, by_voter_last_update, by_content_weight_voter) -- **Why critical**: Tracks individual votes on content. Required for curation reward calculations and vote-changing logic. -- **Fields to snapshot**: ALL fields - - `id`, `voter`, `content`, `weight`, `rshares`, `vote_percent`, `last_update`, `num_changes` - -### 3.11 `block_post_validation_object` - -- **File**: `libraries/chain/include/graphene/chain/chain_objects.hpp` -- **Index**: `block_post_validation_index` (by_id) -- **Why critical**: Tracks block post-validation state used in consensus for witness participation verification. -- **Fields to snapshot**: ALL fields - - `id`, `block_num`, `block_id`, `current_shuffled_witnesses`, `current_shuffled_witnesses_validations` - ---- - -## 4. IMPORTANT Objects (Required for Correct State Transitions) - -These objects contain state that will be acted upon during normal block processing. If missing, specific operations will fail or produce incorrect results. - -### 4.1 `transaction_object` - -- **File**: `libraries/chain/include/graphene/chain/transaction_object.hpp` -- **Index**: `transaction_index` (by_id, by_trx_id, by_expiration) -- **Why important**: Prevents duplicate transaction execution. Without it, replayed transactions could be applied twice. -- **Fields to snapshot**: ALL fields - - `id`, `packed_trx`, `trx_id`, `expiration` -- **Note**: Only transactions not yet expired need to be included. Expired ones are cleaned up each block. At snapshot time, only include transactions with `expiration > snapshot_block_time`. - -### 4.2 `vesting_delegation_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `vesting_delegation_index` (by_id, by_delegation, by_received) -- **Why important**: Tracks active vesting share delegations. Required for correct `effective_vesting_shares` calculation and delegation operations. -- **Fields to snapshot**: ALL fields - - `id`, `delegator`, `delegatee`, `vesting_shares`, `min_delegation_time` - -### 4.3 `vesting_delegation_expiration_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `vesting_delegation_expiration_index` (by_id, by_expiration, by_account_expiration) -- **Why important**: Tracks pending delegation expirations. These are processed in `clear_expired_delegations()` during block processing. -- **Fields to snapshot**: ALL fields - - `id`, `delegator`, `vesting_shares`, `expiration` - -### 4.4 `fix_vesting_delegation_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `fix_vesting_delegation_index` (by_id) -- **Why important**: Permanent delegation fix records. Required for correct vesting share accounting. -- **Fields to snapshot**: ALL fields - - `id`, `delegator`, `delegatee`, `vesting_shares` - -### 4.5 `withdraw_vesting_route_object` - -- **File**: `libraries/chain/include/graphene/chain/chain_objects.hpp` -- **Index**: `withdraw_vesting_route_index` (by_id, by_withdraw_route, by_destination) -- **Why important**: Defines routing for vesting withdrawals. Required for `process_vesting_withdrawals()`. -- **Fields to snapshot**: ALL fields - - `id`, `from_account`, `to_account`, `percent`, `auto_vest` - -### 4.6 `escrow_object` - -- **File**: `libraries/chain/include/graphene/chain/chain_objects.hpp` -- **Index**: `escrow_index` (by_id, by_from_id, by_to, by_agent, by_ratification_deadline) -- **Why important**: Active escrow contracts. Processed during `expire_escrow_ratification()`. -- **Fields to snapshot**: ALL fields - - `id`, `escrow_id`, `from`, `to`, `agent` - - `ratification_deadline`, `escrow_expiration` - - `token_balance`, `pending_fee` - - `to_approved`, `agent_approved`, `disputed` - -### 4.7 `proposal_object` - -- **File**: `libraries/chain/include/graphene/chain/proposal_object.hpp` -- **Index**: `proposal_index` (by_id, by_account, by_expiration) -- **Why important**: Active proposals. Processed during `clear_expired_proposals()`. -- **Fields to snapshot**: ALL fields - - `id`, `author`, `title`, `memo` - - `expiration_time`, `review_period_time` - - `proposed_operations` - - `required_active_approvals`, `available_active_approvals` - - `required_master_approvals`, `available_master_approvals` - - `required_regular_approvals`, `available_regular_approvals` - - `available_key_approvals` - -### 4.8 `required_approval_object` - -- **File**: `libraries/chain/include/graphene/chain/proposal_object.hpp` -- **Index**: `required_approval_index` (by_id, by_account) -- **Why important**: Links accounts to proposals requiring their approval. Required for proposal authorization checking. -- **Fields to snapshot**: ALL fields - - `id`, `account`, `proposal` - -### 4.9 `committee_request_object` - -- **File**: `libraries/chain/include/graphene/chain/committee_objects.hpp` -- **Index**: `committee_request_index` (by_id, by_request_id, by_status, by_creator, by_worker, by_creator_url) -- **Why important**: Active committee requests. Processed during `committee_processing()`. -- **Fields to snapshot**: ALL fields - - `id`, `request_id`, `url`, `creator`, `worker` - - `required_amount_min`, `required_amount_max` - - `start_time`, `duration`, `end_time` - - `status`, `votes_count`, `conclusion_time` - - `conclusion_payout_amount`, `payout_amount`, `remain_payout_amount` - - `last_payout_time`, `payout_time` - -### 4.10 `committee_vote_object` - -- **File**: `libraries/chain/include/graphene/chain/committee_objects.hpp` -- **Index**: `committee_vote_index` (by_id, by_voter, by_request_id) -- **Why important**: Committee votes on active requests. -- **Fields to snapshot**: ALL fields - - `id`, `request_id`, `voter`, `vote_percent`, `last_update` - -### 4.11 `invite_object` - -- **File**: `libraries/chain/include/graphene/chain/invite_objects.hpp` -- **Index**: `invite_index` (by_id, by_invite_key, by_status, by_creator, by_receiver) -- **Why important**: Active invites with balance. Processed during `clear_used_invites()`. -- **Fields to snapshot**: ALL fields - - `id`, `creator`, `receiver`, `invite_key`, `invite_secret` - - `balance`, `claimed_balance` - - `create_time`, `claim_time`, `status` - -### 4.12 `award_shares_expire_object` - -- **File**: `libraries/chain/include/graphene/chain/chain_objects.hpp` -- **Index**: `award_shares_expire_index` (by_id, by_expiration) -- **Why important**: Pending award share expirations. Processed during `expire_award_shares_processing()`. -- **Fields to snapshot**: ALL fields - - `id`, `expires`, `rshares` - -### 4.13 `paid_subscription_object` - -- **File**: `libraries/chain/include/graphene/chain/paid_subscription_objects.hpp` -- **Index**: `paid_subscription_index` (by_id, by_creator) -- **Why important**: Active paid subscription offers. Required for `paid_subscribe_processing()`. -- **Fields to snapshot**: ALL fields - - `id`, `creator`, `url`, `levels`, `amount`, `period`, `update_time` - -### 4.14 `paid_subscribe_object` - -- **File**: `libraries/chain/include/graphene/chain/paid_subscription_objects.hpp` -- **Index**: `paid_subscribe_index` (by_id, by_subscriber, by_creator, by_next_time, by_subscribe) -- **Why important**: Active subscriptions with pending payments. Required for `paid_subscribe_processing()`. -- **Fields to snapshot**: ALL fields - - `id`, `subscriber`, `creator`, `level`, `amount`, `period` - - `start_time`, `next_time`, `end_time`, `active`, `auto_renewal` - -### 4.15 `witness_penalty_expire_object` - -- **File**: `libraries/chain/include/graphene/chain/witness_objects.hpp` -- **Index**: `witness_penalty_expire_index` (by_id, by_account, by_expiration) -- **Why important**: Tracks witness penalties that will expire. Affects witness schedule calculations. -- **Fields to snapshot**: ALL fields - - `id`, `witness`, `penalty_percent`, `expires` - ---- - -## 5. OPTIONAL Objects (Can Be Deferred or Partially Included) - -These objects are useful for full functionality but are not strictly required for consensus. - -### 5.1 `account_metadata_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `account_metadata_index` (by_id, by_account) -- **Why optional**: Stores JSON metadata for accounts. Only created in non-low-mem builds (`#ifndef IS_LOW_MEM`). Not used in consensus. -- **Recommendation**: Include for API completeness; exclude in minimal DLT mode. - -### 5.2 `content_type_object` - -- **File**: `libraries/chain/include/graphene/chain/content_object.hpp` -- **Index**: `content_type_index` (by_id, by_content) -- **Why optional**: Stores content body/title/json_metadata. Only created in non-low-mem builds. Not used in consensus. -- **Recommendation**: Include for API completeness; exclude in minimal DLT mode. - -### 5.3 `master_authority_history_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `master_authority_history_index` (by_id, by_account) -- **Why optional**: Tracks historical master authority changes for account recovery. Only needed if recovery of old authority is requested. -- **Recommendation**: Include — it is referenced during account recovery processing. - -### 5.4 `account_recovery_request_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `account_recovery_request_index` (by_id, by_account, by_expiration) -- **Why optional**: Tracks pending recovery requests. Processed during `account_recovery_processing()`. If excluded, pending recoveries would be lost. -- **Recommendation**: Include — active recovery requests should be preserved. - -### 5.5 `change_recovery_account_request_object` - -- **File**: `libraries/chain/include/graphene/chain/account_object.hpp` -- **Index**: `change_recovery_account_request_index` (by_id, by_account, by_effective_date) -- **Why optional**: Tracks pending recovery account changes. Processed when effective date is reached. -- **Recommendation**: Include — pending changes should be preserved. - -### 5.6 `custom_protocol_object` (Plugin-Conditional) - -- **File**: `plugins/custom_protocol_api/include/graphene/plugins/custom_protocol_api/custom_protocol_api_object.hpp` -- **Index**: `custom_protocol_index` (by_id, by_account_custom_sequence_block_num) -- **Why optional**: Stores per-account custom sequence counters (`custom_sequence`, `custom_sequence_block_num`). Not used in consensus directly, but **requires full replay to reconstruct** if lost. Without it, applications relying on custom protocol sequencing will see incorrect sequence numbers. -- **Conditional inclusion logic**: - - **Export**: Include in snapshot only if the `custom_protocol_api` plugin is enabled on the exporting node. If the plugin is disabled, its index does not exist in chainbase and there is nothing to export. - - **Import**: Load from snapshot only if the `custom_protocol_api` plugin is enabled on the importing node. If the plugin is disabled, skip this section — the data will not be loaded and the plugin's index will remain empty (applications using the plugin will need a full replay to populate it). -- **Fields to snapshot**: ALL fields - - `id`, `account`, `custom_protocol_id`, `custom_sequence`, `custom_sequence_block_num` - ---- - -## 6. EXCLUDED Objects and Indexes - -### 6.1 `block_stats_object` - -- **Status**: Declared in `object_type` enum but no concrete class definition found in codebase. Likely a placeholder. -- **Decision**: Exclude from snapshot. - -### 6.2 Plugin Indexes (All Excluded from Consensus Snapshot) - -These indexes are maintained by plugins for API purposes only. They do not affect consensus and can be rebuilt after snapshot load. - -| Plugin | Indexes | Reason to Exclude | -|--------|---------|-------------------| -| follow | `follow_index`, `feed_index`, `blog_index`, `follow_count_index`, `blog_author_stats_index` | Social graph data, not consensus | -| account_history | `account_history_index`, `account_range_index` | Historical operation index, not consensus | -| account_by_key | `key_lookup_index` | Key-to-account lookup, can be rebuilt | -| tags | `tag_index`, `tag_stats_index`, `author_tag_stats_index`, `language_index` | Content tagging, not consensus | -| private_message | `message_index` | Messaging data, not consensus | -| operation_history | `operation_index` | Historical operation records, not consensus | - -**Note**: `custom_protocol_api` has been moved to OPTIONAL (section 5.6) because its data requires full replay to reconstruct. It is included conditionally based on plugin enablement on the exporting and importing nodes. - -### 6.3 Non-Persistent Runtime State (Excluded) - -| State | Location | Reason | -|-------|----------|--------| -| `_pending_tx` | `database.hpp:428` | In-flight transactions, will be resubmitted | -| `_popped_tx` | `database.hpp:427` | Temporary cache, not needed | -| `_current_trx_id` | `database.hpp:535` | Transient, reset on startup | -| `_current_block_num`, `_current_trx_in_block`, `_current_op_in_trx`, `_current_virtual_op` | `database.hpp:536-539` | Transient block processing state | -| `_checkpoints` | `database.hpp:541` | Node-specific configuration, not state | -| `_custom_operation_interpreters` | `database.hpp:556` | Plugin-registered, rebuilt on startup | - ---- - -## 7. Non-Object State Required in Snapshot - -Beyond chainbase objects, additional state must be captured for the node to resume correctly. - -### 7.1 Snapshot Header (Metadata) - -``` -{ - "version": 1, // Snapshot format version - "chain_id": "...", // Chain identifier for validation - "snapshot_block_num": 12345678, // Block number at snapshot time - "snapshot_block_id": "...", // Block hash at snapshot time - "snapshot_block_time": "...", // Timestamp of snapshot block - "last_irreversible_block_num": 12345000, // LIB at snapshot time - "last_irreversible_block_id": "...", // LIB hash - "snapshot_creation_time": "...", // When snapshot was created - "object_counts": { // For validation during load - "account_object": 5000, - "witness_object": 50, - ... - } -} -``` - -### 7.2 Fork Database Seed - -The fork database (`_fork_db`) contains blocks that are not yet irreversible. After loading a snapshot, the fork database should be seeded with the head block: - -``` -{ - "fork_db_head_block": { ... } // The signed_block at snapshot_block_num -} -``` - -This is necessary because `_fork_db.start_block()` is called with the head block during `database::open()`. - -### 7.3 Block Log Position - -The node needs to know where to start syncing from the network: - -``` -{ - "block_log_head_block_num": 12345678, // Last block in block_log (if available) - "block_log_head_block_id": "..." // Its hash -} -``` - -In DLT mode, the block_log may be truncated or absent. The node will sync remaining blocks from P2P network starting from `last_irreversible_block_num + 1`. - -### 7.4 Hardfork State Derivation - -The `_hardfork_times[]` and `_hardfork_versions[]` arrays are populated from code in `init_hardforks()` and `apply_hardfork()`. These are **not** stored in the database — they are compiled into the binary. The snapshot only needs the `hardfork_property_object` which records which hardforks have been applied. - -**Important**: The snapshot must be loaded by a binary whose compiled hardfork history is at least as recent as `hardfork_property_object.last_hardfork`. Otherwise, the node cannot correctly process the chain. - ---- - -## 8. Snapshot Format Specification - -### 8.1 Format Options - -| Format | Pros | Cons | -|--------|------|------| -| **JSON** | Human-readable, debuggable, compatible with existing fc::reflect | Large file size, slow serialization | -| **Binary (fc::raw)** | Compact, fast, already used for chainbase | Not human-readable, version-sensitive | -| **JSON + Binary hybrid** | Header in JSON, data in binary | Complexity | - -### 8.2 Recommended Format: Binary with JSON Header - -``` -[JSON Header] -[separator: \0\0\0\0] -[binary section: fc::raw packed objects by type] -[binary section: fork_db seed block] -[checksum: SHA256 of all preceding data] -``` - -Each object type section: - -``` -[uint32_t: object_type enum value] -[uint32_t: number of objects] -[fc::raw packed object 1] -[fc::raw packed object 2] -... -``` - -### 8.3 File Extension - -`.viz-snapshot` (e.g., `snapshot-12345678.viz-snapshot`) - ---- - -## 9. Snapshot Creation Process - -### 9.1 When to Create a Snapshot - -The snapshot should be created at an **irreversible block** boundary. This ensures: -- No undo state needs to be captured -- The state is final and will not be reverted -- Fork database is clean at this point - -### 9.2 Snapshot Creation Approaches - -There are several approaches to creating a snapshot while maintaining consistency: - -#### 9.2.1 Full Node Pause (Simple, with Downtime) - -``` -1. Stop accepting new blocks from P2P -2. Wait for current block processing to complete -3. Lock all operations (API + block application) -4. Create snapshot -5. Resume operations -``` - -**Pros**: Simple to implement, guaranteed consistency -**Cons**: Node unavailable during snapshot creation (several seconds) - -#### 9.2.2 Read Lock Without API Pause (Recommended) - -Use `with_strong_read_lock` at the irreversible block boundary. This is the recommended approach. - -``` -1. Wait for current block to become irreversible (LIB) - - Irreversible blocks cannot be reorganized - - This guarantees state consistency -2. Call with_strong_read_lock([&]() { ... }) - - API read requests continue to work - - Only new block application is blocked (write) -3. Serialize all objects to file -4. Release read lock automatically when lambda exits -5. Continue P2P sync (buffered blocks are applied in batch) -``` - -**Pros**: -- API remains available for reads -- Minimal downtime — only during serialization -- Consistency guaranteed by read lock + irreversible boundary - -**Cons**: -- New blocks not applied for several seconds -- P2P buffers incoming blocks, then applies them in batch - -**Implementation Example**: - -```cpp -void snapshot_plugin::create_snapshot(const fc::path& output_path) { - auto& db = _chain_db->db(); - - // 1. Get current LIB - uint32_t lib = db.last_non_undoable_block_num(); - auto lib_block = db.fetch_block_by_number(lib); - - // 2. Acquire strong read lock - db.with_strong_read_lock([&]() { - // 3. Write header with LIB info - snapshot_header header; - header.snapshot_block_num = lib; - header.snapshot_block_id = lib_block->id(); - header.last_irreversible_block_num = lib; - header.last_irreversible_block_id = lib_block->id(); - header.chain_id = db.get_chain_id(); - header.snapshot_creation_time = fc::time_point::now(); - - // 4. Serialize all object types (CRITICAL + IMPORTANT + OPTIONAL) - std::vector payload; - payload.reserve(64 * 1024 * 1024); // pre-allocate - - // Export each index... - export_section(db, payload); - export_section(db, payload); - // ... all other indexes ... - - // 5. Write fork_db seed block (the LIB block itself) - fc::raw::pack(payload, *lib_block); - - // 6. Compute SHA256 checksum - auto checksum = fc::sha256::hash(payload.data(), payload.size()); - header.payload_sha256 = checksum; - - // 7. Write to file (magic + version + header + payload) - write_snapshot_file(output_path, header, payload); - }); - - // 8. Read lock released automatically here - // 9. Node continues normal operation -} -``` - -**Key Points**: -- `with_strong_read_lock` is already used in VIZ codebase (see `database.cpp`) -- Lock is acquired at the database level, preventing any writes -- API read operations (`with_strong_read_lock` on their own) can proceed in parallel -- The lock duration depends on snapshot size (~44 MB takes ~1-3 seconds to serialize) -- P2P layer buffers incoming blocks during this time and applies them after lock release - -#### 9.2.3 Asynchronous Copy-on-Write (Complex) - -Make a file-level copy of shared_memory, then serialize from the copy. - -**Pros**: No blocking at all -**Cons**: Complex implementation, requires filesystem support, disk space doubled temporarily - -### 9.3 Creation Algorithm (Detailed) - -``` -1. Wait for block to become irreversible (or use current LIB) -2. Acquire strong read lock on database -3. Write JSON header with metadata -4. For each object type in CRITICAL + IMPORTANT categories: - a. Iterate all objects via get_index().indices() - b. Serialize each object using fc::raw::pack() - c. Write section to file -5. Write fork_db head block (the signed_block at LIB) -6. Compute and write checksum -7. Release read lock -8. Validate snapshot by loading it in a test instance -``` - -### 9.4 Optimization: Filter Expired Objects - -At snapshot time, skip objects that are already expired: -- `transaction_object` with `expiration <= snapshot_time` -- `vesting_delegation_expiration_object` with `expiration <= snapshot_time` -- `account_recovery_request_object` with `expires <= snapshot_time` -- `award_shares_expire_object` with `expires <= snapshot_time` -- `invite_object` with `status == used` - ---- - -## 10. Snapshot Loading Process (DLT Mode Startup) - -### 10.1 Loading Algorithm - -``` -1. Open chainbase database with shared_memory_file -2. Call init_schema() and initialize_indexes() -3. Read snapshot file header, validate version and chain_id -4. For each object type section in the snapshot: - a. Create objects in chainbase using create() - b. Validate object IDs match expected sequence -5. After all objects loaded: - a. Validate dynamic_global_property_object exists and is consistent - b. Validate witness_schedule_object exists - c. Validate hardfork_property_object exists - d. Verify object_counts match header -6. Call init_hardforks() (populates in-memory arrays from code) -7. Call initialize_evaluators() -8. Open block_log (if exists) or create empty one -9. Seed fork_db with head block from snapshot -10. Set chainbase revision to head_block_number -11. Begin P2P sync from last_irreversible_block_num + 1 -``` - -### 10.2 Validation After Load - -After loading, the following invariants must hold: - -1. `dynamic_global_property_object.head_block_number` == `snapshot_block_num` (from header) -2. `dynamic_global_property_object.head_block_id` == `snapshot_block_id` (from header) -3. `hardfork_property_object.current_hardfork_version` >= compiled minimum -4. Sum of all `account_object.balance` + `committee_fund` + ... == `current_supply` -5. Sum of all `account_object.vesting_shares` == `total_vesting_shares` -6. At least one `witness_object` with valid `signing_key` - -### 10.3 DLT Mode P2P Sync - -After snapshot load, the node must sync blocks from `last_irreversible_block_num + 1` to the current chain head: - -``` -1. Connect to P2P peers -2. Request blocks starting from last_irreversible_block_num + 1 -3. For each received block: - a. Validate block header (witness, timestamp) - b. Apply block with normal validation - c. Add to block_log (if running with block_log) -4. Once caught up, operate normally -``` - ---- - -## 11. Implementation: Plugin Architecture - -### 11.1 Plugin Design - -The snapshot functionality should be implemented as an `appbase::plugin` named `snapshot_plugin`. - -``` -snapshot_plugin - |-- snapshot_creation (command: create snapshot) - |-- snapshot_loading (startup: --snapshot=path/to/snapshot) - |-- snapshot_validation (verify loaded state) -``` - -### 11.2 CLI Options - -``` ---snapshot=path/to/snapshot.viz-snapshot Load from snapshot instead of replay ---create-snapshot=path/to/output Create snapshot at current head block ---snapshot-at-block=N Create snapshot when block N is reached -``` - -### 11.3 Integration with database::open() - -Modified startup flow: - -``` -if (snapshot_path specified) { - database::open_snapshot(snapshot_path); // Load from snapshot - // Skip reindex, skip block_log verification - // Start P2P sync from LIB + 1 -} else { - database::open(data_dir, ...); // Normal startup -} -``` - -### 11.4 Key Implementation Files to Modify/Create - -| File | Action | Description | -|------|--------|-------------| -| `plugins/snapshot/CMakeLists.txt` | Create | Build configuration | -| `plugins/snapshot/snapshot_plugin.hpp` | Create | Plugin header | -| `plugins/snapshot/snapshot_plugin.cpp` | Create | Plugin implementation (create/load/validate) | -| `plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp` | Create | Serialization/deserialization logic | -| `libraries/chain/database.hpp` | Modify | Add `open_snapshot()` method | -| `libraries/chain/database.cpp` | Modify | Implement `open_snapshot()` | -| `programs/vizd/main.cpp` | Modify | Add --snapshot CLI option | - ---- - -## 12. Complete Object List Summary - -### CRITICAL (Must Include) - -| # | Object Type | Index Type | Key Fields | Est. Count | -|---|-------------|------------|------------|------------| -| 1 | `dynamic_global_property_object` | `dynamic_global_property_index` | head_block, supply, vesting totals | 1 | -| 2 | `witness_schedule_object` | `witness_schedule_index` | current schedule, virtual time | 1 | -| 3 | `hardfork_property_object` | `hardfork_property_index` | processed_hardforks, versions | 1 | -| 4 | `account_object` | `account_index` | balances, vesting, energy, proxy | ~accounts | -| 5 | `account_authority_object` | `account_authority_index` | master/active/regular auth | ~accounts | -| 6 | `witness_object` | `witness_index` | signing_key, votes, schedule | ~witnesses | -| 7 | `witness_vote_object` | `witness_vote_index` | account-witness link | ~votes | -| 8 | `block_summary_object` | `block_summary_index` | block_id (TaPOS) | 65536 | -| 9 | `content_object` | `content_index` | rshares, cashout, payouts | ~content | -| 10 | `content_vote_object` | `content_vote_index` | vote weight, rshares | ~votes | -| 11 | `block_post_validation_object` | `block_post_validation_index` | witness validations | ~recent blocks | - -### IMPORTANT (Should Include) - -| # | Object Type | Index Type | Key Fields | Est. Count | -|---|-------------|------------|------------|------------| -| 12 | `transaction_object` | `transaction_index` | trx_id, expiration | ~pending | -| 13 | `vesting_delegation_object` | `vesting_delegation_index` | delegator, delegatee, shares | ~delegations | -| 14 | `vesting_delegation_expiration_object` | `vesting_delegation_expiration_index` | expiration, delegator | ~pending | -| 15 | `fix_vesting_delegation_object` | `fix_vesting_delegation_index` | delegator, delegatee | ~fixes | -| 16 | `withdraw_vesting_route_object` | `withdraw_vesting_route_index` | from, to, percent | ~routes | -| 17 | `escrow_object` | `escrow_index` | from, to, agent, balances | ~escrows | -| 18 | `proposal_object` | `proposal_index` | author, title, ops, approvals | ~proposals | -| 19 | `required_approval_object` | `required_approval_index` | account, proposal | ~approvals | -| 20 | `committee_request_object` | `committee_request_index` | creator, worker, amounts | ~requests | -| 21 | `committee_vote_object` | `committee_vote_index` | voter, request, percent | ~votes | -| 22 | `invite_object` | `invite_index` | creator, key, balance | ~invites | -| 23 | `award_shares_expire_object` | `award_shares_expire_index` | expires, rshares | ~pending | -| 24 | `paid_subscription_object` | `paid_subscription_index` | creator, levels, period | ~subscriptions | -| 25 | `paid_subscribe_object` | `paid_subscribe_index` | subscriber, creator, timing | ~subscribers | -| 26 | `witness_penalty_expire_object` | `witness_penalty_expire_index` | witness, penalty, expires | ~penalties | - -### OPTIONAL (Include for Full Mode) - -| # | Object Type | Index Type | Key Fields | Est. Count | -|---|-------------|------------|------------|------------| -| 27 | `account_metadata_object` | `account_metadata_index` | account, json_metadata | ~accounts | -| 28 | `content_type_object` | `content_type_index` | content, body, title | ~content | -| 29 | `master_authority_history_object` | `master_authority_history_index` | account, prev_master | ~history | -| 30 | `account_recovery_request_object` | `account_recovery_request_index` | account, new_master | ~pending | -| 31 | `change_recovery_account_request_object` | `change_recovery_account_request_index` | account, recovery, date | ~pending | -| 32 | `custom_protocol_object` | `custom_protocol_index` | account, custom_sequence | ~accounts (plugin-conditional) | - -### EXCLUDED - -| # | Object Type | Reason | -|---|-------------|--------| -| - | `block_stats_object` | No implementation found | -| - | Plugin indexes (follow, tags, etc.) | Non-consensus, API-only, rebuildable | - ---- - -## 13. Estimated Snapshot Size - -Based on typical VIZ chain state: - -| Category | Object Count | Avg Size (bytes) | Total | -|----------|-------------|-------------------|-------| -| `dynamic_global_property_object` | 1 | ~200 | ~0.2 KB | -| `witness_schedule_object` | 1 | ~500 | ~0.5 KB | -| `hardfork_property_object` | 1 | ~200 | ~0.2 KB | -| `account_object` | ~5,000 | ~800 | ~4 MB | -| `account_authority_object` | ~5,000 | ~300 | ~1.5 MB | -| `witness_object` | ~100 | ~600 | ~60 KB | -| `witness_vote_object` | ~5,000 | ~30 | ~150 KB | -| `block_summary_object` | 65,536 | ~40 | ~2.5 MB | -| `content_object` | ~50,000 | ~500 | ~25 MB | -| `content_vote_object` | ~200,000 | ~50 | ~10 MB | -| `transaction_object` | ~100 | ~500 | ~50 KB | -| `vesting_delegation_object` | ~2,000 | ~80 | ~160 KB | -| Other IMPORTANT objects | ~1,000 | ~200 | ~200 KB | -| **TOTAL** | | | **~44 MB** | - -With compression (zstd/lz4): estimated **~8-15 MB** - -This is dramatically smaller than the full shared_memory file (which can be several GB) and the block_log. - ---- - -## 14. Security Considerations - -### 14.1 Snapshot Trust Model - -The snapshot is a **trusted state**. Loading a snapshot means trusting the creator of the snapshot. This is acceptable for: - -- Node operators creating their own snapshots -- Community-provided snapshots with known hashes -- Snapshots verifiable against a known block hash - -### 14.2 Snapshot Integrity - -- SHA256 checksum of the entire snapshot file -- Chain ID verification to prevent cross-chain loading -- Block ID verification against known checkpoints (if available) -- Supply invariant checks after loading - -### 14.3 Snapshot Authenticity - -For production deployments, snapshot files should be distributed with: -- A SHA256 hash signed by a trusted key -- Or a Merkle proof linking the snapshot to a known block hash - ---- - -## 15. Open Questions and Future Work - -1. **Incremental snapshots**: Support creating delta snapshots from a previous snapshot (reduce creation time and storage) -2. **Snapshot compression**: Integrate zstd compression for smaller files -3. **Partial snapshot loading**: Load only specific object types (e.g., only consensus-critical for minimal nodes) -4. **Snapshot streaming**: Stream snapshot creation to avoid holding entire state in memory -5. **Block log pruning**: After snapshot load, trim block_log to only keep blocks after LIB -6. **Automatic snapshot schedule**: Periodically create snapshots at configurable intervals -7. **Snapshot validation tool**: Standalone tool to verify a snapshot file without loading it into a running node -8. **Cross-version compatibility**: Handle snapshot migration when object schemas change between hardforks diff --git a/.qoder/plan/mini-plan-new-hardfork-split-validator-reward.md b/.qoder/plan/mini-plan-new-hardfork-split-validator-reward.md deleted file mode 100644 index d14a076240..0000000000 --- a/.qoder/plan/mini-plan-new-hardfork-split-validator-reward.md +++ /dev/null @@ -1,168 +0,0 @@ -# Механизм распределения наград делегаторам (Reward Sharing) - -## 1. Основные понятия и текущая модель - -### 1.1. Глоссарий -| Термин | Описание | -|---|---| -| **SHARES** | Нативная единица учёта ценности в сети (аналог токена). | -| **Делегат (Validator)** | Нода, выбранная в активный пул и участвующая в подписи блоков. | -| **Делегатор (Voter)** | Пользователь, отдавший свои голоса (стейк) за конкретного делегата. | -| **Раунд** | Цикл из 21 блока, в котором происходит ротация подписывающих нод. | -| **Эпоха раздачи (Distribution Epoch)** | Период накопления наград делегатами, по истечении которого запускается расчёт и выплата делегаторам. | -| **Комиссия делегата (Commission Rate)** | Процент от награды за блоки, который делегат обязуется распределить среди своих делегаторов. Устанавливается самим делегатом. | -| **Вес голоса (Vote Weight)** | Количество SHARES, делегированных пользователем данному делегату. | - -### 1.2. Текущая механика производства блоков -- Активный пул состоит из **Top-11** делегатов и **10** резервных (саппорт) делегатов. -- Каждые **21 блок** (один раунд) происходит ротация согласно механике «перевёрнутой горы». -- За каждый успешно подписанный блок делегат получает фиксированную награду: **0.199998 SHARES**. -- Если делегат выбывает (отключился), его место в раунде подхватывает один из резервных делегатов, конкурирующих между собой. - -### 1.3. Проблема распределения «на лету» -Раздавать долю от `0.199998 SHARES` (например, 10% = 0.019999 SHARES) после каждого блока между всеми делегаторами — нерационально: -- Сумма слишком мала, возникают ошибки округления. -- Высокая вычислительная нагрузка на ноду при переборе списка делегаторов в каждом блоке. -- Фрагментация балансов (пыль). - ---- - -## 2. Предлагаемая схема накопления и раздачи - -### 2.1. Эпоха раздачи (Distribution Epoch) - -**Параметр консенсуса:** `distribution_epoch_length` — интервал, через который происходит расчёт и выплата доли делегаторам. - -**Начальное предложение:** `1 день` (≈ 28 800 блоков при 3-секундном блоке). - -Значение выбирается консенсусом делегатов и может быть изменено через голосование (governance). Допустимые значения: `1 день`, `5 дней`, `10 дней`. - -### 2.2. Накопление наград делегатом - -Каждый делегат имеет два счёта учёта наград: - -1. **Собственный счёт делегата (`validator_self_reward`)** — та часть награды, которую делегат оставляет себе (комиссия). -2. **Счёт для делегаторов (`validator_delegator_reward`)** — та часть, которая будет распределена между проголосовавшими за него пользователями. - -При получении награды за блок (`0.199998 SHARES`) происходит немедленное разделение: - -``` -block_reward = 0.199998 SHARES -commission_rate = делегат.комиссия // например, 50% → 0.5 - -delegator_share = block_reward * commission_rate -validator_share = block_reward - delegator_share - -validator_self_reward += validator_share -validator_delegator_reward += delegator_share -``` - -Оба счёта существуют **виртуально**, то есть балансы делегаторов не обновляются до окончания эпохи. - -### 2.3. Калькулятор выплат по окончании эпохи - -При наступлении блока-экспирации (конец эпохи раздачи) для каждого делегата запускается **калькулятор выплат**: - -#### Входные данные для делегата `V`: -- `accumulated_reward` — сумма на счёте `validator_delegator_reward` за истекшую эпоху. -- `commission_rate` — комиссия делегата, зафиксированная **на момент начала эпохи** (снапшот). -- `voters[]` — список делегаторов с их весами голосов (снапшот на начало эпохи). -- `total_vote_weight` — сумма весов всех делегаторов делегата `V`. - -#### Алгоритм расчёта: - -``` -total_distributed = 0 - -для каждого voter из voters[]: - voter_share = accumulated_reward * (voter.weight / total_vote_weight) - - если voter_share < MIN_PAYOUT (0.000001 SHARES): - пропустить (не начислять) - иначе: - начислить voter_share на баланс voter - total_distributed += voter_share - -// Нераспределённый остаток -undistributed = accumulated_reward - total_distributed - -// Остаток возвращается делегату -validator_self_reward += undistributed -``` - -#### Ограничения и защита: -- **Минимальная выплата (`MIN_PAYOUT`):** `0.000001 SHARES`. Если расчётная доля делегатора меньше этого значения, начисление не производится, сумма остаётся в нераспределённом остатке и возвращается делегату. -- **Снапшот голосов:** Состав делегаторов и их веса фиксируются **на начало эпохи**. Изменения в голосовании (переголосование, добавление/вывод стейка) в течение эпохи не влияют на текущую раздачу; они вступят в силу со следующей эпохи. - -### 2.4. Сброс после раздачи - -После завершения расчётов: -- `validator_delegator_reward` обнуляется. -- Делается новый снапшот голосов на следующую эпоху. -- Начинается новое накопление с новым значением `commission_rate` (если делегат его изменил). - ---- - -## 3. Числовой пример - -### Исходные данные -- Длина эпохи: `1 день` = `28 800 блоков`. -- Делегат «Alice» имеет комиссию `50%`. -- За эпоху Alice подписала `2 400 блоков` (участвовала не во всех раундах). - -### Накопление -``` -block_reward = 0.199998 -signed_blocks = 2400 - -total_block_reward = 2400 * 0.199998 = 479.9952 SHARES - -delegator_share = 479.9952 * 0.5 = 239.9976 SHARES -validator_share = 479.9952 * 0.5 = 239.9976 SHARES -``` - -На счетах Alice на конец эпохи: -- `validator_self_reward` = 239.9976 SHARES -- `validator_delegator_reward` = 239.9976 SHARES - -### Распределение среди делегаторов -У Alice три делегатора (снапшот на начало эпохи): - -| Делегатор | Вес голоса (SHARES) | Доля | -|---|---|---| -| Bob | 100 000 | 66.67% | -| Carol | 40 000 | 26.67% | -| Dave | 10 000 | 6.67% | -| **Total** | **150 000** | 100% | - -Расчёт: -``` -Bob = 239.9976 * 0.6667 = 159.9984 SHARES -Carol = 239.9976 * 0.2667 = 63.9936 SHARES -Dave = 239.9976 * 0.0667 = 16.0056 SHARES - (проверка: 159.9984 + 63.9936 + 16.0056 ≈ 239.9976) -``` - -Все доли больше `0.000001 SHARES`, нераспределённого остатка нет. - -### Ситуация с пылью -Если бы у Dave было `0.0001 SHARES` веса, его расчётная доля составила бы `≈ 0.00000016 SHARES`, что меньше `0.000001`. Dave ничего не получает, его доля возвращается Alice. - ---- - -## 4. Преимущества схемы - -1. **Эффективность для C++ ноды:** Никаких операций записи в состоянии для тысяч делегаторов на каждом блоке — только один проход в конце эпохи. -2. **Гибкость:** Каждый делегат сам устанавливает комиссию, конкурируя за голоса делегаторов. -3. **Защита от пыли:** Минимальный порог выплат предотвращает замусоривание состояния и нерациональные вычисления. -4. **Справедливость:** Снапшот на начало эпохи защищает от манипуляций с переголосованием «в последний момент». -5. **Простота аудита:** Все награды прозрачно распределяются по фиксированному алгоритму; нераспределённый остаток возвращается делегату. - ---- - -## 5. Дальнейшие шаги - -- [ ] Вынести `distribution_epoch_length` в параметры консенсуса с возможностью изменения через governance-голосование. -- [ ] Добавить в структуру делегата поля: `commission_rate`, `validator_delegator_reward`, снапшот голосов на начало эпохи. -- [ ] Реализовать функцию `process_distribution_epoch()` в коде C++ ноды, вызываемую по детерминированному условию (конец эпохи). -- [ ] Покрыть функциональность юнит-тестами с проверкой граничных условий (нулевой вес, минимальные выплаты, смена комиссии). \ No newline at end of file diff --git a/.qoder/plan/rename-block-production-condition.md b/.qoder/plan/rename-block-production-condition.md deleted file mode 100644 index ca52d9c1f2..0000000000 --- a/.qoder/plan/rename-block-production-condition.md +++ /dev/null @@ -1,127 +0,0 @@ -# Rename: `block_production_condition` → `block_validation_condition` - -## Overview - -Witnesses in VIZ do not *produce* blocks autonomously — they *validate* the chain state and sign the next block when it is their scheduled turn. The term "production" is misleading; "validation" better reflects the semantic role. This plan renames the namespace, the enum type, and all enum values that use the old name across the codebase. - ---- - -## Scope of Changes - -### Source files (code changes required) - -| File | What changes | -|------|-------------| -| [plugins/witness/include/graphene/plugins/witness/witness.hpp](../../plugins/witness/include/graphene/plugins/witness/witness.hpp) | Rename namespace `block_production_condition` → `block_validation_condition`; rename enum `block_production_condition_enum` → `block_validation_condition_enum`; rename enum value `exception_producing_block` → `exception_validating_block` | -| [plugins/witness/witness.cpp](../../plugins/witness/witness.cpp) | Update all uses of the namespace, the enum type, all enum value references, method names `block_production_loop` → `block_validation_loop`, `maybe_produce_block` → `maybe_validate_block` | - -### Documentation files (text search-and-replace) - -| File | Action | -|------|--------| -| [.qoder/repowiki/en/content/Witness.md](./../repowiki/en/content/Witness.md) | Update all references to old names | -| [.qoder/research/consensus-emergency-recovery.md](./../research/consensus-emergency-recovery.md) | Update code snippets and prose | -| [.qoder/docs/fork-collision-hardfork-proposal.md](./../docs/fork-collision-hardfork-proposal.md) | Update code snippets | -| [.qoder/docs/consensus-emergency-params.md](./../docs/consensus-emergency-params.md) | Update code snippets | -| [.qoder/plans/Fork_Collision_Resolution_Fix_24537a6e.md](./../plans/Fork_Collision_Resolution_Fix_24537a6e.md) | Update code snippets | - ---- - -## Detailed Changes - -### 1. `witness.hpp` — Namespace and enum rename - -**File:** `plugins/witness/include/graphene/plugins/witness/witness.hpp` - -```cpp -// BEFORE -namespace block_production_condition { - enum block_production_condition_enum { - produced = 0, - not_synced = 1, - not_my_turn = 2, - not_time_yet = 3, - no_private_key = 4, - low_participation = 5, - lag = 6, - consecutive = 7, - exception_producing_block = 8, - fork_collision = 9, - minority_fork = 10 - }; -} - -// AFTER -namespace block_validation_condition { - enum block_validation_condition_enum { - produced = 0, - not_synced = 1, - not_my_turn = 2, - not_time_yet = 3, - no_private_key = 4, - low_participation = 5, - lag = 6, - consecutive = 7, - exception_validating_block = 8, - fork_collision = 9, - minority_fork = 10 - }; -} -``` - -### 2. `witness.cpp` — All references - -**File:** `plugins/witness/witness.cpp` - -Rename map (search → replace): - -| Old | New | -|-----|-----| -| `block_production_condition::block_production_condition_enum` | `block_validation_condition::block_validation_condition_enum` | -| `block_production_condition::` | `block_validation_condition::` | -| `block_production_condition_enum` | `block_validation_condition_enum` | -| `exception_producing_block` | `exception_validating_block` | -| `block_production_loop` (method name) | `block_validation_loop` | -| `maybe_produce_block` (method name) | `maybe_validate_block` | - -> **Note:** `maybe_produce_block` appears in both the forward declaration (line ~102–104) and the definition (line ~660). Both must be updated together or the build will fail. - -### 3. Documentation files — Text substitution - -For each doc file listed in the scope table, apply the same rename map as a plain-text search-and-replace. No structural changes to the documents are needed — only identifier names inside code blocks and prose references. - ---- - -## Enum Values That Stay Unchanged - -These enum values already describe the *reason for not validating* (or the outcome), not the act of production, so they need no renaming: - -- `produced` — outcome, keep as-is -- `not_synced` -- `not_my_turn` -- `not_time_yet` -- `no_private_key` -- `low_participation` -- `lag` -- `consecutive` -- `fork_collision` -- `minority_fork` - -Only `exception_producing_block` → `exception_validating_block` changes because the word "producing" appears in it. - ---- - -## Implementation Steps - -1. **`witness.hpp`** — rename namespace, enum type, and `exception_producing_block`. -2. **`witness.cpp`** — rename all namespace-qualified references, both method declarations and definitions. -3. **Build** — compile to confirm zero errors before touching docs. -4. **Docs** — apply text substitution to the five documentation files. - ---- - -## Risk - -- Low. This is a pure rename with no behavioral change. -- The numeric values of enum members are preserved, so any serialized state that stores these as integers (e.g. log output) is unaffected. -- No public API or wire protocol uses this enum — it is internal to the witness plugin. diff --git a/.qoder/plans/DLT_P2P_Fixes_5d013323.md b/.qoder/plans/DLT_P2P_Fixes_5d013323.md deleted file mode 100644 index 34892e0aa2..0000000000 --- a/.qoder/plans/DLT_P2P_Fixes_5d013323.md +++ /dev/null @@ -1,496 +0,0 @@ -# DLT P2P Fixes — Implementation Plan - -Fixes all issues found during review verification of `.qoder/docs/dlt-p2p-network-redesign-review.md`. - ---- - -## Task 1: Compile Error — `peer_dlt_latest_block` field name mismatch (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -The code references `peer_dlt_latest_block` but the field in `dlt_peer_state` is named `peer_dlt_latest`. - -**Changes**: -- Line 523: `it->second.peer_dlt_latest_block` → `it->second.peer_dlt_latest` -- Line 531: `s.peer_dlt_latest_block` → `s.peer_dlt_latest` - ---- - -## Task 2: Functional Bug — `broadcast_block_post_validation()` corrupts peer_head_num (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`broadcast_block_post_validation()` at line 805 sets `msg.head_block_num = 0` with comment "filled by receiver from block_id". But `on_dlt_fork_status()` at line 699 stores it as `peer_head_num = 0`, corrupting peer state. - -**Fix**: Extract block number from the `block_id` using `block_header::num_from_id()`: -```cpp -// Line 804-805: replace -msg.head_block_id = block_id; -msg.head_block_num = 0; // filled by receiver from block_id -// With: -msg.head_block_id = block_id; -msg.head_block_num = block_header::num_from_id(block_id); -``` - -Also add the necessary include if not present: `#include ` (likely already available through `graphene/protocol/block.hpp`). - ---- - -## Task 3: Fork Resolution Non-Functional — always picks first branch (P0) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -`compute_branch_info()` returns `total_vote_weight = 0` for every branch. The comparison `0 > 0` is always false, so the first branch in `tips` always wins. The delegate already provides `compare_fork_branches()` which does the correct vote-weighted comparison with +10% longer-chain bonus. - -**Fix**: Replace `compute_branch_info()` iterations in `resolve_fork()` with `compare_fork_branches()`: - -Replace lines 1130-1139: -```cpp -// Find the heaviest branch -dlt_fork_branch_info winner; -bool first = true; -for (const auto& tip : tips) { - auto info = compute_branch_info(tip); - if (first || info.total_vote_weight > winner.total_vote_weight) { - winner = info; - first = false; - } -} -``` - -With: -```cpp -// Find the heaviest branch using vote-weighted comparison -block_id_type winner_tip = tips[0]; -for (size_t i = 1; i < tips.size(); ++i) { - if (_delegate->compare_fork_branches(tips[i], winner_tip) > 0) { - winner_tip = tips[i]; - } -} -dlt_fork_branch_info winner; -winner.tip = winner_tip; -``` - -The rest of `resolve_fork()` already uses `winner.tip` for hysteresis and fork switching, so it will work with the new `winner_tip`. - -After this change, `compute_branch_info()` is no longer called from `resolve_fork()`. It can be kept for potential future use or removed. - ---- - -## Task 4: `expected_next_block` tracking never used (P1) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -The field `expected_next_block` is declared in `dlt_peer_state` but never set or validated. Per plan section 3.7: reject blocks that skip too far ahead (hole-creation attack prevention). - -**Changes**: - -In `on_dlt_block_range_reply()` (after line 633, inside the block loop), add ordering validation before `accept_block()`: -```cpp -// Validate block ordering -if (state.expected_next_block != 0 && block.block_num() != state.expected_next_block) { - wlog(DLT_LOG_RED "Block #${n} from ${ep} out of order (expected #${e})" DLT_LOG_RESET, - ("n", block.block_num())("ep", state.endpoint)("e", state.expected_next_block)); - record_packet_result(peer, false); - continue; -} -``` - -After successful `accept_block()`, set the expected next block: -```cpp -state.expected_next_block = block.block_num() + 1; -``` - -Same for `on_dlt_block_reply()` (line 673): add the same validation before `accept_block()`. - -On disconnect (`handle_disconnect()`), reset: `state.expected_next_block = 0;` - ---- - -## Task 5: `pending_block_batch` timeout + `block_validation_timeout()` (P1) - -**Files**: `libraries/network/include/graphene/network/dlt_p2p_node.hpp`, `libraries/network/dlt_p2p_node.cpp` - -The field `pending_block_batch_time` and helper `has_pending_batch_timeout()` exist but are never used. The `block_validation_timeout()` method is not implemented. - -**Changes**: - -**Header** (`dlt_p2p_node.hpp`): Add method declaration in the private section (after `periodic_task()` line 194): -```cpp -void block_validation_timeout(); -``` - -**Implementation** (`dlt_p2p_node.cpp`): - -1. In `on_dlt_block_range_reply()` (line 615), before the block processing loop, set the batch start time: -```cpp -state.pending_block_batch_time = fc::time_point::now(); -``` - -2. After the block processing loop completes successfully, clear it: -```cpp -state.pending_block_batch_time = fc::time_point(); -``` - -3. Implement `block_validation_timeout()`: -```cpp -void dlt_p2p_node::block_validation_timeout() { - for (auto& [id, state] : _peer_states) { - if (state.has_pending_batch_timeout()) { - wlog(DLT_LOG_RED "Block validation timeout for peer ${ep} (30s)" DLT_LOG_RESET, - ("ep", state.endpoint)); - record_packet_result(id, false); - state.pending_block_batch_time = fc::time_point(); - // If already at threshold, soft_ban will happen via record_packet_result - } - } -} -``` - -4. Call from `periodic_task()` (after `sync_stagnation_check()` line 1274): -```cpp -block_validation_timeout(); -``` - ---- - -## Task 6: Fork window reset on non-confirmation (P1) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -In `track_fork_state()` (lines 1116-1120), `_fork_detected = false` is set after `resolve_fork()` regardless of whether resolution succeeded. When hysteresis is not met, this causes a fresh 42-block countdown instead of continuous retry. - -**Fix**: Move `_fork_detected = false` into `resolve_fork()` — only clear it when resolution actually completes. - -Change `track_fork_state()` (lines 1116-1120): -```cpp -// Before: -if (_fork_detected && - block.block_num() - _fork_detection_block_num >= FORK_RESOLUTION_BLOCK_THRESHOLD) { - resolve_fork(); - _fork_detected = false; -} - -// After: -if (_fork_detected && - block.block_num() - _fork_detection_block_num >= FORK_RESOLUTION_BLOCK_THRESHOLD) { - resolve_fork(); - // _fork_detected is cleared inside resolve_fork() only when resolution completes -} -``` - -In `resolve_fork()`, add `_fork_detected = false` at the two exit points where resolution actually completes: - -1. After line 1127 (`_fork_status = DLT_FORK_STATUS_NORMAL; return;` — branch count < 2, fork is over): -```cpp -if (tips.size() < 2) { - _fork_status = DLT_FORK_STATUS_NORMAL; - _fork_detected = false; // fork resolved: only 1 branch remains - return; -} -``` - -2. At the end of the function (after the hysteresis is confirmed and fork switch is executed, line 1169): -```cpp -// Reset hysteresis -_fork_resolution_state = dlt_fork_resolution_state(); -_fork_detected = false; // fork resolution completed -``` - -Do NOT set `_fork_detected = false` at the early return (line 1153) where hysteresis is not confirmed — that's the whole point. - ---- - -## Task 7: `switch_to_fork()` in delegate — only pops one block (P1) - -**File**: `plugins/p2p/p2p_plugin.cpp` (lines 189-201) - -Current implementation calls `pop_block()` once but never re-pushes blocks from the new fork. The chain's `_push_block()` already has a full fork-switch implementation (database.cpp:1590-1730) that handles pop-until-common-ancestor + re-apply-new-branch + LIB guard + DLT crash prevention. - -**Fix**: Replace the simplified `switch_to_fork()` with a call to `push_block()` which triggers the chain's built-in fork switch: - -```cpp -void switch_to_fork(const block_id_type& new_head) override { - try { - auto& fdb = chain.db().get_fork_db(); - auto block = fdb.fetch_block(new_head); - if (block) { - ilog("Switching to fork with head ${id}", ("id", new_head)); - // The chain's push_block() handles full fork switch: - // pop-until-common-ancestor, re-apply new branch, - // LIB guard, DLT crash prevention - chain.db().push_block(*block); - } - } catch (const fc::exception& e) { - wlog("Error switching to fork: ${e}", ("e", e.to_detail_string())); - } -} -``` - -This requires adding the include for the block type (already available through `graphene/chain/database.hpp`). - ---- - -## Task 8: `is_head_on_branch()` too simplistic (P1) - -**File**: `plugins/p2p/p2p_plugin.cpp` (lines 203-206) - -Current implementation does `tip == head_block_id()` — misses the case where our head IS on the branch but not at its tip (e.g., our head is block 100, tip is block 105 on the same branch). - -**Fix**: Use `fork_db.fetch_branch_from()` to check if our head is an ancestor of the tip: - -```cpp -bool is_head_on_branch(const block_id_type& tip) const override { - if (tip == chain.db().head_block_id()) return true; - try { - auto& fdb = chain.db().get_fork_db(); - if (!fdb.is_known_block(tip) || !fdb.is_known_block(chain.db().head_block_id())) - return false; - auto branches = fdb.fetch_branch_from(tip, chain.db().head_block_id()); - // If our head is in the "old" branch (branches.second), we're on the same branch - // as the tip — they share a common ancestor and our head is below the tip - return !branches.second.empty(); - } catch (...) { - return false; - } -} -``` - ---- - -## Task 9: Spam strikes not incremented for expired/TaPoS-invalid rejections (P2) - -**File**: `libraries/network/dlt_p2p_node.cpp` - -In `add_to_mempool()`: -- Line 967: expired transaction returns false without `record_packet_result(sender, false)` -- Line 984: TaPoS-invalid transaction returns false without `record_packet_result(sender, false)` - -**Fix**: - -Line 967, replace: -```cpp -if (trx.expiration < fc::time_point_sec(fc::time_point::now())) return false; -``` -With: -```cpp -if (trx.expiration < fc::time_point_sec(fc::time_point::now())) { - if (from_peer && sender != INVALID_PEER_ID) record_packet_result(sender, false); - return false; -} -``` - -Line 984, replace: -```cpp -if (!is_tapos_valid(trx)) return false; -``` -With: -```cpp -if (!is_tapos_valid(trx)) { - if (from_peer && sender != INVALID_PEER_ID) record_packet_result(sender, false); - return false; -} -``` - ---- - -## Task 10: `periodic_dlt_prune_check()` is a no-op (P2) - -**File**: `libraries/network/dlt_p2p_node.cpp` (lines 1224-1227) - -Currently empty. Should trigger batch pruning when the DLT block log exceeds `_dlt_block_log_max_blocks`. - -**Fix**: -```cpp -void dlt_p2p_node::periodic_dlt_prune_check() { - if (!_delegate) return; - uint32_t earliest = _delegate->get_dlt_earliest_block(); - uint32_t latest = _delegate->get_dlt_latest_block(); - if (latest == 0 || earliest == 0) return; - - uint32_t current_range = latest - earliest + 1; - if (current_range <= _dlt_block_log_max_blocks) return; - - // Only prune in batches of DLT_PRUNE_BATCH_SIZE (10000) - if (latest - _last_prune_block_num < DLT_PRUNE_BATCH_SIZE) return; - - ilog(DLT_LOG_GREEN "DLT block log exceeds max (${r} > ${m}), pruning ${b} blocks" DLT_LOG_RESET, - ("r", current_range)("m", _dlt_block_log_max_blocks)("b", DLT_PRUNE_BATCH_SIZE)); - - // The actual pruning is done at the chain level via truncate_before() - // We signal the delegate to prune, passing the new start block number - uint32_t new_start = earliest + DLT_PRUNE_BATCH_SIZE; - // Delegate method needed — for now, log the intent - // TODO: Add dlt_p2p_delegate::prune_dlt_block_log(uint32_t new_start) - _last_prune_block_num = latest; -} -``` - -This is a partial implementation — a new delegate method `prune_dlt_block_log()` would be needed for the full chain. Mark as partial with a TODO. - ---- - -## Task 11: `has_emergency_private_key()` returns false (P2) - -**File**: `plugins/p2p/p2p_plugin.cpp` (lines 80-83) - -Currently always returns `false`. Should check if the witness plugin has an emergency private key configured. - -**Fix**: Query the witness plugin: -```cpp -bool has_emergency_private_key() const override { - auto* wit_plug = appbase::app().find_plugin(); - if (wit_plug) { - return wit_plug->is_emergency_key_configured(); - } - return false; -} -``` - -This requires: -1. Adding `#include ` to p2p_plugin.cpp -2. Adding `bool is_emergency_key_configured() const;` to the witness_plugin public API -3. Implementing it in the witness plugin (check if emergency master key is set) - -Since this crosses plugin boundaries and requires changes to the witness plugin, mark as requiring coordination. The minimal change is to add the include and the query, with a stub on the witness side that returns `true` if the key is in the config. - ---- - -## Task 12: `accept_block()` ignores `sync_mode` parameter (P2) - -**File**: `plugins/p2p/p2p_plugin.cpp` (lines 139-151) - -Currently always calls `push_block()` the same way regardless of `sync_mode`. In sync mode, blocks are being applied in bulk and certain expensive checks could be skipped. - -**Fix**: Pass `skip` flags to `push_block()` based on sync mode: -```cpp -bool accept_block(const signed_block& block, bool sync_mode) override { - try { - uint32_t skip = graphene::chain::database::skip_nothing; - if (sync_mode) { - // During bulk sync, skip expensive checks that are redundant - // for blocks we trust from our fork peers - skip = graphene::chain::database::skip_witness_signature - | graphene::chain::database::skip_transaction_signatures; - } - chain.db().push_block(block, skip); - return false; // fork detection done via on_block_applied callback - } catch (const graphene::chain::unlinkable_block_exception&) { - wlog("Unlinkable block #${n}, storing in fork_db", ("n", block.block_num())); - chain.db().get_fork_db().push_block(block); - return false; - } catch (const fc::exception& e) { - wlog("Error accepting block #${n}: ${e}", ("n", block.block_num())("e", e.to_detail_string())); - return false; - } -} -``` - -Note: The `skip_witness_signature` flag must be used carefully — it should only be applied for blocks from fork-aligned peers. The current design already ensures this because only fork-aligned peers exchange blocks. - ---- - -## Task 13: `resync_from_lib()` is shallow (P2) - -**Files**: `plugins/p2p/p2p_plugin.cpp` (lines 215-217, 437-441), `libraries/network/dlt_p2p_node.cpp` (lines 847-856) - -The delegate-level `resync_from_lib()` is empty. The node-level version just calls `transition_to_sync()` + re-requests blocks. A proper resync from LIB should: -1. Pop blocks back to LIB -2. Reset fork tracking state -3. Re-request blocks from LIB+1 - -**Fix for dlt_p2p_node::resync_from_lib()** (line 847): -```cpp -void dlt_p2p_node::resync_from_lib(bool force_emergency) { - ilog(DLT_LOG_GREEN "DLT P2P: resync from LIB requested (force_emergency=${f})" DLT_LOG_RESET, - ("f", force_emergency)); - - // Reset fork tracking - _fork_detected = false; - _fork_detection_block_num = 0; - _fork_resolution_state = dlt_fork_resolution_state(); - _fork_status = DLT_FORK_STATUS_NORMAL; - - transition_to_sync(); - - // Re-send hello to all peers to get updated chain state - auto hello = build_hello_message(); - for (auto& [id, state] : _peer_states) { - if (state.lifecycle_state == DLT_PEER_LIFECYCLE_ACTIVE || - state.lifecycle_state == DLT_PEER_LIFECYCLE_SYNCING) { - send_message(id, message(hello)); - request_blocks_from_peer(id); - } - } -} -``` - -The delegate-level `resync_from_lib()` can remain empty since the P2P node handles the logic internally. The chain-level block popping is handled by the caller (witness plugin) before invoking `resync_from_lib()`. - ---- - -## Task 14: Review Document Fixes - -**File**: `.qoder/docs/dlt-p2p-network-redesign-review.md` - -### 14a: Factual error in GAP 4 (line 116) - -Current text: -> "The plan's pseudocode does NOT set `_fork_detected = false` inside `track_fork_state()` after calling `resolve_fork()`." - -This is incorrect — the plan's pseudocode (plan lines 643-647) DOES set `_fork_detected = false`. Both the plan's pseudocode and implementation share the same issue. - -Replace line 116 with: -> "Both the plan's pseudocode and the implementation set `_fork_detected = false` after `resolve_fork()` — but this contradicts the plan's own design intent in section 3.7, which specifies that only the confirmation counter should reset on lead flip, not the 42-block detection window." - -### 14b: Severity inconsistency — GAP 5 - -- Line 124 heading: "(P0 Anti-Spam)" -- Line 191 summary: "P2 (nice to fix)" - -Align both to P0 (matches plan's P0 rating for mempool DoS protection): -Change line 191 from: -``` -| **P2 (nice to fix)** | GAP 5 — incomplete spam strikes; Known gaps 1-6 (already documented) | -``` -To: -``` -| **P0 (must fix)** | GAP 5 — incomplete spam strikes (plan rates this P0) | -| **P2 (nice to fix)** | Known gaps 1-6 (already documented) | -``` - -### 14c: Severity inconsistency — GAP 6 - -- Line 144 heading: "(P1 Fork)" -- Line 189 summary: "P0 (must fix)" - -Align heading to P0 (fork resolution is non-functional): -Change line 144 from `### GAP 6: Fork resolution winner always picks first branch (P1 Fork)` to `### GAP 6: Fork resolution winner always picks first branch (P0 Fork)` - -### 14d: Upgrade minor observation #2 - -Minor observation #2 says `broadcast_block_post_validation()` sends a `dlt_fork_status_message` "functional but semantically imprecise." But `msg.head_block_num = 0` actually corrupts `peer_head_num` in the receiver — this is a functional bug, not just semantic imprecision. - -Replace line 178 with: -> `broadcast_block_post_validation()` sends a `dlt_fork_status_message` with `head_block_num = 0` — the receiver stores this as `peer_head_num = 0`, corrupting peer state tracking. This is a functional bug, not just semantic imprecision. - ---- - -## Execution Order - -Tasks should be executed in this order to minimize conflicts: - -1. **Task 1** (compile error) — must be first, code won't compile without it -2. **Task 2** (head_block_num = 0) — simple one-line fix -3. **Task 3** (fork resolution) — highest-impact logic fix -4. **Task 6** (fork window reset) — related to Task 3, same area -5. **Task 5** (block validation timeout) — new method + wiring -6. **Task 4** (expected_next_block) — validation additions -7. **Task 7** (switch_to_fork delegate) — delegate fix -8. **Task 8** (is_head_on_branch) — delegate fix -9. **Task 9** (spam strikes) — simple additions -10. **Task 10** (prune check) — partial implementation -11. **Task 11** (emergency key) — cross-plugin, partial -12. **Task 12** (accept_block sync_mode) — optimization -13. **Task 13** (resync_from_lib) — node logic -14. **Task 14** (review doc) — documentation fixes, last \ No newline at end of file diff --git a/.qoder/plans/Fork_Collision_Resolution_Fix_24537a6e.md b/.qoder/plans/Fork_Collision_Resolution_Fix_24537a6e.md deleted file mode 100644 index 6252b053c7..0000000000 --- a/.qoder/plans/Fork_Collision_Resolution_Fix_24537a6e.md +++ /dev/null @@ -1,328 +0,0 @@ - -# Fork Collision Resolution Fix - -## Problem -When a witness node detects a fork collision (competing block at same height in fork_db), it defers block production forever. The competing block from the dead fork is never removed from fork_db, so `maybe_produce_block()` keeps returning `fork_collision` every 250ms. Meanwhile, blocks from the longer/healthier chain can't be applied because the head is stuck, creating a growing gap that eventually makes fork switching impossible. - -## Root Cause Analysis - -### How vote-weighted fork comparison works (existing HF12 code) - -`compute_branch_weight()` in `database.cpp:_push_block()` (lines 1300-1314): -1. `fetch_branch_from(tip_a, tip_b)` walks both chains back to their **common ancestor** -2. Returns two vectors: `branches.first` = all blocks from fork A's tip to common ancestor, `branches.second` = same for fork B -3. For each branch, iterates through **ALL blocks** in that branch -4. For each block, gets the `witness` name (who produced that block) -5. Looks up `witness_object.votes` from current DB state — this is **on-chain stake vote count** (how many VIZ tokens voted for that witness), NOT the scheduled slot -6. Uses `flat_set` to count each witness **only once** (even if it produced multiple blocks) -7. Skips `CHAIN_EMERGENCY_WITNESS_ACCOUNT` -8. The branch with higher total vote weight wins; ties broken by longer chain -9. **NEW: Longer chain gets +10% bonus on its vote weight** — each block produced is a consensus "vote" by the producing witness. Witnesses on the longer chain didn't defer and kept producing by consensus rules, which is strong evidence of network support. - -**Answer: it sums `wit_obj.votes` (on-chain stake) for ALL unique witnesses that produced blocks in the divergent portion of each fork, not just the top block. The longer chain gets a +10% bonus on its total weight.** - -### Where the witness plugin goes wrong -In `witness.cpp:maybe_produce_block()` (lines 549-577), the fork collision check does NOT use vote-weight comparison: -- It only checks "does any competing block exist at `head_block_num+1` with a different parent?" -- If yes -> blindly defers, no evaluation of which fork is better -- It never asks: "which fork has more vote weight? Should I produce on my fork or switch?" -- This creates a deadlock: the witness waits for fork resolution, but fork resolution only happens via `_push_block()` which can't run because the head is stuck - -### The deadlock sequence -1. Head at 79402010, competing block at 79402011 from dead fork in fork_db -2. Witness scheduled at 79402011 -> sees competing block -> defers -3. P2P blocks 79402012+ arrive but can't be pushed (gap, parent unknown in fork_db) -4. `_push_block()` never gets a chance to do vote-weight comparison -5. Witness keeps deferring every 250ms -> permanently stuck -6. Gap grows until fork_db window (2400 blocks) is exceeded -> no recovery possible - -### Critical constraint: `compute_branch_weight` CANNOT solve the stuck scenario -In your scenario (head at 79402010, network at 79404861+), the longer chain's blocks are NOT in fork_db — they were rejected because the parent was unknown (gap too large). So `fetch_branch_from()` cannot compute the branch for the longer chain. The existing vote-weight comparison **requires both chain tips to exist in fork_db**. - -This means we need TWO levels of fix: -- **Level 1 (immediate)**: When fork_db has competing blocks at `head+1`, use vote-weight comparison to decide whether to produce or switch. This handles the case where BOTH forks are in fork_db. -- **Level 2 (stuck recovery)**: When the witness has been deferring and head is stuck (not advancing), bypass the collision check entirely — the competing block is from a dead fork that clearly lost (the network moved on without it). Produce on our fork. - -## Fix Strategy: Two-Level Fork Decision in Witness Plugin - -### Level 1: Vote-weighted comparison (when both forks are in fork_db) -When a competing block at `head+1` exists in fork_db: -1. **Evaluate fork weights** using `compute_branch_weight()` logic (same as `_push_block()`) -2. **If our fork has more vote weight** -> produce on our fork (the competing block is from a losing fork) -3. **If the competing fork has more vote weight** -> switch to it first, then produce on it -4. **If tied** -> defer briefly (1-2 slots) - -### Level 2: Stuck-head timeout (when fork_db comparison is impossible) -When the witness has been deferring for N consecutive slots and head hasn't advanced: -1. The competing block is clearly from a dead fork (network moved on) -2. Remove the competing block(s) from fork_db -3. Produce on our fork -4. This handles the case where the longer chain's blocks aren't in fork_db - -### Level 3: Prune dead-fork entries on block apply (defensive) -When `_push_block()` successfully applies a block, remove competing blocks at that height from fork_db that are from dead forks - -## Detailed Changes - -### 1. `libraries/chain/include/graphene/chain/database.hpp` — Expose fork comparison as public method - -```cpp -/// Compare two fork branches by vote weight (HF12 logic). -/// Sums wit_obj.votes (on-chain stake) for all unique witnesses in each branch, -/// from the tip back to the common ancestor. -/// The longer chain gets a +10% bonus on its total weight (reflects that more -/// witnesses kept producing on it by consensus rules without deferring). -/// Returns: >0 if branch_a is heavier, <0 if branch_b is heavier, 0 if tied -/// Returns 0 if either tip is not in fork_db (cannot compare) -int compare_fork_branches(const block_id_type& branch_a_tip, const block_id_type& branch_b_tip) const; -``` - -### 2. `libraries/chain/database.cpp` — Implement `compare_fork_branches()` - -Extract `compute_branch_weight` lambda from lines 1300-1314 into the new public method. -Add +10% bonus to the longer chain's weight. -Wrap in try/catch to return 0 when `fetch_branch_from()` fails (one tip not in fork_db). -Refactor `_push_block()` to call `compare_fork_branches()` instead of inline code. - -```cpp -int database::compare_fork_branches(const block_id_type& branch_a_tip, const block_id_type& branch_b_tip) const { - try { - if (!_fork_db.is_known_block(branch_a_tip) || !_fork_db.is_known_block(branch_b_tip)) - return 0; // Cannot compare — one or both tips not in fork_db - - auto branches = _fork_db.fetch_branch_from(branch_a_tip, branch_b_tip); - - auto compute_branch_weight = [&](const fork_database::branch_type& branch) -> share_type { - flat_set seen_witnesses; - share_type total_weight = 0; - for (const auto& item : branch) { - const auto& wit_name = item->data.witness; - if (wit_name == CHAIN_EMERGENCY_WITNESS_ACCOUNT) continue; - if (seen_witnesses.insert(wit_name).second) { - try { - const auto& wit_obj = get_witness(wit_name); - total_weight += wit_obj.votes; - } catch (...) {} - } - } - return total_weight; - }; - - share_type weight_a = compute_branch_weight(branches.first); - share_type weight_b = compute_branch_weight(branches.second); - - // Longer chain gets +10% bonus on its vote weight. - // Each block produced is a consensus "vote" — witnesses on the longer - // chain didn't defer and kept producing by consensus rules. - // This reflects the stronger network support signal. - auto a_num = block_header::num_from_id(branch_a_tip); - auto b_num = block_header::num_from_id(branch_b_tip); - if (a_num > b_num) { - weight_a = weight_a + weight_a / 10; // +10% - } else if (b_num > a_num) { - weight_b = weight_b + weight_b / 10; // +10% - } - - if (weight_a > weight_b) return 1; // branch_a is heavier - if (weight_b > weight_a) return -1; // branch_b is heavier - return 0; // tied - } catch (...) { - return 0; // Cannot compare - } -} -``` - -### 3. `libraries/chain/include/graphene/chain/fork_database.hpp` — Add `remove_blocks_by_number()` - -```cpp -void remove_blocks_by_number(uint32_t num); -``` - -### 4. `libraries/chain/fork_database.cpp` — Implement `remove_blocks_by_number()` - -```cpp -void fork_database::remove_blocks_by_number(uint32_t num) { - auto blocks = fetch_block_by_number(num); - for (const auto& b : blocks) { - _index.get().erase(b->id); - } -} -``` - -### 5. `libraries/chain/database.cpp` — Prune dead-fork blocks after apply - -In `_push_block()`, after successfully applying a block that extends the current chain (no fork switch, around line 1417), add: - -```cpp -// Prune stale competing blocks from dead forks at this height -auto competing = _fork_db.fetch_block_by_number(new_block.block_num()); -for (const auto& cb : competing) { - if (cb->id != new_head->id && cb->data.previous != head_block_id()) { - wlog("Pruning stale competing block ${id} at height ${n} from fork_db (dead fork)", - ("id", cb->id)("n", new_block.block_num())); - _fork_db.remove(cb->id); - } -} -``` - -### 6. `plugins/witness/include/graphene/plugins/witness/witness.hpp` — Add config - -No header changes needed; the timeout is internal to `impl`. - -### 7. `plugins/witness/witness.cpp` — Two-level fork decision - -**Add to impl struct:** -```cpp -std::atomic fork_collision_defer_count_{0}; -uint32_t _fork_collision_timeout_blocks = 21; // safety timeout: one full witness round (21 blocks = 63s) -fc::time_point _fork_collision_start_time; // when we first started deferring -uint32_t _fork_collision_head_num = 0; // head_block_num when collision started -``` - -**Add CLI option:** `--fork-collision-timeout-blocks` (default: 21, i.e. one full witness schedule round = 63 seconds. After a full round, all scheduled witnesses have produced on the longer chain, confirming it's canonical.) - -**Replace the fork collision block (lines 545-578) with two-level logic:** - -```cpp -// Check if a competing block already exists in the fork database for this block height. -{ - auto existing_blocks = db.get_fork_db().fetch_block_by_number(db.head_block_num() + 1); - if (existing_blocks.size() > 0) { - bool has_competing_block = false; - item_ptr competing_block; - - if (dgp.emergency_consensus_active) { - has_competing_block = true; - competing_block = existing_blocks[0]; - } else { - for (const auto &eb : existing_blocks) { - if (eb->data.witness != scheduled_witness && - eb->data.previous != db.head_block_id()) { - has_competing_block = true; - competing_block = eb; - break; - } - } - } - - if (has_competing_block && competing_block) { - fork_collision_defer_count_++; - - // LEVEL 2: Stuck-head timeout - // If we've been deferring and the head hasn't advanced, the competing - // block is from a dead fork. The network has moved on without it. - // After 21 consecutive deferrals (one full witness round = 63s), - // we can be sure the longer chain had all scheduled witnesses - // produce on it — confirming it's the canonical chain. - if (fork_collision_defer_count_ > _fork_collision_timeout_blocks) { - wlog("Fork collision timeout exceeded (${n} deferrals, head stuck at ${h}). " - "Removing dead-fork competing block and producing on our chain.", - ("n", fork_collision_defer_count_.load())("h", db.head_block_num())); - db.get_fork_db().remove_blocks_by_number(db.head_block_num() + 1); - // Fall through to produce block - } - // LEVEL 1: Vote-weighted comparison (when both forks are in fork_db) - else if (db.has_hardfork(CHAIN_HARDFORK_12)) { - int weight_cmp = db.compare_fork_branches( - competing_block->id, db.head_block_id()); - - if (weight_cmp < 0) { - // Our fork has MORE vote weight -> produce on our fork - wlog("Our fork has more vote weight at height ${h}. " - "Producing despite competing block from weaker fork.", - ("h", db.head_block_num() + 1)); - // Remove the losing competing block - db.get_fork_db().remove(competing_block->id); - // Fall through to produce block - } else if (weight_cmp > 0) { - // Competing fork has MORE vote weight - // The competing branch is in fork_db and has more support. - // We should switch to it. The normal _push_block path will - // handle the switch when the competing block's children arrive. - // For now, defer to let the fork switch happen naturally. - capture("height", db.head_block_num() + 1)("scheduled_witness", scheduled_witness); - wlog("Competing fork at height ${h} has more vote weight. " - "Deferring to allow fork switch to stronger chain.", - ("h", db.head_block_num() + 1)); - return block_production_condition::fork_collision; - } else { - // Tied (or comparison impossible — one tip not in fork_db) - // Defer briefly, timeout will kick in - capture("height", db.head_block_num() + 1)("scheduled_witness", scheduled_witness); - wlog("Fork collision at height ${h} with tied/unknown vote weight. " - "Deferring (attempt ${n}/${max}).", - ("h", db.head_block_num() + 1) - ("n", fork_collision_defer_count_.load()) - ("max", _fork_collision_timeout_blocks)); - return block_production_condition::fork_collision; - } - } - // Pre-HF12: original defer behavior with timeout - else { - capture("height", db.head_block_num() + 1)("scheduled_witness", scheduled_witness); - return block_production_condition::fork_collision; - } - } - } -} -``` - -**Reset `fork_collision_defer_count_`** to 0 in `block_production_loop()` when result is: -- `produced` — block was made, no collision -- `not_my_turn` / `not_time_yet` — normal skips, collision resolved -- Any result where `db.head_block_num()` has changed since last check - -## File Change Summary - -| File | Change | -|------|--------| -| `libraries/chain/include/graphene/chain/database.hpp` | Add `compare_fork_branches()` declaration | -| `libraries/chain/database.cpp` | Extract `compute_branch_weight` into `compare_fork_branches()`, prune dead fork blocks after apply | -| `libraries/chain/include/graphene/chain/fork_database.hpp` | Add `remove_blocks_by_number()` declaration | -| `libraries/chain/fork_database.cpp` | Implement `remove_blocks_by_number()` | -| `plugins/witness/witness.cpp` | Two-level fork decision: vote-weighted comparison + stuck-head timeout | - -## Key Design Decisions - -1. **`wit_obj.votes` = on-chain stake** — the vote-weight comparison sums the stake (VIZ tokens) that voted for each unique witness that produced blocks in the divergent portion of each fork. It is NOT the scheduled slot count. -2. **All blocks in the divergent branch count** — not just the top block. `fetch_branch_from()` walks from each tip back to the common ancestor, and all unique witnesses on each branch contribute their stake weight. -3. **Longer chain gets +10% bonus** — each block is a consensus "vote" by the producing witness. Witnesses on the longer chain didn't defer and kept producing by consensus rules. The +10% bonus ensures that a slightly shorter chain with slightly more stake cannot override a clearly longer chain that more witnesses kept building on. -4. **Our fork wins ties** — when vote weights (including bonus) are equal, we produce on our own chain (less disruptive) -5. **Competing fork with more weight -> defer for switch** — if the other chain has more support, we defer to allow `_push_block()` to naturally switch us when more blocks arrive -6. **Stuck-head timeout = 21 blocks (one full witness round)** — after 21 consecutive deferrals (63 seconds), all scheduled witnesses have had a chance to produce on the longer chain. We can be confident the longer chain is canonical. The competing block from the dead fork is removed and production resumes. -7. **Pruning on block apply** — when a block is applied, competing blocks from dead forks at that height are removed, preventing them from causing false collision detection in the future - -## Verification -- Short micro-forks (1-2 blocks): vote-weight comparison resolves quickly, no stuck -- Our fork has more votes: witness produces immediately -- Competing fork has more votes: witness defers for natural switch via `_push_block()` -- Stuck head (your scenario): timeout after 21 slots (one full witness round) removes dead-fork block, witness produces -- Stale fork_db entries pruned on each block apply -- Emergency mode: existing behavior preserved (any competing block = defer, timeout applies) - ---- - -## Implementation Status - -All planned changes have been implemented. Deviations from the original plan are noted below. - -| # | Planned Change | File | Status | Notes | -|---|---------------|------|--------|-------| -| 1 | Add `compare_fork_branches()` declaration | `database.hpp` | Done | Matches plan exactly | -| 2 | Implement `compare_fork_branches()` with +10% longer-chain bonus | `database.cpp` | Done | Matches plan; refactored `_push_block()` to use it instead of inline lambda | -| 3 | Refactor `_push_block()` HF12 fork-switch to use `compare_fork_branches()` | `database.cpp` | Done | Replaced 26-line inline lambda with 4-line call to `compare_fork_branches()` | -| 4 | Add `remove_blocks_by_number()` declaration | `fork_database.hpp` | Done | Matches plan exactly | -| 5 | Implement `remove_blocks_by_number()` | `fork_database.cpp` | Done | Matches plan exactly | -| 6 | Prune dead-fork blocks after block apply | `database.cpp` | Done | Slight deviation: uses `new_block.id()` instead of `new_head->id` (code is in the non-fork-switch path where `new_head` is out of scope) | -| 7 | Add fork collision state fields to `impl` struct | `witness.cpp` | Done | **Deviation**: removed `_fork_collision_head_num` (dead code) and `_fork_collision_start_time` (unused). Only `fork_collision_defer_count_` and `_fork_collision_timeout_blocks` remain | -| 8 | Add `--fork-collision-timeout-blocks` CLI option | `witness.cpp` | Done | Default 21, matches plan | -| 9 | Two-level fork decision in `maybe_produce_block()` | `witness.cpp` | Done | **Deviation**: Level 2 timeout runs BEFORE the HF12 check, so pre-HF12 nodes also benefit from the timeout. The plan had Level 2 inside the HF12 branch | -| 10 | Reset `fork_collision_defer_count_` in `block_production_loop()` | `witness.cpp` | Done | Reset on `produced`, `not_synced`, `not_my_turn`. **Not reset** on `not_time_yet` (timer hasn't fired yet, count should persist) | - -### Bugs Found and Fixed During Review - -| # | Severity | Bug | Fix | -|---|----------|-----|-----| -| 1 | Critical | Pre-HF12 path deferred forever (same as original bug) — Level 2 timeout was inside the `else if (has_hardfork(HF12))` branch | Moved Level 2 timeout check before the HF12 branch so all nodes benefit | -| 2 | Low | `_fork_collision_head_num` declared but never read or written | Removed the field | -| 3 | Info | `fork_collision_defer_count_` was planned as `std::atomic` but implemented as `uint32_t` | Kept as `uint32_t` — all access is single-threaded (block production loop) | diff --git a/.qoder/plans/Witness-to-Validator_Full_Rename_6e522add.md b/.qoder/plans/Witness-to-Validator_Full_Rename_6e522add.md deleted file mode 100644 index ae25feb8ac..0000000000 --- a/.qoder/plans/Witness-to-Validator_Full_Rename_6e522add.md +++ /dev/null @@ -1,148 +0,0 @@ -# Witness-to-Validator Full Rename Plan - -Phase 1 (internal C++ methods/enums) is already done. This plan covers everything remaining. - -## Scope: 5 Protocol Operations - -| Type ID | Old Struct | New Struct | -|---------|-----------|------------| -| 6 | `witness_update_operation` | `validator_update_operation` | -| 7 | `account_witness_vote_operation` | `account_validator_vote_operation` | -| 8 | `account_witness_proxy_operation` | `account_validator_proxy_operation` | -| 30 | `shutdown_witness_operation` | `shutdown_validator_operation` | -| 42 | `witness_reward_operation` | `validator_reward_operation` | - -## Task 1: Protocol operation struct renames - -**Files:** -- `libraries/protocol/include/graphene/protocol/chain_operations.hpp` — rename 3 structs + 3 FC_REFLECT macros -- `libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp` — rename 2 structs + 2 FC_REFLECT macros + constructors -- `libraries/protocol/include/graphene/protocol/operations.hpp` — update 5 names in static_variant list (order unchanged!) -- `libraries/protocol/chain_operations.cpp` — rename 3 validate() method definitions - -Rename `witness` field to `validator` in `account_validator_vote_operation` (was `account_witness_vote_operation`). Also rename `witness` field to `validator` in `validator_reward_operation` (was `witness_reward_operation`). - -## Task 2: JSON backward-compatibility alias table - -**File:** `libraries/protocol/operation_util_impl.cpp` - -Add a `resolve_operation_name()` function that maps old JSON names to new names: -- `witness_update` → `validator_update` -- `account_witness_vote` → `account_validator_vote` -- `account_witness_proxy` → `account_validator_proxy` -- `shutdown_witness` → `shutdown_validator` -- `witness_reward` → `validator_reward` - -This must be hooked into the `from_variant` path so nodes accept both old and new JSON names from clients. - -## Task 3: Evaluator renames - -**Files:** -- `libraries/chain/include/graphene/chain/chain_evaluator.hpp` — `DEFINE_EVALUATOR(witness_update)` → `DEFINE_EVALUATOR(validator_update)`, same for vote and proxy -- `libraries/chain/chain_evaluator.cpp` — 3 method signatures -- `libraries/chain/chain_properties_evaluators.cpp` — `witness_update_evaluator::do_apply` -- `libraries/chain/database.cpp` — 3 `register_evaluator` calls + all `push_virtual_operation(witness_reward_operation(...))` → `validator_reward_operation(...)` and `push_virtual_operation(shutdown_witness_operation(...))` → `shutdown_validator_operation(...)` - -## Task 4: Chain object renames - -**File:** `libraries/chain/include/graphene/chain/witness_objects.hpp` -- `witness_object` → `validator_object` -- `witness_schedule_object` → `validator_schedule_object` -- `witness_schedule_type` → `validator_schedule_type` -- `current_shuffled_witnesses` → `current_shuffled_validators` -- `witness_index` → `validator_index` -- `witness_id_type` → `validator_id_type` -- `witness_object_type` → `validator_object_type` -- All FC_REFLECT macros - -Also rename the file itself: `witness_objects.hpp` → `validator_objects.hpp` - -**File:** `libraries/chain/include/graphene/chain/chain_objects.hpp` -- `block_post_validation_object` → `validator_confirmation_object` - -**File:** `libraries/chain/include/graphene/chain/chain_object_types.hpp` -- `witness_object_type` → `validator_object_type` -- `witness_schedule_object_type` → `validator_schedule_object_type` - -**Every file that includes `witness_objects.hpp`** must be updated to include `validator_objects.hpp` and use new type names. - -## Task 5: Database layer references - -**Files:** -- `libraries/chain/database.cpp` — all references to witness_object, witness_schedule_object, get_witness_schedule_object(), etc. -- `libraries/chain/database.hpp` — method signatures like `get_witness_schedule_object()` -- `libraries/chain/include/graphene/chain/database.hpp` — same - -Key method renames: -- `get_witness_schedule_object()` → `get_validator_schedule_object()` -- `get_scheduled_witness()` → `get_scheduled_validator()` -- `get_slot_time()`, `get_slot_at_time()` — keep (no "witness") -- `adjust_witness_votes()` → `adjust_validator_votes()` -- `adjust_proxied_witness_votes()` → `adjust_proxied_validator_votes()` - -## Task 6: API object + endpoint renames - -**File:** `libraries/api/include/graphene/api/witness_api_object.hpp` → rename to `validator_api_object.hpp` -- `witness_api_object` → `validator_api_object` - -**File:** `libraries/api/witness_api_object.cpp` — same rename + all field references - -**File:** `plugins/witness_api/plugin.cpp` — rename all 8 API endpoints + add deprecated aliases: -- `get_active_witnesses` → `get_active_validators` (+ keep old as alias) -- `get_witness_schedule` → `get_validator_schedule` (+ keep old as alias) -- `get_witnesses` → `get_validators` (+ keep old as alias) -- `get_witness_by_account` → `get_validator_by_account` (+ keep old as alias) -- `get_witnesses_by_vote` → `get_validators_by_vote` (+ keep old as alias) -- `get_witnesses_by_counted_vote` → `get_validators_by_counted_vote` (+ keep old as alias) -- `get_witness_count` → `get_validator_count` (+ keep old as alias) -- `lookup_witness_accounts` → `lookup_validator_accounts` (+ keep old as alias) - -**File:** `plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp` — update DEFINE_API_ARGS macros - -## Task 7: Wallet renames - -**Files:** -- `libraries/wallet/wallet.cpp` — rename commands, keep old as deprecated aliases -- `libraries/wallet/include/graphene/wallet/wallet.hpp` — method declarations -- `libraries/wallet/include/graphene/wallet/remote_node_api.hpp` — remote API method names - -## Task 8: Plugin directory + config renames - -This involves actual directory renaming which is outside the scope of code editing tools. Manual steps: -- `plugins/witness/` → `plugins/validator/` -- `plugins/witness_api/` → `plugins/validator_api/` -- `plugins/witness_guard/` → `plugins/validator_guard/` -- Update all CMakeLists.txt references -- Update `share/vizd/config/config_witness.ini` → `config_validator.ini` -- Update `share/vizd/config/config.ini` plugin names - -## Task 9: Update documentation - -- `.qoder/docs/witness-to-validator-migration-reference.md` — update status table to "Done" -- `.qoder/docs/op-witness.md` → rename to `op-validator.md` with new operation names -- `.qoder/docs/witness-plugin.md` → rename/rewrite -- `.qoder/docs/data-types.md` — update operation type table - -## Task 10: Build verification - -Compile the entire project to verify no broken references. - -## Execution Order - -Tasks 1-5 must be done together (they're interdependent — renaming a struct breaks all references). Recommended approach: -1. Task 1 (protocol structs) + Task 2 (alias table) together -2. Task 3 (evaluators) — immediately after, since they reference the structs -3. Task 4 (chain objects) — next, largest scope -4. Task 5 (database layer) — after chain objects -5. Task 6 (API) — after database -6. Task 7 (wallet) — after API -7. Task 8 (plugins/config) — last, requires directory renames -8. Task 9 (docs) -9. Task 10 (build verify) - -## Risk Assessment - -- **Binary wire format:** Zero risk — integer type IDs are unchanged -- **JSON compatibility:** The alias table ensures old clients can still submit transactions with old names -- **Shared memory on-disk format:** `witness_object` is serialized to shared memory by type ID, not name — but FC_REFLECT field names ARE serialized in some contexts. Need to verify if renaming FC_REFLECT fields breaks the shared memory format. If it does, a migration layer is needed. -- **Snapshot format:** Snapshots serialize objects as JSON with field names — renaming fields breaks snapshot compatibility with old snapshots diff --git a/.qoder/plans/dlt-p2p-network-redesign_91a7ca29.md b/.qoder/plans/dlt-p2p-network-redesign_91a7ca29.md deleted file mode 100644 index 5ff1e60b16..0000000000 --- a/.qoder/plans/dlt-p2p-network-redesign_91a7ca29.md +++ /dev/null @@ -1,785 +0,0 @@ -# DLT P2P Network Redesign — Analysis & Implementation Plan - -## 1. Current System Analysis - -### 1.1 Existing P2P Architecture (node.cpp — 6978 lines) -The current P2P layer is a general-purpose synopsis-based protocol from Graphene/BitShares with many layers of backwards compatibility: - -- **Hello handshake**: Exchanges node identity, chain state, DLT mode, emergency status via `user_data` fields (already extended for DLT in `generate_hello_user_data` around line 2297). -- **Synopsis sync**: `get_blockchain_synopsis()` builds exponential backoff hash list → peer returns which blocks it doesn't know → `fetch_items` requests batches → `send_sync_block_to_node_delegate` processes them. -- **Inventory gossip**: Normal operation uses `item_ids_inventory_message` to advertise new blocks/transactions. -- **Fork handling**: `fork_rejected_until` soft-ban, `unlinkable_block_strikes`, `sync_spam_strikes` counters. -- **Chain status announcements**: Type 5018 — already carries head, LIB, DLT range, emergency flags. -- **Post-validation**: `block_post_validation_message` (type 6009) lets witnesses signal block confirmation. - -### 1.2 Existing DLT Infrastructure (already built) -| Component | What exists | -|-----------|-------------| -| `dlt_block_log` | Memory-mapped rolling block log with index, `read_block_by_num()`, `head()`, `start_block_num()`, `truncate_before()` | -| `fork_db` | `fetch_block_by_number()`, `fetch_branch_from()`, `compare_fork_branches()` (vote-weighted) | -| `node_delegate` | `is_dlt_mode()`, `get_dlt_earliest_block_num()`, `is_emergency_consensus_active()`, `has_emergency_private_key()` | -| `chain_status_announcement` | Message type 5018 with head/LIB/DLT/emergency fields | -| `witness_plugin` | Minority fork detection, `resync_from_lib()`, fork collision deferral with Level 1 (vote-weight) and Level 2 (timeout) | - -### 1.3 What's Broken/Problematic in node.cpp -- 6978 lines of mostly irrelevant Graphene inheritance -- Synopsis-based sync is overengineered for DLT where blocks are contiguous -- Complex state machine (synopsis→fetch_ids→fetch_items→process) prone to ping-pong loops -- Peer discovery is overcomplicated (potential_peer_db, firewall checks, address gossip) -- Inventory advertisement adds complexity without benefit for block-only DLT -- Soft-ban/strike logic scattered across multiple locations -- Thread model (`P2P_IN_DEDICATED_THREAD`) adds overhead - ---- - -## 2. Proposed Design Analysis - -### 2.1 Core Protocol (Normal Mode) - -**Step 1: Peer registration + discovery** -- **Bootstrap**: Read seed peer endpoints from config (`p2p-seed-node`, already exists in p2p_plugin) -- **Peer discovery via "friends" exchange**: After a node transitions from sync/catchup to forward mode, it becomes eligible to participate in peer discovery. Once every 10 minutes per peer, a node may send a `dlt_peer_exchange_request` ("send me your 'our fork' friends") to any connected peer. The responder replies with `dlt_peer_exchange_reply` containing its known "our fork" peer endpoints (IP:port + node_id). If a peer asks too frequently, the responder sends `dlt_peer_exchange_rate_limited` ("you already asked, wait N seconds"). -- **Peer database**: Simple in-memory set of known peer endpoints, pruned on disconnect. No persistent potential_peer_db, no firewall checks — simpler than the old `peers.json` + `potential_peer_db` machinery. -- **Assessment**: Controlled peer discovery without the complexity of the existing address-gossip system. Rate-limiting (10 min cooldown per peer) prevents flooding while allowing the network to gradually learn about new nodes that join. - -**Step 2: Hello with DLT range + status** -- Send: `[dlt_start, dlt_end]`, head block (num + hash), LIB (num + hash), emergency status, fork status, node status (sync/forward) -- Receiver checks if initiator's head/LIB are in our dlt_block_log or fork_db → flags as "our fork" (exchange enabled, `fork_alignment=true`) or "not our fork" (`fork_alignment=false`) -- **Node status model**: The node has 2 statuses: - - **SYNC**: Catching up — send hello, try to find next continuation after our head, request blocks in ranges. When we reach the top → transition to FORWARD. - - **FORWARD**: Caught up — exchange data with "our fork" peers. If fork detected, get competing blocks and mark peer as "our" or "not our". Don't care if peer's head is above ours. -- **Assessment**: This replaces the existing synopsis approach. Better for DLT. Simplified from the previous 3-state model: - - We don't care about initiator's head being above ours — they're just ahead. - - In sync mode: just get blocks after our head. - - In forward mode: mark peer as "our" or "not our" based on chain link. - - LIB below dlt_start = "unknown" during sync (allow exchange), re-evaluate in forward mode. - - **Keep**: "fork status (not used, but visible in logs)" — valuable for debugging. - -**Step 3: Range query + get request** -- Peer asks: "do you have block X with hash H?" -- We check dlt_block_log: if known, respond with actual available range + wait for specific `get` packet -- `get` packet: block_num + prev_hash (to verify chain link) -- We send: the block + next_available_num (or 0 if none) + sync_status bool -- If sync_status says "last block", flag peer as "our fork" (exchange enabled) -- **Assessment**: This is essentially a binary-search-free sync. Good for DLT. But: - - **Improvement**: The "range query" step could be skipped. Just include the range in hello response. - - **Improvement**: The "prev_hash" check is a good anti-corruption measure. Keep it. - - **Issue**: What if we don't have the requested block? Current design says "we saying that we not have it" — need a `not_available` response type. - -**Step 4: Exchange + retranslation** -- When we receive a block/transaction from "our fork" peer → add to chain + retranslate to all "our fork" peers -- Witnesses send post-validation to accelerate LIB -- **Assessment**: Already implemented via `broadcast_block` + `broadcast_block_post_validation`. The retranslation to "our fork" peers only is a good optimization over broadcast-to-all. - -### 2.2 Fork Resolution (Fork Mode) - -**Key design**: Wait until end of schedule round, then tally vote weights per fork branch. - -**Analysis of the proposed fork resolution**: -- The existing system already has `compare_fork_branches()` in database.cpp (line 1359-1417) which does vote-weighted comparison with +10% longer-chain bonus. -- The user wants to defer fork resolution to schedule round boundaries — this is MORE conservative than the existing Level 1+Level 2 system. -- **Resolution trigger**: Use `num_scheduled_witnesses * 2` blocks (e.g., 21 × 2 = 42 blocks = 2 full rounds) as the fork resolution threshold — same as the existing emergency DLT minority fork detection in witness.cpp (line 722: `CHAIN_MAX_WITNESSES * 2`). This avoids the ambiguity of "end of schedule round" when different forks have diverged at different block heights. When 42 blocks have been produced since the fork was first detected, resolution fires. -- **Improvement needed**: None — this is a clean, proven threshold already used in production code. - -**Data structure: fork_db with `get_all_active_forks()`**: -- The fork_db already supports multiple forks at same height (`fetch_block_by_number()` returns a vector). -- Add `fork_database::get_all_active_branch_tips()` — returns distinct tip IDs for all currently tracked fork branches. -- Each branch is then resolved via the existing `compare_fork_branches()` vote-weighted comparison (database.cpp line 1359-1417). -- **Design decision confirmed**: Use fork_db as the sole fork data structure; no separate "array of arrays". - -**Issue: "Stop producing blocks if in minority fork"** -- Already implemented in witness.cpp minority fork detection (line 648-666) -- The new P2P layer needs to expose a `bool is_on_majority_fork()` query - -### 2.3 Emergency Mode - -The user's emergency design is mostly aligned with existing code: -- Emergency activates when no blocks processed for timeout period (already in `_apply_block` emergency check, database.cpp ~line 5200) -- Reset witness signing keys (already done: `w.signing_key = public_key_type()` at line 5001) -- Free slots go to `committee` account (already: hybrid schedule override at line 2733) -- Nodes with emergency key produce blocks (already: witness_plugin emergency master check) - -**Issue**: "If node in emergency got blocks with emergency witness — auto choose this fork as main head" -- The existing `compare_fork_branches()` already does this: branch with emergency committee blocks wins unconditionally (line 1395-1397) -- **Good**: Aligned with existing logic. - -**Issue**: "LIB moves faster" during emergency -- Already implemented: during emergency, LIB advances every block capped at HEAD-1 (line 5737-5782) -- **Good**: No changes needed. - -### 2.4 Anti-Spam - -"Good packet resets spam counter" — **This is a significant improvement over existing logic.** - -Current system has independent strike counters that only decrement on certain actions. The user's proposal is: -- Each peer has a `spam_strikes` counter -- Any valid block, valid transaction, or valid hello response → reset counter to 0 -- Invalid/duplicate/wrong-fork packets → increment counter -- Counter exceeds threshold → soft-ban - -**Assessment**: Much simpler and more effective than the current multi-counter system. The reset-on-good behavior naturally recovers from transient issues. - -**Recommendation**: Use a single `spam_strikes` per peer instead of the current multiple counters (`unlinkable_block_strikes`, `sync_spam_strikes`, `fetch_ids_rate_limit_strikes`). - -### 2.5 DLT Pruning - -"Remove old blocks every 1000 blocks, keep only `dlt-block-log-max-blocks` (default 100000)" - -The existing `dlt_block_log::truncate_before()` works but is expensive (copies all retained data). - -**Decision: Modify `truncate_before()` to batch-prune 10000 blocks at once instead of 1000.** This reduces copy frequency by 10x while keeping the implementation simple (no ring-buffer refactor needed). The pruning trigger checks every 10000 blocks produced — when `current_head - dlt_start > dlt-block-log-max-blocks`, prune the oldest 10000 blocks in one call. - ---- - -## 3. Design Issues & Improvements - -### 3.1 Peer Discovery via "Friends" Exchange — Design Details - -The user's proposal is: -- After catchup → forward mode, exchange "our fork" peers -- `dlt_peer_exchange_request` message: "send me your friends" -- `dlt_peer_exchange_reply` message: list of known peer endpoints (IP:port + node_id) -- Rate limit: once per 10 minutes per peer -- If asked too soon: `dlt_peer_exchange_rate_limited` ("you already asked, wait N seconds") - -**Improvements over old system**: The existing node.cpp uses: -- `potential_peer_db` (persistent JSON file `peers.json`) -- `address_request_message`/`address_message` gossip -- `firewall_check_state_data` for NAT detection -- Connection disposition tracking (last_connection_succeeded/failed) - -All of this is unnecessary for DLT where we only care about "our fork" peers. The proposed friends exchange is simpler: -- No persistence — peers are discovered through live exchange only -- No firewall checks — DLT nodes are assumed reachable (config-controlled) -- No address gossip — only intentional peer exchange requests -- Rate-limiting prevents abuse (spam counter also applies) - -**Edge cases**: -- New node with only seed peers: after catchup, sends `dlt_peer_exchange_request` to a seed. Seed responds with its known peers. Node connects to new ones. -- Peer disconnects: NOT immediately removed from `_known_peers` set. Instead, the peer is flagged as `disconnected` and reconnection is attempted with an incrementing backoff step (starting at ~30s, doubling each retry, capped at 3600s max). If the peer does not respond for 8 hours (configurable), it is permanently removed from `_known_peers`. -- Self in peer list: receiver filters out its own node_id and already-connected peers. -- All peers exhausted: periodic timer (every ~12 min) picks a random connected peer to re-request. If no new peers found, nothing happens. - -### 3.2 Transaction Propagation Design - -Transactions follow a clear lifecycle: -1. **Ingest**: Transactions enter the system via the `jsonrpc` plugin (API endpoint). -2. **Broadcast**: The node translates (retransmits) the transaction to all "our fork" peers. -3. **Mempool**: A separate in-memory transaction index (mempool) collects and deduplicates pending transactions. -4. **Witness inclusion**: When a witness creates a block and includes the transaction, the block is broadcast. -5. **Dedup on block receipt**: When we receive a block containing a transaction that is in our mempool, we remove that transaction from the mempool (we have a separate index for working with transactions). -6. **Retranslation**: If we receive a new transaction from an "our fork" peer, we retranslate it to all other "our fork" peers (excluding the sender). - -This provides natural deduplication: transactions are tracked in the mempool until they appear in a confirmed block, then pruned. - -**Transaction expiry pruning**: Transactions have an `expiration` field (`fc::time_point_sec`). Expired transactions MUST be pruned from the P2P mempool — they will never be included in a block. The P2P layer checks mempool entries periodically and removes any where `expiration < now`. - -**Transaction fork linkage (TaPoS)**: Transactions reference a specific block via `ref_block_num` + `ref_block_prefix` (TaPoS — Transactions as Proof of Stake). The chain validates this in `_apply_transaction()` (database.cpp:4547-4554) by checking against `block_summary_object`. If `ref_block_num` points to a block NOT in our fork (e.g., on a competing fork), the TaPoS check fails → the transaction is invalid for us. **Therefore**: when we switch forks or detect that a transaction's `ref_block_num` references a block not on our chain, we MUST prune that transaction from the P2P mempool. - -**Current system already has these mechanisms (but at the chain level, not P2P level)**: -- `_pending_tx` (database.hpp:504): `vector` — the witness mempool. Used during `generate_block()` to select transactions for the next block. -- `transaction_object` / `transaction_index` (transaction_object.hpp): Chainbase persistent index with `by_trx_id` (hashed, for dedup) and `by_expiration` (ordered, for cleanup). Created when a transaction is included in a block. -- `clear_expired_transactions()` (database.cpp:5944-5953): Already prunes expired `transaction_object` entries during block processing. -- TaPoS check (database.cpp:4547-4554): Verifies `ref_block_num`/`ref_block_prefix` against `block_summary_object`. Rejects transactions referencing unknown/fork blocks. - -**The new DLT P2P mempool is SEPARATE from the chain's `_pending_tx`**: The P2P mempool sits at the network layer (before chain acceptance). It needs its own expiry + fork-alignment pruning because the chain's mechanisms only apply after a transaction is accepted into `_pending_tx`. A transaction that arrives from a peer might be expired or reference a fork block — we should prune it at the P2P layer before even trying to push it to the chain. - -**Comparison with old P2P transaction flow**: The old P2P does NOT work the same way. The old flow uses: -- **Inventory gossip**: Advertises transaction IDs via `item_ids_inventory_message` → peer requests if missing. Not direct relay. -- **No separate mempool**: Chain's `accept_transaction()` handles dedup internally — no explicit P2P-level mempool index. -- **Broadcast to ALL peers**: `node->broadcast(trx_message(tx))` sends to every connected peer, not just "our fork". -- **No mempool pruning**: When a transaction appears in a block, there's no explicit removal from a P2P mempool — the chain just won't accept it again. -- **No expiry pruning at P2P level**: Expired transactions are only cleaned up by the chain's `clear_expired_transactions()`, not at the P2P layer. - -The new DLT P2P flow is simpler and more efficient: direct relay (no inventory gossip), separate P2P mempool index (explicit dedup, expiry pruning, and fork-alignment pruning), and targeted broadcast ("our fork" peers only). - -### 3.3 Initial Sync / Gap Filling - -**DLT stores only the top head block range** — older blocks are pruned. For example, if the node holds blocks [200..500], blocks [1..199] are already pruned and NOT stored. This is how DLT works: only the latest `dlt-block-log-max-blocks` range is retained. - -**Bulk get with last-block-info**: The `get` request works in bulk (request a range of blocks). The reply includes the requested blocks PLUS additional info only about the **last block in the bulk** (its hash, next_available, sync_status). This keeps replies compact. - -**Gap handling for new/recovery nodes**: -- A new or recovering node tries to fetch all needed blocks from known peers. -- If a gap is discovered (missing blocks that no connected peer has), the node MUST **reset its state** and go forward by **importing a snapshot from trusted peers**. -- There is no partial gap-filling across disconnected ranges — either the chain is contiguous from the peer's perspective, or the node resyncs from a snapshot. - -### 3.4 IMPORTANT: Multiple Simultaneous Peers -The proposal describes 1:1 exchange but not multi-peer coordination: -- What if peer A gives us block 100 and peer B gives us a different block 100? -- The fork_db handles this, but the P2P layer needs to know when to stop requesting from a peer -- **Recommendation**: Track per-peer "last good block" and prefer peers that give us chain-extending blocks - -### 3.5 IMPORTANT: "Our fork" determination and Node Sync/Forward Model - -The node operates in two primary statuses: - -**1. SYNC status** (catching up): -- We send hello to peers and try to find the next continuation after our head block. -- We request blocks in ranges after our head from connected peers. -- When we reach the top (head = no more blocks available from any peer) → transition to FORWARD status. -- During sync, we don't care about fork alignment — we just need blocks that continue our chain. - -**2. FORWARD status** (caught up, exchanging data): -- We exchange blocks and transactions with "our fork" peers. -- If a fork is detected (block doesn't link to our head), we try to get the competing blocks. -- The competing blocks may be true for our consensus or false — it's OK, we just need to **mark this peer as "our" or "not our"**. -- "Our fork" peer = their head or LIB hash is in our `dlt_block_log` or `fork_db`. -- "Not our fork" peer = their blocks don't link to anything we know. - -**We don't care if initiator's head is above ours** — they're just ahead, that's fine. Strange things happen on the network. - -**Fork status during forward mode**: -- `fork_status = 0` (normal): Peer's blocks extend our chain → "our fork", full exchange. -- `fork_status = 1` (looking_resolution): Peer's blocks create a fork → still exchange, but mark peer. Let `fork_db` + vote-weight resolution determine winner. -- `fork_status = 2` (minority): We're on the losing fork → stop producing, switch. - -**Edge case: initiator's LIB is below our dlt_start**: We can't verify their fork alignment → treat as "unknown" during sync (allow exchange to get blocks). Once in forward mode, re-evaluate after we have their blocks. - -### 3.6 Color-Coded Logging — Good Design -Existing color codes already defined (line 79-83 in node.cpp): -``` -CLOG_RED = fork blocks -CLOG_ORANGE = warnings -CLOG_GRAY = transactions -CLOG_GREEN = sync/production -CLOG_CYAN = diagnostics -``` -The user's proposal adds: -- Green: sync start, catchup, block production -- White: normal block exchange from our fork -- Red: fork block exchange -- Dark gray: transaction exchange - -**Assessment**: These map well to existing colors. Just need consistency. - -### 3.7 Security Hardening (from AI Review) - -**P0 — Mempool DoS protection**: Hard mempool size limits with eviction policy: -- `max_transactions` (default 10000) — hard cap on mempool entries -- `max_memory_bytes` (default 100MB) — hard cap on total mempool memory -- `max_tx_size` (default 64KB) — reject oversized transactions at P2P layer -- `max_expiration_headroom` (default 24h) — reject transactions with `expiration` too far in the future -- Eviction policy: when caps are hit, evict oldest-expiry transactions first -- All rejections increment sender's `spam_strikes` - -**P1 — Peer exchange poisoning protection**: Anti-sybil diversity requirements: -- `max_peers_per_subnet` (default 2 per /24) — prevent same-subnet domination -- `max_accept_from_exchange` (default 10 peers per exchange reply) — cap to prevent single-reply flooding -- `min_uptime_for_exchange` (default 600s) — peer must be connected and stable before its endpoint is shared in exchange replies -- Filter exchange replies: remove peers from same subnet if limit reached, cap reply size - -**P1 — Fork resolution hysteresis**: The 42-block window alone can create a decision race at the boundary where both forks briefly appear as winners during network partition. Add confirmation requirement: -- After the 42-block window, compute the vote-weight winner -- The winner must maintain its lead for `CONFIRMATION_BLOCKS` (6) consecutive blocks before we execute the fork switch -- If the lead flips during confirmation, reset the counter — prevents premature switching - -**P1 — Block validation ordering**: The `prev_block_id` check prevents chain link corruption, but we also need: -- `block.previous` must exist in our `fork_db` or `dlt_block_log` — reject blocks that reference unknown ancestors (prevents circular dependencies and future-reference attacks) -- Per-peer `expected_next_block` tracking — reject blocks that skip too far ahead (prevents hole-creation attacks) -- Blocks received but not yet validated: track with `pending_block_batch` timeout (30s) — if validation doesn't complete, soft-ban the peer - -**P2 — Sync-to-forward transition race**: "No more blocks available from any peer" is ambiguous during temporary disconnects. Add sync stagnation detection: -- Track `last_block_received_time` during sync -- If no new block for `SYNC_STAGNATION_SEC` (30s), re-request from all connected peers (up to 3 retries) -- If still stagnated after retries → transition to FORWARD with warning log -- Prevents getting stuck in SYNC due to transient network issues - -**P2 — Reconnection backoff amplification**: Add jitter and reset conditions: -- Add random jitter (±25% of backoff interval) to prevent synchronized reconnection storms -- Reset `reconnect_backoff_sec` to initial value (30s) when a connection stays stable for > 5 minutes — prevents persistent long backoff from transient disconnects - -**P2 — Transaction fork-awareness during sync**: Transactions received during SYNC mode reference a chain that may get reorganized during catchup. Tag them as provisional: -- `mempool_entry.is_provisional = true` for transactions received during sync -- `mempool_entry.expected_head` = our head at time of receipt -- On SYNC→FORWARD transition: revalidate all provisional entries against final chain, prune those whose TaPoS is now invalid - -**P3 — Protocol version negotiation**: Add `protocol_version` field to `dlt_hello_message` (start at 1). Peers with different major versions disable exchange. Allows future protocol upgrades without breaking compatibility. - -**P3 — Peer lifecycle state machine**: Explicit states with timeouts: -- `connecting` (5s timeout) → `handshaking` (10s timeout) → `syncing` → `active` → `disconnected` (backoff) → `banned` (duration from spam threshold) -- Each transition has a timeout — if stuck in any intermediate state, disconnect and move to `disconnected` - ---- - -## 4. Implementation Plan - -### Phase 1: New Message Types (libraries/network/include/graphene/network/) - -**Task 1.1**: Define new message types in `core_messages.hpp` (after type 5018): -``` -dlt_hello_message_type = 5100 // replaces hello for DLT peers -dlt_hello_reply_message_type = 5101 // response to dlt_hello -dlt_range_request_message_type = 5102 // "do you have block N?" -dlt_range_reply_message_type = 5103 // "yes, my range is [S..E]" -dlt_get_block_range_message_type = 5104 // "send me blocks [N..M]" (bulk fetch) -dlt_block_range_reply_message_type = 5105 // blocks [N..M] + last-block info only -dlt_get_block_message_type = 5106 // "send me block N, prev=H" (single block) -dlt_block_reply_message_type = 5107 // block + next_available + sync_status -dlt_not_available_message_type = 5108 // "I don't have that block" -dlt_fork_status_message_type = 5109 // fork resolution status -dlt_peer_exchange_request_type = 5110 // "send me your 'our fork' friends" -dlt_peer_exchange_reply_type = 5111 // list of known peer endpoints -dlt_peer_exchange_rate_limited_type = 5112 // "you already asked, wait N sec" -dlt_transaction_message_type = 5113 // broadcast new transaction to peers -``` - -**Task 1.2**: Define message structs: - -```cpp -// DLT Hello — sent on connection -struct dlt_hello_message { - uint16_t protocol_version; // start at 1; major version mismatch disables exchange - block_id_type head_block_id; - uint32_t head_block_num; - block_id_type lib_block_id; - uint32_t lib_block_num; - uint32_t dlt_earliest_block; // our dlt_block_log start - uint32_t dlt_latest_block; // our dlt_block_log end (head) - bool emergency_active; - bool has_emergency_key; - uint8_t fork_status; // 0=normal, 1=looking_resolution, 2=minority - uint8_t node_status; // 0=sync (catching up), 1=forward (caught up, exchanging) -}; - -// DLT Hello Reply — response to hello -struct dlt_hello_reply_message { - bool exchange_enabled; // "our fork" = true - bool fork_alignment; // true = peer's blocks link to ours, false = not our fork - block_id_type initiator_head_seen; // which of initiator's blocks we recognize - block_id_type initiator_lib_seen; - uint32_t our_dlt_earliest; - uint32_t our_dlt_latest; - uint8_t our_fork_status; - uint8_t our_node_status; // 0=sync, 1=forward -}; - -// Block range request (bulk fetch) -struct dlt_get_block_range_message { - uint32_t start_block_num; - uint32_t end_block_num; - block_id_type prev_block_id; // hash of block (start-1) for chain link verification -}; - -// Block range reply — reply includes all blocks + info only about the LAST block -struct dlt_block_range_reply_message { - std::vector blocks; - uint32_t last_block_next_available; // next block after last in range (0=none) - bool is_last; // true = last block we have, peer fully synced -}; - -// Transaction broadcast -struct dlt_transaction_message { - signed_transaction trx; -}; - -// Single block request (non-bulk, for individual blocks) -struct dlt_get_block_message { - uint32_t block_num; - block_id_type prev_block_id; // to verify chain link -}; - -// Single block reply -struct dlt_block_reply_message { - signed_block block; - uint32_t next_available; // 0 = no more blocks - bool is_last; // true = last block we have, peer fully synced -}; - -// Not available -struct dlt_not_available_message { - uint32_t block_num; -}; - -// Peer exchange request — "send me your 'our fork' friends" -// Rate-limited: responder ignores if asked more than once per 10 min -struct dlt_peer_exchange_request { - // empty — the request itself implies intent -}; - -// Peer exchange reply — list of known "our fork" peer endpoints -struct dlt_peer_exchange_reply { - struct peer_endpoint_info { - fc::ip::endpoint endpoint; - node_id_t node_id; - }; - std::vector peers; -}; - -// Rate-limit response — "you already asked, wait N seconds" -struct dlt_peer_exchange_rate_limited { - uint32_t wait_seconds; // how long until next allowed request -}; -``` - -### Phase 2: New DLT P2P Node Class (libraries/network/) - -**Task 2.1**: Create `dlt_p2p_node.hpp` — new class `dlt_p2p_node`: -- Peer array from config (seeds) + dynamically discovered peers -- Per-peer state: `dlt_peer_state` struct - - `node_status` (0=sync, 1=forward) - - `exchange_enabled` (our fork) - - `fork_alignment` (true = blocks link to ours) - - `peer_head_num`, `peer_head_id`, `peer_lib_num`, `peer_lib_id` - - `peer_dlt_range_start`, `peer_dlt_range_end` - - `peer_emergency_active`, `peer_has_emergency_key` - - `peer_node_status` (0=sync, 1=forward) - - `spam_strikes` (single counter, reset on good packet) - - `last_good_packet_time` - - `last_peer_exchange_request_time` (per-peer rate-limit, 600s cooldown) - - `pending_requests` (what we asked this peer for) - - `expected_next_block` (for block ordering validation) - - `pending_block_batches` (blocks received but not yet validated, with 30s timeout) - - `last_connection_duration` (for backoff reset on stable connections > 5min) - - **Peer lifecycle state machine**: - - `peer_lifecycle_state` (connecting → handshaking → syncing → active → disconnected → banned) - - Each intermediate state has a timeout (connecting=5s, handshaking=10s) - - Timeout → disconnect and move to `disconnected` - - **Reconnection tracking**: - - `connection_state` (connected / disconnected / banned) - - `disconnected_since` (fc::time_point, set on disconnect) - - `next_reconnect_attempt` (fc::time_point, incrementing backoff) - - `reconnect_backoff_sec` (starts at 30s, doubles each retry, capped at 3600s) -- `_known_peers`: in-memory set of `{fc::ip::endpoint, node_id_t}` — non-persistent. Peers are NOT immediately removed on disconnect; they are flagged `disconnected` and reconnection is attempted with backoff. A peer is permanently removed only after **8 hours of continuous non-response** (configurable via `dlt-peer-max-disconnect-hours`). -- Main loop: process incoming messages, periodic peer discovery (every ~10 min send exchange request to one peer), periodic reconnection attempts for disconnected peers. -- **Node status transitions**: - - Start in SYNC mode: send hello to peers, request blocks after our head. - - SYNC → FORWARD: when no more blocks available from any peer (reached the top), transition to FORWARD and start exchanging data + enable peer discovery. - - FORWARD → SYNC: if we detect a long fork or need to resync (rare, e.g. after snapshot import). -- No dedicated thread — use fc::asio or simple poll loop - -**Task 2.2**: Create `dlt_p2p_node.cpp` — implement: - -**Normal mode handlers**: -``` -on_dlt_hello() → check peer's chain link to ours; set fork_alignment; if our node is SYNC, request blocks after our head; if FORWARD, mark peer as "our"/"not our"; check protocol_version compatibility -on_dlt_hello_reply() → if exchange_enabled && fork_alignment, start catching up (if SYNC) or begin exchange (if FORWARD) -on_dlt_get_block_range() → bulk fetch: request blocks [N..M], reply with blocks + last-block info only -on_dlt_block_range_reply() → validate prev_hash link on first block, validate block ordering (previous must be known), push all to chain, retranslate; if last block reached and we're SYNC → transition to FORWARD -on_dlt_get_block() → read from dlt_block_log, send block_reply or not_available -on_dlt_block_reply() → validate prev_hash link, validate block ordering, push to chain, retranslate -on_dlt_transaction() → add to P2P mempool (dedup by tx_id, check expiry, check TaPoS fork alignment, check size limits), retranslate to all "our fork" peers (excl. sender) -on_dlt_peer_exchange_request() → if peer asked in last 600s, send rate_limited; else send our known "our fork" peers (filtered: min_uptime, subnet diversity, cap reply size) -on_dlt_peer_exchange_reply() → add received peer endpoints to our known-peers set (filtered: subnet diversity, cap per reply), attempt connections to new ones -on_block_added_to_chain() → remove any transactions in this block from P2P mempool (separate mempool index); if fork switch occurred, prune transactions whose `ref_block_num` is not on our fork -transition_to_forward() → when sync reaches top (no more blocks from any peer, or sync stagnation timeout): set node_status=FORWARD, start exchange, enable peer discovery; revalidate provisional mempool entries -periodic_mempool_cleanup() → prune expired transactions (`expiration < now`) and TaPoS-invalid transactions (`ref_block_num` not on our fork) from P2P mempool; enforce mempool size limits with eviction -sync_stagnation_check() → if no new block for 30s during sync, re-request from all peers (up to 3 retries); if still stagnated → transition_to_forward with warning -peer_lifecycle_timeout() → check peer lifecycle state timeouts (connecting=5s, handshaking=10s); if stuck, disconnect and move to disconnected -block_validation_timeout() → if pending_block_batch not validated within 30s, soft-ban the peer that sent it -``` - -**Peer discovery logic**: -```cpp -// Per-peer rate-limit tracking -fc::time_point _last_peer_exchange_request_time; -static constexpr uint32_t PEER_EXCHANGE_COOLDOWN_SEC = 600; // 10 minutes - -void dlt_p2p_node::on_dlt_peer_exchange_request(peer_id peer) { - auto now = fc::time_point::now(); - if (_last_peer_exchange_request_time != fc::time_point() && - now - _last_peer_exchange_request_time < fc::seconds(PEER_EXCHANGE_COOLDOWN_SEC)) { - uint32_t wait = PEER_EXCHANGE_COOLDOWN_SEC - - (now - _last_peer_exchange_request_time).count() / 1000000; - send_message(peer, dlt_peer_exchange_rate_limited{wait}); - return; - } - _last_peer_exchange_request_time = now; - - // Collect "our fork" peers (exchange_enabled=true, in FORWARD mode) - std::vector friends; - for (auto& [id, state] : _peer_states) { - if (state.exchange_enabled && state.node_status == NODE_STATUS_FORWARD) { - friends.push_back({state.endpoint, id}); - } - } - send_message(peer, dlt_peer_exchange_reply{friends}); -} - -void dlt_p2p_node::on_dlt_peer_exchange_reply(const dlt_peer_exchange_reply& reply) { - for (auto& info : reply.peers) { - if (!is_known_peer(info.node_id) && !is_connected_to(info.node_id)) { - _known_peers.insert(info); - // Attempt connection if under max_connections - if (_active_connections.size() < _max_connections) { - connect_to_peer(info.endpoint); - } - } - } -} - -// Reconnection logic for disconnected peers -void dlt_p2p_node::handle_disconnect(peer_id peer) { - auto& state = _peer_states[peer]; - state.peer_lifecycle_state = PEER_LIFECYCLE_DISCONNECTED; - state.disconnected_since = fc::time_point::now(); - - // Reset backoff to initial if the connection was stable (>5 min) - if (state.last_connection_duration > 300) { // 5 minutes stable - state.reconnect_backoff_sec = INITIAL_RECONNECT_BACKOFF_SEC; // 30s - } - - state.reconnect_backoff_sec = std::min(state.reconnect_backoff_sec * 2, MAX_RECONNECT_BACKOFF_SEC); // capped at 3600s - - // Add random jitter (±25%) to prevent synchronized reconnection storms - uint32_t jitter = (rand() % (state.reconnect_backoff_sec / 2)) - (state.reconnect_backoff_sec / 4); - state.next_reconnect_attempt = fc::time_point::now() + fc::seconds(state.reconnect_backoff_sec + jitter); - // Do NOT remove from _known_peers — peer stays known for reconnection -} - -void dlt_p2p_node::periodic_reconnect_check() { - auto now = fc::time_point::now(); - auto expire_threshold = now - fc::hours(PEER_MAX_DISCONNECT_HOURS); // 8 hours default - - for (auto it = _known_peers.begin(); it != _known_peers.end(); ) { - auto& state = _peer_states[it->node_id]; - if (state.peer_lifecycle_state == PEER_LIFECYCLE_DISCONNECTED) { - // Permanently remove if no response for 8 hours - if (state.disconnected_since < expire_threshold) { - wlog("Removing peer ${p} after ${h}h of non-response", ("p", it->node_id)("h", PEER_MAX_DISCONNECT_HOURS)); - it = _known_peers.erase(it); - _peer_states.erase(it->node_id); - continue; - } - // Attempt reconnection if backoff timer has elapsed - if (now >= state.next_reconnect_attempt && _active_connections.size() < _max_connections) { - ilog("Attempting reconnect to peer ${p} (backoff=${b}s)", ("p", it->node_id)("b", state.reconnect_backoff_sec)); - connect_to_peer(it->endpoint); - } - } - ++it; - } -} -``` - -**Fork mode handlers**: -``` -check_fork_resolution_needed() → called each block; if multiple forks exist, set fork_status=looking_resolution -resolve_fork_at_round_end() → called when schedule round completes; tally vote weights per fork branch -``` - -**Emergency mode handlers**: -``` -on_emergency_status_change() → update peer flags, adjust fork choice priority -``` - -**Task 2.3**: Anti-spam implementation: -```cpp -bool dlt_p2p_node::record_packet_result(peer_id peer, bool is_good) { - if (is_good) { - peer_state[peer].spam_strikes = 0; - peer_state[peer].last_good_packet_time = now(); - return true; - } - peer_state[peer].spam_strikes++; - if (peer_state[peer].spam_strikes >= SPAM_THRESHOLD) { - soft_ban_peer(peer, BAN_DURATION); - return false; - } - return true; -} -``` - -### Phase 3: P2P Plugin Replacement (plugins/p2p/) - -**Task 3.1**: Replace `p2p_plugin_impl` in `p2p_plugin.cpp` — swap internal implementation: -- Appbase plugin requiring `chain::plugin` (same as current) -- Replace internal `graphene::network::node` with `dlt_p2p_node` -- Configuration: keep `p2p-endpoint` (port 2001/4243), `p2p-seed-node`; add `dlt-block-log-max-blocks`, `dlt-peer-max-disconnect-hours`, `dlt-mempool-max-tx`, `dlt-mempool-max-bytes`, `dlt-mempool-max-tx-size`, `dlt-mempool-max-expiration-hours`, `dlt-peer-exchange-max-per-reply`, `dlt-peer-exchange-max-per-subnet`, `dlt-peer-exchange-min-uptime-sec` -- Remove old config: `p2p-stats-enabled`, `p2p-stats-interval`, `p2p-stale-sync-detection`, `p2p-stale-sync-timeout-seconds` (replaced by built-in DLT mechanisms) -- Public API stays identical: `broadcast_block()`, `broadcast_block_post_validation()`, `broadcast_transaction()`, `broadcast_chain_status()`, `set_block_production()`, `resync_from_lib()`, `trigger_resync()`, `get_connections_count()`, `reconnect_seeds()`, `pause_block_processing()`, `resume_block_processing()`, `get_last_network_block_time()` -- **Transaction lifecycle**: - - Transactions enter via `jsonrpc` plugin → added to P2P mempool (separate in-memory index, dedup by tx_id) - - On receipt: check expiry (`expiration < now` → discard), check TaPoS fork alignment (`ref_block_num` not on our fork → discard) - - Broadcast transaction to all "our fork" peers (excl. sender) - - On new block (witness produces): broadcast block to all "our fork" peers - - On block receipt: remove any transactions in this block from P2P mempool (using separate mempool index) - - On fork switch: prune P2P mempool transactions whose `ref_block_num` is not on our fork -- Periodic: prune P2P mempool (expired + TaPoS-invalid), prune dlt_block_log (batch-prune 10000 at a time via `truncate_before()`), update peer status, reconnect to disconnected peers (backoff 30s→…→3600s), resolve forks, remove stale peers (8h non-response) - -**Task 3.2**: Color-coded console logging: -```cpp -#define DLT_LOG_GREEN "\033[32m" // sync, production -#define DLT_LOG_WHITE "\033[37m" // normal block exchange -#define DLT_LOG_RED "\033[91m" // fork block -#define DLT_LOG_DGRAY "\033[90m" // transaction exchange -#define DLT_LOG_RESET "\033[0m" - -// Usage: -ilog(DLT_LOG_GREEN "Starting sync from peer ${p}" DLT_LOG_RESET, ("p", peer)); -ilog(DLT_LOG_WHITE "Got block #${n} from our fork peer ${p}" DLT_LOG_RESET, ("n", num)("p", peer)); -ilog(DLT_LOG_RED "FORK: Got block #${n} from ${p} — does NOT link to our head!" DLT_LOG_RESET, ("n", num)("p", peer)); -ilog(DLT_LOG_DGRAY "Got transaction ${id} from ${p}" DLT_LOG_RESET, ("id", txid)("p", peer)); -``` - -### Phase 4: Fork Resolution Implementation - -**Task 4.1**: Fork resolution trigger (confirmed: `num_scheduled_witnesses * 2`): -```cpp -// Fork resolution fires after 42 blocks (2 full rounds) since first detection. -// Same threshold as emergency DLT minority fork detection (CHAIN_MAX_WITNESSES * 2). -static constexpr uint32_t FORK_RESOLUTION_BLOCK_THRESHOLD = CHAIN_MAX_WITNESSES * 2; - -struct fork_branch_info { - block_id_type tip; - std::vector blocks; // blocks in this branch - std::set witnesses; - share_type total_vote_weight; - bool has_emergency_blocks; - uint32_t block_count; -}; - -// Called each time a block is applied: -void dlt_p2p_node::track_fork_state(const signed_block& block) { - auto competing = fork_db.fetch_block_by_number(block.block_num()); - if (competing.size() > 1) { - if (!_fork_detected) { - _fork_detected = true; - _fork_detection_block_num = block.block_num(); - } - } - - // Resolution trigger: 42 blocks (2 rounds) since fork was first detected - if (_fork_detected && block.block_num() - _fork_detection_block_num >= FORK_RESOLUTION_BLOCK_THRESHOLD) { - resolve_fork(); - _fork_detected = false; - } -} -``` - -**Task 4.2**: Fork resolution logic (uses confirmed `fork_db.get_all_active_branch_tips()` + existing `compare_fork_branches()` + hysteresis confirmation): -```cpp -struct fork_resolution_state { - block_id_type current_winner_tip; - uint32_t consecutive_blocks_as_winner = 0; - static constexpr uint32_t CONFIRMATION_BLOCKS = 6; // Must maintain lead for 6 blocks - - bool is_confirmed() const { - return consecutive_blocks_as_winner >= CONFIRMATION_BLOCKS; - } -}; - -void dlt_p2p_node::resolve_fork() { - // Get all distinct branch tips from fork_db - auto branch_tips = fork_db.get_all_active_branch_tips(); - if (branch_tips.size() < 2) return; // no fork to resolve - - fork_branch_info winner; - share_type max_weight = 0; - - for (auto& tip : branch_tips) { - auto info = compute_branch_info(tip, fork_db); - // +10% bonus to longer chain (reuses existing compare_fork_branches logic) - if (info.block_count > winner.block_count) { - info.total_vote_weight += info.total_vote_weight / 10; - } - if (info.total_vote_weight > max_weight) { - max_weight = info.total_vote_weight; - winner = info; - } - } - - // Hysteresis: winner must maintain lead for CONFIRMATION_BLOCKS before we switch - if (winner.tip == _fork_state.current_winner_tip) { - _fork_state.consecutive_blocks_as_winner++; - } else { - _fork_state.current_winner_tip = winner.tip; - _fork_state.consecutive_blocks_as_winner = 1; - } - - if (!_fork_state.is_confirmed()) { - ilog(DLT_LOG_ORANGE "Fork resolution: candidate ${t} has ${n}/${c} confirmations", - ("t", winner.tip)("n", _fork_state.consecutive_blocks_as_winner)("c", fork_resolution_state::CONFIRMATION_BLOCKS)); - return; // Not confirmed yet, wait - } - - if (our_head_is_on_branch(winner)) { - // We're on the majority fork — continue - _fork_status = FORK_STATUS_NORMAL; - ilog(DLT_LOG_GREEN "Fork resolved: we are on majority fork (weight=${w})" DLT_LOG_RESET, ("w", max_weight)); - } else { - // We're on minority fork — switch or stop producing - _fork_status = FORK_STATUS_MINORITY; - wlog(DLT_LOG_RED "We are on MINORITY fork! Stopping production, switching to majority." DLT_LOG_RESET); - switch_to_branch(winner.tip); - notify_witness_plugin_minority_fork(); - } - - // Reset hysteresis state after resolution - _fork_state = fork_resolution_state{}; -} -``` - -### Phase 5: In-Place Replacement (No Additional Port) - -The new DLT P2P system **replaces** the old `node.cpp`-based P2P — it does NOT run alongside it on a separate port. Reasons: -- Old P2P and new DLT P2P use different wire protocols (old: Graphene hello/synopsis/inventory; new: DLT hello/range/exchange types 5100-5113). They cannot communicate with each other — running both on different ports creates two isolated sub-networks. -- All witnesses can switch simultaneously (system is in emergency mode), so no gradual migration period is needed. -- The `witness` and `witness_guard` plugins have hard dependencies on `p2p_plugin` via `APPBASE_PLUGIN_REQUIRES`. Replacing the internals avoids any changes to those plugins. - -**Task 5.1**: Replace `p2p_plugin` implementation in-place: -- Keep the same plugin name `"p2p"` and class name `p2p_plugin` -- Keep the same public API: `broadcast_block()`, `broadcast_block_post_validation()`, `broadcast_transaction()`, `broadcast_chain_status()`, `set_block_production()`, `resync_from_lib()`, `trigger_resync()`, `get_connections_count()`, `reconnect_seeds()`, `pause_block_processing()`, `resume_block_processing()`, `get_last_network_block_time()` -- Replace internal `p2p_plugin_impl` (which wraps `graphene::network::node`) with a new impl that wraps `dlt_p2p_node` -- Keep the same `p2p-endpoint` config option (default port 2001 mainnet, 4243 testnet) -- Keep `p2p-seed-node` config option (seed peers) -- Add new config options: `dlt-block-log-max-blocks`, `dlt-peer-max-disconnect-hours`, `dlt-mempool-max-tx`, `dlt-mempool-max-bytes`, `dlt-mempool-max-tx-size`, `dlt-mempool-max-expiration-hours`, `dlt-peer-exchange-max-per-reply`, `dlt-peer-exchange-max-per-subnet`, `dlt-peer-exchange-min-uptime-sec` -- Remove old config options that are no longer relevant: `p2p-stats-enabled`, `p2p-stats-interval`, `p2p-stale-sync-detection`, `p2p-stale-sync-timeout-seconds` (replaced by built-in DLT mechanisms) -- `witness`, `witness_guard`, and `snapshot` plugins require **zero code changes** — they consume the same `p2p_plugin` interface - -**Task 5.2**: Remove old `node.cpp`-based code paths: -- `p2p_plugin_impl` no longer inherits from `graphene::network::node_delegate` -- The `graphene::network::node` class and `node.cpp` are no longer used by the plugin (can be kept in the library for reference but not linked into the build) -- Old message types (synopsis, inventory gossip, etc.) are no longer processed - -**Task 5.3**: Testing: -- Unit tests for message serialization -- Integration test: 3-node network with fork injection -- Emergency mode activation test -- Anti-spam threshold test -- Verify witness plugin works with replaced p2p_plugin (no API changes) - ---- - -## 5. Summary of Improvements Needed in User's Proposal - -| Issue | Proposed Fix | -|-------|-------------| -| Transaction propagation definition | CONFIRMED: jsonrpc → P2P mempool → all "our fork" peers. Dedup when block confirms transaction (separate mempool index). Expired transactions pruned from P2P mempool. TaPoS fork-alignment check: if `ref_block_num` is not on our fork → prune from P2P mempool. | -| Single-block fetch is slow for bulk sync | CONFIRMED: Bulk `get_range` with info only about last block in the bulk. | -| "End of schedule round" ambiguous during forks | CONFIRMED: Use `num_scheduled_witnesses * 2` (42 blocks = 2 rounds), same threshold as existing emergency DLT minority fork detection. | -| "Our fork" determination needs 3 states | CONFIRMED: Node has 2 statuses (sync/forward). In sync: just get blocks after our head. In forward: mark peer as "our" or "not our" based on chain link. Don't care if peer is ahead. LIB below dlt_start = "unknown" during sync, re-evaluate in forward mode. | -| Peer disconnect handling | CONFIRMED: Flag disconnected, reconnect with incrementing backoff (30s→60s→…→3600s max). Remove after 8 hours of non-response. | -| dlt_block_log pruning is expensive | CONFIRMED: Modify `truncate_before()` to batch-prune 10000 blocks at once instead of 1000. | -| DLT gap filling / initial sync | CONFIRMED: DLT stores only top head range. Gaps → reset state + import snapshot from trusted peers. | -| Dual-mode migration with additional port | CONFIRMED: No additional port needed. In-place replacement — keep same `p2p` plugin name, same `p2p-endpoint` port (2001/4243), same public API. Replace internals only (`node.cpp` → `dlt_p2p_node`). `witness`/`witness_guard`/`snapshot` plugins require zero changes. | -| Mempool DoS protection | P0: Hard size limits (max_transactions=10000, max_memory=100MB, max_tx_size=64KB), max expiration 24h, eviction by oldest-expiry | -| Peer exchange poisoning | P1: Anti-sybil: max 2 peers per /24 subnet, max 10 peers per exchange reply, min 600s uptime before sharing | -| Fork resolution race condition | P1: Add hysteresis — winner must maintain lead for 6 consecutive blocks after 42-block window before switch executes | -| Block validation ordering | P1: block.previous must be known, per-peer expected_next_block tracking, pending_block_batch 30s timeout | -| Sync-to-forward transition race | P2: Sync stagnation detection — 30s no-block timeout, 3 retries, then transition with warning | -| Reconnection backoff amplification | P2: Add jitter (±25%), reset backoff on stable connection > 5min | -| Transaction fork-awareness during sync | P2: Tag sync-mode transactions as provisional, revalidate on SYNC→FORWARD transition | -| Protocol version negotiation | P3: `protocol_version` field in hello, major version mismatch disables exchange | -| Peer lifecycle state machine | P3: connecting(5s)→handshaking(10s)→syncing→active→disconnected→banned with timeouts | - ---- - -## 6. File Structure - -``` -libraries/network/ -├── include/graphene/network/ -│ ├── dlt_p2p_messages.hpp # New message types -│ ├── dlt_p2p_node.hpp # New node class -│ └── dlt_p2p_peer_state.hpp # Per-peer state struct -├── dlt_p2p_messages.cpp # Message serialization -├── dlt_p2p_node.cpp # Core network logic -└── CMakeLists.txt # Updated - -plugins/p2p/ # In-place replacement — same plugin name, same API -├── include/graphene/plugins/p2p/ -│ └── p2p_plugin.hpp # Same header, same public API -├── p2p_plugin.cpp # Replaced impl: wraps dlt_p2p_node instead of node.cpp -└── CMakeLists.txt -``` diff --git a/.qoder/plans/pm-plan/onix-protocol-specification.md b/.qoder/plans/pm-plan/onix-protocol-specification.md deleted file mode 100644 index f1d1d720f4..0000000000 --- a/.qoder/plans/pm-plan/onix-protocol-specification.md +++ /dev/null @@ -1,939 +0,0 @@ -# Onix Protocol Specification - -**Version:** 2.0 (on-chain / HF14) -**Status:** Formal technical specification — now realized as consensus operations on VIZ DLT - ---- - -> **On-chain (HF14).** Implemented as first-class consensus operations (`pm_*`) on VIZ DLT and verified in -> `consensus_sim`. **All percentages are basis points (bp): 10000 = 100.00%**; all durations are -> governance parameters in **seconds / blocks**. Median-voted parameters live in the `chain_properties_pm` -> struct (§3); per-market fields are the `pm_create_market` operation; all state is in the chainbase -> objects of §17. Oracle fees use offer→quote (creator ceiling → oracle freezes its quote at accept, -> emitting `pm_market_accepted`). Disputes have two modes — committee (`dispute_mode = 0`, default: -> stake-weighted **public** `pm_dispute_vote`, revisable until close, Lazy-Pool stake counts) and account -> (`dispute_mode = 1`: a named `dispute_resolver`). - -## Table of Contents - -1. [Definitions and Roles](#1-definitions-and-roles) -2. [Currency and Precision](#2-currency-and-precision) -3. [System Parameters](#3-system-parameters) -4. [Market State Machine](#4-market-state-machine) -5. [Onix Binary: Constant Product Market Maker](#5-onix-binary-constant-product-market-maker) -6. [Onix Multi: LMSR with Parimutuel Settlement](#6-onix-multi-lmsr-with-parimutuel-settlement) -7. [Fee Structure](#7-fee-structure) -8. [Time Penalty for Late Bets](#8-time-penalty-for-late-bets) -9. [Liquidity Provision](#9-liquidity-provision) -10. [Resolution and Payout](#10-resolution-and-payout) -11. [Bet Cancellation](#11-bet-cancellation) -12. [Dispute System](#12-dispute-system) -13. [Oracle Penalty for Missed Resolution](#13-oracle-penalty-for-missed-resolution) -14. [Oracle Reputation Scoring](#14-oracle-reputation-scoring) -15. [Position Transfers](#15-position-transfers) -16. [Lazy Liquidity Pool](#16-lazy-liquidity-pool) -16a. [Opt-In Leverage](#16a-opt-in-leverage-lazy-pool-funded) -16b. [Batch / Commit-Reveal Betting](#16b-batch-commit-reveal-betting-anti-mev) -17. [On-Chain Object Model](#17-on-chain-object-model) - ---- - -## 1. Definitions and Roles - -| Role | Definition | -|------|-----------| -| **Market Creator** | Pays `pm_market_creation_fee` (`pm_create_market`); sets the question, outcomes, liquidity, fee ceilings, and timing parameters | -| **Oracle** | Registers (fee: `pm_oracle_registration_fee`), deposits insurance (min: `pm_min_oracle_insurance`), quotes its fee terms in **basis points** (≤ creator ceiling) + fixed fee at acceptance, accepts/rejects markets, provides outcome decisions | -| **Bettor** | Places bets on outcomes; receives tokens proportional to stake and current reserves | -| **Liquidity Provider (LP)** | Supplies capital to market pools; earns time-weighted share of liquidity fees + penalty pool | -| **Lazy Pool Provider** | Deposits VIZ into the Lazy Liquidity Pool with a lock period; pool auto-allocates to markets and distributes rewards via `reward_per_share` accumulator | -| **Dispute Resolver** | Account mode only (`dispute_mode = 1`): the per-market `dispute_resolver` account arbitrates. Committee mode (`dispute_mode = 0`) uses no resolver — the SHARES electorate votes | -| **DAO / committee fund** | The chain's existing committee fund. Receives `pm_market_creation_fee` and extra oracle penalties | - ---- - -## 2. Currency and Precision - -All amounts are stored as integers with precision = 1/1000 (milli-VIZ). `1000` internal units = 1.000 VIZ. - -Time penalty values use precision = 1/1,000,000 (micro-units). - ---- - -## 3. System Parameters - -### Median-voted parameters (`chain_properties_pm`) - -All economic parameters are delegate median-voted (no hard fork to tune) and live in the on-chain -`chain_properties_pm` struct. **All percentages are basis points (bp, 10000 = 100.00%); durations are -seconds or blocks.** Exact defaults and ranges are in [Chain Properties](../../../docs/governance/chain-properties.md#pm-parameters); -the authoritative source is the struct itself. - -| Group | Parameters | -|---|---| -| Registration & floors | `pm_oracle_registration_fee`, `pm_min_oracle_insurance`, `pm_market_creation_fee`, `pm_min_liquidity`, `pm_max_outcomes`, `pm_max_market_duration` | -| Fees & penalties (bp) | `pm_max_oracle_fee_percent`, `pm_oracle_penalty_percent`, `pm_no_contest_penalty_percent`, `pm_default_time_penalty_percent`, `pm_max_time_penalty` | -| Disputes | `pm_dispute_fee`, `pm_dispute_grace_sec`, `pm_oracle_dispute_response_sec`, `pm_dispute_vote_period_sec`, `pm_dispute_auto_close_sec`, `pm_dispute_approve_min_percent` (bp), `pm_dispute_reward_multiplier` (bp) | -| Lazy pool | `pm_lazy_pool_enabled`, `pm_lazy_alloc_percent`, `pm_lazy_max_total_alloc_percent`, `pm_lazy_recall_step_percent`, `pm_lazy_lock_sec`, `pm_lazy_emergency_penalty_percent` | -| Leverage | `pm_leverage_enabled`, `pm_leverage_fund_percent`, `pm_leverage_max_per_position_bp`, `pm_leverage_max_position_ratio_percent`, `pm_leverage_min_market_liquidity`, `pm_leverage_safety_margin_percent`, `pm_leverage_max_slippage_percent`, `pm_leverage_m_factor_percent`, `pm_leverage_pool_profit_percent`, `pm_leverage_expiration_buffer_sec`, `pm_conversion_profit_cost_percent` | -| Batch / commit-reveal | `pm_commit_reveal_enabled`, `pm_batch_epoch_blocks`, `pm_reveal_window_blocks`, `pm_commit_no_reveal_penalty_percent` (bp), `pm_min_batch_bet` | -| Processing | `pm_processing_cap_per_block` | - -The recipient of `pm_market_creation_fee` and extra oracle penalties is the chain's existing committee/DAO -fund — not a PM-specific account. - -### Per-market parameters (`pm_create_market` operation) - -Set by the creator at creation; the oracle fee fields are a **ceiling** the oracle quotes against at -acceptance (offer→quote). Full field reference: the Prediction Market operations doc. - -| Field | Description | -|---|---| -| `oracle`, `market_type` (0 binary / 1 multi), `outcomes`, `url` | market definition | -| `oracle_fee_percent`, `oracle_fixed_fee` | oracle fee **ceiling** (bp + fixed); the oracle freezes its quote ≤ this (and ≤ median `pm_max_oracle_fee_percent`) at accept | -| `creator_fee_percent`, `liquidity_fee_percent` | creator & LP fees (bp of the losers' pool) | -| `liquidity`, `lmsr_b` | seed liquidity; `lmsr_b` for multi markets | -| `betting_expiration`, `result_expiration` | timers | -| `time_penalty_type`, `time_penalty_value`, `penalty_curve_type` | late-bet penalty shape | -| `allow_early_resolution`, `allow_cancellation` | toggles | -| `allow_batch`, `allow_instant_bet` | betting modes (binary) | -| `endogeneity_tier` | 1 econ-data / 2 sports / 3 political (display/risk hint) | -| `dispute_mode` (0 committee / 1 account), `dispute_resolver` | dispute routing | -| `dispute_penalty_percent` | oracle penalty policy on a successful dispute (bp, signed) | -| `metadata` | free-form client JSON (consensus-opaque; parsed off-chain) | - ---- - -## 4. Market State Machine - -### States - -| Status | Name | Description | -|--------|------|-------------| -| -1 | Deleted | Oracle rejected; liquidity returned to creator | -| 0 | Waiting | Awaiting oracle review | -| 1 | Active | Accepting bets until `betting_expiration` | -| 2 | Closed | Betting ended, awaiting oracle resolution | -| 3 | Resolved | Outcome determined, payouts calculated | - -### Payout States - -| payout_status | Name | Description | -|---------------|------|-------------| -| 0 | Not calculated | Pre-resolution | -| 1 | Calculated | Payouts pending (grace period active) | -| 2 | Paid | All payouts processed | -| 3 | Disputed | Dispute filed, payouts frozen | - -### Transitions - -``` -Waiting (0) ──[oracle accepts]──► Active (1) ──[betting_expiration]──► Closed (2) - │ │ │ - │ oracle rejects │ early resolution │ oracle resolves - ▼ │ (if allowed) ▼ -Deleted (-1) └──────────────────────────► Resolved (3) - │ - grace period (12h) - ▼ - Paid out -``` - -**Preconditions:** - -| Transition | Preconditions | -|-----------|---------------| -| 0 → 1 | Oracle has insurance ≥ `min_oracle_insurance`; oracle accepts | -| 0 → 1 (self-oracle) | Creator = oracle; insurance check; auto-approves at creation | -| 0 → -1 | Oracle rejects; liquidity returned to creator | -| 1 → 3 | Oracle submits resolution with outcome (0, 1, or -1 for no-contest); `allow_early_resolution=1` or `time ≥ betting_expiration` | -| 2 → 3 | Oracle submits resolution; `time ≤ result_expiration` | -| 3 → paid | Grace period passed with no dispute; cron processes payouts | - -### Market Creation Flow - -1. Deduct `market_creation_fee` from creator → DAO fund (non-refundable) -2. Record `oracle_fixed_fee` from oracle profile on market -3. Lock `liquidity` from creator balance -4. Initialize reserves: `reserve_a = floor(liquidity/2)`, `reserve_b = liquidity − reserve_a` -5. Compute `k = reserve_a × reserve_b` -6. If self-oracle: auto-approve to status=1 with insurance check -7. If external oracle: enter status=0 - -### Oracle Acceptance Flow - -When oracle accepts (status 0 → 1): - -1. Transfer `oracle_fixed_fee` from creator balance to oracle balance (skipped if self-oracle) -2. Increment oracle `markets_accepted` counter -3. Update oracle `last_active_time` -4. Lazy Pool auto-allocation triggered (if pool has free balance) - -### Audit Trail - -Every state-changing action is a consensus operation or virtual operation, permanently recorded in the block log and queryable via `account_history`. Bets, cancels, liquidity add/withdraw, accept/reject, resolution, dispute, dispute-resolve, payout, and penalty all appear as `pm_*` operations/virtual-operations, alongside the market reserves they touched. - ---- - -## 5. Onix Binary: Constant Product Market Maker - -### Invariant - -``` -k = reserve_a × reserve_b -``` - -`k` changes only on liquidity add/withdraw operations. - -### Bet Placement (side A) - -``` -new_reserve_b = reserve_b + amount -new_reserve_a = floor(k / new_reserve_b) -tokens_received = reserve_a − new_reserve_a -price = amount × 1,000,000 / tokens_received -``` - -Symmetric for side B (swap a/b). - -### Slippage Protection - -Optional `min_tokens` parameter on `place-bet`. If `tokens_received < min_tokens`, transaction rejected. - -### Market Initialization - -``` -reserve_a = floor(liquidity / 2) -reserve_b = liquidity − reserve_a -k = reserve_a × reserve_b -``` - -Minimum initial liquidity: 100,000 mVIZ (100 VIZ). - -### Weight (Token) Semantics - -- `weight` = number of outcome tokens received by bettor (set by the CPMM at bet time) -- `weight` is a **relative claim**, not a VIZ-denominated payout. Settlement is **parimutuel** (identical to Onix Multi): winners receive their stake back plus a proportional share of the losers' pool, by weight. -- If bet on side A and outcome A wins: `payout = bet_amount + (weight / total_winning_weight) × winners_pool − time_penalty_on_profit` -- If outcome A loses: payout = 0 (stake forfeited into the winners' pool) - -CPMM is the **pricing engine** (probability + weight assignment); it no longer gates payout. This makes the two market types share one settlement model: *the AMM assigns weights (CPMM for binary, LMSR for multi); losers fund winners pro-rata by weight.* - -### Price Display - -``` -implied_probability_A = reserve_b / (reserve_a + reserve_b) × 100% -implied_probability_B = reserve_a / (reserve_a + reserve_b) × 100% -``` - -### LP Principal Guarantee (Proof) - -Under parimutuel settlement the guarantee is exact and does not rely on the curve geometry: - -``` -Money OUT = L (LP principal) + Σ(winning bet_amount) + winners_pool + fees - = L + winning_bets + (losers_sum − fees) + fees - = L + winning_bets + losing_bets = L + all_bets = Money IN -``` - -Total payout is capped at `losers_sum` regardless of weights, so LP principal `L` is returned unconditionally and winners are funded entirely by losers. (The legacy AM-GM bound `reserve_a + reserve_b ≥ L` is no longer needed for solvency; it remains a property of the pricing curve.) - ---- - -## 6. Onix Multi: LMSR with Parimutuel Settlement - -### Price Function (Softmax) - -For N outcomes with quantity parameters q_1, ..., q_N and liquidity parameter b: - -``` -price(i) = exp(q_i / b) / Σ_j exp(q_j / b) -``` - -**Invariant:** `Σ_i price(i) = 1` (by definition of softmax). - -### Cost Function - -``` -C(q) = b × ln(Σ_j exp(q_j / b)) -``` - -Cost to buy Δ tokens on outcome i: - -``` -cost = C(q + Δ·e_i) − C(q) - = b × [ln(Σ_j exp(q'_j / b)) − ln(Σ_j exp(q_j / b))] -where q'_i = q_i + Δ, all other q'_j = q_j -``` - -Numerical stability (log-sum-exp trick): - -``` -ln(Σ exp(x_j)) = max(x) + ln(Σ exp(x_j − max(x))) -``` - -### Liquidity Parameter - -``` -b = S / ln(N) -``` - -where S = LP subsidy deposit, N = number of outcomes. - -### Settlement (at resolution) - -``` -1. Oracle declares winning outcome -2. losers_sum = Σ bet_amount for all non-winning bets -3. oracle_fee = floor(losers_sum × oracle_fee_percent / 10000) -4. creator_fee = floor(losers_sum × creator_fee_percent / 10000) -5. liq_fee = floor(losers_sum × liquidity_fee_percent / 10000) -6. winners_pool = losers_sum − oracle_fee − creator_fee − liq_fee -7. For each winning bettor: - payout = bet_amount + (their_tokens / total_winning_tokens × winners_pool) − time_penalty -8. LP subsidy returned unconditionally -9. LP earns time-weighted share of liq_fee -``` - -### LP Principal Guarantee (Proof) - -1. LP deposits S VIZ as subsidy. This sets b = S / ln(N). -2. During betting, users pay VIZ → receive tokens. VIZ accumulates as betting pool. -3. At resolution: losers forfeit 100% → `losers_sum`. Winners paid from `losers_sum` (not from subsidy). -4. LP subsidy S returned **unconditionally** — it is architecturally separate from the payout flow. - -### Edge Cases - -| Scenario | Outcome | -|----------|---------| -| All bets on winning outcome | `losers_sum=0`, `winners_pool=0`. Every bettor gets back `bet_amount`. LP subsidy returned. | -| No bets on winning outcome | `losers_sum=total_bets`. Undistributed `winners_pool` → LP bonus. | -| Zero-volume market | LP subsidy returned. No fees, no payouts. | -| Single bettor wins | Bettor receives `bet_amount + winners_pool`. LP subsidy returned. | - -### Operations - -| Operation | Description | -|-----------|-------------| -| `pm_create_market_multi { oracle, outcomes, liquidity, fees, ... }` | Create N-outcome market | -| `pm_place_bet_multi { market, outcome_index, amount, min_tokens }` | Buy tokens for outcome | -| `pm_cancel_bet_multi { bet_id, min_return }` | Sell tokens back via reverse LMSR | -| `pm_add_liquidity_multi { market, amount }` | Add LP subsidy (increases b) | -| `pm_withdraw_liquidity_multi { liquidity_id }` | Withdraw LP subsidy (min floor enforced) | -| `pm_resolve_multi { market, winning_outcome }` | Oracle declares winner, triggers settlement | - -Binary markets (N=2) use Onix Binary (CPMM). LMSR used only for N > 2. - ---- - -## 7. Fee Structure - -### Resolution-Time Fee Computation - -All percentage fees computed at resolution from **losing side's total volume**: - -``` -losers_sum = Σ bet_amount for all losing bets - -oracle_fee = floor(losers_sum × oracle_fee_percent / 10000) -creator_fee = floor(losers_sum × creator_fee_percent / 10000) -liquidity_fee = floor(losers_sum × liquidity_fee_percent / 10000) -winners_pool = losers_sum − oracle_fee − creator_fee − liquidity_fee -``` - -Fees are NOT deducted from bets at placement time. Full bet amount enters CPMM/LMSR reserves. - -### Oracle Fixed Fee - -One-time fee per market. Set by oracle on profile. Paid by creator to oracle at market acceptance. Skipped entirely for self-oracle markets (no balance operation occurs). - -### Fee Tracking Fields - -- `oracle_fee_earned` — not used at resolution; fee computed from losers_sum -- `liquidity_fee_earned` — cumulative LP fees already paid to early-withdrawn LPs; at resolution: `LP fee pool = max(0, floor(losers_sum × liquidity_fee_percent / 10000) − liquidity_fee_earned) + penalty_pool` -- Per-bet `oracle_fee` and `liquidity_fee` recorded for audit; not accumulated on market - -### Rounding - -All calculations use `floor()`. Undistributed dust (< 1 mVIZ) sent to DAO fund during final payout. - ---- - -## 8. Time Penalty for Late Bets - -### Penalty Window - -| Type | Window Calculation | -|------|-------------------| -| Fixed (type=0) | `penalty_window = time_penalty_value` seconds before expiration | -| Percentage (type=1) | `penalty_window = time_penalty_value / 100 × (betting_expiration − market_creation_time)` | - -### Penalty Calculation - -``` -time_to_expiration = betting_expiration − current_time - -if time_to_expiration < penalty_window: - ratio = 1 − (time_to_expiration / penalty_window) - - if penalty_curve_type == 1: // quadratic - penalty_ratio = ratio × ratio - else: // linear - penalty_ratio = ratio - - time_penalty = floor(penalty_ratio × max_time_penalty) -else: - time_penalty = 0 -``` - -### Application at Payout (Profit-Only) - -``` -profit = floor(winners_pool × weight / total_winning_weight) // parimutuel share of losers' pool -penalty_deduction = floor(profit × time_penalty / 1,000,000) -net_payout = bet_amount + profit − penalty_deduction -``` - -**Invariant:** `net_payout ≥ bet_amount` — the penalty applies only to the profit share, so winners always receive at least their principal. (Identical for Onix Binary and Onix Multi.) - ---- - -## 9. Liquidity Provision - -### Adding Liquidity - -``` -add_a = amount × reserve_a / (reserve_a + reserve_b) -add_b = amount − add_a -new_reserve_a = reserve_a + add_a -new_reserve_b = reserve_b + add_b -new_k = new_reserve_a × new_reserve_b -``` - -Records `sec_to_expiration = betting_expiration − current_time` at deposit time. - -### Time-Weighted Fee Distribution (at resolution) - -``` -fee_pool = remaining_liquidity_fee + total_penalty_pool - -weight_i = amount_i × max(1, sec_to_expiration_i) -total_weight = Σ weight_i -fee_share_i = floor(fee_pool × weight_i / total_weight) -lp_payout_i = principal_i + fee_share_i -``` - -Each deposit is an independent position. Multiple deposits by the same user are tracked separately. - -### Early Withdrawal - -**Preconditions:** market status=1, `time < betting_expiration`, `resulting liquidity_sum ≥ 100,000 mVIZ`. - -``` -// Fractional withdrawal -fraction = withdraw_amount / lp_amount -withdraw_weight_a = floor(weight_a × fraction) -withdraw_weight_b = floor(weight_b × fraction) - -// Reverse reserves -new_reserve_a = reserve_a − withdraw_weight_a -new_reserve_b = reserve_b − withdraw_weight_b -new_k = new_reserve_a × new_reserve_b - -// Time-ratio discount -time_served = current_time − lp_deposit_time -market_duration = betting_expiration − market_creation_time -time_ratio = min(1, time_served / market_duration) - -// Fee share (conservative: min of both sides) -fee_from_a = floor(a_bets_sum × liquidity_fee_percent / 10000) -fee_from_b = floor(b_bets_sum × liquidity_fee_percent / 10000) -estimated_pool = min(fee_from_a, fee_from_b) − already_paid_to_early_lps -lp_tw = withdraw_amount × max(1, sec_to_expiration) -total_tw = Σ (active LP time-weights) -raw_fee_share = floor(estimated_pool × lp_tw / total_tw) -fee_share = floor(raw_fee_share × time_ratio) - -returned = withdraw_amount + fee_share -``` - -**Post-expiration lock:** LP withdrawal blocked when `time ≥ betting_expiration`. All LP positions locked until resolution. - -### Principal Safety on Early Withdrawal - -Withdrawal subtracts original `weight_a` and `weight_b` (not proportional share of current reserves). If `reserve_a < weight_a` or `reserve_b < weight_b`, withdrawal is **blocked**. - -### Creator as First LP - -Market creator is automatically the first LP. Their `sec_to_expiration` equals the full market duration, giving maximum time-weight. - ---- - -## 10. Resolution and Payout - -### Payout Priority Order - -| Priority | Type | Recipient | Amount | -|----------|------|-----------|--------| -| 1 | Oracle fee (2) | Oracle | `floor(losers_sum × oracle_fee_percent / 10000)` | -| 1.5 | Creator fee (7) | Creator | `floor(losers_sum × creator_fee_percent / 10000)` | -| 2 | Creator LP (1) | Creator | `principal + time-weighted fee share` | -| 3 | LP return (1) | LPs | `principal + time-weighted fee share` | -| 4 | Winner bets (0) | Winners | `bet_amount + floor(winners_pool × weight / total_winning_weight) − penalty_deduction` (parimutuel) | -| 5 | Dispute refund (5) | Dispute participants | (if applicable) | -| 6 | Oracle penalty bonus (6) | All participants | (if oracle penalized) | - -### Losing Side - -Payout = 0. Stakes absorbed into reserve pool. - -### Zero-Volume Markets - -LPs receive full principal. Oracle receives fixed fee (if any). All fee accumulators remain 0. - ---- - -## 11. Bet Cancellation - -### Preconditions - -| Condition | Check | -|-----------|-------| -| Bet is active | `bet.status == 0` | -| User owns bet | `bet.user == current_user.id` | -| Market active | `market.status == 1` | -| Betting open | `current_time < market.betting_expiration` | -| Cancellation allowed | `market.allow_cancellation == 1` | - -### Reverse CPMM Mechanics - -For bet on side A (side=0): - -``` -new_reserve_a = reserve_a + tokens -new_reserve_b = floor(k / new_reserve_a) -amount_returned = reserve_b − new_reserve_b -if amount_returned <= 0: amount_returned = 0 -``` - -Symmetric for side B. - -### Slippage Protection - -Optional `min_return` parameter. If `amount_returned < min_return`, transaction rejected. - -### State Changes (atomic) - -1. Bet status → 1 (cancelled), `returned_amount` recorded -2. Market reserves updated -3. Market bet sums decremented by original bet amount -4. User balance increased by `amount_returned`, `bets_balance` decreased -5. History entry (type=4) logged -6. Market log entry with before/after reserves - ---- - -## 12. Dispute System - -### Filing Preconditions - -- Filer has placed a bet on the market -- Within `pm_dispute_grace_sec` after resolution -- Routing by mode: **committee** (`dispute_mode = 0`) — no resolver account needed, the SHARES electorate votes via `pm_dispute_vote` (public, revisable until `voting_end_time`, weight = `effective_vesting_shares` + Lazy-Pool stake→shares), tallied by the `pm_dispute_finalize` cron; **account** (`dispute_mode = 1`) — the market's named `dispute_resolver` issues `pm_dispute_resolve` -- No open dispute on market -- Filer pays `pm_dispute_fee` - -### Oracle Response - -Mandatory within `pm_oracle_dispute_response_sec`. If missed, `pm_dispute_fee` is auto-slashed from insurance and recorded on the oracle object. - -### Dispute Lifecycle - -``` -Resolution (T=0) → Grace period (T to T+12h) → Dispute filed (T≤12h) - → Oracle response (12h window) → Resolver decision (up to 14 days) - → After verdict: recalculate or unfreeze → Auto-payout after new grace period - → Auto-close fallback (T+14 days): full refund + oracle penalty -``` - -### Dispute Upheld (Oracle Wrong) - -``` -reward_pool = min(dispute_fee × multiplier, oracle_insurance) - -1. Disputer: dispute_fee returned (from escrow) -2. From oracle insurance (reward_pool): - disputer_reward = floor(reward_pool / multiplier) → disputer - voter_reward = reward_pool − disputer_reward → resolver -3. Remaining insurance: extra penalty (resolver discretion) → DAO fund -``` - -### Dispute Rejected (Oracle Right) - -``` -Disputer loses dispute_fee: - 50% → resolver (dispute_rejected_voter_percent / 10000) - 50% → oracle (dispute_rejected_oracle_percent / 10000) -``` - -### Recalculation Process (Oracle Wrong) - -1. Validate penalty (capped at remaining insurance after reward_pool) -2. Disputer reward paid -3. Resolver reward paid -4. Oracle insurance slashed -5. Bans applied (if requested) -6. Delete all existing non-paid payouts -7. Flip winning outcome (A↔B) -8. Regenerate payouts from scratch with corrected outcome -9. Audit trail recorded - -### Committee Powers - -| Parameter | Type | Description | -|-----------|------|-------------| -| `penalty_amount` | mVIZ | Additional insurance slash (0 to remaining) → DAO fund | -| `ban_oracle` | 0/1 | Ban oracle | -| `ban_oracle_until` | unix ts / 0 | 0=permanent, >0=expires | -| `ban_creator` | 0/1 | Ban creator | -| `ban_creator_until` | unix ts / 0 | 0=permanent, >0=expires | - -### Auto-Close (14-day fallback) - -| Action | Description | -|--------|-------------| -| Plaintiff | Dispute fee refunded | -| Oracle | `dispute_fee` slashed from insurance | -| Bets | All refunded (original amounts) | -| LPs | All refunded (principal only) | -| Penalty distribution | Slashed amount distributed proportionally to all participants | -| Dispute status | Set to 3 (auto-closed) | - -### No-Contest Declaration - -Oracle calls `oracle-no-contest` with `market_id` and `reason`. - -1. All bets → pending refund payouts (full original amount) -2. All LP positions → pending refund payouts (principal only) -3. Penalty: `oracle_no_contest_penalty_percent`% of `dispute_fee` from insurance -4. Penalty distributed proportionally to participants -5. Market: `resolved_outcome = -1`, `payout_status = 1` -6. Grace period starts (disputable) - -### 3-Outcome Resolution (No-Contest Dispute) - -Resolver chooses one of: -- `correct_outcome = 0` — A wins (recalculate payouts) -- `correct_outcome = 1` — B wins (recalculate payouts) -- `correct_outcome = -1` — Confirm no-contest (keep refund payouts) - -If oracle wrong: pending refund payouts deleted, replaced with correct winner payouts. Standard dispute penalties apply. - ---- - -## 13. Oracle Penalty for Missed Resolution - -If oracle fails to resolve by `result_expiration`: - -``` -penalty_amount = floor(oracle_insurance × oracle_penalty_percent / 100) -``` - -### Distribution - -``` -stakes[user_id] += bet_amount (for each active bet) -stakes[user_id] += liquidity_amount (for each active LP position) -total_stakes = Σ stakes[user_id] - -bonus_i = floor(penalty_amount × stakes[user_id] / total_stakes) -``` - -Each participant receives: full refund (principal) + proportional bonus. - -Market finalized: status=3, payout_status=2. - ---- - -## 14. Oracle Reputation Scoring - -### Raw Metrics (14 counters per oracle) - -| Metric | Type | Source | -|--------|------|--------| -| `markets_accepted` | counter | oracle-accept-market | -| `markets_resolved` | counter | resolve-market | -| `markets_no_contest` | counter | oracle-no-contest | -| `markets_missed` | counter | cron (missed deadline) | -| `disputes_received` | counter | create-dispute | -| `disputes_lost` | counter | resolve-dispute (status=1) | -| `disputes_won` | counter | resolve-dispute (status=2) | -| `disputes_auto_closed` | counter | cron (14-day auto-close) | -| `dispute_responses_missed` | counter | cron (12h response deadline) | -| `total_volume_resolved` | mVIZ | resolve-market (sum of bets_sum) | -| `total_insurance_slashed` | mVIZ | all penalty events | -| `avg_resolution_time` | seconds | resolve-market | -| `bans_received` | counter | resolve-dispute | -| `active_since` | timestamp | register-oracle | -| `last_active_time` | timestamp | accept/resolve/no-contest | - -### Derived Rates - -Denominator: `total_outcomes = markets_resolved + markets_no_contest + markets_missed` - -| Rate | Formula | -|------|---------| -| `resolution_rate` | `markets_resolved / total_outcomes` | -| `dispute_loss_rate` | `disputes_lost / disputes_received` | -| `no_contest_rate` | `markets_no_contest / total_outcomes` | -| `deadline_miss_rate` | `markets_missed / total_outcomes` | -| `dispute_response_rate` | `1 − (dispute_responses_missed / disputes_received)` | - -### Reliability Score (0–100) - -``` -reliability_score = clamp(0, 100, - BASE_SCORE - − W_DISPUTE_LOSS × dispute_loss_rate × 100 - − W_NO_CONTEST × excess_no_contest × 100 - − W_DEADLINE_MISS × deadline_miss_rate × 100 - − W_NO_RESPONSE × (1 − dispute_response_rate) × 100 - + W_VOLUME_BONUS × volume_tier - + W_EXPERIENCE × experience_tier × freshness_multiplier - − W_BAN_PENALTY × bans_received -) -``` - -Where `excess_no_contest = max(0, no_contest_rate − 0.10)`. - -### Weight Defaults - -| Weight | Value | -|--------|-------| -| BASE_SCORE | 50 | -| W_DISPUTE_LOSS | 0.40 | -| W_NO_CONTEST | 0.10 | -| W_DEADLINE_MISS | 0.20 | -| W_NO_RESPONSE | 0.15 | -| W_VOLUME_BONUS | 0–25 (tiered: ≥10K→+5, ≥100K→+10, ≥500K→+15, ≥1M→+20, ≥5M→+25) | -| W_EXPERIENCE | 0–25 (tiered: ≥7d→+5, ≥30d→+10, ≥90d→+15, ≥180d→+20, ≥365d→+25) | -| W_BAN_PENALTY | 15 per ban | - -### Freshness Decay - -| Days since last active | Multiplier | -|----------------------|-----------| -| ≤ 30 | 1.00 | -| 31–90 | 0.75 | -| 91–180 | 0.50 | -| > 180 | 0.25 | - -### Composite Trust Score - -``` -trust_score = reliability_score × risk_factor -``` - -| Risk score (insurance/bets) | risk_factor | -|---------------------------|-------------| -| ≥ 3.0× | 1.00 | -| ≥ 2.0× | 0.95 | -| ≥ 1.0× | 0.85 | -| < 1.0× | 0.70 | - -### New Oracle Detection - -`total_outcomes < 5` → `is_new = true`. Distinct badge in UI. - -Score computed on read via `compute_oracle_reliability_score()`, not stored. - ---- - -## 15. Position Transfers - -### Operation - -``` -pm_transfer_position { bet_id, to_user, amount, memo } -``` - -- Transfer all or part of a bet's tokens to another account -- Transferred tokens retain original market and outcome -- Payout goes to current holder at resolution -- No slippage, no market impact — pure record reassignment -- Works for both Onix Binary and Onix Multi positions - -### Memo Privacy Model - -| Mode | Format | Visibility | -|------|--------|------------| -| Plaintext | String not starting with `#` | Public on-chain | -| Encrypted | String starting with `#` | Private — only sender and recipient can decrypt | - -Encryption: ECIES shared-secret `ECDH(sender_memo_private, recipient_memo_public)` using VIZ account memo keys (standard Graphene model). Client-side encryption/decryption. - ---- - -## 16. Lazy Liquidity Pool - -### Parameters - -| Median-voted parameter | Role | -|---------|-------------| -| `pm_lazy_pool_enabled` | pool kill-switch | -| `pm_lazy_alloc_percent` | share of free balance allocated per market (bp) | -| `pm_lazy_max_total_alloc_percent` | cap on the pool fraction across active markets (bp) | -| `pm_lazy_recall_step_percent` | graduated-recall step on idle markets (bp) | -| `pm_lazy_lock_sec` | deposit lock period (seconds) | -| `pm_lazy_emergency_penalty_percent` | penalty on locked profit for emergency withdrawal (bp) | -| `pm_min_liquidity` | minimum allocation per market (also the market seed floor) | - -### Deposit - -- First depositor: `shares = amount` -- Subsequent: `new_shares = amount × total_shares / free_balance` -- Lock timer: `unlock_time = now + pm_lazy_lock_sec` -- Reward settlement before share calculation: `pending += shares × (pool.rps − user.snapshot) / PRECISION` - -### Auto-Allocation - -On market activation (status → 1): - -``` -alloc_amount = free_balance × allocation_percent / 100 -× (1 − active_market_penalty_pct / 100) ^ oracle_active_market_count -× (1 − fault_penalty_pct / 100) ^ oracle_active_fault_stamps -``` - -Checks: `alloc_amount ≥ min_market_allocation`, `allocated + alloc_amount ≤ total × max_total_allocation / 100`. - -Pool LP inserted with `user=0`. Participates identically in time-weighted fee distribution. - -### Reward Distribution (Lazy Accounting) - -On market resolution with pool LP profit: - -``` -profit = lp_return − allocation_amount -if profit > 0 AND total_shares > 0: - pool.reward_per_share += profit × PRECISION / total_shares -``` - -User reward (computed on read): - -``` -live_reward = pending_rewards + shares × (pool.rps − user.snapshot) / PRECISION -``` - -### Planned Withdrawal - -From consolidated unlocked record (full or partial): - -``` -1. Run unlock consolidation -2. Settle rewards: pending += shares × (rps − snapshot) / PRECISION -3. Share value = shares_to_burn × free_balance / total_shares -4. Reward portion = pending_rewards × withdraw_percent / 100 -5. Total payout = share value + reward portion -``` - -### Emergency Withdrawal - -All deposits (locked + unlocked): - -``` -1. Settle rewards -2. total_value = shares × free_balance / total_shares + pending_rewards -3. profit = total_value − principal_deposited -4. if profit > 0: penalty = profit × (locked_shares / total_shares) × emergency_penalty / 100 -5. Penalty → pool reward_per_share -6. User receives: total_value − penalty -``` - -### Opportunity-Cost Protection - -**A. Graduated Recall:** Market duration divided into 10 steps. At each step, if volume in period < `allocation × recall_volume_threshold_pct / 100`, recall `recall_pct_per_step`% of current allocation to pool. - -**B. Active Market Penalty:** `factor = (1 − active_market_penalty_pct / 100) ^ active_market_count`. Recursive 5% reduction per oracle active market. - -**C. Fault Stamps:** On bad market outcomes (no-contest, missed deadline, zero volume, dispute loss, no response, auto-close), oracle receives a fault stamp that auto-expires after a clean-operation window. `fault_factor = (1 − fault_penalty_pct / 100) ^ active_stamps`. - -### Design Decision: Real Depth Only (No Virtual/Phantom Liquidity) - -A *virtual* (phantom) liquidity offset — a curve reserve added for pricing but backed by no real capital and deleted at settlement, optionally median-voted — is value-conservative in the closed bet→cancel→settle loop (the vAMM technique) and is tempting as a cold-start stabilizer for thin markets. Onix **deliberately does not implement it.** Lazy-Pool auto-allocation (§16) already delivers the same launch-smoothing with **real** capital that earns fees, has an accountable owner, and follows demand per market. Phantom depth is rejected because, applied carelessly, it harms market structure and trust: - -1. **Forgeable depth** lets a thin or manipulated market look deep and liquid, eroding the price signal that real, costly depth would carry. -2. **Distorted information aggregation** — virtual depth flattens curve weights, weakening the reward for early correct information and making the price unresponsive to news (a stale forecast). The right depth is per-market and volume-dependent; a single governance constant cannot track it. -3. **Conditional solvency** — it stays solvent only while never redeemed or used as collateral. The moment it backs a cancel, early withdrawal, or leverage loan it must be excluded everywhere or it leaks real money (e.g. leverage sized/recovered against fake depth → real bad debt to pool depositors). Every "size-against-liquidity / pay-the-LP" path becomes an excludability footgun. -4. **No owner, no yield, no accountability** — virtual depth bears no risk and earns no fee for anyone real, deleting the retail safe-yield product on the markets it touches. - -Onix therefore keeps **only real numbers**: every unit of depth is real capital — redeemable, fee-earning, accountable — provided through the Lazy Pool. The conscious tradeoff is to forgo a cheap virtual stabilizer in favour of price-signal integrity and the solvency of every real-money path. - ---- - -## 16a. Opt-In Leverage (Lazy-Pool-Funded) - -Live since HF14; opt-in, governed by median kill-switch `pm_leverage_enabled` (default off). - -- **Open** (`pm_leverage_open`) — a bettor posts collateral; the Lazy Pool **loans** the margin from - `free_balance` (capped by `leverage_fund_used`; checked against `pm_leverage_fund_percent`, - `…_max_per_position_bp`, `…_max_position_ratio_percent`, `…_min_market_liquidity` at open time). No - token emission — the position is fully collateralized from the system's view. A leveraged open does - **not** create a `pm_bet`; the curve weight is held on the `pm_leverage_position_object`. -- **Liquidation** — runs against **pre-bet reserves** so the pool recovers `min(cancel_value, - obligation) ≥ loan`: opposing-bet cascade (`pm_place_bet`) and settlement force-close are always - full-recovery (loan + interest → pool); the **only** bounded bad-debt path is a same-side - `pm_cancel_bet` (Case B). The cascade is **not** gated by `pm_leverage_enabled` (the flag blocks only - new opens), so disabling leverage never strips protection from open positions. -- **Virtual ops** — `pm_leverage_resolve` (force-close at settlement, with outcome + leverage), - `pm_leverage_liquidate` (mid-market, `reason` 0 opposing / 1 cancel). -- **Governance weight** — Lazy-Pool depositors keep their PM-dispute and DAO-committee vote weight - (pool NAV → vesting-shares via `get_vesting_share_price`, HF14-gated). - -API: `get_account_leverage_positions`, `get_market_leverage_positions`, `get_lazy_pool`. - -## 16b. Batch / Commit-Reveal Betting (anti-MEV) - -Live since HF14 for **binary** markets (multi forces `allow_instant_bet` until LMSR batch lands); -opt-in per market (`allow_batch` / `allow_instant_bet`), median kill-switch `pm_commit_reveal_enabled`. - -- `pm_place_bet` with `mode = 1` queues a **batch** bet; `pm_commit_bet` (commitment hash + escrow) → - `pm_reveal_bet` runs the **commit-reveal** flow. Unrevealed commitments forfeit - `pm_commit_no_reveal_penalty_percent` (bp) via `pm_commit_forfeit`. -- At each epoch boundary (`pm_batch_epoch_blocks`, reveal window `pm_reveal_window_blocks`) queued bets - settle at a **uniform price** via the `pm_batch_settle` cron — only the net residual moves the AMM, so - intra-batch ordering carries no advantage and the `Σ reserve ≥ L` invariant is preserved. - -## 17. On-Chain Object Model - -All state lives in **chainbase objects** registered as core indexes at HF14 — there is no SQL database. Field-level definitions live in the operation/object headers and -are queryable read-only via the [`prediction_market_api` plugin](../../../docs/plugins/prediction-market-api.md). The -reputation counters the prototype kept on a `users` table are now fields on `pm_oracle_object`. - -| Object (index) | Holds | Looked up by | -|---|---|---| -| `pm_oracle_object` | oracle registration, insurance, the 14 reputation counters, fault stamps, bans | owner | -| `pm_market_object` | market config, CPMM reserves (`reserve_a/b`, `k`), `*_fee_percent` (bp), `status` / `payout_status`, timers, `dispute_mode`, `a_bets_sum` / `b_bets_sum` | id / creator / oracle / result_expiration | -| `pm_outcome_object` | per-outcome LMSR `q`, `bets_sum`, `bets_count` (multi markets) | market + outcome | -| `pm_bet_object` | a bet — account, `side` / `outcome_index`, `amount`, curve `weight`, `time_penalty`, `status`, `mode` | market / account | -| `pm_liquidity_object` | an LP position — principal, deposit time, time-weight; `provider` empty ⇒ lazy-pool LP | market | -| `pm_commit_object` | a commit-reveal commitment hash + escrow (batch / commit-reveal) | market / account | -| `pm_dispute_object` | a dispute — disputer, `proposed_outcome`, fee escrow, timers, `status`, `dispute_mode` | market | -| `pm_dispute_vote_object` | one committee ballot — voter, `vote_outcome`, `vote_percent` (revisable until close) | market + voter | -| `pm_lazy_pool_object` | the singleton pool — `free_balance` / `allocated_balance` / `earned_balance`, `reward_per_share`, `leverage_fund_used`, `total_shares` | singleton (id 0) | -| `pm_lazy_deposit_object` | a depositor — shares, reward snapshot, unlock time | account | -| `pm_lazy_allocation_object` | the pool's silent LP allocation to one market + graduated-recall state (`bets_sum_at_check`, `check_step`, `recalled_amount`) | market | -| `pm_leverage_position_object` | an open leveraged position — collateral, loan, obligation, curve weight, `status` | account / market + status | -| `pm_creator_ban_object` | a banned creator — `banned_until`, `ban_count` | ban account | - -Reputation metrics are computed on read (`compute_oracle_reliability_score()` — §14), not stored. All -percentage fields are basis points (`*_percent`, bp). Lazy-pool per-market allocations and -graduated-recall state live on `pm_lazy_allocation_object`; oracle fault stamps and reputation counters -live on `pm_oracle_object`. - -**Plugin-only (non-consensus):** `pm_market_meta_object` — off-chain-parsed market metadata -(category / tags / banned jurisdictions) for discovery and jurisdiction filtering; it is built by the -`prediction_market_api` plugin from each market's opaque `metadata` string and never participates in -consensus. - -See the Prediction Market operations reference for the full field definitions of these objects. diff --git a/.qoder/repowiki/en/content/API Reference.md b/.qoder/repowiki/en/content/API Reference.md deleted file mode 100644 index 80730cbc9a..0000000000 --- a/.qoder/repowiki/en/content/API Reference.md +++ /dev/null @@ -1,443 +0,0 @@ -# API Reference - - -**Referenced Files in This Document** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [plugin.hpp](file://plugins/committee_api/include/graphene/plugins/committee_api/committee_api.hpp) -- [plugin.hpp](file://plugins/social_network/plugin.hpp) -- [plugin.hpp](file://plugins/paid_subscription_api/plugin.hpp) -- [plugin.hpp](file://plugins/custom_protocol_api/include/graphene/plugins/custom_protocol_api/custom_protocol_api.hpp) -- [plugin.hpp](file://plugins/invite_api/plugin.hpp) -- [plugin.hpp](file://plugins/witness_api/plugin.hpp) -- [plugin.hpp](file://plugins/network_broadcast_api/plugin.hpp) -- [plugin.hpp](file://plugins/account_history/plugin.hpp) -- [plugin.cpp](file://plugins/account_history/plugin.cpp) -- [history_object.hpp](file://plugins/account_history/include/graphene/plugins/account_history/history_object.hpp) -- [plugin.hpp](file://plugins/follow/plugin.hpp) -- [plugin.hpp](file://plugins/private_message/plugin.hpp) -- [plugin.hpp](file://plugins/tags/plugin.hpp) -- [plugin.hpp](file://plugins/test_api/plugin.hpp) -- [plugin.cpp](file://plugins/operation_history/plugin.cpp) - - -## Update Summary -**Changes Made** -- Enhanced Account History API documentation with improved get_account_history method behavior -- Added detailed error handling documentation for edge cases -- Updated method parameter specifications and validation logic -- Improved documentation for account range tracking and sequence management -- Added practical examples for common API usage patterns - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the VIZ CPP Node JSON-RPC API system. It covers the HTTP and WebSocket endpoints exposed by the node, the method registration mechanism, request/response schemas, error handling, and operational guidance. It also outlines the functional categories of APIs present in the codebase and provides practical usage patterns and integration notes. - -## Project Structure -The JSON-RPC system is implemented as a plugin that registers API methods and dispatches requests. The webserver plugin exposes HTTP and WebSocket endpoints and forwards JSON-RPC requests to the JSON-RPC plugin. Other plugins register their own API methods under named namespaces. - -```mermaid -graph TB -subgraph "HTTP/WebSocket Layer" -WS["Webserver Plugin
HTTP/WS endpoints"] -end -subgraph "JSON-RPC Core" -JR["JSON-RPC Plugin
Method registry and dispatcher"] -end -subgraph "API Plugins" -DB["Database API"] -CM["Committee API"] -SN["Social Network API"] -PS["Paid Subscription API"] -CP["Custom Protocol API"] -IW["Invite API"] -WT["validator API"] -NB["Network Broadcast API"] -AH["Account History API"] -FL["Follow API"] -PM["Private Message API"] -TG["Tags API"] -TA["Test API"] -end -WS --> JR -JR --> DB -JR --> CM -JR --> SN -JR --> PS -JR --> CP -JR --> IW -JR --> WT -JR --> NB -JR --> AH -JR --> FL -JR --> PM -JR --> TG -JR --> TA -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L378-L395) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L203) - -**Section sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L254-L312) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L378-L423) - -## Core Components -- JSON-RPC Plugin: Provides the method registry, dispatch logic, and response envelope. It supports batch requests and maintains method-to-plugin reindexing for compatibility. -- Webserver Plugin: Exposes HTTP and WebSocket endpoints. Routes inbound messages to the JSON-RPC plugin and returns responses. -- API Plugins: Each plugin registers its methods under a namespace (e.g., database_api, social_network, committee_api). Methods follow a consistent signature pattern and return structured results. - -Key behaviors: -- Request envelope: Supports JSON-RPC 2.0 with id, method, and params. -- Method naming: api_name.method_name. -- Batch requests: Array of requests processed serially with ordered responses. -- Error codes: Standardized JSON-RPC error codes plus internal codes for parsing and dispatch failures. - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L46-L54) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L402-L423) - -## Architecture Overview -The runtime flow for HTTP and WebSocket requests: - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "Webserver Plugin" -participant JR as "JSON-RPC Plugin" -participant API as "Target API Plugin" -Client->>WS : "POST / or WS message" -WS->>JR : "call(json)" -JR->>JR : "Parse and validate" -JR->>API : "Dispatch api.method(args)" -API-->>JR : "Result or exception" -JR-->>WS : "JSON-RPC response" -WS-->>Client : "HTTP 200 or WS message" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L216-L246) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L290-L336) - -## Detailed Component Analysis - -### HTTP Endpoints -- Endpoint: HTTP server configured via webserver plugin options. -- Method: POST with JSON body. -- Headers: Content-Type application/json. -- Body: Single JSON-RPC request or array of requests. -- Response: JSON object or array of JSON-RPC responses. - -Operational notes: -- The webserver plugin resolves endpoints and starts listeners for HTTP and/or WebSocket. -- For HTTP, the request body is forwarded to the JSON-RPC plugin; the response is sent back immediately. - -**Section sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L254-L312) -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L216-L246) - -### WebSocket Endpoints -- Endpoint: WebSocket server configured via webserver plugin options. -- Transport: Text frames carrying JSON-RPC messages. -- Behavior: Messages are processed asynchronously; responses are sent back on the same connection. - -**Section sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L254-L312) -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L192-L214) - -### JSON-RPC Envelope and Errors -- Envelope fields: - - jsonrpc: String "2.0". - - id: Integer or string; optional for notifications. - - method: String "api.method" or legacy "call" with params. - - params: Optional array or object depending on method. -- Responses include: - - result: Result object or array. - - error: Object with code, message, and optional data. - - id: Matches request id. - -Standard error codes: -- Parse error, invalid request, method not found, invalid params, internal error, server error, no params, parse params error, error during call. - -**Section sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L27-L32) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L46-L54) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) - -### Method Registration and Dispatch -- Registration: Plugins register methods via a macro-based API declaration and the JSON-RPC plugin's add_api_method. -- Dispatch: The dispatcher validates method names, extracts api_name and method_name, and invokes the bound method with a msg_pack carrying parsed arguments. -- Compatibility: A method reindex maps method names to parent plugins to support legacy calls. - -```mermaid -flowchart TD -Start(["Incoming Request"]) --> Parse["Parse JSON-RPC"] -Parse --> Validate{"Valid?"} -Validate --> |No| Err["Return JSON-RPC error"] -Validate --> |Yes| Resolve["Resolve api.method"] -Resolve --> Found{"Found?"} -Found --> |No| NotFound["Return method not found"] -Found --> |Yes| Call["Invoke bound method"] -Call --> Result["Return result or error"] -Err --> End(["Done"]) -NotFound --> End -Result --> End -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L213) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L109-L113) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L159-L178) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L342-L357) - -### Database API (Blockchain State Queries) -- Namespace: database_api -- Purpose: Read-only queries against the blockchain state. -- Typical methods (selected): - - get_dynamic_global_properties - - get_chain_properties - - get_hardfork_version - - get_block_header, get_block - - get_irreversible_block_header, get_irreversible_block - - lookup_account_names, lookup_accounts, get_account_count - - get_vesting_delegations, get_expiring_vesting_delegations - - get_transaction_hex, get_required_signatures, get_potential_signatures, verify_authority, verify_account_authority - - get_database_info - - get_proposed_transactions - - get_accounts_on_sale, get_accounts_on_auction, get_subaccounts_on_sale -- Notes: - - Many methods accept parameters; consult the API plugin header for exact signatures. - - Subscriptions: set_block_applied_callback, set_pending_transaction_callback, cancel_all_subscriptions. - -Example invocation pattern: -- HTTP: POST with {"jsonrpc":"2.0","id":1,"method":"database_api.get_dynamic_global_properties","params":[]}. -- WebSocket: Send the same JSON text frame. - -**Section sources** -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L137-L169) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L209-L226) - -### Social Network APIs (Content and Interactions) -- Namespace: social_network -- Purpose: Content discovery, discussions, and social interactions. -- Typical methods (selected): - - get_discussions_by_payout, get_post_discussions_by_payout - - get_comment_discussions_by_payout - - get_discussions_by_trending, get_discussions_by_created, get_discussions_by_votes - - get_active_votes, get_account_votes - - get_content_replies - - get_follow_counts, get_followers_by_type, get_following_by_type -- Notes: - - Methods commonly accept pagination and filtering parameters; refer to plugin header for exact signatures. - -Example invocation pattern: -- HTTP: POST with {"jsonrpc":"2.0","id":1,"method":"social_network.get_discussions_by_trending","params":[...]} - -**Section sources** -- [plugin.hpp](file://plugins/social_network/plugin.hpp) - -### Governance APIs (Committee and Proposals) -- Namespace: committee_api -- Purpose: Committee-related operations and proposals. -- Typical methods (selected): - - get_active_committee - - get_proposal - - get_proposals -- Notes: - - Consult the plugin header for exact signatures and parameters. - -Example invocation pattern: -- HTTP: POST with {"jsonrpc":"2.0","id":1,"method":"committee_api.get_active_committee","params":[]} - -**Section sources** -- [plugin.hpp](file://plugins/committee_api/include/graphene/plugins/committee_api/committee_api.hpp) - -### Custom Protocol APIs (Specialized Business Logic) -- Namespace: custom_protocol_api -- Purpose: Specialized operations defined by custom protocol extensions. -- Typical methods (selected): - - get_custom_protocol_data -- Notes: - - Consult the plugin header for exact signatures and parameters. - -Example invocation pattern: -- HTTP: POST with {"jsonrpc":"2.0","id":1,"method":"custom_protocol_api.get_custom_protocol_data","params":[]} - -**Section sources** -- [plugin.hpp](file://plugins/custom_protocol_api/include/graphene/plugins/custom_protocol_api/custom_protocol_api.hpp) - -### Account History API (Enhanced) -- Namespace: account_history -- Purpose: Retrieve account operation history with enhanced error handling and edge case management. -- Method: get_account_history -- Parameters: - - account: String - Account name to query history for - - from: Integer - Absolute sequence number, where UINT32_MAX (-1) means most recent - - limit: Integer - Maximum number of items to return (1-1000, inclusive) -- Return: Map of sequence numbers to operation objects -- Enhanced Features: - - Improved error handling for edge cases - - Better parameter validation with clear error messages - - Account range tracking to prevent searching unavailable sequences - - Enhanced documentation for method behavior - -**Updated** Enhanced get_account_history method with improved error handling and edge case management - -**Section sources** -- [plugin.hpp](file://plugins/account_history/plugin.hpp#L83-L92) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L186-L234) -- [history_object.hpp](file://plugins/account_history/include/graphene/plugins/account_history/history_object.hpp#L44-L119) - -### Additional API Categories -- Paid Subscription API: Namespace paid_subscription_api -- Invite API: Namespace invite_api -- validator API: Namespace witness_api -- Network Broadcast API: Namespace network_broadcast_api -- Follow API: Namespace follow -- Private Message API: Namespace private_message -- Tags API: Namespace tags -- Test API: Namespace test_api - -Notes: -- Each API is implemented by its respective plugin and registered with the JSON-RPC plugin. -- Invocation follows the same JSON-RPC envelope and method naming scheme. - -**Section sources** -- [plugin.hpp](file://plugins/paid_subscription_api/plugin.hpp) -- [plugin.hpp](file://plugins/invite_api/plugin.hpp) -- [plugin.hpp](file://plugins/witness_api/plugin.hpp) -- [plugin.hpp](file://plugins/network_broadcast_api/plugin.hpp) -- [plugin.hpp](file://plugins/follow/plugin.hpp) -- [plugin.hpp](file://plugins/private_message/plugin.hpp) -- [plugin.hpp](file://plugins/tags/plugin.hpp) -- [plugin.hpp](file://plugins/test_api/plugin.hpp) - -## Dependency Analysis -- The webserver plugin depends on the JSON-RPC plugin to process requests. -- The JSON-RPC plugin depends on appbase and maintains a registry of api_name.method_name to bound methods. -- API plugins depend on the JSON-RPC plugin to register their methods. - -```mermaid -graph LR -WS["webserver_plugin"] --> JR["json_rpc_plugin"] -JR --> DB["database_api"] -JR --> CM["committee_api"] -JR --> SN["social_network"] -JR --> PS["paid_subscription_api"] -JR --> CP["custom_protocol_api"] -JR --> IW["invite_api"] -JR --> WT["witness_api"] -JR --> NB["network_broadcast_api"] -JR --> AH["account_history"] -JR --> FL["follow"] -JR --> PM["private_message"] -JR --> TG["tags"] -JR --> TA["test_api"] -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L314-L327) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L378-L395) - -**Section sources** -- [plugin.hpp](file://plugins/webserver/webserver_plugin.cpp#L314-L327) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L378-L400) - -## Performance Considerations -- Thread pool sizing: Configure the webserver thread pool to match workload characteristics. -- Batch requests: Submit multiple requests in a single HTTP call to reduce overhead. -- Subscriptions: Use callbacks judiciously; they can increase memory and CPU usage. -- Rate limiting: Apply external rate limiting at the reverse proxy or load balancer level if needed. -- Account history limits: The get_account_history method enforces a maximum limit of 1000 operations to prevent excessive resource consumption. - -## Troubleshooting Guide -Common issues and resolutions: -- Invalid JSON-RPC envelope: Ensure jsonrpc equals "2.0", id is integer or string, and method is present. -- Method not found: Verify api_name.method_name exists and the plugin is loaded. -- Invalid params: Check parameter types and presence according to the method signature. -- Server errors: Inspect logs for exceptions and stack traces. -- Account history errors: Common errors include account not found in history index, from sequence out of range, and limit exceeded. - -**Updated** Enhanced error handling for account history API with specific error messages for edge cases - -Error handling behavior: -- Parsing and dispatch errors return standardized JSON-RPC error objects. -- Exceptions thrown by API methods are captured and mapped to server errors with optional data. -- Account history API provides specific error messages for parameter validation failures. - -**Section sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L290-L311) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L114-L136) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L194-L202) - -## Conclusion -The VIZ CPP Node exposes a robust JSON-RPC interface via HTTP and WebSocket, backed by a modular plugin architecture. API plugins register methods under distinct namespaces, enabling clear separation of concerns. The Account History API has been enhanced with improved error handling, better parameter validation, and enhanced documentation for edge cases. By following the documented envelopes, method naming, and error handling patterns, clients can reliably integrate with the node for blockchain state queries, social interactions, governance operations, and specialized protocols. - -## Appendices - -### Practical Usage Patterns -- HTTP GET/POST: Use POST with application/json and a JSON-RPC envelope. -- WebSocket: Send text frames with JSON-RPC envelopes; subscribe to block or transaction callbacks if needed. -- Batch: Send an array of requests; receive an array of responses in order. -- Account History: Use get_account_history with proper parameter validation and error handling. - -### Migration and Backwards Compatibility -- Legacy call: The "call" method remains supported for backward compatibility; prefer explicit "api.method" calls. -- Method reindex: Some methods are remapped to parent plugins; ensure your client handles reindexing if you rely on legacy names. -- Account History: The enhanced get_account_history method maintains backward compatibility while providing improved error handling. - -**Section sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L235-L236) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L342-L357) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L186-L234) - -### Account History API Examples -Common usage patterns for the enhanced get_account_history method: - -**Get latest operations for an account:** -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "account_history.get_account_history", - "params": ["useraccount", 4294967295, 100] -} -``` - -**Get operations from a specific sequence:** -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "account_history.get_account_history", - "params": ["useraccount", 1000, 50] -} -``` - -**Error handling examples:** -- Account not found in history index: "Account not found in history index, it may have been purged since the last ${b} blocks are stored in the history" -- From sequence out of range: "From is less than account history start sequence ${s}" or "From is greater than account history end sequence ${s}" -- Limit exceeded: "Limit of ${l} is greater than maximum allowed (1000)" - -**Section sources** -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L186-L234) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L194-L202) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Advanced Topics/Advanced Plugin Development.md b/.qoder/repowiki/en/content/Advanced Topics/Advanced Plugin Development.md deleted file mode 100644 index b787dfe91d..0000000000 --- a/.qoder/repowiki/en/content/Advanced Topics/Advanced Plugin Development.md +++ /dev/null @@ -1,354 +0,0 @@ -# Advanced Plugin Development - - -**Referenced Files in This Document** -- [plugin.md](file://documentation/plugin.md) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [testing.md](file://documentation/testing.md) -- [building.md](file://documentation/building.md) -- [newplugin.py](file://programs/util/newplugin.py) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [account_history_plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides advanced guidance for developing plugins for the VIZ C++ Node. It covers plugin architecture patterns, lifecycle management, integration with the core system, advanced development techniques (custom evaluators, database object extensions, inter-plugin communication), testing strategies, performance optimization, deployment, and troubleshooting. The content is grounded in the repository’s plugin framework, JSON-RPC API binding, evaluator system, and existing plugin implementations. - -## Project Structure -The plugin ecosystem is organized around a modular architecture: -- Core chain and protocol abstractions define operations, evaluators, and database signals. -- The JSON-RPC plugin provides a dispatch mechanism for API registration and invocation. -- Individual plugins implement domain-specific logic, register APIs, and subscribe to chain/database events. -- A scaffolding script automates boilerplate generation for new plugins. - -```mermaid -graph TB -subgraph "Core Chain" -D["database.hpp
Signals and hooks"] -E["evaluator.hpp
Base evaluator"] -CE["chain_evaluator.hpp
Concrete evaluators"] -end -subgraph "JSON-RPC Layer" -J["json_rpc/plugin.hpp
API registry and dispatcher"] -end -subgraph "Plugins" -AH["account_history/plugin.cpp/.hpp
History tracking"] -TA["test_api/test_api_plugin.cpp/.hpp
Sample API"] -WS["webserver_plugin.hpp
HTTP/WebSocket server"] -end -D --> AH -D --> TA -J --> AH -J --> TA -WS --> J -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L23) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L1-L28) -- [building.md](file://documentation/building.md#L1-L200) - -## Core Components -- Application base and plugin lifecycle: Plugins derive from the application base plugin interface and implement initialize/startup/shutdown hooks. They register API factories and connect to database signals. -- JSON-RPC API binding: The JSON-RPC plugin maintains a registry of API methods and dispatches incoming requests. Plugins register their methods via a macro-driven visitor pattern. -- Chain/database integration: Plugins subscribe to database signals (e.g., applied_block, pre_apply_operation, on_applied_transaction) to react to chain events. -- Scaffolding tool: The new plugin generator produces boilerplate for plugin headers, implementation, API classes, and CMake configuration. - -Key implementation references: -- Plugin lifecycle and API registration in a typical plugin implementation. -- JSON-RPC API registration and method dispatch. -- Database signals used by plugins to observe chain activity. -- Scaffolding script for generating plugin boilerplate. - -**Section sources** -- [account_history_plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L97) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L23) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [newplugin.py](file://programs/util/newplugin.py#L126-L217) - -## Architecture Overview -The plugin architecture centers on: -- A plugin base class exposing lifecycle hooks. -- A JSON-RPC plugin that binds API names to method implementations. -- A chain database that emits signals plugins can subscribe to. -- Optional webserver plugin to expose HTTP/WS endpoints. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "webserver_plugin" -participant JR as "json_rpc : : plugin" -participant PL as "MyPlugin API" -participant DB as "database" -Client->>WS : "HTTP/WS request" -WS->>JR : "Dispatch JSONRPC" -JR->>PL : "Invoke method(args)" -PL->>DB : "Read/Write chain state" -DB-->>PL : "Result" -PL-->>JR : "Return value" -JR-->>WS : "Response" -WS-->>Client : "HTTP/WS response" -``` - -**Diagram sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L185-L194) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) - -## Detailed Component Analysis - -### Plugin Lifecycle and Registration Patterns -- Lifecycle: initialize → startup → shutdown. During startup, plugins typically register API factories and connect to database signals. -- Registration: Plugins register APIs via a macro-driven visitor that iterates over declared methods and registers them with the JSON-RPC plugin. -- Example patterns: - - Connect to applied_block to react to new blocks. - - Use weak read locks when querying the database from API methods to avoid contention. - - Add plugin-specific indices to the database for efficient lookups. - -```mermaid -flowchart TD -Start(["Initialize"]) --> Startup["Startup"] -Startup --> RegAPI["Register API factory"] -RegAPI --> ConnectSignals["Connect to database signals"] -ConnectSignals --> RunLoop["Serve requests"] -RunLoop --> Shutdown["Shutdown"] -Shutdown --> End(["Exit"]) -``` - -**Diagram sources** -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L185-L194) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) - -**Section sources** -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L185-L194) -- [plugin.md](file://documentation/plugin.md#L11-L28) - -### JSON-RPC API Binding and Invocation -- API registration: Plugins declare API methods and use a macro to register them with the JSON-RPC plugin. The macro expands to a visitor that binds method names to callable lambdas. -- Dispatch: The JSON-RPC plugin stores method descriptors and invokes bound methods with parsed arguments. -- Argument/result types: Methods accept a single argument struct and return a single result struct; void methods use a dedicated type. - -```mermaid -sequenceDiagram -participant P as "Plugin" -participant JR as "json_rpc : : plugin" -participant C as "Caller" -P->>JR : "Register API methods" -C->>JR : "Call method with args" -JR->>P : "Invoke bound method" -P-->>JR : "Return result" -JR-->>C : "JSONRPC response" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L121-L140) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L25-L35) - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L27-L53) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L25-L35) - -### Database Signals and Inter-Plugin Communication -- Signals: The database emits signals for pre/post operation application, applied blocks, and transaction events. Plugins can subscribe to these signals to implement cross-cutting concerns. -- Inter-plugin coordination: Plugins can communicate indirectly by observing each other’s operations via signals and shared indices. - -```mermaid -sequenceDiagram -participant DB as "database" -participant P1 as "Plugin A" -participant P2 as "Plugin B" -DB->>P1 : "pre_apply_operation(notification)" -DB->>P2 : "pre_apply_operation(notification)" -DB->>P1 : "applied_block(block)" -DB->>P2 : "applied_block(block)" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L487-L489) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L487-L489) - -### Custom Evaluators and Database Object Extensions -- Evaluators: Operations are validated and applied by evaluators. The evaluator base defines apply/get_type, and concrete evaluators implement do_apply. -- Custom operation interpreter: The database supports registering custom operation interpreters to extend the evaluator registry for custom operations. -- Extension patterns: Plugins can add new indices to the database to support efficient queries for custom data. - -```mermaid -classDiagram -class evaluator~OperationType~ { -+apply(op) -+get_type() -} -class evaluator_impl~EvaluatorType, OperationType~ { -+apply(op) -+get_type() -+db() -} -class account_history_plugin { -+plugin_initialize() -+plugin_startup() -+plugin_shutdown() -} -evaluator_impl <|-- account_history_plugin : "uses database signals" -``` - -**Diagram sources** -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L407-L410) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) - -**Section sources** -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L407-L410) - -### Webserver and Real-Time Event Handling -- Webserver plugin: Provides HTTP/WS endpoints and runs its own io_service thread to isolate request handling from the main application thread. -- Real-time events: Plugins can emit notifications via database signals; the webserver can expose these via WebSocket endpoints (pattern demonstrated by the webserver plugin). - -```mermaid -graph TB -WS["webserver_plugin.hpp
HTTP/WS server"] -JR["json_rpc::plugin.hpp
API registry"] -AH["account_history_plugin.cpp
applied_block listener"] -WS --> JR -AH --> JR -``` - -**Diagram sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp#L471-L501) - -**Section sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -### Asynchronous Processing and Threading Model -- Threading: The webserver plugin runs its own io_service thread to avoid blocking the main application thread. Callbacks can be posted to the HTTP thread from any thread. -- Asynchronous patterns: Plugins should avoid heavy work in signal handlers; queue tasks to background threads or use async I/O where appropriate. - -**Section sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L19-L31) - -### Plugin Testing Framework -- Unit tests: Build targets include a chain test executable. Tests are categorized by functionality (basic, block, operation, serialization, etc.). -- Runtime configuration: Test harness supports log level, report level, and selective test execution via runtime options. -- Coverage: Code coverage can be captured using lcov with Debug builds and the coverage flag. - -```mermaid -flowchart TD -Dev["Write tests"] --> Build["Build chain_test"] -Build --> Run["Run tests with options"] -Run --> Report["Generate coverage reports"] -``` - -**Diagram sources** -- [testing.md](file://documentation/testing.md#L1-L43) - -**Section sources** -- [testing.md](file://documentation/testing.md#L1-L43) - -### Deployment and Distribution -- Enabling plugins: Use configuration options to enable plugins and public APIs. Some plugins require replaying the chain when enabling/disabling. -- Public APIs: Configure which APIs are exposed publicly and protect sensitive endpoints. -- Packaging: Drop third-party plugins into the external plugins directory; CMake aggregates internal plugins and builds them automatically. - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) - -## Dependency Analysis -Plugins declare dependencies on other plugins and the chain database. The JSON-RPC plugin is often a dependency for API-enabled plugins. The application base manages plugin initialization order and dependency resolution. - -```mermaid -graph LR -JR["json_rpc::plugin.hpp"] -AH["account_history/plugin.cpp/.hpp"] -TA["test_api/test_api_plugin.cpp/.hpp"] -DB["database.hpp"] -AH --> JR -TA --> JR -AH --> DB -TA --> DB -``` - -**Diagram sources** -- [account_history_plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L61-L65) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) - -**Section sources** -- [account_history_plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L61-L65) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35) - -## Performance Considerations -- Memory management: Use weak read locks when querying the database from API methods to minimize contention. Avoid long-running operations in signal handlers. -- Caching: Maintain in-memory caches for hot paths; invalidate on applied_block or relevant signals. -- Resource utilization: Prefer streaming or paginated queries for large datasets. Limit batch sizes and use database indices added by plugins. -- Concurrency: Offload CPU-intensive tasks to background threads; use async I/O in the webserver plugin to keep the main thread responsive. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Debugging: Use the debug_node plugin to simulate chain state changes and test plugin behavior under controlled scenarios. Bind RPC to localhost and restrict public API exposure when using debug APIs. -- Logging: Adjust log levels and test report levels to gather more details during failures. -- Signal handling: Verify that plugins connect to the correct signals and handle errors gracefully without deadlocking the chain. - -**Section sources** -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) -- [testing.md](file://documentation/testing.md#L16-L23) - -## Conclusion -The VIZ C++ Node provides a robust, extensible plugin architecture. By leveraging the JSON-RPC API binding, database signals, and scaffolding tools, developers can implement advanced plugins ranging from custom APIs to deep chain integrations. Following the lifecycle patterns, performance guidelines, and testing strategies outlined here will help ensure reliable, maintainable, and high-performance plugins. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples Index -- Custom validator: Implement an evaluator for a custom operation and register it via the custom operation interpreter. -- Specialized API: Use the scaffolding tool to generate a plugin, add API methods, and register them with the JSON-RPC plugin. -- System integration: Subscribe to applied_block and pre_apply_operation signals to mirror chain state to external systems. - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L126-L217) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Advanced Topics/Advanced Topics.md b/.qoder/repowiki/en/content/Advanced Topics/Advanced Topics.md deleted file mode 100644 index 4ed9191704..0000000000 --- a/.qoder/repowiki/en/content/Advanced Topics/Advanced Topics.md +++ /dev/null @@ -1,293 +0,0 @@ -# Advanced Topics - - -**Referenced Files in This Document** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [1.hf](file://libraries/chain/hardfork.d/1.hf) -- [10.hf](file://libraries/chain/hardfork.d/10.hf) -- [11.hf](file://libraries/chain/hardfork.d/11.hf) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [CMakeLists.txt](file://plugins/CMakeLists.txt) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides expert-level guidance on advanced topics for the VIZ CPP Node, focusing on hardfork implementation and management, database schema design and optimization, security considerations and vulnerability assessment, and advanced plugin development patterns. It synthesizes the codebase’s hardfork system, fork database, chain database, network node, plugin framework, and protocol versioning to deliver practical, code-backed advice for extending core functionality and integrating with external systems. - -## Project Structure -The VIZ CPP Node is organized around a layered architecture: -- Protocol: Versioning, operations, and core types -- Chain: Block processing, database, fork database, evaluators, and object schemas -- Network: Peer-to-peer node and message handling -- Plugins: Modular extensions exposing APIs and specialized indexes -- Programs: Executables and utilities - -```mermaid -graph TB -subgraph "Protocol" -PVersion["version.hpp"] -end -subgraph "Chain" -DB["database.hpp"] -ForkDB["fork_database.hpp"] -Objects["chain_objects.hpp"] -Eval["evaluator.hpp"] -COI["custom_operation_interpreter.hpp"] -end -subgraph "Network" -NetNode["node.hpp"] -end -subgraph "Plugins" -PList["plugins/CMakeLists.txt"] -ABK["account_by_key_plugin.cpp"] -end -PVersion --> DB -DB --> ForkDB -DB --> Objects -DB --> Eval -DB --> COI -NetNode --> DB -PList --> ABK -``` - -**Diagram sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L1-L156) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L1-L62) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L28) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L1-L233) - -**Section sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L1-L156) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L1-L62) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L28) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L1-L233) - -## Core Components -- Hardfork system: Managed via dedicated headers and a property object storing processed hardforks, current and next hardfork versions, and timestamps. -- Fork database: Maintains a tree of unlinked blocks with indices for ID, previous ID, and block number, enabling efficient branching and rebranching. -- Chain database: Extends a persistent object store with block validation, transaction processing, hardfork orchestration, and plugin hooks. -- Network node: Provides peer discovery, sync, and broadcast with delegate callbacks for block/tx handling. -- Plugin framework: Adds indexes and APIs, integrates with database signals, and supports custom operation interpreters. - -**Section sources** -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf#L18-L56) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L182-L304) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Architecture Overview -The system orchestrates block/application logic through the chain database, which coordinates with the fork database for out-of-order block handling and with plugins for extended functionality. Network peers supply blocks and transactions, validated by the chain database against configured hardforks and checkpoints. - -```mermaid -sequenceDiagram -participant Peer as "Peer" -participant Net as "Network Node" -participant DB as "Chain Database" -participant Fork as "Fork DB" -participant HF as "Hardfork Logic" -Peer->>Net : "Block/Transaction" -Net->>DB : "handle_block()/handle_transaction()" -DB->>HF : "process_hardforks()" -HF-->>DB : "applied hardforks" -DB->>Fork : "push_block()/walk_main_branch_to_num()" -Fork-->>DB : "head/new head" -DB-->>Net : "validation result" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L78-L98) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L511-L516) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L95) - -## Detailed Component Analysis - -### Hardfork Implementation and Management -- Versioning model: Uses a triple (major, hardfork, release) with dedicated hardfork version comparisons. -- Hardfork headers define constants for each hardfork, including activation time and version. -- Hardfork property object tracks processed hardforks, last hardfork, current and next hardfork versions, and next activation time. -- Orchestration: The chain database initializes hardfork arrays, processes hardforks per block, and applies migrations when thresholds are met. - -```mermaid -flowchart TD -Start(["Start"]) --> Init["Initialize hardfork arrays"] -Init --> Check["Check next hardfork time/version"] -Check --> |Threshold reached| Apply["Apply hardfork migration"] -Check --> |Not reached| Wait["Continue normal operation"] -Apply --> UpdateProps["Update hardfork property object"] -UpdateProps --> Next["Advance last_hardfork/current_hardfork_version"] -Next --> End(["End"]) -Wait --> End -``` - -**Diagram sources** -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf#L18-L56) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L511-L516) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L52-L121) - -**Section sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L1-L156) -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf#L18-L56) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [10.hf](file://libraries/chain/hardfork.d/10.hf#L1-L7) -- [11.hf](file://libraries/chain/hardfork.d/11.hf#L1-L7) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L511-L516) - -### Database Schema Design and Optimization -- Object persistence: Chain database extends a persistent object store; objects are defined with multi-index containers supporting unique and composite keys. -- Index optimization: Composite indices enable efficient queries by author/permlink, account authorities, and routing tables; hashed indices accelerate lookups by ID and previous ID. -- Fork database indices: Hashed by block ID and by previous ID; ordered by block number; capped at a maximum depth to control memory growth. -- Schema evolution: New plugin indexes are added via a helper that registers multi-index types with the database. - -```mermaid -classDiagram -class Database { -+initialize_indexes() -+add_plugin_index() -} -class ChainObjects { -+escrow_index -+withdraw_vesting_route_index -+award_shares_expire_index -+block_post_validation_index -} -class ForkDB { -+push_block() -+fetch_branch_from() -+walk_main_branch_to_num() -} -Database --> ChainObjects : "manages" -Database --> ForkDB : "coordinates" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L411-L414) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L50-L201) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L100-L121) - -**Section sources** -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L411-L414) - -### Security Considerations and Vulnerability Assessment -- Cryptographic implementation: Relies on underlying protocol/crypto primitives for signatures and keys; ensure keys are handled securely and never logged. -- API authentication: Plugins expose JSON-RPC APIs; secure endpoints via reverse proxy or TLS termination and restrict access. -- Network security: The node delegates block/tx handling to a delegate; validate all inbound messages and enforce rate limits; use allowed peers and bandwidth caps. -- Vulnerability mitigation: Keep hardforks synchronized across the network; monitor block/post validation; avoid exposing internal ports publicly; sanitize logs to prevent sensitive data leakage. - -[No sources needed since this section provides general guidance] - -### Advanced Plugin Development Patterns -- Custom evaluators: Define evaluators via macros and templates; attach to operations; use database references for state reads/writes. -- Database object extensions: Add plugin-specific indexes using a registration helper; connect to pre/post operation signals to keep auxiliary structures consistent. -- Inter-plugin communication: Use database signals (pre/post apply operation, applied block) to coordinate state changes; pass data via shared objects or plugin APIs. - -```mermaid -sequenceDiagram -participant DB as "Chain Database" -participant Plug as "Plugin" -participant Sig as "Signals" -DB->>Sig : "pre_apply_operation" -Sig-->>Plug : "operation notification" -Plug->>Plug : "update auxiliary indexes" -DB->>Sig : "post_apply_operation" -Sig-->>Plug : "operation notification" -Plug->>Plug : "finalize state" -``` - -**Diagram sources** -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L158-L164) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L286) - -**Section sources** -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L1-L62) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L28) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L1-L233) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L286) - -## Dependency Analysis -- Protocol versioning underpins hardfork comparisons and migrations. -- Chain database depends on fork database for block tree management and on plugin indexes for extended schemas. -- Network node depends on chain database for validation and delegates block/tx handling. -- Plugins depend on chain database signals and registration helpers. - -```mermaid -graph LR -Version["version.hpp"] --> DB["database.hpp"] -DB --> Fork["fork_database.hpp"] -DB --> Objects["chain_objects.hpp"] -DB --> Plugins["Plugins"] -Net["node.hpp"] --> DB -``` - -**Diagram sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L1-L156) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) - -**Section sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L1-L156) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) - -## Performance Considerations -- Memory management: Tune shared memory sizing and periodic checks; adjust increments and minimum free sizes to avoid frequent resizing. -- Fork database depth: The maximum depth bounds memory growth; ensure reordering windows align with operational needs. -- Index selection: Use composite indices for multi-field queries; prefer hashed indices for fast ID lookups; minimize redundant indexes. -- Scalability: Offload heavy analytics to plugins; leverage plugin indexes to reduce chain database overhead; batch operations where appropriate. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Hardfork delays: Verify next hardfork time and version; confirm processed hardforks and last hardfork counters; ensure clocks are synchronized. -- Validation failures: Inspect skip flags and validation steps; check checkpoints and block log integrity; review plugin pre/post operation handlers. -- Network issues: Confirm peer connectivity, bandwidth limits, and allowed peers; inspect propagation data for blocks/transactions. -- Plugin anomalies: Validate plugin initialization and shutdown sequences; ensure indexes are registered and signals are connected. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L54-L73) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L186-L193) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L268-L289) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L197-L222) - -## Conclusion -This guide outlined advanced topics for VIZ CPP Node, covering hardfork lifecycle management, database design with multi-index strategies, security best practices, and plugin development patterns. By leveraging the provided code-backed insights—particularly around hardfork headers, fork database indices, chain database orchestration, and plugin registration—you can extend core functionality safely and efficiently while maintaining performance and security. - -## Appendices -- Example references for deep dives: - - Hardfork headers: [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7), [10.hf](file://libraries/chain/hardfork.d/10.hf#L1-L7), [11.hf](file://libraries/chain/hardfork.d/11.hf#L1-L7) - - Plugin registration: [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - - Plugin example: [account_by_key_plugin.cpp](file://plugins/account_by_key/account_by_key_plugin.cpp#L1-L233) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Advanced Topics/Database Schema Design.md b/.qoder/repowiki/en/content/Advanced Topics/Database Schema Design.md deleted file mode 100644 index 7da4617ba1..0000000000 --- a/.qoder/repowiki/en/content/Advanced Topics/Database Schema Design.md +++ /dev/null @@ -1,554 +0,0 @@ -# Database Schema Design - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the database schema design and persistence model of VIZ CPP Node. It covers: -- Object persistence system and chain object types -- Database schema definitions and storage optimization strategies -- Fork database implementation, conflict resolution, and branch management -- Index management and query optimization techniques -- Object relationships and interaction patterns -- Schema evolution, versioning, migrations, and backward compatibility -- Practical examples for extending the schema with custom objects and optimizing queries -- Maintenance procedures and guidance for designing efficient data models for plugins - -## Project Structure -The database layer is built on top of ChainBase and integrates with Protocol types. The schema is defined via object classes and Boost.MultiIndex containers. Core runtime components include: -- Database lifecycle and schema initialization -- Fork database for chain branching and conflict resolution -- Index registration and plugin index hooks -- Object definitions for accounts, content, validators, proposals, invites, and auxiliary objects - -```mermaid -graph TB -subgraph "Database Layer" -DB["database.hpp/.cpp"] -IDX["index.hpp"] -FDB["fork_database.hpp/.cpp"] -end -subgraph "Schema Objects" -TYPES["chain_object_types.hpp"] -ACC["account_object.hpp"] -CON["content_object.hpp"] -WIT["witness_objects.hpp"] -PRO["proposal_object.hpp"] -INV["invite_objects.hpp"] -EXT["chain_objects.hpp"] -end -DB --> FDB -DB --> IDX -DB --> TYPES -DB --> ACC -DB --> CON -DB --> WIT -DB --> PRO -DB --> INV -DB --> EXT -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [database.cpp](file://libraries/chain/database.cpp#L206-L268) -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp#L8-L24) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L28-L145) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L226) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [database.cpp](file://libraries/chain/database.cpp#L206-L268) -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp#L8-L24) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) - -## Core Components -- Database lifecycle and initialization: - - Open and reindex operations, schema initialization, evaluator setup, and hardfork initialization - - Memory management and resizing during replay -- Fork database: - - Maintains a tree of unlinked and linked blocks, supports branch fetching and head updates - - Enforces maximum reordering window and invalidation flags -- Index management: - - Core and plugin indices are registered via helper functions - - MultiIndex containers define primary and composite indexes per object type - -Key responsibilities: -- [Open/reindex](file://libraries/chain/database.cpp#L206-L268) -- [Initialize schema and indexes](file://libraries/chain/database.cpp#L2992-L3005) -- [Fork database operations](file://libraries/chain/fork_database.cpp#L33-L90) -- [Index registration helpers](file://libraries/chain/include/graphene/chain/index.hpp#L8-L24) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L206-L268) -- [database.cpp](file://libraries/chain/database.cpp#L2992-L3005) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L90) -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp#L8-L24) - -## Architecture Overview -The database architecture combines ChainBase with custom schema objects and a fork-aware block storage model. - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, ...) -+reindex(data_dir, shared_mem_dir, ...) -+initialize_indexes() -+init_schema() -+push_block(...) -+push_transaction(...) -+get_account(name) -+get_content(author, permlink) -+get_witness(owner) -+get_proposal(author, title) -} -class fork_database { -+push_block(signed_block) -+set_head(item) -+fetch_branch_from(first, second) -+walk_main_branch_to_num(n) -+is_known_block(id) -} -class account_object -class content_object -class witness_object -class proposal_object -class invite_object -database --> fork_database : "uses" -database --> account_object : "persists" -database --> content_object : "persists" -database --> witness_object : "persists" -database --> proposal_object : "persists" -database --> invite_object : "persists" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L144) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L114) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L28-L83) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L38) - -## Detailed Component Analysis - -### Object Persistence System and Chain Object Types -Object types are enumerated and mapped to persistent objects. Each object inherits from a base object class and is associated with a MultiIndex container that defines its indexes. - -- Enumerated object types: - - Dynamic global property, account, authority, validator, transaction, block summary, validator schedule, content, content type, content vote, validator vote, hardfork property, vesting routes, authorities history, recovery requests, escrow, block stats, vesting delegation, fixed delegation, delegation expiration, metadata, proposal, required approvals, committee request/vote, invite, award shares expiration, paid subscriptions, validator penalties, block post validation - -- Object identity and serialization: - - Object IDs are typed identifiers; reflection and raw packing/unpacking are supported for persistence and RPC - -Representative definitions: -- [Object types enumeration](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [Object ID and reflection](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L113-L207) - -Storage optimization strategies: -- Shared string buffers and inter-process allocators minimize memory overhead -- Composite indexes reduce scans for common queries (e.g., by_name, by_cashout_time) - -**Section sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L113-L207) - -### Account Object Schema and Indexes -Accounts store balances, vesting shares, delegation metrics, auction/bidding state, bandwidth, and governance participation. - -Primary and composite indexes: -- by_id (unique) -- by_name (unique, lexicographic) -- by_account_on_sale/by_account_on_auction (non-unique) -- by_account_on_sale_start_time (non-unique) -- by_subaccount_on_sale (non-unique) -- by_next_vesting_withdrawal (composite: next_vesting_withdrawal + id) - -Optimization notes: -- Composite index by_next_vesting_withdrawal enables efficient batch processing of upcoming withdrawals -- Separate indexes for sale/auction flags support targeted queries for marketplace operations - -**Section sources** -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L144) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L291-L315) - -### Content Object Schema and Indexes -Content objects represent posts/comments with voting, payout, and nesting metadata. Content types and votes are separate objects with dedicated indexes. - -Indexes: -- by_id (unique) -- by_cashout_time (composite: cashout_time + id) -- by_permlink (composite: author + permlink) -- by_root (composite: root_content + id) -- by_parent (composite: parent_author + parent_permlink + id) -- Non-consensus indexes (API-heavy): - - by_last_update (composite: parent_author + last_update + id) - - by_author_last_update (composite: author + last_update + id) - -Content vote indexes: -- by_id (unique) -- by_content_voter (unique composite: content + voter) -- by_voter_content (unique composite: voter + content) -- by_voter_last_update (composite: voter + last_update + content) -- by_content_weight_voter (composite: content + weight + voter) - -Optimization notes: -- Composite indexes on author/permlink and root/content enable fast lookup of discussions and hierarchy navigation -- Weighted ordering by content_weight_voter supports leaderboards and trending calculations - -**Section sources** -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L114) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L197-L248) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L144-L184) - -### validator and Governance Objects -validator objects track scheduling, votes, signing keys, and penalties. Governance objects include votes and schedules. - -Indexes: -- witness_object: - - by_id (unique) - - by_work (non-unique) - - by_name (unique) - - by_vote_name (composite: votes + owner) - - by_counted_vote_name (composite: counted_votes + owner) - - by_schedule_time (composite: virtual_scheduled_time + id) -- witness_vote_object: - - by_id (unique) - - by_account_witness (unique composite: account + validator) - - by_witness_account (unique composite: validator + account) -- witness_schedule_object: - - by_id (unique) -- witness_penalty_expire_object: - - by_id (unique) - - by_account (non-unique) - - by_expiration (non-unique) - -Optimization notes: -- Virtual scheduled time index supports O(log N) scheduling decisions -- Composite indexes on account-validator pairs enable fast vote lookups - -**Section sources** -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L183-L219) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L224-L248) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L250-L256) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L276-L291) - -### Proposal and Authority Objects -Proposals encapsulate partially approved transactions with required/approved sets. Required approvals link accounts to proposals. - -Indexes: -- proposal_object: - - by_id (unique) - - by_account (composite: author + title) - - by_expiration (non-unique) -- required_approval_object: - - by_id (unique) - - by_account (composite: account + proposal) - -Optimization notes: -- Composite keys on author/title and account/proposal enable targeted queries for governance dashboards - -**Section sources** -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L108-L126) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L128-L140) - -### Invite Object Schema -Invite objects track creator, receiver, secret, key, balances, and status. - -Indexes: -- by_id (unique) -- by_invite_key (non-unique) -- by_status (non-unique) -- by_creator (non-unique) -- by_receiver (non-unique) - -Optimization notes: -- Multiple non-unique indexes support quick filtering by key, status, and participant roles - -**Section sources** -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L44-L66) - -### Auxiliary and Specialized Objects -Auxiliary objects include vesting routes, escrow, award shares expiration, and block post validation. - -Examples: -- Withdraw vesting routes: - - by_id (unique) - - by_withdraw_route (composite: from_account + to_account) - - by_destination (composite: to_account + id) -- Escrow: - - by_id (unique) - - by_from_id (composite: from + escrow_id) - - by_to (composite: to + id) - - by_agent (composite: agent + id) - - by_ratification_deadline (composite: is_approved + ratification_deadline + id) -- Award shares expiration: - - by_id (unique) - - by_expiration (non-unique) -- Block post validation: - - by_id (unique) - -Optimization notes: -- Composite indexes on multi-key fields enable targeted settlement/cleanup workflows - -**Section sources** -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L75-L98) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L104-L141) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L160-L172) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L192-L201) - -### Fork Database Implementation -The fork database manages a tree of blocks with: -- Linked index for canonical chain -- Unlinked index for orphaned/out-of-order blocks -- Hashed indexes by block_id and by_previous -- Ordered index by block_num - -Conflict resolution and branch management: -- push_block inserts blocks and links to previous if known -- fetch_branch_from walks both branches toward a common ancestor -- walk_main_branch_to_num and fetch_block_on_main_branch_by_number traverse canonical chain -- set_max_size prunes old blocks beyond a configurable threshold - -Invalidation and unlinkability: -- Blocks flagged invalid prevent further linking -- Attempting to push blocks outside the reordering window triggers assertions - -```mermaid -flowchart TD -Start(["Push Block"]) --> CheckHead["Has head and previous known?"] -CheckHead --> |No| InsertUnlinked["Insert into unlinked index"] -CheckHead --> |Yes| Link["Link to previous"] -Link --> InsertLinked["Insert into linked index"] -InsertLinked --> UpdateHead["Update head if higher num"] -UpdateHead --> Done(["Return head"]) -InsertUnlinked --> TryNext["Attempt to link pending blocks"] -TryNext --> Done -``` - -**Diagram sources** -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L90) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L100-L121) - -**Section sources** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L90) - -### Index Management and Query Optimization -Index registration: -- Core indices are added via add_core_index -- Plugin indices are registered via add_plugin_index and signaled after schema initialization - -Common optimization techniques: -- Prefer composite indexes for multi-field queries (e.g., author+permlink, voter+content) -- Use non-unique indexes for status filters (e.g., by_account_on_sale, by_expiration) -- Order composite keys by selectivity and access patterns (e.g., time-based indexes with secondary sort by id) - -**Section sources** -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp#L8-L24) -- [database.cpp](file://libraries/chain/database.cpp#L2952-L2960) - -### Object Relationship Patterns -Relationships among entities: -- Accounts own content and votes; content references authors and parents; votes reference accounts and content -- validators schedule and produce blocks; validator votes link accounts to validators -- Proposals require approvals from active/master/regular sets; required approvals link accounts to proposals -- Invites connect creators/receivers and keys to balances -- Vesting delegation links delegators to delegatees; expiration objects track time-based cleanup - -```mermaid -erDiagram -ACCOUNT ||--o{ CONTENT : "author" -ACCOUNT ||--o{ CONTENT_VOTE : "voter" -CONTENT ||--o{ CONTENT_VOTE : "content" -ACCOUNT ||--o{ WITNESS_VOTE : "account" -validator ||--o{ WITNESS_VOTE : "validator" -ACCOUNT ||--o{ VESTING_DELEGATION : "delegator" -ACCOUNT ||--o{ VESTING_DELEGATION_EXPIRATION : "delegator" -ACCOUNT ||--o{ PROPOSAL : "author" -ACCOUNT ||--o{ REQUIRED_APPROVAL : "account" -PROPOSAL ||--o{ REQUIRED_APPROVAL : "proposal" -ACCOUNT ||--o{ INVITE : "creator/receiver" -``` - -**Diagram sources** -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L144) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L121-L138) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L135-L150) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L90-L103) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L38) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L181-L228) - -## Dependency Analysis -The database depends on ChainBase for persistence primitives and integrates with Protocol types. The fork database is tightly coupled with block storage and maintains a separate block tree. - -```mermaid -graph LR -DB["database.hpp/.cpp"] --> CB["ChainBase"] -DB --> PROT["protocol/*"] -DB --> FDB["fork_database.hpp/.cpp"] -DB --> SCHEMA["schema headers (.hpp)"] -SCHEMA --> TYPES["chain_object_types.hpp"] -SCHEMA --> OBJACC["account_object.hpp"] -SCHEMA --> OBJCON["content_object.hpp"] -SCHEMA --> OBJWIT["witness_objects.hpp"] -SCHEMA --> OBJPRO["proposal_object.hpp"] -SCHEMA --> OBJINV["invite_objects.hpp"] -SCHEMA --> OBJEXT["chain_objects.hpp"] -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L50) -- [database.cpp](file://libraries/chain/database.cpp#L1-L40) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L20) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L1-L40) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L20) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L1-L15) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L20) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L1-L15) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L1-L15) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L20) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L50) -- [database.cpp](file://libraries/chain/database.cpp#L1-L40) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L20) - -## Performance Considerations -- Memory management: - - Shared memory sizing and incremental growth during reindex - - Periodic checks and reserved memory protection -- Index selection: - - Use composite indexes to avoid full scans on multi-column filters - - Prefer non-unique indexes for status-based filtering -- Fork pruning: - - Limit maximum reordering window to cap memory footprint -- Batch operations: - - Leverage composite ordering for efficient iteration (e.g., by_next_vesting_withdrawal) - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and diagnostics: -- Database open failures: - - Revision mismatch between chainbase and head block num - - Head block mismatch with block log -- Reindex interruptions: - - Signal guard handles OS signals during replay -- Memory pressure: - - Automatic resizing and periodic free memory checks -- Fork database errors: - - Unlinkable block exceptions when previous is unknown - - Invalid block flags prevent propagation - -Operational references: -- [Open and revision checks](file://libraries/chain/database.cpp#L242-L248) -- [Block log validation](file://libraries/chain/database.cpp#L250-L257) -- [Signal guard and reindex loop](file://libraries/chain/database.cpp#L300-L340) -- [Memory checks and resizing](file://libraries/chain/database.cpp#L396-L400) -- [Fork database unlinkable assertion](file://libraries/chain/fork_database.cpp#L59-L63) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L242-L248) -- [database.cpp](file://libraries/chain/database.cpp#L250-L257) -- [database.cpp](file://libraries/chain/database.cpp#L300-L340) -- [database.cpp](file://libraries/chain/database.cpp#L396-L400) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L59-L63) - -## Conclusion -The VIZ CPP Node database schema leverages ChainBase with carefully designed MultiIndex containers to support high-throughput consensus and API workloads. The fork database ensures robust branch handling and conflict resolution. Composite indexes and typed object IDs enable efficient queries and maintainability. The modular index registration pattern allows plugins to extend the schema safely. Proper maintenance and monitoring of memory and fork pruning are essential for sustained performance. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Schema Evolution and Migration Guidance -- Versioning and hardforks: - - Hardfork timestamps and versions are maintained in the database and processed during initialization -- Migration strategies: - - Use schema initialization to register new indices and objects - - Apply conditional logic during replay to transform legacy data into new structures -- Backward compatibility: - - Keep existing indexes and IDs stable - - Add new optional fields and non-conflicting indexes - - Avoid changing primary key semantics - -References: -- [Hardfork initialization and processing](file://libraries/chain/database.cpp#L262-L264) -- [Schema initialization hook](file://libraries/chain/database.cpp#L2992-L3005) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L262-L264) -- [database.cpp](file://libraries/chain/database.cpp#L2992-L3005) - -### Extending the Schema with Custom Objects -Steps: -- Define a new object class inheriting from the base object -- Declare MultiIndex container with desired indexes -- Register the index via add_core_index or add_plugin_index -- Reflect the object for serialization - -Example references: -- [Core index registration helper](file://libraries/chain/include/graphene/chain/index.hpp#L14-L21) -- [Object definition pattern](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L30) -- [MultiIndex container pattern](file://libraries/chain/include/graphene/chain/content_object.hpp#L197-L248) - -**Section sources** -- [index.hpp](file://libraries/chain/include/graphene/chain/index.hpp#L14-L21) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L30) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L197-L248) - -### Query Optimization Examples -- Fast lookup by author and permlink: - - Use by_permlink composite index on content -- Efficient vote ranking: - - Use by_content_weight_voter composite index on content votes -- Batch vesting withdrawals: - - Use by_next_vesting_withdrawal composite index on accounts -- Governance filtering: - - Use by_expiration on proposals and by_account on required approvals - -References: -- [Content by_permlink](file://libraries/chain/include/graphene/chain/content_object.hpp#L210-L214) -- [Content vote by_content_weight_voter](file://libraries/chain/include/graphene/chain/content_object.hpp#L172-L181) -- [Account by_next_vesting_withdrawal](file://libraries/chain/include/graphene/chain/account_object.hpp#L307-L312) -- [Proposal by_expiration](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L123-L125) -- [Required approval by_account](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L134-L139) - -**Section sources** -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L210-L214) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L172-L181) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L307-L312) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L123-L125) -- [proposal_object.hpp](file://libraries/chain/include/graphene/chain/proposal_object.hpp#L134-L139) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Advanced Topics/Hardfork Management.md b/.qoder/repowiki/en/content/Advanced Topics/Hardfork Management.md deleted file mode 100644 index 60eb37ed22..0000000000 --- a/.qoder/repowiki/en/content/Advanced Topics/Hardfork Management.md +++ /dev/null @@ -1,550 +0,0 @@ -# Hardfork Management - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [1.hf](file://libraries/chain/hardfork.d/1.hf) -- [2.hf](file://libraries/chain/hardfork.d/2.hf) -- [3.hf](file://libraries/chain/hardfork.d/3.hf) -- [4.hf](file://libraries/chain/hardfork.d/4.hf) -- [5.hf](file://libraries/chain/hardfork.d/5.hf) -- [6.hf](file://libraries/chain/hardfork.d/6.hf) -- [7.hf](file://libraries/chain/hardfork.d/7.hf) -- [8.hf](file://libraries/chain/hardfork.d/8.hf) -- [9.hf](file://libraries/chain/hardfork.d/9.hf) -- [10.hf](file://libraries/chain/hardfork.d/10.hf) -- [11.hf](file://libraries/chain/hardfork.d/11.hf) -- [12.hf](file://libraries/chain/hardfork.d/12.hf) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) - - -## Update Summary -**Changes Made** -- Added Emergency Consensus Recovery (HF12) as the latest hardfork implementation -- Updated hardfork numbering from 11 to 12 with CHAIN_HARDFORK_12_VERSION and CHAIN_HARDFORK_12_TIME configurations -- Enhanced validator scheduling logic with emergency mode activation -- Added emergency consensus recovery mechanisms and three-state safety enforcement -- Updated CHAIN_NUM_HARDFORKS from 11 to 12 in preamble -- Added comprehensive emergency mode functionality including fork switching and validator management - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the hardfork management system in the VIZ C++ Node. It covers how hardforks are defined, stored, loaded, and enforced during node runtime; how scheduled upgrades are coordinated with validator voting; how backward compatibility is maintained; and how migrations and state transitions are executed. The system now includes Emergency Consensus Recovery (HF12) as the latest hardfork implementation with sophisticated emergency mode activation and validator scheduling changes designed to recover from network consensus failures. - -## Project Structure -The hardfork system is centered around: -- A dedicated directory of hardfork definition files under libraries/chain/hardfork.d -- A database-level hardfork property object that tracks current and next hardfork versions and timestamps -- Runtime logic in the database that initializes hardfork state, evaluates hardfork boundaries, and applies version-specific behavior -- Emergency consensus recovery mechanisms for network failure scenarios - -```mermaid -graph TB -HFDir["Hardfork Definitions
libraries/chain/hardfork.d/*.hf"] -Preamble["Preamble Header
0-preamble.hf"] -HF1["HF1
1.hf"] -HF2["HF2
2.hf"] -HF3["HF3
3.hf"] -HF4["HF4
4.hf"] -HF5["HF5
5.hf"] -HF6["HF6
6.hf"] -HF7["HF7
7.hf"] -HF8["HF8
8.hf"] -HF9["HF9
9.hf"] -HF10["HF10
10.hf"] -HF11["HF11
11.hf"] -HF12["HF12
12.hf"] -DBHdr["Database Hardfork Properties
database.hpp"] -DBInit["Hardfork Init & Evaluation
database.cpp"] -Emergency["Emergency Consensus
Recovery"] -validator["Enhanced validator
Scheduling"] -Config["Configuration
Parameters"] -HFDir --> Preamble -HFDir --> HF1 -HFDir --> HF2 -HFDir --> HF3 -HFDir --> HF4 -HFDir --> HF5 -HFDir --> HF6 -HFDir --> HF7 -HFDir --> HF8 -HFDir --> HF9 -HFDir --> HF10 -HFDir --> HF11 -HFDir --> HF12 -Preamble --> DBHdr -HFDir --> DBInit -DBHdr --> DBInit -HF12 --> Emergency -HF12 --> validator -HF12 --> Config -``` - -**Diagram sources** -- [0-preamble.hf:55-56](file://libraries/chain/hardfork.d/0-preamble.hf#L55-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [config.hpp:110-123](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L123) - -**Section sources** -- [0-preamble.hf:1-56](file://libraries/chain/hardfork.d/0-preamble.hf#L1-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -## Core Components -- Hardfork definition files (*.hf): Define constants for each hardfork ID, timestamp, and protocol hardfork version. They are included by the preamble and compiled into the node binary. -- Hardfork property object: Tracks last processed hardfork, current hardfork version, and next hardfork version/time. Updated by runtime logic and persisted in the database. -- Database runtime: Initializes hardfork state on open/reindex, evaluates hardfork boundaries during block application, and conditionally applies behavior changes gated by has_hardfork() checks. -- **Emergency Consensus Recovery**: Advanced emergency mode activation that automatically recovers network consensus when blocks stop being produced for extended periods. - -Key responsibilities: -- Version management: Maintains arrays of hardfork times and versions used by the node, now supporting up to 12 hardforks. -- Scheduled upgrades: Watches validator votes and sets next hardfork according to majority. -- Backward compatibility: Uses has_hardfork() checks to branch behavior depending on applied hardfork level. -- Migration and state transitions: Applies changes to chain properties, validators, and runtime logic when crossing hardfork boundaries. -- **Network recovery**: Implements automatic emergency mode activation and recovery mechanisms. - -**Section sources** -- [0-preamble.hf:54-56](file://libraries/chain/hardfork.d/0-preamble.hf#L54-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -## Architecture Overview -The hardfork architecture integrates definitions, runtime initialization, and evaluation during block processing, now enhanced with emergency consensus recovery capabilities. - -```mermaid -sequenceDiagram -participant Node as "Node Startup" -participant DB as "Database" -participant HFProps as "Hardfork Property Object" -participant ForkDB as "Fork DB" -participant BlockLog as "Block Log" -participant Emergency as "Emergency Mode" -Node->>DB : open(data_dir, shared_mem_dir, ...) -DB->>DB : init_schema(), initialize_indexes(), initialize_evaluators() -DB->>HFProps : load current_hardfork_version, next_hardfork, next_hardfork_time -DB->>BlockLog : open("block_log") -DB->>ForkDB : start_block(head_block) -DB->>DB : init_hardforks() (reads persisted state) -DB->>Emergency : check emergency conditions -Emergency-->>DB : activate if needed -DB-->>Node : ready to validate/apply blocks -loop Block Processing -Node->>DB : push_block(new_block) -DB->>DB : evaluate hardfork boundaries -DB->>HFProps : update next_hardfork if validator consensus changes -DB->>Emergency : monitor LIB timestamp -Emergency-->>DB : activate/deactivate emergency mode -DB-->>Node : block accepted or rejected based on hardfork rules -end -``` - -**Diagram sources** -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [database.cpp:2052-2143](file://libraries/chain/database.cpp#L2052-L2143) - -## Detailed Component Analysis - -### Hardfork Directory and Definition Files -- Purpose: Provide compile-time constants for hardfork IDs, timestamps, and protocol hardfork versions. -- Organization: One *.hf file per hardfork, plus a preamble header that defines the hardfork property object schema and counts. -- **Updated**: Now includes HF12 (Emergency Consensus Recovery) as the latest hardfork. -- Example entries: - - Hardfork 1: timestamp and version for fixing a median calculation. - - Hardfork 2: timestamp and version for fixing a committee approval threshold. - - Hardfork 4: introduces major protocol changes (award operations, custom sequences). - - Hardfork 6: modifies validator penalties and vote counting. - - Hardfork 9: adjusts chain parameters for invites, subscriptions, and fees. - - Hardfork 11: emission model changes. - - **Hardfork 12: Emergency Consensus Recovery with emergency mode activation and validator scheduling changes**. - -Practical notes: -- Modify *.hf files to define a new hardfork; do not edit generated files. -- Keep timestamps realistic and coordinated with validator voting. -- **Updated CHAIN_NUM_HARDFORKS from 11 to 12 in preamble**. - -**Section sources** -- [0-preamble.hf:54-56](file://libraries/chain/hardfork.d/0-preamble.hf#L54-L56) -- [1.hf:1-7](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [2.hf:1-7](file://libraries/chain/hardfork.d/2.hf#L1-L7) -- [3.hf:1-7](file://libraries/chain/hardfork.d/3.hf#L1-L7) -- [4.hf:1-7](file://libraries/chain/hardfork.d/4.hf#L1-L7) -- [5.hf:1-7](file://libraries/chain/hardfork.d/5.hf#L1-L7) -- [6.hf:1-7](file://libraries/chain/hardfork.d/6.hf#L1-L7) -- [7.hf:1-7](file://libraries/chain/hardfork.d/7.hf#L1-L7) -- [8.hf:1-7](file://libraries/chain/hardfork.d/8.hf#L1-L7) -- [9.hf:1-7](file://libraries/chain/hardfork.d/9.hf#L1-L7) -- [10.hf:1-7](file://libraries/chain/hardfork.d/10.hf#L1-L7) -- [11.hf:1-7](file://libraries/chain/hardfork.d/11.hf#L1-L7) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -### Hardfork Property Object and Runtime State -- Schema: Contains processed hardforks vector, last hardfork ID, current hardfork version, and next hardfork version/time. -- Initialization: During open(), the node loads persisted hardfork state and ensures consistency with the chainbase revision and block log. -- Updates: During block application, the node evaluates validator consensus and updates next_hardfork accordingly. -- **Enhanced**: Now supports emergency consensus properties for HF12. - -```mermaid -classDiagram -class HardforkPropertyObject { -+id -+processed_hardforks -+last_hardfork -+current_hardfork_version -+next_hardfork -+next_hardfork_time -+emergency_consensus_active -+emergency_consensus_start_block -} -class Database { -+init_hardforks() -+process_hardforks() -+apply_hardfork(hardfork) -+has_hardfork(hardfork) bool -+_hardfork_times[] -+_hardfork_versions[] -} -Database --> HardforkPropertyObject : "reads/writes" -``` - -**Diagram sources** -- [0-preamble.hf:18-56](file://libraries/chain/hardfork.d/0-preamble.hf#L18-L56) -- [global_property_object.hpp:138-144](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L138-L144) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -**Section sources** -- [0-preamble.hf:18-56](file://libraries/chain/hardfork.d/0-preamble.hf#L18-L56) -- [global_property_object.hpp:138-144](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L138-L144) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -### Emergency Consensus Recovery (HF12) -**New Section**: HF12 introduces comprehensive emergency consensus recovery mechanisms designed to automatically recover network consensus when blocks stop being produced for extended periods. - -#### Emergency Mode Activation -- **Automatic Detection**: Monitors last irreversible block (LIB) timestamp and activates emergency mode after CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC (1 hour) without new blocks. -- **Emergency validator**: Creates and activates the CHAIN_EMERGENCY_WITNESS_ACCOUNT ("committee") with CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY to produce blocks. -- **Neutral Voting**: Emergency validator votes for the currently applied hardfork version (status quo) to avoid pushing for new hardforks. - -#### Three-State Safety Enforcement -- **Healthy Network**: Participation ≥ 33% - enforces safe defaults automatically, overriding manual config overrides. -- **Distressed Network**: Participation < 33% - honors manual config overrides to allow operators to accelerate recovery. -- **Emergency Mode**: Automatically bypasses both stale and participation checks when emergency consensus is active. - -#### Enhanced validator Scheduling -- **Hybrid Schedule**: During emergency mode, replaces unavailable validator slots with emergency validator while maintaining real validator positions. -- **Vote Weighted Fork Switching**: HF12 implements vote-weighted chain comparison during fork switching, using sum of raw votes from unique non-committee validators as primary criterion. -- **Median Computation**: Excludes emergency validator from median property computations to prevent skewing chain parameters. - -```mermaid -flowchart TD -Start(["Block Production Check"]) --> CheckHF["Check HF12 Active?"] -CheckHF --> |Yes| CheckEmergency{"Emergency Mode Active?"} -CheckHF --> |No| Legacy["Legacy Behavior"] -CheckEmergency --> |Yes| EnableProduction["Auto-enable Production
Bypass Stale & Participation Checks"] -CheckEmergency --> |No| CheckParticipation["Check Participation Rate"] -CheckParticipation --> |≥33%| Healthy["Healthy Network
Enforce Safe Defaults"] -CheckParticipation --> |<33%| Distressed["Distressed Network
Honor Manual Overrides"] -EnableProduction --> End(["Production Allowed"]) -Healthy --> End -Distressed --> End -Legacy --> End -``` - -**Diagram sources** -- [validator.cpp:354-392](file://plugins/validator/validator.cpp#L354-L392) -- [database.cpp:2052-2143](file://libraries/chain/database.cpp#L2052-L2143) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) - -**Section sources** -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [database.cpp:2052-2143](file://libraries/chain/database.cpp#L2052-L2143) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [validator.cpp:354-392](file://plugins/validator/validator.cpp#L354-L392) - -### Hardfork Evaluation and Block Application -- During block validation and application, the node checks: - - Whether the current hardfork version requires applying changes. - - Whether validator consensus indicates a scheduled upgrade. - - **Emergency mode activation conditions** based on LIB timestamp monitoring. -- The node compares validator votes against configured hardfork versions/times and updates next_hardfork accordingly. -- Behavior changes are gated behind has_hardfork() checks to preserve backward compatibility. -- **Enhanced**: HF12 adds emergency consensus detection and three-state safety enforcement logic. - -```mermaid -flowchart TD -Start(["Start Block Apply"]) --> CheckHF["Check current_hardfork_version vs next_hardfork"] -CheckHF --> Consensus{"validator consensus
requires upgrade?"} -Consensus --> |Yes| UpdateNext["Update next_hardfork and time"] -Consensus --> |No| CheckEmergency["Check Emergency Mode Conditions"] -CheckEmergency --> EmergencyActive{"Emergency Mode
Active?"} -EmergencyActive --> |Yes| EmergencyLogic["Apply Emergency
Consensus Logic"] -EmergencyActive --> |No| Continue["Continue with current version"] -UpdateNext --> Continue -EmergencyLogic --> Continue -Continue --> ApplyOps["Apply operations with
has_hardfork() branches"] -ApplyOps --> End(["End Block Apply"]) -``` - -**Diagram sources** -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [database.cpp:1600-1654](file://libraries/chain/database.cpp#L1600-L1654) - -**Section sources** -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [database.cpp:1600-1654](file://libraries/chain/database.cpp#L1600-L1654) - -### Migration Procedures and State Transitions -- On open(): - - Initialize schema and indexes. - - Open block log and fork DB. - - Initialize hardfork state from persisted data. - - Assert chainbase revision matches head block number. - - **Initialize emergency consensus properties if present**. -- On reindex: - - Replay blocks from the block log with skip flags optimized for speed. - - Apply each block with hardfork-aware logic including emergency mode detection. - - Set revision periodically to ensure progress. - - **Process emergency consensus state transitions during replay**. - -Operational guidance: -- Before upgrading, back up the database and block log. -- Run with read-only mode initially to verify compatibility. -- Monitor logs for hardfork-related warnings or errors. -- **Monitor emergency mode activation and deactivation events**. - -**Section sources** -- [database.cpp:206-268](file://libraries/chain/database.cpp#L206-L268) -- [database.cpp:270-350](file://libraries/chain/database.cpp#L270-L350) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -### Rollback and Recovery for Failed Upgrades -- Undo sessions: The database uses undo sessions to roll back partial changes when block application fails. -- Fork switching: If a new head does not build off the current head, the node switches forks and reapplies blocks safely. -- **Enhanced fork switching**: HF12 implements vote-weighted chain comparison during fork switching, using sum of raw votes from unique non-committee validators as primary criterion. -- Pop block: Removes the head block and restores transactions to pending state. -- **Emergency mode recovery**: Automatic recovery mechanisms handle emergency consensus state transitions. - -```mermaid -sequenceDiagram -participant DB as "Database" -participant ForkDB as "Fork DB" -participant Session as "Undo Session" -participant Emergency as "Emergency Mode" -DB->>ForkDB : push_block(new_block) -alt failure -DB->>ForkDB : remove(new_block.id) -DB-->>DB : throw exception -else success -DB->>Session : start_undo_session() -DB->>Session : apply_block(...) -Session-->>DB : session.push() -end -Note over Emergency : HF12 Enhanced Logic -ForkDB->>Emergency : check emergency conditions -Emergency->>ForkDB : set_emergency_mode(flag) -``` - -**Diagram sources** -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [fork_database.hpp:118-129](file://libraries/chain/include/graphene/chain/fork_database.hpp#L118-L129) - -**Section sources** -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) -- [fork_database.hpp:118-129](file://libraries/chain/include/graphene/chain/fork_database.hpp#L118-L129) - -### Implementing Custom Hardfork Logic -Steps to add a new hardfork: -1. Define the hardfork in a new *.hf file with ID, timestamp, and version. -2. **Increment CHAIN_NUM_HARDFORKS in the preamble** (now 12). -3. Gate behavior changes using has_hardfork(CHAIN_HARDFORK_N) checks in relevant code paths. -4. Optionally adjust chain parameters or validators in update_median_witness_props() or related routines. -5. **Consider emergency mode implications** for network recovery scenarios. -6. Test with a local testnet or snapshot to validate behavior before mainnet deployment. - -Examples of where to add logic: -- Operation evaluators: Wrap validation or execution in has_hardfork() branches. -- Chain properties: Adjust median properties or inflation logic based on hardfork level. -- validator scheduling: Update vote counting or penalties depending on hardfork. -- **Emergency mode handling**: Implement recovery mechanisms for network failure scenarios. - -**Section sources** -- [0-preamble.hf:54-56](file://libraries/chain/hardfork.d/0-preamble.hf#L54-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.cpp:1715-1779](file://libraries/chain/database.cpp#L1715-L1779) -- [database.cpp:2341-2399](file://libraries/chain/database.cpp#L2341-L2399) - -### Adding New Operation Types -- Define the operation type in the protocol layer. -- Register an evaluator for the operation. -- Gate any new behavior behind has_hardfork() checks. -- Ensure backward compatibility by preserving old validation paths. -- **Consider emergency mode compatibility** for critical operations. - -### Modifying Existing Behavior -- Identify the affected subsystem (e.g., validator voting, inflation, chain properties, emergency mode). -- Add a new hardfork constant and timestamp. -- Update the relevant runtime logic to branch on has_hardfork(). -- **Implement emergency mode considerations** for network recovery scenarios. -- Verify with tests and a staged rollout. - -**Section sources** -- [database.cpp:1830-1891](file://libraries/chain/database.cpp#L1830-L1891) -- [database.cpp:2341-2399](file://libraries/chain/database.cpp#L2341-L2399) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -### Common Hardfork Scenarios -- Protocol changes: Introduce new operations or modify semantics (e.g., award operations, custom sequences). -- Bug fixes: Correct calculations or state transitions (e.g., median properties, vote accounting). -- Feature additions: Enable new chain parameters or fee structures (e.g., invites, subscriptions, validator penalties). -- **Network recovery**: Emergency consensus activation and recovery mechanisms for consensus failures. - -Validation procedures: -- Confirm hardfork timestamps align with validator votes. -- Verify has_hardfork() branches execute the intended logic. -- Run reindex tests to ensure deterministic replay. -- **Test emergency mode activation and recovery scenarios**. - -**Section sources** -- [1.hf:1-7](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [2.hf:1-7](file://libraries/chain/hardfork.d/2.hf#L1-L7) -- [4.hf:1-7](file://libraries/chain/hardfork.d/4.hf#L1-L7) -- [6.hf:1-7](file://libraries/chain/hardfork.d/6.hf#L1-L7) -- [9.hf:1-7](file://libraries/chain/hardfork.d/9.hf#L1-L7) -- [11.hf:1-7](file://libraries/chain/hardfork.d/11.hf#L1-L7) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -## Dependency Analysis -The hardfork system depends on: -- Hardfork definition files for compile-time constants. -- Database hardfork property object for runtime state. -- validator consensus for determining next hardfork. -- Block log and fork database for replay and fork switching. -- **Emergency consensus parameters and configurations**. - -```mermaid -graph TB -HFFiles["*.hf files"] -Preamble["0-preamble.hf"] -HF12["12.hf
Emergency Consensus"] -DBHdr["database.hpp
hardfork arrays"] -DBInit["database.cpp
init_hardforks/process_hardforks"] -HFProps["HardforkPropertyObject"] -ForkDB["Fork DB"] -BlockLog["Block Log"] -Config["config.hpp
Emergency Params"] -validator["validator.cpp
Three-State Safety"] -Emergency["Emergency Logic"] -HFFiles --> Preamble -Preamble --> DBHdr -DBHdr --> DBInit -HFProps --> DBInit -ForkDB --> DBInit -BlockLog --> DBInit -HF12 --> DBInit -Config --> DBInit -validator --> DBInit -Emergency --> DBInit -``` - -**Diagram sources** -- [0-preamble.hf:54-56](file://libraries/chain/hardfork.d/0-preamble.hf#L54-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [config.hpp:110-123](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L123) -- [validator.cpp:354-392](file://plugins/validator/validator.cpp#L354-L392) - -**Section sources** -- [0-preamble.hf:54-56](file://libraries/chain/hardfork.d/0-preamble.hf#L54-L56) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) -- [database.hpp:577-578](file://libraries/chain/include/graphene/chain/database.hpp#L577-L578) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [config.hpp:110-123](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L123) - -## Performance Considerations -- Reindexing with skip flags reduces overhead by bypassing expensive validations. -- Periodic revision setting during reindex prevents excessive memory pressure. -- Auto-scaling shared memory helps avoid failures during heavy reindex workloads. -- **Emergency mode optimization**: Minimal performance impact through efficient emergency validator creation and activation. -- **Enhanced fork switching**: Vote-weighted chain comparison adds computational overhead but improves network stability. - -Recommendations: -- Configure shared memory sizing appropriately for your hardware. -- Monitor free memory and adjust thresholds to trigger resizing proactively. -- **Monitor emergency mode activation frequency** to assess network health. -- **Optimize validator scheduling algorithms** for emergency mode scenarios. - -**Section sources** -- [database.cpp:270-350](file://libraries/chain/database.cpp#L270-L350) -- [database.cpp:368-430](file://libraries/chain/database.cpp#L368-L430) -- [database.cpp:1096-1135](file://libraries/chain/database.cpp#L1096-L1135) - -## Troubleshooting Guide -Common issues and resolutions: -- Revision mismatch on open: Indicates chainbase revision does not match head block number; reindex or restore from a compatible backup. -- Chain state mismatch with block log: Requires reindex to reconcile state. -- Memory exhaustion during reindex: Increase shared memory size or tune auto-resize parameters. -- Hardfork not triggering: Verify validator consensus matches configured hardfork version/time; check has_hardfork() branches. -- **Emergency mode activation failures**: Check CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC configuration and LIB timestamp monitoring. -- **Emergency validator creation issues**: Verify CHAIN_EMERGENCY_WITNESS_ACCOUNT and CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY settings. -- **Three-state safety enforcement problems**: Review validator participation rate calculations and configuration overrides. - -Diagnostic steps: -- Review logs around open() and reindex() for explicit assertions or exceptions. -- Confirm hardfork timestamps and versions in *.hf files. -- Validate that next_hardfork updates according to validator votes. -- **Monitor emergency mode activation and deactivation events**. -- **Check fork switching behavior** during emergency mode. - -**Section sources** -- [database.cpp:206-268](file://libraries/chain/database.cpp#L206-L268) -- [database.cpp:270-350](file://libraries/chain/database.cpp#L270-L350) -- [database.cpp:1600-1654](file://libraries/chain/database.cpp#L1600-L1654) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [validator.cpp:354-392](file://plugins/validator/validator.cpp#L354-L392) - -## Conclusion -The VIZ hardfork system provides a robust, versioned mechanism for managing protocol upgrades, now enhanced with comprehensive emergency consensus recovery capabilities. By combining compile-time definitions, runtime state tracking, consensus-driven scheduling, and automatic network recovery mechanisms, it enables safe, backward-compatible upgrades even during network failure scenarios. The addition of HF12 (Emergency Consensus Recovery) significantly strengthens the system's resilience and reliability for critical network operations. - -## Appendices -- Practical checklist for upgrades: - - Freeze node binaries to the target version. - - Prepare a snapshot and backup. - - Deploy *.hf files and rebuild (remember to increment CHAIN_NUM_HARDFORKS to 12). - - Start node in read-only mode to validate. - - Monitor logs and metrics. - - Coordinate with validators to reach consensus. - - **Monitor emergency mode activation and recovery scenarios**. - - Proceed with full node operation after verification. -- **Emergency mode operational procedures**: - - Monitor CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC threshold. - - Verify emergency validator activation and block production. - - Track emergency mode duration and automatic deactivation. - - Test fork switching behavior during emergency scenarios. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Advanced Topics/Security Implementation.md b/.qoder/repowiki/en/content/Advanced Topics/Security Implementation.md deleted file mode 100644 index a8b6eb9e92..0000000000 --- a/.qoder/repowiki/en/content/Advanced Topics/Security Implementation.md +++ /dev/null @@ -1,467 +0,0 @@ -# Security Implementation - - -**Referenced Files in This Document** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp) -- [shared_authority.cpp](file://libraries/chain/shared_authority.cpp) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) -- [config.ini](file://share/vizd/config/config.ini) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive security implementation documentation for the VIZ CPP Node. It covers cryptographic security (digital signature verification, key management, secure communications), authority and multi-signature systems, API authentication and authorization, network security, vulnerability assessment, best practices for plugin development, and operational security procedures. The goal is to help operators, developers, and auditors understand how security is implemented and how to extend or maintain it safely. - -## Project Structure -Security-relevant components are distributed across: -- Protocol layer: cryptographic primitives, authorities, and signature validation logic -- Chain layer: shared-memory compatible authority representation -- Network layer: encrypted peer-to-peer transport -- Plugins: API exposure and webserver hosting -- Configuration: runtime security-related settings - -```mermaid -graph TB -subgraph "Protocol Layer" -A["authority.hpp"] -B["sign_state.hpp"] -end -subgraph "Chain Layer" -C["shared_authority.hpp"] -end -subgraph "Network Layer" -D["stcp_socket.hpp"] -E["node.hpp"] -end -subgraph "Plugins" -F["auth_util plugin.hpp/.cpp"] -G["webserver_plugin.hpp/.cpp"] -end -subgraph "Config" -H["config.ini"] -end -A --> B -C --> B -D --> E -F --> A -G --> H -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp#L21-L54) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) -- [config.ini](file://share/vizd/config/config.ini) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L1-L113) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L1-L99) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp#L1-L60) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L1-L99) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L1-L336) -- [config.ini](file://share/vizd/config/config.ini) - -## Core Components -- Digital signature verification and authority checks: - - Authority model with thresholds and weighted participants - - Signature state engine to validate authorities recursively -- Key management: - - Public key extraction from signatures - - Shared authority for shared memory compatibility -- Secure communications: - - ECDH-based per-connection AES encryption for peer transport -- API exposure: - - Webserver plugin serving JSON-RPC over HTTP/WebSocket - - Authorization via account authority and signature validation - -Key implementation references: -- Authority and classification: [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- Signature state and recursion depth: [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- Shared authority for chain storage: [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- Encrypted peer transport: [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- Webserver plugin endpoints: [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -## Architecture Overview -The security architecture integrates cryptographic checks, authority validation, and secure transport. At runtime: -- Clients submit transactions with signatures -- The node validates signatures against account authorities -- Transactions are propagated securely over encrypted peer links -- APIs are exposed via a configurable webserver - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "Webserver Plugin" -participant Auth as "Auth Utility Plugin" -participant Chain as "Chain Database" -participant Net as "Network Node" -Client->>WS : "JSON-RPC request" -WS->>Auth : "check_authority_signature(account, level, digest, sigs)" -Auth->>Chain : "lookup account authority" -Auth->>Auth : "derive signing keys from signatures" -Auth->>Auth : "build sign_state and check_authority()" -Auth-->>WS : "verified signing keys" -WS-->>Client : "JSON-RPC response" -Client->>Net : "broadcast signed transaction" -Net-->>Client : "propagation confirmed" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L258-L262) - -## Detailed Component Analysis - -### Digital Signature Verification and Authority System -- Authority model: - - Threshold-weighted participation for accounts - - Support for account and key authorities - - Classification enum for roles (master, active, key, regular) -- Signature state engine: - - Builds a set of provided signatures - - Recursively resolves nested authorities up to a maximum depth - - Filters unused approvals and signatures -- Shared authority: - - Compatible with shared memory allocation for chain objects - -```mermaid -classDiagram -class Authority { -+uint32_t weight_threshold -+account_auths -+key_auths -+add_authority(...) -+get_keys() -+is_impossible() -+num_auths() -+clear() -+validate() -} -class SignState { -+provided_signatures -+unused_signatures -+approved_by -+unused_approvals -+signed_by(k) -+check_authority(id) -+check_authority(au, depth) -+remove_unused_signatures() -+filter_unused_approvals() -} -class SharedAuthority { -+weight_threshold -+account_auths -+key_auths -+add_authority(...) -+get_keys() -+is_impossible() -+num_auths() -+validate() -} -SignState --> Authority : "validates against" -SharedAuthority --> Authority : "convertible to/from" -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp) -- [shared_authority.cpp](file://libraries/chain/shared_authority.cpp) - -### Key Management and Signature Extraction -- Extract signing keys from provided signatures using deterministic recovery -- Build a set of available keys for authority checks -- Validate authorities against account active/master/regular levels - -```mermaid -flowchart TD -Start(["Start"]) --> GetSig["Receive signatures"] -GetSig --> RecoverKeys["Recover public keys from signatures"] -RecoverKeys --> BuildSet["Build available keys set"] -BuildSet --> ResolveAuth["Resolve account authority by level"] -ResolveAuth --> CheckSS["Initialize sign_state and check_authority()"] -CheckSS --> Pass{"Authority satisfied?"} -Pass --> |Yes| ReturnOK["Return verified keys"] -Pass --> |No| ReturnErr["Fail with error"] -ReturnOK --> End(["End"]) -ReturnErr --> End -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) - -**Section sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) - -### Secure Communication Protocols (Peer Transport) -- ECDH key exchange establishes a shared secret per connection -- AES encoder/decoder streams protect message payloads -- TCP socket wrapper supports read/write buffering and flushing - -```mermaid -sequenceDiagram -participant PeerA as "Peer A" -participant PeerB as "Peer B" -participant SockA as "stcp_socket(A)" -participant SockB as "stcp_socket(B)" -PeerA->>SockA : "connect_to(remote)" -PeerB->>SockB : "accept()" -SockA->>SockB : "exchange ephemeral keys" -SockA->>SockA : "derive shared secret" -SockB->>SockB : "derive shared secret" -SockA->>SockB : "encrypted payload" -SockB->>SockA : "encrypted payload" -``` - -**Diagram sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) - -### API Authentication and Authorization -- Webserver plugin exposes JSON-RPC over HTTP and WebSocket -- Requests are dispatched to registered handlers on the application’s io_service thread -- Authorization is enforced by the auth_util plugin, which verifies signatures against account authorities - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "Webserver Plugin" -participant RPC as "JSON-RPC Handler" -participant Auth as "Auth Utility Plugin" -participant DB as "Chain Database" -Client->>WS : "HTTP/WS JSON-RPC" -WS->>RPC : "call(payload)" -RPC->>Auth : "check_authority_signature(...)" -Auth->>DB : "lookup account authorities" -Auth-->>RPC : "verification result" -RPC-->>WS : "authorized response" -WS-->>Client : "HTTP/WS response" -``` - -**Diagram sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) - -**Section sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp#L21-L54) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) - -### Network Security Measures -- Peer authentication via encrypted channels prevents passive eavesdropping -- Node maintains peer database and propagation timing metadata -- Bandwidth limits and advanced parameters can be configured for operational control - -```mermaid -graph TB -N["Node"] -P1["Peer 1"] -P2["Peer 2"] -Enc["Encrypted Channel (ECDH+AES)"] -N --- Enc --- P1 -N --- Enc --- P2 -N -.-> P1 -N -.-> P2 -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -### Vulnerability Assessment Procedures -- Common risks: - - Insufficient signature validation leading to unauthorized operations - - Weak randomness or reused nonces in cryptographic contexts - - Man-in-the-middle attacks on unencrypted RPC endpoints - - Denial-of-service via oversized payloads or excessive concurrent requests -- Penetration testing approaches: - - Validate authority bypass attempts by submitting malformed signatures - - Test recursion depth limits and resource exhaustion under heavy nested authorities - - Verify transport encryption and handshake integrity - - Stress test webserver endpoints for rate-limiting and memory exhaustion -- Audit methodology: - - Static analysis of authority thresholds and recursion bounds - - Dynamic testing of signature recovery and authority resolution paths - - Network capture analysis to confirm encrypted transport usage - - Review configuration files for exposed endpoints and weak defaults - -[No sources needed since this section provides general guidance] - -### Security Best Practices for Plugin Development -- Input validation: - - Reject malformed or oversized payloads at plugin boundaries - - Enforce strict schema validation for JSON-RPC arguments -- Secure coding patterns: - - Prefer constant-time comparisons for secrets - - Avoid storing plaintext credentials; derive keys securely -- Threat modeling: - - Enumerate trusted vs. untrusted inputs - - Model actor permissions per account authority levels -- Example patterns: - - Use the existing auth_util API to validate signatures before processing sensitive operations - - Leverage the webserver plugin’s thread pool sizing to manage resource consumption - -[No sources needed since this section provides general guidance] - -### Practical Examples for Custom Plugins -- Implementing signature verification: - - Use the auth_util API to validate signatures against account authorities before applying state changes - - Reference: [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- Exposing a secure API: - - Register JSON-RPC endpoints via the webserver plugin and enforce authorization inside the handler - - Reference: [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- Integrating encrypted transport: - - For inter-node communication, rely on the built-in stcp_socket for ECDH-based encryption - - Reference: [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -**Section sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -### Security Monitoring, Incident Response, and Updates -- Monitoring: - - Track peer connection counts, bandwidth usage, and propagation delays - - Monitor webserver thread pool saturation and error rates -- Incident response: - - Isolate affected endpoints, rotate keys, and re-validate authorities - - Review logs around failed signature validations and authority checks -- Updates: - - Apply hardforks and protocol upgrades that adjust authority thresholds or signature validation rules - - Update transport encryption parameters and cipher suites as needed - -[No sources needed since this section provides general guidance] - -## Dependency Analysis -The security subsystem exhibits clear separation of concerns: -- Protocol and chain layers define the authority model and signature validation -- Network layer enforces transport security -- Plugins expose APIs and orchestrate authorization - -```mermaid -graph LR -Proto["Protocol Layer
authority.hpp, sign_state.hpp"] -Chain["Chain Layer
shared_authority.hpp"] -Net["Network Layer
stcp_socket.hpp, node.hpp"] -Auth["Auth Utility Plugin
plugin.hpp/.cpp"] -WS["Webserver Plugin
webserver_plugin.hpp/.cpp"] -Proto --> Auth -Chain --> Auth -Net --> WS -WS --> Auth -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp#L21-L54) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L100) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [plugin.hpp](file://plugins/auth_util/include/graphene/plugins/auth_util/plugin.hpp#L21-L54) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) - -## Performance Considerations -- Signature validation cost scales with authority depth and key count; tune recursion limits and key sets accordingly -- Webserver thread pool size impacts throughput under load; monitor queue lengths and latency -- Network bandwidth limits prevent abuse while maintaining propagation performance - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Signature validation failures: - - Confirm account authority levels and weights - - Verify signature recovery produces expected public keys - - Check recursion depth and nested authority chains -- Transport errors: - - Validate ECDH handshake completion and shared secret derivation - - Inspect TCP socket read/write buffers and flush behavior -- Webserver issues: - - Ensure endpoints resolve and ports are available - - Confirm thread pool size adequate for expected concurrency - -**Section sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L78) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L266-L312) - -## Conclusion -VIZ CPP Node implements a robust security model centered on threshold-based authorities, deterministic signature verification, and encrypted peer transport. Operators should focus on proper configuration, continuous monitoring, and disciplined plugin development practices to maintain a secure deployment. Regular audits, updates, and incident response procedures will further strengthen resilience against evolving threats. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices -- Configuration highlights for security: - - Configure webserver endpoints and thread pool size - - Ensure encrypted peer transport is enabled and properly bound - - Limit bandwidth and manage peer lists for operational safety - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Architecture Overview.md b/.qoder/repowiki/en/content/Architecture Overview/Architecture Overview.md deleted file mode 100644 index 11a1f01001..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Architecture Overview.md +++ /dev/null @@ -1,537 +0,0 @@ -# Architecture Overview - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [CMakeLists.txt](file://CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [libraries/api/include/graphene/api/chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the architecture of the VIZ C++ Node system. It explains how the main vizd process orchestrates core libraries (chain, protocol, network, wallet), the plugin-based extension mechanism, and external dependencies. It also documents the event-driven observer pattern, data flow from JSON-RPC requests through plugins to database operations, and system boundaries for peer communication, API handling, and persistent state management. Cross-cutting concerns such as performance, security, and monitoring are addressed alongside architectural decisions like the use of C++ for performance, Boost.Signals2 for event handling, and layered separation of concerns. - -## Project Structure -The repository is organized around a layered design: -- Top-level build and configuration: CMake and third-party dependencies -- Libraries: chain, protocol, network, api, utilities, time, wallet -- Plugins: modular feature extensions (chain, p2p, json_rpc, database_api, etc.) -- Programs: vizd (daemon), cli_wallet, utilities -- Share: configuration templates, Dockerfiles, seed nodes - -```mermaid -graph TB -subgraph "Top-level" -CMK["CMakeLists.txt"] -LIBS_CMK["libraries/CMakeLists.txt"] -PLUG_CMK["plugins/CMakeLists.txt"] -end -subgraph "Libraries" -L_CHAIN["libraries/chain"] -L_PROTOCOL["libraries/protocol"] -L_NETWORK["libraries/network"] -L_API["libraries/api"] -L_UTIL["libraries/utilities"] -L_TIME["libraries/time"] -L_WALLET["libraries/wallet"] -end -subgraph "Plugins" -P_CHAIN["plugins/chain"] -P_JSONRPC["plugins/json_rpc"] -P_DB_API["plugins/database_api"] -P_P2P["plugins/p2p"] -P_WBS["plugins/webserver"] -P_WITNESS["plugins/validator"] -P_TAGS["plugins/tags"] -P_ACCOUNT_HISTORY["plugins/account_history"] -P_ACCOUNT_BY_KEY["plugins/account_by_key"] -P_PRIVATE_MESSAGE["plugins/private_message"] -P_AUTH_UTIL["plugins/auth_util"] -P_DEBUG["plugins/debug_node"] -P_RAW_BLOCK["plugins/raw_block"] -P_BLOCK_INFO["plugins/block_info"] -P_FOLLOW["plugins/follow"] -P_COMMITTEE_API["plugins/committee_api"] -P_INVITE_API["plugins/invite_api"] -P_PAID_SUBSCRIPTION_API["plugins/paid_subscription_api"] -P_CUSTOM_PROTOCOL_API["plugins/custom_protocol_api"] -end -subgraph "Programs" -PR_VIZD["programs/vizd"] -PR_CLI["programs/cli_wallet"] -PR_UTIL["programs/util"] -end -CMK --> LIBS_CMK -CMK --> PLUG_CMK -CMK --> PR_VIZD -CMK --> PR_CLI -CMK --> PR_UTIL -LIBS_CMK --> L_CHAIN -LIBS_CMK --> L_PROTOCOL -LIBS_CMK --> L_NETWORK -LIBS_CMK --> L_API -LIBS_CMK --> L_UTIL -LIBS_CMK --> L_TIME -LIBS_CMK --> L_WALLET -PLUG_CMK --> P_CHAIN -PLUG_CMK --> P_JSONRPC -PLUG_CMK --> P_DB_API -PLUG_CMK --> P_P2P -PLUG_CMK --> P_WBS -PLUG_CMK --> P_WITNESS -PLUG_CMK --> P_TAGS -PLUG_CMK --> P_ACCOUNT_HISTORY -PLUG_CMK --> P_ACCOUNT_BY_KEY -PLUG_CMK --> P_PRIVATE_MESSAGE -PLUG_CMK --> P_AUTH_UTIL -PLUG_CMK --> P_DEBUG -PLUG_CMK --> P_RAW_BLOCK -PLUG_CMK --> P_BLOCK_INFO -PLUG_CMK --> P_FOLLOW -PLUG_CMK --> P_COMMITTEE_API -PLUG_CMK --> P_INVITE_API -PLUG_CMK --> P_PAID_SUBSCRIPTION_API -PLUG_CMK --> P_CUSTOM_PROTOCOL_API -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Core Components -- vizd process: Initializes plugins, sets logging, starts the event loop, and manages lifecycle. -- Chain library: Core blockchain state machine, fork database, block/tx validation, and persistence. -- Protocol library: Operation definitions, transactions, and chain-specific types. -- Network library: Peer-to-peer networking, message handling, and synchronization. -- Wallet library: Remote node API integration and transaction construction utilities. -- Plugin system: Modular features exposed via APIs and hooks integrated into the app lifecycle. - -Key architectural anchors: -- Event-driven observer pattern via fc::signals in the chain database. -- JSON-RPC plugin routing to registered APIs. -- Plugin registration and initialization in vizd’s main entry point. - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L10-L12) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L200) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L127) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L200) - -## Architecture Overview -High-level system boundaries and interactions: -- Internal boundaries: vizd process hosts plugins; plugins depend on libraries; chain database persists state; network interacts with peers; API plugins expose RPC endpoints. -- External boundaries: peers (other nodes), clients (wallets, applications), and optional external systems (e.g., MongoDB plugin). - -```mermaid -graph TB -subgraph "vizd Process" -MAIN["programs/vizd/main.cpp
Initialize plugins, logging, exec loop"] -APPBASE["AppBase Framework
(external thirdparty)"] -end -subgraph "Core Libraries" -L_CHAIN["libraries/chain
database.hpp"] -L_PROTOCOL["libraries/protocol
operations.hpp"] -L_NETWORK["libraries/network
node.hpp"] -L_API["libraries/api
chain_api_properties.hpp"] -L_WALLET["libraries/wallet
wallet.hpp"] -end -subgraph "Plugins" -P_CHAIN["plugins/chain
plugin.cpp"] -P_JSONRPC["plugins/json_rpc
plugin.cpp"] -P_DB_API["plugins/database_api"] -P_P2P["plugins/p2p"] -P_WBS["plugins/webserver"] -P_WITNESS["plugins/validator"] -P_TAGS["plugins/tags"] -P_ACCOUNT_HISTORY["plugins/account_history"] -P_ACCOUNT_BY_KEY["plugins/account_by_key"] -P_PRIVATE_MESSAGE["plugins/private_message"] -P_AUTH_UTIL["plugins/auth_util"] -P_DEBUG["plugins/debug_node"] -P_RAW_BLOCK["plugins/raw_block"] -P_BLOCK_INFO["plugins/block_info"] -P_FOLLOW["plugins/follow"] -P_COMMITTEE_API["plugins/committee_api"] -P_INVITE_API["plugins/invite_api"] -P_PAID_SUBSCRIPTION_API["plugins/paid_subscription_api"] -P_CUSTOM_PROTOCOL_API["plugins/custom_protocol_api"] -end -MAIN --> APPBASE -MAIN --> P_CHAIN -MAIN --> P_JSONRPC -MAIN --> P_DB_API -MAIN --> P_P2P -MAIN --> P_WBS -MAIN --> P_WITNESS -MAIN --> P_TAGS -MAIN --> P_ACCOUNT_HISTORY -MAIN --> P_ACCOUNT_BY_KEY -MAIN --> P_PRIVATE_MESSAGE -MAIN --> P_AUTH_UTIL -MAIN --> P_DEBUG -MAIN --> P_RAW_BLOCK -MAIN --> P_BLOCK_INFO -MAIN --> P_FOLLOW -MAIN --> P_COMMITTEE_API -MAIN --> P_INVITE_API -MAIN --> P_PAID_SUBSCRIPTION_API -MAIN --> P_CUSTOM_PROTOCOL_API -P_CHAIN --> L_CHAIN -P_JSONRPC --> L_API -P_DB_API --> L_API -P_P2P --> L_NETWORK -P_WBS --> L_API -P_WITNESS --> L_CHAIN -P_TAGS --> L_CHAIN -P_ACCOUNT_HISTORY --> L_CHAIN -P_ACCOUNT_BY_KEY --> L_CHAIN -P_PRIVATE_MESSAGE --> L_CHAIN -P_AUTH_UTIL --> L_CHAIN -P_DEBUG --> L_CHAIN -P_RAW_BLOCK --> L_CHAIN -P_BLOCK_INFO --> L_CHAIN -P_FOLLOW --> L_CHAIN -P_COMMITTEE_API --> L_CHAIN -P_INVITE_API --> L_CHAIN -P_PAID_SUBSCRIPTION_API --> L_CHAIN -P_CUSTOM_PROTOCOL_API --> L_PROTOCOL -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L61-L91) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L50) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L200) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/api/include/graphene/api/chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp#L11-L44) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L127) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L200) - -## Detailed Component Analysis - -### vizd Process and Plugin Registration -- The main entry point registers and initializes core plugins, sets logging configuration, and starts the event loop. -- Plugins are conditionally compiled and registered, including chain, p2p, webserver, database_api, and many others. - -```mermaid -sequenceDiagram -participant Main as "vizd main.cpp" -participant App as "AppBase Application" -participant Chain as "Chain Plugin" -participant Net as "P2P Plugin" -participant WS as "Webserver Plugin" -Main->>App : register_plugin(chain) -Main->>App : register_plugin(p2p) -Main->>App : register_plugin(webserver) -Main->>App : initialize(chain,p2p,webserver) -App-->>Main : initialized -Main->>App : startup() -App->>Chain : start() -App->>Net : start() -App->>WS : start() -Main->>App : exec() (event loop) -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L61-L91) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L117-L122) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L139-L142) - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) - -### Chain Library and Observer Pattern -- The chain database extends chainbase and emits signals for events (e.g., block accepted, transaction applied). -- Plugins subscribe to these signals to implement features like history tracking, indexing, and notifications. - -```mermaid -classDiagram -class Database { -+open(data_dir, shared_mem_dir, ...) -+push_block(...) -+push_transaction(...) -+reindex(...) -+wipe(...) -} -class ChainPlugin { -+db() Database -+accept_block(...) -+accept_transaction(...) -} -Database <.. ChainPlugin : "used by" -``` - -**Diagram sources** -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L50) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L10-L12) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp#L96-L167) - -### Network Library and Peer Communication -- The network node defines a delegate interface for block/transaction handling and synchronization. -- It coordinates peer connections, message propagation, and blockchain sync status callbacks. - -```mermaid -classDiagram -class NodeDelegate { -<> -+has_item(id) -+handle_block(blk_msg, sync_mode, contained_trx_ids) -+handle_transaction(trx_msg) -+handle_message(msg) -+get_block_ids(synopsis, remaining, limit) -+get_item(id) -+get_blockchain_synopsis(ref, n) -+sync_status(item_type, item_count) -+connection_count_changed(count) -+get_block_number(hash) -+get_block_time(hash) -+get_blockchain_now() -+get_head_block_id() -+estimate_last_known_fork(ts) -+error_encountered(msg, err) -} -class Node { -+set_node_delegate(NodeDelegate*) -+load_configuration(path) -+close() -} -Node ..|> NodeDelegate : "implements" -``` - -**Diagram sources** -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L60-L167) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L200) - -**Section sources** -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L200) - -### Protocol Layer and Operations -- The protocol layer defines the operation type union and related chain operations, virtual operations, and chain-specific types. -- This forms the basis for validation, signing, and evaluation in the chain library. - -```mermaid -classDiagram -class Operation { -<> -} -class Operations { -+transfer_operation -+account_update_operation -+proposal_create_operation -+...many others... -} -Operation <|-- Operations : "contains" -``` - -**Diagram sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -**Section sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) - -### API Layer and JSON-RPC -- The JSON-RPC plugin exposes a method registry and dispatch mechanism to route RPC calls to plugin APIs. -- It constructs responses and handles errors consistently. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant JSONRPC as "JSON-RPC Plugin" -participant Registry as "Registered APIs" -participant Chain as "Chain Database" -Client->>JSONRPC : {"method" : "call","params" : [api,method,args]} -JSONRPC->>Registry : find_api_method(api, method) -Registry-->>JSONRPC : api_method -JSONRPC->>Registry : invoke(api_method, args) -Registry-->>JSONRPC : result or error -JSONRPC-->>Client : {"result" : ..., "id" : ...} -``` - -**Diagram sources** -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L200) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L200) - -**Section sources** -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L200) - -### Wallet Integration -- The wallet library integrates with remote node APIs and provides helpers for transaction building and signing. -- It relies on protocol types and chain constants for compatibility. - -**Section sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L127) - -## Dependency Analysis -- Build-time: CMake aggregates libraries and plugins; thirdparty components are referenced externally. -- Runtime: vizd depends on appbase; plugins depend on libraries; chain database underpins most plugins. - -```mermaid -graph LR -MAIN["vizd main.cpp"] --> APPBASE["AppBase"] -MAIN --> PCHAIN["plugins/chain"] -MAIN --> PJRPC["plugins/json_rpc"] -PCHAIN --> LCHAIN["libraries/chain"] -PJRPC --> LAPIS["libraries/api"] -PCHAIN -.-> LPROTOCOL["libraries/protocol"] -PCHAIN -.-> LNETWORK["libraries/network"] -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L61-L91) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Performance Considerations -- C++ chosen for performance-critical components (validation, networking, persistence). -- Shared memory database (chainbase) optimized for fast reads/writes. -- Optional MongoDB plugin for analytics/offloading; controlled via build flags. -- Logging configuration supports JSON/console/file appenders for observability. -- Compiler flags tuned per platform; optional ccache support. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Logging configuration: The main process parses logging sections from config and applies fc::configure_logging. -- Exception handling: JSON-RPC plugin wraps transport exceptions and returns structured errors. -- Chain operations: Chain plugin validates blocks/transactions and can replay or wipe the database when corrupted. - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L211-L288) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L96-L136) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp#L134-L146) - -## Conclusion -The VIZ C++ Node employs a modular, plugin-based architecture built atop robust core libraries. The vizd process orchestrates initialization and runtime, while plugins extend functionality safely. The chain database leverages an observer pattern for event-driven features, and JSON-RPC provides a clean API boundary. System boundaries separate peer communication, client APIs, and persistent state, enabling maintainability, scalability, and targeted optimizations. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### System Context Diagram -```mermaid -graph TB -subgraph "External" -PEERS["Peers"] -CLIENTS["Wallets/Applications"] -end -subgraph "Node" -VIZD["vizd process"] -subgraph "Plugins" -P_CHAIN["chain"] -P_P2P["p2p"] -P_JSONRPC["json_rpc"] -P_DB_API["database_api"] -P_WBS["webserver"] -P_WITNESS["validator"] -P_TAGS["tags"] -P_ACCOUNT_HISTORY["account_history"] -P_ACCOUNT_BY_KEY["account_by_key"] -P_PRIVATE_MESSAGE["private_message"] -P_AUTH_UTIL["auth_util"] -P_DEBUG["debug_node"] -P_RAW_BLOCK["raw_block"] -P_BLOCK_INFO["block_info"] -P_FOLLOW["follow"] -P_COMMITTEE_API["committee_api"] -P_INVITE_API["invite_api"] -P_PAID_SUBSCRIPTION_API["paid_subscription_api"] -P_CUSTOM_PROTOCOL_API["custom_protocol_api"] -end -subgraph "Libraries" -L_CHAIN["chain"] -L_PROTOCOL["protocol"] -L_NETWORK["network"] -L_API["api"] -L_WALLET["wallet"] -end -end -PEERS <- --> P_P2P -CLIENTS <- --> P_JSONRPC -CLIENTS <- --> P_DB_API -CLIENTS <- --> P_WBS -VIZD --> P_CHAIN -VIZD --> P_P2P -VIZD --> P_JSONRPC -VIZD --> P_DB_API -VIZD --> P_WBS -VIZD --> P_WITNESS -VIZD --> P_TAGS -VIZD --> P_ACCOUNT_HISTORY -VIZD --> P_ACCOUNT_BY_KEY -VIZD --> P_PRIVATE_MESSAGE -VIZD --> P_AUTH_UTIL -VIZD --> P_DEBUG -VIZD --> P_RAW_BLOCK -VIZD --> P_BLOCK_INFO -VIZD --> P_FOLLOW -VIZD --> P_COMMITTEE_API -VIZD --> P_INVITE_API -VIZD --> P_PAID_SUBSCRIPTION_API -VIZD --> P_CUSTOM_PROTOCOL_API -P_CHAIN --> L_CHAIN -P_JSONRPC --> L_API -P_DB_API --> L_API -P_P2P --> L_NETWORK -P_WBS --> L_API -P_WITNESS --> L_CHAIN -P_TAGS --> L_CHAIN -P_ACCOUNT_HISTORY --> L_CHAIN -P_ACCOUNT_BY_KEY --> L_CHAIN -P_PRIVATE_MESSAGE --> L_CHAIN -P_AUTH_UTIL --> L_CHAIN -P_DEBUG --> L_CHAIN -P_RAW_BLOCK --> L_CHAIN -P_BLOCK_INFO --> L_CHAIN -P_FOLLOW --> L_CHAIN -P_COMMITTEE_API --> L_CHAIN -P_INVITE_API --> L_CHAIN -P_PAID_SUBSCRIPTION_API --> L_CHAIN -P_CUSTOM_PROTOCOL_API --> L_PROTOCOL -``` - -**Diagram sources** -- [README.md](file://README.md#L1-L53) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L61-L91) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L50) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L200) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/api/include/graphene/api/chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp#L11-L44) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L127) -- [plugins/chain/plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) -- [plugins/json_rpc/plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L200) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Log Reader Module.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Log Reader Module.md deleted file mode 100644 index 2f0b970ed9..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Log Reader Module.md +++ /dev/null @@ -1,472 +0,0 @@ -# Block Log Reader Module - - -**Referenced Files in This Document** -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -The Block Log Reader Module is a critical component of the VIZ CPP Node that provides efficient access to blockchain data stored in append-only block log files. This module serves two primary purposes: traditional block log storage for full nodes and DLT (Snapshot-based) block log storage for lightweight nodes. The module implements memory-mapped file access patterns to achieve high-performance block retrieval while maintaining data integrity through robust validation mechanisms. - -The module consists of two main classes: `block_log` for standard blockchain nodes and `dlt_block_log` for snapshot-based nodes. Both classes provide thread-safe access to block data through memory-mapped files, enabling fast random access to blocks by number and sequential traversal capabilities. - -## Project Structure -The Block Log Reader Module is organized within the VIZ blockchain implementation under the chain library. The structure follows a clear separation of concerns with interface definitions in header files and implementation details in source files. - -```mermaid -graph TB -subgraph "Block Log Module Structure" -A[block_log.hpp] --> B[block_log.cpp] -C[dlt_block_log.hpp] --> D[dlt_block_log.cpp] -E[database.hpp] --> F[database.cpp] -G[test_block_log.cpp] -H[plugin.cpp] -end -subgraph "File Types" -I[.block_log files] -J[.block_log.index files] -K[.dlt_block_log files] -L[.dlt_block_log.index files] -end -B --> I -B --> J -D --> K -D --> L -``` - -**Diagram sources** -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [block_log.cpp:1-302](file://libraries/chain/block_log.cpp#L1-L302) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [dlt_block_log.cpp:1-414](file://libraries/chain/dlt_block_log.cpp#L1-L414) - -**Section sources** -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) - -## Core Components -The Block Log Reader Module comprises two primary components that work together to provide comprehensive block storage and retrieval capabilities: - -### Standard Block Log (`block_log`) -The standard block log provides traditional blockchain storage with a complete append-only log of all blocks. It supports: -- Memory-mapped file access for high performance -- Random access by block number through index files -- Sequential traversal capabilities -- Automatic index reconstruction when corrupted -- Thread-safe operations with reader-writer locks - -### DLT Block Log (`dlt_block_log`) -The DLT block log is designed specifically for snapshot-based nodes that maintain only a rolling window of recent blocks. It provides: -- Offset-aware indexing for arbitrary starting block numbers -- Rolling window capability with configurable block limits -- Efficient truncation operations to manage storage -- Specialized handling for snapshot-loaded states -- Optimized for lightweight node operations - -**Section sources** -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) - -## Architecture Overview -The Block Log Reader Module integrates deeply with the VIZ blockchain database system, providing essential block storage and retrieval capabilities. The architecture follows a layered approach with clear separation between storage, access, and application layers. - -```mermaid -graph TB -subgraph "Application Layer" -A[Database Operations] -B[Plugin Services] -C[Debug Tools] -end -subgraph "Block Log Layer" -D[Block Log Manager] -E[DLT Block Log Manager] -F[Memory Mapped Files] -end -subgraph "Storage Layer" -G[Main Block Files] -H[Index Files] -I[DLT Block Files] -J[DLT Index Files] -end -subgraph "Validation Layer" -K[File Integrity Checks] -L[Index Reconstruction] -M[Thread Safety] -end -A --> D -A --> E -B --> D -C --> D -D --> F -E --> F -F --> G -F --> H -F --> I -F --> J -D --> K -E --> K -D --> L -E --> L -D --> M -E --> M -``` - -**Diagram sources** -- [database.cpp:229-231](file://libraries/chain/database.cpp#L229-L231) -- [database.cpp:569-580](file://libraries/chain/database.cpp#L569-L580) -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [dlt_block_log.cpp:161-209](file://libraries/chain/dlt_block_log.cpp#L161-L209) - -The architecture ensures that block data is consistently available across different operational modes, supporting both full nodes with complete block histories and lightweight nodes with rolling block windows. - -**Section sources** -- [database.hpp:567-568](file://libraries/chain/include/graphene/chain/database.hpp#L567-L568) -- [database.cpp:229-231](file://libraries/chain/database.cpp#L229-L231) - -## Detailed Component Analysis - -### Block Log Implementation Analysis -The block_log class implements a sophisticated memory-mapped file system for efficient block storage and retrieval. The implementation uses a doubly-linked list structure where each block is followed by its position in the file, enabling both forward and backward traversal. - -```mermaid -classDiagram -class BlockLog { --unique_ptr~block_log_impl~ my -+block_log() -+~block_log() -+open(fc : : path) -+close() -+is_open() bool -+append(signed_block) uint64_t -+flush() -+read_block(uint64_t) pair~signed_block,uint64_t~ -+read_block_by_num(uint32_t) optional~signed_block~ -+get_block_pos(uint32_t) uint64_t -+read_head() signed_block -+head() optional~signed_block~ -+static npos : uint64_t -} -class BlockLogImpl { --optional~signed_block~ head --block_id_type head_id --string block_path --string index_path --mapped_file block_mapped_file --mapped_file index_mapped_file --read_write_mutex mutex -+open(fc : : path) -+append(signed_block, vector~char~) uint64_t -+read_block(uint64_t, signed_block) uint64_t -+construct_index() -+get_block_pos(uint32_t) uint64_t -+read_head() signed_block -} -BlockLog --> BlockLogImpl : "owns" -``` - -**Diagram sources** -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [block_log.cpp:15-227](file://libraries/chain/block_log.cpp#L15-L227) - -The implementation employs several key design patterns: - -#### Memory-Mapped File Access -The module uses Boost's memory-mapped file functionality to achieve zero-copy block access. This approach eliminates the overhead of traditional file I/O operations and enables direct memory access to block data. - -#### Index-Based Random Access -The block log maintains a separate index file containing file positions for each block. This allows O(1) random access by block number through direct index calculation rather than sequential scanning. - -#### Automatic Recovery Mechanisms -The implementation includes comprehensive recovery mechanisms that automatically detect and repair inconsistencies between block files and index files during initialization. - -**Section sources** -- [block_log.cpp:105-113](file://libraries/chain/block_log.cpp#L105-L113) -- [block_log.cpp:115-132](file://libraries/chain/block_log.cpp#L115-L132) -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) - -### DLT Block Log Implementation Analysis -The dlt_block_log class extends the standard block log concept to support snapshot-based nodes with rolling window capabilities. Unlike the standard block log, it maintains an offset-aware index that can start from arbitrary block numbers. - -```mermaid -classDiagram -class DLTBlockLog { --unique_ptr~dlt_block_log_impl~ my -+dlt_block_log() -+~dlt_block_log() -+open(fc : : path) -+close() -+is_open() bool -+append(signed_block) uint64_t -+flush() -+read_block_by_num(uint32_t) optional~signed_block~ -+head() optional~signed_block~ -+start_block_num() uint32_t -+head_block_num() uint32_t -+num_blocks() uint32_t -+truncate_before(uint32_t) -+static npos : uint64_t -} -class DLTBlockLogImpl { --optional~signed_block~ head --block_id_type head_id --uint32_t _start_block_num --string block_path --string index_path --mapped_file block_mapped_file --mapped_file index_mapped_file --read_write_mutex mutex -+open(fc : : path) -+append(signed_block, vector~char~) uint64_t -+read_block(uint64_t, signed_block) uint64_t -+construct_index() -+get_block_pos(uint32_t) uint64_t -+read_head() signed_block -+truncate_before(uint32_t) -} -DLTBlockLog --> DLTBlockLogImpl : "owns" -``` - -**Diagram sources** -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [dlt_block_log.cpp:18-277](file://libraries/chain/dlt_block_log.cpp#L18-L277) - -The DLT implementation introduces several specialized features: - -#### Offset-Aware Indexing -The index header stores the starting block number, enabling the calculation of index positions for any block within the rolling window. This design allows the log to maintain gaps at the beginning when blocks are truncated. - -#### Rolling Window Management -The module supports dynamic truncation of old blocks while maintaining the rolling window constraint. This is essential for lightweight nodes that need to limit storage consumption. - -#### Snapshot Mode Compatibility -The DLT block log is specifically designed to work with snapshot-based node operations where the main blockchain state is loaded from a snapshot rather than replaying the entire block history. - -**Section sources** -- [dlt_block_log.cpp:161-209](file://libraries/chain/dlt_block_log.cpp#L161-L209) -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -### Database Integration Analysis -The Block Log Reader Module integrates seamlessly with the VIZ database system, providing transparent access to block data regardless of the operational mode. - -```mermaid -sequenceDiagram -participant DB as Database -participant BL as BlockLog -participant DLT as DLTBlockLog -participant FS as File System -DB->>BL : open(data_dir/"block_log") -DB->>DLT : open(data_dir/"dlt_block_log") -DB->>FS : initialize file mappings -Note over DB : During normal operation -DB->>BL : read_block_by_num(block_num) -BL->>FS : read block data -FS-->>BL : block data -BL-->>DB : signed_block -Note over DB : During DLT mode -DB->>DLT : read_block_by_num(block_num) -DLT->>FS : read block data -FS-->>DLT : block data -DLT-->>DB : signed_block -Note over DB : Fallback mechanism -DB->>BL : read_block_by_num(block_num) -alt block not found -DB->>DLT : read_block_by_num(block_num) -DLT-->>DB : signed_block or none -end -``` - -**Diagram sources** -- [database.cpp:229-231](file://libraries/chain/database.cpp#L229-L231) -- [database.cpp:569-580](file://libraries/chain/database.cpp#L569-L580) -- [database.cpp:623-640](file://libraries/chain/database.cpp#L623-L640) - -The integration provides several key benefits: - -#### Transparent Fallback Mechanism -The database automatically attempts to retrieve blocks from the standard block log first, falling back to the DLT block log if the standard log doesn't contain the requested block. This design ensures compatibility across different node configurations. - -#### Mode-Specific Behavior -The module adapts its behavior based on whether the node is operating in normal mode or DLT mode, optimizing performance and resource usage accordingly. - -#### Consistent API Interface -Both block log implementations expose identical APIs, allowing the database to treat them uniformly regardless of the underlying storage mechanism. - -**Section sources** -- [database.cpp:229-231](file://libraries/chain/database.cpp#L229-L231) -- [database.cpp:569-580](file://libraries/chain/database.cpp#L569-L580) -- [database.cpp:623-640](file://libraries/chain/database.cpp#L623-L640) - -## Dependency Analysis -The Block Log Reader Module has well-defined dependencies that contribute to its modularity and maintainability. Understanding these dependencies is crucial for effective integration and troubleshooting. - -```mermaid -graph TB -subgraph "External Dependencies" -A[Boost.Iostreams] -B[Boost.Filesystem] -C[Boost.Thread] -D[FC Library] -E[Protocol Library] -end -subgraph "Internal Dependencies" -F[Chain Library] -G[Database Core] -H[Memory Management] -end -subgraph "Block Log Module" -I[block_log] -J[dlt_block_log] -end -I --> A -I --> B -I --> C -I --> D -I --> E -I --> F -I --> G -I --> H -J --> A -J --> B -J --> C -J --> D -J --> E -J --> F -J --> G -J --> H -``` - -**Diagram sources** -- [block_log.cpp:1-6](file://libraries/chain/block_log.cpp#L1-L6) -- [dlt_block_log.cpp:1-6](file://libraries/chain/dlt_block_log.cpp#L1-L6) - -The dependency structure reveals several important characteristics: - -### External Library Dependencies -The module relies on several Boost libraries for core functionality: -- **Boost.Iostreams**: Provides memory-mapped file capabilities essential for high-performance block access -- **Boost.Filesystem**: Handles file system operations including path manipulation and file existence checks -- **Boost.Thread**: Enables thread-safe operations through shared mutexes and RAII-based locking - -### Internal Library Dependencies -The module integrates with VIZ's internal libraries: -- **FC Library**: Provides fundamental data structures and utilities used throughout the blockchain implementation -- **Protocol Library**: Defines the block structure and serialization formats used for block storage and retrieval - -### Design Benefits -The dependency structure supports several design goals: -- **Modularity**: Clear separation between external and internal dependencies enables easier maintenance -- **Portability**: Minimal external dependencies reduce portability challenges -- **Performance**: Direct integration with VIZ's optimized data structures maximizes efficiency - -**Section sources** -- [block_log.cpp:1-6](file://libraries/chain/block_log.cpp#L1-L6) -- [dlt_block_log.cpp:1-6](file://libraries/chain/dlt_block_log.cpp#L1-L6) - -## Performance Considerations -The Block Log Reader Module is designed with performance as a primary concern, implementing several optimization strategies to minimize latency and maximize throughput. - -### Memory-Mapped File Performance -The use of memory-mapped files eliminates the overhead of traditional file I/O operations by allowing direct memory access to block data. This approach provides several performance benefits: - -- **Zero-Copy Access**: Blocks can be accessed directly from memory without additional copying operations -- **Predictable Latency**: Memory-mapped access provides consistent performance characteristics regardless of file size -- **Reduced System Calls**: Eliminates the overhead of frequent system calls associated with traditional file I/O - -### Index-Based Random Access -The dual-file architecture with separate data and index files enables O(1) random access to blocks by number. The index file contains pre-calculated positions for each block, eliminating the need for sequential scanning. - -### Thread-Safe Operations -The implementation uses reader-writer locks to balance concurrent access patterns: -- **Read Operations**: Multiple readers can access the block log simultaneously without blocking -- **Write Operations**: Exclusive access ensures data consistency during block appends -- **Lock Granularity**: Fine-grained locking minimizes contention in high-concurrency scenarios - -### Storage Optimization Strategies -Several strategies are employed to optimize storage usage and access patterns: - -#### Block Size Limits -The implementation enforces maximum block size limits to prevent memory allocation issues and ensure predictable performance characteristics. - -#### File Resizing Operations -Blocks are appended using efficient file resizing operations that minimize fragmentation and maintain optimal file system performance. - -#### Index Reconstruction Efficiency -When index corruption is detected, the reconstruction process is optimized to minimize downtime and ensure data integrity. - -**Section sources** -- [block_log.cpp:73-88](file://libraries/chain/block_log.cpp#L73-L88) -- [dlt_block_log.cpp:83-98](file://libraries/chain/dlt_block_log.cpp#L83-L98) - -## Troubleshooting Guide -The Block Log Reader Module includes comprehensive error handling and diagnostic capabilities to facilitate troubleshooting and maintenance operations. - -### Common Issues and Solutions - -#### Block Log Corruption Detection -The module implements automatic detection of block log corruption through multiple validation mechanisms: - -**File Size Validation**: Ensures minimum file sizes are maintained to prevent access violations -**Position Verification**: Validates block positions using embedded position markers -**Index Consistency Checks**: Verifies that index entries correspond to actual block data - -#### Recovery Procedures -When corruption is detected, the module follows systematic recovery procedures: - -**Index Reconstruction**: Automatically rebuilds corrupted index files by scanning the main data file -**File Reinitialization**: Recreates missing or damaged files with appropriate initialization -**State Validation**: Verifies recovered state against expected block log characteristics - -#### Performance Monitoring -The module provides several mechanisms for monitoring and diagnosing performance issues: - -**Operation Timing**: Logs timing information for critical operations to identify performance bottlenecks -**Memory Usage Tracking**: Monitors memory-mapped file usage to prevent excessive memory consumption -**File System Health**: Continuously monitors file system health and reports potential issues - -### Diagnostic Tools and Utilities -Several tools and utilities are available for troubleshooting block log issues: - -#### Test Harness -The module includes a comprehensive test harness that demonstrates proper usage and validates functionality across different scenarios. - -#### Debug Plugin Integration -The debug plugin provides interactive access to block log functionality, enabling developers to inspect block data and diagnose issues in real-time. - -#### Logging and Monitoring -Extensive logging is implemented throughout the module to provide detailed information about operations, errors, and performance characteristics. - -**Section sources** -- [block_log.cpp:115-132](file://libraries/chain/block_log.cpp#L115-L132) -- [dlt_block_log.cpp:125-159](file://libraries/chain/dlt_block_log.cpp#L125-L159) -- [test_block_log.cpp:1-54](file://programs/util/test_block_log.cpp#L1-L54) - -## Conclusion -The Block Log Reader Module represents a sophisticated implementation of blockchain data storage and retrieval systems. Its dual-mode architecture supports both traditional full nodes and modern snapshot-based lightweight nodes, providing flexibility while maintaining high performance standards. - -The module's design emphasizes several key principles: -- **Performance**: Memory-mapped files and index-based access enable fast block retrieval -- **Reliability**: Comprehensive error handling and automatic recovery mechanisms ensure data integrity -- **Flexibility**: Support for multiple operational modes accommodates diverse deployment scenarios -- **Maintainability**: Clean separation of concerns and modular design facilitate ongoing development and maintenance - -The implementation demonstrates best practices in systems programming, combining low-level file system operations with high-level abstractions to create a robust and efficient block storage solution. The module serves as a foundation for the broader VIZ blockchain infrastructure, enabling reliable and scalable blockchain operations across various node configurations. - -Future enhancements could focus on additional performance optimizations, expanded monitoring capabilities, and further simplification of the dual-mode architecture to reduce complexity while maintaining compatibility with existing deployments. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Processing and Validation.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Processing and Validation.md deleted file mode 100644 index 47c662e950..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Block Processing and Validation.md +++ /dev/null @@ -1,547 +0,0 @@ -# Block Processing and Validation - - -**Referenced Files in This Document** -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [node.cpp](file://libraries/network/node.cpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) - - -## Update Summary -**Changes Made** -- Enhanced logging system documentation for sync blocks with info level logging and console color formatting -- Updated sync block and normal block push logs from debug to info level for better production visibility -- Added documentation for console color formatting in block processing logs -- Improved logging visibility for production environments - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Logging System Enhancements](#logging-system-enhancements) -7. [Dependency Analysis](#dependency-analysis) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction -This document explains the Block Processing and Validation system responsible for accepting incoming blocks, validating their integrity and consensus compliance, applying state changes, and maintaining blockchain consistency. It focuses on: -- Efficient block storage and retrieval via the block log -- The block validation pipeline (header, size, merkle, validator scheduling) -- The push_block() and validate_block() orchestration -- Block summary object creation and validator participation tracking -- Block replay for synchronization and state reconstruction -- Integration with fork database, validator scheduling, and state persistence -- Block size limits, transaction ordering, and consensus enforcement -- Enhanced logging system with production-ready visibility - -## Project Structure -The block processing pipeline spans several core modules: -- Chain database: orchestrates validation, fork selection, state application, and persistence -- Fork database: manages canonical chain and forks for reorganization decisions -- Block log: persistent append-only storage enabling fast replay and random access -- Block summary and validator schedule: support consensus checks and participation metrics -- Network layer: handles block propagation and synchronization with enhanced logging - -```mermaid -graph TB -subgraph "Chain Layer" -DB["database.hpp/.cpp"] -FD["fork_database.hpp/.cpp"] -BL["block_log.hpp/.cpp"] -BS["block_summary_object.hpp"] -end -subgraph "Network Layer" -NET["node.cpp"] -P2P["p2p_plugin.cpp"] -CHAIN["chain plugin.cpp"] -end -subgraph "Protocol" -PB["signed_block (protocol)"] -TX["signed_transaction (protocol)"] -end -DB --> FD -DB --> BL -DB --> BS -DB --> PB -DB --> TX -NET --> DB -P2P --> NET -CHAIN --> DB -``` - -**Diagram sources** -- [database.hpp:36-200](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) -- [fork_database.hpp:53-122](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [block_summary_object.hpp:19-42](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L42) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) - -**Section sources** -- [database.hpp:36-200](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) -- [fork_database.hpp:53-122](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [block_summary_object.hpp:19-42](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L42) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) - -## Core Components -- Block log: Append-only, memory-mapped storage with an auxiliary index for O(1) random access by block number. Supports reading head, reading by position, and reconstructing the index if inconsistent. -- Fork database: Maintains a linked tree of candidate blocks, supports pushing blocks, fetching branches, and selecting the heaviest chain head. -- Database: Implements validate_block(), push_block(), and apply_block() to enforce consensus rules, apply state changes, and persist blocks. -- Network layer: Handles block propagation, synchronization, and enhanced logging with console color formatting. - -Key responsibilities: -- validate_block(): Validates Merkle root, block size, and optionally validator signature and schedule alignment -- push_block(): Coordinates fork selection, reorganization, and state application -- apply_block(): Applies all transactions and operations, updates dynamic properties, and creates block summaries -- block_log: Provides deterministic replay and persistence -- Enhanced logging: Provides production-ready visibility with info level logging and console color formatting - -**Section sources** -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [fork_database.hpp:53-122](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [database.hpp:193-196](file://libraries/chain/include/graphene/chain/database.hpp#L193-L196) -- [database.cpp:737-792](file://libraries/chain/database.cpp#L737-L792) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) - -## Architecture Overview -The block processing flow integrates validation, fork management, state application, persistence, and enhanced logging with console color formatting. - -```mermaid -sequenceDiagram -participant Net as "Network/P2P" -participant P2P as "p2p_plugin.cpp" -participant Chain as "chain plugin.cpp" -participant DB as "database.cpp" -participant FD as "fork_database.cpp" -participant BL as "block_log.cpp" -Net->>P2P : "handle_block(sync_mode, block)" -P2P->>P2P : "ilog(CLOG_WHITE ... sync/normal block)" -P2P->>Chain : "accept_block(block, sync_mode)" -Chain->>Chain : "ilog(sync_start/end messages)" -Chain->>DB : "validate_block(skip)" -DB->>DB : "_validate_block(...)" -Chain->>DB : "push_block(block, skip)" -DB->>FD : "push_block(new_block)" -alt "Fork switch required" -DB->>DB : "pop_block() until fork split" -DB->>DB : "apply_block() for each fork branch" -end -DB->>DB : "apply_block(new_block)" -DB->>BL : "append(signed_block)" -P2P->>Net : "ilog(successful/not applied)" -Net-->>Net : "result (fork_switched?)" -``` - -**Diagram sources** -- [p2p_plugin.cpp:142-174](file://plugins/p2p/p2p_plugin.cpp#L142-L174) -- [plugin.cpp:103-142](file://plugins/chain/plugin.cpp#L103-L142) -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) - -## Detailed Component Analysis - -### Block Log: Storage, Retrieval, and Replay -The block log provides: -- Append-only persistence of signed blocks -- Random access by block number via an index file -- Head traversal and index reconstruction -- Memory-mapped IO for performance - -Implementation highlights: -- Open/close lifecycle with index consistency checks -- Index reconstruction if mismatched with head position -- Safe read with bounds and endianness-aware position reads -- Append with packed serialization and position linking - -```mermaid -flowchart TD -Start(["Open block_log"]) --> CheckFiles["Check block/index existence"] -CheckFiles --> |Both present| CompareHeads["Compare last positions"] -CompareHeads --> |Mismatch| RebuildIndex["Reconstruct index"] -CompareHeads --> |Match| Ready["Ready"] -CheckFiles --> |Index missing| RebuildIndex -CheckFiles --> |Block empty| CleanIndex["Remove and recreate index"] -RebuildIndex --> Ready -Ready --> Append["append(signed_block)"] -Append --> Flush["flush()"] -Ready --> ReadByNum["read_block_by_num(n)"] -ReadByNum --> ReadPos["get_block_pos(n)"] -ReadPos --> ReadBlock["read_block(pos)"] -ReadBlock --> Head["read_head()/head()"] -``` - -**Diagram sources** -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [block_log.cpp:195-226](file://libraries/chain/block_log.cpp#L195-L226) -- [block_log.cpp:263-299](file://libraries/chain/block_log.cpp#L263-L299) - -**Section sources** -- [block_log.hpp:38-71](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [block_log.cpp:195-226](file://libraries/chain/block_log.cpp#L195-L226) -- [block_log.cpp:263-299](file://libraries/chain/block_log.cpp#L263-L299) - -### Fork Database: Canonical Chain and Reorganization -The fork database maintains: -- Linked tree of blocks with previous-id linkage -- Heaviest chain head selection -- Fetching branches from divergent heads -- Unlinkable block caching and DFS insertion - -Key behaviors: -- push_block() inserts and links; marks invalid blocks to prevent chaining -- fetch_branch_from() returns branches to a common ancestor -- walk_main_branch_to_num() and fetch_block_on_main_branch_by_number() resolve main-chain blocks by number - -```mermaid -classDiagram -class fork_database { -+push_block(signed_block) shared_ptr -+set_head(item_ptr) void -+head() shared_ptr -+is_known_block(id) bool -+fetch_block(id) item_ptr -+fetch_branch_from(first, second) pair -+walk_main_branch_to_num(n) item_ptr -+set_max_size(s) void -} -class fork_item { -+id : block_id_type -+num : uint32_t -+invalid : bool -+data : signed_block -+prev : weak_ptr -+previous_id() block_id_type -} -fork_database --> fork_item : "manages" -``` - -**Diagram sources** -- [fork_database.hpp:53-122](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) - -**Section sources** -- [fork_database.hpp:53-122](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) - -### Database: Validation Pipeline and Block Application -The database coordinates validation and application: -- validate_block(): Enforces Merkle root, block size, and optionally validator signature and schedule alignment -- push_block(): Orchestrates fork selection and reorganization; calls apply_block() on success -- apply_block(): Applies all transactions and operations, updates dynamic properties, and creates block summaries - -```mermaid -sequenceDiagram -participant Caller as "Caller" -participant DB as "database.cpp" -participant FD as "fork_database.cpp" -participant BL as "block_log.cpp" -Caller->>DB : "validate_block(new_block, skip)" -DB->>DB : "_validate_block(...)" -DB-->>Caller : "skip flags updated" -Caller->>DB : "push_block(new_block, skip)" -DB->>FD : "push_block(new_block)" -alt "new_head differs from head" -DB->>DB : "fetch_branch_from(new_head, head)" -DB->>DB : "pop_block() until split" -DB->>DB : "apply_block() for each branch" -end -DB->>DB : "apply_block(new_block)" -DB->>BL : "append(new_block)" -DB-->>Caller : "fork_switched?" -``` - -**Diagram sources** -- [database.cpp:737-792](file://libraries/chain/database.cpp#L737-L792) -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) - -Validation steps: -- Merkle root verification against transaction set -- Block size enforcement against dynamic maximum -- Optional validator signature validation -- Optional validator schedule alignment (slot correctness) - -Fork selection: -- If new head extends beyond current head, compute branches and switch if heavier -- On failure, mark block invalid and restore good fork - -State application: -- apply_block() applies all operations and transactions -- Updates dynamic global properties (participation, sizes, reserve ratios) -- Creates block summary entries for TaPOS - -**Section sources** -- [database.hpp:193-196](file://libraries/chain/include/graphene/chain/database.hpp#L193-L196) -- [database.cpp:737-792](file://libraries/chain/database.cpp#L737-L792) -- [database.cpp:847-925](file://libraries/chain/database.cpp#L847-L925) -- [database.cpp:3443-3500](file://libraries/chain/database.cpp#L3443-L3500) -- [database.cpp:3723-3748](file://libraries/chain/database.cpp#L3723-L3748) -- [database.cpp:3750-3757](file://libraries/chain/database.cpp#L3750-L3757) -- [database.cpp:3759-3873](file://libraries/chain/database.cpp#L3759-L3873) - -### Enhanced validator Account Validation and Graceful Error Handling - -**Updated** Enhanced validator account validation during block production with comprehensive pre-check mechanisms - -The system now performs preliminary verification using find_account() calls instead of relying solely on get_account() which would throw exceptions if accounts are missing. This ensures graceful handling of missing validator accounts and prevents node crashes during block production. - -Key improvements: -- Pre-check mechanism using find_account() before block generation -- Graceful error handling with critical logging for shared memory corruption detection -- Prevention of exceptions during block production when validator accounts are missing -- Comprehensive error reporting with validator metadata for debugging - -```mermaid -flowchart TD -WStart(["validator Block Production"]) --> PreCheck["Pre-check: find_account(witness_owner)"] -PreCheck --> Found{"Account found?"} -Found --> |Yes| SigCheck["Validate validator signature"] -Found --> |No| CriticalLog["Critical: Log missing account details"] -CriticalLog --> Assert["Assert with detailed error message"] -SigCheck --> GenBlock["Generate block"] -GenBlock --> PostCheck["Post-check: find_account(cwit.owner)"] -PostCheck --> PostFound{"Account found?"} -PostFound --> |Yes| ApplyBlock["Apply block and distribute rewards"] -PostFound --> |No| CriticalLog2["Critical: Log missing validator account"] -CriticalLog2 --> Assert2["Assert with replay recommendation"] -``` - -**Diagram sources** -- [database.cpp:1294-1311](file://libraries/chain/database.cpp#L1294-L1311) -- [database.cpp:2824-2837](file://libraries/chain/database.cpp#L2824-L2837) -- [database.cpp:2871-2884](file://libraries/chain/database.cpp#L2871-L2884) - -**Section sources** -- [database.cpp:1294-1311](file://libraries/chain/database.cpp#L1294-L1311) -- [database.cpp:2824-2837](file://libraries/chain/database.cpp#L2824-L2837) -- [database.cpp:2871-2884](file://libraries/chain/database.cpp#L2871-L2884) -- [database.hpp:185-187](file://libraries/chain/include/graphene/chain/database.hpp#L185-L187) - -### Block Header Validation and validator Scheduling -Header validation ensures: -- Previous block ID matches current head -- Timestamp monotonicity -- validator signature verification (optional) -- validator schedule alignment (slot correctness) - -validator participation tracking: -- Missed block counters and penalties -- Participation rate computation via recent slots -- Irreversible block updates based on validator majorities - -```mermaid -flowchart TD -HStart(["validate_block_header"]) --> PrevCheck["Verify previous == head_block_id"] -PrevCheck --> TSCheck["Verify timestamp > head_block_time"] -TSCheck --> SigCheck{"skip_witness_signature?"} -SigCheck --> |No| VerifySig["Validate block.signee against validator key"] -SigCheck --> |Yes| SkipSig["Skip signature check"] -VerifySig --> SchCheck{"skip_witness_schedule_check?"} -SkipSig --> SchCheck -SchCheck --> |No| SlotCheck["Get slot_at_time(timestamp) and verify scheduled validator"] -SchCheck --> |Yes| SkipSch["Skip schedule check"] -SlotCheck --> HEnd(["Valid"]) -SkipSch --> HEnd -``` - -**Diagram sources** -- [database.cpp:3724-3748](file://libraries/chain/database.cpp#L3724-L3748) -- [database.cpp:3759-3873](file://libraries/chain/database.cpp#L3759-L3873) - -**Section sources** -- [database.cpp:3724-3748](file://libraries/chain/database.cpp#L3724-L3748) -- [database.cpp:3759-3873](file://libraries/chain/database.cpp#L3759-L3873) - -### Block Summary Object and TaPOS -Block summary objects store minimal per-block identifiers used for TaPOS (Transaction as Proof of Stake). They enable transactions to reference recent block hashes and timestamps for validity and expiration checks. - -```mermaid -classDiagram -class block_summary_object { -+id -+block_id -} -class block_summary_index -block_summary_index --> block_summary_object : "stores" -``` - -**Diagram sources** -- [block_summary_object.hpp:19-42](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L42) - -**Section sources** -- [block_summary_object.hpp:19-42](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L42) - -### Block Replay Mechanism -Replay reconstructs chain state by iterating blocks from the block log: -- Start from genesis or configured block number -- Apply each block in sequence, updating state and dynamic properties -- Skip heavy validations during reindex to accelerate replay -- Ensure chainbase revision matches head block number - -```mermaid -flowchart TD -RStart(["reindex(from_block_num)"]) --> LoadFlags["Set skip flags for reindex"] -LoadFlags --> Loop["Iterate blocks from block_log"] -Loop --> Apply["apply_block(next_block)"] -Apply --> Next["Next block"] -Next --> |More| Loop -Next --> |Done| REnd(["Complete"]) -``` - -**Diagram sources** -- [database.cpp:270-300](file://libraries/chain/database.cpp#L270-L300) -- [database.cpp:250-257](file://libraries/chain/database.cpp#L250-L257) - -**Section sources** -- [database.cpp:270-300](file://libraries/chain/database.cpp#L270-L300) -- [database.cpp:250-257](file://libraries/chain/database.cpp#L250-L257) - -## Logging System Enhancements - -**Updated** Enhanced logging system for sync blocks with info level logging and console color formatting - -The logging system has been significantly enhanced to provide better production visibility with info level logging and console color formatting. These improvements ensure that block processing activities are visible in production environments without overwhelming debug-level verbosity. - -### Sync Block Logging with Info Level Visibility - -The network layer now provides enhanced logging for sync block operations with info level granularity: - -- **Successful sync block acceptance**: `ilog("Successfully pushed sync block ${num} (id:${id})")` - Provides confirmation when sync blocks are successfully processed -- **Sync block rejection**: `ilog("Sync block #${num} not applied (already on chain, micro-fork, or parent unknown ahead)")` - Documents why sync blocks are not applied -- **Sync mode transitions**: `ilog("\033[92m>>> Syncing Blockchain started from block #${n} (head: ${head})\033[0m")` and `ilog("\033[92mSync mode ended: received normal block #${n} (head: ${head}), sync_start_logged reset\033[0m")` - Tracks sync mode lifecycle - -These logs are upgraded from debug to info level, making them visible in production configurations without requiring debug logging to be enabled. - -### Console Color Formatting for Block Processing - -The P2P plugin implements comprehensive console color formatting for block processing visibility: - -- **Color constants**: `CLOG_WHITE`, `CLOG_GRAY`, `CLOG_RESET` define ANSI color codes for terminal output -- **Sync block notifications**: `ilog(CLOG_WHITE "Chain pushing sync block #${block_num} (head: ${head}, gap: ${gap})" CLOG_RESET)` - White text for sync blocks -- **Normal block notifications**: `ilog(CLOG_WHITE "Chain pushing normal block #${block_num} (head: ${head}, gap: ${gap})" CLOG_RESET)` - White text for normal blocks -- **Transaction processing**: `ilog(CLOG_WHITE "Got ${t} transactions on block ${b} by ${w} -- latency: ${l} ms" CLOG_RESET)` - White text for transaction counts - -The color formatting enhances readability in terminal environments, allowing operators to quickly distinguish between sync blocks, normal blocks, and transaction processing information. - -### Production-Ready Logging Strategy - -The enhanced logging system follows a production-ready strategy: - -- **Info level logging**: Critical block processing events are logged at info level for production visibility -- **Console color formatting**: Terminal output uses color codes for improved readability -- **Structured information**: Logs include block numbers, timestamps, validator information, and performance metrics -- **Minimal noise**: Debug-level verbose logging is reduced while maintaining essential operational information - -```mermaid -flowchart TD -LogStart(["Block Processing Event"]) --> CheckType{"Block Type?"} -CheckType --> |Sync Block| SyncLog["ilog(info level)"] -CheckType --> |Normal Block| NormalLog["ilog(info level)"] -SyncLog --> ColorFormat["Console Color Formatting"] -NormalLog --> ColorFormat -ColorFormat --> StructInfo["Structured Information"] -StructInfo --> ProdVisibility["Production Visibility"] -``` - -**Diagram sources** -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) - -**Section sources** -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [p2p_plugin.cpp:16:19](file://plugins/p2p/p2p_plugin.cpp#L16-L19) - -## Dependency Analysis -The following diagram shows module-level dependencies among the core components involved in block processing. - -```mermaid -graph LR -DB["database.cpp"] --> FD["fork_database.cpp"] -DB --> BL["block_log.cpp"] -DB --> BS["block_summary_object.hpp"] -DB --> DH["database.hpp"] -FD --> FH["fork_database.hpp"] -BL --> BH["block_log.hpp"] -BS --> BH -NET["node.cpp"] --> DB -P2P["p2p_plugin.cpp"] --> NET -CHAIN["chain plugin.cpp"] --> DB -``` - -**Diagram sources** -- [database.hpp:3-8](file://libraries/chain/include/graphene/chain/database.hpp#L3-L8) -- [fork_database.hpp:3-18](file://libraries/chain/include/graphene/chain/fork_database.hpp#L3-L18) -- [block_log.hpp:3-9](file://libraries/chain/include/graphene/chain/block_log.hpp#L3-L9) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) - -**Section sources** -- [database.hpp:3-8](file://libraries/chain/include/graphene/chain/database.hpp#L3-L8) -- [fork_database.hpp:3-18](file://libraries/chain/include/graphene/chain/fork_database.hpp#L3-L18) -- [block_log.hpp:3-9](file://libraries/chain/include/graphene/chain/block_log.hpp#L3-L9) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) - -## Performance Considerations -- Memory-mapped IO: The block log uses memory-mapped files for efficient random access and streaming reads/writes. -- Index reconstruction: On mismatch, the index is reconstructed by scanning the entire block log; this is expensive but safe. -- Skip flags: During reindex or trusted operations, validations can be selectively skipped to improve throughput. -- Undo sessions: State changes are wrapped in undo sessions to support rollback on errors and efficient reversion during forks. -- Pending transactions: During block generation, transactions are re-applied to reflect time-dependent semantics and respect block size limits. -- **Enhanced validator validation**: Pre-check mechanisms using find_account() avoid exception overhead and improve block production reliability. -- **Enhanced logging**: Info level logging provides production visibility without debug-level overhead, while console color formatting improves terminal readability. - -## Troubleshooting Guide -Common issues and remedies: -- Block log/head mismatch: The block log automatically detects inconsistencies and reconstructs the index. If repeated failures occur, inspect logs around index construction and ensure proper shutdown procedures. -- Fork reorganization failures: If applying a fork branch fails, the system removes invalid blocks from the fork database, restores the good fork, and rethrows the error. Review the failing block and validator participation. -- Excessive memory usage during replay: The database reserves memory and resizes shared memory if allocation fails mid-replay. Monitor logs for forced resizing events. -- Invalid validator schedule: If a block's timestamp slot does not align with the scheduled validator, validation fails. Verify time synchronization and validator schedules. -- **Missing validator accounts**: Enhanced pre-check mechanisms now detect missing validator accounts gracefully, logging critical details and preventing node crashes. Such issues typically indicate shared memory corruption requiring node restart with replay. -- **Enhanced logging visibility**: Production environments can now monitor block processing through info level logs without debug configuration, while console color formatting improves terminal readability for operators. - -**Section sources** -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [database.cpp:847-925](file://libraries/chain/database.cpp#L847-L925) -- [database.cpp:804-823](file://libraries/chain/database.cpp#L804-L823) -- [database.cpp:3724-3748](file://libraries/chain/database.cpp#L3724-L3748) -- [database.cpp:1294-1311](file://libraries/chain/database.cpp#L1294-L1311) -- [node.cpp:3354-3366](file://libraries/network/node.cpp#L3354-L3366) -- [plugin.cpp:104-121](file://plugins/chain/plugin.cpp#L104-L121) -- [p2p_plugin.cpp:152-157](file://plugins/p2p/p2p_plugin.cpp#L152-L157) - -## Conclusion -The Block Processing and Validation system integrates robust storage (block log), fork management (fork database), and strict consensus validation (database) to ensure blockchain consistency. The validate_block() and push_block() methods coordinate header checks, validator scheduling, Merkle roots, and block size limits. The system supports efficient replay for synchronization and maintains validator participation metrics to enforce consensus. - -**Enhanced validator account validation** provides improved reliability during block production by performing preliminary verification using find_account() calls instead of relying on get_account() which would throw exceptions. This change ensures graceful handling of missing validator accounts and prevents node crashes, while maintaining comprehensive error reporting for debugging shared memory corruption scenarios. - -**Enhanced logging system** provides production-ready visibility with info level logging for sync blocks and normal blocks, upgraded from debug level for better production monitoring. Console color formatting improves terminal readability with white text for block processing notifications and structured information including block numbers, validator information, and performance metrics. - -Proper use of skip flags, memory mapping, and undo sessions yields strong performance and reliability, making the system resilient to various operational challenges while maintaining strict consensus enforcement. The enhanced logging system ensures that block processing activities are visible in production environments without overwhelming debug-level verbosity, supporting effective monitoring and troubleshooting of blockchain operations. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Chain Library.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Chain Library.md deleted file mode 100644 index c27426cf05..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Chain Library.md +++ /dev/null @@ -1,995 +0,0 @@ -# Chain Library - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp) -- [operation_notification.hpp](file://libraries/chain/include/graphene/chain/operation_notification.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [snapshot_plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [node.cpp](file://libraries/network/node.cpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [console_appender.cpp](file://thirdparty/fc/src/log/console_appender.cpp) -- [main.cpp](file://programs/vizd/main.cpp) - - -## Update Summary -**Changes Made** -- Enhanced blockchain synchronization logging with guard variable to prevent duplicate sync start messages -- Updated sync restart reasons to use info-level logging instead of debug-level for clearer insights -- Added block processing logs with current head block numbers and gap calculations -- Increased logging frequency from every 10,000 blocks to every 500 blocks during synchronization -- Enhanced logging system documentation with ANSI color codes for operational visibility -- Improved network node synchronization logging with info-level messages for sync restart reasons - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Snapshot Loading and DLT Mode](#snapshot-loading-and-dlt-mode) -7. [Enhanced Logging System and Operational Visibility](#enhanced-logging-system-and-operational-visibility) -8. [Dependency Analysis](#dependency-analysis) -9. [Performance Considerations](#performance-considerations) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Conclusion](#conclusion) -12. [Appendices](#appendices) - -## Introduction -This document describes the Chain Library, the core blockchain state management system. It explains how the database persists blockchain state, validates blocks and transactions, resolves forks, and stores blocks efficiently. The library now includes enhanced snapshot loading capabilities, DLT (Data Ledger Technology) mode support, improved error handling during snapshot operations, and a comprehensive logging system with ANSI color codes for enhanced operational visibility. It also documents the data model (objects and indices), the evaluator system for operation processing, and the observer pattern used for event-driven notifications. Practical examples and performance optimization techniques are included to help developers integrate and operate the Chain Library effectively. - -## Project Structure -The Chain Library is organized around a central database class that orchestrates: -- State persistence and indexing via ChainBase -- Fork handling with a fork database -- Block log for durable storage -- DLT rolling block log for selective block retention -- Object model definitions for accounts, validators, committee requests, and more -- Evaluator registry for operation processing -- Observer signals for event-driven integrations -- Snapshot loading and state restoration capabilities -- Enhanced logging system with color-coded synchronization messages - -```mermaid -graph TB -subgraph "Chain Core" -DB["database.hpp/.cpp"] -FDB["fork_database.hpp/.cpp"] -BLK["block_log.hpp/.cpp"] -DLT["dlt_block_log.hpp/.cpp"] -end -subgraph "Object Model" -OT["chain_object_types.hpp"] -CO["chain_objects.hpp"] -AO["account_object.hpp"] -WO["witness_objects.hpp"] -CT["committee_objects.hpp"] -TO["transaction_object.hpp"] -end -subgraph "Processing" -EV["evaluator.hpp"] -CEV["chain_evaluator.hpp"] -ON["operation_notification.hpp"] -SNAP["snapshot_plugin.cpp"] -CHAINPLUG["chain plugin.cpp"] -end -subgraph "Logging System" -LOG["console_appender.cpp"] -MAIN["main.cpp"] -SYNC["node.cpp"] -validator["validator.cpp"] -end -DB --> FDB -DB --> BLK -DB --> DLT -DB --> OT -DB --> CO -DB --> AO -DB --> WO -DB --> CT -DB --> TO -DB --> EV -DB --> CEV -DB --> ON -CHAINPLUG --> SNAP -CHAINPLUG --> DB -SNAP --> LOG -SYNC --> LOG -validator --> LOG -MAIN --> LOG -``` - -**Diagram sources** -- [database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [database.cpp:206-456](file://libraries/chain/database.cpp#L206-L456) -- [fork_database.hpp:53-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [fork_database.cpp:1-245](file://libraries/chain/fork_database.cpp#L1-L245) -- [block_log.hpp:1-200](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L200) -- [block_log.cpp:230-302](file://libraries/chain/block_log.cpp#L230-L302) -- [dlt_block_log.hpp:35-75](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L75) -- [dlt_block_log.cpp:161-382](file://libraries/chain/dlt_block_log.cpp#L161-L382) -- [chain_object_types.hpp:44-146](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [chain_objects.hpp:20-226](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L226) -- [account_object.hpp:20-143](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L143) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [committee_objects.hpp:15-47](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L47) -- [transaction_object.hpp:19-56](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp:14-79](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) -- [operation_notification.hpp:11-26](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L11-L26) -- [plugin.cpp:360-432](file://plugins/chain/plugin.cpp#L360-L432) -- [snapshot_plugin.cpp:980-1200](file://plugins/snapshot/plugin.cpp#L980-L1200) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) -- [main.cpp:234-253](file://programs/vizd/main.cpp#L234-L253) - -**Section sources** -- [database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [database.cpp:206-456](file://libraries/chain/database.cpp#L206-L456) - -## Core Components -- Database: Central state manager that opens/closes the chain, replays history, pushes blocks and transactions, manages undo sessions, and emits observer signals. Now includes DLT mode support and snapshot loading capabilities. -- Fork Database: Maintains a tree of candidate blocks, supports branch resolution, and selects the longest chain. -- Block Log: Provides durable, memory-mapped storage for blocks and an index for fast random access. -- DLT Rolling Block Log: Enhanced block storage system that maintains only a rolling window of recent blocks for selective retention. -- Object Model: Defines all persistent objects (accounts, validators, committee requests, transactions, etc.) and their multi-index containers. -- Evaluator System: Registry and base classes for operation processing with a standardized interface. -- Observer Pattern: Signals for pre/post operation application, applied block, and transaction events. -- Snapshot Plugin: Handles state restoration from snapshots and manages snapshot lifecycle. -- Enhanced Logging System: Comprehensive color-coded logging with ANSI escape sequences for enhanced operational visibility and progress monitoring. - -Key responsibilities: -- Persistence: ChainBase-backed storage with configurable shared memory sizing and periodic revision alignment. -- Validation: Block and transaction validation with configurable skip flags for reindexing and specialized scenarios. -- Consensus: Fork selection and irreversible block updates. -- Eventing: Notifications for plugins and observers. -- State Restoration: Snapshot loading for rapid node startup and state recovery. -- DLT Operations: Selective block retention for compliance and archival purposes. -- Operational Visibility: Color-coded logging for synchronization progress and system status with enhanced frequency monitoring. - -**Section sources** -- [database.hpp:56-110](file://libraries/chain/include/graphene/chain/database.hpp#L56-L110) -- [database.cpp:206-350](file://libraries/chain/database.cpp#L206-L350) -- [fork_database.hpp:53-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [block_log.hpp:1-200](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L200) -- [dlt_block_log.hpp:35-75](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L75) -- [evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) - -## Architecture Overview -The Chain Library composes several subsystems with enhanced snapshot and DLT capabilities: -- database orchestrates state transitions and emits signals, now supporting DLT mode and snapshot operations -- fork_database maintains candidate chains -- block_log provides durable storage -- dlt_block_log provides selective block retention in DLT mode -- object model defines schema and indices -- evaluators apply operations atomically within undo sessions -- snapshot plugin handles state restoration and validation -- enhanced logging system provides color-coded operational visibility with improved synchronization monitoring - -```mermaid -sequenceDiagram -participant App as "Caller" -participant DB as "database" -participant FDB as "fork_database" -participant BLK as "block_log" -participant DLT as "dlt_block_log" -participant LOG as "Logging System" -participant OBS as "Observers" -App->>DB : push_block(signed_block) -DB->>FDB : push_block() -alt fork head advanced -DB->>DB : fetch_branch_from() -loop pop blocks until forked -DB->>DB : pop_block() -end -loop push new fork blocks -DB->>DB : apply_block() -DB->>OBS : notify_applied_block() -DB->>LOG : Emit colored sync progress (every 500 blocks) -end -else same fork -DB->>DB : apply_block() -end -DB->>BLK : append() -DB->>DLT : append() (if DLT mode) -DB->>OBS : notify_applied_block() -``` - -**Diagram sources** -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) -- [dlt_block_log.cpp:211-230](file://libraries/chain/dlt_block_log.cpp#L211-L230) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) - -**Section sources** -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [fork_database.cpp:168-210](file://libraries/chain/fork_database.cpp#L168-L210) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) -- [dlt_block_log.cpp:211-230](file://libraries/chain/dlt_block_log.cpp#L211-L230) - -## Detailed Component Analysis - -### Database: State Management, Validation, and Events -The database class extends ChainBase and encapsulates: -- Opening/closing the database and block log -- Reindexing from block log -- Pushing blocks and transactions with configurable validation -- Undo sessions for atomic state transitions -- Observer signals for operations and blocks -- DLT mode support for selective block retention -- Snapshot loading capabilities for rapid state restoration - -Notable APIs: -- Block lifecycle: validate_block, push_block, pop_block, generate_block -- Transaction lifecycle: validate_transaction, push_transaction -- Queries: get_account, get_witness, get_content, get_escrow, get_dynamic_global_properties, get_witness_schedule_object, get_hardfork_property_object -- Fork and block log helpers: is_known_block, is_known_transaction, fetch_block_by_id, fetch_block_by_number, get_block_ids_on_fork -- DLT mode: _dlt_mode flag, _dlt_block_log_max_blocks configuration -- Observers: pre_apply_operation, post_apply_operation, applied_block, on_pending_transaction, on_applied_transaction - -Validation flags allow skipping expensive checks during reindexing or trusted operations. - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, ...) -+reindex(data_dir, shared_mem_dir, from_block_num, ...) -+open_from_snapshot(data_dir, shared_mem_dir, initial_supply, shared_file_size, flags) -+push_block(signed_block, skip) -+validate_block(signed_block, skip) -+push_transaction(signed_transaction, skip) -+validate_transaction(signed_transaction, skip) -+generate_block(...) -+pop_block() -+get_account(name) -+get_witness(name) -+get_content(author, permlink) -+get_escrow(name, id) -+get_dynamic_global_properties() -+get_witness_schedule_object() -+get_hardfork_property_object() -+is_known_block(id) -+is_known_transaction(id) -+fetch_block_by_id(id) -+fetch_block_by_number(n) -+get_block_ids_on_fork(head) -+pre_apply_operation(signal) -+post_apply_operation(signal) -+applied_block(signal) -+on_pending_transaction(signal) -+on_applied_transaction(signal) -+initialize_hardforks() -} -class fork_database -class block_log -class dlt_block_log -database --> fork_database : "uses" -database --> block_log : "uses" -database --> dlt_block_log : "uses" -``` - -**Diagram sources** -- [database.hpp:111-558](file://libraries/chain/include/graphene/chain/database.hpp#L111-L558) -- [database.cpp:206-456](file://libraries/chain/database.cpp#L206-L456) -- [fork_database.hpp:53-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [block_log.hpp:1-200](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L200) -- [dlt_block_log.hpp:35-75](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L75) - -**Section sources** -- [database.hpp:111-558](file://libraries/chain/include/graphene/chain/database.hpp#L111-L558) -- [database.cpp:206-456](file://libraries/chain/database.cpp#L206-L456) - -### Fork Database: Fork Resolution and Branch Selection -The fork database maintains a tree of candidate blocks: -- push_block inserts a block and links it to previous if possible -- fetch_branch_from computes divergent branches to resolve forks -- walk_main_branch_to_num and fetch_block_on_main_branch_by_number resolve canonical chain membership -- set_max_size prunes old blocks to bound memory growth - -```mermaid -flowchart TD -Start(["push_block"]) --> LinkCheck["Link to previous known block?"] -LinkCheck --> |No| Cache["Add to unlinked cache"] -LinkCheck --> |Yes| Insert["_push_block: insert into index"] -Insert --> UpdateHead{"New head? (higher num)"} -UpdateHead --> |Yes| SetHead["Set head"] -UpdateHead --> |No| Done(["Return head"]) -Cache --> Done -SetHead --> Done -``` - -**Diagram sources** -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) - -**Section sources** -- [fork_database.hpp:53-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L125) -- [fork_database.cpp:47-90](file://libraries/chain/fork_database.cpp#L47-L90) - -### Block Log: Efficient Storage and Retrieval -The block log provides: -- Memory-mapped files for blocks and an index -- Random access by block number via index -- Append-only writes with position tracking -- Robust startup logic to reconcile head positions and reconstruct index if needed - -```mermaid -flowchart TD -Open(["open(file)"]) --> InitFiles["Ensure block/index files exist"] -InitFiles --> MapFiles["Map files into memory"] -MapFiles --> Reconcile["Compare heads and reconstruct index if needed"] -Reconcile --> Ready(["Ready"]) -Append(["append(block)"]) --> Pack["Pack block"] -Pack --> WriteBlock["Write to block log"] -WriteBlock --> WriteIndex["Write position to index"] -WriteIndex --> UpdateHead["Update head"] -ReadNum(["read_block_by_num(n)"]) --> Pos["Get position from index"] -Pos --> ReadBlock["Read block at position"] -ReadBlock --> Verify["Verify block number"] -``` - -**Diagram sources** -- [block_log.cpp:134-194](file://libraries/chain/block_log.cpp#L134-L194) -- [block_log.cpp:195-227](file://libraries/chain/block_log.cpp#L195-L227) -- [block_log.cpp:270-285](file://libraries/chain/block_log.cpp#L270-L285) - -**Section sources** -- [block_log.hpp:1-200](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L200) -- [block_log.cpp:134-194](file://libraries/chain/block_log.cpp#L134-L194) -- [block_log.cpp:270-285](file://libraries/chain/block_log.cpp#L270-L285) - -### DLT Block Log: Selective Block Retention -The DLT block log provides: -- Memory-mapped files for blocks and an index with rolling window capability -- Configurable maximum blocks retention via _dlt_block_log_max_blocks -- Automatic truncation when exceeding configured limits -- Separate from standard block log for compliance and archival purposes -- Support for DLT mode where only irreversible blocks are retained - -```mermaid -flowchart TD -Open(["open(file)"]) --> InitFiles["Ensure dlt block/index files exist"] -InitFiles --> MapFiles["Map files into memory"] -MapFiles --> Reconcile["Reconstruct index if mismatched"] -Reconcile --> Ready(["Ready"]) -Append(["append(block)"]) --> CheckLimit{"Exceeds max blocks?"} -CheckLimit --> |Yes| Truncate["Truncate old blocks"] -CheckLimit --> |No| Continue["Continue"] -Truncate --> TruncateBefore["truncate_before(new_start)"] -TruncateBefore --> Continue -Continue --> Pack["Pack block"] -Pack --> WriteBlock["Write to dlt block log"] -WriteBlock --> WriteIndex["Write position to index"] -WriteIndex --> UpdateHead["Update head"] -``` - -**Diagram sources** -- [dlt_block_log.cpp:161-230](file://libraries/chain/dlt_block_log.cpp#L161-L230) -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -**Section sources** -- [dlt_block_log.hpp:35-75](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L75) -- [dlt_block_log.cpp:161-230](file://libraries/chain/dlt_block_log.cpp#L161-L230) -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -### Data Model: Objects and Indices -The object model defines persistent entities and their indices: -- Object types enumerate all managed object kinds -- Account, validator, committee request/vote, transaction, escrow, vesting delegation, and more -- Multi-index containers provide unique and composite keys for efficient lookups - -Representative object categories: -- Accounts: balances, vesting shares, delegation, auction metadata, bandwidth tracking -- validators: votes, virtual scheduling, signing keys, version/hardfork votes -- Committee: requests with statuses, funding, payouts -- Transactions: deduplication and expiration tracking -- Escrow and routes: multi-signature transfers and routing - -```mermaid -erDiagram -ACCOUNT { -name : string -balance : asset -vesting_shares : asset -delegated_vesting_shares : asset -received_vesting_shares : asset -energy : int16 -last_vote_time : time_point_sec -} -validator { -owner : account_name_type -votes : share_type -signing_key : public_key_type -running_version : version -hardfork_version_vote : hardfork_version -hardfork_time_vote : time_point_sec -} -COMMITTEE_REQUEST { -request_id : uint32 -creator : account_name_type -worker : account_name_type -required_amount_min : asset -required_amount_max : asset -status : uint16 -start_time : time_point_sec -end_time : time_point_sec -payout_amount : asset -remain_payout_amount : asset -} -TRANSACTION_OBJECT { -trx_id : transaction_id_type -expiration : time_point_sec -} -ESCROW { -escrow_id : uint32 -from : account_name_type -to : account_name_type -agent : account_name_type -ratification_deadline : time_point_sec -escrow_expiration : time_point_sec -token_balance : asset -pending_fee : asset -to_approved : bool -agent_approved : bool -disputed : bool -} -ACCOUNT ||--o{ WITNESS_VOTE : "votes_for" -ACCOUNT ||--o{ ESCROW : "escrows" -ACCOUNT ||--o{ COMMITTEE_VOTE : "votes" -COMMITTEE_REQUEST ||--o{ COMMITTEE_VOTE : "votes" -TRANSACTION_OBJECT ||--|| BLOCK : "referenced_in" -``` - -**Diagram sources** -- [chain_object_types.hpp:44-146](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [account_object.hpp:20-143](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L143) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [committee_objects.hpp:15-47](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L47) -- [transaction_object.hpp:19-56](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [chain_objects.hpp:20-141](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L141) - -**Section sources** -- [chain_object_types.hpp:44-146](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L146) -- [account_object.hpp:20-143](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L143) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [committee_objects.hpp:15-47](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L47) -- [transaction_object.hpp:19-56](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [chain_objects.hpp:20-141](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L141) - -### Evaluator System: Operation Processing -The evaluator system provides a uniform mechanism to apply operations: -- Base evaluator interface with apply and type identification -- Evaluator implementations for each operation type -- Registry-driven dispatch to the appropriate evaluator - -```mermaid -classDiagram -class evaluator~OperationType~ { -<> -+apply(op : OperationType) void -+get_type() int -} -class evaluator_impl~EvaluatorType, OperationType~ { --_db : database -+apply(op : OperationType) void -+get_type() int -+db() database& -} -class account_create_evaluator -class transfer_evaluator -class witness_update_evaluator -evaluator_impl <|-- account_create_evaluator -evaluator_impl <|-- transfer_evaluator -evaluator_impl <|-- witness_update_evaluator -evaluator <|-- evaluator_impl -``` - -**Diagram sources** -- [evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp:14-79](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) - -**Section sources** -- [evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [chain_evaluator.hpp:14-79](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) - -### Observer Pattern: Event-Driven Architecture -The database emits signals for: -- Pre/post operation application -- Applied block -- Pending/applied transactions - -Plugins and observers can subscribe to these signals to react to state changes without tight coupling. - -```mermaid -sequenceDiagram -participant DB as "database" -participant OBS as "Observers" -participant EVAL as "evaluator" -DB->>EVAL : apply_operation(op) -DB->>OBS : pre_apply_operation(note) -EVAL-->>DB : operation applied -DB->>OBS : post_apply_operation(note) -DB->>OBS : applied_block(block) -DB->>OBS : on_applied_transaction(trx) -``` - -**Diagram sources** -- [database.hpp:252-286](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [operation_notification.hpp:11-26](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L11-L26) -- [database.cpp:1158-1198](file://libraries/chain/database.cpp#L1158-L1198) - -**Section sources** -- [database.hpp:252-286](file://libraries/chain/include/graphene/chain/database.hpp#L252-L286) -- [operation_notification.hpp:11-26](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L11-L26) -- [database.cpp:1158-1198](file://libraries/chain/database.cpp#L1158-L1198) - -## Snapshot Loading and DLT Mode - -### Enhanced Chain Plugin Startup Sequence -The chain plugin now implements a sophisticated startup sequence that handles both normal operation and snapshot-based initialization: - -```mermaid -flowchart TD -Start(["plugin_startup()"]) --> CheckSnapshot{"--snapshot option present?"} -CheckSnapshot --> |Yes| CheckSHM["Check shared_memory.bin exists"] -CheckSHM --> |Exists & >0| NormalStartup["Skip snapshot import, use normal startup"] -CheckSHM --> |Missing/Empty| CheckFile["Check snapshot file exists"] -CheckFile --> |Exists| OpenSnapshot["Call db.open_from_snapshot()"] -CheckFile --> |Missing| NormalStartup -OpenSnapshot --> LoadState["Execute snapshot_load_callback()"] -LoadState --> ValidateState["Validate snapshot integrity"] -ValidateState --> Success{"Load success?"} -Success --> |Yes| RenameFile["Rename snapshot to .used"] -Success --> |No| Error["Log fatal error and exit"] -NormalStartup --> NormalOpen["Call db.open()"] -NormalOpen --> ReplayCheck{"Need replay?"} -ReplayCheck --> |Yes| ExecuteReplay["Execute replay_db()"] -ReplayCheck --> |No| CompleteStartup["Complete startup"] -ExecuteReplay --> CompleteStartup -CompleteStartup --> Sync["on_sync()"] -``` - -**Diagram sources** -- [plugin.cpp:364-432](file://plugins/chain/plugin.cpp#L364-L432) -- [plugin.cpp:434-491](file://plugins/chain/plugin.cpp#L434-L491) - -**Section sources** -- [plugin.cpp:364-432](file://plugins/chain/plugin.cpp#L364-L432) -- [plugin.cpp:434-491](file://plugins/chain/plugin.cpp#L434-L491) - -### Database Initialization for Snapshot Mode -The database provides a dedicated `open_from_snapshot` method that initializes the chain in DLT mode: - -**Updated** Enhanced with DLT mode flag management and improved error handling - -Key features: -- Sets `_dlt_mode = true` for DLT operations -- Wipes existing shared memory to ensure clean state -- Initializes schema and opens shared memory with proper flags -- Opens both standard and DLT block logs -- Handles genesis initialization in read-write mode - -**Section sources** -- [database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) - -### Snapshot Loading Process -The snapshot plugin implements comprehensive state restoration: - -**Updated** Enhanced with improved error handling and validation - -Process overview: -1. Parse and validate snapshot header -2. Verify chain ID compatibility and version support -3. Validate payload checksum for integrity -4. Clear genesis-created objects to prevent conflicts -5. Import objects in dependency order (singletons first, then multi-instance) -6. Set chainbase revision to match snapshot head block -7. Seed fork database with snapshot head block - -**Section sources** -- [snapshot_plugin.cpp:1000-1200](file://plugins/snapshot/plugin.cpp#L1000-L1200) - -### DLT Mode Flag Management -The database maintains two key DLT-related flags: - -**Updated** Added comprehensive DLT mode support - -- `_dlt_mode`: Boolean flag indicating snapshot-loaded state -- `_dlt_block_log_max_blocks`: Configurable limit for rolling block retention - -Behavior in DLT mode: -- Block log append operations are conditionally executed -- Irreversible blocks are selectively written to DLT block log -- Automatic truncation when exceeding configured limits -- Separate from standard block log for compliance purposes - -**Section sources** -- [database.hpp:57-64](file://libraries/chain/include/graphene/chain/database.hpp#L57-L64) -- [database.cpp:3985-4051](file://libraries/chain/database.cpp#L3985-L4051) - -### Error Handling Improvements -Enhanced error handling during snapshot operations: - -**Updated** Added comprehensive error handling and recovery mechanisms - -- Graceful fallback to normal startup when snapshot import fails -- Detailed error logging with specific failure reasons -- Automatic snapshot file renaming to prevent re-import -- Validation of snapshot integrity before import -- Proper cleanup and resource management on errors - -**Section sources** -- [plugin.cpp:391-417](file://plugins/chain/plugin.cpp#L391-L417) -- [snapshot_plugin.cpp:1014-1032](file://plugins/snapshot/plugin.cpp#L1014-L1032) - -## Enhanced Logging System and Operational Visibility - -### Enhanced Logging Infrastructure -The Chain Library now features a comprehensive logging system with ANSI color codes designed to improve operational visibility during blockchain synchronization and state management operations. - -#### Color-Coded Log Categories -The logging system uses distinct ANSI color codes for different operational contexts: - -- **Green (✓)**: Successful operations, block generation, and positive confirmations -- **Brown/Yellow (⚠)**: Warning conditions, synchronization progress, and informational messages -- **Cyan (✗)**: Error conditions and critical failures -- **Default**: Debug-level information and internal operations - -#### Synchronization Progress Messages -Blockchain synchronization messages utilize yellow color coding for enhanced visibility: - -- **Yellow ANSI Codes**: `\033[93m` for synchronization progress indicators -- **Orange ANSI Codes**: `\033[33m` for snapshot import operations -- **Green ANSI Codes**: `\033[92m` for successful block generation - -#### Enhanced Synchronization Monitoring -**Updated** The synchronization system now includes improved monitoring with: - -- **Guard Variable**: `sync_start_logged` prevents duplicate sync start messages -- **Increased Frequency**: Progress logging occurs every 500 blocks instead of every 10,000 blocks -- **Color-Coded Progress**: Yellow messages for synchronization progress and block acceptance -- **Comprehensive Coverage**: Both sync start and ongoing progress messages are color-coded - -#### Implementation Details -The logging system leverages the FC (Fast Crypto) framework's console appender with enhanced color support: - -```mermaid -flowchart TD -Start(["Block Processing"]) --> CheckSync{"Currently Syncing?"} -CheckSync --> |Yes| CheckGuard{"sync_start_logged?"} -CheckGuard --> |No| LogStart["Log Sync Start (Green)"] -LogStart --> SetGuard["Set sync_start_logged = true"] -SetGuard --> CheckFreq{"block_num() % 500 == 0?"} -CheckGuard --> |Yes| CheckFreq -CheckFreq --> |Yes| LogProgress["Log Progress (Yellow)"] -CheckFreq --> |No| Skip["Skip Logging"] -CheckSync --> |No| ResetGuard["Reset sync_start_logged = false"] -ResetGuard --> Continue["Continue Processing"] -LogProgress --> Continue -Skip --> Continue -``` - -**Diagram sources** -- [plugin.cpp:100-113](file://plugins/chain/plugin.cpp#L100-L113) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) -- [main.cpp:234-253](file://programs/vizd/main.cpp#L234-L253) - -#### Synchronization Progress Indicators -During blockchain synchronization, the system provides enhanced color-coded progress updates: - -- **Green messages** indicate synchronization start (only logged once per sync session) -- **Yellow messages** indicate synchronization progress every 500 blocks -- **Green messages** confirm successful block generation by validators -- **Orange messages** highlight snapshot import operations -- **Default messages** show internal synchronization mechanics - -#### Color Scheme Configuration -The logging system supports configurable color schemes through program options: - -- Console appenders support level-specific color assignments -- Default color mappings include debug (green), warn (brown/yellow), and error (cyan) -- Custom color configurations can be specified in logging configuration files - -**Section sources** -- [plugin.cpp:58-113](file://plugins/chain/plugin.cpp#L58-L113) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) -- [main.cpp:234-253](file://programs/vizd/main.cpp#L234-L253) -- [snapshot_plugin.cpp:1018-1032](file://plugins/snapshot/plugin.cpp#L1018-L1032) -- [validator.cpp:286](file://plugins/validator/validator.cpp#L286) - -### Enhanced Troubleshooting with Color Coding -The enhanced color-coded logging system significantly improves troubleshooting capabilities: - -#### Visual Progress Tracking -- **Green sync start messages**: Show when synchronization begins (logged once per session) -- **Yellow progress bars**: Show synchronization completion every 500 blocks -- **Green confirmations**: Highlight successful operations -- **Orange warnings**: Indicate snapshot import progress -- **Red alerts**: Signal critical errors requiring immediate attention - -#### Operational Context Clarity -Different log levels use distinct colors to provide immediate context: -- **Debug (Green)**: Low-level operational details -- **Info/Warn (Yellow/Brown)**: Synchronization progress and warnings -- **Error (Cyan)**: Critical failures and exceptions - -#### Terminal Output Enhancement -The ANSI color codes provide immediate visual feedback in terminal environments: -- Color-coded timestamps for better temporal tracking -- Distinct color schemes for different log sources -- Improved readability during high-volume logging scenarios -- Guard variable prevents log spam during sync sessions - -**Section sources** -- [node.cpp:3446-3456](file://libraries/network/node.cpp#L3446-L3456) -- [snapshot_plugin.cpp:1770-1771](file://plugins/snapshot/plugin.cpp#L1770-L1771) -- [validator.cpp:286](file://plugins/validator/validator.cpp#L286) - -### Network Node Synchronization Logging Enhancements -**Updated** The network node synchronization system now uses info-level logging for sync restart reasons, providing clearer insights into synchronization behavior: - -- **Info-level logging**: Sync restart reasons now use ilog instead of dlog for better visibility -- **Current head block numbers**: Logs include current head block numbers and gap calculations -- **Enhanced sync restart detection**: Improved logging for peer synchronization restarts -- **Block acceptance notifications**: Yellow progress messages with block numbers and producer information - -**Section sources** -- [node.cpp:2428-2444](file://libraries/network/node.cpp#L2428-L2444) -- [node.cpp:3276-3280](file://libraries/network/node.cpp#L3276-L3280) -- [database.cpp:5295-5303](file://libraries/chain/database.cpp#L5295-L5303) - -### Enhanced Logging Improvements Summary -The logging system enhancements include: - -1. **Guard Variable Protection**: `sync_start_logged` prevents duplicate sync start messages -2. **Info-Level Logging**: Sync restart reasons use ilog instead of dlog for better visibility -3. **Enhanced Progress Frequency**: Logging occurs every 500 blocks instead of every 10,000 blocks -4. **Color-Coded Notifications**: ANSI escape sequences provide visual distinction for different log types -5. **Current Head Block Numbers**: Logs include current head block numbers and gap calculations -6. **Improved Network Sync**: Better logging for peer synchronization restarts and block acceptance - -**Section sources** -- [plugin.cpp:58-121](file://plugins/chain/plugin.cpp#L58-L121) -- [node.cpp:2428-2444](file://libraries/network/node.cpp#L2428-L2444) -- [node.cpp:3276-3280](file://libraries/network/node.cpp#L3276-L3280) -- [database.cpp:5295-5303](file://libraries/chain/database.cpp#L5295-L5303) - -## Dependency Analysis -The database depends on: -- fork_database for chain selection -- block_log for durable storage -- dlt_block_log for selective block retention in DLT mode -- object model headers for schema definitions -- evaluator registry for operation application -- observer signals for event emission -- snapshot plugin for state restoration -- enhanced logging system for operational visibility - -```mermaid -graph LR -DB["database.hpp/.cpp"] --> FDB["fork_database.hpp/.cpp"] -DB --> BLK["block_log.hpp/.cpp"] -DB --> DLT["dlt_block_log.hpp/.cpp"] -DB --> OT["chain_object_types.hpp"] -DB --> CO["chain_objects.hpp"] -DB --> AO["account_object.hpp"] -DB --> WO["witness_objects.hpp"] -DB --> CT["committee_objects.hpp"] -DB --> TO["transaction_object.hpp"] -DB --> EV["evaluator.hpp"] -DB --> CEV["chain_evaluator.hpp"] -DB --> ON["operation_notification.hpp"] -CHAINPLUG["chain plugin.cpp"] --> SNAP["snapshot_plugin.cpp"] -CHAINPLUG --> DB -LOGSYS["console_appender.cpp"] --> MAIN["main.cpp"] -LOGSYS --> SYNC["node.cpp"] -LOGSYS --> validator["validator.cpp"] -``` - -**Diagram sources** -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [database.cpp:1-200](file://libraries/chain/database.cpp#L1-L200) -- [fork_database.hpp:1-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp:1-200](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L200) -- [dlt_block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L75) -- [chain_object_types.hpp:1-246](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L1-L246) -- [chain_objects.hpp:1-226](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L1-L226) -- [account_object.hpp:1-565](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L565) -- [witness_objects.hpp:1-313](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L313) -- [committee_objects.hpp:1-137](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L1-L137) -- [transaction_object.hpp:1-56](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L1-L56) -- [evaluator.hpp:1-62](file://libraries/chain/include/graphene/chain/evaluator.hpp#L1-L62) -- [chain_evaluator.hpp:1-80](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L1-L80) -- [operation_notification.hpp:1-27](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L1-L27) -- [plugin.cpp:1-526](file://plugins/chain/plugin.cpp#L1-L526) -- [snapshot_plugin.cpp:1-1976](file://plugins/snapshot/plugin.cpp#L1-L1976) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) -- [main.cpp:234-253](file://programs/vizd/main.cpp#L234-L253) - -**Section sources** -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [database.cpp:1-200](file://libraries/chain/database.cpp#L1-L200) - -## Performance Considerations -- Shared memory sizing and auto-resize: Configure minimum free memory thresholds and incremental growth to avoid frequent resizes during heavy load. -- Block log I/O: Memory-mapped files reduce syscall overhead; ensure adequate OS page cache and avoid fragmentation. -- Fork pruning: Limit fork cache size to bound memory usage; prune old blocks when head advances significantly. -- Validation flags: During reindexing, skip expensive checks (signatures, merkle, authority) to accelerate replay. -- Bandwidth accounting: Efficient per-account bandwidth calculations prevent excessive CPU usage on producers. -- Undo sessions: Use short-lived sessions to minimize rollback overhead; squash temporary sessions after successful application. -- DLT mode optimization: Configure `_dlt_block_log_max_blocks` appropriately to balance storage requirements and performance. -- Snapshot loading: Use snapshot mode for rapid node startup, especially for large blockchains. -- **New**: Enhanced logging performance: Color-coded logging with guard variables and increased frequency provides better operational visibility with minimal overhead while significantly improving troubleshooting efficiency. -- **New**: Synchronization monitoring: The `sync_start_logged` guard prevents duplicate messages and reduces log volume during sync sessions. -- **New**: Info-level logging for sync restarts: Using ilog instead of dlog for sync restart reasons provides clearer insights into synchronization behavior. -- **New**: Network synchronization improvements: Enhanced logging with current head block numbers and gap calculations improves monitoring accuracy. - -## Troubleshooting Guide -Common issues and remedies: -- Chain mismatch after restart: The database verifies revision against head block number; if inconsistent, a specific exception is thrown indicating the mismatch. -- Block log/head mismatch: On open, the database validates that the block log head matches the chain head; if not, a specific exception instructs reindexing. -- Memory pressure: Monitor free memory and trigger auto-resize when thresholds are met; periodically print free memory status. -- Fork collisions: When multiple blocks are produced at the same slot, warnings are logged; ensure correct fork resolution and head updates. -- Bad allocation during block push: On memory exhaustion, the system attempts to resize shared memory and retry. -- Snapshot import failures: Check shared_memory.bin existence and snapshot file accessibility; the system gracefully falls back to normal startup. -- DLT mode errors: Verify DLT block log configuration and ensure sufficient disk space for rolling window retention. -- Chain ID mismatches: Snapshot loading validates chain ID compatibility; ensure using correct snapshot for target network. -- **New**: Enhanced color-coded log interpretation: Use green messages for synchronization start (once per session), yellow messages for synchronization progress every 500 blocks, green for successful operations, orange for snapshot operations, and red for critical errors to quickly identify operational status. -- **New**: Synchronization monitoring: The guard variable prevents duplicate sync start messages and ensures consistent progress reporting every 500 blocks. -- **New**: Info-level logging improvements: Sync restart reasons now use info-level logging for better visibility and clearer insights into synchronization behavior. -- **New**: Network synchronization logging: Enhanced logging with current head block numbers and gap calculations provides better monitoring accuracy. - -**Section sources** -- [database.cpp:232-248](file://libraries/chain/database.cpp#L232-L248) -- [database.cpp:270-350](file://libraries/chain/database.cpp#L270-L350) -- [database.cpp:368-430](file://libraries/chain/database.cpp#L368-L430) -- [database.cpp:832-844](file://libraries/chain/database.cpp#L832-L844) -- [plugin.cpp:371-380](file://plugins/chain/plugin.cpp#L371-L380) -- [snapshot_plugin.cpp:1018-1020](file://plugins/snapshot/plugin.cpp#L1018-L1020) - -## Conclusion -The Chain Library provides a robust, modular framework for blockchain state management with enhanced snapshot loading capabilities and DLT mode support. Its design separates concerns across database orchestration, fork handling, durable storage, typed object models, operation processing, and event-driven observation. The addition of snapshot loading enables rapid node startup and state restoration, while DLT mode provides selective block retention for compliance and archival purposes. The enhanced logging system with ANSI color codes significantly improves operational visibility during synchronization and troubleshooting, featuring guard variables to prevent duplicate messages and increased frequency monitoring for better progress tracking. The updated info-level logging for sync restart reasons provides clearer insights into synchronization behavior with current head block numbers and gap calculations. By leveraging ChainBase for persistence, fork_database for consensus, block_log for storage, the new DLT block log for selective retention, and comprehensive color-coded logging for operational insights, it achieves high throughput, reliability, and regulatory compliance. Developers can extend functionality via evaluators and observe state changes through signals, enabling flexible plugin architectures with enhanced operational capabilities. - -## Appendices - -### Common Database Operations and Examples -- Open and replay: - - Open database and block log, initialize indexes and evaluators, then start block log and rewind undo state. - - Reindex from a specified block number with skip flags to bypass validations. - - **New**: Open from snapshot using `open_from_snapshot()` for rapid initialization. -- Push block: - - Validate block (merkle and size), push to fork database, resolve forks if needed, apply block, persist to block log, emit applied block signal. - - **Enhanced**: In DLT mode, selectively write irreversible blocks to DLT block log with color-coded progress updates every 500 blocks. -- Push transaction: - - Validate transaction size, apply within a pending session, record changes, and emit pending/applied transaction signals. -- Query state: - - Retrieve account, validator, content, escrow, dynamic global properties, validator schedule, and hardfork property objects by name or identifier. -- Fork resolution: - - Compute branches from current head to a candidate fork head, pop blocks until common ancestor, then push new fork blocks. -- **New**: Snapshot operations: - - Load snapshot state via callback during startup with orange/yellow color-coded progress indicators - - Validate snapshot integrity and chain compatibility - - Handle snapshot file lifecycle (renaming, cleanup) -- **New**: Enhanced color-coded logging: - - Green messages for synchronization start (logged once per session via guard variable) - - Yellow messages for synchronization progress every 500 blocks - - Green messages for successful block generation - - Orange messages for snapshot import operations - - Red messages for error conditions -- **New**: Network synchronization logging: - - Info-level logging for sync restart reasons with clearer insights - - Current head block numbers and gap calculations in DLT mode - - Enhanced sync progress notifications with producer information - -**Section sources** -- [database.cpp:206-350](file://libraries/chain/database.cpp#L206-L350) -- [database.cpp:800-925](file://libraries/chain/database.cpp#L800-L925) -- [database.cpp:936-970](file://libraries/chain/database.cpp#L936-L970) -- [database.hpp:136-169](file://libraries/chain/include/graphene/chain/database.hpp#L136-L169) -- [plugin.cpp:364-432](file://plugins/chain/plugin.cpp#L364-L432) -- [snapshot_plugin.cpp:1000-1200](file://plugins/snapshot/plugin.cpp#L1000-L1200) - -### Performance Optimization Techniques -- Tune shared memory growth: Set minimum free memory and increment sizes to avoid frequent resizing. -- Use skip flags during reindexing: Disable signature and authority checks to accelerate replay. -- Monitor and log memory: Periodic logs help detect approaching limits before failures. -- Keep fork cache bounded: Adjust maximum fork size to control memory footprint. -- Batch operations: Group related operations to minimize undo session overhead. -- **New**: Configure DLT mode: Set `_dlt_block_log_max_blocks` to balance storage and performance. -- **New**: Optimize snapshot loading: Use appropriate snapshot files and monitor import performance with color-coded progress indicators. -- **New**: Manage DLT storage: Regularly monitor DLT block log size and adjust retention policies. -- **New**: Enhanced logging optimization: Color-coded logging with guard variables and increased frequency provides better operational benefits with minimal overhead. -- **New**: Info-level logging optimization: Using ilog for sync restart reasons improves visibility with minimal performance impact. -- **New**: Network synchronization optimization: Enhanced logging with current head block numbers and gap calculations provides better monitoring accuracy. - -**Section sources** -- [database.cpp:368-430](file://libraries/chain/database.cpp#L368-L430) -- [fork_database.cpp:92-124](file://libraries/chain/fork_database.cpp#L92-L124) -- [database.hpp:62-64](file://libraries/chain/include/graphene/chain/database.hpp#L62-L64) -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -### DLT Mode Configuration -**New Section** Configuration and usage guidelines for DLT mode - -Configuration options: -- `--dlt-block-log-max-blocks`: Number of recent blocks to keep in rolling DLT block log (default: 100000) -- `_dlt_mode`: Internal flag indicating DLT operation mode -- `_dlt_block_log`: Separate block log instance for DLT operations - -Usage scenarios: -- Compliance reporting with selective block retention -- Archival purposes with configurable retention periods -- Reduced storage requirements for non-validating nodes -- Regulatory compliance with immutable block records - -**Section sources** -- [plugin.cpp:234-236](file://plugins/chain/plugin.cpp#L234-L236) -- [database.hpp:57-64](file://libraries/chain/include/graphene/chain/database.hpp#L57-L64) -- [dlt_block_log.cpp:161-230](file://libraries/chain/dlt_block_log.cpp#L161-L230) - -### Enhanced Color-Coded Logging Reference -**New Section** Comprehensive reference for enhanced color-coded logging system - -#### ANSI Color Codes Used -- **`\033[92m`** (Green): Successful operations, block generation confirmations, and synchronization start messages -- **`\033[33m`** (Orange): Snapshot import operations and P2P transfer progress -- **`\033[93m`** (Yellow): Synchronization progress, warnings, and informational messages (every 500 blocks) -- **`\033[96m`** (Cyan): Error conditions and critical failures -- **`\033[0m`** (Reset): Reset color formatting - -#### Enhanced Log Message Categories -- **Synchronization Start**: Green messages for sync start (logged once per session via `sync_start_logged` guard) -- **Synchronization Progress**: Yellow messages for block acceptance and sync progress every 500 blocks -- **Snapshot Operations**: Orange messages for import/export operations -- **Block Generation**: Green messages for successful block production -- **Error Conditions**: Cyan messages for critical failures -- **Debug Information**: Default color for low-level operational details -- **Network Sync**: Info-level messages for sync restarts and peer interactions with current head block numbers - -#### Guard Variables and Frequency Control -- **`sync_start_logged`**: Boolean guard variable to prevent duplicate sync start messages -- **Logging Frequency**: Progress logging occurs every 500 blocks instead of every 10,000 blocks for better monitoring -- **Terminal Compatibility**: ANSI color codes work in Unix/Linux terminals with proper color support -- **Windows Compatibility**: Windows terminals may require ANSI emulation for full color support -- **Fallback Behavior**: Non-color terminals automatically fall back to plain text output - -**Section sources** -- [plugin.cpp:58-113](file://plugins/chain/plugin.cpp#L58-L113) -- [snapshot_plugin.cpp:50-53](file://plugins/snapshot/plugin.cpp#L50-L53) -- [console_appender.cpp:132-154](file://thirdparty/fc/src/log/console_appender.cpp#L132-L154) -- [node.cpp:3446-3456](file://libraries/network/node.cpp#L3446-L3456) -- [validator.cpp:286](file://plugins/validator/validator.cpp#L286) - -### Network Synchronization Logging Reference -**New Section** Enhanced logging improvements for network synchronization - -#### Info-Level Logging Improvements -- **Sync Restart Reasons**: Now use ilog instead of dlog for better visibility -- **Peer Synchronization**: Enhanced logging for peer synchronization restarts -- **Block Acceptance**: Yellow progress messages with block numbers and producer information -- **Gap Calculations**: Current head block numbers and gap calculations in DLT mode - -#### Logging Categories -- **Sync Start**: Green messages with block numbers and head information -- **Sync Progress**: Yellow messages every 500 blocks with timestamp and producer -- **Sync End**: Reset messages when normal blocks are received -- **Network Events**: Info-level messages for sync restarts and peer interactions with enhanced detail - -**Section sources** -- [node.cpp:2428-2444](file://libraries/network/node.cpp#L2428-L2444) -- [node.cpp:3276-3280](file://libraries/network/node.cpp#L3276-L3280) -- [database.cpp:5295-5303](file://libraries/chain/database.cpp#L5295-L5303) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/DLT Rolling Block Log.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/DLT Rolling Block Log.md deleted file mode 100644 index 7917b065fb..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/DLT Rolling Block Log.md +++ /dev/null @@ -1,1572 +0,0 @@ -# DLT Rolling Block Log - - -**Referenced Files in This Document** -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [snapshot_plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) - - -## Update Summary -**Changes Made** -- Enhanced Windows compatibility with separate logical file size tracking to address memory-mapped file size drift after thousands of resize operations -- Implemented sophisticated mapping verification and healing mechanisms through verify_mapping() method -- Added comprehensive diagnostic capabilities including verify_continuity() and resize_count() methods -- Enhanced automatic gap recovery system with intelligent gap detection and DLT block log reset functionality -- Integrated periodic diagnostic monitoring into P2P stats task for DLT mode nodes -- Added signal-based integration with snapshot plugin for automatic fresh snapshot creation -- Enhanced gap logging and monitoring with automatic warning suppression through _dlt_gap_logged state management -- Added new reset() method for safe log clearing and reinitialization -- Enhanced diagnostic monitoring with comprehensive gap detection and integrity verification - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project_structure) -3. [Core Components](#core_components) -4. [Architecture Overview](#architecture_overview) -5. [Detailed Component Analysis](#detailed_component_analysis) -6. [Windows Compatibility and Memory Mapping Fixes](#windows-compatibility-and-memory-mapping-fixes) -7. [Crash Recovery and Atomic Operations](#crash-recovery-and-atomic-operations) -8. [Selective Retention Policies](#selective-retention-policies) -9. [Automatic Pruning Capabilities](#automatic-pruning-capabilities) -10. [Enhanced Blockchain Recovery System](#enhanced-blockchain-recovery-system) -11. [Configuration Management](#configuration-management) -12. [Dependency Analysis](#dependency-analysis) -13. [Performance Considerations](#performance-considerations) -14. [Enhanced Error Handling and Fallback Mechanisms](#enhanced-error-handling-and-fallback-mechanisms) -15. [DLT Mode Fork Database Seeding](#dlt-mode-fork-database-seeding) -16. [Enhanced Block Availability Checking](#enhanced-block-availability-checking) -17. [Stalled Sync Detection for DLT Nodes](#stalled-sync-detection-for-dlt-nodes) -18. [Enhanced Gap Handling During Synchronization](#enhanced-gap-handling-during-synchronization) -19. [DLT Block Log Accessibility Enhancement](#dlt-block-log-accessibility-enhancement) -20. [Comprehensive DLT Block Range Management System](#comprehensive-dlt-block-range-management-system) -21. [Enhanced P2P Synchronization Capabilities](#enhanced-p2p-synchronization-capabilities) -22. [Multi-Layered Fallback Mechanisms](#multi-layered-fallback-mechanisms) -23. [Enhanced DLT Block Log Reset Functionality](#enhanced-dlt-block-log-reset-functionality) -24. [Automatic Gap Recovery System](#automatic-gap-recovery-system) -25. [Enhanced Diagnostic and Monitoring Capabilities](#enhanced-diagnostic-and-monitoring-capabilities) -26. [Troubleshooting Guide](#troubleshooting-guide) -27. [Conclusion](#conclusion) - -## Introduction -This document explains the comprehensive DLT (Data Ledger Technology) Rolling Block Log implementation used by VIZ blockchain nodes to maintain a sliding window of recent irreversible blocks with selective retention policies and automatic pruning capabilities. The DLT mode provides advanced support for snapshot-based nodes, enabling efficient serving of recent blocks to P2P peers while maintaining configurable retention windows and automated cleanup mechanisms. Recent enhancements include critical Windows compatibility improvements with separate logical file size tracking, sophisticated mapping verification and healing mechanisms, enhanced diagnostic capabilities, and strengthened validation logic throughout the implementation. The latest architectural improvements introduce comprehensive Windows compatibility fixes, methods to synchronize and verify logical sizes against actual mapped sizes, healing mechanisms for file size mismatches, periodic mapping verification, improved block read/append logic using logical sizes with correctness assertions, and enhanced diagnostic capabilities through `verify_mapping()`, `verify_continuity()`, and `resize_count()` methods. - -## Project Structure -The DLT rolling block log is implemented as a standalone component with comprehensive integration into the main database system. It operates alongside the traditional block log while providing specialized functionality for snapshot-based ("DLT") nodes with selective retention and automatic pruning capabilities. - -```mermaid -graph TB -subgraph "Chain Layer" -DLT["dlt_block_log.hpp/.cpp"] -BL["block_log.cpp"] -DB["database.cpp"] -FD["fork_database.cpp"] -DH["database.hpp"] -END -subgraph "Plugins" -CP["plugins/chain/plugin.cpp"] -SP["plugins/snapshot/plugin.cpp"] -PP["plugins/p2p/p2p_plugin.cpp"] -END -CP --> DB -SP --> DB -PP --> DB -DB --> DLT -DB --> BL -DB --> FD -DLT -.-> BL -FD -.-> DB -CP --> DH -SP --> DH -PP --> DH -``` - -**Diagram sources** -- [dlt_block_log.hpp:1-89](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L89) -- [dlt_block_log.cpp:1-582](file://libraries/chain/dlt_block_log.cpp#L1-L582) -- [block_log.cpp:1-302](file://libraries/chain/block_log.cpp#L1-L302) -- [database.cpp:220-271](file://libraries/chain/database.cpp#L220-L271) -- [fork_database.cpp:1-258](file://libraries/chain/fork_database.cpp#L1-L258) -- [plugin.cpp:320-330](file://plugins/chain/plugin.cpp#L320-L330) -- [snapshot_plugin.cpp:1960-2039](file://plugins/snapshot/plugin.cpp#L1960-L2039) -- [p2p_plugin.cpp:255-286](file://plugins/p2p/p2p_plugin.cpp#L255-L286) -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) - -**Section sources** -- [dlt_block_log.hpp:1-89](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L89) -- [dlt_block_log.cpp:1-582](file://libraries/chain/dlt_block_log.cpp#L1-L582) -- [block_log.cpp:1-302](file://libraries/chain/block_log.cpp#L1-L302) -- [database.cpp:220-271](file://libraries/chain/database.cpp#L220-L271) -- [fork_database.cpp:1-258](file://libraries/chain/fork_database.cpp#L1-L258) -- [plugin.cpp:320-330](file://plugins/chain/plugin.cpp#L320-L330) -- [snapshot_plugin.cpp:1960-2039](file://plugins/snapshot/plugin.cpp#L1960-L2039) -- [p2p_plugin.cpp:255-286](file://plugins/p2p/p2p_plugin.cpp#L255-L286) -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) - -## Core Components -- **DLT Rolling Block Log API**: Provides comprehensive methods for opening/closing, appending blocks, selective reading by block number, querying head/start/end indices, intelligent truncation with retention policies, and the new reset() method for safe log clearing and reinitialization. -- **Windows-Compatible Memory-Mapped File System**: Implements sophisticated logical file size tracking separate from mapped_file.size() to handle Windows memory-mapped file size drift after thousands of resize() cycles, with automatic healing mechanisms and periodic verification. -- **Advanced Memory-Safe Implementation**: Manages sophisticated memory-mapped files for data and offset-aware index storage using std::memcpy operations instead of unsafe pointer casts, maintains head state with automatic validation, reconstructs indexes when inconsistencies are detected, and performs safe truncation with temporary files and atomic operations. -- **Integrated Database System**: Seamlessly opens both DLT rolling block log and primary block log during normal and snapshot modes, implements fallback block retrieval when primary block log is empty, coordinates DLT mode detection and operation with enhanced error handling, and includes automatic fork database seeding functionality. -- **Enhanced Fork Database Integration**: Provides sophisticated fork database management with automatic seeding from DLT block log, improved block availability checking logic, and enhanced P2P fallback mechanisms. -- **Comprehensive Chain Plugin Configuration**: Exposes runtime options for configuring maximum blocks to retain, selective retention policies, and automatic pruning thresholds with flexible parameter management. -- **Enhanced Snapshot Plugin Integration**: Provides improved block verification, checksum validation, and seamless transition to DLT mode after snapshot import with enhanced error handling and automatic snapshot creation upon DLT block log reset. -- **Enhanced P2P Fallback Mechanisms**: Implements graceful fallback from primary block log to DLT rolling block log with detailed error reporting and logging for DLT mode scenarios. -- **Stalled Sync Detection**: Implements automatic detection and recovery from stalled P2P sync for DLT nodes, with configurable timeout settings and automatic snapshot reload capabilities. -- **Enhanced Gap Handling**: Provides sophisticated gap management during synchronization between fork database and DLT block log, with automatic seeding, intelligent gap detection, and comprehensive recovery mechanisms including the new reset() method. -- **Enhanced Blockchain Recovery System**: Implements comprehensive recovery mechanisms including DLT block log replay functionality, crash recovery with atomic file operations, and enhanced error handling for corrupted states. -- **Enhanced DLT Block Log Accessibility**: Provides both const and non-const accessors for DLT block log functionality, enabling external components to modify DLT block log properties during runtime operations while maintaining read-only access for general use. -- **Comprehensive DLT Block Range Management System**: Implements precise block availability tracking with earliest_available_block_num() method, enabling sophisticated P2P synchronization with multi-layered fallback mechanisms and enhanced peer interaction handling. -- **Enhanced P2P Synchronization Capabilities**: Provides comprehensive block range validation, advertising prevention, and detailed error reporting for DLT mode operations with improved peer interaction handling. -- **Multi-Layered Fallback Mechanisms**: Implements sophisticated block retrieval chain with fork database, primary block log, and DLT block log fallback layers, providing robust error handling and graceful degradation. -- **Enhanced DLT Block Log Reset Functionality**: Provides safe log clearing and reinitialization through the new reset() method, enabling automatic recovery from synchronization gaps and improved operational flexibility. -- **Automatic Gap Recovery System**: Implements intelligent gap detection and automatic recovery mechanisms that monitor synchronization gaps between DLT block log and fork database, automatically resetting the DLT block log when gaps are detected and suppressing redundant warnings. -- **Enhanced Diagnostic and Monitoring System**: Provides comprehensive diagnostic capabilities through `verify_mapping()` method for periodic mapping consistency verification and `resize_count()` method for tracking resize operations, with detailed logging and healing mechanisms. -- **Enhanced Gap Detection and Recovery**: Provides sophisticated gap detection and automatic recovery mechanisms that monitor synchronization gaps between DLT block log and fork database, automatically resetting the DLT block log when gaps are detected and providing comprehensive gap logging and monitoring capabilities. - -**Enhanced Key Capabilities**: -- Offset-aware index layout supporting arbitrary start block numbers with intelligent retention policies -- Append-only storage with position checks ensuring sequential integrity and selective block management -- Automatic index reconstruction with conflict resolution and selective retention enforcement -- Safe truncation with temporary files, atomic swapping, and intelligent pruning based on configured limits -- Comprehensive DLT mode support with automatic fork database seeding and fallback mechanisms -- Enhanced block identification and verification during snapshot operations -- Improved error handling and validation for DLT mode operations -- Graceful fallback mechanisms with detailed logging for P2P block serving operations -- Strengthened block validation logic with comprehensive error reporting and synchronization handling -- **Windows Compatibility**: Separate logical file size tracking to handle memory-mapped file size drift after thousands of resize operations -- **Mapping Verification**: Periodic verification of logical vs. mapped file sizes with automatic healing mechanisms -- **Diagnostic Tracking**: Comprehensive resize operation counting for monitoring and debugging -- **Critical Memory Safety Improvements**: Replaced all unsafe uint64_t pointer casts with std::memcpy operations for cross-platform compatibility -- **Comprehensive Crash Recovery**: Implemented .bak file restoration mechanisms for atomic file operations during truncation -- **Enhanced Cross-Platform Compatibility**: Standardized file operations and memory-mapped file handling across platforms -- **Automatic Fork Database Seeding**: Enhanced DLT mode fork database seeding functionality that automatically seeds fork database from dlt_block_log when chain starts from fresh snapshot import -- **Improved Block Availability Checking**: Enhanced block availability checking logic with better DLT mode support and error handling -- **Stalled Sync Detection**: Automatic detection and recovery from stalled P2P sync with configurable timeouts and snapshot reload capabilities -- **Enhanced Gap Management**: Sophisticated gap handling during synchronization with automatic seeding, intelligent detection, and comprehensive recovery mechanisms -- **Enhanced Blockchain Recovery System**: New reindex_from_dlt method provides core functionality for rebuilding blockchain state from DLT rolling block log after snapshot import -- **Enhanced DLT Block Log Accessibility**: Both const and non-const accessors enable external components to modify DLT block log properties during runtime while maintaining read-only access for general use -- **Comprehensive DLT Block Range Management**: Precise block availability tracking with earliest_available_block_num() method for improved P2P synchronization -- **Enhanced P2P Synchronization**: Multi-layered fallback mechanisms with detailed error reporting and logging for DLT mode scenarios -- **Robust Fallback Chain**: Sophisticated block retrieval chain with fork database, primary block log, and DLT block log fallback layers -- **Enhanced DLT Block Log Reset**: Safe log clearing and reinitialization through reset() method with comprehensive cleanup of temporary and backup files -- **Automatic Gap Recovery**: Intelligent gap detection and automatic recovery mechanisms with automatic DLT block log reset and signal emission to snapshot plugin -- **Enhanced Gap Detection**: New verify_continuity() method provides comprehensive gap detection and integrity verification for DLT block log -- **Automatic Gap Recovery**: Enhanced gap detection and automatic recovery system with automatic DLT block log reset and signal emission to snapshot plugin -- **Enhanced P2P Integration**: Periodic integrity scanning using verify_continuity() method with comprehensive gap reporting and logging - -**Section sources** -- [dlt_block_log.hpp:35-89](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L89) -- [dlt_block_log.cpp:18-278](file://libraries/chain/dlt_block_log.cpp#L18-L278) -- [database.cpp:230-231](file://libraries/chain/database.cpp#L230-L231) -- [fork_database.cpp:24-28](file://libraries/chain/fork_database.cpp#L24-L28) -- [plugin.cpp:327-329](file://plugins/chain/plugin.cpp#L327-L329) -- [snapshot_plugin.cpp:1968-1970](file://plugins/snapshot/plugin.cpp#L1968-L1970) -- [p2p_plugin.cpp:265-272](file://plugins/p2p/p2p_plugin.cpp#L265-L272) -- [snapshot_plugin.cpp:1414-1500](file://plugins/snapshot/plugin.cpp#L1414-L1500) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) -- [database.cpp:835-858](file://libraries/chain/database.cpp#L835-L858) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -## Architecture Overview -The DLT rolling block log operates in conjunction with the primary block log, providing comprehensive support for snapshot-based nodes with selective retention policies and automatic pruning. During normal operation, the database opens both logs and validates them. In DLT mode (after snapshot import), the primary block log remains empty while the database holds state; the DLT rolling block log serves as a fallback with intelligent retention management and enhanced block verification. The P2P layer now includes improved error handling with graceful fallback mechanisms and detailed logging for DLT mode scenarios. The enhanced accessibility model allows external components to modify DLT block log properties during runtime operations while maintaining read-only access for general use. The comprehensive DLT block range management system provides precise block availability tracking with the earliest_available_block_num() method, enabling sophisticated P2P synchronization with multi-layered fallback mechanisms. The new automatic gap recovery system provides intelligent gap detection and automatic recovery mechanisms that monitor synchronization gaps and automatically reset the DLT block log when necessary. The enhanced diagnostic system provides comprehensive monitoring through periodic mapping verification and resize operation tracking. - -```mermaid -sequenceDiagram -participant App as "Application" -participant Chain as "Chain Plugin" -participant DB as "Database" -participant SP as "Snapshot Plugin" -participant PP as "P2P Plugin" -participant DLT as "DLT Block Log" -participant BL as "Block Log" -participant FD as "Fork Database" -App->>Chain : Start node -Chain->>DB : open(data_dir, ...) -DB->>BL : open("block_log") -DB->>DLT : open("dlt_block_log") -alt Primary block log has head -DB->>DB : validate against chain state -else Empty block log (DLT mode) -DB->>DB : set_dlt_mode=true -DB->>DB : skip block log validation -DB->>FD : seed from dlt_block_log head -end -App->>DB : get_dlt_block_log() (non-const) -DB->>DLT : modify properties during runtime -App->>DB : get_dlt_block_log() (const) -DB->>DLT : read-only access for general use -App->>DB : fetch_block_by_number(n) -DB->>BL : read_block_by_num(n) -alt Found in primary log -BL-->>DB : block -else Not found -DB->>DLT : read_block_by_num(n) -alt Found in DLT log -DLT-->>DB : block (fallback) -else Not found -DB->>DB : check DLT mode -alt In DLT mode -DB->>PP : serve via P2P fallback -PP->>PP : log graceful fallback -PP-->>DB : key_not_found_exception -else Not in DLT mode -DB-->>App : block not found -end -end -DB-->>App : block -``` - -**Diagram sources** -- [database.cpp:230-268](file://libraries/chain/database.cpp#L230-L268) -- [database.cpp:560-627](file://libraries/chain/database.cpp#L560-L627) -- [block_log.cpp:238-241](file://libraries/chain/block_log.cpp#L238-241) -- [dlt_block_log.cpp:313-328](file://libraries/chain/dlt_block_log.cpp#L313-L328) -- [snapshot_plugin.cpp:1968-1970](file://plugins/snapshot/plugin.cpp#L1968-L1970) -- [p2p_plugin.cpp:259-286](file://plugins/p2p/p2p_plugin.cpp#L259-L286) -- [fork_database.cpp:24-28](file://libraries/chain/fork_database.cpp#L24-L28) -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) - -## Detailed Component Analysis - -### DLT Rolling Block Log API -The public interface defines comprehensive lifecycle, append, read, and maintenance operations with thread-safe access via read/write locks, supporting selective retention policies and automatic pruning capabilities. The new reset() method provides safe log clearing and reinitialization functionality, while the new verify_mapping(), verify_continuity(), and resize_count() methods provide enhanced diagnostic capabilities. - -```mermaid -classDiagram -class dlt_block_log { -+open(file) -+close() -+is_open() bool -+append(block) uint64_t -+flush() -+read_block_by_num(block_num) optional~signed_block~ -+head() optional~signed_block~ -+start_block_num() uint32_t -+head_block_num() uint32_t -+num_blocks() uint32_t -+truncate_before(new_start) -+reset() -+verify_mapping() bool -+verify_continuity() vector~uint32_t~ -+resize_count() uint64_t -} -``` - -**Diagram sources** -- [dlt_block_log.hpp:35-89](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L89) - -**Section sources** -- [dlt_block_log.hpp:35-89](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L89) - -### Windows-Compatible Memory-Mapped File System -The implementation now includes sophisticated Windows compatibility fixes through separate logical file size tracking. The system maintains independent logical sizes for block and index files, tracking them separately from mapped_file.size() to handle Windows memory-mapped file size drift after thousands of resize() cycles. This prevents get_block_pos() from rejecting valid block numbers due to stale mapping metadata. - -**Key Windows Compatibility Features**: -- Separate logical file size tracking for block and index files -- Independent tracking of _logical_block_size and _logical_index_size -- Automatic healing mechanisms for stale mapping detection -- Periodic verification through verify_mapping() method -- Enhanced read_block() and get_block_pos() logic using logical sizes -- Comprehensive resize operation counting for diagnostic purposes - -**Enhanced Memory Mapping Architecture**: -- Logical sizes tracked independently of mapped_file.size() -- After thousands of resize() cycles, mapped_file.size() can return stale values -- By tracking logical sizes ourselves, we avoid this Windows-specific bug -- Enhanced get_block_pos() uses logical_index_size() instead of mapped_file.size() -- Improved read_block() validates against logical_block_size() for correctness - -**Section sources** -- [dlt_block_log.cpp:31-38](file://libraries/chain/dlt_block_log.cpp#L31-L38) -- [dlt_block_log.cpp:59-66](file://libraries/chain/dlt_block_log.cpp#L59-L66) -- [dlt_block_log.cpp:119-136](file://libraries/chain/dlt_block_log.cpp#L119-L136) -- [dlt_block_log.cpp:138-155](file://libraries/chain/dlt_block_log.cpp#L138-L155) - -### Advanced Memory-Safe Implementation Details -The implementation manages sophisticated memory-mapped files with comprehensive error handling, intelligent validation, and automatic recovery mechanisms. It enforces strict position checks using std::memcpy operations instead of unsafe pointer casts, implements selective retention policies, and provides automatic pruning capabilities. - -**Key Advanced Behaviors**: -- Sophisticated memory-mapped files for zero-copy reads with comprehensive error handling using std::memcpy -- Offset-aware index with intelligent header management and selective entry tracking using safe memory operations -- Strict position validation during append operations with conflict resolution using FC_ASSERT -- Intelligent index reconstruction with selective retention enforcement using atomic memory operations -- Safe truncation using temporary files with atomic swap and comprehensive validation -- Automatic pruning based on configured retention limits with selective block management -- **Enhanced Reset Functionality**: Safe log clearing and reinitialization with comprehensive cleanup of temporary and backup files -- **Windows Compatibility**: Separate logical file size tracking to handle memory-mapped file size drift -- **Mapping Verification**: Periodic consistency checking with automatic healing mechanisms - -**Updated** Enhanced memory safety through std::memcpy operations replacing unsafe uint64_t pointer casts throughout the implementation - -```mermaid -flowchart TD -Start([Open DLT Log]) --> CheckFiles["Check block/index existence"] -CheckFiles --> HasBlocks{"Has block records?"} -HasBlocks --> |Yes| ReadHead["Read head block"] -ReadHead --> HasIndex{"Has index records?"} -HasBlocks --> |No| WipeIndex{"Index exists?"} -WipeIndex --> |Yes| ReconstructIndex["Intelligent reconstruction"] -WipeIndex --> |No| Ready["Ready"] -HasIndex --> |Yes| CompareHeads["Compare last positions"] -CompareHeads --> Match{"Positions match?"} -Match --> |Yes| Ready -Match --> |No| ReconstructIndex -HasIndex --> |No| ReconstructIndex -ReconstructIndex --> ApplyRetention["Apply retention policies"] -ApplyRetention --> Ready -``` - -**Diagram sources** -- [dlt_block_log.cpp:161-209](file://libraries/chain/dlt_block_log.cpp#L161-L209) -- [dlt_block_log.cpp:125-159](file://libraries/chain/dlt_block_log.cpp#L125-L159) - -**Section sources** -- [dlt_block_log.cpp:18-278](file://libraries/chain/dlt_block_log.cpp#L18-L278) - -### Enhanced Append Operation Flow -The append operation validates sequential positioning with intelligent conflict resolution, writes block data with trailing position markers using std::memcpy, updates the index with selective retention enforcement, and maintains head state with automatic pruning triggers. The operation now uses logical sizes for validation and tracking. - -**Updated** Memory-safe append operations using std::memcpy for all data transfers, with enhanced validation using logical sizes - -```mermaid -sequenceDiagram -participant Client as "Caller" -participant DLT as "dlt_block_log_impl" -participant BF as "Block File" -participant IF as "Index File" -Client->>DLT : append(block) -DLT->>IF : resize to expected index size -DLT->>BF : resize to current file size + packed block + 8 -DLT->>BF : write packed block + trailing position (std : : memcpy) -DLT->>IF : write index entry (std : : memcpy) -DLT->>DLT : update head/head_id -DLT->>DLT : check retention limits -alt Exceeds 2x limit -DLT->>DLT : trigger automatic pruning -end -DLT-->>Client : block position -``` - -**Diagram sources** -- [dlt_block_log.cpp:211-268](file://libraries/chain/dlt_block_log.cpp#L211-L268) - -**Section sources** -- [dlt_block_log.cpp:211-268](file://libraries/chain/dlt_block_log.cpp#L211-L268) - -### Intelligent Truncation Process -Truncation creates temporary files containing only retained blocks with selective retention enforcement, then atomically replaces the original files with comprehensive validation and automatic cleanup using .bak files for crash recovery. - -**Updated** Enhanced truncation with comprehensive crash recovery using .bak file restoration - -```mermaid -flowchart TD -TStart([Truncate Before]) --> Validate["Validate range and open state"] -Validate --> CheckRetention["Check retention policies"] -CheckRetention --> BuildTemp["Build temp files with retained blocks"] -BuildTemp --> CloseOrig["Close original files"] -CloseOrig --> Swap["Swap temp -> original (.bak backup)"] -Swap --> Reopen["Reopen with new state"] -Reopen --> Cleanup["Cleanup temporary files"] -Cleanup --> TEnd([Complete]) -``` - -**Diagram sources** -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -**Section sources** -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) - -### Enhanced Reset Functionality -The new reset() method provides safe log clearing and reinitialization capabilities. It closes the current log, deletes all data and index files, removes stale temporary and backup files, then reopens the log as empty. This functionality is crucial for automatic gap recovery and synchronization gap management. - -**Enhanced Reset Features**: -- Safe log clearing with comprehensive file cleanup including temporary and backup files -- Atomic file deletion and recreation process with proper error handling -- Preservation of file path and configuration while resetting internal state -- Comprehensive logging with old range information for debugging and monitoring -- Cleanup of .tmp and .bak files that may be left from interrupted operations - -**Section sources** -- [dlt_block_log.cpp:523-543](file://libraries/chain/dlt_block_log.cpp#L523-L543) - -### Enhanced Gap Detection and Recovery System -The new verify_continuity() method provides comprehensive gap detection and integrity verification for the DLT block log. This method walks the entire block range and identifies missing or unreadable blocks, returning a vector of block numbers that need attention. The database now includes sophisticated gap detection between DLT block log and fork database, with automatic recovery mechanisms that reset the DLT block log when gaps are detected. - -**Enhanced Gap Detection Features**: -- `verify_continuity()` method: Walks entire block range and identifies missing/unreadable blocks -- Returns vector of block numbers that are missing or unreadable for comprehensive gap reporting -- O(N) complexity where N = num_blocks, used sparingly (e.g., stats task) -- Integration with automatic gap recovery system for seamless gap management -- Comprehensive gap logging with automatic warning suppression to prevent redundant messages - -**Enhanced Gap Recovery System Features**: -- Automatic detection of gaps between dlt_end and fork_db_start positions -- Intelligent gap detection with configurable thresholds and automatic DLT block log reset -- Seamless continuation of block synchronization after gap recovery -- Integration with snapshot plugin for automatic fresh snapshot creation -- Enhanced logging with detailed gap information and recovery actions -- Prevention of repeated gap recovery operations for the same gap condition -- **Enhanced State Management**: Automatic suppression of redundant gap warnings through _dlt_gap_logged flag - -**Enhanced Gap Recovery Process**: -- Detection of gap between dlt_end and fork_db_start positions -- Identification of earliest available block in fork database -- Automatic reset() method invocation to clear DLT block log -- Sequential writing of available blocks from fork database -- Signal emission to snapshot plugin for fresh snapshot creation -- Continued gap monitoring and recovery as needed -- **Enhanced Warning Suppression**: Automatic logging state management to prevent redundant gap warnings - -```mermaid -flowchart TD -GapDetection["Gap Detection"] --> CheckGap{"Gap > Threshold?"} -CheckGap --> |No| ContinueSync["Continue Normal Sync"] -CheckGap --> |Yes| FindForkStart["Find Earliest Fork Block"] -FindForkStart --> ResetDLT["Call reset() method"] -ResetDLT --> WriteBlocks["Write Available Blocks"] -WriteBlocks --> EmitSignal["Emit dlt_block_log_was_reset"] -EmitSignal --> CreateSnapshot["Create Fresh Snapshot"] -CreateSnapshot --> ContinueSync -ContinueSync -``` - -**Diagram sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -**Section sources** -- [dlt_block_log.cpp:576-602](file://libraries/chain/dlt_block_log.cpp#L576-L602) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -### Enhanced Diagnostic and Monitoring Capabilities -The new diagnostic system provides comprehensive monitoring through two key methods: `verify_mapping()` for periodic mapping consistency verification and `resize_count()` for tracking resize operations. These methods enable proactive detection and healing of Windows memory-mapped file size drift issues. - -**Enhanced Diagnostic Features**: -- `verify_mapping()` method: Checks logical vs. mapped file size consistency and heals stale mappings -- `verify_continuity()` method: Walks entire block range and reports gaps for integrity verification -- `resize_count()` method: Tracks number of resize operations since log open for diagnostic purposes -- Periodic verification integrated into P2P stats task for DLT mode nodes -- Comprehensive logging with detailed information about mapping status and healing actions -- Automatic reopening of files when stale mapping is detected - -**Enhanced Mapping Verification Process**: -- Compares mapped_file.size() with tracked _logical_block_size and _logical_index_size -- Detects stale mapping after thousands of resize() cycles -- Automatically closes and reopens files to refresh mapping -- Logs detailed information about detected inconsistencies and healing actions -- Prevents get_block_pos() from rejecting valid block numbers due to stale metadata - -**Enhanced Gap Integrity Scanning**: -- Periodic verification of DLT block log integrity through verify_continuity() method -- Comprehensive gap reporting with detailed block number information -- Integration with P2P stats task for automatic gap detection and logging -- Enhanced error reporting with gap count and missing block information -- Automatic gap suppression to prevent redundant logging - -**Section sources** -- [dlt_block_log.cpp:545-579](file://libraries/chain/dlt_block_log.cpp#L545-L579) -- [dlt_block_log.cpp:576-602](file://libraries/chain/dlt_block_log.cpp#L576-L602) -- [p2p_plugin.cpp:761-765](file://plugins/p2p/p2p_plugin.cpp#L761-L765) - -### Integrated Database Operations -The database seamlessly integrates DLT block log alongside block_log.cpp, coordinating fallback retrieval, DLT mode detection, selective retention enforcement, automatic pruning with comprehensive state management and enhanced error handling. - -```mermaid -sequenceDiagram -participant DB as "Database" -participant BL as "Block Log" -participant DLT as "DLT Block Log" -DB->>BL : open("block_log") -DB->>DLT : open("dlt_block_log") -alt Head block present in BL -DB->>DB : validate chain state -else Empty BL (DLT mode) -DB->>DB : set_dlt_mode=true -DB->>DB : skip validation -DB->>DB : seed fork_db from dlt_block_log -end -DB->>DLT : read_block_by_num(n) (fallback) -DB->>DB : check retention limits -alt Exceeds 2x limit -DB->>DLT : trigger automatic pruning -end -``` - -**Diagram sources** -- [database.cpp:230-268](file://libraries/chain/database.cpp#L230-L268) -- [database.cpp:560-627](file://libraries/chain/database.cpp#L560-L627) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -**Section sources** -- [database.cpp:230-268](file://libraries/chain/database.cpp#L230-L268) -- [database.cpp:560-627](file://libraries/chain/database.cpp#L560-L627) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -### Enhanced Snapshot Plugin Integration -The snapshot plugin provides comprehensive integration with DLT mode operations, including improved block verification, checksum validation, and seamless transition to DLT mode after snapshot import with enhanced error handling. The plugin now listens for the dlt_block_log_was_reset signal to automatically create fresh snapshots for other DLT nodes. - -**Enhanced Snapshot Operations**: -- Improved block identification and verification during snapshot loading -- Enhanced checksum validation with comprehensive error reporting -- Seamless transition to DLT mode with proper state initialization -- Better integration with database layer for DLT mode operations -- Enhanced fallback mechanisms for block verification and serving -- Stalled sync detection for automatic recovery from stalled P2P sync -- Automatic snapshot reload capabilities with DLT mode support -- **Enhanced Signal Integration**: Listens for dlt_block_log_was_reset signal to create fresh snapshots for other DLT nodes - -**Section sources** -- [snapshot_plugin.cpp:1968-1970](file://plugins/snapshot/plugin.cpp#L1968-L1970) -- [snapshot_plugin.cpp:942-1054](file://plugins/snapshot/plugin.cpp#L942-L1054) -- [snapshot_plugin.cpp:1414-1500](file://plugins/snapshot/plugin.cpp#L1414-L1500) -- [snapshot_plugin.cpp:2790-2791](file://plugins/snapshot/plugin.cpp#L2790-L2791) -- [snapshot_plugin.cpp:3254](file://plugins/snapshot/plugin.cpp#L3254) - -### Enhanced Blockchain Recovery System -The new enhanced blockchain recovery system provides comprehensive crash recovery capabilities through DLT block log replay functionality. The reindex_from_dlt method enables rebuilding blockchain state from DLT rolling block log after snapshot import, with enhanced error handling, progress tracking, and comprehensive logging. - -**Key Recovery Features**: -- DLT block log replay functionality for crash recovery scenarios with progress tracking -- Automatic DLT mode activation during recovery operations with enhanced validation -- Enhanced fork database seeding with proper block validation and P2P synchronization -- Comprehensive error handling with detailed logging and graceful degradation mechanisms -- Selective block replay with progress tracking and memory management optimization -- Atomic operation support with temporary file management for data integrity -- Enhanced logging with percentage completion and memory usage reporting -- Graceful handling of interrupted recovery operations with automatic cleanup - -**Section sources** -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [plugin.cpp:542-555](file://plugins/chain/plugin.cpp#L542-L555) - -## Windows Compatibility and Memory Mapping Fixes - -### Separate Logical File Size Tracking -The DLT block log implementation now includes sophisticated Windows compatibility fixes through separate logical file size tracking. This addresses a critical issue where Windows memory-mapped file size can become stale after thousands of resize() cycles, causing get_block_pos() to reject valid block numbers. - -**Windows Compatibility Features**: -- Separate tracking of _logical_block_size and _logical_index_size independent of mapped_file.size() -- Independent file size validation using logical sizes instead of mapped_file.size() -- Automatic healing mechanisms for stale mapping detection and recovery -- Enhanced get_block_pos() logic that uses logical_index_size() for validation -- Improved read_block() validation against logical_block_size() for correctness - -**Enhanced Memory Mapping Architecture**: -- Logical sizes tracked separately from mapped_file.size() to handle Windows drift -- After thousands of resize() cycles, mapped_file.size() can return stale values -- By tracking logical sizes ourselves, we avoid Windows-specific memory-mapped file size bugs -- Enhanced validation logic prevents rejection of valid block numbers due to stale metadata - -**Section sources** -- [dlt_block_log.cpp:31-38](file://libraries/chain/dlt_block_log.cpp#L31-L38) -- [dlt_block_log.cpp:59-66](file://libraries/chain/dlt_block_log.cpp#L59-L66) -- [dlt_block_log.cpp:119-136](file://libraries/chain/dlt_block_log.cpp#L119-L136) -- [dlt_block_log.cpp:138-155](file://libraries/chain/dlt_block_log.cpp#L138-L155) - -### Mapping Verification and Healing Mechanisms -The `verify_mapping()` method provides comprehensive periodic verification of mapping consistency and automatic healing of stale mappings. This method is automatically called from the P2P stats task for DLT mode nodes to detect and heal Windows memory-mapped file size drift issues. - -**Enhanced Mapping Verification Features**: -- Periodic verification of logical vs. mapped file size consistency -- Automatic detection and healing of stale mappings after thousands of resize operations -- Detailed logging with information about detected inconsistencies and healing actions -- Automatic reopening of files when stale mapping is detected -- Integration with P2P stats task for DLT mode nodes - -**Enhanced Healing Process**: -- Compares mapped_file.size() with tracked _logical_block_size and _logical_index_size -- Detects stale mapping after extensive file resizing operations -- Automatically closes and reopens files to refresh memory mapping -- Logs detailed information about mapping status and healing actions -- Prevents data corruption or block access issues due to stale metadata - -**Section sources** -- [dlt_block_log.cpp:74-100](file://libraries/chain/dlt_block_log.cpp#L74-L100) -- [dlt_block_log.cpp:545-574](file://libraries/chain/dlt_block_log.cpp#L545-L574) -- [p2p_plugin.cpp:761-765](file://plugins/p2p/p2p_plugin.cpp#L761-L765) - -### Enhanced Block Read/Append Logic Using Logical Sizes -The block read and append logic has been enhanced to use logical sizes instead of mapped_file.size() for improved reliability and cross-platform compatibility. This change ensures consistent behavior across different operating systems and prevents issues caused by stale memory-mapped file size metadata. - -**Enhanced Read Logic**: -- `read_block()` now validates against logical_block_size() instead of mapped_file.size() -- Enhanced position validation with detailed error reporting -- Correctness assertions using logical sizes for block boundary validation -- Improved error messages with logical size information - -**Enhanced Append Logic**: -- `append()` uses logical_index_size() for position validation -- Enhanced index entry validation with logical size tracking -- Improved error handling with detailed context information -- Better integration with resize operation tracking - -**Section sources** -- [dlt_block_log.cpp:138-155](file://libraries/chain/dlt_block_log.cpp#L138-L155) -- [dlt_block_log.cpp:304-369](file://libraries/chain/dlt_block_log.cpp#L304-L369) - -## Crash Recovery and Atomic Operations - -### Comprehensive Crash Recovery Mechanisms -The DLT block log implementation includes sophisticated crash recovery mechanisms that ensure data integrity even during unexpected shutdowns or system failures. The system automatically detects and recovers from interrupted operations using .bak file restoration. - -**Crash Recovery Features**: -- Automatic detection of interrupted truncation operations through .bak file monitoring -- Safe restoration of data from .bak files when original files are missing or corrupted -- Atomic file operations using temporary files (.tmp) and backup files (.bak) -- Comprehensive cleanup of stale temporary files during startup -- Graceful degradation when crash recovery is not possible - -**Updated** Enhanced crash recovery with .bak file restoration and atomic operation guarantees - -```mermaid -flowchart TD -Startup([Startup]) --> CheckBak["Check .bak files"] -CheckBak --> BakExists{"Bak files exist?"} -BakExists --> |Yes| CheckOriginals["Check original file status"] -CheckOriginals --> OriginalMissing{"Originals missing/empty?"} -OriginalMissing --> |Yes| RestoreFromBak["Restore from .bak files"] -OriginalMissing --> |No| CleanBak["Clean .bak files"] -BakExists --> |No| NormalStartup["Normal startup"] -RestoreFromBak --> NormalStartup -CleanBak --> NormalStartup -``` - -**Diagram sources** -- [dlt_block_log.cpp:172-202](file://libraries/chain/dlt_block_log.cpp#L172-L202) - -**Section sources** -- [dlt_block_log.cpp:172-202](file://libraries/chain/dlt_block_log.cpp#L172-L202) -- [dlt_block_log.cpp:432-444](file://libraries/chain/dlt_block_log.cpp#L432-L444) - -### Atomic File Operations -The truncation process implements atomic file operations to ensure data consistency. The system uses a three-phase approach: backup original files, write new files to temporary locations, then atomically replace originals. - -**Atomic Operation Features**: -- Backup original files to .bak before any modifications -- Write new data to .tmp files to avoid partial writes -- Atomic rename operations that are guaranteed to succeed or fail completely -- Automatic cleanup of backup files after successful operations -- Comprehensive rollback capability if operations fail - -**Section sources** -- [dlt_block_log.cpp:432-444](file://libraries/chain/dlt_block_log.cpp#L432-L444) - -## Selective Retention Policies -The DLT rolling block log implements sophisticated selective retention policies that allow fine-grained control over which blocks are maintained and when automatic pruning occurs. These policies ensure optimal disk usage while maintaining serviceability for P2P peers. - -**Retention Policy Features**: -- Configurable maximum block retention with runtime parameter control -- Intelligent pruning threshold management (2x limit vs. configured retention) -- Selective block preservation based on last irreversible block (LIB) boundaries -- Automatic cleanup of obsolete blocks while preserving serviceable ranges -- Flexible retention window adjustment for different operational requirements - -**Section sources** -- [plugin.cpp:327-329](file://plugins/chain/plugin.cpp#L327-L329) -- [database.cpp:4005-4036](file://libraries/chain/database.cpp#L4005-L4036) -- [database.cpp:4170-4172](file://libraries/chain/database.cpp#L4170-L4172) -- [database.cpp:4392-4394](file://libraries/chain/database.cpp#L4392-L4394) - -## Automatic Pruning Capabilities -The DLT rolling block log provides comprehensive automatic pruning capabilities that maintain optimal performance and disk usage through intelligent block lifecycle management and selective cleanup operations. - -**Pruning Mechanism Features**: -- Automatic pruning triggered when block count exceeds 2x configured retention limit -- Intelligent block range calculation based on head block number and retention policy -- Atomic file replacement with temporary file management for data integrity -- Comprehensive validation and cleanup of temporary files after successful pruning -- Selective pruning that preserves serviceable blocks while removing obsolete data - -**Section sources** -- [database.cpp:4043-4047](file://libraries/chain/database.cpp#L4043-L4047) -- [database.cpp:4189-4192](file://libraries/chain/database.cpp#L4189-L4192) -- [database.cpp:4419-4421](file://libraries/chain/database.cpp#L4419-L4421) - -## Enhanced Blockchain Recovery System -The new enhanced blockchain recovery system provides comprehensive crash recovery capabilities through DLT block log replay functionality. The reindex_from_dlt method enables rebuilding blockchain state from DLT rolling block log after snapshot import, with enhanced error handling, progress tracking, and comprehensive logging. - -**Enhanced Recovery System Features**: -- DLT block log replay functionality with progress tracking and percentage completion reporting -- Automatic DLT mode activation during recovery operations with enhanced validation logic -- Enhanced fork database seeding with proper block validation and P2P synchronization support -- Comprehensive error handling with detailed logging and graceful degradation mechanisms -- Selective block replay with progress tracking, memory management optimization, and checkpointing -- Atomic operation support with temporary file management for data integrity during recovery -- Enhanced logging with memory usage reporting and performance metrics -- Graceful handling of interrupted recovery operations with automatic cleanup and state restoration - -**Section sources** -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [plugin.cpp:542-555](file://plugins/chain/plugin.cpp#L542-L555) - -## Configuration Management -The chain plugin provides comprehensive runtime configuration management for DLT rolling block log operations, allowing flexible control over retention policies, pruning thresholds, and operational parameters. - -**Configuration Parameters**: -- `dlt-block-log-max-blocks`: Maximum number of recent blocks to keep in the rolling DLT block log (default: 100,000) -- Runtime parameter validation and enforcement -- Integration with database state management for seamless operation -- Support for disabling DLT block log functionality (0 = disabled) - -**Section sources** -- [plugin.cpp:233-236](file://plugins/chain/plugin.cpp#L233-L236) -- [plugin.cpp:326-329](file://plugins/chain/plugin.cpp#L326-L329) - -## Dependency Analysis -The DLT rolling block log implementation has comprehensive dependencies across multiple system components, providing robust integration with the blockchain infrastructure while maintaining separation of concerns. - -**Core Dependencies**: -- dlt_block_log.hpp/cpp depends on: - - Protocol block definitions for signed blocks with comprehensive serialization - - Boost iostreams for advanced memory-mapped file access with error handling - - Boost filesystem for sophisticated file operations and cleanup - - FC library for comprehensive assertions, data streams, and logging -- database.cpp integrates DLT block log with comprehensive fallback mechanisms and state management -- plugin.cpp configures DLT rolling block log with runtime parameter management and validation -- snapshot_plugin.cpp provides enhanced integration with DLT mode operations and block verification -- p2p_plugin.cpp implements enhanced error handling and graceful fallback mechanisms for DLT mode scenarios -- fork_database.cpp provides enhanced fork database management with automatic seeding capabilities - -```mermaid -graph LR -DLT_H["dlt_block_log.hpp"] --> DLT_CPP["dlt_block_log.cpp"] -DLT_CPP --> BL_CPP["block_log.cpp"] -DLT_CPP --> DB_CPP["database.cpp"] -DLT_CPP --> FD_CPP["fork_database.cpp"] -CP_CPP["plugins/chain/plugin.cpp"] --> DB_CPP -SP_CPP["plugins/snapshot/plugin.cpp"] --> DB_CPP -PP_CPP["plugins/p2p/p2p_plugin.cpp"] --> DB_CPP -DB_CPP --> DH_HPP["database.hpp"] -``` - -**Diagram sources** -- [dlt_block_log.hpp:1-10](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L10) -- [dlt_block_log.cpp:1-7](file://libraries/chain/dlt_block_log.cpp#L1-L7) -- [block_log.cpp:1-6](file://libraries/chain/block_log.cpp#L1-L6) -- [database.cpp:1-10](file://libraries/chain/database.cpp#L1-L10) -- [fork_database.cpp:1-6](file://libraries/chain/fork_database.cpp#L1-L6) -- [plugin.cpp:1-10](file://plugins/chain/plugin.cpp#L1-L10) -- [snapshot_plugin.cpp:1960-2039](file://plugins/snapshot/plugin.cpp#L1960-L2039) -- [p2p_plugin.cpp:1-10](file://plugins/p2p/p2p_plugin.cpp#L1-L10) - -**Section sources** -- [dlt_block_log.hpp:1-10](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L10) -- [dlt_block_log.cpp:1-7](file://libraries/chain/dlt_block_log.cpp#L1-L7) -- [block_log.cpp:1-6](file://libraries/chain/block_log.cpp#L1-L6) -- [database.cpp:1-10](file://libraries/chain/database.cpp#L1-L10) -- [fork_database.cpp:1-6](file://libraries/chain/fork_database.cpp#L1-L6) -- [plugin.cpp:1-10](file://plugins/chain/plugin.cpp#L1-L10) -- [snapshot_plugin.cpp:1960-2039](file://plugins/snapshot/plugin.cpp#L1960-L2039) -- [p2p_plugin.cpp:1-10](file://plugins/p2p/p2p_plugin.cpp#L1-L10) - -## Performance Considerations -The DLT rolling block log implementation provides optimized performance characteristics through advanced memory management, intelligent caching strategies, and efficient I/O operations designed for high-throughput blockchain operations. - -**Performance Optimizations**: -- Sophisticated memory-mapped files enabling zero-copy reads with comprehensive error handling -- Offset-aware index allowing O(1) lookup performance with intelligent caching -- Batched write operations with selective retention enforcement for optimal throughput -- Intelligent truncation scheduling during low-traffic periods to minimize latency impact -- Configurable retention limits preventing excessive disk usage and rebuild overhead -- Automatic pruning reduces fragmentation and maintains optimal file system performance -- **Enhanced Memory Safety**: std::memcpy operations provide predictable performance across platforms -- **Improved Reliability**: Crash recovery mechanisms eliminate data corruption risks -- **Enhanced Recovery Performance**: DLT block log replay provides faster recovery than full blockchain reindex -- **Optimized Recovery Operations**: Progress tracking and memory management improve recovery performance -- **Enhanced Runtime Access**: Non-const accessor methods enable efficient runtime property modifications -- **Comprehensive Range Management**: earliest_available_block_num() method provides precise block availability tracking -- **Enhanced P2P Performance**: Multi-layered fallback mechanisms reduce error rates and improve synchronization -- **Enhanced Reset Performance**: Efficient log clearing and reinitialization with minimal overhead -- **Automatic Gap Recovery**: Intelligent gap detection and recovery mechanisms improve synchronization reliability -- **Windows Compatibility**: Separate logical file size tracking prevents performance issues on Windows systems -- **Enhanced Diagnostic Performance**: verify_mapping() method provides efficient periodic verification without blocking operations -- **Improved Memory Mapping**: Logical size tracking reduces memory-mapped file size drift issues and improves reliability -- **Enhanced Gap Detection Performance**: verify_continuity() method provides efficient gap detection with minimal overhead -- **Automatic Gap Recovery Performance**: Seamless gap recovery without manual intervention improves operational efficiency - -## Enhanced Error Handling and Fallback Mechanisms - -### Improved DLT Mode Detection and Validation -The database now includes enhanced DLT mode detection with improved validation logic. When the primary block log is empty but the database has state (loaded from snapshot), the system sets DLT mode and skips block log validation with comprehensive logging and graceful fallback mechanisms. - -**Enhanced DLT Mode Features**: -- Improved detection logic when block_log.read_block_by_num(head_block_num()) fails -- Enhanced logging with detailed information about DLT mode activation -- Graceful fallback mechanisms that prevent crashes when block data is unavailable -- Better integration between database and DLT block log for seamless operation -- Comprehensive error reporting for DLT mode initialization and operation - -```mermaid -flowchart TD -OpenDB["Open Database"] --> CheckBL["Check block_log head"] -CheckBL --> HasHead{"Head block present?"} -HasHead --> |Yes| ValidateState["Validate chain state"] -HasHead --> |No| SetDLT["Set DLT mode"] -SetDLT --> SkipValidation["Skip block log validation"] -SkipValidation --> SeedForkDB["Seed fork_db from dlt_block_log"] -SeedForkDB --> LogDLT["Log DLT mode activation"] -LogDLT --> Ready["Ready for DLT operations"] -``` - -**Diagram sources** -- [database.cpp:250-271](file://libraries/chain/database.cpp#L250-L271) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -**Section sources** -- [database.cpp:259-268](file://libraries/chain/database.cpp#L259-L268) -- [database.cpp:262-267](file://libraries/chain/database.cpp#L262-L267) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -### Enhanced P2P Fallback Implementation -The P2P plugin now includes significantly enhanced error handling specifically designed for DLT mode scenarios. When serving blocks to peers in DLT mode, the system gracefully handles cases where block data may not be available for certain ranges, providing detailed logging and appropriate error responses with comprehensive error reporting. - -**Enhanced P2P Error Handling Features**: -- Graceful fallback from primary block log to DLT rolling block log with detailed logging -- Specialized error handling for DLT mode where block data may not be available for early blocks -- Improved error reporting with specific messages for DLT mode block availability issues -- Proper exception handling with fc::key_not_found_exception for unavailable blocks in DLT mode -- Enhanced debugging information for troubleshooting DLT mode block serving issues -- Detailed logging with "Block ${id} not available in DLT mode (no block data for this range)" messages -- Graceful fallback mechanism that logs detailed information about why blocks are unavailable - -```mermaid -flowchart TD -GetItem["get_item(id)"] --> CheckType{"Is block message?"} -CheckType --> |Yes| FetchFromDB["Fetch from database"] -FetchFromDB --> Found{"Block found?"} -Found --> |Yes| ReturnBlock["Return block"] -Found --> |No| CheckDLTMode{"In DLT mode?"} -CheckDLTMode --> |Yes| LogFallback["Log graceful fallback with detailed message"] -LogFallback --> ThrowException["Throw key_not_found_exception"] -CheckDLTMode --> |No| LogError["Log detailed error with block ID"] -LogError --> ReturnEmpty["Return empty response"] -Found --> |No| CheckDLTMode -``` - -**Diagram sources** -- [p2p_plugin.cpp:259-286](file://plugins/p2p/p2p_plugin.cpp#L259-L286) - -**Section sources** -- [p2p_plugin.cpp:265-272](file://plugins/p2p/p2p_plugin.cpp#L265-L272) - -### Enhanced Database Fallback Logic -The database layer now includes improved fallback mechanisms with better error handling and logging for DLT mode operations. The fallback logic provides more detailed information about why blocks may not be available and handles edge cases more gracefully with comprehensive error reporting. - -**Enhanced Database Fallback Features**: -- Improved logging for DLT mode fallback scenarios with detailed error messages -- Better error reporting when blocks are not found in either log -- Enhanced validation and error handling for DLT mode operations -- More informative error messages for debugging DLT mode issues -- Graceful handling of edge cases in block serving operations -- Comprehensive fallback chain: fork_db → block_log → dlt_block_log → error - -**Section sources** -- [database.cpp:576-580](file://libraries/chain/database.cpp#L576-L580) -- [database.cpp:609-613](file://libraries/chain/database.cpp#L609-L613) - -### Enhanced Storage-Related Error Reporting -The system now provides comprehensive error reporting for storage-related issues in DLT mode, including detailed logging of block availability problems and graceful degradation mechanisms. - -**Enhanced Storage Error Handling**: -- Detailed logging of block availability issues in DLT mode -- Graceful fallback mechanisms that prevent crashes when blocks are unavailable -- Comprehensive error messages that help operators diagnose storage issues -- Proper exception handling that maintains system stability -- Enhanced debugging information for troubleshooting DLT mode block serving - -**Section sources** -- [database.cpp:599-621](file://libraries/chain/database.cpp#L599-L621) -- [database.cpp:623-640](file://libraries/chain/database.cpp#L623-L640) - -### Strengthened Block Validation Logic -The DLT block log implementation now includes enhanced validation logic with comprehensive error checking and reporting. The validation ensures data integrity and provides detailed feedback when inconsistencies are detected. - -**Enhanced Validation Features**: -- Improved position validation during append operations with conflict resolution -- Enhanced index reconstruction with selective retention enforcement -- Better error reporting for validation failures and recovery operations -- Comprehensive logging of validation results and corrective actions -- Strengthened block verification with detailed error messages - -**Section sources** -- [dlt_block_log.cpp:241-249](file://libraries/chain/dlt_block_log.cpp#L241-L249) -- [dlt_block_log.cpp:320-325](file://libraries/chain/dlt_block_log.cpp#L320-L325) - -### Enhanced Blockchain Recovery Error Handling -The enhanced blockchain recovery system includes comprehensive error handling with detailed logging and graceful degradation mechanisms. The system provides informative error messages and continues operation when recovery is not possible. - -**Enhanced Recovery Error Handling Features**: -- Detailed logging of recovery operations with progress tracking and percentage completion -- Graceful fallback when DLT block log replay fails with comprehensive error reporting -- Continued operation with snapshot state when recovery is not possible -- Enhanced debugging information for troubleshooting recovery issues -- Automatic cleanup and state restoration for interrupted recovery operations -- Memory usage reporting and performance metrics during recovery operations - -**Section sources** -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [plugin.cpp:542-555](file://plugins/chain/plugin.cpp#L542-L555) - -## DLT Mode Fork Database Seeding - -### Automatic Fork Database Seeding Functionality -The DLT mode now includes sophisticated automatic fork database seeding functionality that enhances P2P synchronization capabilities. When the database detects DLT mode (empty block log with existing chain state), it attempts to seed the fork database from the DLT block log head, enabling immediate P2P synchronization. - -**Enhanced Fork Database Seeding Features**: -- Automatic detection of DLT mode conditions during database initialization -- Intelligent validation of DLT block log head against current chain state -- Conditional seeding of fork database when DLT block log covers the head block -- Graceful fallback to minimal fork database entry when DLT block log is incomplete -- Comprehensive logging of seeding operations and their outcomes -- Enhanced P2P synchronization capabilities through proper fork database state - -```mermaid -flowchart TD -DLTMode["DLT Mode Detected"] --> CheckHead["Check DLT Block Log Head"] -CheckHead --> ValidHead{"Head Block Valid?"} -ValidHead --> |Yes| CheckMatch["Check Block ID Match"] -CheckMatch --> |Match| SeedForkDB["Seed Fork Database from DLT Head"] -CheckMatch --> |No| MinimalEntry["Create Minimal Fork Entry"] -ValidHead --> |No| MinimalEntry -SeedForkDB --> LogSuccess["Log Successful Seeding"] -MinimalEntry --> LogFallback["Log Fallback Behavior"] -LogSuccess --> Ready["P2P Sync Ready"] -LogFallback --> Ready -``` - -**Diagram sources** -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -**Section sources** -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -### Enhanced Fork Database Integration -The fork database now integrates more closely with DLT mode operations, providing automatic seeding capabilities and improved block availability checking logic. The fork database can be seeded from DLT block log data or created as minimal entries for P2P synchronization. - -**Enhanced Fork Database Features**: -- Automatic seeding from DLT block log head when available -- Minimal fork database entries for P2P synchronization in DLT mode -- Improved block availability checking with DLT mode awareness -- Enhanced error handling for fork database operations -- Better integration with DLT block log for seamless operation - -**Section sources** -- [fork_database.cpp:24-28](file://libraries/chain/fork_database.cpp#L24-L28) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) - -## Enhanced Block Availability Checking - -### Improved DLT Mode Block Availability Logic -The block availability checking logic has been significantly enhanced to provide better support for DLT mode operations. The system now uses block_summary objects as hints and verifies block availability against the preferred chain, with special handling for DLT mode scenarios. - -**Enhanced Block Availability Features**: -- DLT mode-aware block availability checking with improved logic -- Block summary object verification for faster block existence checks -- Preferred chain verification to ensure blocks are part of the main chain -- Enhanced error handling for DLT mode block availability issues -- Improved fallback mechanisms for block retrieval operations - -```mermaid -flowchart TD -CheckAvailability["Check Block Availability"] --> CheckDLTMode{"In DLT Mode?"} -CheckDLTMode --> |No| NormalCheck["Standard Block Summary Check"] -CheckDLTMode --> |Yes| DLTCheck["DLT Mode Block Summary Check"] -NormalCheck --> VerifyBlock["Verify Block Exists"] -DLTCheck --> VerifySummary["Verify Block Summary"] -VerifySummary --> VerifyChain["Verify Preferred Chain"] -VerifyChain --> FinalResult["Return Availability Result"] -VerifyBlock --> FinalResult -``` - -**Diagram sources** -- [database.cpp:560-595](file://libraries/chain/database.cpp#L560-L595) - -**Section sources** -- [database.cpp:560-595](file://libraries/chain/database.cpp#L560-L595) - -### Enhanced Block Retrieval Chain -The block retrieval chain has been improved to provide better fallback mechanisms and error handling. The system now follows a more sophisticated chain of fallbacks: fork_db → block_log → DLT block log → error, with enhanced validation at each step. - -**Enhanced Block Retrieval Features**: -- Improved block retrieval chain with better error handling -- Enhanced validation of block IDs at each stage -- Better integration between fork database and DLT block log -- Improved error reporting for block retrieval failures -- Enhanced fallback mechanisms for different block sources - -**Section sources** -- [database.cpp:656-697](file://libraries/chain/database.cpp#L656-L697) - -## Stalled Sync Detection for DLT Nodes - -### Automatic Stalled Sync Detection and Recovery -The snapshot plugin now includes sophisticated stalled sync detection capabilities specifically designed for DLT nodes. This feature automatically monitors P2P sync progress and can detect when the node becomes stalled, triggering automatic recovery mechanisms. - -**Stalled Sync Detection Features**: -- Configurable timeout settings for detecting stalled P2P sync -- Automatic detection of no block reception for extended periods -- Integration with trusted peer network for automatic snapshot reload -- Graceful recovery through snapshot reload without manual intervention -- Comprehensive logging of stalled sync events and recovery actions -- Automatic restart of sync detection after recovery - -```mermaid -flowchart TD -StartSync["Start P2P Sync"] --> Monitor["Monitor Block Reception"] -Monitor --> ReceiveBlock["Receive Block"] -ReceiveBlock --> UpdateTimer["Update Last Block Time"] -UpdateTimer --> Monitor -Monitor --> Stalled{"Stalled Timeout Reached?"} -Stalled --> |No| Monitor -Stalled --> |Yes| CheckPeers["Query Trusted Peers for Newer Snapshot"] -CheckPeers --> NewSnapshot{"Newer Snapshot Available?"} -NewSnapshot --> |No| ContinueSync["Continue P2P Sync"] -NewSnapshot --> |Yes| ReloadSnapshot["Reload Snapshot and Enable DLT Mode"] -ReloadSnapshot --> RestartDetection["Restart Stalled Sync Detection"] -ContinueSync --> Monitor -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1435-1500](file://plugins/snapshot/plugin.cpp#L1435-L1500) -- [snapshot_plugin.cpp:2790-2791](file://plugins/snapshot/plugin.cpp#L2790-L2791) - -**Section sources** -- [snapshot_plugin.cpp:1414-1500](file://plugins/snapshot/plugin.cpp#L1414-L1500) -- [snapshot_plugin.cpp:2790-2791](file://plugins/snapshot/plugin.cpp#L2790-L2791) - -### Enhanced Configuration Options -The stalled sync detection system provides comprehensive configuration options for operators to tune the behavior according to their network conditions and requirements. - -**Configuration Options**: -- `enable-stalled-sync-detection`: Enable/disable stalled sync detection (default: false) -- `stalled-sync-timeout-minutes`: Timeout period before considering sync stalled (default: 5 minutes) -- Integration with trusted peer network for automatic snapshot discovery -- Automatic snapshot reload without manual intervention -- Comprehensive logging and monitoring capabilities - -**Section sources** -- [snapshot_plugin.cpp:2691-2696](file://plugins/snapshot/plugin.cpp#L2691-L2696) -- [snapshot_plugin.cpp:2863-2866](file://plugins/snapshot/plugin.cpp#L2863-L2866) - -## Enhanced Gap Handling During Synchronization - -### Enhanced Gap Management in DLT Mode -The DLT rolling block log now includes sophisticated gap handling capabilities that manage the synchronization gap between the fork database and DLT block log. This enhancement ensures smooth operation during the critical period when the DLT block log is catching up to the fork database. - -**Enhanced Gap Handling Features**: -- Automatic detection of gaps between fork database and DLT block log -- Intelligent logging of gap status with detailed information about progress -- Graceful handling of missing blocks in DLT block log during gap periods -- Automatic seeding of DLT block log from fork database as blocks become available -- Enhanced logging with gap filling progress and completion notifications -- Prevention of repeated logging for the same gap status -- **Enhanced Gap Recovery**: Automatic gap detection and recovery with DLT block log reset functionality - -```mermaid -flowchart TD -StartGap["Start Gap Handling"] --> CheckGap{"Gap Exists?"} -CheckGap --> |No| Complete["Gap Filled - Complete"] -CheckGap --> |Yes| LogGap["Log Gap Status"] -LogGap --> CheckForkDB["Check Fork DB for Next Block"] -CheckForkDB --> BlockAvailable{"Block Available?"} -BlockAvailable --> |Yes| AppendBlock["Append Block to DLT Log"] -AppendBlock --> UpdateProgress["Update Gap Progress"] -UpdateProgress --> CheckGap -BlockAvailable --> |No| CheckGapReset{"Need DLT Reset?"} -CheckGapReset --> |Yes| ResetDLT["Reset DLT Block Log"] -ResetDLT --> LogReset["Log Reset Action"] -LogReset --> CheckGap -CheckGapReset --> |No| LogSkip["Log Gap Skip"] -LogSkip --> WaitRetry["Wait and Retry Later"] -WaitRetry --> CheckGap -Complete -``` - -**Diagram sources** -- [database.cpp:4581-4608](file://libraries/chain/database.cpp#L4581-L4608) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -**Section sources** -- [database.cpp:4581-4608](file://libraries/chain/database.cpp#L4581-L4608) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -### Enhanced Gap Logging and Monitoring -The gap handling system provides comprehensive logging and monitoring capabilities to track the progress of gap filling operations. This includes detailed information about gap status, progress indicators, and completion notifications. - -**Enhanced Gap Logging Features**: -- Detailed logging of gap status with block numbers and progress indicators -- Information about DLT head block, LIB (Last Irreversible Block), and gap size -- Prevention of repeated logging for the same gap status -- Notification when gap begins to fill and when it completes -- Enhanced debugging information for troubleshooting gap handling issues -- **Enhanced Gap Recovery Logging**: Comprehensive logging of automatic gap recovery actions and DLT block log reset operations - -**Section sources** -- [database.cpp:4581-4608](file://libraries/chain/database.cpp#L4581-L4608) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -### Automatic Gap Recovery System -The automatic gap recovery system provides sophisticated gap detection and automatic recovery mechanisms that monitor synchronization gaps between DLT block log and fork database. When gaps are detected, the system automatically resets the DLT block log and aligns it with the fork database. - -**Enhanced Gap Recovery System Features**: -- Intelligent gap detection between DLT block log end and fork database start positions -- Automatic DLT block log reset when gaps exceed acceptable thresholds -- Seamless continuation of block synchronization after reset -- Integration with snapshot plugin for automatic fresh snapshot creation -- Comprehensive logging of gap recovery actions and outcomes -- Prevention of repeated gap recovery operations for the same gap -- **Enhanced State Management**: Automatic suppression of redundant gap warnings through _dlt_gap_logged flag - -**Enhanced Gap Recovery Process**: -- Detection of gap between dlt_end and fork_db_start positions -- Identification of earliest available block in fork database -- Automatic reset() method invocation to clear DLT block log -- Sequential writing of available blocks from fork database -- Signal emission to snapshot plugin for fresh snapshot creation -- Continued gap monitoring and recovery as needed -- **Enhanced Warning Suppression**: Automatic logging state management to prevent redundant gap warnings - -```mermaid -flowchart TD -GapDetection["Gap Detection"] --> CheckGap{"Gap > Threshold?"} -CheckGap --> |No| ContinueSync["Continue Normal Sync"] -CheckGap --> |Yes| FindForkStart["Find Earliest Fork Block"] -FindForkStart --> ResetDLT["Call reset() method"] -ResetDLT --> WriteBlocks["Write Available Blocks"] -WriteBlocks --> EmitSignal["Emit dlt_block_log_was_reset"] -EmitSignal --> CreateSnapshot["Create Fresh Snapshot"] -CreateSnapshot --> ContinueSync -ContinueSync -``` - -**Diagram sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -**Section sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -### Signal-Based Integration with Snapshot Plugin -The automatic gap recovery system integrates with the snapshot plugin through the dlt_block_log_was_reset signal. When the DLT block log is reset due to gap recovery, the signal is emitted, prompting the snapshot plugin to create a fresh snapshot for other DLT nodes. - -**Enhanced Signal Integration Features**: -- Automatic emission of dlt_block_log_was_reset signal upon DLT block log reset -- Snapshot plugin listening for reset signal to create fresh snapshots -- Seamless coordination between gap recovery and snapshot creation -- Enhanced bootstrap capability for other DLT nodes -- Comprehensive logging of signal-based integration actions - -**Section sources** -- [database.hpp:332-338](file://libraries/chain/include/graphene/chain/database.hpp#L332-L338) -- [snapshot_plugin.cpp:3254](file://plugins/snapshot/plugin.cpp#L3254) - -### Automatic State Management for Gap Warnings -The automatic gap recovery system includes intelligent state management to suppress redundant gap warnings. A boolean flag _dlt_gap_logged is used to track whether a gap warning has already been logged, preventing repeated logging for the same gap condition. - -**Enhanced State Management Features**: -- _dlt_gap_logged boolean flag for gap warning suppression -- Automatic setting of flag when gap warning is first logged -- Reset of flag when gap begins to fill with new blocks -- Re-enabling of gap logging when gaps reappear -- Prevention of redundant gap warnings during recovery operations -- Enhanced debugging information for gap state management - -**Section sources** -- [database.cpp:5482-5499](file://libraries/chain/database.cpp#L5482-L5499) - -## Enhanced DLT Block Log Reset Functionality - -### Safe Log Clearing and Reinitialization -The new reset() method provides comprehensive safe log clearing and reinitialization capabilities. When called, it closes the current DLT block log, deletes all data and index files, removes stale temporary and backup files, then reopens the log as empty. This functionality is essential for automatic gap recovery and synchronization gap management. - -**Enhanced Reset Method Features**: -- Safe log clearing with comprehensive file cleanup including .tmp and .bak files -- Atomic file deletion and recreation process with proper error handling -- Preservation of file path and configuration while resetting internal state -- Comprehensive logging with old range information for debugging and monitoring -- Thread-safe operation with proper locking mechanisms - -**Enhanced Reset Process**: -- Close current DLT block log with proper cleanup -- Delete all data files (block_path, block_path + ".tmp", block_path + ".bak") -- Delete all index files (index_path, index_path + ".tmp", index_path + ".bak") -- Reopen DLT block log with original path -- Log completion with old range information - -**Section sources** -- [dlt_block_log.cpp:523-543](file://libraries/chain/dlt_block_log.cpp#L523-L543) - -### Automatic Gap Recovery Integration -The reset() method is automatically triggered during gap recovery operations when synchronization gaps are detected between the DLT block log and fork database. This ensures that the DLT block log is properly aligned with the fork database for continued synchronization. - -**Enhanced Gap Recovery Integration Features**: -- Automatic detection of gaps between dlt_end and fork_db_start positions -- Triggering of reset() method when gaps exceed acceptable thresholds -- Seamless continuation of block synchronization after reset -- Integration with snapshot plugin for automatic fresh snapshot creation -- Comprehensive logging of gap recovery actions and outcomes -- Prevention of repeated gap recovery operations for the same gap - -**Section sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -## Automatic Gap Recovery System - -### Intelligent Gap Detection and Recovery -The automatic gap recovery system provides sophisticated gap detection and automatic recovery mechanisms that monitor synchronization gaps between DLT block log and fork database. When gaps are detected, the system automatically resets the DLT block log and aligns it with the fork database. - -**Enhanced Gap Recovery System Features**: -- Intelligent gap detection between DLT block log end and fork database start positions -- Automatic DLT block log reset when gaps exceed acceptable thresholds -- Seamless continuation of block synchronization after reset -- Integration with snapshot plugin for automatic fresh snapshot creation -- Comprehensive logging of gap recovery actions and outcomes -- Prevention of repeated gap recovery operations for the same gap -- **Enhanced Warning Suppression**: Automatic suppression of redundant gap warnings through _dlt_gap_logged state management - -**Enhanced Gap Recovery Process**: -- Detection of gap between dlt_end and fork_db_start positions -- Identification of earliest available block in fork database -- Automatic reset() method invocation to clear DLT block log -- Sequential writing of available blocks from fork database -- Signal emission to snapshot plugin for fresh snapshot creation -- Continued gap monitoring and recovery as needed -- **Enhanced State Management**: Automatic logging state management to prevent redundant gap warnings - -```mermaid -flowchart TD -GapDetection["Gap Detection"] --> CheckGap{"Gap > Threshold?"} -CheckGap --> |No| ContinueSync["Continue Normal Sync"] -CheckGap --> |Yes| FindForkStart["Find Earliest Fork Block"] -FindForkStart --> ResetDLT["Call reset() method"] -ResetDLT --> WriteBlocks["Write Available Blocks"] -WriteBlocks --> EmitSignal["Emit dlt_block_log_was_reset"] -EmitSignal --> CreateSnapshot["Create Fresh Snapshot"] -CreateSnapshot --> ContinueSync -ContinueSync -``` - -**Diagram sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -**Section sources** -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) - -### Signal-Based Integration with Snapshot Plugin -The automatic gap recovery system integrates with the snapshot plugin through the dlt_block_log_was_reset signal. When the DLT block log is reset due to gap recovery, the signal is emitted, prompting the snapshot plugin to create a fresh snapshot for other DLT nodes. - -**Enhanced Signal Integration Features**: -- Automatic emission of dlt_block_log_was_reset signal upon DLT block log reset -- Snapshot plugin listening for reset signal to create fresh snapshots -- Seamless coordination between gap recovery and snapshot creation -- Enhanced bootstrap capability for other DLT nodes -- Comprehensive logging of signal-based integration actions - -**Section sources** -- [database.hpp:332-338](file://libraries/chain/include/graphene/chain/database.hpp#L332-L338) -- [snapshot_plugin.cpp:3254](file://plugins/snapshot/plugin.cpp#L3254) - -## DLT Block Log Accessibility Enhancement - -### Enhanced DLT Block Log Accessor Methods -The DLT block log accessibility has been significantly enhanced with the introduction of both const and non-const accessor methods. This enhancement enables external components to modify DLT block log properties during runtime operations while maintaining read-only access for general use. - -**Enhanced Accessor Methods**: -- `const dlt_block_log &get_dlt_block_log() const` - Provides read-only access for general use -- `dlt_block_log &get_dlt_block_log()` - Provides mutable access for external components to modify DLT block log properties during runtime operations - -**Enhanced Runtime Property Modification Capabilities**: -- External components can modify DLT block log properties during runtime operations -- Maintains thread safety through proper locking mechanisms -- Enables dynamic configuration of DLT block log behavior based on operational requirements -- Supports runtime adjustments to retention policies and pruning thresholds -- Allows external components to optimize DLT block log performance based on current workload - -**Integration with External Components**: -- Chain plugin can access DLT block log for recovery operations with mutable access -- Snapshot plugin can modify DLT block log properties during snapshot import -- P2P plugin can optimize DLT block log access patterns for peer synchronization -- Database layer can dynamically adjust DLT block log configuration based on memory usage - -**Section sources** -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) -- [plugin.cpp:627-627](file://plugins/chain/plugin.cpp#L627-L627) -- [snapshot_plugin.cpp:1473-1476](file://plugins/snapshot/plugin.cpp#L1473-L1476) - -### Enhanced External Component Integration -The enhanced accessibility model provides comprehensive integration capabilities for external components that need to interact with the DLT block log during runtime operations. - -**Enhanced External Component Integration Features**: -- Chain plugin can access DLT block log for recovery operations with mutable access -- Snapshot plugin can modify DLT block log properties during snapshot import -- P2P plugin can optimize DLT block log access patterns for peer synchronization -- Database layer can dynamically adjust DLT block log configuration based on operational requirements -- Enhanced error handling and validation for external component modifications -- Thread-safe access patterns that prevent race conditions during runtime modifications - -**Section sources** -- [plugin.cpp:626-632](file://plugins/chain/plugin.cpp#L626-L632) -- [snapshot_plugin.cpp:1472-1477](file://plugins/snapshot/plugin.cpp#L1472-L1477) - -## Comprehensive DLT Block Range Management System - -### Earliest Available Block Number Method -The comprehensive DLT block range management system introduces the earliest_available_block_num() method, which provides precise block availability tracking for DLT mode operations. This method determines the lowest block number for which the node can serve full block data from block_log, DLT block log, or fork database. - -**Enhanced Earliest Available Block Number Features**: -- Determines the lowest block number that can be served across all available sources -- In non-DLT mode, returns 1 (block_log always starts from block 1) -- In DLT mode, returns the minimum of head_block_num() and DLT block log start_block_num() -- Prevents advertising blocks that cannot be served to P2P peers -- Enables sophisticated P2P synchronization with accurate block range information - -**Enhanced DLT Mode Logic**: -- DLT mode: blocks come from dlt_block_log and fork_db -- After snapshot import, dlt_block_log may have only the head block -- earliest = head_block_num() initially -- Check dlt_block_log range: if dlt_start > 0 && dlt_start < earliest, earliest = dlt_start -- fork_db blocks are typically at/above head, so they don't lower the floor - -```mermaid -flowchart TD -StartEA["earliest_available_block_num()"] --> CheckMode{"Non-DLT Mode?"} -CheckMode --> |Yes| CheckBL["Check block_log head"] -CheckBL --> HasHead{"Has block_log head?"} -HasHead --> |Yes| ReturnOne["Return 1"] -HasHead --> |No| ReturnHead["Return head_block_num()"] -CheckMode --> |No| InitEarliest["Initialize earliest = head_block_num()"] -InitEarliest --> CheckDLT["Check dlt_block_log start_block_num()"] -CheckDLT --> ValidDLT{"dlt_start > 0 && dlt_start < earliest?"} -ValidDLT --> |Yes| UpdateEarliest["Update earliest = dlt_start"] -ValidDLT --> |No| SkipUpdate["Skip update"] -UpdateEarliest --> ReturnEarliest["Return earliest"] -SkipUpdate --> ReturnEarliest -``` - -**Diagram sources** -- [database.cpp:835-858](file://libraries/chain/database.cpp#L835-L858) - -**Section sources** -- [database.cpp:835-858](file://libraries/chain/database.cpp#L835-L858) - -### Enhanced Block Range Validation -The comprehensive DLT block range management system provides sophisticated block range validation for P2P synchronization. The system prevents advertising blocks that fall outside the available range, reducing error rates and improving peer interaction quality. - -**Enhanced Validation Features**: -- P2P layer uses earliest_available_block_num() to clamp block requests -- Prevents "You are missing a sync item you claim to have" errors -- Provides detailed logging of block range limitations -- Enables graceful handling of DLT mode block availability constraints -- Comprehensive error reporting with block ID and range information - -**Section sources** -- [p2p_plugin.cpp:294-302](file://plugins/p2p/p2p_plugin.cpp#L294-L302) -- [p2p_plugin.cpp:317-323](file://plugins/p2p/p2p_plugin.cpp#L317-L323) - -## Enhanced P2P Synchronization Capabilities - -### Multi-Layered Fallback Mechanisms -The enhanced P2P synchronization capabilities implement sophisticated multi-layered fallback mechanisms that provide robust error handling and graceful degradation. The system follows a comprehensive fallback chain: fork database → primary block log → DLT block log → error, with detailed logging at each stage. - -**Enhanced Fallback Chain Features**: -- Fork database → block_log → dlt_block_log → error progression -- Detailed logging for each fallback stage with block ID and availability information -- Enhanced error reporting with comprehensive context for troubleshooting -- Graceful degradation when blocks are not available in any source -- Improved peer interaction handling with reduced error rates - -**Enhanced Block Serving Logic**: -- get_block_by_id(): fork_db → block_log → dlt_block_log → error -- get_block_by_number(): fork_db → block_log → dlt_block_log → error -- Detailed logging with block ID, availability range, and DLT block log boundaries -- Proper exception handling with fc::key_not_found_exception for unavailable blocks - -```mermaid -flowchart TD -GetBlock["get_block_by_id()"] --> CheckForkDB["Check fork_db"] -CheckForkDB --> FoundFork{"Found in fork_db?"} -FoundFork --> |Yes| ReturnFork["Return fork_db block"] -FoundFork --> |No| CheckBlockLog["Check block_log"] -CheckBlockLog --> FoundBL{"Found in block_log?"} -FoundBL --> |Yes| ReturnBL["Return block_log block"] -FoundBL --> |No| CheckDLT["Check dlt_block_log"] -CheckDLT --> FoundDLT{"Found in dlt_block_log?"} -FoundDLT --> |Yes| ReturnDLT["Return dlt_block_log block"] -FoundDLT --> |No| ThrowError["Throw key_not_found_exception"] -``` - -**Diagram sources** -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) - -**Section sources** -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) -- [database.cpp:884-901](file://libraries/chain/database.cpp#L884-L901) - -### Enhanced Peer Interaction Handling -The enhanced P2P synchronization capabilities provide comprehensive peer interaction handling with detailed logging and error reporting. The system prevents common P2P errors and provides informative feedback for troubleshooting. - -**Enhanced Peer Interaction Features**: -- Detailed logging of block serving operations with block ID and range information -- Graceful fallback mechanisms that prevent peer disconnections -- Comprehensive error reporting with block availability context -- Enhanced debugging information for troubleshooting DLT mode issues -- Improved peer satisfaction through reduced error rates and better error handling - -**Section sources** -- [p2p_plugin.cpp:330-364](file://plugins/p2p/p2p_plugin.cpp#L330-L364) -- [p2p_plugin.cpp:370-489](file://plugins/p2p/p2p_plugin.cpp#L370-L489) - -## Multi-Layered Fallback Mechanisms - -### Sophisticated Block Retrieval Chain -The multi-layered fallback mechanisms implement a sophisticated block retrieval chain that provides robust error handling and graceful degradation. The system follows a comprehensive fallback progression with detailed validation and logging at each stage. - -**Enhanced Fallback Chain Implementation**: -- fork_database::fetch_block() for block ID lookups -- block_log::read_block_by_num() for primary block log retrieval -- dlt_block_log::read_block_by_num() for DLT block log fallback -- Comprehensive validation of block IDs and content at each stage -- Detailed logging with block ID, availability range, and error context - -**Enhanced Error Handling**: -- Detailed error reporting for each fallback stage -- Graceful degradation when blocks are not available -- Comprehensive logging with block ID and range information -- Proper exception handling with fc::key_not_found_exception -- Enhanced debugging information for troubleshooting - -**Section sources** -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) -- [database.cpp:884-901](file://libraries/chain/database.cpp#L884-L901) - -### Enhanced Block Availability Tracking -The multi-layered fallback mechanisms provide comprehensive block availability tracking that enables precise determination of which blocks can be served from each source. This tracking system prevents serving blocks that are not available and provides detailed logging for troubleshooting. - -**Enhanced Availability Tracking Features**: -- Precise tracking of block availability across all sources -- Detailed logging of block serving operations with source information -- Enhanced error reporting with comprehensive context -- Graceful handling of unavailable blocks with proper fallback -- Improved peer interaction through accurate availability information - -**Section sources** -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) -- [database.cpp:884-901](file://libraries/chain/database.cpp#L884-L901) - -## Enhanced Diagnostic and Monitoring Capabilities - -### Comprehensive Diagnostic System -The enhanced diagnostic system provides comprehensive monitoring and analysis capabilities through the new `verify_mapping()`, `verify_continuity()`, and `resize_count()` methods. These methods enable proactive detection and healing of Windows memory-mapped file size drift issues, along with detailed tracking of resize operations for performance monitoring. - -**Enhanced Diagnostic Features**: -- `verify_mapping()` method: Periodic verification of logical vs. mapped file size consistency -- `verify_continuity()` method: Walks entire block range and reports gaps for integrity verification -- `resize_count()` method: Tracking of resize operations since log open for diagnostic purposes -- Integration with P2P stats task for automatic periodic verification in DLT mode -- Comprehensive logging with detailed information about mapping status and healing actions -- Automatic reopening of files when stale mapping is detected - -**Enhanced Mapping Verification Process**: -- Compares mapped_file.size() with tracked _logical_block_size and _logical_index_size -- Detects stale mapping after thousands of resize() cycles -- Automatically closes and reopens files to refresh mapping -- Logs detailed information about detected inconsistencies and healing actions -- Prevents get_block_pos() from rejecting valid block numbers due to stale metadata - -**Enhanced Gap Integrity Scanning**: -- Periodic verification of DLT block log integrity through verify_continuity() method -- Comprehensive gap reporting with detailed block number information -- Integration with P2P stats task for automatic gap detection and logging -- Enhanced error reporting with gap count and missing block information -- Automatic gap suppression to prevent redundant logging - -**Enhanced Resize Tracking**: -- `_resize_count` field tracks number of resize operations performed -- Used for performance monitoring and debugging -- Integrated into P2P stats logging for DLT mode nodes -- Helps identify potential memory-mapped file size drift issues - -**Section sources** -- [dlt_block_log.cpp:545-579](file://libraries/chain/dlt_block_log.cpp#L545-L579) -- [dlt_block_log.cpp:576-602](file://libraries/chain/dlt_block_log.cpp#L576-L602) -- [p2p_plugin.cpp:757-765](file://plugins/p2p/p2p_plugin.cpp#L757-L765) - -### Periodic Monitoring Integration -The diagnostic system is integrated into the P2P stats task for DLT mode nodes, providing automatic periodic monitoring without manual intervention. This ensures continuous monitoring of mapping consistency and resize operations. - -**Enhanced Monitoring Integration Features**: -- Automatic periodic verification in DLT mode through P2P stats task -- Integration with existing P2P monitoring infrastructure -- Minimal performance impact through scheduled execution -- Comprehensive logging with detailed diagnostic information -- Automatic healing of detected mapping inconsistencies - -**Section sources** -- [p2p_plugin.cpp:757-765](file://plugins/p2p/p2p_plugin.cpp#L757-L765) - -## Troubleshooting Guide -Comprehensive troubleshooting guidance for DLT-specific scenarios, retention policy issues, automatic pruning failures, enhanced blockchain recovery problems, configuration issues, DLT block range management problems, enhanced P2P synchronization issues, multi-layered fallback mechanism failures, the new DLT block log accessibility enhancement, enhanced DLT block log reset functionality, automatic gap recovery system issues, enhanced diagnostic and monitoring capabilities, Windows compatibility issues, mapping verification problems, gap detection and recovery issues, and systematic diagnostic approaches and enhanced error reporting. - -**Common DLT Mode Issues**: -- Index mismatch detection and automatic reconstruction with selective retention enforcement -- Empty block log in DLT mode validation and fallback mechanism verification -- Truncation failures with temporary file cleanup and atomic operation validation -- Retention policy violations with selective block preservation and pruning triggers -- Configuration parameter validation and runtime parameter enforcement -- Enhanced block verification failures during snapshot operations -- P2P fallback errors in DLT mode with detailed logging and error reporting -- Graceful fallback mechanism failures with proper exception handling -- Storage-related issues with comprehensive error messages and logging -- Enhanced synchronization issues with detailed logging capabilities -- **Windows Compatibility Issues**: Memory-mapped file size drift after thousands of resize operations -- **Mapping Verification Problems**: Issues with verify_mapping() method periodic verification -- **Gap Detection Issues**: Problems with verify_continuity() method gap detection and integrity verification -- **Resize Tracking Issues**: Problems with resize_count() method diagnostic tracking -- **Memory Safety Issues**: Unsafe pointer cast errors resolved through std::memcpy operations -- **Crash Recovery Problems**: .bak file restoration failures and atomic operation issues -- **Cross-Platform Compatibility**: Platform-specific file operation problems -- **Fork Database Seeding Failures**: Issues with automatic DLT mode fork database seeding -- **Enhanced Block Availability Problems**: DLT mode block availability checking failures -- **Improved Error Handling**: Better error reporting and logging throughout the system -- **Stalled Sync Detection Issues**: Timeout configuration problems and recovery failures -- **Snapshot Reload Failures**: Automatic snapshot reload mechanism issues -- **Gap Handling Problems**: Issues with DLT mode gap management and synchronization -- **Enhanced Blockchain Recovery Issues**: DLT block log replay failures and recovery mechanism problems -- **Recovery Progress Tracking**: Missing progress indicators and percentage completion reporting -- **DLT Block Log Accessibility Issues**: Problems with const/non-const accessor method usage -- **Runtime Property Modification Failures**: Issues with external components modifying DLT block log properties -- **DLT Block Range Management Issues**: Problems with earliest_available_block_num() method usage -- **Enhanced P2P Synchronization Problems**: Issues with multi-layered fallback mechanisms and block serving -- **Multi-Layered Fallback Failures**: Problems with comprehensive fallback chain implementation -- **Enhanced DLT Block Log Reset Issues**: Problems with safe log clearing and reinitialization functionality -- **Automatic Gap Recovery Failures**: Issues with intelligent gap detection and automatic recovery mechanisms -- **Signal Integration Problems**: Issues with dlt_block_log_was_reset signal emission and snapshot plugin integration -- **Gap Warning Suppression Issues**: Problems with _dlt_gap_logged state management and redundant warning prevention -- **Diagnostic System Issues**: Problems with verify_mapping(), verify_continuity(), and resize_count() method usage and monitoring - -**Section sources** -- [dlt_block_log.cpp:161-209](file://libraries/chain/dlt_block_log.cpp#L161-L209) -- [dlt_block_log.cpp:356-411](file://libraries/chain/dlt_block_log.cpp#L356-L411) -- [database.cpp:259-268](file://libraries/chain/database.cpp#L259-L268) -- [p2p_plugin.cpp:265-272](file://plugins/p2p/p2p_plugin.cpp#L265-L272) -- [database.cpp:266-292](file://libraries/chain/database.cpp#L266-L292) -- [database.cpp:560-595](file://libraries/chain/database.cpp#L560-L595) -- [snapshot_plugin.cpp:1435-1500](file://plugins/snapshot/plugin.cpp#L1435-L1500) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [database.hpp:515-516](file://libraries/chain/include/graphene/chain/database.hpp#L515-L516) -- [database.cpp:835-858](file://libraries/chain/database.cpp#L835-L858) -- [dlt_block_log.cpp:523-543](file://libraries/chain/dlt_block_log.cpp#L523-L543) -- [database.cpp:4910-5150](file://libraries/chain/database.cpp#L4910-L5150) -- [database.cpp:5482-5499](file://libraries/chain/database.cpp#L5482-L5499) -- [dlt_block_log.cpp:545-579](file://libraries/chain/dlt_block_log.cpp#L545-L579) -- [dlt_block_log.cpp:576-602](file://libraries/chain/dlt_block_log.cpp#L576-L602) -- [p2p_plugin.cpp:757-765](file://plugins/p2p/p2p_plugin.cpp#L757-L765) - -## Conclusion -The DLT Rolling Block Log provides a comprehensive, offset-aware append-only storage mechanism specifically designed for snapshot-based nodes with advanced selective retention policies and automatic pruning capabilities. Recent enhancements include critical Windows compatibility improvements with separate logical file size tracking, sophisticated mapping verification and healing mechanisms, enhanced diagnostic capabilities, and strengthened validation logic with comprehensive error reporting. The most significant enhancement is the comprehensive DLT block range management system with the earliest_available_block_num() method, which provides precise block availability tracking and enables sophisticated P2P synchronization with multi-layered fallback mechanisms. The enhanced P2P synchronization capabilities now provide robust error handling with detailed logging and graceful fallback mechanisms for DLT mode scenarios, while the multi-layered fallback mechanisms ensure reliable block retrieval across fork database, primary block log, and DLT block log sources. The enhanced accessibility model provides comprehensive integration capabilities for external components that need to interact with the DLT block log during runtime operations. The chain plugin can now modify DLT block log properties during recovery operations, the snapshot plugin can adjust DLT block log behavior during snapshot import, and the P2P plugin can optimize DLT block log access patterns for peer synchronization. This enhancement maintains thread safety through proper locking mechanisms while enabling dynamic configuration of DLT block log behavior based on operational requirements. The enhanced P2P fallback mechanisms now provide graceful handling of DLT mode scenarios where block data may not be available for certain ranges, with detailed logging and appropriate error responses including specific messages like "Block ${id} not available in DLT mode (no block data for this range)". The most notable recent enhancement is the sophisticated gap handling during synchronization between fork database and DLT block log. This system automatically manages the critical period when the DLT block log is catching up to the fork database, with intelligent logging, automatic seeding, and graceful handling of missing blocks. The gap handling system prevents repeated logging for the same gap status and provides detailed progress notifications, ensuring smooth operation during the synchronization process. The new enhanced blockchain recovery system represents a major advancement in DLT node reliability and operational efficiency. The reindex_from_dlt method provides core functionality for rebuilding blockchain state from DLT rolling block log after snapshot import, with comprehensive error handling, progress tracking, enhanced fork database seeding, and detailed logging capabilities. This system enables rapid recovery from corrupted states while maintaining data integrity and operational continuity, with enhanced progress reporting and memory management optimization. Its sophisticated integration with the database ensures seamless fallback when the primary block log is empty, while configurable limits, intelligent retention enforcement, and automatic cleanup mechanisms help manage disk usage efficiently. The implementation leverages advanced memory-mapped files, strict position validation using std::memcpy operations, and comprehensive error handling to deliver reliable performance and data integrity for modern blockchain operations. The improved error handling and fallback mechanisms ensure that DLT mode operations are robust, well-documented, and provide excellent user experience for both operators and P2P peers with comprehensive logging and graceful degradation capabilities. The critical memory safety improvements eliminate undefined behavior risks, while the crash recovery mechanisms ensure data integrity even during unexpected system failures. The enhanced fork database seeding and block availability checking logic provide comprehensive support for DLT mode operations, making the system more reliable and user-friendly for snapshot-based node operations. The stalled sync detection feature further enhances the system's resilience and operational efficiency by automatically handling network connectivity issues without manual intervention. The enhanced gap handling capabilities and new blockchain recovery system represent significant improvements in DLT mode synchronization reliability, user experience, and operational efficiency. The latest accessibility enhancement completes the comprehensive DLT block log functionality by enabling external components to modify DLT block log properties during runtime operations while maintaining read-only access for general use, providing a robust foundation for advanced DLT node operations. The comprehensive DLT block range management system with the earliest_available_block_num() method, enhanced P2P synchronization capabilities with multi-layered fallback mechanisms, and sophisticated peer interaction handling represent the most significant advancement in DLT mode support and P2P synchronization reliability. The new reset() method and automatic gap recovery system provide enhanced operational flexibility and improved synchronization reliability, making the DLT rolling block log a cornerstone component of the VIZ blockchain's advanced node capabilities. The enhanced diagnostic system with verify_mapping(), verify_continuity(), and resize_count() methods provides comprehensive monitoring and proactive issue detection, ensuring optimal performance and reliability in production environments. The Windows compatibility fixes and mapping verification mechanisms address critical cross-platform issues, making the system more robust and reliable across different operating systems and deployment scenarios. The new verify_continuity() method and automatic gap recovery system represent the most significant advancement in DLT block log integrity verification and gap management, providing comprehensive protection against data corruption and synchronization issues while maintaining optimal performance and reliability. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/Database Management.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/Database Management.md deleted file mode 100644 index 30a886b208..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Database Management/Database Management.md +++ /dev/null @@ -1,1788 +0,0 @@ -# Database Management - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [chainbase.hpp](file://thirdparty/chainbase/include/chainbase/chainbase.hpp) -- [chainbase.cpp](file://thirdparty/chainbase/src/chainbase.cpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [db_with.hpp](file://libraries/chain/include/graphene/chain/db_with.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [exception.hpp](file://thirdparty/fc/include/fc/exception/exception.hpp) -- [exception.cpp](file://thirdparty/fc/src/exception.cpp) -- [exceptions.hpp](file://libraries/protocol/include/graphene/protocol/exceptions.hpp) -- [stacktrace.cpp](file://thirdparty/fc/src/stacktrace.cpp) -- [config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced DLT block log gap detection and recovery with automatic gap recovery mechanisms -- Improved error reporting throughout gap detection and recovery workflow with intelligent warning suppression -- Added _dlt_gap_logged flag mechanism for intelligent warning suppression during gap recovery -- Enhanced logging throughout DLT block log operations for better diagnostics and troubleshooting -- Improved gap recovery logic with better error handling and recovery strategies - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Emergency Consensus Implementation](#emergency-consensus-implementation) -7. [Dependency Analysis](#dependency-analysis) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction -This document describes the Database Management system that serves as the core state persistence layer for the VIZ blockchain. It covers the database class lifecycle, initialization and cleanup, validation steps, session management, memory allocation strategies, shared memory configuration, checkpoints for fast synchronization, block log integration, observer pattern usage, DLT mode detection and conditional operations, enhanced block fetching logic with DLT mode awareness, the new `_dlt_gap_logged` flag mechanism for intelligent warning suppression, comprehensive operation guard implementation for concurrent access protection, dual operation guard patterns for validator scheduling safety, enhanced P2P plugin block validation with operation guard protection, and practical examples of database operations and performance optimization. - -**Updated** - Enhanced with sophisticated exception handling mechanisms that preserve derived exception types during rethrow operations, comprehensive fork database management with improved diagnostic capabilities, and enhanced early rejection logic for blocks far ahead with unknown parents. The system now includes comprehensive database crash debugging capabilities with debug_crash logging throughout critical code paths, debug-block-production configuration option for detailed block production logging, and enhanced diagnostic visibility into database operations. The system also features stacktrace crash handlers for improved crash diagnostics and extensive debug logging markers (DEBUG_CRASH) throughout database and validator production code. - -## Project Structure -The database subsystem is implemented primarily in the chain library with enhanced support for operation guards, concurrent access protection, and comprehensive crash debugging: -- Core database interface and declarations: libraries/chain/include/graphene/chain/database.hpp -- Implementation of database operations with enhanced DLT mode support, emergency consensus, operation guards, concurrent access protection, and comprehensive debug logging: libraries/chain/database.cpp -- Chainbase integration with operation_guard RAII pattern and resize barrier mechanisms: thirdparty/chainbase/include/chainbase/chainbase.hpp and thirdparty/chainbase/src/chainbase.cpp -- Block log abstraction: libraries/chain/include/graphene/chain/block_log.hpp and libraries/chain/block_log.cpp -- DLT block log for rolling window storage: libraries/chain/include/graphene/chain/dlt_block_log.hpp and libraries/chain/dlt_block_log.cpp -- Fork database for reversible blocks: libraries/chain/include/graphene/chain/fork_database.hpp and libraries/chain/fork_database.cpp -- Database exceptions including unlinkable_block_exception: libraries/chain/include/graphene/chain/database_exceptions.hpp -- Snapshot plugin integration: plugins/snapshot/plugin.cpp for DLT mode initialization -- Postponed transaction processing: libraries/chain/include/graphene/chain/db_with.hpp for transaction queue management -- Validator Plugin integration with dual operation guard patterns and debug logging: plugins/validator/validator.cpp and plugins/validator/include/graphene/plugins/validator/validator.hpp -- Protocol configuration: libraries/protocol/include/graphene/protocol/config.hpp for emergency consensus constants -- Network layer integration: libraries/network/node.cpp for peer connectivity management -- P2P plugin integration with operation guard protection: plugins/p2p/p2p_plugin.cpp for enhanced exception handling and concurrent access safety -- Enhanced exception handling infrastructure: thirdparty/fc/include/fc/exception/exception.hpp and thirdparty/fc/src/exception.cpp -- Protocol exceptions with dynamic rethrow support: libraries/protocol/include/graphene/protocol/exceptions.hpp -- Stacktrace crash handlers for improved diagnostics: thirdparty/fc/src/stacktrace.cpp - -```mermaid -graph TB -subgraph "Chain Library" -DBH["database.hpp"] -DBCPP["database.cpp"] -BLH["block_log.hpp"] -BLCPP["block_log.cpp"] -DLTH["dlt_block_log.hpp"] -DLTCPP["dlt_block_log.cpp"] -FDH["fork_database.hpp"] -FDCPP["fork_database.cpp"] -DEH["database_exceptions.hpp"] -DBWH["db_with.hpp"] -ENDH["emergency_consensus_constants"] -ENDH2["exception handling infrastructure"] -STH["stacktrace crash handlers"] -end -subgraph "Chainbase Integration" -CBH["chainbase.hpp"] -CBCPP["chainbase.cpp"] -end -subgraph "Plugins" -SNAPH["snapshot/plugin.cpp"] -validator["validator/validator.cpp"] -WITNESSH["validator.hpp"] -P2PH["p2p/p2p_plugin.cpp"] -end -subgraph "Network Layer" -NODE["node.cpp"] -EXC["exceptions.hpp"] -end -subgraph "Exception System" -EXCEPTIONH["fc/exception.hpp"] -EXCEPTIONCPP["fc/exception.cpp"] -PROTOEX["protocol/exceptions.hpp"] -end -DBH --> DBCPP -DBCPP --> BLH -DBCPP --> BLCPP -DBCPP --> DLTH -DBCPP --> DLTCPP -DBCPP --> FDH -DBCPP --> FDCPP -DBCPP --> DEH -DBCPP --> DBWH -DBCPP --> ENDH -DBCPP --> CBH -DBCPP --> CBCPP -DBCPP --> EXCEPTIONH -DBCPP --> EXCEPTIONCPP -DBCPP --> PROTOEX -DBCPP --> STH -SNAPH --> DBH -validator --> DBH -WITNESSH --> validator -P2PH --> DBH -NODE --> DBH -EXC --> NODE -``` - -**Diagram sources** -- [database.hpp:1-670](file://libraries/chain/include/graphene/chain/database.hpp#L1-L670) -- [database.cpp:1-6760](file://libraries/chain/database.cpp#L1-L6760) -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [chainbase.cpp:1-200](file://thirdparty/chainbase/src/chainbase.cpp#L1-L200) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [block_log.cpp:1-302](file://libraries/chain/block_log.cpp#L1-L302) -- [dlt_block_log.hpp:1-80](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L80) -- [dlt_block_log.cpp:1-476](file://libraries/chain/dlt_block_log.cpp#L1-L476) -- [fork_database.hpp:1-144](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L144) -- [fork_database.cpp:1-278](file://libraries/chain/fork_database.cpp#L1-L278) -- [database_exceptions.hpp:1-136](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L1-L136) -- [db_with.hpp:1-154](file://libraries/chain/include/graphene/chain/db_with.hpp#L1-L154) -- [plugin.cpp:1180-1379](file://plugins/snapshot/plugin.cpp#L1180-L1379) -- [validator.cpp:270-469](file://plugins/validator/validator.cpp#L270-L469) -- [validator.hpp:38-73](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L38-L73) -- [config.hpp:111-118](file://libraries/protocol/include/graphene/protocol/config.hpp#L111-L118) -- [node.cpp:3185-3384](file://libraries/network/node.cpp#L3185-L3384) -- [exceptions.hpp:27-48](file://libraries/network/include/graphene/network/exceptions.hpp#L27-L48) -- [p2p_plugin.cpp:225-424](file://plugins/p2p/p2p_plugin.cpp#L225-L424) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exceptions.hpp:21-46](file://libraries/protocol/include/graphene/protocol/exceptions.hpp#L21-L46) -- [stacktrace.cpp:1-78](file://thirdparty/fc/src/stacktrace.cpp#L1-L78) - -**Section sources** -- [database.hpp:1-670](file://libraries/chain/include/graphene/chain/database.hpp#L1-L670) -- [database.cpp:1-6760](file://libraries/chain/database.cpp#L1-L6760) -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [chainbase.cpp:1-200](file://thirdparty/chainbase/src/chainbase.cpp#L1-L200) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [block_log.cpp:1-302](file://libraries/chain/block_log.cpp#L1-L302) -- [dlt_block_log.hpp:1-80](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L80) -- [dlt_block_log.cpp:1-476](file://libraries/chain/dlt_block_log.cpp#L1-L476) -- [fork_database.hpp:1-144](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L144) -- [fork_database.cpp:1-278](file://libraries/chain/fork_database.cpp#L1-L278) -- [database_exceptions.hpp:1-136](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L1-L136) -- [db_with.hpp:1-154](file://libraries/chain/include/graphene/chain/db_with.hpp#L1-L154) -- [plugin.cpp:1180-1379](file://plugins/snapshot/plugin.cpp#L1180-L1379) -- [validator.cpp:270-469](file://plugins/validator/validator.cpp#L270-L469) -- [validator.hpp:38-73](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L38-L73) -- [config.hpp:111-118](file://libraries/protocol/include/graphene/protocol/config.hpp#L111-L118) -- [node.cpp:3185-3384](file://libraries/network/node.cpp#L3185-L3384) -- [exceptions.hpp:27-48](file://libraries/network/include/graphene/network/exceptions.hpp#L27-L48) -- [p2p_plugin.cpp:225-424](file://plugins/p2p/p2p_plugin.cpp#L225-L424) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exceptions.hpp:21-46](file://libraries/protocol/include/graphene/protocol/exceptions.hpp#L21-L46) -- [stacktrace.cpp:1-78](file://thirdparty/fc/src/stacktrace.cpp#L1-L78) - -## Core Components -- database class: Public interface for blockchain state management, block and transaction processing, checkpoints, and event notifications with enhanced DLT mode support, emergency consensus implementation, operation guard integration, improved error handling, and comprehensive debug logging capabilities. -- chainbase integration: Provides persistent object storage and undo sessions with enhanced memory management, operation_guard RAII pattern, and resize barrier mechanisms for concurrent access protection. -- block_log: Append-only block storage with random-access indexing. -- dlt_block_log: Rolling window block storage specifically designed for DLT (snapshot-based) nodes. -- fork_database: Maintains reversible blocks and supports fork selection and switching with emergency mode support and enhanced unlinkable block detection. -- signal_guard: Enhanced signal handling for graceful restart sequence management. -- **Enhanced Exception Handling**: Sophisticated exception preservation during rethrow operations using fc::exception_factory and dynamic_rethrow_exception for proper derived type restoration. -- **Enhanced Fork Database Management**: Comprehensive diagnostic capabilities with detailed logging for fork recovery operations, improved unlinkable block exception handling, and enhanced fork switching logic. -- **Enhanced Early Rejection Logic**: Intelligent block validation with gap-based decision system (≤100 gap deferred to fork_db, >100 gap rejected) for blocks far ahead with unknown parents. -- **Enhanced Fork Database Exception Prevention**: Proper unlinkable_block_exception throwing for dead fork detection and improved fork switching logic with deterministic tie-breaking. -- **Enhanced Memory Management**: Comprehensive logging system for shared memory allocation with detailed free memory and maximum memory state reporting, plus deferred resize operations. -- **Enhanced P2P Synchronization**: Improved unlinkable block classification with soft-banning for dead forks and sync restart prevention for far-ahead blocks. -- **Enhanced Operation Guard System**: Comprehensive concurrent access protection using operation_guard RAII pattern, dual operation guard patterns for validator scheduling safety, and resize barrier mechanisms. -- **Enhanced Multi-Layered Block Retrieval**: Systematic fallback mechanisms that check fork database when primary block log fails to locate required data, ensuring consistent behavior across different block logging configurations. -- **Enhanced Last Irreversible Block Advancement**: Enhanced logic that falls back to fork database when block log lacks required data, maintaining data consistency and availability. -- **Enhanced Emergency Consensus**: Automatic recovery system with comprehensive logging and safety checks for network stall detection and recovery. -- **Enhanced Shared Memory Corruption Detection**: New shared_memory_corruption_exception type for structured error handling during validator account validation and block processing. -- **Enhanced Auto-Recovery System**: Integrated automatic recovery from snapshot for shared memory corruption scenarios with comprehensive error handling and node restart procedures. -- **Enhanced Crash Debugging Capabilities**: Comprehensive debug_crash logging throughout critical code paths for improved crash diagnostics and troubleshooting. -- **Enhanced Block Production Debugging**: debug-block-production configuration option for detailed block production logging and monitoring. -- **Enhanced Stacktrace Crash Handlers**: Improved crash diagnostics with stacktrace generation and signal handling for fatal errors. -- **Enhanced DLT Gap Recovery**: Intelligent gap detection and recovery mechanisms with automatic gap recovery and warning suppression using _dlt_gap_logged flag. - -Key responsibilities: -- Lifecycle: open(), open_from_snapshot(), reindex(), close(), wipe() with improved error handling -- Validation: validate_block(), validate_transaction(), with configurable skip flags -- Operations: push_block(), push_transaction(), generate_block() with enhanced memory pressure handling and concurrent access protection -- DLT Mode: Conditional block log operations, rolling window management, snapshot-aware initialization -- Observers: signals for pre/post operation, applied block, pending/applied transactions -- Persistence: integrates with block_log and dlt_block_log for different operational modes -- Enhanced Block Fetching: DLT mode-aware block retrieval with proper validation logic and fallback mechanisms -- Enhanced Exception Preservation: Proper derived exception type restoration during rethrow operations -- Enhanced Fork Recovery: Comprehensive logging and error recovery for fork switching operations -- Enhanced Early Rejection: Intelligent block rejection for far-ahead blocks with unknown parents using gap-based decision system -- Enhanced Fork Database Exception Prevention: Comprehensive mechanisms to prevent fork database exceptions through early rejection and proper dead fork detection -- Enhanced Memory Management: Detailed logging of memory states before and after resizing operations for administrator visibility -- Enhanced P2P Protection: Operation guard integration in P2P plugin for safe concurrent access during block validation and validator key retrieval -- Enhanced validator Scheduling Safety: Dual operation guard patterns in validator scheduling calculations to ensure thread safety during slot determination and validator validation -- Enhanced Shared Memory Validation: Graceful error handling for validator account validation with structured exception reporting -- Enhanced Auto-Recovery Integration: Seamless integration with Validator Plugin for automatic recovery from shared memory corruption -- **Enhanced Crash Debugging**: Comprehensive debug_crash logging markers throughout database operations for improved troubleshooting -- **Enhanced Block Production Monitoring**: debug-block-production configuration option for detailed block production logging and monitoring -- **Enhanced Stacktrace Generation**: Automatic stacktrace generation for crash diagnostics and improved debugging experience -- **Enhanced DLT Gap Detection**: Intelligent gap detection in DLT block log with automatic recovery and warning suppression -- **Enhanced Gap Recovery Logging**: Comprehensive logging throughout gap detection and recovery workflow for better diagnostics - -**Section sources** -- [database.hpp:61-115](file://libraries/chain/include/graphene/chain/database.hpp#L61-L115) -- [database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [block_log.hpp:38-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L75) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [fork_database.hpp:53-144](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L144) -- [database.cpp:929-984](file://libraries/chain/database.cpp#L929-L984) -- [db_with.hpp:33-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L33-L100) -- [config.hpp:111-118](file://libraries/protocol/include/graphene/protocol/config.hpp#L111-L118) -- [chainbase.cpp:225-279](file://thirdparty/chainbase/src/chainbase.cpp#L225-L279) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exceptions.hpp:21-46](file://libraries/protocol/include/graphene/protocol/exceptions.hpp#L21-L46) -- [stacktrace.cpp:72-78](file://thirdparty/fc/src/stacktrace.cpp#L72-L78) - -## Architecture Overview -The database composes four primary subsystems with enhanced DLT mode support, emergency consensus implementation, operation guard integration, improved error handling, and comprehensive crash debugging capabilities: -- Chainbase: Persistent object database with undo/redo capabilities, operation_guard RAII pattern, and resize barrier mechanisms for concurrent access protection -- Fork database: Holds recent blocks for fork resolution with emergency mode support and enhanced unlinkable block detection -- Block log: Immutable, append-only block storage with index -- DLT block log: Rolling window block storage for DLT (snapshot-based) nodes -- Signal guard: Enhanced signal handling for graceful restart sequences -- **Enhanced Exception Handling Infrastructure**: Sophisticated exception preservation during rethrow operations using fc::exception_factory and dynamic_rethrow_exception for proper derived type restoration -- **Enhanced Fork Database Management**: Comprehensive diagnostic capabilities with detailed logging for fork recovery operations, improved unlinkable block exception handling, and enhanced fork switching logic -- **Enhanced Early Rejection Logic**: Intelligent block validation with gap-based decision system (≤100 gap deferred to fork_db, >100 gap rejected) for blocks far ahead with unknown parents -- **Enhanced Fork Database Exception Prevention**: Proper unlinkable_block_exception throwing for dead fork detection and improved fork switching logic with deterministic tie-breaking -- **Enhanced Memory Management**: Comprehensive logging system for shared memory allocation with detailed state reporting, plus deferred resize operations -- **Enhanced P2P Synchronization**: Improved unlinkable block classification with soft-banning for dead forks and sync restart prevention for far-ahead blocks -- **Enhanced Operation Guard System**: Comprehensive concurrent access protection using operation_guard RAII pattern, dual operation guard patterns for validator scheduling safety, and resize barrier mechanisms -- **Enhanced Multi-Layered Block Retrieval**: Systematic fallback mechanisms that check fork database when primary block log fails to locate required data, ensuring consistent behavior across different block logging configurations -- **Enhanced Last Irreversible Block Advancement**: Enhanced logic that falls back to fork database when block log lacks required data, maintaining data consistency and availability -- **Enhanced Emergency Consensus**: Automatic recovery system with comprehensive logging and safety checks for network stall detection and recovery -- **Enhanced Shared Memory Corruption Detection**: New shared_memory_corruption_exception type for structured error reporting during critical validation failures -- **Enhanced Auto-Recovery Integration**: Seamless integration with Validator Plugin for automatic recovery from shared memory corruption scenarios -- **Enhanced Crash Debugging System**: Comprehensive debug_crash logging throughout critical code paths for improved crash diagnostics and troubleshooting -- **Enhanced Block Production Monitoring**: debug-block-production configuration option for detailed block production logging and monitoring -- **Enhanced Stacktrace Crash Handlers**: Automatic stacktrace generation for crash diagnostics and improved debugging experience -- **Enhanced DLT Gap Recovery System**: Intelligent gap detection and automatic recovery mechanisms with warning suppression for improved diagnostics - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, ...) -+open_from_snapshot(data_dir, shared_mem_dir, initial_supply, shared_file_size, chainbase_flags) -+reindex(data_dir, shared_mem_dir, from_block_num, ...) -+close(rewind=true) -+push_block(block, skip_flags) -+push_transaction(trx, skip_flags) -+validate_block(block, skip_flags) -+validate_transaction(trx, skip_flags) -+set_dlt_mode(enabled) -+add_checkpoints(map) -+get_block_log() -+signals : pre_apply_operation, post_apply_operation, applied_block, on_pending_transaction, on_applied_transaction -+_dlt_mode : bool -+_dlt_block_log_max_blocks : uint32_t -+_dlt_gap_logged : bool -+_debug_block_production : bool -+signal_guard : enhanced error handling -+_maybe_warn_multiple_production(height) -+CHIAN_PENDING_TRANSACTION_EXECUTION_LIMIT : time limit constant -+emergency_consensus_activation : automatic recovery system -+hybrid_witness_scheduling : dynamic validator replacement -+lib_monitoring : timestamp analysis -+check_free_memory(skip_print, current_block_num, immediate_resize) -+set_min_free_shared_memory_size(value) -+set_inc_shared_memory_size(value) -+set_block_num_check_free_size(value) -+apply_pending_resize() : deferred memory resize -+_pending_resize : bool -+_pending_resize_target : size_t -+push_block(block, skip) : enhanced error handling -+apply_pending_resize() : thread-safe memory management -+enhanced_early_rejection_logic : gap-based decision system -+enhanced_fork_exception_prevention : comprehensive exception prevention -+make_operation_guard() : concurrent access protection -+begin_resize_barrier() : resize safety -+end_resize_barrier() : resize safety -+find_block_id_for_num(block_num) : enhanced multi-layered retrieval -+fetch_block_by_id(id) : enhanced multi-layered retrieval -+fetch_block_by_number(num) : enhanced multi-layered retrieval -+update_last_irreversible_block(skip) : enhanced fallback logic -+dynamic_rethrow_exception() : enhanced exception preservation -+shared_memory_corruption_detection : structured error handling -+auto_recovery_integration : seamless recovery procedures -+install_stacktrace_crash_handler() : crash diagnostics -+enhanced_dlt_gap_recovery : automatic gap recovery with warning suppression -} -class chainbase { -+free_memory() : size_t -+max_memory() : size_t -+reserved_memory() : size_t -+set_reserved_memory(value) -+resize(new_size) -+operation_guard : concurrent access protection -+begin_resize_barrier() : resize safety -+end_resize_barrier() : resize safety -} -class operation_guard { -+operation_guard(database& db) -+~operation_guard() -+release() : manual guard release -+operation_guard(operation_guard&& other) -} -class block_log { -+open(path) -+close() -+append(block) -+read_block_by_num(num) -+flush() -+head() -} -class dlt_block_log { -+open(path) -+close() -+append(block) -+read_block_by_num(num) -+truncate_before(new_start) -+head() -+num_blocks() -} -class fork_database { -+push_block(block) -+start_block(block) -+set_head(item) -+fetch_branch_from(first, second) -+set_max_size(n) -+set_emergency_mode(active) -+is_known_block(id) -+fetch_block_by_number(num) -+fetch_block_on_main_branch_by_number(num) -+is_emergency_mode() : emergency consensus mode flag -+remove_blocks_by_number(num) -+remove_blocks_by_number(num) -} -class signal_guard { -+setup() -+restore() -+get_is_interrupted() -+throw_exception() -} -class pending_transactions_restorer { -+pending_transactions_restorer(db, skip, pending) -+~pending_transactions_restorer() -+apply_trxs : bool -+applied_txs : uint32_t -+postponed_txs : uint32_t -} -class unlinkable_block_exception { -+inherits from chain_exception -+thrown for dead fork detection -+enhanced logging for fork recovery -} -class shared_memory_corruption_exception { -+inherits from chain_exception -+thrown for critical validation failures -+triggers automatic recovery procedures -+structured error reporting -} -class enhanced_early_rejection_logic { -+gap_based_decision_system(gap) -+defer_small_gaps_to_fork_db(gap) -+reject_large_gaps_immediately(gap) -+prevent_fork_db_exceptions(block) -+avoid_sync_restart_loops(block) -} -class enhanced_fork_exception_prevention { -+detect_dead_forks_at_or_below_head(block) -+prevent_fork_db_exceptions(block) -+classify_and_handle_unlinkable_blocks(block) -} -class exception_factory { -+rethrow(exception) : preserves derived types -+register_exception() : registers exception builders -} -class crash_debug_system { -+debug_crash_logging : comprehensive debug markers -+debug_block_production : detailed production logging -+stacktrace_crash_handlers : crash diagnostics -} -class dlt_gap_recovery_system { -+_dlt_gap_logged : bool flag for warning suppression -+detect_gap_in_dlt_log() : intelligent gap detection -+automatic_gap_recovery() : automatic recovery mechanisms -+suppress_repeated_warnings() : warning suppression logic -+enhanced_logging_for_recovery() : comprehensive recovery logging -} -database --> block_log : "uses (normal mode)" -database --> dlt_block_log : "uses (DLT mode)" -database --> fork_database : "uses with enhanced error handling" -database --> signal_guard : "enhanced restart handling" -database --> pending_transactions_restorer : "manages postponed tx" -database --> chainbase : "enhanced memory management with operation guards" -database --> unlinkable_block_exception : "enhanced fork handling" -database --> shared_memory_corruption_exception : "structured corruption detection" -database --> enhanced_early_rejection_logic : "gap-based decision system" -database --> enhanced_fork_exception_prevention : "comprehensive exception prevention" -database --> exception_factory : "enhanced exception preservation" -database --> crash_debug_system : "comprehensive crash debugging" -database --> dlt_gap_recovery_system : "automatic gap recovery with warning suppression" -chainbase --> operation_guard : "RAII concurrent access protection" -``` - -**Diagram sources** -- [database.hpp:61-115](file://libraries/chain/include/graphene/chain/database.hpp#L61-L115) -- [database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [block_log.hpp:38-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L75) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [fork_database.hpp:53-144](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L144) -- [database.cpp:94-184](file://libraries/chain/database.cpp#L94-L184) -- [db_with.hpp:33-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L33-L100) -- [chainbase.cpp:225-279](file://thirdparty/chainbase/src/chainbase.cpp#L225-L279) -- [database_exceptions.hpp:83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83) -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [stacktrace.cpp:72-78](file://thirdparty/fc/src/stacktrace.cpp#L72-L78) - -## Detailed Component Analysis - -### Database Lifecycle: Constructor, Destructor, and Methods -- Constructor and destructor: Initialize internal implementation and ensure pending transactions are cleared on destruction. -- open(): Initializes schema, opens shared memory, initializes indexes and evaluators, loads genesis if needed, opens both block_log and dlt_block_log, rewinds undo state, verifies chain consistency, and initializes hardfork state. **Enhanced** with DLT mode detection and graceful error handling. -- open_from_snapshot(): **Enhanced** - Sets DLT mode flag to true, wipes shared memory for clean state, initializes schema and chainbase, opens both block_log and dlt_block_log, and logs snapshot import progress. -- reindex(): **Enhanced** - Uses signal_guard for graceful restart handling, reads blocks sequentially from the block log with improved error propagation, applies them with aggressive skip flags to accelerate replay, periodically sets revision, checks free memory, and updates fork database head. -- close(): Clears pending transactions, flushes and closes chainbase, closes both block_log and dlt_block_log, resets fork database. -- wipe(): Closes database, wipes shared memory file, optionally removes both block_log and dlt_block_log. - -```mermaid -sequenceDiagram -participant App as "Application" -participant DB as "database" -participant SG as "signal_guard" -participant CB as "chainbase" -participant BL as "block_log" -participant DLT as "dlt_block_log" -App->>DB : open_from_snapshot(data_dir, shared_mem_dir, ...) -DB->>DB : _dlt_mode = true -DB->>CB : wipe(shared_mem_dir) -DB->>DB : init_schema() -DB->>CB : open(shared_mem_dir, flags, size) -DB->>DB : initialize_indexes() -DB->>DB : initialize_evaluators() -DB->>DB : with_strong_write_lock(init_genesis) -DB->>BL : open(data_dir/"block_log") -DB->>DLT : open(data_dir/"dlt_block_log") -App->>DB : reindex(data_dir, shared_mem_dir, from_block_num, ...) -DB->>SG : setup() -DB->>DB : with_strong_write_lock() -loop for each block -DB->>BL : read_block_by_num(block_num) -DB->>DB : apply_block(block, skip_flags) -DB->>DB : check_free_memory(...) -DB->>DB : signal_guard : get_is_interrupted()? -alt interrupted -DB->>SG : restore() -DB->>App : appbase : app().quit() -end -end -DB->>DLT : start_block(head) -``` - -**Diagram sources** -- [database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [database.cpp:330-410](file://libraries/chain/database.cpp#L330-L410) -- [database.cpp:134-184](file://libraries/chain/database.cpp#L134-L184) - -**Section sources** -- [database.hpp:61-115](file://libraries/chain/include/graphene/chain/database.hpp#L61-L115) -- [database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [database.cpp:503-519](file://libraries/chain/database.cpp#L503-L519) -- [database.cpp:330-410](file://libraries/chain/database.cpp#L330-L410) -- [database.cpp:134-184](file://libraries/chain/database.cpp#L134-L184) - -### Enhanced Exception Handling Infrastructure -**Updated** - The database now includes sophisticated exception handling infrastructure that preserves derived exception types during rethrow operations: - -- **Exception Factory Registration**: The fc::exception_factory system registers exception builders for proper type restoration during rethrow operations. -- **Dynamic Rethrow Support**: Enhanced dynamic_rethrow_exception() method that preserves derived exception types using exception_factory::rethrow(). -- **Protocol Exception Integration**: Protocol exceptions include dynamic_rethrow_exception() implementations that check code() values before rethrowing to ensure proper type restoration. -- **Enhanced Exception Propagation**: The database uses FC_LOG_AND_RETHROW macros that preserve exception types during logging and rethrow operations. -- **Unlinkable Block Exception Enhancement**: The unlinkable_block_exception now includes comprehensive logging for fork recovery operations with detailed block information and head block context. -- **Shared Memory Corruption Exception**: New shared_memory_corruption_exception type provides structured error handling for critical validation failures with detailed logging and automatic recovery integration. - -```mermaid -flowchart TD -Start(["Exception Occurs"]) --> Capture["Catch fc::exception"] -Capture --> Log["Log exception details"] -Log --> CheckType{"Exception type registered?"} -CheckType --> |Yes| Factory["exception_factory::rethrow()"] -Factory --> ReThrow["Rethrow as derived type"] -CheckType --> |No| DirectThrow["Direct throw (preserve type)"] -DirectThrow --> ReThrow -ReThrow --> Propagate["Propagate to caller"] -``` - -**Diagram sources** -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exceptions.hpp:21-46](file://libraries/protocol/include/graphene/protocol/exceptions.hpp#L21-L46) - -**Section sources** -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exceptions.hpp:21-46](file://libraries/protocol/include/graphene/protocol/exceptions.hpp#L21-L46) - -### Enhanced Fork Database Management with Diagnostic Capabilities -**Updated** - The fork database now includes comprehensive diagnostic capabilities and enhanced logging for fork recovery operations: - -- **Enhanced Unlinkable Block Logging**: Improved logging of fork database linking failures with detailed block information, head block context, and parent-child relationships. -- **Comprehensive Fork Recovery Logging**: Detailed logging for fork switching operations including branch comparison results, exception handling during fork recovery, and state restoration procedures. -- **Enhanced Error Recovery**: Systematic error recovery procedures during fork switching with proper state restoration and fork database cleanup. -- **Improved Fork Switching Logic**: Enhanced fork comparison logic with deterministic tie-breaking and comprehensive error handling for invalid fork scenarios. -- **Dead Fork Detection**: Proper identification and removal of stale competing blocks from fork database to prevent memory bloat and improve performance. - -```mermaid -flowchart TD -Start(["Fork Switch Attempt"]) --> CheckHead{"Head in fork_db?"} -CheckHead --> |No| Reject["Reject block (cannot switch)"] -CheckHead --> |Yes| CompareBranches["Compare fork branches"] -CompareBranches --> ComputeWeight["Compute branch weights"] -ComputeWeight --> DecideSwitch{"Should switch forks?"} -DecideSwitch --> |Yes| CheckEmergency{"Emergency mode?"} -DecideSwitch --> |No| KeepCurrent["Keep current fork"] -CheckEmergency --> |No| SwitchForks["Perform fork switch"] -CheckEmergency --> |Yes| CheckTie{"Tie at same height?"} -CheckTie --> |No| SwitchForks -CheckTie --> |Yes| TieBreak["Use deterministic hash tie-breaking"] -TieBreak --> SwitchForks -SwitchForks --> HandleExceptions["Handle exceptions during fork recovery"] -HandleExceptions --> LogRecovery["Log fork recovery operations"] -LogRecovery --> Cleanup["Clean up fork database"] -Cleanup --> UpdateHead["Update fork_db head"] -KeepCurrent --> End(["Complete"]) -UpdateHead --> End -``` - -**Diagram sources** -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [database.cpp:1440-1500](file://libraries/chain/database.cpp#L1440-L1500) - -**Section sources** -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [database.cpp:1440-1500](file://libraries/chain/database.cpp#L1440-L1500) -- [database_exceptions.hpp:83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83) - -### Enhanced Early Rejection Logic for Blocks Far Ahead with Unknown Parents -**New** - The database now includes sophisticated early rejection logic that prevents fork database exceptions and sync restart loops during snapshot imports: - -- **Gap-Based Decision System**: The `_push_block()` method implements a gap-based decision system that rejects blocks based on the gap between block number and head block number. -- **Small Gap Deferral**: Blocks with gaps ≤ 100 are deferred to fork_db unlinked index for automatic chain linking when parent blocks arrive. -- **Large Gap Rejection**: Blocks with gaps > 100 are immediately rejected to prevent memory bloat from dead-fork blocks. -- **Prevent Fork Database Exceptions**: Eliminates unnecessary fork database operations for blocks that would cause unlinkable_block_exception. -- **Avoid Sync Restart Loops**: Prevents P2P sync restart loops that would stall synchronization during snapshot imports. -- **Intelligent Parent Validation**: The system checks if the block's parent is known in the fork database before attempting fork database operations. -- **Safe First Block Acceptance**: The system always allows blocks whose previous equals the head block ID to ensure sync progress continues. - -```mermaid -flowchart TD -Start(["_push_block(new_block)"]) --> CheckAtOrBelow{"new_block.block_num() <= head_block_num()?"} -CheckAtOrBelow --> |Yes| CheckExisting{"existing_id == new_block.id()?"} -CheckExisting --> |Yes| IgnoreBlock["Ignore block (already on chain)"] -CheckExisting --> |No| CheckParent{"new_block.previous != block_id_type() && !_fork_db.is_known_block(new_block.previous)?"} -CheckParent --> |Yes| RejectDeadFork["Reject dead fork block"] -CheckParent --> |No| FallThrough["Fall through to normal logic"] -CheckAtOrBelow --> |No| CheckFarAhead{"new_block.block_num() > head_block_num() && new_block.previous != block_id_type() && !_fork_db.is_known_block(new_block.previous)?"} -CheckFarAhead --> |Yes| CheckGap{"gap = new_block.block_num() - head_block_num()"} -CheckGap --> |gap > 100| RejectLargeGap["Reject large gap (>100) immediately"] -CheckGap --> |gap <= 100| DeferSmallGap["Defer small gap (<=100) to fork_db"] -CheckFarAhead --> |No| CheckForkDB["Proceed to fork_db.push_block()"] -IgnoreBlock --> ReturnFalse["return false"] -RejectDeadFork --> ThrowException["Throw unlinkable_block_exception"] -FallThrough --> CheckForkDB -RejectLargeGap --> ReturnFalse -DeferSmallGap --> LogDefer["Log deferral to fork_db unlinked index"] -CheckForkDB --> ForkDBPush["fork_db.push_block(new_block)"] -ForkDBPush --> ReturnResult["return result"] -``` - -**Diagram sources** -- [database.cpp:1216-1286](file://libraries/chain/database.cpp#L1216-L1286) -- [database.cpp:1360-1380](file://libraries/chain/database.cpp#L1360-L1380) - -**Section sources** -- [database.cpp:1216-1286](file://libraries/chain/database.cpp#L1216-L1286) -- [database.cpp:1360-1380](file://libraries/chain/database.cpp#L1360-L1380) - -### Enhanced Fork Database Exception Prevention Mechanisms -**New** - The database now includes comprehensive mechanisms to prevent fork database exceptions through intelligent early rejection and proper dead fork detection: - -- **Dead Fork Detection at or Below Head**: Blocks at or below the head but on different forks whose parents are not in the fork database are immediately rejected with unlinkable_block_exception, enabling P2P layer to soft-ban the offending peer. -- **Gap-Based Large Gap Rejection**: Blocks far ahead of the head with gaps > 100 are silently rejected to prevent fork database operations and sync restart loops. -- **Proper Exception Classification**: The system distinguishes between dead fork blocks (at/below head) and far-ahead blocks that slipped past early rejection for proper P2P handling. -- **Enhanced Error Propagation**: Proper unlinkable_block_exception throwing ensures downstream components can classify and handle different types of unlinkable blocks appropriately. - -```mermaid -flowchart TD -Start(["Enhanced Fork Exception Prevention"]) --> CheckDeadFork{"Block at or below head on different fork?"} -CheckDeadFork --> |Yes| CheckParentKnown{"Parent in fork_db?"} -CheckParentKnown --> |No| ThrowDeadFork["Throw unlinkable_block_exception (dead fork)"] -CheckParentKnown --> |Yes| NormalLogic["Fall through to normal logic"] -CheckDeadFork --> |No| CheckFarAhead{"Block far ahead with unknown parent?"} -CheckFarAhead --> |Yes| CheckGap{"gap > 100?"} -CheckGap --> |Yes| RejectLargeGap["Reject large gap immediately"] -CheckGap --> |No| DeferSmallGap["Defer small gap to fork_db"] -CheckFarAhead --> |No| CheckForkDB["Proceed to fork_db.push_block()"] -ThrowDeadFork --> Classify["P2P soft-bans peer (dead fork)"] -RejectLargeGap --> PreventLoop["Prevent sync restart loops"] -DeferSmallGap --> LogDefer["Log deferral to fork_db"] -NormalLogic --> CheckForkDB -CheckForkDB --> ForkDBOps["Fork DB operations"] -ForkDBOps --> EnhancedHandling["Enhanced error handling"] -``` - -**Diagram sources** -- [database.cpp:1216-1286](file://libraries/chain/database.cpp#L1216-L1286) -- [p2p_plugin.cpp:175-192](file://plugins/p2p/p2p_plugin.cpp#L175-L192) -- [node.cpp:3192-3211](file://libraries/network/node.cpp#L3192-L3211) - -**Section sources** -- [database.cpp:1216-1286](file://libraries/chain/database.cpp#L1216-L1286) -- [p2p_plugin.cpp:175-192](file://plugins/p2p/p2p_plugin.cpp#L175-L192) -- [node.cpp:3192-3211](file://libraries/network/node.cpp#L3192-L3211) - -### Enhanced P2P Synchronization with Early Rejection Integration -**New** - The P2P synchronization system now integrates with the early rejection logic to prevent sync restart loops: - -- **Unlinkable Block Classification**: The P2P layer distinguishes between dead fork blocks (at or below head) and far-ahead blocks that slipped past early rejection. -- **Dead Fork Handling**: At-or-below-head blocks from dead forks trigger soft-banning to prevent continued transmission of stale blocks. -- **Far-Ahead Block Handling**: Far-ahead blocks trigger sync restart instead of soft-banning to allow sequential block fetching. -- **Deferred Resize Integration**: The P2P layer handles deferred resize scenarios by restarting sync to re-fetch missed blocks after memory operations complete. - -```mermaid -flowchart TD -Start(["P2P Block Processing"]) --> TryPush["Try push_block()"] -TryPush --> Success{"Client accepted?"} -Success --> |Yes| UpdatePeers["Update peer lists"] -Success --> |No| CheckException{"Exception type?"} -CheckException --> |unlinkable_block_exception| Classify["Classify unlinkable block"] -CheckException --> |other| HandleOther["Handle other exceptions"] -Classify --> CheckNum{"peer_block_num <= our_head?"} -CheckNum --> |Yes| SoftBan["Soft-ban peer (dead fork)"] -CheckNum --> |No| RestartSync["Restart sync (far-ahead)"] -SoftBan --> UpdatePeers -RestartSync --> UpdatePeers -HandleOther --> UpdatePeers -UpdatePeers --> End(["Complete"]) -``` - -**Diagram sources** -- [node.cpp:3185-3384](file://libraries/network/node.cpp#L3185-L3384) -- [p2p_plugin.cpp:181-196](file://plugins/p2p/p2p_plugin.cpp#L181-L196) - -**Section sources** -- [node.cpp:3185-3384](file://libraries/network/node.cpp#L3185-L3384) -- [p2p_plugin.cpp:181-196](file://plugins/p2p/p2p_plugin.cpp#L181-L196) - -### Enhanced Operation Guard Implementation for Concurrent Access Protection -**New** - The database now features comprehensive operation guard implementation for concurrent access protection: - -- **Operation Guard RAII Pattern**: The `operation_guard` class provides automatic concurrent access protection using RAII pattern, ensuring proper cleanup when guards go out of scope. -- **Dual Operation Guard Patterns**: Systematic implementation of dual operation guards in validator scheduling calculations to prevent race conditions during complex slot determination operations. -- **Resize Barrier Integration**: Operation guards participate in resize barrier mechanisms, blocking during memory resizing operations to prevent stale pointer issues. -- **P2P Plugin Protection**: Operation guard integration in P2P plugin for safe concurrent access during block validation and validator key retrieval operations. -- **validator Scheduling Safety**: Dual operation guard patterns ensure thread safety during validator scheduling calculations, protecting lockless reads from concurrent memory resizing. -- **Concurrent Resize Safety**: Enhanced resize barrier mechanisms that pause all database operations during memory resizing, preventing data corruption and stale pointer issues. - -```mermaid -flowchart TD -Start(["Operation Guard Usage"]) --> CheckCritical{"Critical Section?"} -CheckCritical --> |Yes| CreateGuard["auto op_guard = make_operation_guard()"] -CheckCritical --> |No| NormalOp["Normal Operation"] -CreateGuard --> ExecuteOp["Execute Critical Operation"] -ExecuteOp --> ReleaseGuard["op_guard.release() (optional)"] -ReleaseGuard --> End(["Complete"]) -NormalOp --> End -``` - -**Diagram sources** -- [database.cpp:1556-1588](file://libraries/chain/database.cpp#L1556-L1588) -- [database.cpp:1593-1594](file://libraries/chain/database.cpp#L1593-L1594) -- [validator.cpp:271-300](file://plugins/validator/validator.cpp#L271-L300) -- [validator.cpp:506-507](file://plugins/validator/validator.cpp#L506-L507) -- [p2p_plugin.cpp:232-243](file://plugins/p2p/p2p_plugin.cpp#L232-L243) - -**Section sources** -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [database.cpp:1556-1588](file://libraries/chain/database.cpp#L1556-L1588) -- [database.cpp:1593-1594](file://libraries/chain/database.cpp#L1593-L1594) -- [validator.cpp:271-300](file://plugins/validator/validator.cpp#L271-L300) -- [validator.cpp:506-507](file://plugins/validator/validator.cpp#L506-L507) -- [p2p_plugin.cpp:232-243](file://plugins/p2p/p2p_plugin.cpp#L232-L243) - -### Enhanced Memory Allocation Strategies and Shared Memory Configuration -**Updated** - The memory management system now includes comprehensive logging capabilities for shared memory allocation and a new deferred resize mechanism: - -- **Auto-resize with Detailed Logging**: When free memory drops below a configured threshold, the system increases shared memory size and logs detailed state information including free memory, maximum memory, and reserved memory before and after resizing operations. -- **Enhanced Free Memory Monitoring**: Periodic checks at configured block intervals log free memory and trigger resizing if needed, with comprehensive state reporting for administrator visibility. -- **Reserved Memory Management**: Prevents fragmentation by reserving a portion of available memory and provides detailed logging of reserved memory states. -- **Configuration Knobs**: Minimum free memory threshold, increment size, and block interval for checks with enhanced monitoring capabilities. -- **Comprehensive Memory State Reporting**: The `_resize` function now logs detailed information about memory states before and after resizing operations, providing administrators with crucial information about memory usage patterns during blockchain operation. -- **Deferred Memory Resize**: The new `_pending_resize` and `_pending_resize_target` fields store resize requests until a safe point when no read locks are held, preventing race conditions and stale pointer issues. -- **Thread-Safe Memory Management**: The `apply_pending_resize()` method acquires its own write lock, waiting for all readers to finish before performing memory operations, ensuring thread safety during high-load scenarios. -- **Enhanced Error Handling**: Graceful handling of boost::interprocess::bad_alloc exceptions by returning false instead of throwing, preserving peer connectivity and logging validator slot-misses. - -```mermaid -flowchart TD -Entry(["check_free_memory(block_num)"]) --> ModCheck["block_num % _block_num_check_free_memory == 0?"] -ModCheck --> |No| Exit(["Return"]) -ModCheck --> |Yes| Compute["Compute reserved and free memory"] -Compute --> Compare{"free_mem < min_free_shared_memory_size?"} -Compare --> |No| Exit -Compare --> |Yes| Resize["_resize(block_num, immediate_resize)"] -Resize --> Exit -``` - -**Diagram sources** -- [database.cpp:639-673](file://libraries/chain/database.cpp#L639-L673) -- [database.cpp:562-605](file://libraries/chain/database.cpp#L562-L605) - -**Section sources** -- [database.cpp:562-605](file://libraries/chain/database.cpp#L562-L605) -- [database.cpp:639-673](file://libraries/chain/database.cpp#L639-L673) -- [database.cpp:412-422](file://libraries/chain/database.cpp#L412-L422) -- [database.cpp:454-482](file://libraries/chain/database.cpp#L454-L482) -- [chainbase.cpp:225-279](file://thirdparty/chainbase/src/chainbase.cpp#L225-L279) - -### Enhanced Memory Management Logging System -**New** - The database now includes comprehensive memory management logging capabilities: - -- **Detailed Resize Logging**: The `_resize` function logs comprehensive information including block number, new memory size, free memory before resizing, and maximum memory before resizing. -- **Post-Resize State Reporting**: After memory resizing, the system logs the current free memory and reserved memory states to provide administrators with immediate feedback on memory allocation changes. -- **Memory State Consistency**: The system ensures that memory state reporting accounts for reserved memory and provides accurate free memory calculations. -- **Administrator Visibility**: Enhanced logging provides administrators with detailed insights into memory usage patterns and helps identify potential memory pressure situations before they impact system performance. -- **Deferred Resize Logging**: The `apply_pending_resize()` method logs detailed information about deferred resize operations, including target memory size and completion status. - -```mermaid -flowchart TD -Start(["_resize(current_block_num, immediate)"]) --> CheckConfig{"_inc_shared_memory_size != 0?"} -CheckConfig --> |No| LogError["elog('Auto-scaling not configured!')"] -CheckConfig --> |Yes| GetStates["Get max_mem and free_mem_before"] -GetStates --> CalculateNew["Calculate new_max = max_mem + _inc_shared_memory_size"] -CalculateNew --> CheckImmediate{"immediate?"} -CheckImmediate --> |No| LogDeferred["wlog deferred resize info"] -LogDeferred --> SetFlags["_pending_resize = true, _pending_resize_target = new_max"] -SetFlags --> ReturnTrue["return true"] -CheckImmediate --> |Yes| LogResize["wlog immediate resize info"] -LogResize --> ResizeFile["resize(new_max)"] -ResizeFile --> GetPostState["Get free_mem and reserved_mem"] -GetPostState --> LogState["wlog free and reserved memory states"] -LogState --> UpdatePrinted["Update _last_free_gb_printed"] -UpdatePrinted --> ReturnTrue -``` - -**Diagram sources** -- [database.cpp:562-605](file://libraries/chain/database.cpp#L562-L605) - -**Section sources** -- [database.cpp:562-605](file://libraries/chain/database.cpp#L562-L605) - -### Enhanced Memory Management Configuration Options -**New** - The database now provides enhanced configuration options for memory management: - -- **set_min_free_shared_memory_size(value)**: Configures the minimum free memory threshold that triggers automatic resizing operations. -- **set_inc_shared_memory_size(value)**: Sets the increment size for shared memory file expansion when the minimum free memory threshold is exceeded. -- **set_block_num_check_free_size(value)**: Configures the block interval for checking free memory and triggering resize operations. -- **Enhanced Memory Monitoring**: The system provides comprehensive monitoring of memory states with detailed logging and reporting capabilities. -- **apply_pending_resize()**: New method that applies deferred memory resize operations at safe points when no read locks are held. - -**Section sources** -- [database.hpp:148-164](file://libraries/chain/include/graphene/chain/database.hpp#L148-L164) -- [database.cpp:546-556](file://libraries/chain/database.cpp#L546-L556) - -### Enhanced Memory Management Fields -**New** - The database now includes two new fields for deferred memory management: - -- **_pending_resize**: A boolean flag indicating whether a memory resize operation is pending and should be applied at the next safe point. -- **_pending_resize_target**: Stores the target memory size for deferred resize operations, allowing the system to apply the resize when thread safety permits. - -These fields enable the deferred resize mechanism to work seamlessly with the existing memory management system while ensuring thread safety during high-load scenarios. - -**Section sources** -- [database.hpp:631-632](file://libraries/chain/include/graphene/chain/database.hpp#L631-L632) - -### Enhanced Memory Management Usage in Block Processing -**New** - The deferred memory resize mechanism is integrated into the block processing pipeline: - -- **push_block()**: Calls `apply_pending_resize()` at the beginning of block processing, before acquiring the main write lock, ensuring memory operations don't interfere with concurrent read operations. -- **generate_block()**: Calls `apply_pending_resize()` before lockless reads, preventing stale pointer issues when memory is resized during block generation. -- **Exception Handling**: When memory exhaustion occurs, the system schedules a deferred resize and lets the exception propagate, preserving peer connectivity and logging validator slot-misses. - -**Updated** - Enhanced error handling for shared memory exhaustion: - -- **Graceful Exception Handling**: The push_block() method now catches boost::interprocess::bad_alloc exceptions and handles them gracefully. -- **Peer Connectivity Preservation**: Instead of throwing exceptions that would disconnect peers, the system returns false and schedules a deferred resize. -- **Memory State Preservation**: The system preserves memory state by setting reserved memory to current free memory before scheduling resize. -- **Automatic Recovery**: The next push_block() call will apply the deferred resize safely, allowing the missed block to be re-received during normal sync. - -**Enhanced Error Handling for Memory Allocation Failures** - The push_block() function now includes sophisticated error handling for boost::interprocess::bad_alloc exceptions: - -- **Exception Detection**: The system detects boost::interprocess::bad_alloc exceptions by searching for the specific error message pattern "boost::interprocess::bad_alloc". -- **Graceful Degradation**: Instead of throwing the exception and potentially disconnecting peers, the system schedules a deferred resize and returns false to indicate the block was not applied. -- **State Preservation**: The system preserves memory state by setting reserved memory to current free memory level before scheduling the resize. -- **Peer Connectivity**: This approach prevents P2P layer disconnections and maintains validator slot-miss logging while preserving node connectivity. -- **Automatic Recovery**: The next push_block() call will apply the deferred resize safely, allowing the missed block to be re-received during normal sync. - -```mermaid -flowchart TD -Start(["push_block(new_block)"]) --> ApplyResize["apply_pending_resize()"] -ApplyResize --> AcquireLock["with_strong_write_lock()"] -AcquireLock --> TryBlock["_push_block(new_block, skip)"] -TryBlock --> CheckMemory["check_free_memory(false, new_block.block_num())"] -CheckMemory --> Success["Return result"] -TryBlock --> Exception{"Memory exception?"} -Exception --> |Yes| CheckBadAlloc{"boost::interprocess::bad_alloc?"} -CheckBadAlloc --> |No| Rethrow["throw e"] -CheckBadAlloc --> |Yes| ScheduleResize["set_reserved_memory(free_memory())"] -ScheduleResize --> SetPending["_resize(new_block.block_num())"] -SetPending --> ReturnFalse["result = false"] -Exception --> |No| Success -``` - -**Diagram sources** -- [database.cpp:1106-1145](file://libraries/chain/database.cpp#L1106-L1145) -- [database.cpp:1460-1470](file://libraries/chain/database.cpp#L1460-L1470) - -**Section sources** -- [database.cpp:1106-1145](file://libraries/chain/database.cpp#L1106-L1145) -- [database.cpp:1460-1470](file://libraries/chain/database.cpp#L1460-L1470) - -### Enhanced Fork Database Handling with Unlinkable Block Exception -**Updated** - The fork database now includes enhanced error handling for proper dead fork detection: - -- **Proper Exception Throwing**: The fork_database::push_block() method now properly throws unlinkable_block_exception when blocks fail to link, enabling better dead fork detection. -- **Enhanced Logging**: Improved logging of fork database linking failures with detailed block information and head block context. -- **Unlinked Block Caching**: Previously unlinked blocks are cached in _unlinked_index for later processing when their parents become available. -- **Improved Fork Switching**: The database's fork switching logic now properly handles unlinkable_block_exception to prevent processing blocks from dead forks. -- **Deterministic Tie-Breaking**: During emergency consensus mode, blocks with identical heights are selected deterministically using block_id hash comparison. - -```mermaid -flowchart TD -Start(["fork_database::push_block(block)"]) --> TryPush["_push_block(item)"] -TryPush --> Success{"Link successful?"} -Success --> |Yes| CheckEmergency{"Emergency mode?"} -CheckEmergency --> |No| ReturnHead["Return _head"] -CheckEmergency --> |Yes| CheckHeight{"Same height as head?"} -CheckHeight --> |No| ReturnHead -CheckHeight --> |Yes| CheckHash{"item.id < _head->id?"} -CheckHash --> |Yes| SetHead["Set _head = item"] -CheckHash --> |No| KeepHead["Keep current head"] -Success --> |No| CacheUnlinked["Cache in _unlinked_index"] -CacheUnlinked --> ThrowException["Throw unlinkable_block_exception"] -ThrowException --> Propagate["Propagate to caller"] -ReturnHead --> Propagate -SetHead --> Propagate -KeepHead --> Propagate -``` - -**Diagram sources** -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) - -**Section sources** -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [database_exceptions.hpp:83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83) - -### Enhanced Fork Switching Logic with Dead Fork Detection and Deterministic Tie-Breaking -**Updated** - The database's fork switching logic now includes improved dead fork detection and emergency consensus tie-breaking: - -- **Dead Fork Detection**: When attempting to switch forks, the system checks if the current head block exists in the fork database before proceeding. -- **Proper Exception Handling**: If the head block is not in the fork database, the system removes the candidate block and throws unlinkable_block_exception. -- **Enhanced Branch Comparison**: Improved fork comparison logic with proper handling of emergency consensus mode tie-breaking using deterministic hash-based selection. -- **Safe Fork Switching**: The system ensures fork switching only occurs when both chains are valid and linked to the current state. -- **Emergency Consensus Tie-Breaking**: During emergency mode, identical-height blocks are selected deterministically by comparing block_id hashes. - -```mermaid -flowchart TD -Start(["Fork Switch Decision"]) --> CheckHead{"Head in fork_db?"} -CheckHead --> |No| RejectFork["Remove candidate block"] -RejectFork --> ThrowException["Throw unlinkable_block_exception"] -CheckHead --> |Yes| CompareBranches["Compare fork branches"] -CompareBranches --> ComputeWeight["Compute branch weights"] -ComputeWeight --> DecideSwitch{"Should switch forks?"} -DecideSwitch --> |Yes| CheckEmergency{"Emergency mode?"} -DecideSwitch --> |No| KeepCurrent["Keep current fork"] -CheckEmergency --> |No| SwitchForks["Perform fork switch"] -CheckEmergency --> |Yes| CheckTie{"Tie at same height?"} -CheckTie --> |No| SwitchForks -CheckTie --> |Yes| TieBreak["Use deterministic hash tie-breaking"] -TieBreak --> SwitchForks -SwitchForks --> UpdateHead["Update fork_db head"] -KeepCurrent --> End(["Complete"]) -UpdateHead --> End -``` - -**Diagram sources** -- [database.cpp:1295-1377](file://libraries/chain/database.cpp#L1295-L1377) - -**Section sources** -- [database.cpp:1295-1377](file://libraries/chain/database.cpp#L1295-L1377) - -### Enhanced Multi-Layered Block Retrieval System -**New** - The database now implements comprehensive multi-layered block retrieval with systematic fallback mechanisms: - -- **Hierarchical Retrieval Strategy**: The `find_block_id_for_num()`, `fetch_block_by_id()`, and `fetch_block_by_number()` methods implement a three-tiered retrieval system: - 1. Primary: Check fork database for current/main branch blocks - 2. Secondary: Check block log for irreversible blocks - 3. Tertiary: Check DLT block log as fallback in DLT mode - 4. Final: Query fork database for any available blocks - -- **DLT Mode Awareness**: In DLT mode, the system prioritizes DLT block log as secondary storage while maintaining fallback to block log and fork database. -- **Consistent Behavior**: This ensures that block retrieval works consistently regardless of which storage layer contains the requested data. -- **Enhanced Fault Tolerance**: Multiple fallback points prevent single points of failure and improve system reliability. - -```mermaid -flowchart TD -Start(["Block Retrieval Request"]) --> CheckForkDB["Check fork database (primary)"] -CheckForkDB --> FoundFork{"Found in fork_db?"} -FoundFork --> |Yes| ReturnFork["Return from fork_db"] -FoundFork --> |No| CheckBlockLog["Check block_log (secondary)"] -CheckBlockLog --> FoundBlockLog{"Found in block_log?"} -FoundBlockLog --> |Yes| ReturnBlockLog["Return from block_log"] -FoundBlockLog --> |No| CheckDLT{"DLT mode enabled?"} -CheckDLT --> |Yes| CheckDLTLog["Check dlt_block_log (fallback)"] -CheckDLTLog --> FoundDLT{"Found in dlt_block_log?"} -FoundDLT --> |Yes| ReturnDLT["Return from dlt_block_log"] -FoundDLT --> |No| CheckFinalFork["Check fork_db for any blocks"] -CheckFinalFork --> FoundAny{"Found in fork_db?"} -FoundAny --> |Yes| ReturnAny["Return from fork_db"] -FoundAny --> |No| ReturnNull["Return null"] -``` - -**Diagram sources** -- [database.cpp:789-827](file://libraries/chain/database.cpp#L789-L827) -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) -- [database.cpp:884-901](file://libraries/chain/database.cpp#L884-L901) - -**Section sources** -- [database.cpp:789-827](file://libraries/chain/database.cpp#L789-L827) -- [database.cpp:860-882](file://libraries/chain/database.cpp#L860-L882) -- [database.cpp:884-901](file://libraries/chain/database.cpp#L884-L901) - -### Enhanced Last Irreversible Block Advancement Logic -**New** - The `update_last_irreversible_block()` method now includes comprehensive fallback mechanisms: - -- **Primary Block Log Check**: First attempts to retrieve the irreversible block from the primary block log -- **Fork Database Fallback**: If block log retrieval fails, checks the fork database for the same block number -- **Consistent ID Assignment**: Uses the fork database block data when available to maintain consistency -- **Enhanced Error Handling**: Prevents crashes when blocks are missing from block log while ensuring proper LIB advancement - -```mermaid -flowchart TD -Start(["update_last_irreversible_block()"]) --> CheckMode{"Normal mode or DLT mode?"} -CheckMode --> |Normal Mode| CheckBlockLog["Read LIB from block_log"] -CheckBlockLog --> CheckValid{"Block valid?"} -CheckValid --> |Yes| SetLIB["Set LIB ID from block_log"] -CheckValid --> |No| CheckForkDB["Check fork_db for LIB block"] -CheckForkDB --> CheckForkValid{"Fork block valid?"} -CheckForkValid --> |Yes| SetLIBFork["Set LIB ID from fork_db"] -CheckForkValid --> |No| ClearLIB["Clear LIB fields"] -CheckMode --> |DLT Mode| CheckDLTLog["Read LIB from dlt_block_log"] -CheckDLTLog --> CheckDLTValid{"DLT block valid?"} -CheckDLTValid --> |Yes| SetLIBDLT["Set LIB ID from dlt_block_log"] -CheckDLTValid --> |No| CheckForkDBDLT["Check fork_db for LIB block"] -CheckForkDBDLT --> CheckForkValidDLT{"Fork block valid?"} -CheckForkValidDLT --> |Yes| SetLIBForkDLT["Set LIB ID from fork_db"] -CheckForkValidDLT --> |No| ClearLIB -SetLIB --> UpdateFields["Update LIB reference fields"] -SetLIBFork --> UpdateFields -SetLIBDLT --> UpdateFields -SetLIBForkDLT --> UpdateFields -ClearLIB --> End(["Complete"]) -UpdateFields --> End -``` - -**Diagram sources** -- [database.cpp:5452-5482](file://libraries/chain/database.cpp#L5452-L5482) -- [database.cpp:5467-5480](file://libraries/chain/database.cpp#L5467-L5480) - -**Section sources** -- [database.cpp:5452-5482](file://libraries/chain/database.cpp#L5452-L5482) -- [database.cpp:5467-5480](file://libraries/chain/database.cpp#L5467-L5480) - -### Enhanced Block Number Collision Detection and Logging -**New** - The database now features sophisticated collision detection with rate-limiting and scenario differentiation: - -- **Same-Parent vs Different-Parent Detection**: The system differentiates between same-parent double production (colliding blocks from the same parent) and different-parent fork scenarios (divergent chain tips). -- **Rate-Limited Warnings**: Uses a static counter and timestamp to suppress repeated warnings at the same block height to avoid log spam during sustained fork conditions. -- **Timestamp Delta Analysis**: Calculates time differences between colliding blocks to help diagnose timing issues. -- **validator Information Logging**: Logs validator names and timestamps for all colliding blocks to aid in forensic analysis. -- **Parent Block ID Tracking**: Records previous block IDs to help analyze fork topology and collision origins. - -```mermaid -flowchart TD -Start(["Block Height Collision"]) --> FetchBlocks["fetch_block_by_number(height)"] -FetchBlocks --> CheckSize{"blocks.size() > 1?"} -CheckSize --> |No| Return["No collision"] -CheckSize --> |Yes| ExtractInfo["Extract validator, timestamp, previous_id"] -ExtractInfo --> SameParent{"all previous_ids identical?"} -SameParent --> |Yes| DoubleProd["Same Parent - Possible Double Production"] -SameParent --> |No| ForkScenario["Different Parents - Fork Scenario"] -DoubleProd --> RateLimit["Check rate limit (5s window)"] -ForkScenario --> RateLimit -RateLimit --> ShouldLog{"Should log warning?"} -ShouldLog --> |No| Return -ShouldLog --> |Yes| LogWarning["Log collision with scenario differentiation"] -LogWarning --> UpdateState["Update last_warned_height/time"] -UpdateState --> LogParents["Log previous block IDs for topology analysis"] -LogParents --> Return -``` - -**Diagram sources** -- [database.cpp:1147-1202](file://libraries/chain/database.cpp#L1147-L1202) - -**Section sources** -- [database.cpp:1147-1202](file://libraries/chain/database.cpp#L1147-L1202) - -### Enhanced Postponed Transaction Processing -**New** - The database now implements intelligent transaction queuing with time-based execution limits: - -- **Time-Based Execution Limits**: Uses `CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT` constant to control processing time per batch. -- **Automatic Queue Management**: When execution time exceeds the limit, transactions are automatically postponed to the next processing cycle. -- **Smart Recovery**: The `pending_transactions_restorer` class handles recovery after fork switches, attempting to reapply transactions within time limits. -- **Progressive Application**: Processes transactions in batches, applying as many as possible within the time limit, with postponed transactions moved to the pending queue. -- **Diagnostic Logging**: Logs the number of applied and postponed transactions to monitor system performance. - -```mermaid -flowchart TD -Start(["Transaction Processing"]) --> CheckTime["Check time elapsed < CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT"] -CheckTime --> |Within Limit| ApplyTx["Apply transaction immediately"] -CheckTime --> |Exceeded Limit| Postpone["Add to postponed queue"] -ApplyTx --> NextTx["Next transaction"] -Postpone --> NextTx -NextTx --> MoreTx{"More transactions?"} -MoreTx --> |Yes| CheckTime -MoreTx --> |No| Complete["Complete processing"] -Complete --> Recovery["pending_transactions_restorer recovery"] -Recovery --> BatchApply["Batch apply within time limit"] -BatchApply --> Finalize["Finalize processing"] -``` - -**Diagram sources** -- [db_with.hpp:33-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L33-L100) - -**Section sources** -- [db_with.hpp:33-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L33-L100) - -### Validation Steps Enumeration and Use Cases -Validation flags control which checks are performed during block and transaction validation: -- skip_nothing: Perform all validations -- skip_witness_signature: Skip validator signature verification (used during reindex) -- skip_transaction_signatures: Skip transaction signatures (used by non-validator nodes) -- skip_transaction_dupe_check: Skip duplicate transaction checks -- skip_fork_db: Skip fork database checks -- skip_block_size_check: Allow oversized blocks when generating locally -- skip_tapos_check: Skip TaPoS and expiration checks -- skip_authority_check: Skip authority checks -- skip_merkle_check: Skip Merkle root verification -- skip_undo_history_check: Skip undo history bounds -- skip_witness_schedule_check: Skip validator schedule validation -- skip_validate_operations: Skip operation validation -- skip_undo_block: Skip undo db on reindex -- skip_block_log: Skip writing to block log (used in DLT mode) -- skip_apply_transaction: Skip applying transaction -- skip_database_locking: Skip database locking - -Typical usage: -- Reindex uses a combination of flags to accelerate replay -- Block generation may skip certain checks for local blocks -- Validation-only nodes may skip expensive checks -- DLT mode uses skip_block_log to avoid normal block log operations - -**Section sources** -- [database.hpp:79-96](file://libraries/chain/include/graphene/chain/database.hpp#L79-L96) -- [database.cpp:340-350](file://libraries/chain/database.cpp#L340-L350) -- [database.cpp:4346-4366](file://libraries/chain/database.cpp#L4346-L4366) - -### Session Management and Undo Semantics -- Pending transaction session: A temporary undo session is created when pushing the first transaction after applying a block; successful transactions merge into the pending block session. -- Block application session: A strong write lock wraps block application; a temporary undo session is used per transaction; upon success, the session is pushed. -- Undo history: Enforced with bounds; last irreversible block advancement commits revisions and writes to appropriate block log based on DLT mode. - -```mermaid -flowchart TD -Start(["push_transaction(trx, skip)"]) --> CheckSession["Check _pending_tx_session.valid()"] -CheckSession --> |No| NewSession["start_undo_session() -> _pending_tx_session"] -CheckSession --> |Yes| UseExisting["Use existing _pending_tx_session"] -NewSession --> TempSession["start_undo_session() -> temp_session"] -UseExisting --> TempSession -TempSession --> ApplyTx["_apply_transaction(trx, skip)"] -ApplyTx --> Success{"Apply success?"} -Success --> |Yes| Merge["temp_session.squash()"] -Merge --> CheckDLT{"_dlt_mode?"} -CheckDLT --> |No| WriteNormal["Write to block_log"] -CheckDLT --> |Yes| WriteDLT["Write to dlt_block_log"] -WriteNormal --> Notify["notify_on_pending_transaction(trx)"] -WriteDLT --> Notify -Success --> |No| Discard["temp_session destructor discards changes"] -Notify --> End(["Return"]) -Discard --> End -``` - -**Diagram sources** -- [database.cpp:948-970](file://libraries/chain/database.cpp#L948-L970) -- [database.cpp:3652-3711](file://libraries/chain/database.cpp#L3652-L3711) - -**Section sources** -- [database.cpp:948-970](file://libraries/chain/database.cpp#L948-L970) -- [database.cpp:3652-3711](file://libraries/chain/database.cpp#L3652-L3711) - -### Checkpoint System for Fast Synchronization -- Checkpoints: A map of block number to expected block ID is maintained; when a checkpoint matches, the system skips expensive validations and authority checks for subsequent blocks until the last checkpoint. -- before_last_checkpoint(): Determines whether the current head is before the last checkpoint to decide whether to enforce stricter checks. - -```mermaid -flowchart TD -Start(["apply_block(block, skip)"]) --> HasCheckpoints{"_checkpoints.size() > 0?"} -HasCheckpoints --> |No| Apply["_apply_block(..., skip)"] -HasCheckpoints --> |Yes| Match{"Checkpoint present for block_num?"} -Match --> |Yes| Tighten["Set skip flags for strict checks"] -Tighten --> Apply -Match --> |No| Apply -``` - -**Diagram sources** -- [database.cpp:3444-3499](file://libraries/chain/database.cpp#L3444-L3499) - -**Section sources** -- [database.hpp:218-224](file://libraries/chain/include/graphene/chain/database.hpp#L218-L224) -- [database.cpp:3444-3499](file://libraries/chain/database.cpp#L3444-L3499) - -### Block Log Integration and Last Irreversible Block Advancement -**Enhanced** - The block log integration now includes improved gap handling for DLT mode: - -- Block log: Append-only storage with a secondary index enabling O(1) random access by block number. -- DLT Block Log: Rolling window storage for DLT mode nodes, maintaining a configurable number of recent blocks. -- IRV advancement: When sufficient validator validations are collected, the system advances last irreversible block, commits the revision, writes blocks to appropriate log based on DLT mode, and updates dynamic global properties with reference fields. -- **Enhanced Gap Logging**: Improved logging for DLT block log gaps during block processing to help diagnose synchronization issues with contextual information. - -```mermaid -sequenceDiagram -participant DB as "database" -participant FD as "fork_database" -participant BL as "block_log" -participant DLT as "dlt_block_log" -participant DGP as "dynamic_global_property_object" -DB->>DB : check_block_post_validation_chain() -alt Enough validations -DB->>DGP : last_irreversible_block_num++ -DB->>DB : commit(last_irreversible_block_num) -alt Normal mode -DB->>BL : append(block) (if not skipping) -else DLT mode with rolling window -DB->>DLT : append(block) -DB->>DLT : flush() -DB->>DLT : truncate_before() if needed -end -DB->>DGP : update last_irreversible_block_id/ref fields -DB->>FD : set_max_size(head - LRI + 1) -end -``` - -**Diagram sources** -- [database.cpp:3986-4039](file://libraries/chain/database.cpp#L3986-L4039) -- [database.cpp:4144-4175](file://libraries/chain/database.cpp#L4144-L4175) -- [database.cpp:4346-4366](file://libraries/chain/database.cpp#L4346-L4366) - -**Section sources** -- [block_log.hpp:38-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L75) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [database.cpp:3986-4039](file://libraries/chain/database.cpp#L3986-L4039) -- [database.cpp:4144-4175](file://libraries/chain/database.cpp#L4144-L4175) -- [database.cpp:4346-4366](file://libraries/chain/database.cpp#L4346-L4366) - -### Observer Pattern Implementation -The database exposes signals for event-driven state changes: -- pre_apply_operation: Emitted before applying an operation -- post_apply_operation: Emitted after applying an operation -- applied_block: Emitted after a block is applied and committed -- on_pending_transaction: Emitted when a transaction is added to the pending state -- on_applied_transaction: Emitted when a transaction is applied to the chain state - -These signals are used by plugins to react to blockchain events without tight coupling. - -**Section sources** -- [database.hpp:284-307](file://libraries/chain/include/graphene/chain/database.hpp#L284-L307) -- [database.cpp:1158-1198](file://libraries/chain/database.cpp#L1158-L1198) -- [database.cpp:3652-3655](file://libraries/chain/database.cpp#L3652-L3655) - -### Enhanced Crash Debugging Capabilities -**New** - The database now includes comprehensive crash debugging capabilities with debug_crash logging throughout critical code paths: - -- **Comprehensive Debug Logging**: Extensive debug_crash logging markers (DEBUG_CRASH) throughout database operations including push_block, update_witness_schedule, schedule normal build, hybrid override, process_funds, notify_applied_block, and notify_changed_objects. -- **Block Production Monitoring**: The debug-block-production configuration option enables detailed block production logging and monitoring for troubleshooting production issues. -- **Stacktrace Crash Handlers**: Enhanced stacktrace crash handlers provide automatic stacktrace generation for crash diagnostics, improving debugging experience for fatal errors. -- **Enhanced Diagnostic Visibility**: Debug logging throughout critical code paths provides comprehensive visibility into database operations for improved troubleshooting and performance analysis. - -The debug_crash logging system includes markers for: -- push_block operations with validator information -- validator schedule updates and emergency consensus handling -- block production scheduling and execution -- fund processing and block notification cycles -- LIB advancement and fork database operations - -**Section sources** -- [database.cpp:1890-1892](file://libraries/chain/database.cpp#L1890-L1892) -- [database.cpp:2281-2283](file://libraries/chain/database.cpp#L2281-L2283) -- [database.cpp:2466-2467](file://libraries/chain/database.cpp#L2466-L2467) -- [database.cpp:2526-2527](file://libraries/chain/database.cpp#L2526-L2527) -- [database.cpp:2536-2537](file://libraries/chain/database.cpp#L2536-L2537) -- [database.cpp:4536-4537](file://libraries/chain/database.cpp#L4536-L4537) -- [database.cpp:4538-4539](file://libraries/chain/database.cpp#L4538-L4539) -- [database.cpp:4544-4545](file://libraries/chain/database.cpp#L4544-L4545) -- [database.cpp:4567-4568](file://libraries/chain/database.cpp#L4567-L4568) -- [database.cpp:4569-4570](file://libraries/chain/database.cpp#L4569-L4570) -- [database.cpp:4571-4572](file://libraries/chain/database.cpp#L4571-L4572) -- [database.cpp:4573-4574](file://libraries/chain/database.cpp#L4573-L4574) -- [database.cpp:5530-5531](file://libraries/chain/database.cpp#L5530-L5531) -- [database.cpp:5543-5544](file://libraries/chain/database.cpp#L5543-L5544) -- [database.cpp:5677-5678](file://libraries/chain/database.cpp#L5677-L5678) -- [database.cpp:5680-5681](file://libraries/chain/database.cpp#L5680-L5681) - -### Enhanced Block Production Debugging -**New** - The debug-block-production configuration option provides detailed block production logging and monitoring: - -- **Configuration Option**: The debug-block-production option is available in the Validator Plugin configuration with default value false. -- **Runtime Control**: The option can be enabled/disabled at runtime through command-line configuration. -- **Production Loop Monitoring**: Comprehensive logging for block production loop including entry/exit points, maybe_produce_block results, and scheduling operations. -- **validator Production Tracking**: Detailed logging for validator production scheduling, slot determination, and block generation processes. -- **Emergency Consensus Monitoring**: Enhanced logging for emergency consensus mode operations including validator schedule overrides and hybrid production scenarios. - -**Section sources** -- [validator.cpp:159-160](file://plugins/validator/validator.cpp#L159-L160) -- [validator.cpp:228-233](file://plugins/validator/validator.cpp#L228-L233) -- [validator.cpp:338-340](file://plugins/validator/validator.cpp#L338-L340) -- [validator.cpp:356-357](file://plugins/validator/validator.cpp#L356-L357) -- [validator.cpp:403-405](file://plugins/validator/validator.cpp#L403-L405) -- [validator.cpp:411-412](file://plugins/validator/validator.cpp#L411-L412) -- [validator.cpp:416-417](file://plugins/validator/validator.cpp#L416-L417) -- [validator.cpp:418-419](file://plugins/validator/validator.cpp#L418-L419) - -### Enhanced Stacktrace Crash Handlers -**New** - The stacktrace crash handlers provide improved crash diagnostics and debugging experience: - -- **Signal Handler Integration**: Enhanced stacktrace crash handlers integrate with standard signal handlers for SIGSEGV, SIGABRT, SIGFPE, and SIGILL. -- **Automatic Stacktrace Generation**: On fatal errors, the system generates detailed stacktrace information including demangled function names and line numbers. -- **Crash Diagnostics**: Comprehensive logging of fatal error signals with stacktrace information for improved debugging and troubleshooting. -- **Integration with Crash Debugging**: Works in conjunction with debug_crash logging to provide complete crash diagnostics and troubleshooting information. - -**Section sources** -- [stacktrace.cpp:48-78](file://thirdparty/fc/src/stacktrace.cpp#L48-L78) - -### Enhanced DLT Gap Recovery System -**New** - The database now includes comprehensive DLT gap recovery mechanisms with intelligent warning suppression: - -- **Gap Detection**: The system intelligently detects gaps between DLT block log end and fork database start during LIB advancement and block processing. -- **Automatic Gap Recovery**: When gaps are detected, the system automatically resets the DLT block log and rebuilds it from the fork database to ensure continuity. -- **Warning Suppression**: The `_dlt_gap_logged` flag mechanism prevents repeated warnings during gap recovery by suppressing repeated "block not in fork_db" messages until the gap is filled. -- **Enhanced Logging**: Comprehensive logging throughout the gap detection and recovery workflow provides detailed diagnostics for troubleshooting. -- **Gap Recovery Completion**: When gaps are filled, the system resets the `_dlt_gap_logged` flag to allow future warnings if gaps reoccur. - -```mermaid -flowchart TD -Start(["DLT Gap Detection"]) --> CheckGap{"Gap detected in DLT log?"} -CheckGap --> |No| NormalOperation["Normal operation"] -CheckGap --> |Yes| CheckRecoverable{"Recoverable gap?"} -CheckRecoverable --> |Yes| ResetDLT["Reset DLT block log from fork_db"] -ResetDLT --> RebuildDLT["Rebuild DLT log from fork_db start"] -RebuildDLT --> SuppressWarning["Set _dlt_gap_logged = true"] -SuppressWarning --> LogRecovery["Log gap recovery"] -LogRecovery --> FlushDLT["Flush DLT block log"] -FlushDLT --> ClearFlag["Clear _dlt_gap_logged on completion"] -ClearFlag --> NormalOperation -CheckRecoverable --> |No| LogNoRecover["Log no recoverable range found"] -LogNoRecover --> SuppressWarning -``` - -**Diagram sources** -- [database.cpp:5092-5105](file://libraries/chain/database.cpp#L5092-L5105) -- [database.cpp:5283-5297](file://libraries/chain/database.cpp#L5283-L5297) -- [database.cpp:5616-5635](file://libraries/chain/database.cpp#L5616-L5635) - -**Section sources** -- [database.cpp:5092-5105](file://libraries/chain/database.cpp#L5092-L5105) -- [database.cpp:5283-5297](file://libraries/chain/database.cpp#L5283-L5297) -- [database.cpp:5616-5635](file://libraries/chain/database.cpp#L5616-L5635) - -### Examples of Database Operations and Queries -- Open database and initialize: open(data_dir, shared_mem_dir, initial_supply, shared_file_size, chainbase_flags) -- **Open from snapshot**: open_from_snapshot(data_dir, shared_mem_dir, initial_supply, shared_file_size, chainbase_flags) - **Enhanced** -- Rebuild state from history: reindex(data_dir, shared_mem_dir, from_block_num, shared_file_size) - **Enhanced with signal handling** -- Push a block: push_block(signed_block, skip_flags) - **Enhanced with shared memory error handling, gap-based early rejection logic, operation guard protection, and comprehensive debug logging** -- Push a transaction: push_transaction(signed_transaction, skip_flags) -- Validate a block: validate_block(signed_block, skip_flags) -- Validate a transaction: validate_transaction(signed_transaction, skip_flags) -- **Set DLT mode**: set_dlt_mode(true/false) - **Enhanced with proper setter implementation** -- **Enhanced Exception Handling**: Sophisticated exception preservation during rethrow operations using fc::exception_factory and dynamic_rethrow_exception for proper derived type restoration -- **Enhanced Fork Database Management**: Comprehensive diagnostic capabilities with detailed logging for fork recovery operations, improved unlinkable block exception handling, and enhanced fork switching logic -- **Enhanced Early Rejection Logic**: Gap-based decision system (≤100 gap deferred to fork_db, >100 gap rejected) for intelligent block rejection of far-ahead blocks with unknown parents to prevent unnecessary fork database operations and sync restart loops -- **Enhanced Fork Database Exception Prevention**: Comprehensive mechanisms to prevent fork database exceptions through early rejection and proper dead fork detection -- **Enhanced Memory Management**: Comprehensive logging of memory states before and after resizing operations for administrator visibility -- **Enhanced P2P Protection**: Operation guard integration in P2P plugin for safe concurrent access during block validation and validator key retrieval -- **Enhanced validator Scheduling Safety**: Dual operation guard patterns in validator scheduling calculations to ensure thread safety during slot determination and validator validation -- **Enhanced Multi-Layered Block Retrieval**: Hierarchical block fetching with systematic fallback mechanisms that check fork database when primary block log fails to locate required data -- **Enhanced Last Irreversible Block Advancement**: Improved logic that falls back to fork database when block log lacks required data, maintaining data consistency -- **Enhanced Collision Detection**: Sophisticated logging for block number collisions with scenario differentiation and rate-limiting -- **Postponed Transaction Processing**: Automatic transaction queuing with time-based execution limits and smart recovery -- **Enhanced Emergency Consensus**: Automatic recovery system with comprehensive logging and safety checks for network stall detection and recovery -- **Enhanced Shared Memory Corruption Detection**: New shared_memory_corruption_exception type for structured error reporting during critical validation failures -- **Enhanced Auto-Recovery Integration**: Seamless integration with Validator Plugin for automatic recovery from shared memory corruption scenarios -- **Enhanced Crash Debugging**: Comprehensive debug_crash logging throughout critical code paths for improved crash diagnostics and troubleshooting -- **Enhanced Block Production Monitoring**: debug-block-production configuration option for detailed block production logging and monitoring -- **Enhanced Stacktrace Crash Handlers**: Automatic stacktrace generation for crash diagnostics and improved debugging experience -- **Enhanced DLT Gap Recovery**: Intelligent gap detection and automatic recovery with warning suppression using _dlt_gap_logged flag for improved diagnostics and reduced log noise - -**Section sources** -- [database.hpp:93-141](file://libraries/chain/include/graphene/chain/database.hpp#L93-L141) -- [database.cpp:458-584](file://libraries/chain/database.cpp#L458-L584) - -## Emergency Consensus Implementation - -**New** - The database now includes comprehensive emergency consensus implementation for automatic network recovery during extended periods without block production. - -### Emergency Consensus Activation Criteria -The emergency consensus system activates automatically when the network experiences extended downtime: - -- **LIB Timestamp Analysis**: System continuously monitors the last irreversible block (LIB) timestamp to detect network stalls -- **Timeout Threshold**: If no blocks are produced for more than CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC seconds (default: 3600 seconds = 1 hour), emergency mode is triggered -- **Safety Checks**: Emergency activation is skipped if LIB timestamp cannot be determined (e.g., after snapshot restore when block_log is empty) to prevent false activations -- **Guard Against Deadlocks**: Prevents emergency mode activation that would cause node deadlocks by ensuring proper LIB availability - -```mermaid -flowchart TD -Start(["Block Processing"]) --> CheckHF{"Has Hardfork 12?"} -CheckHF --> |No| Normal["Normal Operation"] -CheckHF --> |Yes| CheckActive{"Emergency Active?"} -CheckActive --> |Yes| Normal -CheckActive --> |No| CheckLIB{"LIB > 0?"} -CheckLIB --> |No| Skip["Skip Check (No LIB)"] -CheckLIB --> |Yes| FetchLIB["Fetch LIB Block"] -FetchLIB --> Valid{"LIB Block Valid?"} -Valid --> |No| Skip -Valid --> |Yes| CalcTime["Calculate Time Since LIB"] -CalcTime --> CheckTimeout{"Time >= Timeout?"} -CheckTimeout --> |No| Normal -CheckTimeout --> |Yes| Activate["Activate Emergency Mode"] -Activate --> CreateWitness["Create/Update Emergency validator"] -CreateWitness --> ResetPenalties["Reset validator Penalties"] -ResetPenalties --> OverrideSchedule["Override validator Schedule"] -OverrideSchedule --> NotifyFork["Notify Fork DB"] -NotifyFork --> LogActivation["Log Emergency Activation"] -LogActivation --> Normal -``` - -**Diagram sources** -- [database.cpp:4334-4463](file://libraries/chain/database.cpp#L4334-L4463) -- [config.hpp:111-118](file://libraries/protocol/include/graphene/protocol/config.hpp#L111-L118) - -**Section sources** -- [database.cpp:4334-4463](file://libraries/chain/database.cpp#L4334-L4463) -- [config.hpp:111-118](file://libraries/protocol/include/graphene/protocol/config.hpp#L111-L118) - -### Hybrid validator Scheduling System -During emergency mode, the system implements a hybrid validator scheduling approach: - -- **Real validator Priority**: Real validators maintain their scheduled slots during normal operation -- **Committee Replacement**: When real validators are unavailable (offline, shutdown, or missing signing keys), committee members automatically replace their slots -- **Full Coverage**: Emergency schedule expands to cover all CHAIN_MAX_WITNESSES slots, ensuring continuous block production -- **Dynamic Adjustment**: Schedule updates dynamically based on real validator availability and network conditions - -```mermaid -flowchart TD -Start(["Schedule Update"]) --> CheckEmergency{"Emergency Active?"} -CheckEmergency --> |No| NormalSchedule["Normal Schedule Update"] -CheckEmergency --> |Yes| IterateSlots["Iterate All Schedule Slots"] -IterateSlots --> CheckSlot{"Slot Available?"} -CheckSlot --> |Yes| KeepReal["Keep Real validator"] -CheckSlot --> |No| ReplaceWithCommittee["Replace with Emergency validator"] -ReplaceWithCommittee --> ExpandSchedule["Expand to Full Schedule"] -ExpandSchedule --> SyncProps["Sync Props with Latest Median"] -SyncProps --> CheckExit{"LIB > Start Block?"} -CheckExit --> |Yes| Deactivate["Deactivate Emergency Mode"] -CheckExit --> |No| Continue["Continue Emergency Mode"] -Deactivate --> NotifyFork["Notify Fork DB"] -NotifyFork --> LogDeactivation["Log Deactivation"] -LogDeactivation --> NormalSchedule -``` - -**Diagram sources** -- [database.cpp:2047-2144](file://libraries/chain/database.cpp#L2047-L2144) - -**Section sources** -- [database.cpp:2047-2144](file://libraries/chain/database.cpp#L2047-L2144) - -### Emergency validator Object Management -The system creates and manages a dedicated emergency validator object: - -- **Emergency validator Account**: Uses CHAIN_EMERGENCY_WITNESS_ACCOUNT (committee account) for emergency operations -- **Public Key Management**: Assigns CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY for block signing during emergencies -- **Properties Synchronization**: Copies current median chain properties to prevent skewing median computations -- **Version Management**: Maintains current binary version and hardfork voting alignment -- **Penalty Reset**: Emergency validator operates independently of normal penalty systems - -```mermaid -flowchart TD -Start(["Emergency Activation"]) --> CheckWitness{"Emergency validator Exists?"} -CheckWitness --> |No| CreateWitness["Create Emergency validator"] -CheckWitness --> |Yes| UpdateWitness["Update Existing validator"] -CreateWitness --> SetKey["Set Emergency Public Key"] -SetKey --> SyncProps["Copy Median Properties"] -SyncProps --> SyncVersion["Sync Version and Votes"] -UpdateWitness --> SetKey -SetKey --> SyncVersion -SyncVersion --> ResetPenalties["Reset Penalties"] -ResetPenalties --> RemoveExpire["Remove Penalty Expires"] -RemoveExpire --> OverrideSchedule["Override Schedule"] -OverrideSchedule --> NotifyFork["Notify Fork DB"] -NotifyFork --> LogCreate["Log validator Creation"] -LogCreate --> Continue["Continue Operation"] -``` - -**Diagram sources** -- [database.cpp:4378-4416](file://libraries/chain/database.cpp#L4378-L4416) - -**Section sources** -- [database.cpp:4378-4416](file://libraries/chain/database.cpp#L4378-L4416) - -### Emergency Mode Deactivation -Emergency mode automatically deactivates when network recovery is detected: - -- **LIB Progress Monitoring**: System continuously monitors last irreversible block advancement -- **Exit Condition**: When last_irreversible_block_num > emergency_consensus_start_block, emergency mode terminates -- **Graceful Transition**: Fork database is notified of emergency mode termination -- **Logging**: Comprehensive logging of emergency period duration and recovery metrics - -```mermaid -flowchart TD -Start(["LIB Monitoring"]) --> CheckEmergency{"Emergency Active?"} -CheckEmergency --> |No| Wait["Wait for LIB"] -CheckEmergency --> |Yes| CheckLIB["Check LIB Advancement"] -CheckLIB --> Compare{"LIB > Start Block?"} -Compare --> |No| Wait -Compare --> |Yes| Deactivate["Deactivate Emergency Mode"] -Deactivate --> UpdateDGP["Set emergency_consensus_active = false"] -UpdateDGP --> NotifyFork["Notify Fork DB"] -NotifyFork --> LogDeactivation["Log Deactivation"] -LogDeactivation --> Wait -``` - -**Diagram sources** -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) - -**Section sources** -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) - -### validator Penalty Handling During Emergencies -Emergency mode includes special handling for validator penalties: - -- **Offline validator Protection**: During emergency mode, penalties for offline validators are not applied -- **Hybrid Schedule Impact**: Committee members filling slots still count as "missed" blocks for normal penalty calculations -- **Recovery Prevention**: Prevents offline validators from accumulating penalties that could lead to permanent shutdown -- **Network Recovery**: Ensures offline validators can recover and resume participation after emergency mode ends - -```mermaid -flowchart TD -Start(["validator Missed Blocks"]) --> CheckEmergency{"Emergency Active?"} -CheckEmergency --> |No| ApplyPenalties["Apply Normal Penalties"] -CheckEmergency --> |Yes| CheckOffline{"Is Offline validator?"} -CheckOffline --> |No| ApplyPenalties -CheckOffline --> |Yes| CheckProducer{"Is Producer?"} -CheckProducer --> |Yes| ApplyPenalties -CheckProducer --> |No| SkipPenalties["Skip Penalties (Emergency)"] -SkipPenalties --> ResetRun["Reset Current Run"] -ResetRun --> Continue["Continue Processing"] -ApplyPenalties --> Continue -``` - -**Diagram sources** -- [database.cpp:4220-4230](file://libraries/chain/database.cpp#L4220-L4230) - -**Section sources** -- [database.cpp:4220-4230](file://libraries/chain/database.cpp#L4220-L4230) - -### LIB Monitoring and Safety Mechanisms -The emergency consensus system includes comprehensive LIB monitoring: - -- **Continuous Timestamp Analysis**: Monitors block timestamps to detect network stalls -- **Safety Guardrails**: Prevents false emergency activations by verifying LIB availability -- **Genesis Time Protection**: Avoids false activations by falling back to genesis_time considerations -- **Network Recovery Detection**: Monitors LIB advancement to determine when emergency mode should end - -### Enhanced Error Logging Throughout Consensus Process -**New** - The emergency consensus implementation includes comprehensive error logging and critical error handling: - -- **Critical Error Logging**: All emergency consensus activation and deactivation events are logged with detailed context including block numbers, timestamps, and validator information -- **Safety Check Logging**: Extensive logging of safety checks to prevent false activations and deadlocks -- **Transition Logging**: Detailed logging of emergency mode entry and exit conditions -- **validator Management Logging**: Comprehensive logging of emergency validator creation, updates, and penalty management -- **Schedule Override Logging**: Detailed logging of validator schedule overrides and hybrid scheduling decisions -- **LIB Monitoring Logging**: Continuous logging of LIB timestamp analysis and recovery detection -- **Error Recovery Logging**: Logging of error recovery mechanisms and fallback procedures - -The enhanced error logging system ensures that operators have comprehensive visibility into emergency consensus operations and can effectively troubleshoot any issues that arise during emergency mode activation or deactivation. - -### Enhanced Shared Memory Corruption Detection and Auto-Recovery -**New** - The database now includes comprehensive shared memory corruption detection and automatic recovery mechanisms: - -- **Structured Exception Handling**: New shared_memory_corruption_exception type replaces direct assertion failures with structured exception handling for critical validation failures. -- **Enhanced validator Validation**: Graceful error handling for validator account validation with detailed logging and structured exception reporting when validator accounts are missing from database. -- **Auto-Recovery Integration**: Seamless integration with Validator Plugin for automatic recovery from shared memory corruption scenarios. -- **Plugin-Level Recovery**: Comprehensive auto-recovery system in plugin.cpp that can automatically recover from snapshots when corruption is detected. -- **Structured Error Reporting**: Detailed logging of corruption detection events with comprehensive context including validator information, signing keys, and memory state. - -```mermaid -flowchart TD -Start(["Shared Memory Corruption Detection"]) --> DetectCorruption["Detect Missing validator Account"] -DetectCorruption --> LogCritical["Log Critical Error Details"] -LogCritical --> ThrowException["Throw shared_memory_corruption_exception"] -ThrowException --> CatchInWitness["Catch in Validator Plugin"] -CatchInWitness --> AttemptRecovery["Attempt Auto-Recovery"] -AttemptRecovery --> FindSnapshot["Find Latest Snapshot"] -FindSnapshot --> CloseDatabase["Close Corrupted Database"] -CloseDatabase --> LoadSnapshot["Load Snapshot State"] -LoadSnapshot --> ResumeOperation["Resume Node Operation"] -ResumeOperation --> End(["Complete"]) -``` - -**Diagram sources** -- [database.cpp:1680-1693](file://libraries/chain/database.cpp#L1680-L1693) -- [database.cpp:3224-3236](file://libraries/chain/database.cpp#L3224-L3236) -- [database.cpp:3272-3284](file://libraries/chain/database.cpp#L3272-L3284) -- [validator.cpp:738-742](file://plugins/validator/validator.cpp#L738-L742) -- [plugin.cpp:760-770](file://plugins/chain/plugin.cpp#L760-L770) - -**Section sources** -- [database.cpp:1680-1693](file://libraries/chain/database.cpp#L1680-L1693) -- [database.cpp:3224-3236](file://libraries/chain/database.cpp#L3224-L3236) -- [database.cpp:3272-3284](file://libraries/chain/database.cpp#L3272-L3284) -- [validator.cpp:738-742](file://plugins/validator/validator.cpp#L738-L742) -- [plugin.cpp:760-770](file://plugins/chain/plugin.cpp#L760-L770) - -## Dependency Analysis -The database depends on: -- chainbase for persistent storage and undo sessions with enhanced memory management, operation_guard RAII pattern, and resize barrier mechanisms -- block_log for immutable block storage and random access -- dlt_block_log for rolling window storage in DLT mode -- fork_database for reversible blocks and fork resolution with emergency mode support and enhanced unlinkable block detection -- protocol types and evaluators for operation processing -- signal_guard for enhanced error handling during restart sequences -- snapshot plugin for DLT mode initialization -- **Enhanced Exception Handling Infrastructure**: Sophisticated exception preservation during rethrow operations using fc::exception_factory and dynamic_rethrow_exception for proper derived type restoration -- **Enhanced Fork Database Management**: Comprehensive diagnostic capabilities with detailed logging for fork recovery operations, improved unlinkable block exception handling, and enhanced fork switching logic -- **Enhanced Early Rejection Logic**: Gap-based decision system (≤100 gap deferred to fork_db, >100 gap rejected) for intelligent block validation with early rejection strategies for blocks far ahead with unknown parents -- **Enhanced Fork Database Exception Prevention**: Comprehensive mechanisms to prevent fork database exceptions through early rejection and proper dead fork detection -- **Enhanced Memory Management**: Comprehensive logging system for shared memory allocation with detailed state reporting, plus deferred resize operations -- **Enhanced P2P Plugin Protection**: Operation guard integration in P2P plugin for safe concurrent access during block validation and validator key retrieval -- **Enhanced Operation Guard System**: Comprehensive concurrent access protection using operation_guard RAII pattern, dual operation guard patterns for validator scheduling safety, and resize barrier mechanisms -- **Enhanced Multi-Layered Block Retrieval**: Systematic fallback mechanisms for critical block data retrieval across multiple storage layers -- **Enhanced Last Irreversible Block Advancement**: Enhanced fallback logic for LIB advancement when primary storage fails -- **Enhanced Emergency Consensus**: Automatic recovery system with comprehensive logging and safety checks for network stall detection and recovery -- **Enhanced Shared Memory Corruption Detection**: New shared_memory_corruption_exception type for structured error handling and automatic recovery integration -- **Enhanced Auto-Recovery System**: Comprehensive auto-recovery from snapshot for shared memory corruption scenarios with seamless plugin integration -- **Enhanced Crash Debugging System**: Comprehensive debug_crash logging throughout critical code paths for improved crash diagnostics and troubleshooting -- **Enhanced Block Production Monitoring**: debug-block-production configuration option for detailed block production logging and monitoring -- **Enhanced Stacktrace Crash Handlers**: Automatic stacktrace generation for crash diagnostics and improved debugging experience -- **Enhanced DLT Gap Recovery System**: Intelligent gap detection and automatic recovery mechanisms with warning suppression using _dlt_gap_logged flag - -```mermaid -graph LR -DB["database.cpp"] --> CB["chainbase (external)"] -DB --> BL["block_log.hpp/.cpp"] -DB --> DLT["dlt_block_log.hpp/.cpp"] -DB --> FD["fork_database.hpp/.cpp"] -DB --> SG["signal_guard (enhanced)"] -DB --> PT["protocol types"] -DB --> EV["evaluators"] -DB --> SNAP["snapshot plugin"] -DB --> EXINF["exception handling infrastructure"] -DB --> FDMGMT["enhanced fork database management"] -DB --> EARLY["enhanced early rejection logic"] -DB --> MEMMGT["enhanced memory management"] -DB --> P2PSEC["enhanced P2P plugin protection"] -DB --> OPGUARD["enhanced operation guard system"] -DB --> MULTILAYER["enhanced multi-layered block retrieval"] -DB --> LIBADVANCE["enhanced last irreversible block advancement"] -DB --> EMER["enhanced emergency consensus"] -DB --> CORRUPTION["enhanced shared memory corruption detection"] -DB --> AUTORECOVERY["enhanced auto-recovery system"] -DB --> CRASHDEBUG["enhanced crash debugging system"] -DB --> BLOCKPROD["enhanced block production monitoring"] -DB --> STACKTRACE["enhanced stacktrace crash handlers"] -DB --> DLTGAP["enhanced DLT gap recovery system"] -``` - -**Diagram sources** -- [database.hpp:1-10](file://libraries/chain/include/graphene/chain/database.hpp#L1-L10) -- [database.cpp:1-30](file://libraries/chain/database.cpp#L1-L30) -- [database.cpp:94-184](file://libraries/chain/database.cpp#L94-L184) -- [chainbase.cpp:225-279](file://thirdparty/chainbase/src/chainbase.cpp#L225-L279) -- [database_exceptions.hpp:83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83) -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) - -**Section sources** -- [database.hpp:1-10](file://libraries/chain/include/graphene/chain/database.hpp#L1-L10) -- [database.cpp:1-30](file://libraries/chain/database.cpp#L1-L30) -- [database.cpp:94-184](file://libraries/chain/database.cpp#L94-L184) -- [chainbase.cpp:225-279](file://thirdparty/chainbase/src/chainbase.cpp#L225-L279) -- [database_exceptions.hpp:83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83) -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) - -## Performance Considerations -- Use skip flags during reindex to bypass expensive validations and improve replay speed. -- Configure shared memory sizing and thresholds to avoid frequent resizing and fragmentation. -- Monitor free memory and adjust increments to keep latency predictable. -- Use checkpoints to reduce validation overhead for recent blocks. -- Tune flush intervals to balance durability and throughput. -- **DLT Mode Optimization**: Use rolling window DLT block log to reduce storage requirements for snapshot-based nodes. -- **Conditional Operations**: Leverage DLT mode to skip unnecessary block log operations while maintaining required functionality. -- **Enhanced Exception Type Preservation**: Graceful fallback mechanisms prevent performance degradation during restart sequences. -- **Multi-layered Fetching**: Hierarchical block retrieval minimizes lookup overhead and improves response times. -- **Enhanced Early Rejection Efficiency**: The new gap-based early rejection logic eliminates unnecessary fork database operations for far-ahead blocks with unknown parents, significantly reducing processing overhead and preventing sync restart loops. -- **Enhanced Fork Database Exception Prevention**: Comprehensive early rejection mechanisms prevent fork database exceptions before they occur, eliminating the need for exception handling and improving overall system efficiency. -- **Enhanced Fork Database Performance**: Proper unlinkable_block_exception handling reduces processing overhead by eliminating dead fork blocks from consideration. -- **Enhanced Fork Switching**: Enhanced fork switching logic with proper dead fork detection and deterministic tie-breaking prevents unnecessary processing and improves fork resolution performance. -- **Enhanced Memory Management**: Comprehensive logging provides administrators with detailed visibility into memory usage patterns, enabling proactive capacity planning and performance optimization. -- **Enhanced Error Handling**: Graceful handling of shared memory exhaustion prevents peer disconnections and maintains network connectivity during memory pressure situations. -- **Enhanced Operation Guard Performance**: The operation guard RAII pattern provides automatic concurrent access protection with minimal overhead, ensuring thread safety without significant performance impact. -- **Enhanced Dual Guard Patterns**: Systematic implementation of dual operation guards in validator scheduling provides comprehensive thread safety with optimized performance characteristics. -- **Enhanced P2P Concurrent Safety**: Operation guard protection in P2P plugin ensures safe concurrent access during block validation with minimal performance overhead. -- **Enhanced Resize Barrier Efficiency**: Enhanced resize barrier mechanisms provide comprehensive concurrent access protection during memory resizing with optimized performance characteristics. -- **Enhanced Multi-Layered Block Retrieval**: Systematic fallback mechanisms eliminate single points of failure and improve system reliability without significant performance impact. -- **Enhanced Last Irreversible Block Advancement**: Enhanced fallback logic maintains data consistency and availability without affecting block processing performance. -- **Enhanced Emergency Consensus Logging**: Comprehensive logging provides operators with detailed visibility into emergency operations without impacting performance. -- **Enhanced Safety Check Optimization**: Emergency consensus safety checks are optimized to minimize performance impact while ensuring network stability. -- **Enhanced Deferred Memory Resize Efficiency**: The new deferred resize mechanism prevents race conditions and stale pointer issues during high-load scenarios, improving overall system reliability and performance. -- **Enhanced Thread-Safe Memory Operations**: Proper lock management during memory resize operations ensures data consistency and prevents performance degradation from thread contention. -- **Enhanced P2P Sync Restart Prevention**: The enhanced early rejection logic prevents sync restart loops during snapshot imports, improving synchronization performance and reducing network overhead. -- **Enhanced Shared Memory Corruption Detection**: Structured exception handling provides detailed error context without significant performance impact during critical validation failures. -- **Enhanced Auto-Recovery Performance**: Seamless integration with Validator Plugin enables rapid recovery from shared memory corruption without significant downtime. -- **Enhanced Crash Debugging Overhead**: The debug_crash logging system adds minimal overhead during normal operation while providing comprehensive debugging capabilities when enabled. -- **Enhanced Block Production Monitoring**: The debug-block-production option provides detailed monitoring capabilities with minimal performance impact. -- **Enhanced Stacktrace Performance**: Stacktrace crash handlers add minimal overhead and provide significant debugging benefits for crash diagnostics. -- **Enhanced DLT Gap Recovery Performance**: Intelligent gap detection and automatic recovery mechanisms provide improved diagnostics with minimal performance impact during DLT mode operations. - -## Troubleshooting Guide -Common issues and remedies: -- Memory exhaustion during block production or reindex: Increase shared file size and tune minimum free memory threshold. -- Chain mismatch between block log and database: Run reindex to rebuild state from block log. -- Excessive undo history: Ensure last irreversible block advances to prune history. -- Signal-related errors: Verify signal handlers and ensure proper exception propagation. -- **Enhanced Exception Type Preservation**: If derived exception types are not being preserved during rethrow operations, verify that fc::exception_factory is properly registering exception builders and that dynamic_rethrow_exception() is being called correctly. -- **Enhanced Fork Database Diagnostics**: Monitor fork recovery logs to identify issues with fork switching operations, including branch comparison failures and exception handling during recovery. -- **Enhanced Early Rejection Issues**: If blocks are being incorrectly rejected, verify the gap calculation logic and ensure that the early rejection criteria are appropriate for the current network conditions. -- **Enhanced Fork Database Exception Prevention**: Monitor unlinkable_block_exception handling to ensure dead fork blocks are properly detected and excluded from processing. -- **Enhanced Memory Management Issues**: Monitor enhanced memory logging to identify potential memory pressure situations and optimize configuration settings. -- **Enhanced Memory Resize Failures**: Check that memory resize operations are completing successfully and review detailed logging for resize operations. -- **Enhanced P2P Sync Restart Loops**: Verify that the enhanced early rejection logic is working correctly to prevent sync restart loops during snapshot imports and normal operation. -- **Enhanced Emergency Consensus Logging**: Verify that critical error logs are being generated and that emergency mode activation/deactivation events are properly recorded. -- **Enhanced Safety Check Failures**: Monitor emergency consensus safety checks to ensure they're functioning correctly and preventing false activations. -- **Enhanced validator Management Problems**: Verify that emergency validator objects are being created and updated correctly during emergency mode activation. -- **Enhanced Deferred Memory Resize Issues**: Monitor the new deferred resize mechanism to ensure it's properly deferring operations until safe points and applying them correctly. -- **Enhanced Thread Safety Problems**: Verify that memory resize operations are not causing race conditions or stale pointer issues during concurrent access. -- **Enhanced Performance Degradation**: Check if the deferred memory resize mechanism is causing unexpected delays or if memory operations are blocking other threads. -- **Enhanced Shared Memory Exhaustion**: Monitor boost::interprocess::bad_alloc exceptions and verify that deferred resize scheduling is working correctly to prevent peer disconnections. -- **Enhanced Peer Connectivity Issues**: Verify that memory pressure handling is preserving peer connections and not causing network instability. -- **Enhanced Fork Switching Problems**: Verify that fork switching logic properly handles unlinkable_block_exception and prevents processing of invalid forks. -- **Enhanced Dead Fork Detection**: Check that the enhanced fork database properly throws unlinkable_block_exception for blocks from dead forks to prevent wasted processing resources. -- **Enhanced Emergency Consensus Tie-Breaking**: Verify that deterministic hash-based tie-breaking is working correctly during emergency mode to ensure consistent block selection across all nodes. -- **Enhanced Operation Guard Issues**: Monitor operation guard functionality to ensure concurrent access protection is working correctly during high-load scenarios. -- **Enhanced Dual Guard Pattern Problems**: Verify that dual operation guards are properly protecting validator scheduling calculations and preventing race conditions. -- **Enhanced P2P Concurrent Access Issues**: Check that operation guard protection is working correctly in P2P plugin for safe concurrent access during block validation. -- **Enhanced Resize Barrier Failures**: Monitor resize barrier mechanisms to ensure they're properly pausing all database operations during memory resizing. -- **Enhanced Concurrent Resize Safety**: Verify that resize barrier mechanisms are preventing stale pointer issues and data corruption during memory operations. -- **Enhanced Multi-Layered Block Retrieval Issues**: Monitor the new fallback mechanisms to ensure they're properly checking fork database when primary block log fails to locate required data. -- **Enhanced Last Irreversible Block Advancement Problems**: Verify that the enhanced fallback logic is working correctly when block log lacks required data. -- **Enhanced Emergency Mode Activation**: Monitor emergency consensus activation logs and verify LIB timestamp analysis is working correctly. -- **Enhanced Hybrid Schedule Issues**: Verify that emergency validator is properly replacing unavailable validators during network recovery. -- **Enhanced Emergency Mode Deactivation**: Check that LIB advancement is properly detected to trigger emergency mode termination. -- **Enhanced validator Penalty Problems**: During emergency mode, verify that offline validator penalties are properly bypassed to prevent network recovery issues. -- **Enhanced Shared Memory Corruption Detection**: Monitor shared_memory_corruption_exception logging to ensure critical validation failures are properly reported. -- **Enhanced Auto-Recovery Integration**: Verify that Validator Plugin auto-recovery is properly integrated with plugin-level recovery system for seamless corruption handling. -- **Enhanced Auto-Recovery Performance**: Monitor auto-recovery performance to ensure rapid recovery from shared memory corruption without significant downtime. -- **Enhanced Crash Debugging Issues**: Verify that debug_crash logging is working correctly and providing comprehensive debugging information when enabled. -- **Enhanced Block Production Monitoring Problems**: Check that debug-block-production option is properly configured and providing detailed block production logging. -- **Enhanced Stacktrace Crash Handler Issues**: Verify that stacktrace crash handlers are properly installed and generating stacktrace information for crash diagnostics. -- **Enhanced DLT Gap Recovery Issues**: Monitor the new _dlt_gap_logged flag mechanism to ensure gap detection and recovery is working correctly and warning suppression is preventing log spam. -- **Enhanced Gap Recovery Logging**: Verify that comprehensive logging throughout the gap detection and recovery workflow is providing adequate diagnostics for troubleshooting. - -**Section sources** -- [database.cpp:789-827](file://libraries/chain/database.cpp#L789-L827) -- [database.cpp:270-279](file://libraries/chain/database.cpp#L270-L279) -- [database.cpp:492-501](file://libraries/chain/database.cpp#L492-L501) -- [database.cpp:1147-1202](file://libraries/chain/database.cpp#L1147-L1202) -- [db_with.hpp:33-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L33-L100) -- [database.cpp:4334-4463](file://libraries/chain/database.cpp#L4334-L4463) -- [database.cpp:2047-2144](file://libraries/chain/database.cpp#L2047-L2144) -- [database.cpp:454-482](file://libraries/chain/database.cpp#L454-L482) -- [database.cpp:1106-1145](file://libraries/chain/database.cpp#L1106-L1145) -- [database.cpp:1460-1470](file://libraries/chain/database.cpp#L1460-L1470) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [database.cpp:1295-1377](file://libraries/chain/database.cpp#L1295-L1377) -- [database.cpp:1216-1286](file://libraries/chain/database.cpp#L1216-L1286) -- [node.cpp:3185-3384](file://libraries/network/node.cpp#L3185-L3384) -- [p2p_plugin.cpp:181-196](file://plugins/p2p/p2p_plugin.cpp#L181-L196) -- [chainbase.hpp:1078-1120](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1120) -- [exception.cpp:166-186](file://thirdparty/fc/src/exception.cpp#L166-L186) -- [exception.hpp:177-215](file://thirdparty/fc/include/fc/exception/exception.hpp#L177-L215) -- [stacktrace.cpp:72-78](file://thirdparty/fc/src/stacktrace.cpp#L72-L78) -- [database.cpp:5092-5105](file://libraries/chain/database.cpp#L5092-L5105) -- [database.cpp:5283-5297](file://libraries/chain/database.cpp#L5283-L5297) -- [database.cpp:5616-5635](file://libraries/chain/database.cpp#L5616-L5635) - -## Conclusion -The Database Management system provides a robust, event-driven, and efficient state persistence layer for the VIZ blockchain with enhanced DLT mode support, emergency consensus implementation, operation guard integration, improved error handling, and comprehensive crash debugging capabilities. It integrates chainbase for persistent storage with comprehensive concurrent access protection, fork_database for reversible blocks, block_log for immutable history, and dlt_block_log for rolling window storage in DLT mode. Through configurable validation flags, checkpointing, memory management, DLT mode detection with proper setter implementation, enhanced block fetching logic with DLT mode awareness, improved gap logging, the new `_dlt_gap_logged` flag mechanism for intelligent warning suppression, comprehensive operation guard implementation for concurrent access protection, dual operation guard patterns for validator scheduling safety, enhanced P2P plugin block validation with operation guard protection, systematic implementation of resize barrier mechanisms, comprehensive debug_crash logging throughout critical code paths, debug-block-production configuration option for detailed block production monitoring, and enhanced stacktrace crash handlers for improved crash diagnostics, it supports fast synchronization, reliable block processing, conditional block log operations, and extensibility via observer signals. - -**Updated** - The system now includes comprehensive database robustness improvements including refined gap-based decision system for unlinkable blocks, enhanced exception handling infrastructure that preserves derived exception types during rethrow operations, comprehensive fork database management with improved diagnostic capabilities and enhanced logging for fork recovery operations, and sophisticated early rejection logic for blocks far ahead with unknown parents. The enhanced fork management logic with improved early rejection mechanisms provides better handling of blocks far ahead with unknown parents, significantly improving the efficiency of the synchronization process and reducing the likelihood of encountering unlinkable blocks that would require peer soft-banning or sync restarts. The enhanced multi-layered block retrieval system represents a significant advancement in database reliability and fault tolerance. The improved last irreversible block advancement logic demonstrates the system's commitment to data consistency and availability. The enhanced exception handling infrastructure ensures that derived exception types are properly preserved during rethrow operations, improving debugging and troubleshooting capabilities. The enhanced memory management system provides comprehensive logging capabilities that offer administrators detailed visibility into memory usage patterns during blockchain operation, while the deferred shared memory resize mechanism significantly improves efficiency during high-load scenarios by preventing race conditions and stale pointer issues through proper thread synchronization and lock management. - -The enhanced exception handling infrastructure represents a fundamental improvement in error handling robustness throughout the database management system. The fc::exception_factory system with proper exception builder registration ensures that derived exception types are preserved during rethrow operations, while the enhanced dynamic_rethrow_exception() method provides reliable type restoration. The protocol exceptions now include comprehensive dynamic_rethrow_exception() implementations that check code() values before rethrowing to ensure proper type preservation. This enhancement significantly improves the debugging experience and makes it easier to identify and resolve issues in the database management system. - -**Enhanced Fork Database Management** - The comprehensive diagnostic capabilities and enhanced logging for fork recovery operations represent a major advancement in fork database reliability and maintainability. The detailed logging for fork switching operations, including branch comparison results, exception handling during fork recovery, and state restoration procedures, provides operators with comprehensive visibility into fork resolution activities. The improved fork switching logic with deterministic tie-breaking and comprehensive error handling for invalid fork scenarios ensures that the system can handle complex fork scenarios reliably. The dead fork detection and pruning mechanisms prevent memory bloat and improve system performance by removing stale competing blocks from the fork database. - -**Enhanced Early Rejection Logic** - The new gap-based decision system represents a significant improvement in synchronization reliability and performance. By intelligently rejecting blocks with gaps > 100 immediately while deferring blocks with gaps ≤ 100 to the fork database, the system prevents unnecessary processing overhead and eliminates the possibility of fork database exceptions that could trigger sync restart loops. This enhancement is particularly beneficial during snapshot imports where the fork database may only contain the head block, preventing the common scenario where P2P peers send blocks that are far ahead and would otherwise cause continuous sync restarts. The early rejection strategy ensures that only blocks with known parents are processed through the fork database, significantly improving the efficiency of the synchronization process and reducing the likelihood of encountering unlinkable blocks that would require peer soft-banning or sync restarts. - -**Enhanced Fork Database Exception Prevention** - The comprehensive exception prevention mechanisms represent a major advancement in fork database reliability. The system now includes multiple layers of protection against fork database exceptions, starting with the intelligent gap-based early rejection of blocks with unknown parents and extending to proper classification and handling of different types of unlinkable blocks. The dead fork detection at or below head ensures that stale fork blocks are properly identified and rejected, while the gap-based large gap rejection prevents unnecessary fork database operations that could trigger sync restart loops. This multi-layered approach to exception prevention significantly improves the robustness of the fork database and reduces the likelihood of synchronization issues caused by malformed or malicious blocks. The enhanced error propagation and classification mechanisms ensure that downstream components can properly handle different types of unlinkable blocks, leading to more efficient and reliable network synchronization. - -**Enhanced Memory Management** - The enhanced memory management system now provides comprehensive logging capabilities that offer administrators detailed visibility into memory usage patterns during blockchain operation. The new deferred shared memory resize mechanism significantly improves efficiency during high-load scenarios by preventing race conditions and stale pointer issues through proper thread synchronization and lock management. The enhanced `_resize` function logs detailed information about free memory, maximum memory, and reserved memory states before and after resizing operations, enabling proactive capacity planning and performance optimization. The improved error detection capabilities in shared memory allocation provides administrators with crucial information about memory usage patterns, helping prevent memory-related issues before they impact system performance. The comprehensive emergency consensus logging system ensures that operators have complete visibility into critical error conditions and recovery procedures. These enhancements make the database management system more transparent, manageable, and suitable for production environments where memory resource optimization and comprehensive error diagnostics are critical. - -**Enhanced P2P Synchronization** - The enhanced P2P synchronization system with improved unlinkable block classification and sync restart prevention represents a significant improvement in network reliability and performance. The P2P layer now properly distinguishes between dead fork blocks (at or below head) and far-ahead blocks that slipped past early rejection, enabling appropriate handling for each scenario. The dead fork handling with soft-banning prevents continued transmission of stale blocks, while the far-ahead block handling with sync restart prevention allows sequential block fetching without causing network stalls. The integration with deferred resize scenarios ensures that P2P operations can continue smoothly even when memory pressure occurs during block processing. - -**Enhanced Operation Guard Implementation** - The comprehensive operation guard system represents a fundamental improvement in concurrent access protection throughout the database management system. The systematic implementation of operation_guard RAII pattern provides automatic concurrent access protection across all critical sections, while the dual operation guard patterns in validator scheduling calculations ensure thread safety during complex slot determination operations. The integration of operation guards in P2P plugin block validation protects validator key retrieval operations from concurrent memory modifications, and the comprehensive resize barrier mechanisms prevent data corruption during memory resizing operations. These enhancements ensure that the database management system can handle high-load scenarios safely and reliably while maintaining data consistency and preventing race conditions that could lead to system instability or data corruption. - -**Enhanced Multi-Layered Block Retrieval System** - The new multi-layered block retrieval system represents a significant advancement in database reliability and fault tolerance. By implementing systematic fallback mechanisms that check fork database when primary block log fails to locate required data, the database ensures consistent behavior across different block logging configurations. This approach eliminates single points of failure and provides improved resilience against storage layer issues, network interruptions, and other operational challenges. The hierarchical retrieval strategy prioritizes current/main branch blocks in the fork database, then checks the primary block log for irreversible blocks, and finally uses the DLT block log as a fallback in DLT mode. This ensures that block retrieval works reliably regardless of which storage layer contains the requested data, providing improved fault tolerance and system reliability. - -**Enhanced Last Irreversible Block Advancement Logic** - The improved LIB advancement logic demonstrates the system's commitment to data consistency and availability. The comprehensive fallback mechanisms ensure that critical blockchain state information remains accessible even when primary storage layers are compromised, preventing system stalls and maintaining network integrity. The systematic approach to LIB advancement maintains consistency between different storage layers while ensuring that the system can continue operating even when individual storage components are temporarily unavailable or inconsistent. - -**Enhanced Emergency Consensus** - The enhanced emergency consensus implementation provides comprehensive logging and safety checks for network stall detection and recovery. The automatic recovery system with detailed logging and safety mechanisms ensures that operators have complete visibility into emergency operations without impacting performance. The enhanced safety check optimization prevents false activations while ensuring network stability, making the system more reliable and suitable for production environments where network reliability is critical. - -**Enhanced Shared Memory Corruption Detection** - The introduction of the new shared_memory_corruption_exception type represents a significant advancement in error handling robustness. This structured exception handling approach replaces direct assertion failures with comprehensive error reporting, enabling better debugging and troubleshooting capabilities. The enhanced validator account validation with graceful error handling during block acceptance and generation processes ensures that critical validation failures are properly detected and reported with detailed context information. - -**Enhanced Auto-Recovery Integration** - The seamless integration with Validator Plugin for automatic recovery from shared memory corruption scenarios represents a major improvement in system reliability and uptime. The comprehensive auto-recovery system in plugin.cpp provides rapid recovery from corruption scenarios with minimal downtime, while the structured error reporting ensures that operators have complete visibility into recovery operations. This integration makes the database management system more resilient to critical hardware and software failures, improving overall system reliability and operator confidence. - -**Enhanced Crash Debugging Capabilities** - The comprehensive crash debugging system with debug_crash logging throughout critical code paths represents a significant advancement in troubleshooting and diagnostics capabilities. The extensive debug markers (DEBUG_CRASH) provide detailed visibility into database operations, while the debug-block-production configuration option enables comprehensive monitoring of block production processes. The enhanced stacktrace crash handlers provide automatic crash diagnostics with detailed stacktrace information, significantly improving the debugging experience and reducing troubleshooting time for critical system issues. - -**Enhanced Block Production Monitoring** - The debug-block-production configuration option provides operators with detailed visibility into block production processes, enabling comprehensive monitoring and troubleshooting of production-related issues. The integration with Validator Plugin ensures that block production logging is comprehensive and actionable, while the detailed logging markers throughout the production pipeline provides granular visibility into production scheduling, slot determination, and block generation processes. - -**Enhanced Stacktrace Crash Handlers** - The enhanced stacktrace crash handlers provide automatic crash diagnostics with detailed stacktrace information, significantly improving the debugging experience for fatal errors. The integration with the crash debugging system ensures that operators have complete visibility into system crashes and can quickly identify and resolve critical issues through comprehensive stacktrace analysis and crash diagnostics. - -**Enhanced DLT Gap Recovery System** - The new DLT gap recovery system represents a significant advancement in DLT mode reliability and diagnostics. The intelligent gap detection and automatic recovery mechanisms with warning suppression using the `_dlt_gap_logged` flag provide improved diagnostics with minimal performance impact during DLT mode operations. The comprehensive logging throughout the gap detection and recovery workflow ensures that operators have complete visibility into DLT block log operations and can effectively troubleshoot gap-related issues without log spam or performance degradation. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Fork Resolution and Consensus.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Fork Resolution and Consensus.md deleted file mode 100644 index 32c5020a11..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Fork Resolution and Consensus.md +++ /dev/null @@ -1,1482 +0,0 @@ -# Fork Resolution and Consensus - - -**Referenced Files in This Document** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [12.hf](file://libraries/chain/hardfork.d/12.hf) - - -## Update Summary -**Changes Made** -- Enhanced fork database with new diagnostic accessors for monitoring block storage statistics -- Added comprehensive storage health metrics including linked/unlinked index sizes and block number ranges -- Integrated diagnostic accessors into P2P monitoring system for real-time block storage analytics -- Improved fork database monitoring capabilities with min/max block number tracking -- Enhanced storage health metrics for better system observability and troubleshooting - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Emergency Consensus Recovery System](#emergency-consensus-recovery-system) -7. [Two-Level Fork Collision Resolution](#two-level-fork-collision-resolution) -8. [Vote-Weighted Fork Comparison Algorithm](#vote-weighted-fork-comparison-algorithm) -9. [Automatic Stale Fork Pruning System](#automatic-stale-fork-pruning-system) -10. [Enhanced Fork Database Diagnostic Accessors](#enhanced-fork-database-diagnostic-accessors) -11. [Storage Health Monitoring and Analytics](#storage-health-monitoring-and-analytics) -12. [Dependency Analysis](#dependency-analysis) -13. [Performance Considerations](#performance-considerations) -14. [Troubleshooting Guide](#troubleshooting-guide) -15. [Conclusion](#conclusion) -16. [Appendices](#appendices) - -## Introduction -This document explains the Fork Resolution and Consensus system that maintains blockchain integrity and handles network partitions. The system has been significantly enhanced with sophisticated gap-based early rejection logic, comprehensive duplicate detection, improved block validation mechanisms, enhanced error handling that prevents infinite synchronization loops, and **NEW**: comprehensive diagnostic accessors for monitoring fork database storage statistics. The fork_database implementation now supports intelligent block rejection, comprehensive duplicate prevention, sophisticated tie-breaking mechanisms for emergency consensus scenarios, advanced fork collision resolution with HF12 logic, and **NEW**: real-time monitoring of linked/unlinked index sizes, minimum/maximum block numbers, and comprehensive storage health metrics. - -## Project Structure -The fork resolution and consensus logic spans several core files with enhanced early rejection, validation, **NEW**: diagnostic monitoring capabilities, and comprehensive storage health metrics: -- fork_database.hpp/cpp: In-memory fork chain storage, branch selection, common ancestor detection, duplicate detection, emergency mode tie-breaking, automatic stale fork pruning, gap-based early rejection, and **NEW**: diagnostic accessors for storage statistics -- database.hpp/cpp: Blockchain database integration, block pushing with early rejection logic, chain reorganization, DLT mode management, sophisticated block validation, vote-weighted fork comparison, and **NEW**: fork database access for diagnostic monitoring -- block_log.hpp: Append-only persistence of blocks for recovery and irreversible state -- dlt_block_log.hpp/cpp: Separate rolling block log for DLT nodes to serve recent irreversible blocks to P2P peers -- validator.cpp: validator scheduling integration with emergency mode awareness, fork collision handling, two-level fork collision resolution, stuck-head timeout mechanism, and automatic chain linking -- p2p_plugin.cpp: **NEW**: Real-time monitoring of fork database storage statistics with comprehensive analytics -- config.hpp: Emergency consensus configuration constants including timeout settings and emergency validator parameters -- 12.hf: Hardfork configuration defining HF12 parameters and activation time - -```mermaid -graph TB -subgraph "Chain Layer" -FD["fork_database.hpp/.cpp"] -DBH["database.hpp"] -DBC["database.cpp"] -BLH["block_log.hpp"] -DLTH["dlt_block_log.hpp/.cpp"] -DIAG["Diagnostic Accessors"] -PMON["P2P Monitoring"] -END["Gap-Based Early Rejection"] -END2["Duplicate Detection"] -END3["Block Validation"] -END4["Exception Handling"] -END5["HF12 Fork Comparison"] -END6["Stuck-Head Timeout"] -END7["Automatic Chain Linking"] -END8["Stale Fork Pruning"] -end -FD --> DBC -DBH --> DBC -BLH --> DBC -DLTH --> DBC -DBC --> FD -DBC --> DIAG -DBC --> PMON -DBC --> END -DBC --> END2 -DBC --> END3 -DBC --> END4 -DBC --> END5 -DBC --> END6 -DBC --> END7 -DBC --> END8 -FD --> DIAG -FD --> END4 -FD --> END5 -FD --> END6 -FD --> END7 -FD --> END8 -PMON --> DIAG -``` - -**Diagram sources** -- [fork_database.hpp:128-150](file://libraries/chain/include/graphene/chain/fork_database.hpp#L128-L150) -- [fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) -- [database.cpp:1204-1270](file://libraries/chain/database.cpp#L1204-L1270) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) -- [validator.cpp:521-544](file://plugins/validator/validator.cpp#L521-L544) - -**Section sources** -- [fork_database.hpp:1-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L168) -- [fork_database.cpp:1-278](file://libraries/chain/fork_database.cpp#L1-L278) -- [database.hpp:1-200](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp:1-6669](file://libraries/chain/database.cpp#L1-L6669) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [dlt_block_log.cpp:1-454](file://libraries/chain/dlt_block_log.cpp#L1-L454) -- [validator.cpp:1-697](file://plugins/validator/validator.cpp#L1-L697) -- [p2p_plugin.cpp:735-771](file://plugins/p2p/p2p_plugin.cpp#L735-L771) -- [config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -## Core Components -- fork_database: Maintains a multi-indexed collection of fork items with enhanced out-of-order block caching, comprehensive duplicate detection, sophisticated tie-breaking mechanisms, emergency mode integration, automatic stale fork pruning capabilities, gap-based early rejection logic, and **NEW**: comprehensive diagnostic accessors for storage statistics monitoring -- database: Integrates fork resolution into block application with sophisticated early rejection logic, comprehensive block validation, performs chain reorganization when a better fork emerges, manages DLT mode for snapshot-based nodes, implements emergency consensus mode activation/deactivation, provides vote-weighted fork comparison for HF12, and **NEW**: exposes fork database access for diagnostic monitoring -- block_log: Provides persistent storage for blocks, enabling recovery and serving as the source of irreversible blocks -- dlt_block_log: Separate rolling block log for DLT nodes that maintains a sliding window of recent irreversible blocks for P2P synchronization -- validator: Integrates validator scheduling with emergency mode awareness, handles fork collisions through two-level resolution system, manages stuck-head timeout mechanism, implements HF12 fork collision resolution, and provides automatic chain linking when parent blocks arrive -- **NEW**: P2P monitoring system: Real-time monitoring of fork database storage statistics including linked/unlinked index sizes, minimum/maximum block numbers, and comprehensive storage health metrics -- emergency consensus: Implements timeout-based emergency mode activation, hybrid validator scheduling, and deterministic tie-breaking mechanisms -- compare_fork_branches: New HF12 function that performs vote-weighted fork comparison with +10% bonus for longer chains -- remove_blocks_by_number: New function that removes all blocks at a specific height to prevent memory bloat from dead-fork blocks - -Key responsibilities: -- Track reversible blocks in memory (fork DB) with enhanced caching for out-of-order blocks, comprehensive duplicate detection, emergency mode tie-breaking, automatic stale fork pruning, and gap-based early rejection -- Implement sophisticated early rejection logic to prevent unnecessary fork database operations and infinite synchronization loops -- Detect and select the best chain by comparing heads with improved validation, emergency mode awareness, and HF12 vote-weighted comparison -- Reorganize the chain when a higher fork becomes active with better error recovery, emergency mode integration, and fork collision resolution -- Manage DLT mode for snapshot-based nodes with automatic fork database seeding capabilities -- Implement emergency consensus mode activation based on timeout thresholds -- Provide hybrid validator scheduling during emergency periods with deterministic tie-breaking -- Persist irreversible blocks to both block_log and dlt_block_log with enhanced reliability and emergency mode awareness -- Serve recent blocks to P2P peers through dlt_block_log for faster synchronization -- Handle emergency validator account creation and key management for consensus recovery -- Distinguish between different types of invalid blocks and handle them appropriately to prevent system degradation -- **New**: Provide comprehensive diagnostic accessors for monitoring fork database storage statistics including linked/unlinked index sizes and block number ranges -- **New**: Integrate diagnostic accessors into P2P monitoring system for real-time storage analytics -- **New**: Enable automatic chain linking when parent blocks arrive via _push_next() mechanism -- **New**: Enhance duplicate detection and prevention throughout the system -- **New**: Implement separate handling paths for linear extensions vs actual fork switches during chain reorganization -- **New**: Add detailed debug logging prefixes (FORK-SWITCH-POP, FORK-RECOVER-POP) for better traceability - -**Section sources** -- [fork_database.hpp:53-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L168) -- [fork_database.cpp:33-92](file://libraries/chain/fork_database.cpp#L33-L92) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [dlt_block_log.hpp:13-33](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L13-L33) -- [validator.cpp:521-544](file://plugins/validator/validator.cpp#L521-L544) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -## Architecture Overview -The fork resolution pipeline integrates with block application and persistence with enhanced early rejection, sophisticated block validation, DLT mode support, automatic seeding mechanisms, emergency consensus recovery, advanced fork collision resolution, automatic chain linking, and **NEW**: comprehensive diagnostic monitoring: - -```mermaid -sequenceDiagram -participant Net as "Network" -participant DB as "database.cpp" -participant FDB as "fork_database.cpp" -participant WIT as "validator.cpp" -participant BL as "block_log.hpp" -participant DLTL as "dlt_block_log.cpp" -participant MON as "P2P Monitoring" -Net->>DB : "push_block(new_block)" -DB->>DB : "Early rejection checks" -DB->>DB : "Validate block types and conditions" -DB->>FDB : "push_block(new_block)" -alt "Block already known" -FDB-->>DB : "Ignore duplicate (duplicate detection)" -else "Unlinkable block" -FDB-->>DB : "Cache in unlinked_index" -else "Valid block" -FDB-->>DB : "Insert and _push_next" -DB->>DB : "Check emergency consensus timeout" -alt "Emergency mode activated" -DB->>WIT : "Override validator schedule to emergency validator" -DB->>FDB : "set_emergency_mode(true)" -DB->>DB : "Skip LIB advancement during emergency" -else "Normal mode" -DB->>DB : "Check new_head vs head_block_id()" -alt "Need fork switch" -DB->>DB : "HF12 : compare_fork_branches()" -DB->>FDB : "fetch_branch_from(new_head.id, head_block_id())" -FDB-->>DB : "branches" -DB->>DB : "pop blocks until common ancestor" -DB->>DB : "apply blocks from new fork" -end -end -DB->>BL : "persist irreversible blocks" -DB->>DLTL : "append to dlt_block_log (if enabled)" -DB->>MON : "collect diagnostic metrics" -MON->>MON : "analyze fork storage statistics" -``` - -**Diagram sources** -- [database.cpp:1204-1270](file://libraries/chain/database.cpp#L1204-L1270) -- [fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) -- [validator.cpp:521-544](file://plugins/validator/validator.cpp#L521-L544) -- [dlt_block_log.cpp:336-340](file://libraries/chain/dlt_block_log.cpp#L336-L340) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -## Detailed Component Analysis - -### Enhanced Gap-Based Early Rejection Logic and Block Validation -**Updated** The database now implements sophisticated early rejection logic that intelligently validates different types of blocks to prevent unnecessary processing and infinite synchronization loops. The system now includes a 100-block gap threshold to prevent memory bloat from dead-fork blocks. - -The early rejection logic includes: - -1. **Already Applied Block Detection**: If a block is at or before the current head and matches the existing block ID, it's ignored to prevent duplicate processing -2. **Different Fork Detection**: Blocks that are at or before the head but on different forks are silently rejected if their parent is not in the fork database -3. **Far Ahead Block Rejection**: Blocks that are far ahead of the current head with unknown parents are silently rejected to prevent P2P sync restart loops -4. **Parent Unknown Detection**: Blocks with unknown parents are rejected to prevent fork database overflow and sync disruption -5. **Gap-Based Rejection**: For blocks with gaps > 100 blocks, immediate rejection prevents memory bloat from dead-fork chains - -```mermaid -flowchart TD -Start(["Block Processing Request"]) --> CheckHead["Check if block_num <= head_block_num()"] -CheckHead --> IsBeforeHead{"Block at or before head?"} -IsBeforeHead --> |Yes| CheckExisting["Check existing block ID"] -CheckExisting --> MatchExisting{"ID matches existing?"} -MatchExisting --> |Yes| IgnoreBlock["Ignore block (already applied)"] -MatchExisting --> |No| CheckParent["Check parent in fork_db"] -CheckParent --> ParentUnknown{"Parent unknown?"} -ParentUnknown --> |Yes| RejectFork["Reject different fork block"] -ParentUnknown --> |No| AllowProcess["Allow processing"] -IsBeforeHead --> |No| CheckFarAhead["Check far ahead blocks"] -CheckFarAhead --> FarAhead{"Block far ahead?"} -FarAhead --> |Yes| CheckParentUnknown["Check parent unknown"] -CheckParentUnknown --> ParentUnknown2{"Parent unknown?"} -ParentUnknown2 --> |Yes| CheckGap["Calculate gap size"] -CheckGap --> GapTooBig{"Gap > 100 blocks?"} -GapTooBig --> |Yes| RejectFarAhead["Reject far ahead block (memory protection)"] -GapTooBig --> |No| DeferBlock["Defer to fork_db unlinked_index"] -ParentUnknown2 --> |No| AllowProcess -FarAhead --> |No| AllowProcess -AllowProcess --> ProcessBlock["Process block normally"] -IgnoreBlock --> End(["Complete"]) -RejectFork --> End -RejectFarAhead --> End -DeferBlock --> End -ProcessBlock --> End -``` - -**Diagram sources** -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) - -**Section sources** -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) - -### Enhanced Duplicate Block Detection and Prevention -**New Section** The fork database now includes comprehensive duplicate block detection to prevent redundant processing and improve P2P synchronization reliability. - -Duplicate detection mechanisms: -- Pre-insertion ID check against existing blocks in the index -- Prevention of duplicate processing during snapshot imports and P2P re-transmissions -- Efficient early rejection of already-applied blocks through database-level validation -- Comprehensive duplicate handling in emergency mode scenarios - -```mermaid -flowchart TD -Start(["Block Insertion Request"]) --> CheckDup["Check existing ID in index"] -CheckDup --> IsDup{"ID exists?"} -IsDup --> |Yes| Return["Return existing head (no-op)"] -IsDup --> |No| ValidatePrev["Validate previous block linkage"] -ValidatePrev --> LinkOK{"Link valid?"} -LinkOK --> |No| CacheUnlink["Cache in unlinked_index"] -LinkOK --> |Yes| InsertBlock["Insert into _index"] -InsertBlock --> PushNext["_push_next(new_item)"] -PushNext --> UpdateHead["Update _head if higher"] -Return --> End(["Complete"]) -CacheUnlink --> End -UpdateHead --> End -``` - -**Diagram sources** -- [fork_database.cpp:48-84](file://libraries/chain/fork_database.cpp#L48-L84) - -**Section sources** -- [fork_database.cpp:48-55](file://libraries/chain/fork_database.cpp#L48-L55) - -### Enhanced Fork Database with Improved Error Handling -**Updated** The fork database now includes comprehensive error handling, sophisticated tie-breaking mechanisms for emergency consensus scenarios, automatic stale fork pruning capabilities, enhanced gap-based early rejection logic, and **NEW**: comprehensive diagnostic accessors for storage statistics monitoring. - -The fork database supports: -- Pushing a block and linking it to the previous block with duplicate prevention -- Tracking the current head with enhanced validation and emergency mode tie-breaking -- Fetching branches from two heads to a common ancestor -- Walking the main branch to a given block number -- Removing blocks and limiting fork depth -- **New**: Iterative processing of cached unlinked blocks via `_push_next` -- **New**: Duplicate detection to prevent redundant processing during snapshot imports -- **New**: Enhanced error handling for unlinkable blocks with comprehensive logging -- **New**: Emergency mode tie-breaking with deterministic hash-based resolution for consensus stability -- **New**: Automatic stale fork pruning through `remove_blocks_by_number()` function -- **New**: Enhanced pruning system with `set_max_size()` that cleans both linked and unlinked indices -- **New**: Gap-based early rejection logic integrated with automatic chain linking -- **New**: Diagnostic accessors for monitoring storage statistics including linked/unlinked sizes and block number ranges - -```mermaid -classDiagram -class fork_database { -+push_block(b) -+set_head(h) -+head() -+pop_block() -+is_known_block(id) -+fetch_block(id) -+fetch_block_by_number(n) -+fetch_branch_from(first, second) -+walk_main_branch_to_num(block_num) -+fetch_block_on_main_branch_by_number(block_num) -+set_max_size(s) -+reset() -+start_block(b) -+remove(b) -+remove_blocks_by_number(num) -+set_emergency_mode(active) -+is_emergency_mode() -+linked_size() size_t -+unlinked_size() size_t -+linked_min_block_num() uint32_t -+linked_max_block_num() uint32_t -+unlinked_min_block_num() uint32_t -+unlinked_max_block_num() uint32_t --_push_block(item) --_push_next(new_item) --_emergency_consensus_active --_max_size --_index --_unlinked_index --_head -} -class fork_item { -+num -+invalid -+id -+data -+prev -+previous_id() -} -fork_database --> fork_item : "stores" -``` - -**Diagram sources** -- [fork_database.hpp:20-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L20-L168) -- [fork_database.cpp:33-278](file://libraries/chain/fork_database.cpp#L33-L278) - -Implementation highlights: -- **Enhanced duplicate detection**: Blocks are checked against existing IDs before insertion to prevent duplicate processing -- **Improved linking validation**: Ensures each new block's previous ID exists in the index and is not marked invalid -- **Robust unlinked block caching**: Cached blocks are processed iteratively when their parent appears via `_push_next` -- **Maximum fork depth enforcement**: Prevents unbounded growth; older blocks are pruned with enhanced cleanup -- **Better error handling**: Comprehensive exception handling for unlinkable blocks with logging -- **Automatic seeding support**: Works seamlessly with DLT mode to enable immediate P2P synchronization -- **Emergency mode tie-breaking**: During emergency mode, deterministic hash-based tie-breaking ensures consensus stability when multiple emergency producers compete at the same height -- **Enhanced exception management**: Sophisticated handling of different types of block validation failures -- **Automatic stale fork pruning**: New `remove_blocks_by_number()` function clears stale competing blocks from dead forks -- **Enhanced pruning system**: `set_max_size()` now cleans both `_index` and `_unlinked_index` for optimal memory management -- **Gap-based early rejection**: Integrated with automatic chain linking to prevent memory bloat while maintaining network efficiency -- **NEW**: **Diagnostic accessors**: Comprehensive monitoring capabilities for fork database storage statistics - -**Section sources** -- [fork_database.hpp:111-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L111-L168) -- [fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) - -### Branch Selection and Common Ancestor Detection -Branch selection relies on walking both branches backward until a common ancestor is found. The method returns two vectors representing the branches from each head to the common ancestor. - -```mermaid -flowchart TD -Start(["Start"]) --> GetHeads["Get first and second heads"] -GetHeads --> WalkLoop1["While first.head.block_num > second.head.block_num:
append first to branch1
advance first.prev"] -WalkLoop1 --> WalkLoop2["While second.head.block_num > first.head.block_num:
append second to branch2
advance second.prev"] -WalkLoop2 --> FindCommon["While first.head.previous != second.head.previous:
append both to respective branches
advance both"] -FindCommon --> DoneCommon["If both valid:
append both to branches"] -DoneCommon --> Return(["Return branches"]) -``` - -**Diagram sources** -- [fork_database.cpp:189-231](file://libraries/chain/fork_database.cpp#L189-L231) - -**Section sources** -- [fork_database.cpp:189-231](file://libraries/chain/fork_database.cpp#L189-L231) - -### Enhanced Chain Reorganization Process -**Updated** The chain reorganization process now includes improved early rejection logic, better error handling, DLT mode awareness, emergency consensus integration, HF12 fork comparison capabilities, automatic chain linking for enhanced P2P synchronization reliability, and **NEW**: comprehensive diagnostic monitoring for storage statistics. - -When a new head is higher and does not build off the current head, the database: -- Performs sophisticated early rejection checks to prevent unnecessary fork switches -- **New**: Uses HF12 logic with `compare_fork_branches()` for vote-weighted fork comparison -- **New**: Applies +10% bonus to longer chain in vote-weighted comparison -- **New**: Falls back to simple longest-chain rule for pre-HF12 compatibility -- Computes branches to the common ancestor with enhanced validation -- Pops blocks until reaching the common ancestor with improved error recovery -- Applies blocks from the new fork in reverse order with comprehensive exception handling -- Handles exceptions by invalidating the problematic fork and restoring the good fork with enhanced logging -- **New**: Works seamlessly with DLT mode to maintain fork database consistency -- **New**: Skips LIB advancement during emergency mode to prevent premature irreversibility -- **New**: Implements vote-weighted chain comparison for HF12 and above for more robust consensus -- **New**: Integrates automatic chain linking via _push_next() when parent blocks arrive -- **New**: Implements separate handling paths for linear extensions vs actual fork switches -- **New**: Adds detailed debug logging prefixes (FORK-SWITCH-POP, FORK-RECOVER-POP) for better traceability -- **New**: Monitors storage statistics during chain reorganization for performance optimization - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant FDB as "fork_database.cpp" -DB->>DB : "Early rejection checks" -DB->>FDB : "push_block(new_block)" -FDB-->>DB : "new_head" -DB->>DB : "if new_head higher and differs" -DB->>DB : "Validate current head in fork_db" -DB->>DB : "HF12 : compare_fork_branches()" -DB->>FDB : "fetch_branch_from(new_head.id, head_block_id())" -FDB-->>DB : "branches" -DB->>DB : "pop blocks until common ancestor" -loop "for each block in new fork" -DB->>DB : "apply_block(block)" -DB->>DB : "Handle exceptions with rollback" -end -DB-->>DB : "return true (switched)" -``` - -**Diagram sources** -- [database.cpp:1037-1177](file://libraries/chain/database.cpp#L1037-L1177) -- [fork_database.cpp:189-231](file://libraries/chain/fork_database.cpp#L189-L231) - -**Section sources** -- [database.cpp:1037-1177](file://libraries/chain/database.cpp#L1037-L1177) - -### Enhanced Chain Reorganization with Separate Handling Paths -**New Section** The chain reorganization process now implements separate handling paths for linear extensions versus actual fork switches, providing more efficient processing and better error recovery. - -When a new head is higher and does not build off the current head, the database: -- **Linear Extension Path**: When `branches.second` is empty (block extends directly from current head) - - No fork switching required - - Some blocks from `branches.first` may have been already applied - - Reset fork database to match current database head - - No pop operations needed -- **Actual Fork Switch Path**: When `branches.second` is not empty (divergent fork) - - Pop blocks from current fork until common ancestor - - Apply blocks from new fork in reverse order - - Comprehensive exception handling with rollback - - Detailed debug logging with FORK-SWITCH-POP prefix - -```mermaid -flowchart TD -Start(["Fork Switch Decision"]) --> CheckBranches{"branches.second empty?"} -CheckBranches --> |Yes| LinearExt["Linear Extension Path"] -CheckBranches --> |No| ActualFork["Actual Fork Switch Path"] -LinearExt --> ResetFork["Reset fork_db to match DB head"] -ResetFork --> Complete["Complete without pop operations"] -ActualFork --> PopBlocks["Pop blocks until common ancestor"] -PopBlocks --> ApplyBlocks["Apply blocks from new fork"] -ApplyBlocks --> CheckExceptions{"Exception occurred?"} -CheckExceptions --> |Yes| Rollback["Rollback and restore original fork"] -CheckExceptions --> |No| UpdateHead["Update fork_db head"] -Rollback --> Complete -UpdateHead --> Complete -``` - -**Diagram sources** -- [database.cpp:1420-1510](file://libraries/chain/database.cpp#L1420-L1510) - -**Section sources** -- [database.cpp:1420-1510](file://libraries/chain/database.cpp#L1420-L1510) - -### Enhanced Debug Logging with Prefixes -**New Section** The system now includes detailed debug logging prefixes for better traceability and debugging of fork resolution processes. - -Debug logging prefixes: -- **FORK-SWITCH-POP**: Logs when popping blocks during actual fork switching -- **FORK-RECOVER-POP**: Logs when popping blocks during fork recovery after exceptions -- **FORK-SWITCH-APPLY**: Logs when applying blocks from new fork during fork switch -- **FORK-RECOVER-APPLY**: Logs when re-applying blocks to restore original fork - -These prefixes help developers and operators quickly identify the type of fork resolution operation being performed and troubleshoot issues more effectively. - -**Section sources** -- [database.cpp:1432-1498](file://libraries/chain/database.cpp#L1432-L1498) - -### DLT Mode Integration and Automatic Seeding -**New Section** The database now supports DLT (Data Ledger Technology) mode for snapshot-based nodes, with automatic seeding of the fork database to enable immediate P2P synchronization. - -DLT mode features: -- **Automatic seeding**: When a snapshot is imported, the fork database is automatically seeded from either the DLT block log or chain state -- **Dual block logging**: Maintains both regular block_log and DLT block_log for different use cases -- **Gap handling**: Manages gaps between DLT block log and fork database during initial synchronization -- **Rolling window**: DLT block log maintains a sliding window of recent blocks for P2P peers - -```mermaid -flowchart TD -Start(["DLT Mode Detection"]) --> CheckLog["Check block_log head"] -CheckLog --> HasHead{"Has head block?"} -HasHead --> |Yes| NormalMode["Normal mode: use block_log head"] -HasHead --> |No| DLTMode["DLT mode detected"] -DLTMode --> SeedFromDLT["Try to seed from DLT block_log"] -SeedFromDLT --> SeedSuccess{"Seed successful?"} -SeedSuccess --> |Yes| ImmediateSync["Enable immediate P2P sync"] -SeedSuccess --> |No| MinimalSeed["Create minimal fork_item"] -MinimalSeed --> WaitFirstBlock["Wait for first block to apply"] -ImmediateSync --> End(["Ready for P2P sync"]) -WaitFirstBlock --> End -``` - -**Diagram sources** -- [database.cpp:259-294](file://libraries/chain/database.cpp#L259-L294) - -**Section sources** -- [database.cpp:259-294](file://libraries/chain/database.cpp#L259-L294) -- [database.hpp:57-78](file://libraries/chain/include/graphene/chain/database.hpp#L57-L78) - -### Enhanced Irreversible Block Determination and Persistence -**Updated** Irreversible blocks are determined by consensus thresholds and persisted to both block_log and dlt_block_log with enhanced reliability, DLT mode awareness, emergency consensus integration, and **NEW**: comprehensive diagnostic monitoring for storage statistics. - -The database updates last irreversible block (LIB) and writes blocks to logs when they become irreversible: -- **DLT mode awareness**: Skips block_log writes in DLT mode while still maintaining dlt_block_log -- **Dual persistence**: Writes to both block_log and dlt_block_log for comprehensive coverage -- **Gap logging**: Suppresses repeated warnings about missing blocks in fork database during initial synchronization -- **Rolling window management**: Automatically truncates DLT block log when it exceeds configured limits -- **Emergency mode integration**: Skips LIB advancement during emergency mode to prevent premature irreversibility -- **Enhanced validation**: Sophisticated block validation prevents invalid blocks from becoming irreversible -- **Stale fork pruning**: Automatically prunes stale competing blocks from dead forks at each height -- **Storage monitoring**: Collects and reports fork database storage statistics for performance optimization - -```mermaid -flowchart TD -Start(["After block application"]) --> CheckLIB["Check consensus threshold for LIB"] -CheckLIB --> CheckEmergency{"Emergency mode active?"} -CheckEmergency --> |Yes| SkipLIB["Skip LIB advancement"] -CheckEmergency --> |No| UpdateLIB["Update last_irreversible_block_num/id/ref fields"] -UpdateLIB --> CheckDLT{"DLT mode enabled?"} -CheckDLT --> |Yes| SkipBlockLog["Skip block_log write"] -CheckDLT --> |No| WriteBlockLog["Write to block_log"] -WriteBlockLog --> WriteDLT["Write to dlt_block_log"] -SkipBlockLog --> WriteDLT -WriteDLT --> CheckDLTWindow["Check DLT window size"] -CheckDLTWindow --> Truncate{"Exceeds limit?"} -Truncate --> |Yes| TruncateDLT["Truncate DLT block log"] -Truncate --> |No| PruneStale["Prune stale competing blocks"] -TruncateDLT --> PruneStale -PruneStale --> CollectStats["Collect fork storage statistics"] -CollectStats --> End(["Ready for recovery"]) -SkipLIB --> End -``` - -**Diagram sources** -- [database.cpp:4444-4533](file://libraries/chain/database.cpp#L4444-L4533) -- [dlt_block_log.cpp:336-340](file://libraries/chain/dlt_block_log.cpp#L336-L340) - -**Section sources** -- [database.cpp:4444-4533](file://libraries/chain/database.cpp#L4444-L4533) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) - -### Enhanced P2P Fallback Mechanisms -**New Section** The P2P system now includes strengthened fallback mechanisms to handle network partitions and improve synchronization reliability, with **NEW**: comprehensive diagnostic monitoring for storage statistics. - -P2P fallback features: -- **Enhanced error handling**: Better propagation of unlinkable block exceptions to network layer -- **Improved peer management**: More robust handling of disconnected peers and connection failures -- **Faster synchronization**: Automatic seeding enables immediate P2P sync for DLT nodes -- **Better network partition handling**: Enhanced mechanisms to recover from network splits -- **Intelligent block rejection**: Prevents infinite sync restart loops through early rejection logic -- **Gap-based protection**: 100-block threshold prevents memory bloat from dead-fork chains -- **Storage monitoring**: Real-time monitoring of fork database storage statistics for performance optimization - -```mermaid -sequenceDiagram -participant Peer as "P2P Peer" -participant P2P as "p2p_plugin.cpp" -participant DB as "database.cpp" -Peer->>P2P : "handle_block(block)" -P2P->>DB : "accept_block(block)" -alt "Block valid" -DB-->>P2P : "true" -P2P-->>Peer : "acknowledge" -else "Unlinkable block" -DB-->>P2P : "unlinkable_block_exception" -P2P-->>Peer : "propagate exception" -P2P->>P2P : "enhanced error handling" -P2P-->>Peer : "fallback to alternative sync" -P2P->>P2P : "collect fork storage metrics" -end -``` - -**Diagram sources** -- [p2p_plugin.cpp:118-164](file://plugins/p2p/p2p_plugin.cpp#L118-L164) - -**Section sources** -- [p2p_plugin.cpp:118-164](file://plugins/p2p/p2p_plugin.cpp#L118-L164) - -### Enhanced API Methods for Fork Detection, Chain Validation, and Recovery -**Updated** Enhanced with improved duplicate detection, DLT mode support, automatic seeding capabilities, emergency mode integration, sophisticated block validation, HF12 fork comparison capabilities, gap-based early rejection, automatic stale fork pruning, **NEW**: comprehensive diagnostic accessors, and automatic chain linking. - -- Fork detection and branch retrieval: - - get_block_ids_on_fork(head_of_fork): Returns ordered list of block IDs from the fork head back to the common ancestor - - fetch_branch_from(first, second): Returns two branches leading to a common ancestor - - **New**: compare_fork_branches(branch_a_tip, branch_b_tip): Vote-weighted fork comparison for HF12 -- Chain validation: - - validate_block(new_block, skip): Validates block Merkle root and size with enhanced error handling -- State recovery: - - open(): Initializes database and starts fork DB at head block with DLT mode awareness - - reindex(): Replays blocks and restarts fork DB at the new head - - find_block_id_for_num(block_num)/get_block_id_for_num(block_num): Resolves block ID across block log, fork DB, and TAPOS buffer with enhanced duplicate handling -- **New**: DLT mode management: - - set_dlt_mode(enabled): Enables/disables DLT mode for snapshot-based nodes - - open_from_snapshot(): Optimized initialization for snapshot-based nodes with automatic seeding -- **New**: Emergency mode management: - - set_emergency_mode(active): Activates or deactivates emergency consensus mode - - is_emergency_mode(): Checks current emergency consensus mode status -- **New**: Enhanced block validation: - - Sophisticated early rejection logic prevents infinite synchronization loops - - Intelligent duplicate detection prevents redundant processing - - Comprehensive exception handling for different block validation failures - - Gap-based rejection with 100-block threshold prevents memory bloat -- **New**: Stale fork management: - - remove_blocks_by_number(num): Removes all blocks at specific height to prune dead forks - - Enhanced pruning system with automatic cleanup of stale competing blocks -- **New**: Automatic chain linking: - - _push_next(): Iterative processing of cached unlinked blocks when parents arrive - - Gap-based protection prevents memory bloat from dead-fork chains -- **New**: Separate handling paths: - - Linear extension vs actual fork switch processing for improved efficiency - - Detailed debug logging with FORK-SWITCH-POP and FORK-RECOVER-POP prefixes -- **New**: Comprehensive diagnostic accessors: - - linked_size(): Returns number of blocks in linked index - - unlinked_size(): Returns number of blocks in unlinked index - - linked_min_block_num(): Returns minimum block number in linked index - - linked_max_block_num(): Returns maximum block number in linked index - - unlinked_min_block_num(): Returns minimum block number in unlinked index - - unlinked_max_block_num(): Returns maximum block number in unlinked index - -**Section sources** -- [database.hpp:115-128](file://libraries/chain/include/graphene/chain/database.hpp#L115-L128) -- [database.cpp:561-580](file://libraries/chain/database.cpp#L561-L580) -- [database.cpp:738-792](file://libraries/chain/database.cpp#L738-L792) -- [database.cpp:206-230](file://libraries/chain/database.cpp#L206-L230) -- [database.cpp:476-515](file://libraries/chain/database.cpp#L476-L515) -- [fork_database.hpp:111-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L111-L168) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) - -### Examples of Enhanced Fork Scenarios and Resolution Processes -**Updated** Enhanced with improved out-of-order block handling, duplicate detection, DLT mode integration, automatic seeding capabilities, emergency consensus recovery, sophisticated early rejection logic, advanced fork collision resolution, automatic chain linking, stale fork pruning, separate handling paths, detailed debug logging, and **NEW**: comprehensive diagnostic monitoring. - -- Scenario A: Out-of-order arrival of blocks with improved caching and automatic linking - - Behavior: New blocks are inserted into the unlinked cache and later inserted when their parent appears via `_push_next`, which automatically links the entire chain - - Mechanism: Enhanced `_push_next` iteratively processes pending blocks whose parent now exists, with comprehensive error handling and automatic chain completion -- Scenario B: Network partition resolves with a longer chain and improved early rejection - - Behavior: The database performs sophisticated early rejection checks, detects a higher head, computes branches, pops blocks, and applies the new fork - - Mechanism: Enhanced early rejection logic prevents unnecessary fork switches and improves P2P synchronization reliability -- Scenario C: Invalid block on a fork with improved error handling - - Behavior: The fork is invalidated and removed; the database restores the good fork and throws the exception with enhanced logging - - Mechanism: Comprehensive exception handling with rollback to previous state and improved error reporting -- **New Scenario D**: Fresh snapshot import with automatic seeding - - Behavior: DLT mode is detected, fork database is automatically seeded from DLT block log or chain state, enabling immediate P2P synchronization - - Mechanism: Enhanced DLT mode detection and automatic seeding prevents P2P synchronization delays -- **New Scenario E**: DLT block log gap handling - - Behavior: When DLT block log falls behind fork database, the system logs warnings once and continues operation - - Mechanism: Gap logging suppression prevents log flooding while maintaining operational awareness -- **New Scenario F**: Emergency consensus mode activation - - Behavior: When no blocks are produced for CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC seconds, emergency mode activates with deterministic tie-breaking - - Mechanism: Emergency validator takes over all validator slots, emergency mode flag is set, and deterministic hash-based tie-breaking ensures consensus stability -- **New Scenario G**: Emergency consensus mode deactivation - - Behavior: When LIB advances past emergency_consensus_start_block, emergency mode is deactivated and normal validator scheduling resumes - - Mechanism: Emergency mode flag is cleared and fork database is notified of emergency mode termination -- **New Scenario H**: Sophisticated early rejection in action - - Behavior: Database rejects blocks that are already applied, on different forks, or far ahead with unknown parents to prevent infinite sync loops - - Mechanism: Intelligent block validation prevents unnecessary processing and system degradation -- **New Scenario I**: Duplicate block prevention - - Behavior: Database and fork database work together to detect and prevent duplicate block processing - - Mechanism: Comprehensive duplicate detection prevents redundant CPU usage and improves synchronization reliability -- **New Scenario J**: HF12 fork collision resolution - - Behavior: When competing blocks appear at the same height, database uses vote-weighted comparison to determine the stronger fork - - Mechanism: `compare_fork_branches()` calculates total vote weight per validator, applies +10% bonus to longer chain, and resolves ties deterministically -- **New Scenario K**: Stuck-head timeout mechanism - - Behavior: After 21 consecutive deferrals (one full validator round), database removes stale competing blocks and produces on the canonical chain - - Mechanism: `fork_collision_defer_count_` tracks deferral attempts, `remove_blocks_by_number()` clears stale blocks, and timeout ensures network progress -- **New Scenario L**: Automatic stale fork pruning - - Behavior: Database periodically removes stale competing blocks from dead forks to prevent memory bloat and improve performance - - Mechanism: `remove_blocks_by_number()` clears all blocks at specific heights, combined with `set_max_size()` pruning for optimal memory usage -- **New Scenario M**: Gap-based early rejection protection - - Behavior: Database rejects blocks with gaps > 100 blocks to prevent memory bloat from dead-fork chains - - Mechanism: 100-block threshold prevents accumulation of stale blocks while allowing normal out-of-order processing -- **New Scenario N**: Automatic chain linking when parent arrives - - Behavior: Database caches unlinkable blocks and automatically links them when their parents arrive via _push_next() - - Mechanism: Iterative processing of cached blocks prevents memory bloat and maintains network efficiency -- **New Scenario O**: Linear extension vs fork switch distinction - - Behavior: Database distinguishes between linear extensions (no fork) and actual fork switches (divergent chains) with separate handling paths - - Mechanism: When `branches.second` is empty, database resets fork_db without pop operations; when not empty, database performs full fork switch with detailed logging -- **New Scenario P**: Detailed debug logging with prefixes - - Behavior: Database logs detailed information about fork resolution operations with FORK-SWITCH-POP and FORK-RECOVER-POP prefixes - - Mechanism: Enhanced logging helps developers trace fork resolution steps and identify issues more quickly -- **New Scenario Q**: Comprehensive diagnostic monitoring in action - - Behavior: P2P monitoring system collects and analyzes fork database storage statistics in real-time - - Mechanism: linked_size(), unlinked_size(), and block number range metrics provide insights into fork database health and performance -- **New Scenario R**: Storage health optimization - - Behavior: Database uses diagnostic metrics to optimize fork database performance and prevent memory bloat - - Mechanism: Storage statistics inform pruning decisions and capacity planning for optimal system performance - -**Section sources** -- [fork_database.cpp:92-103](file://libraries/chain/fork_database.cpp#L92-L103) -- [database.cpp:1075-1087](file://libraries/chain/database.cpp#L1075-L1087) -- [database.cpp:259-294](file://libraries/chain/database.cpp#L259-L294) -- [database.cpp:4581-4594](file://libraries/chain/database.cpp#L4581-L4594) -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [validator.cpp:597-612](file://plugins/validator/validator.cpp#L597-L612) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -## Emergency Consensus Recovery System - -### Emergency Consensus Mode Activation -The emergency consensus mode activates automatically when no blocks are produced for more than CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC seconds (1 hour by default). This mechanism ensures blockchain continuity during extended network partitions or validator failures. - -Emergency mode activation process: -- **Timeout detection**: The database checks if seconds_since_LIB >= CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC -- **Mode activation**: Sets emergency_consensus_active = true and records emergency_consensus_start_block -- **Emergency validator setup**: Creates or updates emergency validator account with CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY -- **Penalty reset**: Resets all validator penalties and re-enables shut-down validators -- **Schedule override**: Overrides validator schedule so all slots are filled by emergency validator -- **Fork database notification**: Sets emergency mode flag in fork database for deterministic tie-breaking - -```mermaid -flowchart TD -Start(["Block Application"]) --> CheckTimeout["Check LIB timestamp vs block timestamp"] -CheckTimeout --> TimeoutExceeded{"seconds_since_LIB >= TIMEOUT?"} -TimeoutExceeded --> |No| NormalOperation["Continue normal operation"] -TimeoutExceeded --> |Yes| ActivateEmergency["Activate Emergency Mode"] -ActivateEmergency --> CreateWitness["Create/Update Emergency validator"] -CreateWitness --> ResetPenalties["Reset All validator Penalties"] -ResetPenalties --> OverrideSchedule["Override validator Schedule"] -OverrideSchedule --> NotifyForkDB["Notify Fork Database"] -NotifyForkDB --> LogActivation["Log Emergency Mode Activation"] -LogActivation --> End(["Emergency Mode Active"]) -NormalOperation --> End -``` - -**Diagram sources** -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) - -### Hybrid validator Scheduling During Emergency -During emergency mode, the validator scheduling system operates differently to ensure consensus stability: -- **All slots filled by emergency validator**: All CHAIN_MAX_WITNESSES slots are assigned to CHAIN_EMERGENCY_WITNESS_ACCOUNT -- **Deterministic tie-breaking**: Emergency mode uses hash-based tie-breaking for consensus stability -- **Skip LIB advancement**: Post-validation chain does not advance LIB during emergency mode -- **Committee exclusion**: Committee validator is excluded from hardfork vote tally and median computation during emergency - -```mermaid -flowchart TD -EmergencyMode["Emergency Mode Active"] --> OverrideSchedule["Override Schedule: All Slots -> Emergency validator"] -OverrideSchedule --> DeterministicTie["Deterministic Hash-Based Tie-Breaking"] -DeterministicTie --> SkipLIB["Skip LIB Advancement"] -SkipLIB --> CommitteeExclusion["Exclude Committee from Hardfork Votes"] -CommitteeExclusion --> EmergencyWitness["Emergency validator Produces All Blocks"] -EmergencyWitness --> ExitCondition["Check Exit Condition: LIB > Start Block"] -ExitCondition --> |True| DeactivateEmergency["Deactivate Emergency Mode"] -ExitCondition --> |False| ContinueEmergency["Continue Emergency Mode"] -DeactivateEmergency --> NotifyForkDB["Notify Fork Database"] -NotifyForkDB --> NormalOperation["Resume Normal Operation"] -``` - -**Diagram sources** -- [database.cpp:4420-4438](file://libraries/chain/database.cpp#L4420-L4438) -- [database.cpp:4444-4450](file://libraries/chain/database.cpp#L4444-L4450) - -### Emergency validator Account Management -The emergency validator account serves as the single producer during emergency consensus mode: -- **Account name**: CHAIN_EMERGENCY_WITNESS_ACCOUNT (defaults to "committee") -- **Signing key**: CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY (deterministic emergency key) -- **Properties**: Copies median chain properties to avoid skewing median computations -- **Hardfork votes**: Votes for currently applied hardfork version to maintain status quo -- **Penalty management**: Emergency validator participates in penalty reset process - -Emergency validator lifecycle: -- **Creation**: Created automatically during emergency mode activation if not exists -- **Updates**: Key and properties updated during emergency mode reactivation -- **Participation**: Produces blocks for CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS consecutive blocks -- **Cleanup**: Penalties removed and normal operations resume after exit condition met - -**Section sources** -- [config.hpp:114-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L114-L124) -- [database.cpp:4360-4398](file://libraries/chain/database.cpp#L4360-L4398) -- [database.cpp:4400-4419](file://libraries/chain/database.cpp#L4400-L4419) - -### Emergency Mode Tie-Breaking Mechanisms -During emergency consensus mode, deterministic hash-based tie-breaking ensures consensus stability when multiple emergency producers compete at the same height: -- **Hash comparison**: When two blocks compete at the same height, compare block_id hashes -- **Lower hash preferred**: The block with the lower block_id hash becomes the head -- **Consensus stability**: Eliminates fork divergence caused by P2P arrival order differences -- **Deterministic resolution**: All nodes converge on the same block regardless of network topology - -Tie-breaking algorithm: -- **Same height competition**: Only applies when emergency mode is active and blocks compete at identical heights -- **Hash-based decision**: Compare item->id < _head->id for tie-breaking decision -- **Immediate head update**: If tie-breaker selects new head, update _head immediately -- **No fork switching**: Tie-breaking occurs within emergency mode without full fork reorganization - -**Section sources** -- [fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) -- [validator.cpp:521-526](file://plugins/validator/validator.cpp#L521-L526) - -### Emergency Exit Conditions and Recovery -Emergency consensus mode deactivates automatically when: -- **LIB advancement**: Last Irreversible Block number exceeds emergency_consensus_start_block -- **Normal validator rejoin**: Regular validators resume production after emergency period -- **Manual intervention**: System administrator can manually deactivate emergency mode - -Emergency exit process: -- **LIB check**: Monitor LIB advancement past emergency start block -- **Mode deactivation**: Set emergency_consensus_active = false -- **Fork database notification**: Clear emergency mode flag in fork database -- **Normal operation resume**: Resume normal validator scheduling and LIB advancement -- **Penalty restoration**: Restore normal penalty calculations for emergency period - -**Section sources** -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) -- [database.cpp:4428-4430](file://libraries/chain/database.cpp#L4428-L4430) - -## Two-Level Fork Collision Resolution - -### Overview -The two-level fork collision resolution system provides robust handling of competing blocks at the same height, combining immediate vote-weighted comparison with timeout-based fallback mechanisms. This system ensures network progress while maintaining consensus integrity. - -### Level 1: Vote-Weighted Comparison (HF12) -When HF12 is active and competing blocks exist at the same height, the system performs immediate vote-weighted comparison: - -1. **Comparison**: `compare_fork_branches()` calculates total vote weight per validator for both forks -2. **Bonus Application**: Longer chain receives +10% bonus to vote weight -3. **Decision Making**: - - If one fork has significantly more weight: produce on stronger fork - - If comparison is inconclusive: defer to timeout mechanism - - If tied: produce on current fork, continue monitoring - -### Level 2: Stuck-Head Timeout -If the network remains stuck with competing blocks for extended periods: - -1. **Timeout Detection**: After 21 consecutive deferrals (one full validator round) -2. **Action**: Remove all stale competing blocks from the dead fork -3. **Resolution**: Produce on the canonical chain with confirmed majority support -4. **Prevention**: Ensures network doesn't stall indefinitely due to fork collisions - -```mermaid -flowchart TD -Start(["Fork Collision Detected"]) --> CheckHF12{"HF12 Active?"} -CheckHF12 --> |Yes| VoteWeight["Level 1: Vote-Weighted Comparison"] -CheckHF12 --> |No| TimeoutOnly["Level 2: Timeout Only"] -VoteWeight --> Compare["compare_fork_branches()"] -Compare --> Stronger{"Stronger Fork?"} -Stronger --> |Yes| ProduceStrong["Produce on Stronger Fork"] -Stronger --> |No| Tie{"Tied or Unknown?"} -Tie --> |Yes| Defer["Defer to Timeout"] -Tie --> |No| ProduceWeak["Produce on Current Fork"] -Defer --> TimeoutCheck["Check Timeout Counter"] -TimeoutOnly --> TimeoutCheck -TimeoutCheck --> TimeoutExceeded{"Timeout Exceeded (21 deferrals)?"} -TimeoutExceeded --> |Yes| RemoveStale["Remove Stale Competing Blocks"] -TimeoutExceeded --> |No| DeferMore["Continue Deferring"] -RemoveStale --> ProduceCanonical["Produce on Canonical Chain"] -ProduceStrong --> End(["Resolved"]) -ProduceWeak --> End -ProduceCanonical --> End -DeferMore --> End -``` - -**Diagram sources** -- [validator.cpp:565-656](file://plugins/validator/validator.cpp#L565-L656) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) - -**Section sources** -- [validator.cpp:565-656](file://plugins/validator/validator.cpp#L565-L656) -- [validator.cpp:121](file://plugins/validator/validator.cpp#L121) - -## Vote-Weighted Fork Comparison Algorithm - -### compare_fork_branches() Function -The `compare_fork_branches()` function implements HF12's vote-weighted fork comparison system: - -#### Algorithm Steps: -1. **Validation**: Ensure both fork tips exist in fork database -2. **Branch Extraction**: Use `fetch_branch_from()` to get branches to common ancestor -3. **Weight Calculation**: Compute total vote weight per validator for each branch -4. **Bonus Application**: Apply +10% bonus to longer chain -5. **Comparison**: Determine stronger fork or tie - -#### Weight Calculation Details: -- **Per-validator Weight**: Sum of vote weights for each unique validator -- **Emergency validator Exclusion**: Emergency validator votes are excluded from calculation -- **Unique validator Counting**: Each validator contributes only once per branch - -#### Bonus System: -- **Longer Chain Advantage**: +10% bonus applied to the fork with more blocks -- **Consensus Signal**: Reflects stronger network support and production continuity -- **Fairness**: Prevents chains from stalling due to minor vote differences - -```mermaid -flowchart TD -Start(["compare_fork_branches()"]) --> Validate["Validate Fork Tips in Fork DB"] -Validate --> Extract["Extract Branches to Common Ancestor"] -Extract --> CalcA["Calculate Weight for Branch A"] -CalcA --> CalcB["Calculate Weight for Branch B"] -CalcB --> BonusA{"Branch A Longer?"} -CalcB --> BonusB{"Branch B Longer?"} -BonusA --> |Yes| ApplyBonusA["+10% Bonus to Branch A"] -BonusB --> |Yes| ApplyBonusB["+10% Bonus to Branch B"] -ApplyBonusA --> Compare["Compare Weights"] -ApplyBonusB --> Compare -Compare --> Result{"Result"} -Result --> |A Stronger| Return1["Return 1"] -Result --> |B Stronger| ReturnNeg1["Return -1"] -Result --> |Tied| Return0["Return 0"] -``` - -**Diagram sources** -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) - -**Section sources** -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) - -## Automatic Stale Fork Pruning System - -### Purpose -The automatic stale fork pruning system prevents memory bloat and improves performance by removing stale competing blocks from dead forks. This system complements the two-level fork collision resolution by providing proactive cleanup. - -### Implementation -The pruning system consists of two main components: - -#### 1. `remove_blocks_by_number()` Function -- **Targeted Removal**: Removes all blocks at a specific height from the fork database -- **Dead Fork Cleanup**: Clears stale competing blocks that will never become canonical -- **Memory Optimization**: Prevents accumulation of unused fork data - -#### 2. Enhanced Pruning with `set_max_size()` -- **Depth Control**: Limits fork database to configurable maximum depth -- **Automatic Cleanup**: Removes oldest blocks when size limit is exceeded -- **Dual Index Cleaning**: Cleans both linked and unlinked indices for optimal memory usage - -### Pruning Trigger Conditions -- **HF12 Fork Collision**: When stuck-head timeout exceeds threshold, stale blocks are removed -- **Size Limit Exceeded**: When fork database exceeds configured maximum size -- **Network Recovery**: After fork resolution, stale competing blocks are cleaned up -- **Gap-Based Protection**: Prevents memory bloat from dead-fork chains with 100-block threshold -- **Post-Application Cleanup**: Automatic pruning of stale competing blocks at each height - -```mermaid -flowchart TD -Start(["Fork Collision Detected"]) --> CheckTimeout{"Timeout Exceeded?"} -CheckTimeout --> |Yes| RemoveByHeight["remove_blocks_by_number(height)"] -CheckTimeout --> |No| CheckSize{"Max Size Exceeded?"} -RemoveByHeight --> CleanUp["Clean Up Memory"] -CheckSize --> |Yes| PruneOld["Prune Oldest Blocks"] -CheckSize --> |No| Monitor["Monitor Fork Health"] -PruneOld --> CleanUp -Monitor --> End(["Continue Operation"]) -CleanUp --> End -``` - -**Diagram sources** -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [fork_database.cpp:114-146](file://libraries/chain/fork_database.cpp#L114-L146) - -**Section sources** -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [fork_database.cpp:114-146](file://libraries/chain/fork_database.cpp#L114-L146) - -## Enhanced Fork Database Diagnostic Accessors - -### Overview -The fork database now includes comprehensive diagnostic accessors that provide real-time monitoring of storage statistics and health metrics. These accessors enable operators to track fork database performance, identify potential issues, and optimize system resources. - -### Diagnostic Accessor Functions - -#### Storage Size Metrics -- **linked_size()**: Returns the number of blocks currently stored in the linked index -- **unlinked_size()**: Returns the number of blocks currently stored in the unlinked index - -#### Block Number Range Metrics -- **linked_min_block_num()**: Returns the minimum block number in the linked index (0 if empty) -- **linked_max_block_num()**: Returns the maximum block number in the linked index (0 if empty) -- **unlinked_min_block_num()**: Returns the minimum block number in the unlinked index (0 if empty) -- **unlinked_max_block_num()**: Returns the maximum block number in the unlinked index (0 if empty) - -### Implementation Details -The diagnostic accessors provide O(1) access to fork database statistics by leveraging the underlying multi-index container structure: - -```mermaid -classDiagram -class fork_database { -+linked_size() size_t -+unlinked_size() size_t -+linked_min_block_num() uint32_t -+linked_max_block_num() uint32_t -+unlinked_min_block_num() uint32_t -+unlinked_max_block_num() uint32_t --private _index : fork_multi_index_type --private _unlinked_index : fork_multi_index_type -} -``` - -**Diagram sources** -- [fork_database.hpp:128-150](file://libraries/chain/include/graphene/chain/fork_database.hpp#L128-L150) - -### Usage in P2P Monitoring -The diagnostic accessors are integrated into the P2P monitoring system for comprehensive storage analytics: - -```mermaid -sequenceDiagram -participant P2P as "P2P Plugin" -participant DB as "Database" -participant FDB as "Fork Database" -P2P->>DB : "get_fork_db()" -DB-->>P2P : "fork_database reference" -P2P->>FDB : "linked_size()" -FDB-->>P2P : "size_t count" -P2P->>FDB : "unlinked_size()" -FDB-->>P2P : "size_t count" -P2P->>FDB : "linked_min_block_num()" -FDB-->>P2P : "uint32_t min" -P2P->>FDB : "linked_max_block_num()" -FDB-->>P2P : "uint32_t max" -P2P->>FDB : "unlinked_min_block_num()" -FDB-->>P2P : "uint32_t min" -P2P->>FDB : "unlinked_max_block_num()" -FDB-->>P2P : "uint32_t max" -P2P->>P2P : "analyze storage metrics" -``` - -**Diagram sources** -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -### Storage Statistics Collection -The P2P monitoring system collects comprehensive storage statistics for real-time analysis: - -- **Fork Database Head**: Current head block number -- **Last Irreversible Block (LIB)**: Most recent irreversible block number -- **Earliest Available Block**: Minimum block number available for P2P serving -- **DLT Block Log Range**: [start..end] range of blocks in DLT log -- **Block Log End**: End position of regular block log -- **Linked Index Statistics**: Size and [min..max] block number range -- **Unlinked Index Statistics**: Size and [min..max] block number range -- **DLT Mode Status**: Current DLT mode activation state -- **DLT Resize Count**: Number of DLT log resizes - -**Section sources** -- [fork_database.hpp:128-150](file://libraries/chain/include/graphene/chain/fork_database.hpp#L128-L150) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -## Storage Health Monitoring and Analytics - -### Real-Time Monitoring System -The P2P plugin implements a comprehensive monitoring system that collects and analyzes fork database storage statistics in real-time: - -#### Monitoring Components -- **Block Storage Metrics**: Linked and unlinked index sizes, block number ranges -- **DLT Coverage Analysis**: Gap detection between DLT block log and fork database -- **Performance Indicators**: DLT mode status, resize counts, and synchronization health -- **Alert Generation**: Automatic detection of potential storage issues - -#### Gap Detection and Analysis -The system monitors gaps between DLT block log and fork database to ensure complete P2P serving capability: - -```mermaid -flowchart TD -Start(["Storage Analysis"]) --> CheckDLT{"DLT Mode Enabled?"} -CheckDLT --> |Yes| CheckRanges["Check DLT and Fork Ranges"] -CheckDLT --> |No| BasicAnalysis["Basic Storage Analysis"] -CheckRanges --> GapDetection["Detect Coverage Gaps"] -GapDetection --> GapExists{"Gap Detected?"} -GapExists --> |Yes| Alert["Generate Gap Alert"] -GapExists --> |No| Normal["Normal Operation"] -Alert --> LogGap["Log DLT Coverage Gap"] -LogGap --> End(["Complete"]) -Normal --> End -BasicAnalysis --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:762-770](file://plugins/p2p/p2p_plugin.cpp#L762-L770) - -#### Storage Health Indicators -The monitoring system tracks key indicators of fork database health: - -- **Linked Index Utilization**: Percentage of blocks successfully linked to main chain -- **Unlinked Index Growth**: Rate of unlinked block accumulation indicating network issues -- **Block Number Distribution**: Evenness of block number distribution across indices -- **DLT Coverage Completeness**: Percentage of blocks available for P2P serving -- **Storage Capacity Planning**: Predictive analysis of storage requirements - -### Performance Optimization Opportunities -The diagnostic accessors enable several optimization opportunities: - -#### Memory Management -- **Dynamic Capacity Adjustment**: Use linked/unlinked size ratios to adjust fork database capacity -- **Early Warning Systems**: Monitor storage metrics to prevent memory exhaustion -- **Resource Allocation**: Optimize shared memory allocation based on storage patterns - -#### Network Synchronization -- **Out-of-Order Block Handling**: Analyze unlinked index growth to optimize synchronization -- **Peer Selection**: Use storage metrics to select optimal synchronization peers -- **Bandwidth Optimization**: Adjust P2P bandwidth based on storage utilization patterns - -#### Operational Insights -- **Capacity Planning**: Use historical storage metrics for infrastructure planning -- **Performance Tuning**: Adjust fork database parameters based on observed patterns -- **Issue Detection**: Identify potential problems before they impact system performance - -**Section sources** -- [p2p_plugin.cpp:739-771](file://plugins/p2p/p2p_plugin.cpp#L739-L771) - -## Dependency Analysis -**Updated** The fork resolution system now includes DLT mode dependencies, automatic seeding capabilities, comprehensive emergency consensus integration, sophisticated early rejection logic, HF12 fork comparison capabilities, advanced fork collision resolution systems, gap-based early rejection protection, automatic chain linking features, separate handling paths, detailed debug logging, and **NEW**: comprehensive diagnostic monitoring system. - -The fork resolution system depends on: -- fork_database for in-memory fork chain management with enhanced caching, duplicate detection, emergency mode tie-breaking, comprehensive error handling, automatic stale fork pruning, HF12 fork comparison, gap-based early rejection, and **NEW**: diagnostic accessors for storage statistics -- database for integrating fork resolution into block application, DLT mode management, automatic seeding, emergency consensus mode activation/deactivation with sophisticated early rejection logic, block validation, and HF12 vote-weighted fork comparison -- block_log for persistence of irreversible blocks in normal mode -- **New**: dlt_block_log for DLT mode persistence and P2P synchronization support -- **New**: Validator Plugin for emergency mode awareness, fork collision handling, two-level fork collision resolution, stuck-head timeout mechanism, HF12 fork comparison integration, and automatic chain linking -- **New**: emergency consensus configuration for timeout thresholds and emergency validator parameters -- **New**: compare_fork_branches function for HF12 vote-weighted fork comparison -- **New**: Enhanced exception handling for different types of block validation failures -- **New**: Automatic stale fork pruning system with remove_blocks_by_number() function -- **New**: Gap-based early rejection logic with 100-block threshold for memory protection -- **New**: Automatic chain linking system via _push_next() for efficient out-of-order block processing -- **New**: Separate handling paths for linear extensions vs actual fork switches during chain reorganization -- **New**: Detailed debug logging prefixes (FORK-SWITCH-POP, FORK-RECOVER-POP) for better traceability -- **New**: Comprehensive diagnostic monitoring system with real-time storage analytics - -```mermaid -graph LR -FDB["fork_database.cpp"] --> DBCPP["database.cpp"] -DBCPP --> BLH["block_log.hpp"] -DBCPP --> DLTH["dlt_block_log.hpp"] -DBCPP --> WIT["validator.cpp"] -DBH["database.hpp"] --> DBCPP -DLTH --> DBCPP -WIT --> DBCPP -CONFIG["config.hpp"] --> DBCPP -HF12["12.hf"] --> DBCPP -CMP["compare_fork_branches()"] --> DBCPP -PRUNE["remove_blocks_by_number()"] --> FDB -GAP["Gap-Based Rejection"] --> DBCPP -LINK["Automatic Chain Linking"] --> FDB -SEPARATE["Separate Handling Paths"] --> DBCPP -DEBUG["Debug Logging Prefixes"] --> DBCPP -DIAG["Diagnostic Accessors"] --> FDB -MON["P2P Monitoring"] --> DIAG -``` - -**Diagram sources** -- [fork_database.cpp:1-278](file://libraries/chain/fork_database.cpp#L1-L278) -- [database.cpp:1-6669](file://libraries/chain/database.cpp#L1-L6669) -- [dlt_block_log.cpp:1-454](file://libraries/chain/dlt_block_log.cpp#L1-L454) -- [validator.cpp:1-697](file://plugins/validator/validator.cpp#L1-L697) -- [config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -**Section sources** -- [fork_database.cpp:1-278](file://libraries/chain/fork_database.cpp#L1-L278) -- [database.cpp:1-6669](file://libraries/chain/database.cpp#L1-L6669) -- [dlt_block_log.cpp:1-454](file://libraries/chain/dlt_block_log.cpp#L1-L454) -- [validator.cpp:1-697](file://plugins/validator/validator.cpp#L1-L697) -- [config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -## Performance Considerations -**Updated** Enhanced with improved caching, duplicate detection, DLT mode integration, automatic seeding mechanisms, emergency consensus recovery optimizations, sophisticated early rejection logic, HF12 fork comparison capabilities, advanced fork collision resolution systems, gap-based early rejection protection, automatic chain linking features, separate handling paths, detailed debug logging, and **NEW**: comprehensive diagnostic monitoring system. - -- Maximum fork depth: The fork database limits the maximum number of blocks that may be skipped in an out-of-order push, preventing excessive memory usage with enhanced cleanup -- Multi-index containers: Efficient lookups by block ID and previous ID minimize traversal costs with improved indexing -- **Enhanced caching**: Improved unlinked block caching with iterative processing via `_push_next` reduces memory pressure and improves P2P synchronization -- **Duplicate prevention**: Comprehensive duplicate detection prevents redundant processing and reduces CPU overhead -- **Early rejection optimization**: Sophisticated early rejection logic prevents unnecessary fork database operations and improves overall system performance -- **Enhanced error handling**: Comprehensive exception handling with specific error types prevents system degradation and improves reliability -- **Pruning**: set_max_size prunes old blocks from both linked and unlinked indices to keep memory bounded with enhanced cleanup -- **Reorganization cost**: Reorganizing across deep forks requires popping and re-applying blocks; keeping forks shallow improves responsiveness with enhanced error recovery -- **Persistence overhead**: Writing to the block log is required for irreversible blocks; batching and flushing strategies can mitigate latency -- **DLT mode optimization**: Automatic seeding eliminates synchronization delays for snapshot-based nodes, improving overall network health -- **Gap handling**: DLT block log gap logging suppression prevents performance impact from excessive warning messages -- **Emergency mode efficiency**: Emergency mode uses optimized tie-breaking with minimal computational overhead while ensuring consensus stability -- **Hybrid scheduling**: Emergency validator scheduling minimizes complexity compared to full validator rotation during emergency periods -- **Penalty management**: Emergency penalty reset avoids complex penalty calculations during emergency mode, reducing computational load -- **Sophisticated validation**: Early rejection logic prevents unnecessary processing and reduces system load during network partitions -- **HF12 fork comparison**: Vote-weighted comparison adds computational overhead but provides more robust consensus decisions -- **Two-level collision resolution**: Additional logic for fork collision handling adds minimal overhead while providing significant reliability improvements -- **Automatic pruning**: Stale fork pruning prevents memory bloat and maintains optimal performance under fork collision conditions -- **Stuck-head timeout**: 21-block timeout provides reasonable balance between network stability and production efficiency -- **Gap-based protection**: 100-block threshold prevents memory bloat from dead-fork chains while maintaining network efficiency -- **Automatic chain linking**: _push_next() mechanism prevents memory bloat and maintains optimal performance under out-of-order block conditions -- **Separate handling paths**: Linear extension vs fork switch processing improves efficiency by avoiding unnecessary operations -- **Debug logging overhead**: Detailed debug logging prefixes add minimal overhead while providing significant debugging benefits -- **Diagnostic monitoring overhead**: Real-time storage analytics add minimal overhead while providing significant operational insights -- **Storage optimization**: Diagnostic metrics enable proactive optimization of fork database performance and resource utilization - -## Troubleshooting Guide -**Updated** Enhanced with improved error handling, duplicate detection, DLT mode support, automatic seeding capabilities, comprehensive emergency consensus troubleshooting, sophisticated early rejection logic, HF12 fork comparison troubleshooting, advanced fork collision resolution guidance, gap-based early rejection troubleshooting, automatic chain linking guidance, separate handling paths, detailed debug logging, and **NEW**: comprehensive diagnostic monitoring troubleshooting. - -Common issues and remedies: -- **Unlinkable block errors**: Occur when a block does not link to a known chain; the fork DB logs and caches the block for later insertion when its parent arrives with enhanced logging and processing via _push_next() -- **Invalid fork handling**: When reorganization fails, the database removes the problematic fork, restores the good fork, and rethrows the exception with comprehensive error recovery -- **Memory pressure**: Adjust shared memory sizing and monitor free memory; the database resizes shared memory when necessary with enhanced monitoring -- **Recovery mismatches**: During open/reindex, the database asserts chain state consistency with the block log and resets the fork DB accordingly with improved validation -- **Duplicate block processing**: The fork DB now prevents duplicate block processing, reducing CPU overhead and improving synchronization reliability -- **Early rejection failures**: Enhanced early rejection logic helps prevent unnecessary fork database operations and improves overall system performance -- **DLT mode issues**: When DLT mode is enabled, verify that DLT block log is properly configured and that automatic seeding is working correctly -- **P2P synchronization delays**: Check that automatic seeding is functioning and that fork database is properly seeded from DLT block log -- **Gap logging**: Monitor DLT block log gaps and adjust configuration if gaps persist beyond acceptable limits -- **Emergency mode activation failures**: Verify CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC configuration and check LIB timestamp calculations -- **Emergency mode deactivation issues**: Monitor LIB advancement and ensure emergency_consensus_start_block tracking is accurate -- **Emergency validator problems**: Verify emergency validator account creation and key management during emergency mode activation -- **Hybrid scheduling conflicts**: Check validator schedule overrides and ensure emergency validator has proper signing key configuration -- **Tie-breaking anomalies**: Monitor emergency mode tie-breaking behavior and verify hash-based resolution consistency across network nodes -- **Infinite sync loops**: Check early rejection logic and ensure proper block validation to prevent continuous sync restarts -- **Block validation failures**: Monitor different types of block validation errors and ensure appropriate exception handling -- **HF12 fork comparison failures**: Verify compare_fork_branches() function returns valid results and check validator vote weight calculations -- **Two-level collision resolution issues**: Monitor fork collision timeout counters and ensure stuck-head timeout mechanism is functioning correctly -- **Vote-weighted comparison anomalies**: Check validator vote weight calculations and ensure emergency validator exclusion is working properly -- **Automatic pruning failures**: Verify remove_blocks_by_number() function is cleaning stale competing blocks and check set_max_size() pruning effectiveness -- **Timeout configuration problems**: Adjust fork-collision-timeout-blocks parameter if network experiences frequent fork collisions or insufficient timeout -- **Gap-based rejection issues**: Verify 100-block threshold is working correctly and check that legitimate out-of-order blocks are not being rejected -- **Automatic chain linking failures**: Check _push_next() mechanism and ensure cached unlinked blocks are being processed correctly when parents arrive -- **Linear extension vs fork switch confusion**: Monitor FORK-SWITCH-POP and FORK-RECOVER-POP debug logs to distinguish between different types of fork resolution operations -- **Debug logging issues**: Verify that debug logging prefixes are appearing correctly and check log level configuration for proper visibility -- **Diagnostic monitoring failures**: Verify diagnostic accessors are returning accurate storage statistics and check P2P monitoring system integration -- **Storage health issues**: Monitor fork database storage metrics to identify potential memory exhaustion or performance degradation -- **DLT coverage gaps**: Use diagnostic metrics to identify and resolve gaps between DLT block log and fork database ranges -- **Performance optimization**: Use diagnostic data to optimize fork database capacity and improve synchronization efficiency - -**Section sources** -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [database.cpp:1075-1087](file://libraries/chain/database.cpp#L1075-L1087) -- [database.cpp:259-294](file://libraries/chain/database.cpp#L259-L294) -- [database.cpp:4581-4594](file://libraries/chain/database.cpp#L4581-L4594) -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) -- [validator.cpp:597-612](file://plugins/validator/validator.cpp#L597-L612) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -## Conclusion -**Updated** The fork resolution and consensus system combines an efficient in-memory fork database with robust chain reorganization, irreversible block persistence, comprehensive DLT mode support, and advanced emergency consensus recovery mechanisms. The system has been significantly enhanced with sophisticated gap-based early rejection logic, comprehensive duplicate detection, DLT mode integration, automatic seeding capabilities, comprehensive emergency consensus implementation, HF12 vote-weighted fork comparison, two-level fork collision resolution, automatic stale fork pruning, and automatic chain linking. The enhanced fork database now supports snapshot-based nodes with immediate P2P synchronization, while the DLT block log provides efficient serving of recent irreversible blocks to peers. The emergency consensus recovery system ensures blockchain continuity through timeout-based activation, hybrid validator scheduling, and deterministic tie-breaking mechanisms. The HF12 fork comparison system provides more robust consensus decisions by weighting chains based on validator vote support with +10% bonus for longer chains. The two-level fork collision resolution system combines immediate vote-weighted comparison with stuck-head timeout to ensure network progress while maintaining consensus integrity. The automatic stale fork pruning system prevents memory bloat and maintains optimal performance under fork collision conditions. The gap-based early rejection logic with 100-block threshold prevents memory bloat from dead-fork chains while maintaining network efficiency. The automatic chain linking system via _push_next() ensures efficient processing of out-of-order blocks. The system integrates tightly with validator scheduling to ensure timely and valid block production, with emergency mode awareness enabling seamless transition between normal and emergency operations. The enhanced APIs enable reliable fork detection, chain validation, and recovery with DLT mode, emergency consensus, HF12 fork comparison, gap-based protection, and automatic chain linking awareness. Performance controls keep resource usage manageable while improving synchronization reliability, network health, and consensus stability during emergency conditions. The sophisticated early rejection logic and block validation mechanisms prevent infinite synchronization loops and system degradation, ensuring robust operation under various network conditions. The separate handling paths for linear extensions vs actual fork switches improve efficiency by avoiding unnecessary operations. The detailed debug logging with FORK-SWITCH-POP and FORK-RECOVER-POP prefixes provides excellent traceability for troubleshooting and monitoring fork resolution operations. **NEW**: The comprehensive diagnostic monitoring system provides real-time insights into fork database storage statistics, enabling proactive optimization and issue detection. The diagnostic accessors offer O(1) access to critical storage metrics including linked/unlinked index sizes and block number ranges, facilitating informed capacity planning and performance tuning. The P2P monitoring integration delivers comprehensive analytics for storage health, DLT coverage gaps, and synchronization performance, ensuring optimal system operation under varying network conditions. - -## Appendices - -### Appendix A: Enhanced Key Data Structures and Complexity -**Updated** Enhanced with improved duplicate detection, caching mechanisms, DLT mode support, automatic seeding capabilities, emergency consensus integration, sophisticated early rejection logic, HF12 fork comparison capabilities, advanced fork collision resolution systems, gap-based early rejection protection, automatic chain linking features, separate handling paths, detailed debug logging, and **NEW**: comprehensive diagnostic monitoring system. - -- fork_item: Stores block data, previous link, and invalid flag -- fork_database: - - push_block: O(log N) average for insertions; unlinked insertion triggers iterative _push_next with duplicate prevention - - fetch_branch_from: O(depth) to traverse both branches to common ancestor - - walk_main_branch_to_num: O(depth) to reach a specific block number - - set_max_size: O(N log N) worst-case pruning across indices with enhanced cleanup - - **New**: Duplicate detection: O(1) lookup for existing block IDs before insertion - - **New**: Enhanced caching: Iterative processing of up to MAX_BLOCK_REORDERING unlinked blocks via _push_next - - **New**: Emergency mode tie-breaking: O(1) hash comparison for tie resolution during emergency periods - - **New**: Enhanced error handling: Comprehensive exception management for different block validation failures - - **New**: Automatic stale fork pruning: O(k) removal of all blocks at specific height (k = number of competing blocks) - - **New**: Enhanced pruning system: O(N) cleanup of both _index and _unlinked_index for optimal memory management - - **New**: Gap-based early rejection: O(1) gap calculation and threshold checking - - **New**: Separate handling paths: O(1) branching between linear extension and fork switch operations - - **New**: Debug logging: Minimal overhead with detailed prefix-based logging for traceability - - **New**: Diagnostic accessors: O(1) access to storage statistics with comprehensive metrics -- **New**: database compare_fork_branches(): - - O(B) where B = number of blocks in longer branch - - Calculates vote weights for each unique validator - - Applies +10% bonus to longer chain - - Returns comparison result (-1, 0, or 1) -- **New**: database early rejection logic: - - Already applied block detection: O(1) lookup for existing block IDs - - Different fork detection: O(1) parent validation in fork database - - Far ahead block rejection: O(1) parent unknown detection with gap calculation - - Gap-based protection: O(1) 100-block threshold checking - - Sophisticated validation prevents unnecessary processing and system degradation -- **New**: dlt_block_log: - - append: O(1) for sequential writes with rolling window management - - read_block_by_num: O(1) for random access within window - - truncate_before: O(n) for window compaction with safe file swapping -- **New**: Emergency consensus configuration: - - CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC: 3600 seconds (1 hour) timeout threshold - - CHAIN_EMERGENCY_WITNESS_ACCOUNT: Emergency validator account name ("committee") - - CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY: Deterministic emergency signing key - - CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS: 21 blocks to trigger emergency mode exit - - Hardfork version: CHAIN_HARDFORK_12 (version 3.1.0) - - Activation time: CHAIN_HARDFORK_12_TIME (Unix timestamp for HF12 activation) -- **New**: DLT mode integration: - - Automatic seeding: O(1) to seed fork database from DLT block log - - Gap handling: O(1) logging suppression with periodic re-enabling -- **New**: Emergency mode integration: - - Activation detection: O(1) timestamp comparison for timeout checks - - Hybrid scheduling: O(N) override of all validator slots to emergency validator - - Penalty reset: O(N) iteration through all validators for penalty clearing -- **New**: HF12 fork comparison: - - Vote-weighted comparison: O(B) where B = number of blocks in longer branch - - Unique validator counting: O(W) where W = number of unique validators per branch - - +10% bonus application: O(1) constant time operation -- **New**: Two-level fork collision resolution: - - Level 1 timeout: O(1) constant time comparison - - Level 2 timeout: O(1) constant time counter check - - Stale fork removal: O(k) where k = number of competing blocks at height -- **New**: Exception handling: - - unlinkable_block_exception: Specific handling for blocks that cannot link - - block_too_old_exception: Specific handling for blocks outside fork window - - Enhanced error categorization prevents system degradation -- **New**: Automatic chain linking: - - _push_next() processing: O(k) where k = number of cached blocks linked - - Gap-based protection: Prevents memory bloat from dead-fork chains -- **New**: Separate handling paths: - - Linear extension: O(1) reset without pop operations - - Fork switch: O(F) where F = number of blocks popped and applied -- **New**: Debug logging: - - Minimal overhead with prefix-based categorization - - FORK-SWITCH-POP: O(1) logging for fork switching operations - - FORK-RECOVER-POP: O(1) logging for fork recovery operations -- **New**: Diagnostic monitoring system: - - linked_size(): O(1) access to linked index size - - unlinked_size(): O(1) access to unlinked index size - - Block number range queries: O(1) access to min/max block numbers - - Real-time analytics: O(1) collection of comprehensive storage metrics - - P2P integration: O(1) metrics delivery for monitoring system - -**Section sources** -- [fork_database.hpp:20-168](file://libraries/chain/include/graphene/chain/fork_database.hpp#L20-L168) -- [fork_database.cpp:48-103](file://libraries/chain/fork_database.cpp#L48-L103) -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) -- [database.cpp:1254-1298](file://libraries/chain/database.cpp#L1254-L1298) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [dlt_block_log.cpp:336-340](file://libraries/chain/dlt_block_log.cpp#L336-L340) -- [config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [database.cpp:2125-2142](file://libraries/chain/database.cpp#L2125-L2142) -- [validator.cpp:597-612](file://plugins/validator/validator.cpp#L597-L612) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) - -### Appendix B: Emergency Consensus Configuration Parameters -**New Section** Comprehensive configuration parameters for emergency consensus mode activation and operation. - -Emergency consensus parameters: -- **Timeout threshold**: CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC (default: 3600 seconds) -- **Emergency validator account**: CHAIN_EMERGENCY_WITNESS_ACCOUNT (default: "committee") -- **Emergency validator key**: CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY (deterministic emergency key) -- **Exit condition**: CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS (default: 21 blocks) -- **Hardfork version**: CHAIN_HARDFORK_12 (version 3.1.0) -- **Activation time**: CHAIN_HARDFORK_12_TIME (Unix timestamp for HF12 activation) - -Configuration impact: -- **Timeout sensitivity**: Lower values trigger emergency mode more frequently, higher values require longer downtime -- **Exit timing**: Controls how quickly normal operation resumes after emergency period -- **Security implications**: Emergency key provides deterministic consensus but requires secure key management -- **Network stability**: Emergency mode ensures blockchain continuity but may temporarily reduce decentralization - -**Section sources** -- [config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -### Appendix C: Enhanced Exception Handling and Error Categories -**New Section** Comprehensive breakdown of exception handling categories and their specific behaviors. - -Exception categories and handling: -- **unlinkable_block_exception**: Thrown when blocks cannot link to known chain; caught and cached in fork database via _push_next() for automatic chain linking -- **block_too_old_exception**: Thrown when blocks are outside fork database window; handled gracefully to prevent system overload -- **block_validation_exception**: Thrown when blocks fail validation checks; handled through early rejection logic -- **duplicate_block_exception**: Prevented through comprehensive duplicate detection mechanisms -- **infinite_sync_loop_exception**: Prevented through sophisticated early rejection logic that detects and rejects problematic blocks -- **fork_collision_exception**: Handled through two-level fork collision resolution system with timeout-based fallback -- **gap_based_rejection**: Prevented through 100-block threshold logic that protects against memory bloat -- **linear_extension_exception**: Prevented through separate handling path that avoids unnecessary operations -- **fork_switch_exception**: Handled through detailed debug logging with FORK-SWITCH-POP prefix for troubleshooting -- **diagnostic_access_exception**: Prevented through comprehensive error handling in diagnostic accessors -- **storage_monitoring_exception**: Handled through graceful degradation in P2P monitoring system - -Exception handling strategies: -- **Early rejection**: Prevents unnecessary processing of invalid blocks -- **Graceful degradation**: Allows system to continue operating despite individual block failures -- **Comprehensive logging**: Detailed error reporting for debugging and monitoring -- **Specific exception types**: Differentiates between different types of failures for appropriate handling -- **System resilience**: Prevents cascading failures through proper exception management -- **HF12 integration**: Vote-weighted fork comparison provides additional error context for fork resolution decisions -- **Automatic chain linking**: _push_next() mechanism prevents memory bloat while maintaining network efficiency -- **Gap-based protection**: 100-block threshold prevents accumulation of stale blocks -- **Separate handling paths**: Linear extension vs fork switch processing improves efficiency -- **Debug logging**: FORK-SWITCH-POP and FORK-RECOVER-POP prefixes provide excellent traceability -- **Diagnostic monitoring**: Real-time storage analytics provide early warning of potential issues - -**Section sources** -- [fork_database.cpp:38-46](file://libraries/chain/fork_database.cpp#L38-L46) -- [fork_database.cpp:59-75](file://libraries/chain/fork_database.cpp#L59-L75) -- [database.cpp:1300-1399](file://libraries/chain/database.cpp#L1300-L1399) -- [database.cpp:1390-1465](file://libraries/chain/database.cpp#L1390-L1465) -- [validator.cpp:614-646](file://plugins/validator/validator.cpp#L614-L646) - -### Appendix D: Diagnostic Accessors Usage Examples -**New Section** Practical examples of using diagnostic accessors for monitoring and troubleshooting fork database storage statistics. - -#### Basic Storage Metrics Collection -```cpp -// Example: Collect basic fork database storage metrics -const auto& fork_db = db.get_fork_db(); -size_t linked_count = fork_db.linked_size(); -size_t unlinked_count = fork_db.unlinked_size(); -uint32_t linked_min = fork_db.linked_min_block_num(); -uint32_t linked_max = fork_db.linked_max_block_num(); -uint32_t unlinked_min = fork_db.unlinked_min_block_num(); -uint32_t unlinked_max = fork_db.unlinked_max_block_num(); - -// Example: Analyze storage utilization -double linked_ratio = (double)linked_count / (linked_count + unlinked_count); -double linked_coverage = (double)(linked_max - linked_min + 1) / linked_count; -double unlinked_growth_rate = (double)unlinked_count / (linked_count + 1); -``` - -#### Storage Health Analysis -```cpp -// Example: Analyze fork database health -if (unlinked_count > linked_count * 0.1) { - // High proportion of unlinked blocks indicates network issues - wlog("High unlinked block ratio: {}%", unlinked_count * 100.0 / (linked_count + unlinked_count)); -} - -if (unlinked_growth_rate > 0.05) { - // Rapid growth in unlinked blocks suggests synchronization problems - wlog("Rapid unlinked block growth detected"); -} - -if (linked_coverage < 0.8) { - // Low coverage indicates potential gaps in fork database - wlog("Low fork database coverage: {}%", linked_coverage * 100); -} -``` - -#### Performance Optimization Based on Diagnostics -```cpp -// Example: Optimize fork database capacity based on storage patterns -if (linked_count > fork_db.max_size() * 0.8) { - // Increase fork database capacity to prevent pruning - db.set_max_size(fork_db.max_size() * 1.2); - wlog("Increased fork database capacity to {} blocks", fork_db.max_size()); -} - -if (unlinked_count < fork_db.max_size() * 0.05) { - // Decrease capacity to save memory - db.set_max_size(fork_db.max_size() * 0.8); - wlog("Decreased fork database capacity to {} blocks", fork_db.max_size()); -} -``` - -#### Integration with P2P Monitoring -```cpp -// Example: Integrate diagnostic metrics with P2P monitoring -void collect_fork_storage_metrics() { - const auto& fork_db = db.get_fork_db(); - - // Collect metrics - auto metrics = std::make_shared( - fork_db.linked_size(), - fork_db.unlinked_size(), - fork_db.linked_min_block_num(), - fork_db.linked_max_block_num(), - fork_db.unlinked_min_block_num(), - fork_db.unlinked_max_block_num() - ); - - // Store metrics for analysis - _storage_metrics_history.push_back(metrics); - - // Generate alerts based on thresholds - check_storage_alerts(metrics); -} -``` - -**Section sources** -- [fork_database.hpp:128-150](file://libraries/chain/include/graphene/chain/fork_database.hpp#L128-L150) -- [p2p_plugin.cpp:739-760](file://plugins/p2p/p2p_plugin.cpp#L739-L760) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Memory Management System.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Memory Management System.md deleted file mode 100644 index 48e5ec50f8..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Memory Management System.md +++ /dev/null @@ -1,655 +0,0 @@ -# Memory Management System - - -**Referenced Files in This Document** -- [chainbase.hpp](file://thirdparty/chainbase/include/chainbase/chainbase.hpp) -- [chainbase.cpp](file://thirdparty/chainbase/src/chainbase.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [shared_ptr.hpp](file://thirdparty/fc/include/fc/shared_ptr.hpp) -- [shared_ptr.cpp](file://thirdparty/fc/src/shared_ptr.cpp) -- [smart_ref_fwd.hpp](file://thirdparty/fc/include/fc/smart_ref_fwd.hpp) -- [smart_ref_impl.hpp](file://thirdparty/fc/include/fc/smart_ref_impl.hpp) -- [unique_ptr.hpp](file://thirdparty/fc/include/fc/unique_ptr.hpp) -- [file_mapping.hpp](file://thirdparty/fc/include/fc/interprocess/file_mapping.hpp) -- [file_mapping.cpp](file://thirdparty/fc/src/interprocess/file_mapping.cpp) -- [mmap_struct.hpp](file://thirdparty/fc/include/fc/interprocess/mmap_struct.hpp) -- [mmap_struct.cpp](file://thirdparty/fc/src/interprocess/mmap_struct.cpp) -- [flat.hpp](file://thirdparty/fc/include/fc/container/flat.hpp) -- [thread_specific.hpp](file://thirdparty/fc/include/fc/thread/thread_specific.hpp) -- [scoped_exit.hpp](file://thirdparty/fc/include/fc/scoped_exit.hpp) -- [aligned.hpp](file://thirdparty/fc/include/fc/aligned.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) - - -## Update Summary -**Changes Made** -- Added comprehensive documentation for the new shared memory resize barrier system -- Documented the sophisticated atomic operation counter system -- Added detailed coverage of begin_resize_barrier() and end_resize_barrier() functions -- Documented operation guards for lockless reads and their role in preventing shared memory corruption -- Enhanced logging capabilities for resize barrier state transitions -- Updated memory monitoring and resizing sections with new barrier-based approach - -## Table of Contents -1. [Introduction](#introduction) -2. [System Architecture](#system-architecture) -3. [Memory Management Components](#memory-management-components) -4. [Shared Memory System](#shared-memory-system) -5. [Reference Counting](#reference-counting) -6. [Smart Pointers and RAII](#smart-pointers-and-raii) -7. [Memory Allocation Strategies](#memory-allocation-strategies) -8. [Locking and Concurrency](#locking-and-concurrency) -9. [Memory Monitoring and Resizing](#memory-monitoring-and-resizing) -10. [Resize Barrier System](#resize-barrier-system) -11. [Operation Guards](#operation-guards) -12. [Enhanced Logging and Diagnostics](#enhanced-logging-and-diagnostics) -13. [Best Practices](#best-practices) -14. [Troubleshooting Guide](#troubleshooting-guide) -15. [Conclusion](#conclusion) - -## Introduction - -The VIZ CPP Node memory management system is built around a sophisticated shared memory architecture that enables high-performance blockchain operations. The system combines traditional C++ memory management with advanced inter-process shared memory techniques, providing both safety and performance for blockchain state persistence and concurrent access. - -The memory management system centers on ChainBase, a specialized database framework that uses Boost.Interprocess for shared memory management, combined with FC library utilities for smart pointers, RAII patterns, and memory-safe operations. This architecture supports the demanding requirements of blockchain applications, including persistent state, concurrent access, and automatic memory management. - -**Updated** The system now includes a sophisticated resize barrier mechanism that provides atomic operations during shared memory resizing, preventing corruption and ensuring data consistency during memory expansion operations. - -## System Architecture - -The memory management system follows a layered architecture that separates concerns between low-level memory management, database operations, and application-level abstractions. - -```mermaid -graph TB -subgraph "Application Layer" -APP[Blockchain Application] -PLUGINS[Plugin System] -API[API Layer] -end -subgraph "Database Layer" -DATABASE[Database Engine] -INDEXES[Index Management] -SESSIONS[Transaction Sessions] -RESIZE_BARRIER[Resize Barrier System] -OPERATION_GUARDS[Operation Guards] -end -subgraph "Memory Management Layer" -SHARED_MEM[Shared Memory] -ALLOCATORS[Custom Allocators] -LOCKS[Lock Management] -ATOMIC_COUNTER[Atomic Operation Counter] -END_RESIZE_BARRIER[End Resize Barrier] -end -subgraph "Low-Level Memory" -INTERPROCESS[Boost Interprocess] -SMART_PTR[Smart Pointers] -FILE_MAPPING[File Mapping] -end -APP --> DATABASE -PLUGINS --> DATABASE -API --> DATABASE -DATABASE --> INDEXES -DATABASE --> SESSIONS -DATABASE --> RESIZE_BARRIER -RESIZE_BARRIER --> OPERATION_GUARDS -RESIZE_BARRIER --> ATOMIC_COUNTER -RESIZE_BARRIER --> END_RESIZE_BARRIER -INDEXES --> SHARED_MEM -SESSIONS --> SHARED_MEM -SHARED_MEM --> ALLOCATORS -ALLOCATORS --> LOCKS -LOCKS --> INTERPROCESS -INTERPROCESS --> SMART_PTR -INTERPROCESS --> FILE_MAPPING -``` - -**Diagram sources** -- [chainbase.hpp:1319-1328](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1319-L1328) -- [database.cpp:613-653](file://libraries/chain/database.cpp#L613-L653) -- [validator.cpp:503-507](file://plugins/validator/validator.cpp#L503-L507) - -## Memory Management Components - -### Core Memory Management Classes - -The system provides several fundamental memory management components that work together to provide robust memory handling: - -```mermaid -classDiagram -class Retainable { --volatile int32_t _ref_count -+retain() void -+release() void -+retain_count() int32_t -+~retainable() virtual -} -class SharedPtr { --T* _ptr -+shared_ptr() constructor -+shared_ptr(shared_ptr) constructor -+shared_ptr(T*, bool) constructor -+shared_ptr(shared_ptr&&) constructor -+~shared_ptr() destructor -+operator*() T& -+operator->() T* -+get() T* -+reset() void -+swap() void -} -class SmartRef { --T* impl -+smart_ref() constructor -+smart_ref(smart_ref&) constructor -+smart_ref(smart_ref&&) constructor -+operator*() T& -+operator->() T* -+~smart_ref() destructor -} -class UniquePtr { --T* _p -+unique_ptr() constructor -+unique_ptr(unique_ptr&&) constructor -+~unique_ptr() destructor -+operator*() T& -+operator->() T* -+reset() void -+release() T* -} -class OperationGuard { --database& _db --bool _active -+operation_guard(database&) -+~operation_guard() -+release() void -+operation_guard(operation_guard&&) -} -Retainable <|-- SharedPtr : "reference counting" -SharedPtr --> Retainable : "uses" -SmartRef --> T : "owns" -UniquePtr --> T : "owns" -OperationGuard --> database : "manages" -``` - -**Diagram sources** -- [shared_ptr.hpp:13-64](file://thirdparty/fc/include/fc/shared_ptr.hpp#L13-L64) -- [smart_ref_fwd.hpp:9-52](file://thirdparty/fc/include/fc/smart_ref_fwd.hpp#L9-L52) -- [unique_ptr.hpp:7-66](file://thirdparty/fc/include/fc/unique_ptr.hpp#L7-L66) -- [chainbase.hpp:1078-1111](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1111) - -**Section sources** -- [shared_ptr.hpp:1-64](file://thirdparty/fc/include/fc/shared_ptr.hpp#L1-L64) -- [smart_ref_fwd.hpp:1-53](file://thirdparty/fc/include/fc/smart_ref_fwd.hpp#L1-L53) -- [unique_ptr.hpp:1-68](file://thirdparty/fc/include/fc/unique_ptr.hpp#L1-L68) -- [chainbase.hpp:1078-1111](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1111) - -## Shared Memory System - -### Managed Memory File Architecture - -The shared memory system uses Boost.Interprocess to create and manage memory-mapped files that serve as the foundation for the database storage: - -```mermaid -sequenceDiagram -participant App as Application -participant DB as Database -participant MMF as Managed Memory File -participant FM as File Mapping -participant MR as Mapped Region -App->>DB : open(shared_mem_dir, flags, size) -DB->>MMF : create/open managed file -MMF->>FM : create file mapping -FM->>MR : create mapped region -MR->>MMF : allocate memory segment -MMF->>DB : initialize environment check -DB->>App : database ready -Note over App,DB : Memory allocation and indexing -App->>DB : create/modify objects -DB->>MMF : allocate from shared memory -MMF->>App : return object reference -App->>DB : close() -DB->>MMF : flush and cleanup -MMF->>FM : unmap file -FM->>MR : destroy mapped region -``` - -**Diagram sources** -- [chainbase.cpp:70-102](file://thirdparty/chainbase/src/chainbase.cpp#L70-L102) -- [file_mapping.cpp:9-41](file://thirdparty/fc/src/interprocess/file_mapping.cpp#L9-L41) -- [mmap_struct.cpp:20-44](file://thirdparty/fc/src/interprocess/mmap_struct.cpp#L20-L44) - -### Memory Layout and Organization - -The shared memory system organizes data in a structured manner optimized for blockchain operations: - -| Memory Segment | Purpose | Size | Protection | -|----------------|---------|------|------------| -| Environment Check | System compatibility verification | Fixed size | Read-only | -| Index Tables | Object indexing structures | Dynamic | Read-write | -| Object Storage | Actual blockchain data | Dynamic | Read-write | -| Undo Buffers | Transaction rollback support | Dynamic | Read-write | -| Lock Information | Concurrency control data | Fixed size | Read-write | -| Resize Barrier State | Atomic operation counters | Fixed size | Read-write | - -**Section sources** -- [chainbase.cpp:70-102](file://thirdparty/chainbase/src/chainbase.cpp#L70-L102) -- [chainbase.hpp:1189-1193](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1189-L1193) -- [chainbase.hpp:1319-1328](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1319-L1328) - -## Reference Counting - -### Retainable Object Pattern - -The reference counting system uses the retainable pattern to provide automatic memory management for shared objects: - -```mermaid -flowchart TD -Start([Object Creation]) --> InitCount["Initialize retain count = 1"] -InitCount --> UseObject["Use Object"] -UseObject --> Increment{"Need More References?"} -Increment --> |Yes| Retain["retain() - increment count"] -Increment --> |No| Continue["Continue Operation"] -Retain --> Continue -Continue --> Release{"Reference No Longer Needed?"} -Release --> |Yes| Decrement["release() - decrement count"] -Decrement --> CheckZero{"Count == 0?"} -CheckZero --> |Yes| Delete["delete this"] -CheckZero --> |No| Wait["Wait for other references"] -Release --> |No| Continue -Delete --> End([Object Destroyed]) -Wait --> Release -``` - -**Diagram sources** -- [shared_ptr.cpp:16-25](file://thirdparty/fc/src/shared_ptr.cpp#L16-L25) - -### Thread-Safe Reference Operations - -The reference counting implementation ensures thread safety through atomic operations and memory barriers: - -| Operation | Memory Ordering | Purpose | -|-----------|----------------|---------| -| retain() | relaxed | Increment reference count | -| release() | release | Decrement count with acquire barrier | -| retain_count() | acquire | Read current count safely | - -**Section sources** -- [shared_ptr.cpp:1-30](file://thirdparty/fc/src/shared_ptr.cpp#L1-L30) -- [shared_ptr.hpp:13-28](file://thirdparty/fc/include/fc/shared_ptr.hpp#L13-L28) - -## Smart Pointers and RAII - -### Smart Pointer Implementation - -The FC library provides several smart pointer implementations that enhance memory safety: - -```mermaid -classDiagram -class SmartRef { --T* impl -+smart_ref(U&&) constructor -+smart_ref(const smart_ref&) constructor -+smart_ref(smart_ref&&) constructor -+operator*() T& -+operator->() T* -+operator=(smart_ref&&) T& -+~smart_ref() destructor -} -class ScopedExit { --Callback callback -+scoped_exit(C&&) constructor -+~scoped_exit() destructor -+operator=(scoped_exit&&) scoped_exit& -} -class Aligned { --union { T _align; char _data[S]; } _store -+operator char*() -+operator const char*() const -} -SmartRef --> T : "heap allocated" -ScopedExit --> Callback : "executes on destruction" -Aligned --> T : "aligned storage" -``` - -**Diagram sources** -- [smart_ref_impl.hpp:40-134](file://thirdparty/fc/include/fc/smart_ref_impl.hpp#L40-L134) -- [scoped_exit.hpp:5-40](file://thirdparty/fc/include/fc/scoped_exit.hpp#L5-L40) -- [aligned.hpp:4-21](file://thirdparty/fc/include/fc/aligned.hpp#L4-L21) - -### RAII Resource Management - -The scoped_exit pattern ensures proper resource cleanup: - -**Section sources** -- [smart_ref_fwd.hpp:1-53](file://thirdparty/fc/include/fc/smart_ref_fwd.hpp#L1-L53) -- [smart_ref_impl.hpp:1-136](file://thirdparty/fc/include/fc/smart_ref_impl.hpp#L1-L136) -- [scoped_exit.hpp:1-40](file://thirdparty/fc/include/fc/scoped_exit.hpp#L1-L40) -- [aligned.hpp:1-21](file://thirdparty/fc/include/fc/aligned.hpp#L1-L21) - -## Memory Allocation Strategies - -### Custom Allocators - -ChainBase uses custom allocators that integrate with the shared memory system: - -```mermaid -flowchart LR -subgraph "Allocator Types" -BA[Boost Allocator] -CI[ChainBase Allocator] -FA[Flat Allocator] -end -subgraph "Memory Sources" -SM[Shared Memory] -HM[Heap Memory] -FM[File Mapping] -end -subgraph "Container Types" -MV[Managed Vector] -MS[Managed String] -MC[Managed Container] -end -BA --> SM -CI --> HM -FA --> FM -SM --> MV -HM --> MS -FM --> MC -``` - -**Diagram sources** -- [chainbase.hpp:53-59](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L53-L59) -- [flat.hpp:1-140](file://thirdparty/fc/include/fc/container/flat.hpp#L1-L140) - -### Memory Alignment and Padding - -The aligned storage template ensures proper memory alignment for different data types: - -**Section sources** -- [chainbase.hpp:53-59](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L53-L59) -- [flat.hpp:1-140](file://thirdparty/fc/include/fc/container/flat.hpp#L1-L140) -- [aligned.hpp:1-21](file://thirdparty/fc/include/fc/aligned.hpp#L1-L21) - -## Locking and Concurrency - -### Reader-Writer Lock System - -The database implements a sophisticated locking mechanism to handle concurrent access: - -```mermaid -stateDiagram-v2 -[*] --> Idle -Idle --> AcquiringRead : request_read_lock() -Idle --> AcquiringWrite : request_write_lock() -AcquiringRead --> ReadLock : lock acquired -AcquiringWrite --> WriteLock : lock acquired -ReadLock --> Processing : perform read operation -WriteLock --> Processing : perform write operation -Processing --> Releasing : operation complete -Releasing --> Idle : unlock -ReadLock --> Upgrading : upgrade to write -Upgrading --> WriteLock : successful upgrade -WriteLock --> Downgrading : downgrade to read -Downgrading --> ReadLock : successful downgrade -``` - -**Diagram sources** -- [chainbase.hpp:1070-1167](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1070-L1167) - -### Lock Timeout and Retry Mechanisms - -The system implements configurable timeout and retry mechanisms for lock acquisition: - -| Lock Type | Default Wait Time | Max Retries | Behavior | -|-----------|------------------|-------------|----------| -| Weak Read | 500,000 μs | 3 | Fail after retries | -| Strong Read | 1,000,000 μs | 100,000 | Extended wait period | -| Weak Write | 500,000 μs | 3 | Fail after retries | -| Strong Write | 1,000,000 μs | 100,000 | Extended wait period | - -**Section sources** -- [chainbase.hpp:1070-1167](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1070-L1167) - -## Memory Monitoring and Resizing - -### Automatic Memory Management - -The database includes sophisticated memory monitoring and automatic resizing capabilities: - -```mermaid -flowchart TD -Start([Block Processing]) --> CheckMemory["check_free_memory()"] -CheckMemory --> CalcReserved["Calculate reserved memory"] -CalcReserved --> CalcFree["Calculate free memory"] -CalcFree --> Compare{"Free < Min Free?"} -Compare --> |Yes| CheckResize{"Auto-resize enabled?"} -Compare --> |No| Continue["Continue normal operation"] -CheckResize --> |Yes| ScheduleResize["Schedule resize"] -CheckResize --> |No| LogWarning["Log warning message"] -ScheduleResize --> ApplyResize["apply_pending_resize()"] -ApplyResize --> Resize["resize(target_size)"] -Resize --> UpdateStats["Update memory statistics"] -UpdateStats --> Continue -LogWarning --> Continue -Continue --> End([Next Block]) -``` - -**Diagram sources** -- [database.cpp:648-682](file://libraries/chain/database.cpp#L648-L682) -- [database.cpp:609-646](file://libraries/chain/database.cpp#L609-L646) - -### Memory Configuration Options - -The system provides extensive configuration options for memory management: - -| Configuration | Default Value | Description | -|---------------|---------------|-------------| -| shared-file-dir | "state" | Location of shared memory files | -| shared-file-size | "2G" | Initial shared memory size | -| inc-shared-file-size | "2G" | Increment size for growth | -| min-free-shared-file-size | Configurable | Minimum free memory threshold | -| read_wait_micro | 500,000 | Read lock wait time | -| max_read_wait_retries | 3 | Read lock retry attempts | -| write_wait_micro | 500,000 | Write lock wait time | -| max_write_wait_retries | 3 | Write lock retry attempts | - -**Section sources** -- [plugin.cpp:199-211](file://plugins/chain/plugin.cpp#L199-L211) -- [database.cpp:648-682](file://libraries/chain/database.cpp#L648-L682) - -## Resize Barrier System - -### Atomic Operation Counter System - -The resize barrier system introduces a sophisticated atomic operation counter that tracks active database operations during memory resizing: - -```mermaid -sequenceDiagram -participant App as Application Thread -participant DB as Database -participant Barrier as Resize Barrier -participant Ops as Active Operations -App->>DB : begin_resize_barrier() -DB->>Barrier : set _resize_in_progress = true -Barrier->>Ops : wait for _active_operations == 0 -Note over Ops : All active operations complete -Ops->>Barrier : notify_all() -Barrier->>DB : begin_resize_barrier() returns -App->>DB : resize(target_size) -DB->>Barrier : end_resize_barrier() -Barrier->>Ops : set _resize_in_progress = false -Ops->>Barrier : notify_all() -Barrier->>DB : end_resize_barrier() returns -``` - -**Diagram sources** -- [chainbase.cpp:295-310](file://thirdparty/chainbase/src/chainbase.cpp#L295-L310) -- [chainbase.hpp:1319-1323](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1319-L1323) - -### Resize Barrier Implementation Details - -The resize barrier system provides atomic operations during shared memory resizing: - -| Component | Data Type | Purpose | -|-----------|-----------|---------| -| _resize_in_progress | std::atomic | Indicates resize operation status | -| _active_operations | std::atomic | Counts currently active operations | -| _resize_barrier_mutex | std::mutex | Synchronization primitive | -| _resize_barrier_cv | std::condition_variable | Condition variable for blocking | - -**Section sources** -- [chainbase.cpp:295-310](file://thirdparty/chainbase/src/chainbase.cpp#L295-L310) -- [chainbase.hpp:1319-1323](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1319-L1323) - -## Operation Guards - -### Lockless Read Protection - -Operation guards provide protection for lockless reads that do not acquire chainbase locks, preventing shared memory corruption during resize operations: - -```mermaid -flowchart TD -Start([Lockless Read Request]) --> CheckBarrier["Check _resize_in_progress"] -CheckBarrier --> |Resize In Progress| WaitGuard["Wait in operation_guard"] -CheckBarrier --> |No Resize| Proceed["Proceed with Lockless Read"] -WaitGuard --> WaitComplete["Operation Guard Released"] -WaitComplete --> Proceed -Proceed --> Complete["Lockless Read Complete"] -``` - -**Diagram sources** -- [chainbase.hpp:1078-1111](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1111) -- [database.cpp:1554-1556](file://libraries/chain/database.cpp#L1554-L1556) - -### Operation Guard Lifecycle - -Operation guards participate in the resize barrier system: - -1. **Construction**: Calls `enter_operation()` which blocks if resize is in progress -2. **Destruction**: Calls `exit_operation()` which decrements counter and notifies resize thread -3. **Manual Release**: Can be explicitly released before scope exit - -**Section sources** -- [chainbase.hpp:1078-1111](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1111) -- [chainbase.cpp:278-293](file://thirdparty/chainbase/src/chainbase.cpp#L278-L293) -- [database.cpp:1554-1556](file://libraries/chain/database.cpp#L1554-L1556) - -## Enhanced Logging and Diagnostics - -### Resize Barrier State Transition Logging - -The system provides enhanced logging capabilities for resize barrier state transitions: - -```mermaid -flowchart TD -Start([Resize Operation]) --> LogStart["Log: Resize barrier: pausing all database operations"] -LogStart --> BeginBarrier["begin_resize_barrier()"] -BeginBarrier --> WaitOps["Wait for active operations to complete"] -WaitOps --> LogResize["Log: Applying deferred shared memory resize"] -LogResize --> PerformResize["resize(target_size)"] -PerformResize --> LogComplete["Log: Deferred shared memory grow complete"] -LogComplete --> EndBarrier["end_resize_barrier()"] -EndBarrier --> LogResume["Log: Resize barrier: all database operations resumed"] -LogResume --> End([Resize Complete]) -``` - -**Diagram sources** -- [database.cpp:624-652](file://libraries/chain/database.cpp#L624-L652) - -### Diagnostic Information - -The resize barrier system logs comprehensive information about memory usage and resize operations: - -- **Current block number**: Tracks resize timing relative to blockchain progress -- **Used memory before/after**: Shows actual memory consumption changes -- **Target size**: Displays planned resize target -- **Free memory**: Monitors available memory after resize - -**Section sources** -- [database.cpp:624-652](file://libraries/chain/database.cpp#L624-L652) -- [database.cpp:577-610](file://libraries/chain/database.cpp#L577-L610) - -## Best Practices - -### Memory Management Guidelines - -1. **Use Smart Pointers**: Prefer smart pointers over raw pointers for automatic memory management -2. **Implement RAII**: Ensure resources are properly cleaned up using RAII patterns -3. **Monitor Memory Usage**: Regularly check memory usage and implement appropriate resizing strategies -4. **Use Appropriate Locking**: Choose the right lock type based on operation requirements -5. **Handle Exceptions**: Ensure proper cleanup in exception scenarios using scoped_exit patterns -6. **Respect Resize Barriers**: Always use operation guards for lockless reads during resize operations -7. **Implement Proper Synchronization**: Use resize barriers for all shared memory modifications - -### Performance Optimization Tips - -1. **Batch Operations**: Group related operations to minimize lock contention -2. **Efficient Allocators**: Use appropriate allocators for different data types -3. **Memory Alignment**: Ensure proper alignment for optimal performance -4. **Undo Buffer Management**: Monitor and manage undo buffer sizes appropriately -5. **Operation Guard Usage**: Use operation guards strategically to prevent shared memory corruption -6. **Resize Timing**: Schedule resizes during maintenance windows when possible - -## Troubleshooting Guide - -### Common Memory Issues - -**Memory Exhaustion Errors** -- Check free memory thresholds and adjust `min-free-shared-file-size` -- Review application memory usage patterns -- Consider implementing more aggressive garbage collection -- Monitor resize barrier operations for blocking issues - -**Lock Contention Problems** -- Analyze lock wait times and adjust timeouts -- Review concurrent access patterns -- Consider reducing lock scope where possible -- Check operation guard usage for proper synchronization - -**Shared Memory Corruption** -- Verify environment compatibility checks pass -- Check file permissions and disk space -- Review concurrent access patterns for race conditions -- Monitor resize barrier state transitions - -**Resize Barrier Deadlocks** -- Ensure all operation guards are properly released -- Check for nested resize operations -- Verify atomic operation counter integrity -- Monitor condition variable notifications - -### Diagnostic Tools - -The system provides several diagnostic capabilities: - -- Memory usage logging with periodic updates -- Lock contention monitoring -- Environment compatibility verification -- Automatic memory resizing notifications -- Resize barrier state transition logging -- Operation guard lifecycle tracking - -**Section sources** -- [database.cpp:648-682](file://libraries/chain/database.cpp#L648-L682) -- [chainbase.cpp:80-89](file://thirdparty/chainbase/src/chainbase.cpp#L80-L89) -- [database.cpp:624-652](file://libraries/chain/database.cpp#L624-L652) - -## Conclusion - -The VIZ CPP Node memory management system represents a sophisticated approach to handling blockchain-specific memory requirements. By combining shared memory architectures with modern C++ memory management techniques, the system achieves both high performance and reliability. - -**Updated** The recent addition of the resize barrier system significantly enhances the system's ability to handle dynamic memory growth while maintaining data integrity and preventing corruption during shared memory modifications. - -Key strengths of the system include: - -- **High Performance**: Shared memory eliminates context switching overhead -- **Reliability**: Comprehensive error checking and recovery mechanisms -- **Scalability**: Automatic memory resizing and monitoring with atomic operations -- **Safety**: Extensive use of RAII and smart pointers with operation guard protection -- **Flexibility**: Configurable parameters for different deployment scenarios -- **Atomic Operations**: Sophisticated resize barrier system with atomic operation counters -- **Enhanced Diagnostics**: Comprehensive logging for resize barrier state transitions - -The system successfully balances the competing demands of blockchain applications: maintaining fast access to persistent state while ensuring data integrity, providing mechanisms for graceful degradation under memory pressure, and protecting against corruption during critical memory operations. - -The resize barrier system, with its atomic operation counter and operation guard mechanism, provides a robust foundation for safe shared memory resizing operations, making the system more resilient to memory pressure and enabling seamless scaling of blockchain state storage. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Object Model and Persistence.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Object Model and Persistence.md deleted file mode 100644 index 65ff7484cd..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Object Model and Persistence.md +++ /dev/null @@ -1,606 +0,0 @@ -# Object Model and Persistence - - -**Referenced Files in This Document** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp) -- [chain_objects.cpp](file://libraries/chain/chain_objects.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the Object Model and Persistence system that defines the complete blockchain data structure in the VIZ C++ node. It documents the object types (account_object, transaction_object, content_object, witness_object, committee_object, and related objects), their schemas, field types, and validation rules as defined in the chain object type registry. It explains lifecycle management (creation, modification, deletion), indexing strategies via multi-index containers, serialization/deserialization, and persistence mechanisms. It also covers relationships among object types, practical examples of object creation/query/manipulation, and considerations for versioning and schema evolution. - -## Project Structure -The object model and persistence are primarily defined in the Chain library under libraries/chain. Key areas: -- Object type registry and shared types: libraries/chain/include/graphene/chain/chain_object_types.hpp -- Object schemas and indices: libraries/chain/include/graphene/chain/*.hpp -- Database interface and persistence: libraries/chain/include/graphene/chain/database.hpp and implementation libraries/chain/database.cpp -- Supporting property and summary objects: libraries/chain/include/graphene/chain/global_property_object.hpp, block_summary_object.hpp, etc. - -```mermaid -graph TB -subgraph "Chain Objects" -A["account_object.hpp"] -T["transaction_object.hpp"] -C["content_object.hpp"] -W["witness_objects.hpp"] -M["committee_objects.hpp"] -G["global_property_object.hpp"] -B["block_summary_object.hpp"] -I["invite_objects.hpp"] -P["paid_subscription_objects.hpp"] -end -R["chain_object_types.hpp"] -D["database.hpp"] -DC["database.cpp"] -R --> A -R --> T -R --> C -R --> W -R --> M -R --> G -R --> B -R --> I -R --> P -D --> DC -A --> D -T --> D -C --> D -W --> D -M --> D -G --> D -B --> D -I --> D -P --> D -``` - -**Diagram sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L180) -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) -- [database.cpp](file://libraries/chain/database.cpp#L198-L200) - -**Section sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) - -## Core Components -This section summarizes the primary object types and their roles in the blockchain state. - -- Dynamic Global Property - - Purpose: Tracks global blockchain state (head block, supply, validator participation, reserve ratios). - - Schema: See [dynamic_global_property_object](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L133). - - Index: Single-entry unique index by id. - -- Account and Related Entities - - account_object: Core account state (balances, vesting, voting power, auction fields). - - account_authority_object: Master/Active/Regular authorities with updates. - - account_metadata_object: JSON metadata per account. - - Vesting delegation objects: Delegation, fixed delegation, and expiration. - - Recovery and master authority history objects. - - References: [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565). - -- Transaction - - transaction_object: Deduplication and expiration tracking for transactions. - - Index: by_id (unique), by_trx_id (hashed), by_expiration (ordered). - - Reference: [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56). - -- Content and Discussions - - content_object: Post/article state (timestamps, rshares, cashout, payouts). - - content_type_object: Title/body/metadata for content. - - content_vote_object: Per-voter per-content vote records. - - Indices: by_id, by_cashout_time, by_permlink, by_root, by_parent, and more; plus content_vote indices. - - Reference: [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270). - -- validators and Voting - - witness_object: validator identity, votes, virtual scheduling, signing key, props. - - witness_vote_object: Voter-to-validator mapping. - - witness_schedule_object: Current shuffled validators and majority version. - - References: [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313). - -- Committee and Proposals - - committee_request_object: Request metadata, amounts, timing, status, payouts. - - committee_vote_object: Voter support per request. - - References: [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137). - -- Block Summary - - block_summary_object: Minimal info for TaPOS checks. - - Reference: [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49). - -- Invites and Paid Subscriptions - - invite_object: Invite issuance, keys, balances, status. - - paid_subscription_object and paid_subscribe_object: Creator subscriptions and subscriber records. - - References: [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72), [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121). - -**Section sources** -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L180) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137) -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121) - -## Architecture Overview -The persistence layer is built on chainbase, which provides a typed object store with multi-index containers. The database class extends chainbase::database and exposes blockchain-specific operations. Object schemas are declared with Boost.MultiIndex indices; serialization is handled by fc::raw and reflection macros. - -```mermaid -classDiagram -class Database { -+open(data_dir, shared_mem_dir, ...) -+reindex(...) -+push_block(...) -+push_transaction(...) -+get_account(name) -+get_content(author, permlink) -+get_witness(owner) -+get_dynamic_global_properties() -} -class Object { -+id -} -class dynamic_global_property_object -class account_object -class account_authority_object -class witness_object -class transaction_object -class content_object -class content_type_object -class content_vote_object -class witness_vote_object -class witness_schedule_object -class committee_request_object -class committee_vote_object -class block_summary_object -class invite_object -class paid_subscription_object -class paid_subscribe_object -Database --> dynamic_global_property_object : "manages" -Database --> account_object : "manages" -Database --> witness_object : "manages" -Database --> transaction_object : "manages" -Database --> content_object : "manages" -Database --> content_type_object : "manages" -Database --> content_vote_object : "manages" -Database --> witness_vote_object : "manages" -Database --> witness_schedule_object : "manages" -Database --> committee_request_object : "manages" -Database --> committee_vote_object : "manages" -Database --> block_summary_object : "manages" -Database --> invite_object : "manages" -Database --> paid_subscription_object : "manages" -Database --> paid_subscribe_object : "manages" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L180) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137) -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121) - -## Detailed Component Analysis - -### Object Type Registry and Shared Types -- Defines the canonical object_type enumeration and shared type aliases (object_id<>). -- Declares shared_string and buffer_type and provides fc::variant/raw serialization hooks for object_id and buffers. -- Provides FC_REFLECT_ENUM for object_type and FC_REFLECT_TYPENAME registrations. - -Key references: -- Enumerations and aliases: [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- Serialization helpers: [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L151-L207) - -**Section sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L151-L207) - -### Account Object Lifecycle and Indices -- Creation: Constructed via constructor templates; stored via chainbase insert/update. -- Modification: Fields updated by evaluators; indices maintained automatically. -- Deletion: Removed when account is deleted or merged. -- Indices: - - by_id (unique) - - by_name (unique, lexicographic) - - by_account_on_sale/by_account_on_auction/by_subaccount_on_sale (non-unique booleans) - - by_account_on_sale_start_time (non-unique) - - by_next_vesting_withdrawal (composite: next_vesting_withdrawal + id) -- Related objects: - - account_authority_object (by_account composite) - - account_metadata_object (by_account) - - vesting_delegation_object (by_delegation, by_received) - - fix_vesting_delegation_object (by_id) - - vesting_delegation_expiration_object (by_expiration, by_account_expiration) - - account_recovery_request_object (by_expiration) - - change_recovery_account_request_object (by_effective_date) - - master_authority_history_object (by_account composite) - -References: -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) - -```mermaid -classDiagram -class account_object { -+id -+name -+balance -+vesting_shares -+energy -+next_vesting_withdrawal -+account_on_sale -+account_on_auction -+account_on_sale_start_time -} -class account_authority_object { -+id -+account -+master -+active -+regular -+last_master_update -} -class account_metadata_object { -+id -+account -+json_metadata -} -class vesting_delegation_object { -+id -+delegator -+delegatee -+vesting_shares -+min_delegation_time -} -class fix_vesting_delegation_object { -+id -+delegator -+delegatee -+vesting_shares -} -class vesting_delegation_expiration_object { -+id -+delegator -+vesting_shares -+expiration -} -class account_recovery_request_object { -+id -+account_to_recover -+new_master_authority -+expires -} -class change_recovery_account_request_object { -+id -+account_to_recover -+recovery_account -+effective_on -} -class master_authority_history_object { -+id -+account -+previous_master_authority -+last_valid_time -} -account_object --> account_authority_object : "authorities" -account_object --> account_metadata_object : "metadata" -account_object --> vesting_delegation_object : "delegations" -account_object --> fix_vesting_delegation_object : "fixed delegations" -account_object --> vesting_delegation_expiration_object : "expirations" -account_object --> account_recovery_request_object : "recovery requests" -account_object --> change_recovery_account_request_object : "change requests" -account_object --> master_authority_history_object : "history" -``` - -**Diagram sources** -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) - -**Section sources** -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L20-L565) - -### Transaction Object Lifecycle and Indices -- Purpose: Detect duplicates and enforce expiration. -- Indices: - - by_id (unique) - - by_trx_id (hashed unique) - - by_expiration (non-unique) -- Serialization: object_id and buffer_type raw pack/unpack helpers. - -References: -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L170-L207) - -```mermaid -sequenceDiagram -participant Eval as "Evaluator" -participant DB as "Database" -participant TX as "transaction_object" -Eval->>DB : "store transaction" -DB->>TX : "insert(packed_trx, trx_id, expiration)" -DB-->>Eval : "object_id" -Note over DB,TX : "Lookup by_trx_id for duplicate detection" -DB->>TX : "find by_trx_id" -TX-->>DB : "exists?" -DB-->>Eval : "duplicate or accepted" -``` - -**Diagram sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L39-L49) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L170-L207) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L170-L207) - -### Content Object Lifecycle and Indices -- Purpose: Store content metadata, voting stats, payout tracking, and permlink hierarchy. -- Indices: - - by_id (unique) - - by_cashout_time (composite) - - by_permlink (composite: author + permlink) - - by_root (composite) - - by_parent (composite) - - by_last_update and by_author_last_update (non-consensus) - - content_vote indices: by_content_voter, by_voter_content, by_voter_last_update, by_content_weight_voter - - content_type_object: by_id, by_content -- Validation rules: - - String comparisons use custom comparator to support shared_string. - - Composite keys ensure uniqueness and efficient range scans. - -References: -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) - -```mermaid -flowchart TD -Start(["Insert or Update Content"]) --> SetFields["Set timestamps, rshares, cashout_time"] -SetFields --> Insert["Insert into content_index"] -Insert --> VotePath{"Has votes?"} -VotePath --> |Yes| UpdateVotes["Update content_vote_index
and permlink indices"] -VotePath --> |No| Done["Done"] -UpdateVotes --> Done -``` - -**Diagram sources** -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L197-L248) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L144-L184) - -**Section sources** -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L270) - -### validator Object Lifecycle and Indices -- Purpose: Track validator identities, votes, virtual scheduling, and penalties. -- Indices: - - witness_index: by_id, by_work, by_name, by_vote_name, by_counted_vote_name, by_schedule_time - - witness_vote_index: by_id, by_account_witness, by_witness_account - - witness_schedule_index: by_id - - witness_penalty_expire_index: by_id, by_account, by_expiration -- Scheduling: Virtual time algorithm uses fc::uint128_t fields to compute scheduling order. - -References: -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) - -```mermaid -classDiagram -class witness_object { -+id -+owner -+votes -+counted_votes -+virtual_scheduled_time -+signing_key -+props -} -class witness_vote_object { -+id -+validator -+account -} -class witness_schedule_object { -+id -+current_virtual_time -+current_shuffled_witnesses -+majority_version -} -class witness_penalty_expire_object { -+id -+validator -+penalty_percent -+expires -} -witness_object --> witness_vote_object : "votes" -witness_object --> witness_schedule_object : "schedule" -witness_object --> witness_penalty_expire_object : "penalties" -``` - -**Diagram sources** -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) - -**Section sources** -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L313) - -### Committee Objects Lifecycle and Indices -- Purpose: Manage committee requests and votes for funding/work proposals. -- Indices: - - committee_request_index: by_id, by_request_id, by_status, by_creator, by_worker, by_creator_url - - committee_vote_index: by_id, by_voter, by_request_id - -References: -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137) - -```mermaid -sequenceDiagram -participant Voter as "Account" -participant DB as "Database" -participant Req as "committee_request_object" -participant Vote as "committee_vote_object" -Voter->>DB : "submit vote(request_id, vote_percent)" -DB->>Req : "load by request_id" -Req-->>DB : "request exists" -DB->>Vote : "insert or update vote" -DB-->>Voter : "ack" -``` - -**Diagram sources** -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L87-L122) - -**Section sources** -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L15-L137) - -### Additional Objects -- Block Summary: Minimal per-block info for TaPOS. - - Reference: [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49) -- Invites: Invite issuance, keys, balances, status. - - Reference: [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- Paid Subscriptions: Creator plans and subscriber records. - - Reference: [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121) - -**Section sources** -- [block_summary_object.hpp](file://libraries/chain/include/graphene/chain/block_summary_object.hpp#L19-L49) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L72) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L121) - -## Dependency Analysis -The object model relies on: -- chainbase for persistent storage and object lifecycle. -- Boost.MultiIndex for multi-dimensional indexing. -- fc::raw and fc::variant for serialization/deserialization. -- Protocol types (asset, price, authority, operation) for cross-object references. - -```mermaid -graph LR -CT["chain_object_types.hpp"] --> AO["account_object.hpp"] -CT --> TO["transaction_object.hpp"] -CT --> CO["content_object.hpp"] -CT --> WO["witness_objects.hpp"] -CT --> CM["committee_objects.hpp"] -CT --> GP["global_property_object.hpp"] -CT --> BS["block_summary_object.hpp"] -CT --> IO["invite_objects.hpp"] -CT --> PS["paid_subscription_objects.hpp"] -DBH["database.hpp"] --> DB_CPP["database.cpp"] -DBH --> AO -DBH --> TO -DBH --> CO -DBH --> WO -DBH --> CM -DBH --> GP -DBH --> BS -DBH --> IO -DBH --> PS -``` - -**Diagram sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) -- [database.cpp](file://libraries/chain/database.cpp#L198-L200) - -**Section sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L200) - -## Performance Considerations -- Multi-index containers provide O(log n) insertion/search for each index; choose indices carefully to avoid excessive duplication. -- Hashed indices (e.g., by_trx_id) offer near O(1) lookup for deduplication. -- Composite indices enable efficient range queries and uniqueness constraints for complex relationships. -- Shared memory layout and allocation via chainbase minimize memory fragmentation. -- Virtual scheduling for validators uses large integer arithmetic; keep computations localized to reduce overhead. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and diagnostics: -- Duplicate transaction detection: Verify by_trx_id index presence and expiration cleanup. - - Reference: [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L39-L49) -- Missing account or authority: Check by_name and composite indices. - - Reference: [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L291-L315) -- Content not found by permlink: Confirm by_permlink index and string comparison behavior. - - Reference: [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L210-L226) -- validator scheduling anomalies: Inspect virtual_scheduled_time and vote indices. - - Reference: [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L183-L219) -- Committee vote conflicts: Ensure by_voter and by_request_id uniqueness. - - Reference: [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L107-L122) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L39-L49) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L291-L315) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L210-L226) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L183-L219) -- [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L107-L122) - -## Conclusion -The VIZ blockchain object model leverages a robust registry of object types, multi-index containers for efficient querying, and chainbase-backed persistence. The design cleanly separates consensus-critical indices from API-friendly ones, supports complex relationships (accounts, content, validators, committees), and provides strong serialization hooks. Proper index selection and lifecycle management are key to maintaining performance and correctness. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Example Workflows - -- Create and query an account - - Insert: Use account_object construction and store via chainbase insert. - - Query: Lookup by_name index for fast account retrieval. - - References: [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L291-L315) - -- Submit a transaction - - Pack transaction, store transaction_object, detect duplicates via by_trx_id. - - References: [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L39-L49) - -- Record a content vote - - Insert or update content_vote_object; maintain content_index and permlink indices. - - References: [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L144-L184) - -- Vote for a validator - - Insert witness_vote_object; update witness_object votes and virtual scheduling. - - References: [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L224-L248) - -- Committee voting - - Insert committee_vote_object keyed by voter and request_id. - - References: [committee_objects.hpp](file://libraries/chain/include/graphene/chain/committee_objects.hpp#L107-L122) - -### Versioning and Schema Evolution -- Object type registry: New object types are added to the enumeration and type aliases. - - Reference: [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- Reflection and raw serialization: FC_REFLECT and FC_REFLECT_TYPENAME declarations define wire format; changes require careful migration. - - Reference: [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L209-L246) -- Hardfork handling: Database may evolve indices and fields across hardforks; consult hardfork-aware code paths. - - Reference: [database.cpp](file://libraries/chain/database.cpp#L91-L92) - -**Section sources** -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L44-L144) -- [chain_object_types.hpp](file://libraries/chain/include/graphene/chain/chain_object_types.hpp#L209-L246) -- [database.cpp](file://libraries/chain/database.cpp#L91-L92) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Transaction Processing.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Transaction Processing.md deleted file mode 100644 index 154436e0e1..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Chain Library/Transaction Processing.md +++ /dev/null @@ -1,409 +0,0 @@ -# Transaction Processing - - -**Referenced Files in This Document** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [network_broadcast_api.cpp](file://plugins/network_broadcast_api/network_broadcast_api.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the Transaction Processing system responsible for validating and executing blockchain operations. It covers: -- Transaction metadata and duplication detection via transaction_object -- Evaluator system for operation interpretation -- Validation pipeline including signature verification, authority checks, and operation validation -- Execution context and rollback mechanisms for apply_transaction() and _apply_transaction() -- Pending transaction management, transaction pool operations, and broadcast mechanisms -- Examples of transaction processing workflows, operation evaluation, and error handling -- Interactions with validator scheduling, fee markets, and state transitions -- Transaction size limits, priority handling, and performance optimization strategies - -## Project Structure -The transaction processing logic spans several core modules: -- Protocol-level transaction and signed transaction definitions -- Chain-level evaluator and registry for operation dispatch -- Database-level transaction validation, execution, and persistence -- Plugins for chain ingestion and network broadcast - -```mermaid -graph TB -subgraph "Protocol Layer" -P1["transaction.hpp
Defines transaction, signed_transaction, annotated_signed_transaction"] -end -subgraph "Chain Layer" -C1["evaluator.hpp
Base evaluator interface"] -C2["evaluator_registry.hpp
Registry for operation dispatch"] -C3["transaction_object.hpp
Transaction metadata and duplication index"] -C4["transaction_object.cpp
Index implementation"] -end -subgraph "Database Layer" -D1["database.hpp/.cpp
apply_transaction/_apply_transaction,
validation, rollback, notifications"] -end -subgraph "Plugins" -PL1["plugins/chain/plugin.cpp
Ingestion and skip flags"] -PL2["plugins/network_broadcast_api/network_broadcast_api.cpp
Broadcast mechanism"] -end -P1 --> D1 -C1 --> C2 -C2 --> D1 -C3 --> D1 -C4 --> D1 -PL1 --> D1 -PL2 --> D1 -``` - -**Diagram sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L44) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L148-L148) -- [network_broadcast_api.cpp](file://plugins/network_broadcast_api/network_broadcast_api.cpp) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L1-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L1-L73) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L1-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L1-L44) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L1-L136) -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L148-L148) - -## Core Components -- Transaction metadata and duplication detection - - transaction_object stores packed transaction bytes, transaction ID, and expiration, enabling duplicate detection and expiry-based cleanup. - - Multi-index container supports by_id, by_trx_id, and by_expiration indices. - -- Evaluator system - - Base evaluator interface defines apply() and get_type(). - - evaluator_impl provides a template wrapper that routes operations to do_apply() of concrete evaluators. - - evaluator_registry maps operation types to registered evaluators and performs dispatch. - -- Transaction validation and execution - - apply_transaction() and _apply_transaction() orchestrate validation, duplicate checks, bandwidth updates, persistence, and operation application. - - apply_operation() notifies pre/post hooks and delegates to the evaluator registry. - -- Pending transactions and broadcasting - - Pending transactions are staged with temporary undo sessions; successful application merges into the pending block session. - - Notifications are emitted for pending and applied transactions; plugins broadcast transactions. - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L44) -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L136) - -## Architecture Overview -The transaction processing pipeline integrates protocol, chain, and database layers with plugin-driven ingestion and broadcasting. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant Plugin as "plugins/chain/plugin.cpp" -participant DB as "database.cpp" -participant Reg as "evaluator_registry.hpp" -participant Eval as "evaluator.hpp" -participant TxObj as "transaction_object.hpp" -Client->>Plugin : Submit signed_transaction -Plugin->>DB : validate_transaction() + apply_transaction() -DB->>DB : _apply_transaction()
- Duplicate check
- _validate_transaction()
- Bandwidth updates
- Persist transaction_object -DB->>Reg : get_evaluator(op) -Reg-->>DB : Evaluator instance -DB->>Eval : apply(op) -Eval-->>DB : Operation executed -DB-->>Plugin : Applied transaction notification -Plugin-->>Client : Result -Note over DB,TxObj : Transaction stored for duplicate detection until expiry -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L148-L148) -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L29-L41) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) - -## Detailed Component Analysis - -### Transaction Metadata and Duplication Detection -- Purpose: Detect duplicate transactions and manage expiry windows. -- Storage: transaction_object holds packed_trx, trx_id, and expiration. -- Indexing: Multi-index supports fast lookup by ID, transaction ID, and expiration ordering. -- Lifecycle: After block processing, expired entries are removed from the index. - -```mermaid -classDiagram -class transaction_object { -+id_type id -+bip : : vector packed_trx -+transaction_id_type trx_id -+time_point_sec expiration -} -class transaction_index { -+create(constructor, object_id_type) -+modify(object, modifier) -+add(unique_ptr) -+remove(object_id_type) -+get(object_id_type) const -} -transaction_index --> transaction_object : "indexes" -``` - -**Diagram sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) - -### Evaluator System -- Base evaluator: Virtual apply() and get_type() define the contract. -- Template evaluator_impl: Wraps concrete evaluators, casting operation to the specific type and invoking do_apply(). -- Registry: Stores evaluators per operation type; get_evaluator() returns the appropriate evaluator instance. - -```mermaid -classDiagram -class evaluator~OperationType~ { -<> -+apply(op : OperationType) void -+get_type() int -} -class evaluator_impl~EvaluatorType, OperationType~ { --database& _db -+apply(op : OperationType) void -+get_type() int -+db() database& -} -class evaluator_registry~OperationType~ { --vector>> _op_evaluators --database& _db -+register_evaluator(args...) -+get_evaluator(op : OperationType) evaluator& -} -evaluator <|-- evaluator_impl -evaluator_registry --> evaluator : "dispatches" -``` - -**Diagram sources** -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L44) - -**Section sources** -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L44) - -### Transaction Validation Pipeline -- Signature verification and authority checks are performed during _validate_transaction(). -- Required authorities are computed from the transaction; bandwidth updates are applied per account and operation type. -- Duplicate transaction detection uses the by_trx_id index; if a duplicate exists, the assertion fails. -- After validation, the transaction is persisted as a transaction_object with expiration. - -```mermaid -flowchart TD -Start(["Start apply_transaction"]) --> SetTrxId["Set current transaction id"] -SetTrxId --> DupCheck{"Duplicate check enabled?"} -DupCheck --> |Yes| FindDup["Lookup by_trx_id"] -FindDup --> DupFound{"Duplicate found?"} -DupFound --> |Yes| FailDup["Fail with duplicate error"] -DupFound --> |No| Validate["_validate_transaction()"] -DupCheck --> |No| Validate -Validate --> ComputeAuth["Compute required authorities"] -ComputeAuth --> Bandwidth["Update account bandwidth"] -Bandwidth --> Persist{"Skip duplicate check?"} -Persist --> |No| Store["Persist transaction_object"] -Persist --> |Yes| Ops["Apply operations"] -Store --> Ops -Ops --> Done(["Done"]) -FailDup --> Done -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L3657-L3711) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3657-L3711) - -### apply_transaction() and _apply_transaction() Methods -- apply_transaction(): Public entrypoint that calls _apply_transaction() and emits on_applied_transaction notification. -- _apply_transaction(): - - Sets execution context (_current_trx_id, _current_virtual_op, _current_op_in_trx) - - Performs duplicate check and validation - - Updates bandwidth accounting for required authorities - - Persists transaction_object (unless skip flag is set) - - Iterates operations and applies via apply_operation() - -```mermaid -sequenceDiagram -participant API as "Caller" -participant DB as "database.cpp" -participant REG as "evaluator_registry.hpp" -participant EVAL as "evaluator.hpp" -API->>DB : apply_transaction(trx, skip) -DB->>DB : _apply_transaction(trx, skip) -DB->>DB : _validate_transaction(trx) -DB->>DB : update_account_bandwidth(...) -DB->>DB : create(transaction_object) -loop For each operation -DB->>REG : get_evaluator(op) -REG-->>DB : evaluator -DB->>EVAL : apply(op) -EVAL-->>DB : success -end -DB-->>API : on_applied_transaction notification -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L29-L41) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) - -### Rollback Mechanisms -- Pending transactions are staged within a temporary undo session created before applying each transaction. -- On success, the temporary session is merged into the pending block session. -- On failure, the temporary session is discarded, preserving the previous clean state. -- During block generation, pending transactions are re-applied with the new block time context; invalid/expired transactions are skipped or postponed. - -```mermaid -flowchart TD -Begin(["Begin pending stage"]) --> TempSess["Start temporary undo session"] -TempSess --> Apply["_apply_transaction(trx)"] -Apply --> Success{"Success?"} -Success --> |Yes| Merge["Merge into pending block session"] -Success --> |No| Discard["Discard temporary session"] -Merge --> Notify["notify_changed_objects()"] -Discard --> End(["End"]) -Notify --> End -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L950-L970) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L950-L970) - -### Pending Transaction Management and Broadcasting -- Pending transactions are appended to an internal list after successful application and merged into the pending block session. -- Notifications are emitted for on_pending_transaction and on_applied_transaction. -- Plugins listen to these notifications to broadcast transactions to peers. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant Notif as "Notifications" -participant Net as "network_broadcast_api.cpp" -DB->>DB : _apply_transaction(trx) -DB->>Notif : notify_on_pending_transaction(trx) -Notif-->>Net : on_pending_transaction callback -DB->>Notif : notify_on_applied_transaction(trx) -Notif-->>Net : on_applied_transaction callback -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L960-L970) -- [database.cpp](file://libraries/chain/database.cpp#L1192-L1198) -- [network_broadcast_api.cpp](file://plugins/network_broadcast_api/network_broadcast_api.cpp) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L960-L970) -- [database.cpp](file://libraries/chain/database.cpp#L1192-L1198) - -### Relationship with validator Scheduling, Fee Markets, and State Transitions -- validator scheduling: The database computes scheduled validators and validates block headers; transaction processing occurs within the context of block production and validation. -- Fee markets and state transitions: Operations modify state objects (e.g., balances, vesting shares, reward funds). Bandwidth accounting influences fee market dynamics indirectly by controlling resource usage and reserve ratios. - -[No sources needed since this section synthesizes relationships without analyzing specific files] - -### Transaction Size Limits, Priority Handling, and Performance Optimization -- Block size limits: During block generation, transactions are included until maximum_block_size is reached; oversized transactions are postponed with a configurable limit. -- Priority handling: Transactions are included in the order they are applied within the pending pool; no explicit prioritization mechanism is shown in the analyzed code. -- Performance optimizations: - - Temporary undo sessions isolate failed transactions without committing state changes. - - Bandwidth updates are applied per-account and per-operation type to prevent excessive data operations. - - Duplicate detection avoids reprocessing identical transactions. - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L1036-L1063) -- [database.cpp](file://libraries/chain/database.cpp#L3675-L3698) - -## Dependency Analysis -The transaction processing system exhibits clear layering: -- Protocol layer defines transaction structures and authority verification helpers. -- Chain layer provides evaluator abstractions and registry for operation dispatch. -- Database layer orchestrates validation, execution, persistence, and notifications. -- Plugins integrate ingestion and broadcasting. - -```mermaid -graph LR -Protocol["transaction.hpp"] --> Database["database.cpp"] -Evaluator["evaluator.hpp"] --> Database -Registry["evaluator_registry.hpp"] --> Database -TxObj["transaction_object.hpp"] --> Database -Plugin["plugins/chain/plugin.cpp"] --> Database -Broadcast["network_broadcast_api.cpp"] --> Plugin -``` - -**Diagram sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L44) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L148-L148) -- [network_broadcast_api.cpp](file://plugins/network_broadcast_api/network_broadcast_api.cpp) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3651-L3722) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L148-L148) - -## Performance Considerations -- Minimize redundant validations by leveraging skip flags appropriately. -- Use temporary undo sessions to avoid expensive rollbacks after failures. -- Monitor average block size and reserve ratio adjustments to tune network capacity. -- Apply bandwidth updates early to prevent oversized operations from consuming resources unnecessarily. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and diagnostics: -- Duplicate transaction errors: Occur when by_trx_id lookup finds an existing transaction_object. -- Validation failures: Thrown by _validate_transaction() during signature verification or authority checks. -- Expiry-related problems: Expired transactions are skipped; ensure proper time synchronization. -- Bandwidth throttling: Excessive data operations may incur additional bandwidth penalties. - -Mitigations: -- Verify transaction signatures and required authorities before submission. -- Monitor pending transaction notifications and error logs. -- Adjust skip flags only when necessary and understood. - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3665-L3667) -- [database.cpp](file://libraries/chain/database.cpp#L3669-L3669) - -## Conclusion -The Transaction Processing system integrates protocol-level transaction definitions, a flexible evaluator registry, and robust database orchestration to validate and execute blockchain operations reliably. It supports duplication detection, bandwidth accounting, rollback via undo sessions, and plugin-driven broadcasting. Understanding the execution context, validation pipeline, and performance characteristics enables effective tuning and troubleshooting of transaction throughput and reliability. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Core Libraries.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Core Libraries.md deleted file mode 100644 index 7edbb80e40..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Core Libraries.md +++ /dev/null @@ -1,389 +0,0 @@ -# Core Libraries - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://libraries/CMakeLists.txt) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the four fundamental library layers that underpin the blockchain node: -- Chain library: blockchain state management, validation, and consensus integration -- Protocol library: operation definitions, transactions, and cryptographic primitives -- Network library: peer-to-peer communication, synchronization, and message transport -- Wallet library: transaction signing, key management, and user-facing APIs - -It documents the architectural patterns used in each layer (observer pattern for event handling, factory-like registries for evaluators), the separation of concerns, and how these libraries integrate to deliver complete blockchain functionality. The design rationale for C++ is grounded in performance and deterministic behavior for cryptographic and consensus-critical operations. - -## Project Structure -The core libraries are organized as independent modules under libraries/, each exporting headers and implementations that are consumed by higher-level applications and plugins. - -```mermaid -graph TB -subgraph "Core Libraries" -CH["Chain Library
libraries/chain"] -PR["Protocol Library
libraries/protocol"] -NW["Network Library
libraries/network"] -WL["Wallet Library
libraries/wallet"] -UT["Utilities Library
libraries/utilities"] -TM["Time Library
libraries/time"] -AP["API Library
libraries/api"] -end -CH --> PR -NW --> PR -WL --> PR -WL --> CH -NW --> CH -CH --> UT -WL --> UT -NW --> UT -CH --> TM -WL --> AP -``` - -**Diagram sources** -- [CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) - -**Section sources** -- [CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) - -## Core Components -- Chain library - - Provides the blockchain state machine, fork resolution, block and transaction validation, and event signaling for observers. - - Exposes APIs to push blocks/transactions, query chain state, and subscribe to lifecycle events. -- Protocol library - - Defines the canonical operation types, transaction structure, and cryptographic primitives (signatures, digests). - - Supplies helpers for authority verification and signature minimization. -- Network library - - Implements a peer-to-peer node with message-oriented transport, peer connection management, and synchronization protocols. - - Offers a delegate interface for integrating chain logic into network callbacks. -- Wallet library - - Offers a high-level API for building, signing, and broadcasting transactions. - - Integrates with remote node APIs via typed remote interfaces and exposes signals for UI updates. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L355) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -## Architecture Overview -The libraries collaborate through well-defined interfaces and event channels: -- The Chain library emits signals for block application, transaction lifecycle, and operation application. -- The Network library invokes the Chain library’s validation and push routines via a node delegate interface. -- The Protocol library defines the shared data structures and cryptographic semantics used across Chain, Network, and Wallet. -- The Wallet library composes transactions using Protocol types, signs them, and broadcasts via Network or remote node APIs. - -```mermaid -graph TB -subgraph "Network Layer" -NET_NODE["graphene::network::node"] -PEER_CONN["graphene::network::peer_connection"] -MSG_CONN["graphene::network::message_oriented_connection"] -end -subgraph "Chain Layer" -CH_DB["graphene::chain::database"] -EVAL["graphene::chain::evaluator"] -REG["Evaluator Registry"] -end -subgraph "Protocol Layer" -OPS["graphene::protocol::operations"] -TX["graphene::protocol::transaction/sig"] -end -subgraph "Wallet Layer" -WALLET["graphene::wallet::wallet_api"] -REMOTE["graphene::wallet::remote_* APIs"] -end -NET_NODE --> CH_DB -PEER_CONN --> NET_NODE -MSG_CONN --> PEER_CONN -WALLET --> TX -WALLET --> REMOTE -WALLET --> CH_DB -CH_DB --> EVAL -EVAL --> OPS -CH_DB --> TX -NET_NODE --> OPS -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L355) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L355) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L44-L85) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L44-L175) - -## Detailed Component Analysis - -### Chain Library -- Responsibilities - - Manage blockchain state, fork database, block log, and hardfork transitions. - - Validate blocks and transactions according to configurable skip flags. - - Apply operations via evaluators and emit signals for observers. -- Architectural patterns - - Observer pattern: Signals for pre/post operation application, applied block, pending/applied transactions. - - Factory/registry pattern: Evaluator registry and custom operation interpreter registry enable extensibility without modifying core logic. -- Key interfaces - - database: open/reindex, push_block/push_transaction, notify_* signals, get_* queries. - - evaluator: polymorphic apply() with static dispatch to concrete operation types. - - chain_evaluator: macro-generated evaluator declarations for each operation. - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, ...) -+reindex(data_dir, shared_mem_dir, ...) -+push_block(...) -+push_transaction(...) -+notify_pre_apply_operation(...) -+notify_post_apply_operation(...) -+notify_applied_block(...) -+notify_on_pending_transaction(...) -+notify_on_applied_transaction(...) -+pre_apply_operation : signal -+post_apply_operation : signal -+applied_block : signal -+on_pending_transaction : signal -+on_applied_transaction : signal -} -class evaluator_T { -<> -+apply(op) -+get_type() int -} -class evaluator_impl_T { --_db : database& -+apply(op) -+get_type() int -+db() database& -} -database --> evaluator_T : "uses registry" -evaluator_impl_T ..|> evaluator_T -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L80) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L561) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L62) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L80) - -### Protocol Library -- Responsibilities - - Define canonical operation types and transaction structure. - - Provide cryptographic helpers: digests, signature computation, authority verification, and signature minimization. -- Architectural patterns - - Static variant for operation union enables efficient dispatch and serialization. - - Visitor-style visit() on transactions to apply visitor to each contained operation. -- Key interfaces - - operations: static_variant union of all operations. - - transaction/sig: structure with operations, extensions, and signature handling. - -```mermaid -classDiagram -class operations { -<> -+union : all operation types -} -class transaction { -+ref_block_num : uint16 -+ref_block_prefix : uint32 -+expiration : time_point_sec -+operations : vector -+extensions : extensions_type -+digest() digest_type -+id() transaction_id_type -+validate() void -+sig_digest(chain_id) digest_type -+set_expiration(time_point_sec) -+set_reference_block(block_id_type) -+visit(visitor) : vector -+get_required_authorities(...) void -} -class signed_transaction { -+signatures : vector -+sign(private_key, chain_id) -+verify_authority(...) -+minimize_required_signatures(...) -+get_signature_keys(chain_id) flat_set -+merkle_digest() digest_type -} -operations --> transaction : "contains" -transaction <|-- signed_transaction -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) - -### Network Library -- Responsibilities - - Peer-to-peer connectivity, message transport, and blockchain synchronization. - - Delegate-driven integration with chain logic for handling blocks, transactions, and sync status. -- Architectural patterns - - Observer pattern: delegate callbacks for block, transaction, message handling, sync status, and connection count changes. - - Message-oriented abstraction: message_oriented_connection encapsulates socket I/O and message framing. - - Factory-like peer connection management: peer_connection maintains queues and negotiation states. -- Key interfaces - - node: listen/connect, add_node, broadcast, sync_from, delegate registration. - - peer_connection: connection states, inventory tracking, message queuing. - - message_oriented_connection: socket binding, sending/receiving messages. - -```mermaid -sequenceDiagram -participant NET as "graphene : : network : : node" -participant PEER as "graphene : : network : : peer_connection" -participant DEL as "node_delegate" -participant CH as "graphene : : chain : : database" -NET->>PEER : "connect_to(endpoint)" -PEER-->>NET : "on_message(block_message)" -NET->>DEL : "handle_block(block_message, sync_mode, contained_txn_ids)" -DEL->>CH : "push_block(next_block)" -CH-->>DEL : "applied_block signal" -DEL-->>NET : "sync_status(...)" -NET-->>PEER : "broadcast(trx_message)" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L355) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L355) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L44-L85) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L355) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L355) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L44-L85) - -### Wallet Library -- Responsibilities - - Build, sign, and propose transactions; manage keys and credentials; expose user-facing APIs. - - Integrate with remote node APIs for read/write operations and broadcasting. -- Architectural patterns - - Remote API façades: typed remote_* structs define method signatures for remote plugins. - - Observer pattern: signals for lock state and quit command. - - Builder pattern: transaction builder handles composing operations and previewing before signing. -- Key interfaces - - wallet_api: transaction builder, signing, account/history queries, memo encryption/decryption. - - remote_* APIs: remote_database_api, remote_network_broadcast_api, etc. - -```mermaid -sequenceDiagram -participant APP as "wallet_api" -participant REM as "remote_network_broadcast_api" -participant NET as "network : : node" -participant CH as "chain : : database" -APP->>APP : "begin_builder_transaction()" -APP->>APP : "add_operation_to_builder_transaction()" -APP->>APP : "preview_builder_transaction()" -APP->>APP : "sign_builder_transaction()" -APP->>REM : "broadcast_transaction(signed_trx)" -REM-->>NET : "broadcast(trx_message)" -NET->>CH : "push_transaction(signed_trx)" -CH-->>APP : "on_applied_transaction signal" -``` - -**Diagram sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L122-L126) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L258-L262) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L268-L275) - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L44-L175) - -## Dependency Analysis -- Inter-library dependencies - - Chain depends on Protocol for operation and transaction types. - - Network depends on Protocol for chain_id and types; integrates with Chain via node delegate. - - Wallet depends on Protocol for transaction types and on Network/Remote APIs for broadcasting. -- Coupling and cohesion - - Loose coupling is achieved via delegate interfaces (node_delegate) and typed remote APIs. - - Cohesion is maintained by keeping each library focused on a single responsibility. - -```mermaid -graph LR -PR["protocol"] --> CH["chain"] -PR --> NW["network"] -PR --> WL["wallet"] -CH --> NW -WL --> NW -WL --> CH -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L3-L8) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L26-L30) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L18-L20) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L3-L8) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L26-L30) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L18-L20) - -## Performance Considerations -- C++ choice - - Deterministic memory layout, zero-overhead abstractions, and fine-grained control over threading and concurrency are essential for cryptographic operations and consensus-critical paths. -- Event-driven design - - Signal emissions in Chain and Wallet avoid synchronous callbacks, reducing contention and enabling asynchronous observers. -- Message-oriented networking - - Encapsulation of socket I/O and message framing reduces overhead and simplifies protocol handling. -- Signature verification and authority checks - - Protocol-level helpers minimize redundant computations and support signature minimization to reduce verification cost. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Validation failures - - Chain library exposes skip flags to bypass expensive checks during reindexing or local operations. Use appropriate skip masks to diagnose validation bottlenecks. -- Transaction signing issues - - Wallet relies on remote node APIs for signature discovery and verification. Confirm remote node connectivity and that required keys are present in the wallet. -- Network synchronization - - Use node delegate callbacks to monitor sync progress and connection counts. Investigate peer inventory lists and sync item requests to identify stalled peers. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L929-L931) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L143-L148) - -## Conclusion -The four core libraries form a cohesive, loosely coupled architecture: -- Chain manages state and validation with observer-driven notifications -- Protocol defines shared data structures and cryptographic semantics -- Network provides robust peer-to-peer transport and synchronization -- Wallet offers a practical interface for signing and broadcasting transactions - -This layered design, combined with C++’s performance characteristics, enables a high-throughput, extensible blockchain node capable of evolving with new operations, network protocols, and wallet features. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Message Handling and Protocol.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Message Handling and Protocol.md deleted file mode 100644 index 15d12fdec9..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Message Handling and Protocol.md +++ /dev/null @@ -1,442 +0,0 @@ -# Message Handling and Protocol - - -**Referenced Files in This Document** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [core_messages.cpp](file://libraries/network/core_messages.cpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the network message handling and protocol layer used by the node. It focuses on: -- Standard network message types for blocks and transactions -- Generic message packaging, serialization, and deserialization -- Protocol versioning and compliance validation -- Message routing, delivery guarantees, ordering, propagation tracking, and duplicate detection -- Practical patterns for message creation, transmission, and processing -- Compression, fragmentation, and protocol upgrade mechanisms -- Guidance for extending the protocol with custom message types - -## Project Structure -The messaging stack spans several files: -- Core message type definitions and constants -- Generic message container and serializer -- TCP transport abstraction with message framing and padding -- Node-level message caching, propagation tracking, and processing -- Peer connection orchestration and queueing - -```mermaid -graph TB -subgraph "Network Layer" -CM["core_messages.hpp
Core message types"] -MSG["message.hpp
Generic message pack/unpack"] -MOC["message_oriented_connection.cpp
TCP framing + padding"] -CFG["config.hpp
Protocol constants"] -end -subgraph "Peer and Node" -PC["peer_connection.cpp
Queueing + dispatch"] -NODE["node.cpp
Caching + propagation + processing"] -NAPI["node.hpp
Propagation data + callbacks"] -end -CM --> MSG -MSG --> MOC -CFG --> MOC -MOC --> PC -PC --> NODE -NAPI --> NODE -``` - -**Diagram sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L42-L573) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L33-L114) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L244-L300) -- [node.cpp](file://libraries/network/node.cpp#L112-L200) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) - -**Section sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L42-L573) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L33-L114) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L244-L300) -- [node.cpp](file://libraries/network/node.cpp#L112-L200) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) - -## Core Components -- Core message types: block_message, trx_message, item_id, and many handshake/control messages -- Generic message: message_header + payload + hash -- Transport: message_oriented_connection with fixed-size padding and bounds checking -- Node-level caching and propagation metadata -- Peer queueing and dispatch - -Key responsibilities: -- Define standardized message envelopes and types -- Pack/unpack messages with reflection-based raw serialization -- Enforce protocol version and message size limits -- Track message propagation and deduplicate via caches keyed by hashes - -**Section sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L54-L151) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L160-L183) -- [node.cpp](file://libraries/network/node.cpp#L112-L176) - -## Architecture Overview -The system separates concerns across layers: -- Protocol types live in core_messages.hpp -- Generic message packaging is in message.hpp -- Transport framing and padding are in message_oriented_connection.cpp -- Node-level caching and propagation tracking are in node.cpp and node.hpp -- Peer queueing and dispatch are in peer_connection.cpp - -```mermaid -sequenceDiagram -participant App as "Application" -participant Node as "node.cpp" -participant Peer as "peer_connection.cpp" -participant Conn as "message_oriented_connection.cpp" -participant Net as "TCP Socket" -App->>Node : "Create message (e.g., block_message)" -Node->>Peer : "Queue message for sending" -Peer->>Conn : "send_message(message)" -Conn->>Net : "Write padded frame (header + payload)" -Net-->>Conn : "ACK" -Conn-->>Peer : "Sent" -Peer-->>Node : "Ack" -Node-->>App : "Queuing complete" -``` - -**Diagram sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L70-L105) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L237-L283) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L272-L297) -- [node.cpp](file://libraries/network/node.cpp#L1372-L1380) - -## Detailed Component Analysis - -### Core Message Types: block_message, trx_message, item_id -- item_id: identifies items by type and hash -- block_message: carries a signed block plus its block_id -- trx_message: carries a signed transaction -- Additional core_message_type_enum entries cover inventory, fetch, hello, and connection lifecycle messages - -```mermaid -classDiagram -class item_id { -+uint32_t item_type -+item_hash_t item_hash -+operator==(other) bool -} -class block_message { -+signed_block block -+block_id_type block_id -} -class trx_message { -+signed_transaction trx -} -class message { -+uint32_t size -+uint32_t msg_type -+std : : vector data -+id() message_hash_type -+as() T -} -message <|-- block_message -message <|-- trx_message -item_id --> block_message : "used in inventory/fetch" -item_id --> trx_message : "used in inventory/fetch" -``` - -**Diagram sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L54-L125) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L42-L106) - -**Section sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L54-L125) -- [core_messages.cpp](file://libraries/network/core_messages.cpp#L30-L49) - -### Generic Message Packaging and Serialization -- message_header: size and msg_type -- message: extends header with payload data -- Constructor packs a typed object into raw bytes -- as() validates msg_type and unpacks the payload -- id() computes a deterministic hash of the serialized payload - -```mermaid -flowchart TD -Start(["Create typed message"]) --> Pack["Pack object into raw bytes"] -Pack --> SetHeader["Set size and msg_type"] -SetHeader --> BuildMsg["Build message (header + data)"] -BuildMsg --> Hash["Compute message hash"] -Hash --> Done(["Ready to send"]) -``` - -**Diagram sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L70-L105) - -**Section sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L42-L106) - -### Transport Framing, Padding, and Bounds Checking -- Fixed 8-byte header with size and msg_type -- Read loop reads header, validates size against MAX_MESSAGE_SIZE, allocates payload with padding, reads remainder, truncates padding -- Send pads total frame length to 16-byte multiples -- Thread-safety guard prevents concurrent sends - -```mermaid -flowchart TD -RStart(["Read loop"]) --> ReadHdr["Read 8-byte header"] -ReadHdr --> CheckSize{"size <= MAX_MESSAGE_SIZE?"} -CheckSize --> |No| Error["Log error and disconnect"] -CheckSize --> |Yes| Alloc["Allocate payload with padding"] -Alloc --> ReadBody["Read remaining bytes"] -ReadBody --> Trunc["Truncate padding"] -Trunc --> Dispatch["Delegate.on_message()"] -Dispatch --> RStart -``` - -**Diagram sources** -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L160-L183) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L38-L39) - -**Section sources** -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L38-L39) - -### Protocol Versioning and Compliance Validation -- Protocol version constant is defined centrally -- hello_message and connection_rejected_message carry core_protocol_version -- Rejection reasons include client_too_old and different_chain - -```mermaid -sequenceDiagram -participant A as "Peer A (hello)" -participant B as "Peer B (node)" -A->>B : "hello_message(core_protocol_version, ...)" -alt "Version mismatch or incompatible chain" -B-->>A : "connection_rejected_message(reason_code, ...)" -else "Compatible" -B-->>A : "connection_accepted_message()" -end -``` - -**Diagram sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L26) - -**Section sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L96-L98) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) - -### Message Routing, Delivery Guarantees, Ordering, and Propagation Tracking -- Peer queueing ensures ordered transmission per peer -- Node maintains a blockchain-tied message cache keyed by message hash and content hash -- message_propagation_data tracks received_time, validated_time, and originating_peer -- Duplicate detection uses message hash and content hash indices - -```mermaid -classDiagram -class message_propagation_data { -+time_point received_time -+time_point validated_time -+node_id_t originating_peer -} -class blockchain_tied_message_cache { -+cache_message(message, hash, propagation_data, content_hash) -+get_message(hash) message -+get_message_propagation_data(content_hash) message_propagation_data -+block_accepted() -} -message_propagation_data <.. blockchain_tied_message_cache : "stored with cached messages" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) -- [node.cpp](file://libraries/network/node.cpp#L112-L176) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) -- [node.cpp](file://libraries/network/node.cpp#L112-L200) - -### Message Validation Workflows and Duplicate Detection -- On receipt, message is validated and processed -- Duplicate detection leverages content hash index to avoid reprocessing identical transactions/blocks -- Propagation metadata is recorded for analytics and debugging - -```mermaid -flowchart TD -In(["Receive message"]) --> Validate["Validate type and payload"] -Validate --> Dedup{"Duplicate content?"} -Dedup --> |Yes| Skip["Skip processing"] -Dedup --> |No| Cache["Cache message with propagation data"] -Cache --> Process["Process item (block/trx)"] -Process --> Broadcast["Advertise to peers"] -Skip --> End(["Done"]) -Broadcast --> End -``` - -**Diagram sources** -- [node.cpp](file://libraries/network/node.cpp#L187-L200) -- [node.cpp](file://libraries/network/node.cpp#L729-L745) - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L187-L200) -- [node.cpp](file://libraries/network/node.cpp#L729-L745) - -### Examples of Message Creation, Transmission, and Processing Patterns -- Creating a block_message: construct with a signed_block; message wrapper sets msg_type and serializes -- Queuing for sending: peer_connection queues messages; send loop transmits with padding -- Processing: node delegates to appropriate handler; for blocks, it may trigger fork selection and broadcasting - -```mermaid -sequenceDiagram -participant Producer as "Block Producer" -participant Node as "node.cpp" -participant Peer as "peer_connection.cpp" -participant Transport as "message_oriented_connection.cpp" -Producer->>Node : "Produce block_message" -Node->>Peer : "Queue for broadcast" -Peer->>Transport : "send_message(message)" -Transport-->>Peer : "Sent" -Peer-->>Node : "Ack" -``` - -**Diagram sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L70-L75) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L272-L297) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L237-L283) - -**Section sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L70-L75) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L272-L297) -- [node.cpp](file://libraries/network/node.cpp#L1372-L1380) - -### Compression, Fragmentation Handling, and Protocol Upgrade Mechanisms -- Compression: not implemented in the referenced files; payload is raw serialized data -- Fragmentation: handled by fixed-size padding and bounded reads/writes; MAX_MESSAGE_SIZE enforces upper bound -- Protocol upgrades: controlled by core_protocol_version; peers exchange hello and reject incompatible versions - -**Section sources** -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L38-L39) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) - -### Implementing Custom Message Types and Extension Points -- Define a new struct with a static type member matching a core_message_type_enum value -- Reflect the struct for serialization -- Ensure msg_type is registered and handled in the node’s dispatcher -- Consider adding to inventory/fetch workflows if the item should be gossiped - -Guidance: -- Keep msg_type unique within the core_message_type_enum range -- Use FC_REFLECT macros for serialization compatibility -- Respect MAX_MESSAGE_SIZE and avoid excessive payloads -- For gossipable items, integrate with inventory and fetch handlers - -**Section sources** -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L95) -- [core_messages.cpp](file://libraries/network/core_messages.cpp#L30-L49) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L478-L560) - -## Dependency Analysis -- core_messages.hpp depends on protocol types and reflection -- message.hpp depends on raw serialization and hashing -- message_oriented_connection.cpp depends on config constants and socket I/O -- node.cpp depends on peer_connection and message propagation metadata -- node.hpp defines the propagation data structure and delegate callbacks - -```mermaid -graph LR -CFG["config.hpp"] --> MOC["message_oriented_connection.cpp"] -MSG["message.hpp"] --> MOC -CMH["core_messages.hpp"] --> MSG -CMH --> MOC -PC["peer_connection.cpp"] --> MOC -NODE["node.cpp"] --> PC -NAPI["node.hpp"] --> NODE -``` - -**Diagram sources** -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L33-L114) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L26-L50) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L29-L31) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L24-L29) -- [node.cpp](file://libraries/network/node.cpp#L64-L66) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) - -**Section sources** -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L26-L50) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L33-L114) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L29-L31) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L24-L29) -- [node.cpp](file://libraries/network/node.cpp#L64-L66) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) - -## Performance Considerations -- Fixed 16-byte padding reduces alignment overhead but increases bandwidth; acceptable given MAX_MESSAGE_SIZE is enforced -- Message size validation prevents oversized packets -- Queueing and per-peer send guards reduce contention -- Blockchain-tied cache evicts based on block clock to bound memory - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and diagnostics: -- Oversized messages: MAX_MESSAGE_SIZE exceeded triggers logs; inspect payload sizes -- Type mismatches: as() throws if msg_type does not match expected type -- Connection closure: read_loop handles EOF and exceptions, invoking on_connection_closed -- Send concurrency: assertion prevents concurrent send_message invocations - -Actions: -- Verify protocol version compatibility in hello messages -- Monitor logs for “message transmission failed” and “disconnected” -- Confirm queue sizes and cache eviction behavior - -**Section sources** -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L168-L169) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L87-L104) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L190-L234) - -## Conclusion -The messaging layer provides a robust, extensible foundation for network communication: -- Strong typing and reflection-based serialization -- Reliable framing with bounds checking and padding -- Clear protocol versioning and rejection semantics -- Built-in propagation tracking and duplicate detection -- Practical patterns for broadcasting and processing - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Message Lifecycle Summary -- Creation: Construct typed message; message wrapper serializes and sets type -- Framing: Header + padded payload written to socket -- Reception: Header read, payload read, padding truncated, type checked -- Processing: Delegate invoked; node caches and tracks propagation -- Broadcasting: Inventory and fetch messages coordinate propagation - -**Section sources** -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp#L70-L105) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L160-L183) -- [node.cpp](file://libraries/network/node.cpp#L112-L176) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Network Library.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Network Library.md deleted file mode 100644 index b5326e6ca8..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Network Library.md +++ /dev/null @@ -1,919 +0,0 @@ -# Network Library - - -**Referenced Files in This Document** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [core_messages.cpp](file://libraries/network/core_messages.cpp) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [peer_database.cpp](file://libraries/network/peer_database.cpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) - - -## Update Summary -**Changes Made** -- Enhanced synchronization logging section to document new CLOG_GRAY ANSI color code for gray-colored log output -- Updated logging verbosity documentation to reflect systematic replacement of fc_ilog with fc_dlog throughout sync process -- Added documentation for enhanced logging in fetch_sync_items_loop, blockchain item inventory handling, sync status updates, and sync start procedures with enhanced visibility -- Updated troubleshooting guidance with new logging patterns and gray color coding -- Enhanced logging system documentation with comprehensive fc_dlog vs fc_ilog usage patterns - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Peer Statistics and Metrics System](#peer-statistics-and-metrics-system) -7. [Peer Information Handling and IP Extraction](#peer-information-handling-and-ip-extraction) -8. [Programmatic Synchronization Control](#programmatic-synchronization-control) -9. [Enhanced Peer Connection Logging](#enhanced-peer-connection-logging) -10. [Enhanced Synchronization Logging System](#enhanced-synchronization-logging-system) -11. [Dependency Analysis](#dependency-analysis) -12. [Performance Considerations](#performance-considerations) -13. [Troubleshooting Guide](#troubleshooting-guide) -14. [Conclusion](#conclusion) - -## Introduction -This document describes the Network Library that implements peer-to-peer communication and network protocol for the VIZ node. It covers the node management layer, peer connection orchestration, standard network messages, secure transport, peer address management, and message serialization. The library provides a robust foundation for blockchain synchronization, transaction broadcasting, and block propagation across a distributed network. - -**Updated** Enhanced with comprehensive peer statistics logging system including latency tracking, blocking status reporting, periodic statistics collection, improved peer information handling with reliable IP address extraction and reduced conversion overhead. Added programmatic synchronization control through the new `resync()` method for improved network recovery from various network states. The virtual `resync()` method provides extensibility for derived classes to customize synchronization restart behavior. Enhanced peer connection logging now supports color-coded output for better visibility of network events. **Enhanced synchronization logging system with new CLOG_GRAY ANSI color code and systematic fc_dlog usage throughout sync process for improved log verbosity and clarity.** - -## Project Structure -The network library is organized into cohesive modules: -- Node management and synchronization orchestration with virtual resync method support -- Peer connection lifecycle and message queues with enhanced logging -- Standard network message definitions -- Secure TCP transport with ECDH key exchange -- Peer address database and topology maintenance -- Message serialization/deserialization framework -- Configuration constants for protocol behavior -- **Peer statistics and metrics collection system with improved IP address extraction** -- **P2P plugin integration for peer monitoring and statistics with color-coded logging** -- **Programmatic synchronization control for network recovery with virtual method extensibility** -- **Enhanced synchronization logging system with CLOG_GRAY color coding and fc_dlog usage patterns** - -```mermaid -graph TB -subgraph "Network Layer" -N["node.hpp
node.cpp"] -PC["peer_connection.hpp
peer_connection.cpp"] -MSG["message.hpp"] -CM["core_messages.hpp
core_messages.cpp"] -STCP["stcp_socket.hpp
stcp_socket.cpp"] -PD["peer_database.hpp
peer_database.cpp"] -MOC["message_oriented_connection.hpp"] -CFG["config.hpp"] -STATS["Statistics System"] -P2P["p2p_plugin.cpp"] -RESYNC["Virtual resync() Method"] -SIMNET["simulated_network"] -COLOR["Color Logging Support"] -SYNCLOG["Enhanced Synchronization Logging"] -GRAY["CLOG_GRAY ANSI Color Code"] -FCDLOG["fc_dlog Usage Patterns"] -end -N --> PC -N --> PD -N --> CM -N --> RESYNC -PC --> MOC -PC --> STCP -PC --> MSG -CM --> MSG -STCP --> MOC -PD --> N -CFG --> N -CFG --> PC -CFG --> STCP -STATS --> N -STATS --> PC -P2P --> STATS -P2P --> RESYNC -P2P --> COLOR -SIMNET --> RESYNC -SYNCLOG --> N -SYNCLOG --> PC -GRAY --> SYNCLOG -FCDLOG --> SYNCLOG -``` - -**Diagram sources** -- [node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [core_messages.hpp:72-573](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L573) -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message_oriented_connection.hpp:45-79](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [config.hpp:26-106](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) -- [node.cpp:5281-5286](file://libraries/network/node.cpp#L5281-L5286) -- [node.cpp:346-347](file://libraries/network/node.cpp#L346-L347) - -**Section sources** -- [node.hpp:1-355](file://libraries/network/include/graphene/network/node.hpp#L1-L355) -- [peer_connection.hpp:1-383](file://libraries/network/include/graphene/network/peer_connection.hpp#L1-L383) -- [core_messages.hpp:1-573](file://libraries/network/include/graphene/network/core_messages.hpp#L1-L573) -- [stcp_socket.hpp:1-99](file://libraries/network/include/graphene/network/stcp_socket.hpp#L1-L99) -- [peer_database.hpp:1-141](file://libraries/network/include/graphene/network/peer_database.hpp#L1-L141) -- [message.hpp:1-114](file://libraries/network/include/graphene/network/message.hpp#L1-L114) -- [message_oriented_connection.hpp:1-85](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L1-L85) -- [config.hpp:1-106](file://libraries/network/include/graphene/network/config.hpp#L1-L106) -- [p2p_plugin.cpp:1-742](file://plugins/p2p/p2p_plugin.cpp#L1-L742) - -## Core Components -- Node: Central orchestrator for peer discovery, connection management, synchronization, and message broadcasting with virtual resync method support. -- PeerConnection: Manages individual peer sessions, message queuing, inventory tracking, and negotiation states with enhanced logging capabilities. -- CoreMessages: Defines standardized message types for transactions, blocks, inventory, handshake, and operational commands. -- STCP Socket: Provides secure transport via ECDH key exchange and AES encryption. -- PeerDatabase: Maintains peer address records, connection history, and topology hints. -- Message: Encapsulates message headers, payload serialization, and type-safe deserialization. -- MessageOrientedConnection: Bridges secure sockets to message streams with event callbacks. -- **Statistics System: Collects and reports peer performance metrics, latency data, and connection statistics with improved IP address extraction reliability.** -- **P2P Plugin: Integrates peer monitoring, statistics collection, and network diagnostics with enhanced error handling and color-coded logging.** -- **Programmatic Synchronization Control: Enables manual restart of synchronization with all connected peers for network recovery scenarios through virtual method extensibility.** -- **Enhanced Logging: Supports color-coded output for better visibility of network events and peer connection states.** -- **Enhanced Synchronization Logging: Provides systematic fc_dlog usage with CLOG_GRAY color coding for improved synchronization process visibility.** - -**Section sources** -- [node.hpp:182-304](file://libraries/network/include/graphene/network/node.hpp#L182-L304) -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [core_messages.hpp:72-573](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L573) -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [message_oriented_connection.hpp:45-79](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) - -## Architecture Overview -The network stack layers securely transport protocol messages between nodes. The Node coordinates peer discovery and synchronization, PeerConnection handles per-peer state and queues, CoreMessages defines the protocol, STCP Socket provides secure transport, and PeerDatabase maintains connectivity hints. - -```mermaid -sequenceDiagram -participant App as "Application" -participant Node as "node" -participant Peer as "peer_connection" -participant MOC as "message_oriented_connection" -participant STCP as "stcp_socket" -participant Stats as "Statistics System" -participant P2P as "p2p_plugin" -participant Net as "Remote Peer" -App->>Node : "connect_to_endpoint(ep)" -Node->>Peer : "create peer_connection" -Peer->>MOC : "connect_to(ep)" -MOC->>STCP : "connect_to(ep)" -STCP->>Net : "TCP connect" -STCP->>Net : "ECDH key exchange" -STCP-->>MOC : "shared secret" -MOC-->>Peer : "secure socket ready" -Peer->>Stats : "record latency metrics" -Peer->>Peer : "send hello_message" -Peer-->>Node : "on_message(hello)" -Node-->>Peer : "broadcast inventory" -Peer-->>App : "handle_block/handle_transaction" -P2P->>Stats : "collect peer statistics" -Stats->>P2P : "enhanced IP address extraction" -Note over Node,P2P : "Virtual resync method support" -P2P->>Node : "resync()" -Node->>Node : "start_synchronizing()" -Note over Node : "Enhanced sync logging with CLOG_GRAY" -``` - -**Diagram sources** -- [node.cpp:780-790](file://libraries/network/node.cpp#L780-L790) -- [peer_connection.cpp:208-242](file://libraries/network/peer_connection.cpp#L208-L242) -- [stcp_socket.cpp:69-72](file://libraries/network/stcp_socket.cpp#L69-L72) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) -- [node.cpp:5281-5286](file://libraries/network/node.cpp#L5281-L5286) - -## Detailed Component Analysis - -### Node Management (node.hpp, node.cpp) -The Node class is the central coordinator for peer discovery, connection orchestration, synchronization, and message broadcasting. It exposes APIs to: -- Configure listening endpoints and accept incoming connections -- Connect to seed nodes and maintain a peer pool -- Broadcast messages and synchronize with peers -- Track connection counts and network usage statistics -- Manage advanced parameters and peer advertising controls -- **Collect and report peer statistics and call performance metrics with improved IP address extraction** -- **Programmatic synchronization control through the virtual resync() method for extensible behavior** -- **Enhanced synchronization logging with systematic fc_dlog usage and CLOG_GRAY color coding** - -Key responsibilities: -- Peer pool management and connection limits -- Synchronization initiation and progress tracking -- Inventory advertisement and request routing -- Bandwidth monitoring and rate limiting -- Firewall detection and NAT traversal helpers -- **Statistics collection and reporting for network performance analysis with reliable peer information handling** -- **Programmatic synchronization restart for network recovery scenarios through virtual method override capability** -- **Comprehensive synchronization process logging with enhanced verbosity and color coding** - -```mermaid -classDiagram -class node { -+load_configuration(dir) -+listen_on_endpoint(ep, wait) -+accept_incoming_connections(bool) -+connect_to_endpoint(ep) -+listen_on_port(port, wait) -+get_actual_listening_endpoint() -+get_connected_peers() -+get_connection_count() -+broadcast(message) -+broadcast_transaction(trx) -+sync_from(item_id, hard_forks) -+set_total_bandwidth_limit(upload, download) -+network_get_info() -+network_get_usage_stats() -+get_potential_peers() -+disable_peer_advertising() -+get_call_statistics() -+resync() -} -class node_impl { --_active_connections --_handshaking_connections --_potential_peer_db --_tcp_server --_delegate --_rate_limiter -+p2p_network_connect_loop() -+fetch_sync_items_loop() -+fetch_items_loop() -+advertise_inventory_loop() -+bandwidth_monitor_loop() -+on_message(...) -+on_hello_message(...) -+on_connection_accepted_message(...) -+on_connection_rejected_message(...) -+on_address_request_message(...) -+on_address_message(...) -+on_fetch_blockchain_item_ids_message(...) -+on_blockchain_item_ids_inventory_message(...) -+on_fetch_items_message(...) -+on_item_not_available_message(...) -+on_item_ids_inventory_message(...) -+on_closing_connection_message(...) -+on_current_time_request_message(...) -+on_current_time_reply_message(...) -+on_check_firewall_message(...) -+on_check_firewall_reply_message(...) -+on_get_current_connections_request_message(...) -+on_get_current_connections_reply_message(...) -+on_connection_closed(...) -+get_call_statistics() -+start_synchronizing() -+resync() -} -class simulated_network { -+resync() override -} -node --> node_impl : "owns" -node <|-- simulated_network : "inherits" -``` - -**Diagram sources** -- [node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [node.cpp:424-799](file://libraries/network/node.cpp#L424-L799) -- [node.cpp:346-347](file://libraries/network/node.cpp#L346-L347) - -**Section sources** -- [node.hpp:182-304](file://libraries/network/include/graphene/network/node.hpp#L182-L304) -- [node.cpp:424-799](file://libraries/network/node.cpp#L424-L799) - -### Peer Connection (peer_connection.hpp, peer_connection.cpp) -PeerConnection encapsulates a single peer session, managing: -- Negotiation states (hello, accepted, rejected) -- Message queueing with real/virtual queued messages -- Inventory tracking and deduplication -- Request/response coordination -- Connection lifecycle (accept/connect/close/destroy) -- Rate limiting and throttling -- **Latency tracking and round-trip delay measurement** -- **Blocking status reporting and synchronization control** -- **Enhanced peer information handling with reliable IP address extraction** -- **Enhanced logging with color support for better visibility** - -```mermaid -stateDiagram-v2 -[*] --> Disconnected -Disconnected --> JustConnected : "connect_to()/accept()" -JustConnected --> ConnectionAccepted : "connection_accepted" -JustConnected --> ConnectionRejected : "connection_rejected" -ConnectionAccepted --> Connected : "negotiation_complete" -ConnectionRejected --> Closing : "close_connection()" -Connected --> Closing : "close_connection()" -Closing --> Closed : "on_connection_closed" -Closed --> [*] -``` - -**Diagram sources** -- [peer_connection.hpp:82-106](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) -- [peer_connection.cpp:169-206](file://libraries/network/peer_connection.cpp#L169-L206) - -Queueing and throttling: -- Real queued messages: full message payload copied -- Virtual queued messages: item_id only, generated on demand -- Size limits and backpressure to prevent memory pressure - -**Section sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp:41-66](file://libraries/network/peer_connection.cpp#L41-L66) -- [peer_connection.cpp:310-354](file://libraries/network/peer_connection.cpp#L310-L354) - -### Core Messages (core_messages.hpp, core_messages.cpp) -Standardized message types for the network protocol: -- Transactions and blocks -- Inventory announcements and requests -- Blockchain ID synchronization -- Handshake and connection control -- Time synchronization and firewall checks -- Current connections reporting -- **Address information with latency metrics and enhanced peer details** - -Message type enumeration and structures define the protocol contract. Serialization is handled by the message wrapper. - -```mermaid -classDiagram -class message { -+uint32_t size -+uint32_t msg_type -+std : : vector data -+message(T& obj) -+T as~T~() -+id() uint160 -} -class core_messages { -<> -trx_message_type -block_message_type -hello_message_type -connection_accepted_message_type -connection_rejected_message_type -item_ids_inventory_message_type -blockchain_item_ids_inventory_message_type -fetch_blockchain_item_ids_message_type -fetch_items_message_type -item_not_available_message_type -address_request_message_type -address_message_type -closing_connection_message_type -current_time_request_message_type -current_time_reply_message_type -check_firewall_message_type -check_firewall_reply_message_type -get_current_connections_request_message_type -get_current_connections_reply_message_type -} -message <.. core_messages : "serialized/deserialized" -``` - -**Diagram sources** -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [core_messages.hpp:72-573](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L573) -- [core_messages.cpp:30-49](file://libraries/network/core_messages.cpp#L30-L49) - -**Section sources** -- [core_messages.hpp:72-573](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L573) -- [core_messages.cpp:30-49](file://libraries/network/core_messages.cpp#L30-L49) -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) - -### Secure TCP Socket (stcp_socket.hpp, stcp_socket.cpp) -Provides secure transport using ECDH key exchange and AES encryption: -- Generates ephemeral keys and performs key exchange -- Initializes AES encoder/decoder with derived shared secret -- Enforces block-aligned reads/writes for cipher integrity -- Exposes secure read/write primitives - -```mermaid -flowchart TD -Start(["Connect/Accept"]) --> GenKey["Generate ephemeral keypair"] -GenKey --> Exchange["Exchange serialized public keys"] -Exchange --> Derive["Derive shared secret via ECDH"] -Derive --> InitAES["Initialize AES encoder/decoder"] -InitAES --> Ready["Secure socket ready"] -Ready --> ReadWrite["Encrypt/decrypt reads/writes"] -ReadWrite --> Close["Close socket"] -``` - -**Diagram sources** -- [stcp_socket.cpp:49-72](file://libraries/network/stcp_socket.cpp#L49-L72) -- [stcp_socket.cpp:132-177](file://libraries/network/stcp_socket.cpp#L132-L177) - -**Section sources** -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp:49-177](file://libraries/network/stcp_socket.cpp#L49-L177) - -### Peer Database (peer_database.hpp, peer_database.cpp) -Maintains persistent records of potential peers: -- Endpoint, last seen time, and disposition tracking -- Connection attempt counters and failure reasons -- Iteration over entries sorted by last seen time -- JSON-backed persistence with pruning - -```mermaid -classDiagram -class peer_database { -+open(path) -+close() -+clear() -+erase(endpoint) -+update_entry(record) -+lookup_or_create_entry_for_endpoint(endpoint) -+lookup_entry_for_endpoint(endpoint) -+begin() -+end() -+size() -} -class potential_peer_record { -+endpoint -+last_seen_time -+last_connection_disposition -+last_connection_attempt_time -+number_of_successful_connection_attempts -+number_of_failed_connection_attempts -+last_error -} -peer_database --> potential_peer_record : "stores" -``` - -**Diagram sources** -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [peer_database.cpp:41-82](file://libraries/network/peer_database.cpp#L41-L82) - -**Section sources** -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) - -### Message Serialization (message.hpp) -Defines the message envelope and serialization: -- Header with size and type -- Payload storage and hashing -- Template-based pack/unpack for protocol messages -- Type safety and runtime checks - -```mermaid -flowchart TD -Pack["Pack T -> raw::pack"] --> Header["Set size/msg_type"] -Header --> Serialize["Store in data vector"] -Serialize --> Message["message object"] -Message --> As["as()"] -As --> Verify["Verify msg_type"] -Verify --> Unpack["raw::unpack to T"] -Unpack --> Result["Return T"] -``` - -**Diagram sources** -- [message.hpp:70-105](file://libraries/network/include/graphene/network/message.hpp#L70-L105) - -**Section sources** -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) - -## Peer Statistics and Metrics System - -**Updated** The network library now includes a comprehensive peer statistics logging system that provides detailed insights into peer performance and network health with improved IP address extraction reliability. - -### Latency Tracking System -The system tracks round-trip delay and clock offset for each peer connection: - -- **Round Trip Delay**: Measures the time for a message to travel to a peer and back -- **Clock Offset**: Calculates time difference between local and remote peer clocks -- **Latency Reporting**: Exposes peer latency in milliseconds for monitoring and selection - -```mermaid -flowchart TD -Start(["Time Synchronization Request"]) --> SendReq["Send current_time_request_message"] -SendReq --> WaitResp["Wait for reply"] -WaitResp --> CalcDelay["Calculate round_trip_delay"] -CalcDelay --> CalcOffset["Calculate clock_offset"] -CalcOffset --> Report["Report to peer_status"] -Report --> Monitor["Monitor peer performance"] -``` - -**Diagram sources** -- [node.cpp:3710-3723](file://libraries/network/node.cpp#L3710-L3723) - -### Blocking Status Reporting -The system monitors and reports peer blocking conditions that affect synchronization: - -- **Inhibit Fetching Sync Blocks**: Tracks peers that are temporarily blocked from receiving sync data -- **Soft Ban Mechanism**: Implements temporary blocking for peers on losing forks during emergency consensus -- **Blocking Reasons**: Reports specific reasons for peer blocking (fork rejection, etc.) - -### Enhanced Peer Information Reporting -The peer information system now includes comprehensive metrics with improved reliability: - -- **Latency Metrics**: `latency_ms` field showing round-trip delay in milliseconds -- **Blocking Status**: `is_blocked` boolean indicating if peer is currently blocked -- **Blocking Reason**: `blocked_reason` field explaining why peer is blocked -- **Connection Quality**: Firewall status, connection duration, and bandwidth metrics -- **Peer Capabilities**: Platform information, version details, and feature support -- **IP Address Extraction**: Reliable extraction with fallback handling for unknown addresses - -### Periodic Statistics Collection -The system implements continuous statistics collection: - -- **Call Statistics**: Tracks method execution times, delays, and performance metrics -- **Network Usage**: Monitors upload/download rates over various time periods -- **Performance Monitoring**: Collects rolling averages for bandwidth utilization -- **Delegate Thread Coordination**: Measures delays between P2P thread and delegate thread execution - -### Statistics Collection Classes - -```mermaid -classDiagram -class call_statistics_collector { -+time_point call_requested_time -+time_point begin_execution_time -+time_point execution_completed_time -+const char* method_name -+execute() -+starting_execution() -+execution_completed() -} -class statistics_gathering_node_delegate_wrapper { -+node_delegate* delegate -+call_stats_accumulator* execution_accumulator -+call_stats_accumulator* delay_before_accumulator -+call_stats_accumulator* delay_after_accumulator -+get_call_statistics() -} -call_statistics_collector --> statistics_gathering_node_delegate_wrapper : "collects" -``` - -**Diagram sources** -- [node.cpp:312-381](file://libraries/network/node.cpp#L312-L381) -- [node.cpp:383-420](file://libraries/network/node.cpp#L383-L420) - -**Section sources** -- [node.hpp:173-179](file://libraries/network/include/graphene/network/node.hpp#L173-L179) -- [node.cpp:4920-4970](file://libraries/network/node.cpp#L4920-L4970) -- [node.cpp:312-381](file://libraries/network/node.cpp#L312-L381) -- [node.cpp:5128-5131](file://libraries/network/node.cpp#L5128-L5131) -- [core_messages.hpp:322-346](file://libraries/network/include/graphene/network/core_messages.hpp#L322-L346) -- [core_messages.hpp:428-448](file://libraries/network/include/graphene/network/core_messages.hpp#L428-L448) - -## Peer Information Handling and IP Extraction - -**Updated** Critical bug fix implemented in peer information handling that improves IP address extraction reliability and reduces potential conversion overhead in the P2P networking layer. - -### Improved IP Address Extraction Reliability -The system now features enhanced IP address extraction with comprehensive error handling: - -- **Safe IP Address Retrieval**: Uses `static_cast(peer_info.host.get_address())` for reliable address extraction -- **Fallback Error Handling**: Implements try-catch block to handle extraction failures gracefully -- **Default Value Provision**: Sets IP to "(unknown)" when extraction fails, preventing crashes -- **Port Extraction**: Direct port extraction using `peer_info.host.port()` with proper type casting -- **Address Key Generation**: Creates reliable `addr_key = ip + ":" + std::to_string(port)` for peer identification - -### Reduced Conversion Overhead -The new implementation minimizes conversion overhead through: - -- **Direct String Casting**: Uses `static_cast()` for immediate conversion without intermediate steps -- **Efficient Port Handling**: Direct port extraction avoids unnecessary string conversions -- **Optimized Address Key Creation**: Single-line address key generation reduces computational overhead -- **Minimal Memory Allocation**: Reduces temporary string allocations during peer information processing - -### Enhanced Peer Statistics Processing -The P2P plugin now processes peer statistics with improved reliability: - -- **Latency Metrics Collection**: Extracts `latency_ms` with proper integer conversion -- **Bytes Received Tracking**: Processes `bytesrecv` with unsigned integer handling -- **Blocking Status Monitoring**: Handles `is_blocked` boolean values reliably -- **Reason Analysis**: Captures `blocked_reason` strings for diagnostic purposes -- **Delta Calculation**: Computes byte delta with overflow protection - -```mermaid -flowchart TD -Start(["Peer Information Processing"]) --> ExtractIP["Extract IP address safely"] -ExtractIP --> TryCatch{"Try-Catch Block"} -TryCatch --> |Success| ValidIP["Use extracted IP"] -TryCatch --> |Failure| DefaultIP["Set IP to '(unknown)'"] -ValidIP --> ExtractPort["Extract port"] -DefaultIP --> ExtractPort -ExtractPort --> CreateKey["Create addr_key"] -CreateKey --> ProcessMetrics["Process latency, bytes, blocking"] -ProcessMetrics --> CalculateDelta["Calculate byte delta"] -CalculateDelta --> LogStats["Log peer statistics"] -``` - -**Diagram sources** -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) -- [node.cpp:4900-4970](file://libraries/network/node.cpp#L4900-L4970) - -### Peer Information Data Flow -The enhanced system processes peer information through a structured pipeline: - -1. **Endpoint Extraction**: Safely extracts peer endpoint with error handling -2. **Metric Collection**: Gathers latency, bytes received, blocking status, and reasons -3. **Delta Computation**: Calculates byte transfer differences with overflow protection -4. **Statistics Logging**: Outputs comprehensive peer statistics with improved reliability - -**Section sources** -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) -- [node.cpp:4900-4970](file://libraries/network/node.cpp#L4900-L4970) - -## Programmatic Synchronization Control - -**Updated Section** The network library now provides programmatic control over synchronization through the virtual `resync()` method, enabling manual restart of synchronization with all connected peers and supporting extensible behavior in derived classes. - -### Virtual Resync Method Implementation -The `resync()` method provides a clean interface for forcing synchronization restart with enhanced extensibility: - -- **Method Purpose**: Restarts synchronization with all currently connected peers -- **Virtual Design**: Declared as virtual in the base `node` class, allowing derived classes to override behavior -- **Implementation**: Calls `start_synchronizing()` which iterates through all active connections -- **Logging**: Emits detailed log messages showing the number of connected peers being restarted -- **Thread Safety**: Verified to run on the correct thread using `VERIFY_CORRECT_THREAD()` - -### Enhanced Extensibility for Derived Classes -The virtual nature of `resync()` allows for specialized behavior in derived classes: - -- **Base Class Behavior**: Default implementation restarts synchronization with all active peers -- **Simulated Network Override**: `simulated_network` class provides empty implementation for testing -- **Custom Implementations**: Derived classes can override `resync()` to implement custom restart logic -- **Consistent Interface**: All implementations follow the same virtual method contract - -### Synchronization Restart Process -When `resync()` is called, the following sequence occurs: - -1. **Connection Enumeration**: Iterates through all currently active peer connections -2. **Individual Restart**: Calls `start_synchronizing_with_peer()` for each connected peer -3. **State Reset**: Forces peers to re-establish synchronization state -4. **Inventory Refresh**: Peers re-advertise their inventory and synchronization status - -```mermaid -flowchart TD -Start(["resync() Called"]) --> CheckActive["Check Active Connections"] -CheckActive --> LoopPeers{"More Peers?"} -LoopPeers --> |Yes| StartPeer["start_synchronizing_with_peer(peer)"] -StartPeer --> LoopPeers -LoopPeers --> |No| LogMsg["Log restart message"] -LogMsg --> Complete["Resync Complete"] -``` - -**Diagram sources** -- [node.cpp:5281-5286](file://libraries/network/node.cpp#L5281-L5286) -- [node.cpp:4164-4168](file://libraries/network/node.cpp#L4164-L4168) - -### Integration with P2P Plugin -The P2P plugin utilizes the `resync()` method for automatic network recovery: - -- **Stale Sync Detection**: Monitors for periods without block reception -- **Automatic Recovery**: When stale sync is detected, calls `resync()` to restart synchronization -- **Seed Reconnection**: Reconnects to seed nodes after resync to ensure continued connectivity -- **Configuration Options**: Controlled by `p2p-stale-sync-detection` and `p2p-stale-sync-timeout-seconds` options - -### Use Cases for Programmatic Resync -The `resync()` method is particularly useful for: - -- **Network Recovery**: Recovering from partial synchronization failures -- **Manual Intervention**: Operator-driven restart of synchronization -- **Debugging**: Clearing stuck synchronization states during development -- **Network State Changes**: Adapting to significant network topology changes -- **Testing Scenarios**: Simulated network testing with controlled synchronization restarts - -**Section sources** -- [node.hpp:298-304](file://libraries/network/include/graphene/network/node.hpp#L298-L304) -- [node.cpp:5281-5286](file://libraries/network/node.cpp#L5281-L5286) -- [node.cpp:4164-4168](file://libraries/network/node.cpp#L4164-L4168) -- [p2p_plugin.cpp:616-618](file://plugins/p2p/p2p_plugin.cpp#L616-L618) -- [node.cpp:346-347](file://libraries/network/node.cpp#L346-L347) - -## Enhanced Peer Connection Logging - -**Updated Section** The network library now supports enhanced peer connection logging with color-coded output for improved visibility and debugging capabilities. - -### Color Logging Support -The P2P plugin implements ANSI color codes for enhanced console logging: - -- **Cyan Color**: Used for general statistics and informational messages -- **White Color**: Used for detailed block processing information with latency metrics -- **Reset Code**: Returns to default terminal color after colored output -- **ANSI Escape Sequences**: Standard color codes supported by most terminals - -### Color-Coded Log Messages -The logging system provides visual distinction for different types of network events: - -- **Block Processing Messages**: White color for detailed block information and transaction counts -- **Statistics Messages**: Cyan color for periodic statistics and peer monitoring information -- **Error Messages**: Red color for critical errors and warnings (when applicable) -- **Debug Messages**: Orange color for detailed debugging information - -### Logging Implementation Details -The color logging is implemented using preprocessor macros: - -- **CLOG_CYAN**: ANSI escape sequence for cyan text -- **CLOG_WHITE**: ANSI escape sequence for white text -- **CLOG_RESET**: ANSI escape sequence to reset text color -- **Macro Usage**: Color codes are embedded directly in log message strings - -### Benefits of Color Logging -The enhanced logging system provides several advantages: - -- **Visual Distinction**: Different types of messages are easily distinguishable by color -- **Improved Debugging**: Color coding helps identify message categories quickly -- **Better Console Reading**: Color contrast makes log output more readable -- **Operator Efficiency**: Faster identification of important information during monitoring - -**Section sources** -- [p2p_plugin.cpp:16-19](file://plugins/p2p/p2p_plugin.cpp#L16-L19) -- [p2p_plugin.cpp:169-171](file://plugins/p2p/p2p_plugin.cpp#L169-L171) - -## Enhanced Synchronization Logging System - -**Updated Section** The network library now features an enhanced synchronization logging system with new CLOG_GRAY ANSI color code and systematic replacement of fc_ilog with fc_dlog throughout the sync process for improved log verbosity and clarity. - -### CLOG_GRAY ANSI Color Code Implementation -The synchronization system introduces a new ANSI color code specifically for gray-colored log output: - -- **CLOG_GRAY Definition**: `#define CLOG_GRAY "\033[90m"` for dark gray text color -- **CLOG_RESET Definition**: `#define CLOG_RESET "\033[0m"` for resetting text color -- **ANSI Escape Sequences**: Standard color codes compatible with most modern terminals -- **Usage Pattern**: Embedded within log messages to provide visual hierarchy - -### Systematic fc_dlog Usage Patterns -The synchronization system has undergone systematic replacement of fc_ilog with fc_dlog for enhanced logging verbosity: - -#### Fetch Synchronization Items Loop -- **Enhanced Item Status Logging**: Uses fc_dlog with CLOG_GRAY for detailed item availability status -- **Peer Condition Monitoring**: Logs peer inhibition status and idle conditions with color coding -- **Request Volume Tracking**: Monitors and logs the number of peers actively requesting blocks - -#### Blockchain Item Inventory Handling -- **Comprehensive Response Logging**: Uses fc_dlog with CLOG_GRAY for detailed inventory response analysis -- **Block Range Information**: Logs block number ranges and remaining item counts with color coding -- **Validation Diagnostics**: Enhanced logging of validation results and error conditions - -#### Sync Status Updates -- **Progress Tracking**: Uses fc_dlog for detailed synchronization progress updates -- **Peer Communication**: Logs peer-specific synchronization status with color coding -- **Resource Management**: Monitors and logs resource allocation during synchronization - -#### Sync Start Procedures -- **Initialization Logging**: Uses fc_dlog for comprehensive startup procedure logging -- **Configuration Validation**: Logs configuration validation results with detailed status -- **Resource Preparation**: Monitors and logs resource preparation for synchronization - -### Enhanced Logging Verbosity -The new logging system provides significantly improved verbosity: - -- **Detailed Peer Analysis**: Comprehensive logging of peer conditions and capabilities -- **Item Tracking**: Enhanced tracking and logging of synchronization items -- **Performance Metrics**: Detailed logging of performance metrics and optimization opportunities -- **Error Diagnostics**: Enhanced error logging with contextual information - -### Color-Coded Log Categories -The synchronization logging system categorizes information using color coding: - -- **Gray Text (CLOG_GRAY)**: Background synchronization processes and status updates -- **Green Text**: Successful operations and positive outcomes -- **Yellow Text**: Warning conditions and potential issues -- **Red Text**: Critical errors and failure conditions -- **Blue Text**: Debug information and detailed technical data - -### Benefits of Enhanced Synchronization Logging -The new logging system provides several advantages: - -- **Improved Visibility**: Color coding makes synchronization processes easier to understand -- **Better Debugging**: Enhanced verbosity helps identify synchronization issues quickly -- **Performance Monitoring**: Detailed logging enables performance optimization -- **Operator Efficiency**: Clear visual hierarchy helps operators monitor network health -- **Troubleshooting Support**: Comprehensive logging aids in diagnosing complex synchronization issues - -**Section sources** -- [node.cpp:81-81](file://libraries/network/node.cpp#L81-L81) -- [node.cpp:1187-1194](file://libraries/network/node.cpp#L1187-L1194) -- [node.cpp:1200-1202](file://libraries/network/node.cpp#L1200-L1202) -- [node.cpp:2651-2663](file://libraries/network/node.cpp#L2651-L2663) -- [node.cpp:2772-2779](file://libraries/network/node.cpp#L2772-L2779) -- [node.cpp:2790-2796](file://libraries/network/node.cpp#L2790-L2796) - -## Dependency Analysis -The network components depend on each other in a layered fashion: -- Node depends on PeerConnection, PeerDatabase, and CoreMessages -- PeerConnection depends on MessageOrientedConnection and STCP Socket -- MessageOrientedConnection depends on STCP Socket and Message -- CoreMessages depends on Protocol types and Message -- Config constants drive behavior across components -- **Statistics system integrates with Node and PeerConnection for metrics collection** -- **P2P plugin integrates with statistics system for enhanced peer monitoring** -- **Resync functionality integrates with Node synchronization system and supports virtual method extensibility** -- **Color logging integrates with P2P plugin for enhanced console output visualization** -- **Enhanced synchronization logging integrates with Node synchronization system and uses CLOG_GRAY color coding** -- **Systematic fc_dlog usage integrates throughout sync process for improved logging verbosity** - -```mermaid -graph LR -Node["node.hpp/.cpp"] --> PeerConn["peer_connection.hpp/.cpp"] -Node --> PeerDB["peer_database.hpp/.cpp"] -Node --> CoreMsg["core_messages.hpp/.cpp"] -Node --> Resync["Virtual resync() Method"] -PeerConn --> Msg["message.hpp"] -PeerConn --> MOC["message_oriented_connection.hpp"] -PeerConn --> STCP["stcp_socket.hpp/.cpp"] -CoreMsg --> Msg -STCP --> MOC -Node --> Cfg["config.hpp"] -PeerConn --> Cfg -STCP --> Cfg -Stats["Statistics System"] --> Node -Stats --> PeerConn -P2P["p2p_plugin.cpp"] --> Stats -P2P --> Resync -P2P --> Color["Color Logging"] -SimNet["simulated_network"] --> Resync -SyncLog["Enhanced Synchronization Logging"] --> Node -SyncLog --> PeerConn -Gray["CLOG_GRAY Color Code"] --> SyncLog -FCDLog["fc_dlog Usage Patterns"] --> SyncLog -``` - -**Diagram sources** -- [node.hpp:26-28](file://libraries/network/include/graphene/network/node.hpp#L26-L28) -- [peer_connection.hpp:26-29](file://libraries/network/include/graphene/network/peer_connection.hpp#L26-L29) -- [core_messages.hpp:26-28](file://libraries/network/include/graphene/network/core_messages.hpp#L26-L28) -- [stcp_socket.hpp:26-28](file://libraries/network/include/graphene/network/stcp_socket.hpp#L26-L28) -- [message_oriented_connection.hpp:26-27](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L26-L27) -- [config.hpp:26-106](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) - -**Section sources** -- [node.hpp:26-28](file://libraries/network/include/graphene/network/node.hpp#L26-L28) -- [peer_connection.hpp:26-29](file://libraries/network/include/graphene/network/peer_connection.hpp#L26-L29) -- [core_messages.hpp:26-28](file://libraries/network/include/graphene/network/core_messages.hpp#L26-L28) -- [stcp_socket.hpp:26-28](file://libraries/network/include/graphene/network/stcp_socket.hpp#L26-L28) -- [message_oriented_connection.hpp:26-27](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L26-L27) -- [config.hpp:26-106](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) - -## Performance Considerations -- Connection limits: Desired and maximum connections are configurable to balance throughput and resource usage. -- Queueing: Per-peer message queue enforces a maximum size to prevent memory pressure. -- Inventory limits: Caps on advertised inventory prevent flooding and ensure timely block propagation. -- Prefetching: Interleaved fetching of IDs and items reduces latency during synchronization. -- Rate limiting: Bandwidth monitor tracks read/write rates and applies limits. -- Throttling: Transaction fetching can be inhibited during heavy load to prioritize block sync. -- **Statistics overhead**: Metrics collection adds minimal overhead while providing valuable performance insights. -- **Latency monitoring**: Round-trip delay tracking helps identify slow or problematic peers for connection optimization. -- **IP extraction efficiency**: Improved IP address extraction reduces CPU overhead and prevents crashes from malformed addresses. -- **Error handling**: Comprehensive try-catch blocks prevent cascading failures in peer information processing. -- **Resync efficiency**: Programmatic resync restarts only active connections, minimizing disruption to healthy peers. -- **Virtual method overhead**: Virtual dispatch adds minimal overhead while providing extensibility benefits. -- **Color logging overhead**: ANSI color codes add minimal overhead while significantly improving log readability. -- **Enhanced sync logging overhead**: New CLOG_GRAY color coding and fc_dlog usage adds minimal overhead while dramatically improving synchronization visibility. -- **Logging verbosity optimization**: Systematic fc_dlog usage provides better performance than fc_ilog in debug mode. - -## Troubleshooting Guide -Common issues and diagnostics: -- Connection failures: Review peer database entries and last connection dispositions. -- Handshake errors: Validate protocol version and chain ID mismatches. -- Message deserialization errors: Ensure message types match and payloads are intact. -- Memory pressure: Monitor queue sizes and reduce advertised inventory. -- Time synchronization: Use current time request/reply messages to detect clock skew. -- **Latency issues**: Monitor `latency_ms` field to identify slow peers affecting synchronization. -- **Blocking peers**: Check `is_blocked` and `blocked_reason` fields to diagnose synchronization problems. -- **Performance bottlenecks**: Use call statistics to identify slow methods and optimize performance. -- **IP extraction failures**: Monitor for "(unknown)" IP addresses indicating extraction errors. -- **Statistics logging issues**: Verify P2P plugin configuration for statistics collection. -- **Synchronization stalls**: Use `resync()` method to manually restart synchronization with all peers. -- **Virtual method conflicts**: Ensure derived classes properly override `resync()` when extending functionality. -- **Color logging issues**: Verify terminal supports ANSI color codes for proper log output formatting. -- **Enhanced sync logging issues**: Verify CLOG_GRAY color code compatibility and fc_dlog macro definitions. -- **Logging verbosity problems**: Check debug level configuration for fc_dlog vs fc_ilog usage patterns. - -Operational controls: -- Disable peer advertising for debugging isolated networks. -- Adjust bandwidth limits to stabilize performance under load. -- Inspect call statistics and connection counts for bottlenecks. -- **Monitor peer metrics**: Regularly review latency and blocking status for network health assessment. -- **Enable statistics logging**: Use `p2p-stats-enabled` option to activate peer monitoring. -- **Configure logging intervals**: Set appropriate `p2p-stats-interval` for desired monitoring frequency. -- **Configure stale sync detection**: Enable `p2p-stale-sync-detection` to automatically recover from stalled synchronization. -- **Manual resync control**: Use `resync()` method for operator-driven synchronization restarts. -- **Extensibility patterns**: Leverage virtual method design for custom synchronization behaviors in derived classes. -- **Color logging configuration**: Ensure terminal supports ANSI color codes for optimal log visualization. -- **Enhanced sync logging configuration**: Verify CLOG_GRAY color code and fc_dlog usage patterns are properly configured. -- **Logging verbosity tuning**: Adjust debug level settings to control fc_dlog vs fc_ilog logging intensity. - -**Section sources** -- [peer_database.hpp:39-45](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L45) -- [node.hpp:288-298](file://libraries/network/include/graphene/network/node.hpp#L288-L298) -- [message.hpp:85-105](file://libraries/network/include/graphene/network/message.hpp#L85-L105) -- [node.cpp:4920-4970](file://libraries/network/node.cpp#L4920-L4970) -- [p2p_plugin.cpp:500-560](file://plugins/p2p/p2p_plugin.cpp#L500-L560) - -## Conclusion -The Network Library provides a comprehensive, secure, and scalable foundation for peer-to-peer communication. Its modular design separates concerns between node orchestration, peer lifecycle management, protocol messaging, secure transport, and peer topology maintenance. With built-in performance controls, diagnostic capabilities, and extensible message types, it supports efficient blockchain synchronization and robust network operation. - -**Updated** The enhanced peer statistics logging system significantly improves network observability by providing detailed latency tracking, blocking status reporting, and comprehensive peer metrics. The critical bug fix in peer information handling ensures reliable IP address extraction with reduced conversion overhead, preventing crashes and improving overall network stability. The integration with the P2P plugin provides comprehensive monitoring capabilities for operators and developers working with the VIZ blockchain network. The new virtual `resync()` method adds powerful programmatic control for network recovery, enabling manual restart of synchronization with all connected peers and improved resilience against various network states and synchronization failures. The virtual method design provides extensibility for derived classes to customize synchronization behavior while maintaining a consistent interface across the network library ecosystem. The enhanced peer connection logging with color support significantly improves the debugging and monitoring experience by providing visual distinction for different types of network events and messages. **The new enhanced synchronization logging system with CLOG_GRAY ANSI color code and systematic fc_dlog usage dramatically improves synchronization process visibility, providing detailed insights into peer conditions, item availability, and synchronization progress while maintaining minimal performance overhead.** \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Node Management.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Node Management.md deleted file mode 100644 index c207aabdbd..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Node Management.md +++ /dev/null @@ -1,756 +0,0 @@ -# Node Management - - -**Referenced Files in This Document** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced peer connection lifecycle management with improved disconnection flow and proper cleanup from _active_connections -- Implemented delayed peer deletion mechanism to prevent peers from staying in _active_connections indefinitely -- Improved remaining_item_count calculation in blockchain item ID requests -- Enhanced inventory deduplication logic with better tracking of items already advertised or requested -- Strengthened disconnect list management with proper peer state transitions - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Peer Connection Lifecycle Management](#enhanced-peer-connection-lifecycle-management) -7. [Improved Disconnection Flow and Cleanup](#improved-disconnection-flow-and-cleanup) -8. [Enhanced Inventory Management and Deduplication](#enhanced-inventory-management-and-deduplication) -9. [Advanced Peer State Management](#advanced-peer-state-management) -10. [Performance Considerations](#performance-considerations) -11. [Troubleshooting Guide](#troubleshooting-guide) -12. [Conclusion](#conclusion) - -## Introduction -This document describes the Node Management component responsible for orchestrating network peers, maintaining connectivity, and managing blockchain synchronization in the P2P layer. It covers the node.hpp class interface, the node_delegate integration for blockchain callbacks, configuration and lifecycle APIs, peer management, and network broadcasting with inventory tracking. The documentation now includes comprehensive coverage of enhanced peer connection lifecycle management, improved disconnection flows, enhanced inventory deduplication, and advanced peer state management systems. - -## Project Structure -The Node Management functionality spans several headers and the implementation source file: -- Public interface: node.hpp defines the node class, node_delegate interface, and related types. -- Implementation: node.cpp implements the node lifecycle, peer orchestration, message routing, synchronization, and inventory management with enhanced connection lifecycle handling. -- Peer model: peer_connection.hpp/cpp defines the peer connection abstraction and state machine with comprehensive connection state management. -- Persistence: peer_database.hpp provides persistent peer discovery records. -- Messaging: message.hpp defines the generic message envelope; core_messages.hpp enumerates core P2P message types. -- Networking primitives: stcp_socket.hpp and message_oriented_connection.hpp underpin transport and framing. -- Emergency consensus: fork_database.hpp/cpp and database.cpp implement emergency mode functionality. - -```mermaid -graph TB -subgraph "Network Layer" -N["node.hpp
Public API"] -NI["node.cpp
Enhanced Implementation
with Lifecycle Management
Delayed Deletion
Improved Deduplication"] -PC["peer_connection.hpp
Enhanced Peer Abstraction
with State Management
Connection Lifecycle"] -PCC["peer_connection.cpp
Connection State Transitions
Inventory Management"] -PD["peer_database.hpp
Persistent Peers"] -MSG["message.hpp
Message Envelope"] -CM["core_messages.hpp
Core Message Types"] -end -subgraph "Transport" -STCP["stcp_socket.hpp"] -MOC["message_oriented_connection.hpp"] -end -subgraph "Emergency Consensus" -FD["fork_database.hpp
Emergency Mode"] -DBC["database.cpp
Consensus Logic"] -CFG["config.hpp
Emergency Constants"] -end -subgraph "DLT Mode Support" -DLP["dlt_block_log.cpp
DLT Block Log"] -P2P["p2p_plugin.cpp
Enhanced Error Logging"] -end -N --> NI -NI --> PC -NI --> PCC -NI --> PD -NI --> MSG -NI --> CM -PC --> STCP -PC --> MOC -NI --> FD -FD --> DBC -DBC --> CFG -NI --> DLP -NI --> P2P -``` - -**Diagram sources** -- [node.hpp:180-355](file://libraries/network/include/graphene/network/node.hpp#L180-L355) -- [node.cpp:869-905](file://libraries/network/node.cpp#L869-L905) -- [peer_connection.hpp:79-354](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L354) -- [peer_connection.cpp:419-448](file://libraries/network/peer_connection.cpp#L419-L448) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message.hpp:42-114](file://libraries/network/include/graphene/network/message.hpp#L42-L114) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [fork_database.hpp:111-120](file://libraries/chain/include/graphene/chain/fork_database.hpp#L111-L120) -- [database.cpp:4334-4463](file://libraries/chain/database.cpp#L4334-L4463) -- [config.hpp:110-123](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L123) -- [dlt_block_log.cpp:368-379](file://libraries/chain/dlt_block_log.cpp#L368-L379) -- [p2p_plugin.cpp:330-360](file://plugins/p2p/p2p_plugin.cpp#L330-L360) - -**Section sources** -- [node.hpp:180-355](file://libraries/network/include/graphene/network/node.hpp#L180-L355) -- [node.cpp:869-905](file://libraries/network/node.cpp#L869-L905) - -## Core Components -- node class: Provides P2P orchestration, configuration, peer management, and broadcast APIs with comprehensive connection lifecycle management and enhanced cleanup mechanisms. -- node_delegate interface: Bridges the P2P layer to the blockchain, handling block ingestion, transaction processing, and sync callbacks with enhanced status reporting. -- peer_connection: Encapsulates a single peer link with state machine, inventory tracking, rate-limited messaging, emergency consensus support, and comprehensive connection state management with proper cleanup. -- peer_database: Persistent store of potential peers with connection history and disposition. -- message: Generic envelope for all P2P messages with hashing and typed serialization. -- fork_database: Manages blockchain forks with emergency consensus mode support and deterministic tie-breaking. - -Key responsibilities: -- Lifecycle: Construction, configuration loading, listener setup, and graceful shutdown with detailed logging and proper cleanup. -- Peer orchestration: Connecting to configured seeds, accepting inbound connections, pruning inactive peers, and enforcing connection limits with enhanced state management. -- Synchronization: Requesting and processing blockchain item IDs, fetching blocks/transactions, and notifying the delegate with enhanced progress tracking. -- Broadcasting: Advertising inventory and sending items to peers with detailed synchronization metrics and improved deduplication. -- Inventory management: Tracking what peers have, what we need, and what we've recently processed with enhanced deduplication logic. -- Emergency consensus: Managing soft-bans, automatic flag resets, and emergency mode operations with enhanced diagnostics. -- Advanced peer state management: Comprehensive connection state transitions, proper cleanup from all connection sets, and delayed deletion mechanisms. -- Enhanced connection lifecycle: Prevention of peers staying in _active_connections indefinitely through proper state transitions and cleanup. -- Improved disconnection flow: Better disconnect list management with proper peer state transitions and cleanup. -- Enhanced inventory deduplication: More sophisticated tracking of items already advertised, requested, or being processed. -- Intelligent peer handling: Differentiating between stale fork peers and legitimate sync candidates to prevent infinite loops. -- DLT mode support: Enhanced error logging with comprehensive block range information for distributed ledger technology mode. -- Comprehensive logging: Detailed peer synchronization progress, item counts, block ranges, and timing information for better debugging and monitoring. - -**Section sources** -- [node.hpp:180-355](file://libraries/network/include/graphene/network/node.hpp#L180-L355) -- [node.cpp:869-905](file://libraries/network/node.cpp#L869-L905) -- [peer_connection.hpp:79-354](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L354) -- [peer_connection.cpp:419-448](file://libraries/network/peer_connection.cpp#L419-L448) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message.hpp:42-114](file://libraries/network/include/graphene/network/message.hpp#L42-L114) -- [fork_database.hpp:111-120](file://libraries/chain/include/graphene/chain/fork_database.hpp#L111-L120) - -## Architecture Overview -The node delegates blockchain integration to a node_delegate and coordinates peers via peer_connection instances with enhanced lifecycle management. The node maintains separate queues for sync and normal operation, enforces bandwidth and connection limits, and periodically prunes stale peers. The enhanced peer handling system provides network-level resilience through intelligent soft-ban mechanisms, automatic flag resets, and deterministic tie-breaking to prevent cascading failures and infinite sync loops. The comprehensive logging system provides detailed peer synchronization progress, item counts, block ranges, and timing information for better debugging and monitoring capabilities. - -```mermaid -classDiagram -class node { -+load_configuration(dir) -+listen_to_p2p_network() -+connect_to_p2p_network() -+add_node(endpoint) -+connect_to_endpoint(endpoint) -+listen_on_endpoint(ep, wait) -+accept_incoming_connections(flag) -+listen_on_port(port, wait) -+get_actual_listening_endpoint() -+get_connected_peers() -+get_connection_count() -+broadcast(message) -+broadcast_transaction(trx) -+sync_from(item_id, hard_fork_nums) -+is_connected() -+set_advanced_node_parameters(variant) -+get_advanced_node_parameters() -+get_transaction_propagation_data(tx_id) -+get_block_propagation_data(block_id) -+get_node_id() -+set_allowed_peers(ids) -+clear_peer_database() -+set_total_bandwidth_limit(up, down) -+network_get_info() -+network_get_usage_stats() -+get_potential_peers() -+disable_peer_advertising() -+get_call_statistics() -} -class node_delegate { -+has_item(id) bool -+handle_block(blk_msg, sync_mode, contained_txs) bool -+handle_transaction(trx_msg) -+handle_message(msg) -+get_block_ids(synopsis, out_remaining, limit) vector -+get_item(id) message -+get_blockchain_synopsis(ref_point, num_after) vector -+sync_status(item_type, count) -+connection_count_changed(count) -+get_block_number(id) uint32 -+get_block_time(id) time_point_sec -+get_blockchain_now() time_point_sec -+get_head_block_id() item_hash_t -+estimate_last_known_fork_from_git_revision_timestamp(ts) uint32 -+error_encountered(msg, err) -} -class peer_connection { -+accept_connection() -+connect_to(endpoint, local_ep) -+send_message(msg) -+send_item(item_id) -+close_connection() -+destroy_connection() -+busy() bool -+idle() bool -+is_transaction_fetching_inhibited() bool -+get_remote_endpoint() -+get_total_bytes_sent() -+get_total_bytes_received() -+get_last_message_sent_time() -+get_last_message_received_time() -+fork_rejected_until fc : : time_point -+inhibit_fetching_sync_blocks bool -+soft_ban_expiration_handling() -+intelligent_peer_classification() -+unlinkable_block_strikes uint32 -+clear_old_inventory() -+is_inventory_advertised_to_us_list_full_for_transactions() bool -+is_inventory_advertised_to_us_list_full() bool -} -class fork_database { -+set_emergency_mode(active) -+is_emergency_mode() bool -+push_block(block) -+head() shared_ptr -} -node --> node_delegate : "calls" -node --> peer_connection : "manages" -peer_connection --> fork_database : "uses" -``` - -**Diagram sources** -- [node.hpp:180-355](file://libraries/network/include/graphene/network/node.hpp#L180-L355) -- [peer_connection.hpp:79-354](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L354) -- [fork_database.hpp:111-120](file://libraries/chain/include/graphene/chain/fork_database.hpp#L111-L120) - -## Detailed Component Analysis - -### Node Lifecycle Management -- Construction and destruction: The node allocates an internal node_impl and initializes defaults for connection targets, timeouts, and rate limiting. On destruction, it attempts to gracefully close connections and updates the peer database. -- Configuration: load_configuration reads node-specific settings (listening endpoint, accept flags) from a JSON file in the configuration directory. -- Listener setup: listen_to_p2p_network and listen_on_endpoint/listen_on_port configure the TCP server to accept inbound connections, with optional retry behavior when the port is busy. -- Startup and shutdown: connect_to_p2p_network initiates outbound connections; close() and destructor ensure cleanup. - -Operational loops: -- p2p_network_connect_loop: Periodically connects to candidate peers, respecting retry/backoff and connection caps. -- fetch_sync_items_loop: Requests missing sync items from peers and schedules processing. -- fetch_items_loop: Normal operation fetching of items not yet in local cache. -- advertise_inventory_loop: Broadcasts new inventory to peers with enhanced deduplication. -- terminate_inactive_connections_loop: Detects and disconnects idle/inactive peers with proper cleanup. -- bandwidth_monitor_loop: Updates rolling averages of read/write throughput. -- fetch_updated_peer_lists_loop: Requests updated peer lists periodically. -- dump_node_status_task: Periodically logs comprehensive peer status and synchronization progress. - -```mermaid -sequenceDiagram -participant App as "Application" -participant Node as "node" -participant Impl as "node_impl" -participant DB as "peer_database" -participant Peer as "peer_connection" -App->>Node : "load_configuration(dir)" -Node->>Impl : "load_configuration(...)" -Impl->>DB : "open/read peers.json" -App->>Node : "listen_to_p2p_network()" -Node->>Impl : "listen_to_p2p_network()" -Impl->>Impl : "start accept loop" -App->>Node : "connect_to_p2p_network()" -Node->>Impl : "connect_to_p2p_network()" -Impl->>Impl : "p2p_network_connect_loop()" -Impl->>Peer : "connect_to(endpoint)" -Peer-->>Impl : "on_connection_accepted" -Impl->>Impl : "move_peer_to_active_list" -Impl->>Peer : "address_request" -Peer-->>Impl : "address_message" -Impl->>DB : "update entries" -Impl->>Impl : "trigger_p2p_network_connect_loop()" -``` - -**Diagram sources** -- [node.cpp:952-1047](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp:1623-1654](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp:2282-2350](file://libraries/network/node.cpp#L2282-L2350) - -**Section sources** -- [node.cpp:869-931](file://libraries/network/node.cpp#L869-L931) -- [node.cpp:952-1047](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp:1623-1654](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp:2282-2350](file://libraries/network/node.cpp#L2282-L2350) - -### Enhanced Peer Connection Lifecycle Management - -**Updated** Enhanced peer connection lifecycle management with improved state transitions and cleanup mechanisms. - -The node now implements comprehensive peer connection lifecycle management with enhanced state transitions and proper cleanup from all connection sets. The system prevents peers from staying indefinitely in _active_connections through proper state transitions and delayed deletion mechanisms. - -**Enhanced Lifecycle Features**: -- **Proper State Transitions**: Connections move through well-defined states: handshaking → active → closing → terminating → deleted -- **Delayed Deletion**: schedule_peer_for_deletion() queues peers for deferred deletion to prevent race conditions -- **Cleanup Assertions**: Verifies peers are not found in any connection set before scheduling deletion -- **Thread Safety**: Enhanced mutex protection for peer deletion operations -- **Connection Set Management**: Proper removal from all connection sets during state transitions - -**Section sources** -- [node.cpp:1805-1865](file://libraries/network/node.cpp#L1805-L1865) -- [node.cpp:5281-5320](file://libraries/network/node.cpp#L5281-L5320) - -### Improved Disconnection Flow and Cleanup - -**Updated** Improved disconnection flow with proper cleanup from _active_connections and enhanced disconnect list management. - -The node implements enhanced disconnection flow with proper cleanup mechanisms that ensure peers are properly removed from all connection sets and cleaned up appropriately. - -**Enhanced Disconnection Features**: -- **Proper Cleanup Sequence**: Connections are removed from _active_connections, _handshaking_connections, _closing_connections, and _terminating_connections -- **State Transition Logging**: Detailed logging of connection state transitions for debugging -- **Error Recording**: Connection errors are recorded in peer database for diagnostic purposes -- **Resource Cleanup**: Rate limiter removal and inventory cleanup during disconnection -- **Graceful Handling**: Proper handling of both user-initiated and error-induced disconnections - -**Section sources** -- [node.cpp:3396-3475](file://libraries/network/node.cpp#L3396-L3475) -- [node.cpp:5281-5320](file://libraries/network/node.cpp#L5281-L5320) - -### Enhanced Inventory Management and Deduplication - -**Updated** Enhanced inventory management with improved deduplication logic and better tracking of items already processed or requested. - -The node implements enhanced inventory management with sophisticated deduplication logic that prevents redundant fetches and unbounded growth of fetch queues. - -**Enhanced Inventory Features**: -- **Multi-level Deduplication**: Checks for items currently being processed, recently advertised, and already requested -- **Sophisticated Tracking**: Tracks items advertised to peers, items requested from peers, and items being processed -- **Inventory Expiration**: Regular cleanup of old inventory to prevent memory growth -- **Priority Management**: Updates timestamps for items that arrive from multiple peers to prioritize fresher inventory -- **Transaction Throttling**: Separate limits for transactions vs blocks to maintain network stability - -**Section sources** -- [node.cpp:3280-3351](file://libraries/network/node.cpp#L3280-L3351) -- [peer_connection.cpp:428-448](file://libraries/network/peer_connection.cpp#L428-L448) - -### Advanced Peer State Management - -**Updated** Advanced peer state management with comprehensive connection state tracking and enhanced peer classification. - -The node implements comprehensive peer state management with detailed tracking of peer connection states, synchronization progress, and resource utilization. - -**Advanced State Features**: -- **Connection State Tracking**: Detailed tracking of handshaking, active, closing, and terminating connection states -- **Synchronization Progress**: Monitoring of peer synchronization status and remaining item counts -- **Resource Utilization**: Tracking of peer-specific resource usage including queue depths and memory allocation -- **Performance Metrics**: Latency measurements, round-trip delays, and connection timing information -- **Soft-Ban Status**: Monitoring of fork_rejected_until timestamps and unlinkable_block_strikes counters - -**Section sources** -- [node.cpp:5321-5351](file://libraries/network/node.cpp#L5321-L5351) -- [peer_connection.hpp:276-298](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L298) - -### Peer Connection Establishment -- Outbound: connect_to_endpoint creates a peer_connection and initiates a connect loop; on success, transitions to negotiation and then active. -- Inbound: accept_loop accepts sockets and starts accept_or_connect_task; after hello exchange, moves to active and starts synchronization. -- Handshake validation: Verifies signatures, chain ID, fork compatibility, and prevents self-connections and duplicates. -- Firewall detection: Uses check-firewall messages to infer NAT/firewall status. -- Emergency consensus: Soft-ban peers on fork rejection with automatic expiration handling and intelligent peer classification. - -```mermaid -sequenceDiagram -participant Impl as "node_impl" -participant Peer as "peer_connection" -participant Delegate as "node_delegate" -Impl->>Peer : "connect_to_task(endpoint)" -Peer-->>Impl : "on_hello_message" -Impl->>Impl : "validate hello (sig, chain, fork)" -alt valid -Impl->>Peer : "send connection_accepted" -Peer-->>Impl : "address_request" -Impl->>Peer : "address_message" -Impl->>Impl : "move_peer_to_active_list" -Impl->>Delegate : "new_peer_just_added -> start_synchronizing" -else invalid -Impl->>Peer : "send connection_rejected" -Impl->>Impl : "disconnect_from_peer" -end -``` - -**Diagram sources** -- [node.cpp:2029-2230](file://libraries/network/node.cpp#L2029-L2230) -- [node.cpp:2232-2250](file://libraries/network/node.cpp#L2232-L2250) -- [node.cpp:2282-2350](file://libraries/network/node.cpp#L2282-L2350) - -**Section sources** -- [node.cpp:2029-2230](file://libraries/network/node.cpp#L2029-L2230) -- [node.cpp:2232-2250](file://libraries/network/node.cpp#L2232-L2250) -- [node.cpp:2282-2350](file://libraries/network/node.cpp#L2282-L2350) - -### Network Topology Maintenance -- Peer selection: Maintains a potential peer database with last-seen timestamps, disposition, and attempt counts; applies exponential backoff and retry windows. -- Connection caps: Tracks handshaking, active, closing, and terminating sets; enforces desired/max connection counts. -- Inactivity pruning: Disconnects peers exceeding inactivity thresholds and reschedules outstanding requests to others. -- Peer advertising: Optionally disables advertising to restrict exposure. -- Emergency consensus: Implements soft-ban mechanisms to prevent cascading disconnections during network emergencies. -- Intelligent peer classification: Differentiates between stale fork peers and legitimate sync candidates to prevent infinite loops. - -```mermaid -flowchart TD -Start(["Connect Loop"]) --> CheckWants{"Wants more connections?"} -CheckWants --> |No| Sleep["Sleep and wait for updates"] -CheckWants --> |Yes| Iterate["Iterate potential peers"] -Iterate --> Eligible{"Eligible to connect?"} -Eligible --> |No| NextPeer["Next peer"] -Eligible --> |Yes| Connect["connect_to_endpoint"] -Connect --> NextPeer -NextPeer --> DoneIter{"Any new connection?"} -DoneIter --> |Yes| CheckWants -DoneIter --> |No| Sleep -``` - -**Diagram sources** -- [node.cpp:952-1047](file://libraries/network/node.cpp#L952-L1047) - -**Section sources** -- [node.cpp:952-1047](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp:1400-1621](file://libraries/network/node.cpp#L1400-L1621) - -### Blockchain Integration via node_delegate -- Block handling: handle_block receives new blocks during sync or normal operation; returns whether a fork switch occurred; populates contained transaction IDs for propagation. -- Transaction processing: handle_transaction validates and accepts transactions. -- Sync callbacks: get_block_ids, get_blockchain_synopsis, sync_status, and connection_count_changed inform the delegate about sync progress and peer counts. -- Fork awareness: Estimates last known fork from timestamps and rejects incompatible peers. - -```mermaid -sequenceDiagram -participant Impl as "node_impl" -participant Peer as "peer_connection" -participant Delegate as "node_delegate" -Peer-->>Impl : "block_message" -Impl->>Delegate : "handle_block(block_msg, sync_mode, contained_txs)" -alt sync_mode -Impl->>Impl : "process_backlog_of_sync_blocks" -else normal -Impl->>Impl : "process_block_during_normal_operation" -end -Delegate-->>Impl : "bool fork_switched" -Impl->>Impl : "broadcast transactions from contained_txs" -``` - -**Diagram sources** -- [node.hpp:79-80](file://libraries/network/include/graphene/network/node.hpp#L79-L80) -- [node.cpp:3117-3199](file://libraries/network/node.cpp#L3117-L3199) - -**Section sources** -- [node.hpp:79-80](file://libraries/network/include/graphene/network/node.hpp#L79-L80) -- [node.cpp:3117-3199](file://libraries/network/node.cpp#L3117-L3199) - -### Configuration Methods -- load_configuration: Reads node_config.json and sets listening endpoint, accept flags, and persistence directory. -- listen_on_endpoint/accept_incoming_connections/listen_on_port: Configure the TCP listener and availability behavior. -- set_advanced_node_parameters/get_advanced_node_parameters: Tuning knobs for advanced behavior. -- set_total_bandwidth_limit: Configures upload/download rate limiting. -- disable_peer_advertising: Restricts outbound peer advertisement. - -**Section sources** -- [node.hpp:200-294](file://libraries/network/include/graphene/network/node.hpp#L200-L294) -- [node.cpp:933-950](file://libraries/network/node.cpp#L933-L950) -- [node.cpp:1686-1713](file://libraries/network/node.cpp#L1686-L1713) - -### Peer Management Functions -- add_node/connect_to_endpoint: Adds a seed or forces immediate connection. -- get_connected_peers: Returns status for UI/monitoring with comprehensive peer information. -- get_connection_count/is_connected: Reports current connectivity. -- set_allowed_peers/clear_peer_database: Controls allowed peers and resets peer DB for diagnostics. -- get_potential_peers/disable_peer_advertising: Inspect and control peer discovery. - -**Section sources** -- [node.hpp:211-296](file://libraries/network/include/graphene/network/node.hpp#L211-L296) -- [node.cpp:1788-1841](file://libraries/network/node.cpp#L1788-L1841) -- [node.cpp:2282-2350](file://libraries/network/node.cpp#L2282-L2350) - -### Network Broadcasting and Inventory -- broadcast/broadcast_transaction: Queues outgoing messages and triggers inventory advertisement. -- Inventory tracking: Per-peer inventories (advertised to us/advertised to peer) and node-wide new_inventory set. -- Rate limiting: fc::rate_limiting_group controls bandwidth. -- Message caching: blockchain_tied_message_cache stores recent messages for retrieval. - -```mermaid -flowchart TD -NewItem["New Item Arrives"] --> Cache["Cache in message_cache"] -Cache --> Advertise["Advertise Inventory"] -Advertise --> ForEachPeer{"For each active peer"} -ForEachPeer --> CheckInv["Check inventory overlap"] -CheckInv --> |Not ours| Queue["Queue for send"] -CheckInv --> |Overlap| Skip["Skip"] -Queue --> Send["Send item_ids_inventory_message"] -Send --> Deliver["Deliver item via fetch_items_message"] -``` - -**Diagram sources** -- [node.cpp:1326-1398](file://libraries/network/node.cpp#L1326-L1398) -- [node.cpp:2830-2892](file://libraries/network/node.cpp#L2830-L2892) -- [node.cpp:111-217](file://libraries/network/node.cpp#L111-L217) - -**Section sources** -- [node.cpp:1326-1398](file://libraries/network/node.cpp#L1326-L1398) -- [node.cpp:2830-2892](file://libraries/network/node.cpp#L2830-L2892) -- [node.cpp:111-217](file://libraries/network/node.cpp#L111-L217) - -## Enhanced Peer Connection Lifecycle Management - -### Comprehensive Connection State Transitions -The node implements comprehensive peer connection state transitions with proper cleanup and enhanced logging throughout the connection lifecycle. - -**Enhanced State Transition Features**: -- **Handshaking Phase**: Initial connection establishment with timeout monitoring and activity tracking -- **Active Phase**: Full operational state with synchronization and inventory management -- **Closing Phase**: Graceful disconnection with proper cleanup and reason recording -- **Terminating Phase**: Final cleanup phase with resource deallocation -- **Deletion Phase**: Deferred deletion to prevent race conditions and ensure proper cleanup - -**State Transition Logging Examples**: -``` -New peer is connected (${peer}), now ${count} active peers -Peer connection closing (${peer}), now ${count} active peers -Peer connection closing (${peer}): ${reason}, now ${count} active peers -Peer connection terminating (${peer}), now ${count} active peers -``` - -**Section sources** -- [node.cpp:5281-5320](file://libraries/network/node.cpp#L5281-L5320) -- [node.cpp:3396-3475](file://libraries/network/node.cpp#L3396-L3475) - -### Delayed Peer Deletion Mechanism -The node implements a delayed peer deletion mechanism to prevent peers from staying indefinitely in _active_connections and to handle cleanup safely. - -**Delayed Deletion Features**: -- **Queuing System**: schedule_peer_for_deletion() queues peers for deferred deletion -- **Mutex Protection**: Thread-safe deletion with optional mutex-based queuing -- **Cleanup Verification**: Asserts that peers are not found in any connection set before deletion -- **Batch Processing**: Processes multiple peers in batches to improve performance -- **Race Condition Prevention**: Prevents race conditions during peer cleanup - -**Section sources** -- [node.cpp:1805-1865](file://libraries/network/node.cpp#L1805-L1865) - -### Enhanced Connection Set Management -The node implements enhanced connection set management with proper cleanup from all connection sets during state transitions. - -**Connection Set Management Features**: -- **Multi-set Tracking**: Maintains separate sets for handshaking, active, closing, and terminating connections -- **Proper Removal**: Ensures peers are removed from all relevant connection sets during state transitions -- **State Validation**: Validates peer states before performing state transitions -- **Cleanup Logging**: Logs connection set operations for debugging and monitoring -- **Resource Management**: Proper cleanup of associated resources during connection termination - -**Section sources** -- [node.cpp:5281-5320](file://libraries/network/node.cpp#L5281-L5320) - -## Improved Disconnection Flow and Cleanup - -### Enhanced Disconnection Sequence -The node implements an enhanced disconnection sequence that ensures proper cleanup from all connection sets and maintains system stability. - -**Enhanced Disconnection Features**: -- **Multi-set Cleanup**: Removes connections from _active_connections, _handshaking_connections, _closing_connections, and _terminating_connections -- **Error Recording**: Records connection errors in peer database for diagnostic purposes -- **Rate Limiter Cleanup**: Removes sockets from rate limiter to free resources -- **Inventory Cleanup**: Cleans up associated inventory and request tracking -- **State Transition Logging**: Comprehensive logging of disconnection events and reasons - -**Section sources** -- [node.cpp:3396-3475](file://libraries/network/node.cpp#L3396-L3475) - -### Proper Cleanup from Active Connections -The node ensures that peers are properly cleaned up from _active_connections during disconnection to prevent resource leaks and maintain accurate connection counts. - -**Cleanup Features**: -- **Active Connection Removal**: Ensures peers are removed from _active_connections during disconnection -- **Connection Count Accuracy**: Maintains accurate connection counts throughout the disconnection process -- **Resource Deallocation**: Proper deallocation of resources associated with disconnected peers -- **State Consistency**: Ensures state consistency across all connection management operations -- **Error Handling**: Robust error handling during cleanup operations - -**Section sources** -- [node.cpp:3413-3428](file://libraries/network/node.cpp#L3413-L3428) - -### Enhanced Disconnect List Management -The node implements enhanced disconnect list management with proper peer state transitions and improved cleanup mechanisms. - -**Disconnect List Features**: -- **State Transition Tracking**: Tracks peer state transitions during disconnection -- **Reason Recording**: Records disconnection reasons for diagnostic purposes -- **Cooldown Management**: Implements reconnect cooldown to prevent rapid reconnection loops -- **Firewall Check Handling**: Handles firewall check state during disconnection -- **Request Rescheduling**: Reschedules outstanding requests to other peers during disconnection - -**Section sources** -- [node.cpp:3355-3394](file://libraries/network/node.cpp#L3355-L3394) - -## Enhanced Inventory Management and Deduplication - -### Sophisticated Deduplication Logic -The node implements sophisticated deduplication logic that prevents redundant fetches and maintains efficient inventory management. - -**Enhanced Deduplication Features**: -- **Multi-level Checking**: Checks for items currently being processed, recently advertised, and already requested -- **Inventory Expiration**: Regular cleanup of old inventory to prevent memory growth -- **Priority Updates**: Updates timestamps for items that arrive from multiple peers -- **Transaction Throttling**: Separate limits for transactions vs blocks to maintain network stability -- **Efficient Tracking**: Sophisticated tracking of items across multiple peers and connection states - -**Section sources** -- [node.cpp:3280-3351](file://libraries/network/node.cpp#L3280-L3351) -- [peer_connection.cpp:428-448](file://libraries/network/peer_connection.cpp#L428-L448) - -### Improved Inventory Expiration -The node implements improved inventory expiration with proper cleanup of old inventory items to prevent memory growth and maintain system performance. - -**Inventory Expiration Features**: -- **Timestamp-based Cleanup**: Removes inventory items older than GRAPHENE_NET_MAX_INVENTORY_SIZE_IN_MINUTES -- **Dual Set Management**: Cleans up both inventory_advertised_to_peer and inventory_peer_advertised_to_us sets -- **Logging and Monitoring**: Logs inventory cleanup operations for debugging and monitoring -- **Memory Management**: Prevents unbounded growth of inventory tracking structures -- **Performance Optimization**: Efficient cleanup algorithms to minimize performance impact - -**Section sources** -- [peer_connection.cpp:428-448](file://libraries/network/peer_connection.cpp#L428-L448) - -### Enhanced Item Tracking and Priority Management -The node implements enhanced item tracking and priority management with sophisticated algorithms for handling duplicate inventory announcements. - -**Enhanced Tracking Features**: -- **Priority Updates**: Updates timestamps for items arriving from multiple peers to prioritize fresher inventory -- **Recently Failed Items**: Tracks items that have been recently fetched but failed to push -- **Multi-peer Coordination**: Coordinates item requests across multiple peers to avoid duplication -- **Efficient Lookup**: Fast lookup and update operations for inventory tracking -- **Resource Optimization**: Optimized data structures for efficient inventory management - -**Section sources** -- [node.cpp:3334-3351](file://libraries/network/node.cpp#L3334-L3351) - -## Advanced Peer State Management - -### Comprehensive Peer State Tracking -The node implements comprehensive peer state tracking with detailed monitoring of peer connection states, synchronization progress, and resource utilization. - -**Peer State Tracking Features**: -- **Connection State Monitoring**: Tracks handshaking, active, closing, and terminating connection states -- **Synchronization Progress**: Monitors peer synchronization status and remaining item counts -- **Resource Utilization**: Tracks peer-specific resource usage including queue depths and memory allocation -- **Performance Metrics**: Measures latency, round-trip delays, and connection timing information -- **Soft-ban Status**: Monitors fork_rejected_until timestamps and unlinkable_block_strikes counters - -**Section sources** -- [node.cpp:5321-5351](file://libraries/network/node.cpp#L5321-L5351) -- [peer_connection.hpp:276-298](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L298) - -### Enhanced Peer Classification and Monitoring -The node implements enhanced peer classification and monitoring with detailed metrics for connection health, synchronization status, and resource utilization. - -**Enhanced Classification Features**: -- **Connection Health Monitoring**: Monitors peer connection quality, latency, and bandwidth utilization -- **Synchronization State Classification**: Classifies peers as in-sync, needing sync, or inhibited from sync -- **Resource Utilization Tracking**: Tracks peer-specific resource allocation and queue management -- **Performance Optimization**: Dynamically adjusts connection parameters based on peer performance -- **Health Assessment**: Comprehensive health assessment of peer connections for network optimization - -**Section sources** -- [node.cpp:5321-5351](file://libraries/network/node.cpp#L5321-L5351) - -### Improved Connection Limit and Bandwidth Monitoring -The node provides comprehensive monitoring of connection limits, bandwidth utilization, and peer resource allocation to ensure optimal network performance. - -**Connection and Bandwidth Monitoring Features**: -- **Connection Limits**: Monitoring of active connections, handshaking peers, and connection caps -- **Bandwidth Utilization**: Real-time tracking of upload/download speeds and bandwidth allocation -- **Resource Allocation**: Monitoring of peer-specific resource allocation and queue management -- **Performance Optimization**: Dynamic adjustment of connection parameters based on network conditions -- **Capacity Planning**: Predictive capacity planning based on connection and bandwidth metrics - -**Section sources** -- [node.cpp:5321-5351](file://libraries/network/node.cpp#L5321-L5351) - -## Performance Considerations -- Connection limits: desired/max connections cap concurrent peers; enforced in is_wanting_new_connections and is_accepting_new_connections. -- Bandwidth throttling: rate limiter updates rolling averages and constrains upload/download rates. -- Prefetching: Limits for sync and normal operations prevent resource exhaustion. -- Inactivity pruning: Keeps the mesh healthy by dropping idle peers and rescheduling requests. -- Enhanced inventory deduplication: Prevents redundant fetches and unbounded growth of fetch queues through sophisticated tracking mechanisms. -- Improved connection lifecycle: Prevents peers from staying indefinitely in _active_connections through proper state transitions and cleanup. -- Enhanced disconnection flow: Better disconnect list management with proper peer state transitions and cleanup. -- Emergency consensus overhead: Minimal performance impact through efficient soft-ban expiration checks. -- Automatic flag management: Reduces manual intervention requirements during extended emergency operations. -- Intelligent peer classification: Optimizes peer selection and reduces wasted bandwidth on stale forks. -- Soft-ban caching: Prevents repeated attempts with problematic peers during emergency periods. -- Trusted peer optimization: Reduced soft-ban duration for trusted peers enables faster network recovery. -- DLT mode monitoring: Enhanced logging provides better visibility into block availability without significant performance impact. -- Peer status reporting: Comprehensive status updates enable better monitoring and resource management. -- Comprehensive logging: Detailed peer synchronization progress, item counts, and timing information provide valuable debugging insights without significant performance impact. -- Memory usage monitoring: Efficient memory tracking helps identify resource bottlenecks and optimize performance. -- Enhanced peer lifecycle management: Improved connection state transitions and cleanup mechanisms reduce resource leaks and improve system stability. -- Delayed deletion mechanism: Prevents race conditions during peer cleanup while maintaining system responsiveness. -- Sophisticated inventory management: Enhanced deduplication logic reduces network traffic and improves efficiency. -- Improved disconnection handling: Better cleanup mechanisms prevent resource leaks and maintain accurate connection counts. - -## Troubleshooting Guide -Common issues and resolutions: -- Port binding conflicts: Use listen_on_port with wait_if_endpoint_is_busy=true to retry; otherwise, allow dynamic port selection. -- Rejection reasons: Review connection_rejected_message reason codes (e.g., connected_to_self, already_connected, not_accepting_connections, different_chain, outdated client). -- Firewall/NAT: Use check-firewall messages to detect; adjust inbound/outbound ports and consider advertised inbound addresses. -- Peer database corruption: Clear peer database via clear_peer_database to reset discovery state. -- Bandwidth saturation: Adjust set_total_bandwidth_limit and review advertised inventory sizes. -- Hard fork incompatibility: Upgrade client if rejected due to inability to process future blocks. -- Emergency mode activation: Monitor logs for "EMERGENCY CONSENSUS MODE activated" messages; system automatically handles recovery. -- Soft-ban effects: If experiencing reduced peer connectivity, check soft-ban expiration timestamps; system should automatically reset flags. -- Flag reset issues: Verify inhibit_fetching_sync_blocks flag resets after soft-ban expiration; manual intervention rarely needed. -- Infinite sync loops: Monitor peer behavior; system now prevents endless sync attempts through intelligent soft-ban mechanisms. -- Stale fork detection: System automatically soft-bans peers on stale forks to prevent wasted resources. -- Trusted peer issues: Verify trusted-snapshot-peer configuration for reduced 5-minute soft-ban duration. -- Block rejection handling: Monitor unlinkable_block_exception patterns to identify stale fork vs legitimate sync scenarios. -- DLT mode errors: Review enhanced error logs for detailed block availability context including available range and dlt_block_log boundaries. -- Sync status monitoring: Use peer status updates to monitor synchronization progress and identify stuck peers. -- Memory usage: Monitor peer queue sizes and memory usage through status reports to identify resource bottlenecks. -- Request timeouts: Review detailed timeout logs with item types, block numbers, and timing thresholds to identify slow or unresponsive peers. -- Connection lifecycle: Monitor connection establishment, closure, and termination events to identify connection stability issues. -- Synchronization progress: Use comprehensive sync status reporting to track synchronization completion and identify bottlenecks. -- **Enhanced connection lifecycle**: Monitor peer state transitions and cleanup operations to identify connection management issues. -- **Delayed deletion mechanism**: Verify that peers are properly queued for deletion and cleaned up without race conditions. -- **Improved disconnection flow**: Monitor disconnection sequences to ensure proper cleanup from all connection sets. -- **Enhanced inventory deduplication**: Monitor inventory tracking to identify deduplication effectiveness and potential issues. -- **Connection set management**: Verify proper cleanup from all connection sets during state transitions. -- **State transition logging**: Use detailed logging to debug connection lifecycle issues and peer state management problems. -- **Cleanup verification**: Ensure that peers are properly removed from _active_connections and other connection sets during disconnection. -- **Race condition prevention**: Monitor delayed deletion mechanism to prevent race conditions during peer cleanup operations. - -**Section sources** -- [node.cpp:2251-2280](file://libraries/network/node.cpp#L2251-L2280) -- [node.cpp:2137-2168](file://libraries/network/node.cpp#L2137-L2168) -- [node.cpp:1686-1713](file://libraries/network/node.cpp#L1686-L1713) -- [node.cpp:1326-1398](file://libraries/network/node.cpp#L1326-L1398) -- [database.cpp:4455-4460](file://libraries/chain/database.cpp#L4455-L4460) -- [p2p_plugin.cpp:633-689](file://plugins/p2p/p2p_plugin.cpp#L633-L689) -- [node.cpp:3540-3562](file://libraries/network/node.cpp#L3540-L3562) -- [node.cpp:3920-3940](file://libraries/network/node.cpp#L3920-L3940) -- [config.ini:103-108](file://share/vizd/config/config.ini#L103-L108) - -## Conclusion -The Node Management component provides a robust, configurable, and efficient P2P orchestration layer with comprehensive emergency consensus support and enhanced peer handling capabilities. The recent enhancements significantly improve connection lifecycle management, disconnection handling, inventory deduplication, and peer state management through comprehensive lifecycle management, improved cleanup mechanisms, enhanced inventory tracking, and advanced peer state management systems. - -The enhanced peer connection lifecycle management system provides detailed state transitions with proper cleanup from all connection sets, preventing peers from staying indefinitely in _active_connections through proper state transitions and delayed deletion mechanisms. The improved disconnection flow ensures proper cleanup from _active_connections and enhanced disconnect list management with proper peer state transitions and cleanup. - -The enhanced inventory management system implements sophisticated deduplication logic that prevents redundant fetches and maintains efficient inventory management through multi-level checking, inventory expiration, and priority updates. The advanced peer state management system provides comprehensive tracking of peer connection states, synchronization progress, and resource utilization with detailed metrics and performance optimization. - -These enhancements ensure the network can recover from extended periods without block production while maintaining operational efficiency and preventing cascading failures. The integration of comprehensive connection lifecycle management, enhanced disconnection handling, sophisticated inventory deduplication, and advanced peer state management creates a powerful toolkit for maintaining network stability under adverse conditions. Proper configuration of limits, bandwidth, peer discovery, emergency consensus parameters, trusted peer settings, and the enhanced connection lifecycle mechanisms, combined with monitoring and troubleshooting practices, yields a stable, performant, and resilient network node capable of handling both normal operations and emergency scenarios with comprehensive diagnostic capabilities and detailed peer connection lifecycle insights. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Originating Peer Tracking.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Originating Peer Tracking.md deleted file mode 100644 index f9082d267d..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Originating Peer Tracking.md +++ /dev/null @@ -1,439 +0,0 @@ -# Originating Peer Tracking - - -**Referenced Files in This Document** -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [peer_database.cpp](file://libraries/network/peer_database.cpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [System Architecture](#system-architecture) -3. [Core Components](#core-components) -4. [Originating Peer Tracking Mechanism](#originating-peer-tracking-mechanism) -5. [Message Flow Analysis](#message-flow-analysis) -6. [Peer Database Management](#peer-database-management) -7. [Security and Validation](#security-and-validation) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction - -Originating Peer Tracking is a critical component of the VIZ blockchain's peer-to-peer networking infrastructure. This system enables the network to maintain accurate records of peer connections, track connection states, and manage peer relationships effectively. The mechanism ensures that nodes can identify the source of incoming messages, maintain connection integrity, and prevent duplicate connections while optimizing network topology. - -The system operates through a sophisticated combination of peer connection management, database persistence, and message routing mechanisms. It tracks peer identities, connection states, and behavioral patterns to create an efficient and secure peer-to-peer network. - -## System Architecture - -The Originating Peer Tracking system is built around several interconnected components that work together to maintain peer connection integrity and track message origins: - -```mermaid -graph TB -subgraph "Network Layer" -NC[node.cpp - Network Core] -PC[peer_connection.cpp - Connection Manager] -CM[core_messages.hpp - Message Types] -end -subgraph "Peer Management" -PD[peer_database.cpp - Database Manager] -PR[potential_peer_record - Peer Records] -end -subgraph "Connection States" -CS[Connection States] -NS[Negotiation Status] -PS[Peer States] -end -NC --> PC -NC --> PD -PC --> CM -PD --> PR -NC --> CS -PC --> NS -PC --> PS -CS --> |"Tracks"| PC -NS --> |"Monitors"| PC -PS --> |"Identifies"| PC -``` - -**Diagram sources** -- [node.cpp:112-5989](file://libraries/network/node.cpp#L112-L5989) -- [peer_connection.cpp:1-484](file://libraries/network/peer_connection.cpp#L1-L484) -- [peer_database.cpp:1-262](file://libraries/network/peer_database.cpp#L1-L262) - -The architecture consists of three primary layers: - -1. **Network Core Layer**: Handles message routing, peer negotiation, and connection management -2. **Peer Management Layer**: Maintains persistent peer records and connection history -3. **State Management Layer**: Tracks connection states, negotiation progress, and peer identification - -## Core Components - -### Peer Connection Management - -The peer connection system manages individual peer relationships and maintains detailed state information: - -```mermaid -classDiagram -class peer_connection { -+node_id_t node_id -+node_id_t node_public_key -+string user_agent -+uint32_t core_protocol_version -+our_connection_state our_state -+their_connection_state their_state -+connection_negotiation_status negotiation_status -+fc : : ip : : address inbound_address -+uint16_t inbound_port -+uint16_t outbound_port -+on_message(originating_connection, message) -+send_message(message) -+get_remote_endpoint() -} -class peer_connection_delegate { -<> -+on_message(originating_peer, message) -+on_connection_closed(originating_peer) -+get_message_for_item(item) -} -class node_impl { -+get_peer_by_node_id(node_id) -+is_already_connected_to_id(node_id) -+on_hello_message(originating_peer, hello_message) -+on_address_message(originating_peer, address_message) -} -peer_connection --> peer_connection_delegate : "delegates to" -node_impl --> peer_connection : "manages" -``` - -**Diagram sources** -- [peer_connection.hpp:79-363](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L363) -- [node.cpp:1881-1893](file://libraries/network/node.cpp#L1881-L1893) - -### Message Type System - -The system defines comprehensive message types for peer communication: - -| Message Type | Purpose | Origin | -|--------------|---------|--------| -| hello_message | Initial peer handshake | Both directions | -| connection_accepted | Accept connection request | Initiator receives | -| connection_rejected | Reject connection request | Initiator receives | -| address_request | Request peer addresses | Both directions | -| address_message | Provide peer addresses | Both directions | -| blockchain_item_ids_inventory | Provide blockchain item IDs | Both directions | - -**Section sources** -- [core_messages.hpp:72-95](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L95) -- [core_messages.hpp:233-265](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L265) - -### Peer Database Structure - -The peer database maintains persistent records of potential peers: - -```mermaid -erDiagram -POTENTIAL_PEER_RECORD { -fc::ip::endpoint endpoint PK -fc::time_point_sec last_seen_time -enum last_connection_disposition -fc::time_point_sec last_connection_attempt_time -uint32 number_of_successful_connection_attempts -uint32 number_of_failed_connection_attempts -optional exception last_error -} -PEER_CONNECTION { -node_id_t node_id PK -node_id_t node_public_key -fc::ip::endpoint remote_endpoint -enum connection_direction -enum firewalled_state -microseconds round_trip_delay -time_point connection_initiation_time -} -POTENTIAL_PEER_RECORD ||--o{ PEER_CONNECTION : "tracks" -``` - -**Diagram sources** -- [peer_database.hpp:47-71](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) -- [peer_connection.hpp:200-225](file://libraries/network/include/graphene/network/peer_connection.hpp#L200-L225) - -**Section sources** -- [peer_database.hpp:39-71](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L71) -- [peer_database.cpp:41-82](file://libraries/network/peer_database.cpp#L41-L82) - -## Originating Peer Tracking Mechanism - -### Connection State Management - -The system maintains detailed connection state information to track peer origins and connection progress: - -```mermaid -stateDiagram-v2 -[*] --> Disconnected -Disconnected --> Just_Connected : "Initial connection" -Just_Connected --> Connection_Accepted : "Hello accepted" -Just_Connected --> Connection_Rejected : "Hello rejected" -Connection_Accepted --> Negotiation_Complete : "Address exchange" -Connection_Rejected --> Closed : "Disconnect" -Negotiation_Complete --> Active : "Move to active list" -Active --> Closed : "Connection lost" -Closed --> [*] -state Just_Connected { -[*] --> Hello_Sent -Hello_Sent --> Connection_Accepted : "Accepted" -Hello_Sent --> Connection_Rejected : "Rejected" -} -``` - -**Diagram sources** -- [peer_connection.hpp:82-106](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) -- [node.cpp:2102-2303](file://libraries/network/node.cpp#L2102-L2303) - -### Peer Identity Resolution - -The system resolves peer identities through multiple validation mechanisms: - -1. **Node ID Extraction**: Extracts node ID from hello message user_data -2. **Signature Verification**: Validates shared secret signatures -3. **Chain ID Validation**: Ensures compatibility with network chain -4. **Duplicate Detection**: Prevents multiple connections to same peer - -**Section sources** -- [node.cpp:2102-2230](file://libraries/network/node.cpp#L2102-L2230) -- [peer_connection.hpp:200-218](file://libraries/network/include/graphene/network/peer_connection.hpp#L200-L218) - -### Firewall Detection and Address Validation - -The system implements sophisticated firewall detection mechanisms: - -```mermaid -flowchart TD -Start([Incoming Hello Message]) --> ExtractInfo["Extract Reported Addresses"] -ExtractInfo --> CompareIP{"Compare Reported vs Actual"} -CompareIP --> |Match| Not_Firewalled["Mark as Not Firewalled"] -CompareIP --> |Mismatch| Firewalled["Mark as Firewalled"] -Not_Firewalled --> UpdateDB["Update Peer Database"] -Firewalled --> UpdateDB -UpdateDB --> CheckPorts{"Check Port Information"} -CheckPorts --> |Complete| AddToList["Add to Potential Peers"] -CheckPorts --> |Incomplete| MarkUnknown["Mark Unknown"] -AddToList --> End([Connection Established]) -MarkUnknown --> End -``` - -**Diagram sources** -- [node.cpp:2247-2268](file://libraries/network/node.cpp#L2247-L2268) -- [peer_database.cpp:160-166](file://libraries/network/peer_database.cpp#L160-L166) - -**Section sources** -- [node.cpp:2247-2268](file://libraries/network/node.cpp#L2247-L2268) -- [peer_database.cpp:151-158](file://libraries/network/peer_database.cpp#L151-L158) - -## Message Flow Analysis - -### Handshake Process - -The peer handshake process follows a structured sequence for establishing connections: - -```mermaid -sequenceDiagram -participant A as "Initiating Node" -participant B as "Target Node" -participant DB as "Peer Database" -A->>B : hello_message (with user_data) -B->>B : parse_hello_user_data_for_peer() -B->>B : validate_node_id() -B->>B : check_chain_compatibility() -B->>B : check_duplicate_connection() -alt Valid Connection -B->>A : connection_accepted_message -A->>B : address_request_message -B->>A : address_message (peer list) -A->>DB : update_peer_records() -A->>A : move_peer_to_active_list() -else Invalid Connection -B->>A : connection_rejected_message -A->>A : disconnect_from_peer() -end -``` - -**Diagram sources** -- [node.cpp:2102-2303](file://libraries/network/node.cpp#L2102-L2303) -- [node.cpp:2355-2423](file://libraries/network/node.cpp#L2355-L2423) - -### Address Exchange Protocol - -The address exchange mechanism enables peer discovery and network expansion: - -```mermaid -flowchart LR -A[Active Peer] --> B[Address Request] -B --> C[Address Message] -C --> D[Update Last Seen Time] -D --> E[Store in Database] -E --> F[Trigger Connection Loop] -F --> G[Attempt New Connections] -style A fill:#e1f5fe -style G fill:#f3e5f5 -``` - -**Diagram sources** -- [node.cpp:2355-2378](file://libraries/network/node.cpp#L2355-L2378) -- [node.cpp:2380-2423](file://libraries/network/node.cpp#L2380-L2423) - -**Section sources** -- [node.cpp:2355-2423](file://libraries/network/node.cpp#L2355-L2423) - -## Peer Database Management - -### Database Operations - -The peer database provides comprehensive operations for managing peer records: - -| Operation | Description | Implementation | -|-----------|-------------|----------------| -| lookup_or_create_entry | Find existing or create new peer record | [peer_database.cpp:160-166](file://libraries/network/peer_database.cpp#L160-L166) | -| update_entry | Update peer connection statistics | [peer_database.cpp:151-158](file://libraries/network/peer_database.cpp#L151-L158) | -| lookup_entry_for_endpoint | Retrieve specific peer record | [peer_database.cpp:168-174](file://libraries/network/peer_database.cpp#L168-L174) | -| begin/end iterators | Iterate through peer records | [peer_database.cpp:176-182](file://libraries/network/peer_database.cpp#L176-L182) | - -### Record Persistence - -The database maintains peer records with automatic persistence: - -```mermaid -flowchart TD -Connect[Node Startup] --> LoadDB[Load JSON Database] -LoadDB --> CheckFile{"Database Exists?"} -CheckFile --> |Yes| ParseJSON[Parse JSON Records] -CheckFile --> |No| CreateEmpty[Create Empty Database] -ParseJSON --> PruneDB[Prune to Maximum Size] -CreateEmpty --> RunNode[Run Node] -PruneDB --> RunNode -RunNode --> Shutdown[Node Shutdown] -Shutdown --> SaveDB[Save to JSON File] -SaveDB --> End[Database Saved] -``` - -**Diagram sources** -- [peer_database.cpp:100-138](file://libraries/network/peer_database.cpp#L100-L138) - -**Section sources** -- [peer_database.cpp:100-138](file://libraries/network/peer_database.cpp#L100-L138) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) - -## Security and Validation - -### Connection Validation - -The system implements multiple layers of connection validation: - -1. **Signature Validation**: Verifies shared secret signatures using ECC -2. **Chain Compatibility**: Ensures peers operate on compatible blockchain networks -3. **Fork Compatibility**: Validates peer compatibility with network hard forks -4. **Duplicate Prevention**: Detects and prevents multiple connections to same peer - -### Security Measures - -```mermaid -flowchart TD -Incoming[Incoming Connection] --> ValidateSignature[Validate Signature] -ValidateSignature --> CheckChain[Check Chain ID] -CheckChain --> CheckFork[Check Fork Compatibility] -CheckFork --> CheckDuplicate[Check Duplicate Connection] -CheckDuplicate --> Valid{All Checks Pass?} -Valid --> |Yes| AcceptConnection[Accept Connection] -Valid --> |No| RejectConnection[Reject Connection] -AcceptConnection --> UpdateStats[Update Statistics] -RejectConnection --> LogReason[Log Rejection Reason] -UpdateStats --> MonitorBehavior[Monitor Behavior] -MonitorBehavior --> End[Connection Active] -LogReason --> End -``` - -**Diagram sources** -- [node.cpp:2114-2209](file://libraries/network/node.cpp#L2114-L2209) - -**Section sources** -- [node.cpp:2114-2209](file://libraries/network/node.cpp#L2114-L2209) -- [peer_connection.cpp:244-253](file://libraries/network/peer_connection.cpp#L244-L253) - -## Performance Considerations - -### Connection Limits - -The system enforces connection limits to maintain optimal performance: - -- **Maximum Connections**: Configurable limit on active peer connections -- **Queued Message Limits**: Prevents memory exhaustion from excessive message queuing -- **Inventory Management**: Controls advertisement of blockchain items to prevent flooding - -### Memory Management - -```mermaid -graph LR -subgraph "Memory Constraints" -QM[Queued Messages: 2MB Limit] -IS[Inventory Size: 50MB Limit] -PC[Peer Connections: Configurable] -end -subgraph "Performance Impact" -TP[Throughput: 1000+ messages/sec] -LP[Latency: < 100ms RTT] -MP[Memory Usage: < 512MB] -end -QM --> TP -IS --> TP -PC --> TP -TP --> LP -LP --> MP -``` - -**Section sources** -- [peer_connection.cpp:314-335](file://libraries/network/peer_connection.cpp#L314-L335) -- [peer_connection.cpp:451-468](file://libraries/network/peer_connection.cpp#L451-L468) - -## Troubleshooting Guide - -### Common Connection Issues - -| Issue | Symptoms | Solution | -|-------|----------|----------| -| Connection Rejected | Immediate disconnection after hello | Check chain ID compatibility and node ID validation | -| Duplicate Connection | Rejection with "already connected" | Verify peer ID uniqueness and connection state | -| Firewall Detection Failure | Incorrect firewalled state | Check port information and NAT traversal | -| Database Corruption | JSON parsing errors on startup | Clear peer database file and restart | - -### Debugging Tools - -The system provides comprehensive logging and debugging capabilities: - -- **Verbose Logging**: Enable detailed P2P logging for connection issues -- **Connection State Monitoring**: Track peer connection states and transitions -- **Message Flow Tracing**: Monitor message sequences and timing -- **Database Inspection**: Query peer database for connection history - -**Section sources** -- [node.cpp:1895-1933](file://libraries/network/node.cpp#L1895-L1933) -- [peer_connection.cpp:109-155](file://libraries/network/peer_connection.cpp#L109-L155) - -## Conclusion - -The Originating Peer Tracking system represents a sophisticated approach to peer-to-peer network management in blockchain systems. Through its comprehensive state tracking, validation mechanisms, and persistent database management, it ensures reliable peer connections while maintaining network security and performance. - -Key strengths of the system include: - -- **Robust Identity Management**: Multi-layered peer identity verification prevents malicious connections -- **Comprehensive State Tracking**: Detailed connection state management enables precise origin tracking -- **Persistent Database**: Reliable peer record storage supports network discovery and maintenance -- **Security Validation**: Multiple validation layers protect against various attack vectors -- **Performance Optimization**: Connection limits and memory management ensure system stability - -The system's modular design allows for easy extension and modification while maintaining backward compatibility with existing network protocols. Its comprehensive logging and debugging capabilities facilitate troubleshooting and system monitoring. - -Future enhancements could include advanced peer reputation systems, improved NAT traversal mechanisms, and enhanced security measures for emerging threats. The current architecture provides a solid foundation for these improvements while maintaining the system's reliability and performance characteristics. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Connection Management.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Connection Management.md deleted file mode 100644 index d3b811146f..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Connection Management.md +++ /dev/null @@ -1,971 +0,0 @@ -# Peer Connection Management - - -**Referenced Files in This Document** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [core_messages.cpp](file://libraries/network/core_messages.cpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [peer_database.cpp](file://libraries/network/peer_database.cpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) -- [plugin.hpp](file://plugins/snapshot/plugin.hpp) -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) -- [config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced peer-to-peer networking infrastructure with corrected timestamp reporting mechanisms -- Comprehensive peer logging capabilities with detailed status reporting and closing reason tracking -- Automatic peer soft-banning mechanisms with configurable strike thresholds -- Enhanced peer synchronization with intelligent strike-based enforcement for unlinkable blocks -- Improved peer database operations with unlinkable_block_strikes tracking -- Dual-tier soft-ban system supporting both trusted and regular peers -- Enhanced error diagnostics for peer synchronization issues -- Configurable 20-strike threshold for unlinkable block soft-ban enforcement -- Intelligent sync spam prevention with 50-strike threshold and 5-minute soft-ban duration -- **NEW** sync_spam_strikes counter and fork_rejected_until mechanism for preventing malicious peers from overwhelming the node with repeated sync requests - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive coverage of Peer Connection Management in the VIZ C++ node networking stack. It focuses on the peer_connection.hpp implementation for managing bidirectional peer communication channels, connection state tracking, and message routing. The document explains peer connection establishment protocols, authentication mechanisms, and handshake procedures. It covers connection lifecycle management including initiation, maintenance, graceful disconnection, and error recovery. It details peer state tracking, connection quality metrics, and peer reputation systems. Message queuing, priority handling, and connection multiplexing are documented along with practical examples and guidance on peer selection, balancing, and fault tolerance. - -**Updated** Enhanced with sophisticated network stability improvements including intelligent soft-ban mechanisms with configurable strike-based enforcement, comprehensive peer database operations with unlinkable_block_strikes tracking, improved peer synchronization logging with detailed status reporting, enhanced error diagnostics for peer synchronization issues, intelligent reputation management systems, and **NEW** sync spam prevention system featuring sync_spam_strikes counter and fork_rejected_until mechanism to prevent malicious peers from overwhelming the node with repeated sync requests. - -## Project Structure -The peer connection management system is composed of several interconnected components with enhanced network stability features: -- Peer-level abstraction: peer_connection encapsulates a single peer's state and messaging with enhanced error handling, soft-ban support, improved peer state fields, closing_reason tracking, and **NEW** sync_spam_strikes counter for configurable strike-based reputation management. -- Transport abstraction: message_oriented_connection wraps a secure transport socket and handles message framing with improved logging. -- Security: stcp_socket performs ECDH key exchange and AES encryption for secure communication. -- Protocol messages: core_messages defines the handshake and operational messages exchanged between peers with reliable IP address handling. -- Node orchestration: node coordinates peer connections, maintains peer databases, and manages lifecycle events with enhanced exception safety, soft-ban functionality, ANSI color-coded notifications, and **NEW** intelligent strike-based enforcement mechanisms including sync spam prevention. -- Configuration: config.hpp centralizes tunable constants for timeouts, limits, and behavior. -- Chain integration: database and fork_database handle block validation with proper exception propagation for P2P layer consumption. -- **Enhanced** Network stability: Intelligent soft-ban mechanisms with configurable strike thresholds, enhanced peer disconnect logging, improved peer database dumping capabilities, and **NEW** sync spam prevention system. - -```mermaid -graph TB -subgraph "Peer Layer" -PC["peer_connection
Bidirectional channel
Enhanced Error Handling
Soft-ban Support
Improved State Fields
Closing Reason Tracking
Unlinkable Block Strikes Counter
Sync Spam Strikes Counter
Intelligent Reputation Management
Sync Spam Prevention"] -end -subgraph "Transport Layer" -MOC["message_oriented_connection
Message framing
Robust Logging"] -STCP["stcp_socket
ECDH + AES"] -end -subgraph "Protocol Layer" -CM["core_messages
Handshake & ops
Reliable IP Extraction"] -MSG["message
Header + payload"] -end -subgraph "Node Orchestration" -N["node
Connection manager
Exception Safety
Soft-ban Logic
ANSI Color Notifications
Intelligent Strike Enforcement
Enhanced Diagnostics
Sync Spam Prevention"] -PD["peer_database
Peer reputation
Enhanced Dumping
JSON Serialization"] -END -subgraph "Network Stability" -SB["Soft-ban Mechanisms
Intelligent Enforcement
Configurable Strike Thresholds"] -CR["Enhanced Logging
Detailed Status Reporting
Closing Reason Tracking"] -DB["Database Operations
Comprehensive Tracking
Improved Serialization"] -SS["Sync Spam Prevention
50-strike Threshold
5-minute Duration
fork_rejected_until Mechanism"] -END -subgraph "Chain Integration" -DBCHAIN["database
Block validation
Exception propagation
Memory resize handling"] -FD["fork_database
Fork management
Link handling"] -EX["exceptions
Network exceptions
Soft-ban types
Memory resize exceptions"] -END -PC --> MOC -MOC --> STCP -PC --> CM -CM --> MSG -N --> PC -N --> PD -N --> SB -N --> CR -N --> DB -N --> SS -N --> DBCHAIN -DBCHAIN --> FD -DBCHAIN --> EX -N --> EX -``` - -**Diagram sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [message_oriented_connection.hpp:45-79](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [core_messages.hpp:72-95](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L95) -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [exceptions.hpp:33-45](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L45) - -**Section sources** -- [peer_connection.hpp:1-386](file://libraries/network/include/graphene/network/peer_connection.hpp#L1-L386) -- [message_oriented_connection.hpp:1-85](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L1-L85) -- [stcp_socket.hpp:1-99](file://libraries/network/include/graphene/network/stcp_socket.hpp#L1-L99) -- [core_messages.hpp:1-573](file://libraries/network/include/graphene/network/core_messages.hpp#L1-L573) -- [node.hpp:1-374](file://libraries/network/include/graphene/network/node.hpp#L1-L374) -- [peer_database.hpp:1-141](file://libraries/network/include/graphene/network/peer_database.hpp#L1-L141) -- [message.hpp:1-114](file://libraries/network/include/graphene/network/message.hpp#L1-L114) -- [database.cpp:1-6389](file://libraries/chain/database.cpp#L1-L6389) -- [fork_database.cpp:1-271](file://libraries/chain/fork_database.cpp#L1-L271) -- [exceptions.hpp:1-49](file://libraries/network/include/graphene/network/exceptions.hpp#L1-L49) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -## Core Components -- peer_connection: Manages a single peer's connection state, queues outgoing messages, tracks inventory, and exposes metrics with enhanced error handling, IP address extraction reliability, and **Enhanced** closing_reason field for improved logging. It delegates message delivery to message_oriented_connection and integrates with node-level callbacks. **Enhanced** with fork_rejected_until and inhibit_fetching_sync_blocks fields for soft-ban functionality, improved peer state management, and **NEW** sync_spam_strikes counter for configurable strike-based reputation management. -- message_oriented_connection: Provides a message-oriented API over a secure socket, handling read/write loops, padding, and error propagation with improved logging mechanisms. -- stcp_socket: Implements ECDH key exchange and AES encryption for secure transport. -- core_messages: Defines the protocol messages used during handshake and runtime operations with reliable IP address handling and enhanced error reporting. -- node: Orchestrates peer connections, manages peer databases, and coordinates synchronization and broadcasting with better exception safety, soft-ban logic, fork rejection handling, ANSI color-coded notification support, and **NEW** intelligent strike-based enforcement mechanisms including sync spam prevention with configurable 20-strike threshold for unlinkable blocks and **NEW** 50-strike threshold for sync spam prevention. -- peer_database: Tracks potential peers, connection attempts, and outcomes for peer selection and reputation with improved error handling and enhanced JSON serialization for database dumping. -- **Enhanced** Soft-ban mechanisms: Intelligent soft-ban enforcement with configurable strike thresholds, reduced soft-ban duration from 3600 seconds to 900 seconds, and trusted peer-aware soft-ban duration calculation. -- **Enhanced** Closing reason tracking: Enhanced peer disconnect logging with closing_reason field for improved troubleshooting and debugging capabilities. -- **Enhanced** Database dumping: Improved peer database dumping capabilities with enhanced JSON serialization and error handling. -- **NEW** Intelligent strike-based reputation system: unlinkable_block_strikes counter accumulates violations for unlinkable blocks at/below head, with automatic soft-ban activation when threshold (20 strikes) is reached, providing tolerant handling of occasional stale fork violations. -- **NEW** Sync spam prevention: sync_spam_strikes counter accumulates repeated sync requests for competing forks, with automatic soft-ban activation when threshold (50 strikes) is reached after 5 minutes duration, utilizing fork_rejected_until mechanism to prevent malicious peers from overwhelming the node. - -Key responsibilities: -- Handshake and authentication: ECDH key exchange via stcp_socket, hello/connection_accepted messages via core_messages with reliable IP address extraction. -- Lifecycle management: Connect, accept, close, destroy, and cleanup with enhanced error recovery and exception safety, including soft-ban mechanisms with ANSI color-coded notifications and **NEW** intelligent strike-based enforcement including sync spam prevention. -- Message routing: Queueing, priority, and multiplexing across peers with improved logging and monitoring. -- Metrics and reputation: Connection times, bytes sent/received, inventory lists, and peer selection with robust error handling. -- **Enhanced** Network stability: Intelligent soft-ban enforcement with configurable thresholds, enhanced peer disconnect logging for troubleshooting. -- **Enhanced** Block processing: Proper handling of blocks returned as false by chain, conversion of unlinkable_block_exception to network exceptions, soft-ban functionality for peer management, comprehensive memory resize exception handling, trusted peer-aware soft-ban duration calculation, and **NEW** intelligent strike-based enforcement for unlinkable blocks and **NEW** sync spam prevention. -- **Enhanced** Peer state management: fork_rejected_until timestamp tracking, inhibit_fetching_sync_blocks flag management, automatic soft-ban expiration handling, trusted peer IP address storage for efficient lookup, closing_reason field for improved logging, and **NEW** sync_spam_strikes counter for reputation management. -- **NEW** Intelligent soft-ban enforcement: Automatic accumulation of unlinkable_block_strikes for peers sending blocks at or below head, with 20-strike threshold triggering soft-ban with fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag, providing tolerant handling of stale fork violations while preventing systematic abuse. -- **NEW** Sync spam prevention: Automatic accumulation of sync_spam_strikes for peers repeatedly requesting sync for competing forks, with 50-strike threshold triggering 5-minute soft-ban with fork_rejected_until timestamp, preventing sync ping-pong loops and resource exhaustion attacks. - -**Section sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp:68-162](file://libraries/network/peer_connection.cpp#L68-L162) -- [message_oriented_connection.cpp:128-140](file://libraries/network/message_oriented_connection.cpp#L128-L140) -- [stcp_socket.cpp:49-72](file://libraries/network/stcp_socket.cpp#L49-L72) -- [core_messages.hpp:233-306](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) -- [node.cpp:424-799](file://libraries/network/node.cpp#L424-L799) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [exceptions.hpp:33-45](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L45) - -## Architecture Overview -The peer connection architecture follows a layered design with enhanced error handling, intelligent soft-ban functionality, ANSI color-coded notifications, and **NEW** configurable strike-based soft-ban enforcement including sync spam prevention: -- Application (node) controls peer lifecycle and delegates message processing to the node delegate with improved exception safety, soft-ban logic, enhanced notification capabilities, and **NEW** intelligent strike-based enforcement including sync spam prevention. -- Peer (peer_connection) holds per-peer state and queues messages with robust error handling mechanisms, including soft-ban state tracking, improved peer state fields, closing_reason field for logging, and **NEW** sync_spam_strikes counter for reputation management. -- Transport (message_oriented_connection) frames messages and manages the read/write loop with enhanced logging. -- Security (stcp_socket) negotiates keys and encrypts traffic. -- Protocol (core_messages) defines the message types and semantics with reliable IP address extraction. -- **Enhanced** Chain integration (database/fork_database) validates blocks and propagates exceptions to the P2P layer for proper peer management, including comprehensive memory resize exception handling. -- **Enhanced** Network stability features (intelligent soft-ban mechanisms, enhanced logging) provide improved network resilience and troubleshooting capabilities. -- **NEW** Intelligent reputation system provides configurable enforcement of unlinkable block violations with tolerant handling of occasional stale forks. -- **NEW** Sync spam prevention provides protection against resource exhaustion attacks through configurable strike thresholds and automatic soft-ban enforcement with fork_rejected_until mechanism. - -```mermaid -sequenceDiagram -participant Node as "node" -participant Peer as "peer_connection" -participant MOC as "message_oriented_connection" -participant STCP as "stcp_socket" -participant Remote as "Remote Peer" -participant Chain as "database/fork_database" -Node->>Peer : "connect_to(endpoint)" -Peer->>MOC : "connect_to(endpoint)" -MOC->>STCP : "connect_to(endpoint)" -STCP->>Remote : "TCP connect" -STCP->>Remote : "ECDH key exchange" -Remote-->>STCP : "Public key" -STCP-->>STCP : "Derive shared secret" -STCP-->>MOC : "Encrypted channel ready" -MOC-->>Peer : "read_loop started" -Peer->>Peer : "send hello with IP extraction" -Peer->>Node : "on_message(hello)" -Node->>Peer : "on_hello_message()" -Peer->>Peer : "send connection_accepted" -Peer->>Node : "on_connection_accepted()" -Note over Node,Peer : "Negotiation complete with enhanced error handling, intelligent soft-ban support,
ANSI notifications, NEW intelligent strike-based enforcement,
and NEW sync spam prevention" -``` - -**Diagram sources** -- [peer_connection.cpp:208-242](file://libraries/network/peer_connection.cpp#L208-L242) -- [message_oriented_connection.cpp:135-140](file://libraries/network/message_oriented_connection.cpp#L135-L140) -- [stcp_socket.cpp:69-72](file://libraries/network/stcp_socket.cpp#L69-L72) -- [core_messages.hpp:233-272](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L272) -- [node.cpp:662-718](file://libraries/network/node.cpp#L662-L718) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -## Detailed Component Analysis - -### peer_connection: Enhanced Bidirectional Channel and State Machine -peer_connection encapsulates: -- Connection states: our_connection_state, their_connection_state, and connection_negotiation_status with improved error handling. -- Message queueing: real_queued_message and virtual_queued_message for immediate and deferred message generation with enhanced logging. -- Inventory tracking: sets for advertised and requested items, sync state, and throttling with robust error recovery. -- Metrics: bytes sent/received, last message timestamps, connection durations, and shared secret exposure with improved monitoring. -- **Enhanced** Soft-ban state: fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag for peer management during emergency scenarios. -- **Enhanced** Peer trust integration: Automatic soft-ban duration calculation based on peer trust status for dual-tier soft-ban system. -- **Enhanced** Closing reason tracking: closing_reason field for enhanced logging and debugging capabilities. -- **NEW** Intelligent reputation: unlinkable_block_strikes counter for tracking violations of unlinkable blocks at/below head with configurable threshold enforcement. -- **NEW** Sync spam prevention: sync_spam_strikes counter for tracking repeated sync requests for competing forks with configurable threshold enforcement and fork_rejected_until mechanism. - -```mermaid -classDiagram -class peer_connection { -+peer_connection_delegate* _node -+message_oriented_connection _message_connection -+queue~unique_ptr~ _queued_messages -+size_t _total_queued_messages_size -+connection_negotiation_status negotiation_status -+our_connection_state our_state -+their_connection_state their_state -+node_id_t node_id -+node_id_t node_public_key -+uint32_t core_protocol_version -+std : : string user_agent -+fc : : ip : : address inbound_address -+uint16_t inbound_port -+uint16_t outbound_port -+bool inhibit_fetching_sync_blocks -+fc : : time_point fork_rejected_until -+std : : string closing_reason -+uint32_t unlinkable_block_strikes -+uint32_t sync_spam_strikes -+uint64_t get_total_bytes_sent() -+uint64_t get_total_bytes_received() -+void send_message(message) -+void send_item(item_id) -+void close_connection() -+void destroy_connection() -+Enhanced error handling with try-catch fallbacks -+Improved IP address extraction reliability -+Intelligent soft-ban state management with ANSI notifications -+Trusted peer awareness for soft-ban duration calculation -+Closing reason tracking for enhanced logging -+Intelligent reputation management for unlinkable blocks -+Sync spam prevention for competing fork requests -+fork_rejected_until mechanism for sync spam protection -} -class queued_message { -<> -+get_message(peer_connection_delegate*) message -+get_size_in_queue() size_t -} -class real_queued_message { -+message message_to_send -+size_t message_send_time_field_offset -+get_message() message -+get_size_in_queue() size_t -} -class virtual_queued_message { -+item_id item_to_send -+get_message(peer_connection_delegate*) message -+get_size_in_queue() size_t -} -peer_connection --> queued_message : "queues" -queued_message <|-- real_queued_message -queued_message <|-- virtual_queued_message -``` - -**Diagram sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp:41-66](file://libraries/network/peer_connection.cpp#L41-L66) - -Key behaviors: -- Outgoing message pipeline: send_message enqueues a real_queued_message with enhanced error handling; send_item enqueues a virtual_queued_message; send_queueable_message validates queue size and triggers send_queued_messages_task with improved logging. -- Inbound message pipeline: on_message delegates to node delegate with robust error recovery; on_connection_closed transitions negotiation_status and notifies node with proper exception handling. -- Lifecycle: accept_connection and connect_to manage transport setup with enhanced error handling; close_connection and destroy_connection coordinate teardown with improved exception safety. -- **Enhanced** Soft-ban management: fork_rejected_until tracks soft-ban expiration; inhibit_fetching_sync_blocks prevents sync operations during ban period; ANSI color-coded notifications for ban events; trusted peer-aware soft-ban duration calculation. -- **Enhanced** Closing reason logging: Enhanced peer disconnect logging with closing_reason field for improved troubleshooting. -- **NEW** Intelligent enforcement: unlinkable_block_strikes counter accumulates violations for blocks at or below head; automatic soft-ban activation when threshold (20 strikes) is reached; automatic reset to 0 upon soft-ban enforcement. -- **NEW** Sync spam prevention: sync_spam_strikes counter accumulates repeated sync requests for competing forks; automatic soft-ban activation when threshold (50 strikes) is reached after 5-minute duration using fork_rejected_until mechanism; automatic reset to 0 upon soft-ban enforcement. - -**Section sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp:244-338](file://libraries/network/peer_connection.cpp#L244-L338) -- [peer_connection.hpp:240-278](file://libraries/network/include/graphene/network/peer_connection.hpp#L240-L278) - -### message_oriented_connection: Enhanced Message Framing and Transport Loop -message_oriented_connection: -- Wraps stcp_socket for secure transport with improved error handling. -- Implements read_loop to decode messages, enforce size limits, and dispatch to delegate with enhanced logging. -- Provides send_message with padding to 16-byte boundaries and flush behavior with robust error recovery. -- Exposes connection metrics and shared secret access with improved monitoring capabilities. - -```mermaid -flowchart TD -Start(["send_message"]) --> Pad["Pad to 16-byte boundary"] -Pad --> Encrypt["Encrypt via AES encoder"] -Encrypt --> Write["Write to socket"] -Write --> Flush["Flush"] -Flush --> UpdateStats["Update bytes_sent + last_message_sent_time"] -UpdateStats --> EnhancedLogging["Enhanced error logging and monitoring"] -EnhancedLogging --> End(["Return with improved reliability"]) -ReadLoopStart(["read_loop"]) --> ReadHeader["Read fixed header"] -ReadHeader --> ValidateSize["Validate size <= MAX_MESSAGE_SIZE"] -ValidateSize --> ReadBody["Read padded body"] -ReadBody --> Dispatch["Delegate.on_message"] -Dispatch --> EnhancedMonitoring["Enhanced monitoring and logging"] -EnhancedMonitoring --> ReadLoopStart -``` - -**Diagram sources** -- [message_oriented_connection.cpp:237-283](file://libraries/network/message_oriented_connection.cpp#L237-L283) -- [message_oriented_connection.cpp:148-235](file://libraries/network/message_oriented_connection.cpp#L148-L235) - -**Section sources** -- [message_oriented_connection.hpp:45-79](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [message_oriented_connection.cpp:128-140](file://libraries/network/message_oriented_connection.cpp#L128-L140) -- [message_oriented_connection.cpp:237-283](file://libraries/network/message_oriented_connection.cpp#L237-L283) -- [message_oriented_connection.cpp:148-235](file://libraries/network/message_oriented_connection.cpp#L148-L235) - -### stcp_socket: Secure Transport with ECDH and AES -stcp_socket: -- Performs ECDH key exchange on connect/accept with enhanced error handling. -- Derives shared secret and initializes AES encoder/decoder with improved reliability. -- Reads/writes in 16-byte increments for AES compatibility with robust error recovery. -- Exposes get_shared_secret for upper layers with enhanced monitoring capabilities. - -```mermaid -sequenceDiagram -participant A as "Local stcp_socket" -participant B as "Remote stcp_socket" -A->>B : "Send serialized public key" -B-->>A : "Send serialized public key" -A->>A : "Compute shared secret (ECDH)" -A->>A : "Init AES encoder/decoder" -B->>B : "Compute shared secret (ECDH)" -B->>B : "Init AES encoder/decoder" -Note over A,B : "Secure channel ready with enhanced error handling" -``` - -**Diagram sources** -- [stcp_socket.cpp:49-72](file://libraries/network/stcp_socket.cpp#L49-L72) -- [stcp_socket.cpp:132-177](file://libraries/network/stcp_socket.cpp#L132-L177) - -**Section sources** -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp:49-72](file://libraries/network/stcp_socket.cpp#L49-L72) -- [stcp_socket.cpp:132-177](file://libraries/network/stcp_socket.cpp#L132-L177) - -### Handshake and Authentication Protocols -Handshake flow with enhanced IP address extraction: -- ECDH key exchange via stcp_socket during connect/accept with improved error handling. -- Hello message exchange with user agent, protocol version, ports, and node identifiers with reliable IP address extraction. -- Connection accepted or rejected messages finalize negotiation with enhanced logging and monitoring. - -```mermaid -sequenceDiagram -participant Local as "Local peer_connection" -participant Remote as "Remote peer_connection" -participant Node as "Local node" -participant RemoteNode as "Remote node" -Local->>Remote : "TCP connect" -Remote-->>Local : "TCP accept" -Local->>Remote : "hello_message with IP extraction" -Remote->>RemoteNode : "on_hello_message" -alt "Accept" -Remote->>Local : "connection_accepted_message" -Local->>Node : "on_connection_accepted" -else "Reject" -Remote->>Local : "connection_rejected_message" -Local->>Node : "on_connection_rejected" -end -Note over Local,Remote : "Enhanced error handling and IP address reliability" -``` - -**Diagram sources** -- [core_messages.hpp:233-306](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) -- [node.cpp:662-718](file://libraries/network/node.cpp#L662-L718) -- [peer_connection.cpp:208-242](file://libraries/network/peer_connection.cpp#L208-L242) - -**Section sources** -- [core_messages.hpp:233-306](file://libraries/network/include/graphene/network/core_messages.hpp#L233-L306) -- [node.cpp:662-718](file://libraries/network/node.cpp#L662-L718) -- [peer_connection.cpp:208-242](file://libraries/network/peer_connection.cpp#L208-L242) - -### Connection Lifecycle Management -Lifecycle stages with enhanced error handling, intelligent soft-ban functionality, ANSI color-coded notifications, and **NEW** configurable strike-based soft-ban enforcement including sync spam prevention: -- Initiation: connect_to for outbound, accept_connection for inbound with improved exception safety. -- Negotiation: hello/connection_accepted or connection_rejected with enhanced logging and monitoring. -- Operation: message exchange, inventory advertisement, sync with robust error recovery mechanisms, soft-ban enforcement, ANSI color-coded notifications, trusted peer-aware soft-ban duration calculation, closing_reason logging, and **NEW** intelligent strike-based enforcement for unlinkable blocks and **NEW** sync spam prevention. -- Maintenance: keep-alive via time requests, bandwidth monitoring with improved reliability, soft-ban expiration checking with color-coded logging, closing_reason tracking, and **NEW** strike counter management. -- Graceful disconnection: closing_connection message, close_connection, destroy_connection with enhanced error handling and closing_reason logging. -- Error recovery: queue overflow closes connection with proper cleanup, peer database updates with improved logging, retry timers with better exception safety. -- **Enhanced** Soft-ban management: fork_rejected_until timestamp enforcement, inhibit_fetching_sync_blocks flag management, automatic soft-ban expiration handling, ANSI color-coded ban notifications, reduced soft-ban duration from 3600 seconds to 900 seconds, trusted peer-aware soft-ban duration calculation. -- **NEW** Intelligent enforcement: unlinkable_block_strikes counter accumulation for blocks at or below head, 20-strike threshold triggering soft-ban with automatic reset to 0, tolerant handling of occasional stale fork violations. -- **NEW** Sync spam prevention: sync_spam_strikes counter accumulation for repeated sync requests for competing forks, 50-strike threshold triggering 5-minute soft-ban with fork_rejected_until timestamp and automatic reset to 0, prevention of sync ping-pong loops. - -```mermaid -stateDiagram-v2 -[*] --> Disconnected -Disconnected --> Connecting : "connect_to() with error handling" -Disconnected --> Accepting : "accept_connection() with enhanced safety" -Connecting --> Connected : "hello + accepted" -Accepting --> Connected : "hello + accepted" -Connected --> NegotiationComplete : "inventory sync" -NegotiationComplete --> SoftBan : "fork_rejected_until set with ANSI notification
Enhanced closing reason logging
NEW : unlinkable_block_strikes counter
Intelligent 20-strike threshold enforcement" -SoftBan --> Connected : "soft-ban expired with color reset" -Connected --> IntelligentEnforcement : "20 unlinkable block strikes
Automatic soft-ban activation
inhibit_fetching_sync_blocks
Automatic strike reset to 0" -IntelligentEnforcement --> Connected : "soft-ban expired with color reset" -Connected --> SyncSpamPrevention : "50 sync spam strikes
Automatic 5-minute soft-ban
fork_rejected_until mechanism
Automatic strike reset to 0" -SyncSpamPrevention --> Connected : "soft-ban expired with color reset" -Connected --> Closing : "close_connection() with enhanced logging
closing_reason tracking" -Closing --> Closed : "on_connection_closed with enhanced logging
Enhanced diagnostics" -Closed --> [*] -``` - -**Diagram sources** -- [peer_connection.hpp:82-106](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) -- [peer_connection.cpp:356-369](file://libraries/network/peer_connection.cpp#L356-L369) -- [node.cpp:718-740](file://libraries/network/node.cpp#L718-L740) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) - -**Section sources** -- [peer_connection.cpp:169-242](file://libraries/network/peer_connection.cpp#L169-L242) -- [peer_connection.cpp:356-369](file://libraries/network/peer_connection.cpp#L356-L369) -- [node.cpp:718-740](file://libraries/network/node.cpp#L718-L740) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) - -### Message Queuing, Priority, and Multiplexing -- Queuing: real_queued_message stores full messages with enhanced error handling; virtual_queued_message defers generation via node delegate with improved logging. -- Limits: GRAPHENE_NET_MAXIMUM_QUEUED_MESSAGES_IN_BYTES prevents memory pressure with better exception safety; exceeding triggers closure with proper cleanup. -- Priority: During sync, prioritized_item_id sorts blocks before transactions with enhanced monitoring; during normal operation, FIFO per peer with throttling and improved error recovery. -- Multiplexing: Multiple peer_connection instances share node delegate with enhanced error handling; each peer has independent queues and state with improved reliability. - -```mermaid -flowchart TD -Enqueue["Enqueue message"] --> CheckQueue["Check queue size with enhanced validation"] -CheckQueue --> |OK| Push["Push to queue with error logging"] -CheckQueue --> |Too large| Close["Close connection with proper cleanup"] -Push --> StartTask{"send_queued_messages_task running?"} -StartTask --> |No| Launch["Launch async task with enhanced monitoring"] -StartTask --> |Yes| Wait["Wait for completion with error handling"] -Launch --> SendLoop["Send loop drains queue with improved logging"] -Wait --> SendLoop -SendLoop --> EnhancedMonitoring["Enhanced monitoring and error recovery"] -EnhancedMonitoring --> Done["Done with proper cleanup"] -``` - -**Diagram sources** -- [peer_connection.cpp:310-338](file://libraries/network/peer_connection.cpp#L310-L338) -- [peer_connection.cpp:255-308](file://libraries/network/peer_connection.cpp#L255-L308) -- [config.hpp:58-58](file://libraries/network/include/graphene/network/config.hpp#L58-L58) - -**Section sources** -- [peer_connection.cpp:310-338](file://libraries/network/peer_connection.cpp#L310-L338) -- [peer_connection.cpp:255-308](file://libraries/network/peer_connection.cpp#L255-L308) -- [config.hpp:58-58](file://libraries/network/include/graphene/network/config.hpp#L58-L58) - -### Peer State Tracking, Metrics, and Reputation -Peer state tracking with enhanced error handling, intelligent soft-ban support, ANSI color-coded notifications, and **NEW** intelligent reputation management including sync spam prevention: -- Connection states: negotiated status, direction, firewalled state, clock offset, round-trip delay with improved monitoring and logging. -- Inventory: advertised to peer, advertised to us, requested, sync state, throttling windows with robust error recovery mechanisms. -- Metrics: bytes sent/received, last message times, connection duration, termination time with enhanced logging and monitoring. -- **Enhanced** Soft-ban state: fork_rejected_until timestamp tracks soft-ban expiration; inhibit_fetching_sync_blocks prevents sync operations during ban period. -- **Enhanced** Trusted peer management: Automatic soft-ban duration calculation based on peer trust status; efficient IP address lookup for trusted peer detection. -- **Enhanced** Closing reason logging: Enhanced peer disconnect logging with closing_reason field for improved troubleshooting. -- **NEW** Intelligent reputation: unlinkable_block_strikes counter tracks violations for unlinkable blocks at/below head; automatic soft-ban activation when threshold (20 strikes) is reached; automatic reset to 0 upon enforcement. -- **NEW** Sync spam prevention: sync_spam_strikes counter tracks repeated sync requests for competing forks; automatic soft-ban activation when threshold (50 strikes) is reached after 5-minute duration using fork_rejected_until mechanism; automatic reset to 0 upon enforcement. - -Reputation and selection with improved reliability: -- peer_database tracks endpoints, last seen, disposition, and attempt counts with enhanced error handling. -- node selects peers based on desired/max connections, retry timeouts, and peer database entries with better exception safety. -- Enhanced logging and monitoring throughout the peer selection and balancing process with ANSI color-coded notifications. -- **Enhanced** Soft-ban enforcement: Automatic soft-ban detection and enforcement during block processing with color-coded logging. -- **Enhanced** Trusted peer awareness: Peer trust status influences soft-ban duration and network behavior. -- **Enhanced** Database dumping: Enhanced peer database dumping with enhanced JSON serialization and error handling. -- **NEW** Intelligent enforcement: Configurable 20-strike threshold for unlinkable blocks at/below head with tolerant handling of occasional stale forks. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban duration using fork_rejected_until mechanism for preventing resource exhaustion attacks. - -**Section sources** -- [peer_connection.hpp:175-279](file://libraries/network/include/graphene/network/peer_connection.hpp#L175-L279) -- [peer_connection.cpp:428-480](file://libraries/network/peer_connection.cpp#L428-L480) -- [peer_database.hpp:47-71](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) -- [node.cpp:518-526](file://libraries/network/node.cpp#L518-L526) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5265-5274](file://libraries/network/node.cpp#L5265-L5274) - -### Enhanced Network Stability Features -**Enhanced** Network stability improvements with comprehensive error handling, intelligent soft-ban mechanisms, ANSI color-coded notifications, and **NEW** configurable strike-based soft-ban enforcement including sync spam prevention: -- **Intelligent soft-ban mechanisms**: Soft-ban duration reduced from 3600 seconds (1 hour) to 900 seconds (15 minutes) for improved network responsiveness; trusted peers receive 5-minute soft-ban duration; regular peers receive 15-minute (reduced) soft-ban duration. -- **Intelligent strike-based enforcement**: Configurable 20-strike threshold for unlinkable blocks at/below head; automatic soft-ban activation with fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag; automatic strike counter reset to 0 upon enforcement. -- **Enhanced peer disconnect logging**: closing_reason field provides detailed information about why peers disconnect for improved troubleshooting. -- **Improved peer database dumping**: Enhanced JSON serialization and error handling for better database management. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban duration using fork_rejected_until mechanism for preventing resource exhaustion attacks. -- Node layer implements intelligent soft-ban functionality for peer management during emergency scenarios with ANSI color-coded notifications. -- **Enhanced** Trusted peer integration: Automatic soft-ban duration calculation based on peer trust status; 5-minute soft-ban for trusted peers, 15-minute (reduced) soft-ban for regular peers. -- P2P plugin converts chain exceptions to network exceptions for consistent handling. -- ANSI color codes (CLOG_RED, CLOG_RESET) provide visual emphasis for ban notifications in terminal output. -- **Enhanced** Memory management: Deferred resize operations during block processing handled gracefully without penalizing peers. -- **NEW** Intelligent reputation management: Configurable 20-strike threshold for unlinkable blocks at/below head; automatic soft-ban activation with fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag; automatic strike counter reset to 0 upon enforcement. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban duration using fork_rejected_until mechanism for preventing resource exhaustion attacks. - -```mermaid -flowchart TD -BlockIn["Block received from peer"] --> ProcessBlock["Process block in database"] -ProcessBlock --> CheckChain["Check chain state"] -CheckChain --> |Valid| AcceptBlock["Accept block"] -CheckChain --> |Unlinkable| CheckPosition["Check block position relative to head"] -CheckPosition --> |At or Below Head| StrikeCounter["Increment unlinkable_block_strikes
Configurable 20-strike threshold"] -StrikeCounter --> CheckThreshold{"Strikes >= 20?"} -CheckThreshold --> |Yes| SoftBan["Soft-ban peer with fork_rejected_until
Set inhibit_fetching_sync_blocks
Reset unlinkable_block_strikes to 0"] -CheckThreshold --> |No| LogStrike["Log strike count with enhanced details"] -CheckPosition --> |Above Head| RestartSync["Restart sync with peer
Fetch missing parents"] -CheckChain --> |Too old| ThrowOld["Throw block_older_than_undo_history"] -CheckChain --> |Memory Resize| ThrowResize["Throw deferred_resize_exception"] -ThrowOld --> ConvertNet["Convert to network exception"] -ThrowResize --> ConvertNet -ConvertNet --> NodeHandle["Node handles exception"] -NodeHandle --> PeerTrust{"Peer is trusted?"} -PeerTrust --> |Yes| SetShortBan["Set fork_rejected_until + inhibit_fetching_sync_blocks
5-minute soft-ban (trusted peers)
ANSI Red Notification"] -PeerTrust --> |No| SetReducedBan["Set fork_rejected_until + inhibit_fetching_sync_blocks
900 sec (15 min) soft-ban (regular peers)
ANSI Red Notification"] -SetShortBan --> Broadcast["Broadcast to peers"] -SetReducedBan --> Broadcast -ThrowResize --> NoBan["No soft-ban (deferred resize)
Just retry block later"] -NoBan --> Broadcast -AcceptBlock --> Broadcast -LogStrike --> Broadcast -SoftBan --> Broadcast -RestartSync --> Broadcast -``` - -**Diagram sources** -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [node.cpp:3874-3908](file://libraries/network/node.cpp#L3874-L3908) -- [node.cpp:3598-3626](file://libraries/network/node.cpp#L3598-L3626) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) -- [p2p_plugin.cpp:172-182](file://plugins/p2p/p2p_plugin.cpp#L172-L182) -- [node.cpp:599-600](file://libraries/network/node.cpp#L599-L600) - -**Section sources** -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [node.cpp:3874-3908](file://libraries/network/node.cpp#L3874-L3908) -- [node.cpp:3598-3626](file://libraries/network/node.cpp#L3598-L3626) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) -- [p2p_plugin.cpp:172-182](file://plugins/p2p/p2p_plugin.cpp#L172-L182) -- [node.cpp:599-600](file://libraries/network/node.cpp#L599-L600) - -### Enhanced Peer Database Operations -**Enhanced** Improved peer database operations with comprehensive tracking and enhanced serialization: -- **Enhanced** JSON serialization: Enhanced JSON serialization for peer database records with improved error handling and logging. -- **Comprehensive** tracking: Enhanced peer database dumping with unlinkable_block_strikes tracking for improved reputation management. -- **Robust** file operations: Enhanced file operations with proper error handling for database loading and saving. -- **Database** management: Improved peer database management with enhanced dumping capabilities for debugging and maintenance. -- **Error** handling: Comprehensive error handling for database operations with detailed logging for troubleshooting. - -```mermaid -flowchart TD -DumpRequest["Peer database dump request"] --> LoadRecords["Load peer records from database"] -LoadRecords --> SerializeJSON["Serialize records to JSON with enhanced tracking"] -SerializeJSON --> SaveFile["Save JSON to file with error handling"] -SaveFile --> Success["Database dumped successfully"] -SaveFile --> |Error| LogError["Log error and continue"] -LogError --> Success -``` - -**Diagram sources** -- [peer_database.cpp:120-137](file://libraries/network/peer_database.cpp#L120-L137) - -**Section sources** -- [peer_database.cpp:120-137](file://libraries/network/peer_database.cpp#L120-L137) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) - -### Enhanced Closing Reason Tracking -**Enhanced** Closing reason tracking with detailed logging for improved troubleshooting: -- **Reason storage**: closing_reason field stores the reason for peer disconnection before moving to closing list. -- **Enhanced logging**: Detailed logging includes both remote and local reasons for disconnection. -- **Error handling**: Enhanced error handling for disconnection scenarios with proper reason logging. -- **Debugging support**: Improved debugging capabilities through detailed closing reason information. - -```mermaid -flowchart TD -DisconnectEvent["Peer disconnection event"] --> StoreReason["Store closing_reason on peer"] -StoreReason --> LogReason["Log reason with enhanced details"] -LogReason --> CloseConnection["Close connection gracefully"] -CloseConnection --> Cleanup["Cleanup resources and state"] -``` - -**Diagram sources** -- [node.cpp:5013-5014](file://libraries/network/node.cpp#L5013-L5014) -- [node.cpp:3061-3062](file://libraries/network/node.cpp#L3061-L3062) - -**Section sources** -- [node.cpp:5013-5014](file://libraries/network/node.cpp#L5013-L5014) -- [node.cpp:3061-3062](file://libraries/network/node.cpp#L3061-L3062) - -### Enhanced Intelligent Soft-Ban Enforcement -**NEW** Configurable intelligent soft-ban mechanism for unlinkable blocks at/below head: -- **Intelligent strike accumulation**: unlinkable_block_strikes counter increments for each unlinkable block received from peers when block number is at or below current head. -- **Configurable threshold enforcement**: When strikes reach 20, automatic soft-ban is triggered with fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag set. -- **Automatic reset**: unlinkable_block_strikes counter resets to 0 after soft-ban enforcement. -- **Tolerant handling**: Provides tolerance for occasional stale fork violations while preventing systematic abuse. -- **Integration**: Seamlessly integrates with existing soft-ban infrastructure and trusted peer considerations. -- **Intelligent enforcement**: Combines configurable thresholds with trusted peer awareness for optimal network stability. - -```mermaid -flowchart TD -BlockReceived["Unlinkable block received"] --> CheckHead["Check if block <= head"] -CheckHead --> |Below or Equal| IncrementStrikes["Increment unlinkable_block_strikes"] -IncrementStrikes --> CheckThreshold{"Strikes >= 20?"} -CheckThreshold --> |Yes| TriggerSoftBan["Trigger soft-ban:
Set fork_rejected_until
Set inhibit_fetching_sync_blocks
Reset strikes to 0"] -CheckThreshold --> |No| LogStrikes["Log current strike count"] -CheckHead --> |Above Head| NormalBehavior["Normal sync behavior
Restart sync with peer"] -TriggerSoftBan --> Broadcast["Broadcast to peers"] -LogStrikes --> Broadcast -NormalBehavior --> Broadcast -``` - -**Diagram sources** -- [node.cpp:3874-3908](file://libraries/network/node.cpp#L3874-L3908) -- [peer_connection.hpp:279-283](file://libraries/network/include/graphene/network/peer_connection.hpp#L279-L283) - -**Section sources** -- [node.cpp:3874-3908](file://libraries/network/node.cpp#L3874-L3908) -- [peer_connection.hpp:279-283](file://libraries/network/include/graphene/network/peer_connection.hpp#L279-L283) - -### Enhanced Sync Spam Prevention -**NEW** Configurable intelligent sync spam prevention mechanism for repeated sync requests: -- **Intelligent strike accumulation**: sync_spam_strikes counter increments for each repeated sync request for competing forks when peer block number is at or below current head. -- **Configurable threshold enforcement**: When strikes reach 50, automatic 5-minute soft-ban is triggered with fork_rejected_until timestamp set. -- **Automatic reset**: sync_spam_strikes counter resets to 0 after soft-ban enforcement. -- **Ping-pong loop prevention**: Prevents endless sync restart loops between peers on competing forks at the same height. -- **Integration**: Seamlessly integrates with existing soft-ban infrastructure and sync management. -- **Resource protection**: Protects network resources from sync spam attacks while maintaining legitimate sync operations. -- **fork_rejected_until mechanism**: Uses timestamp-based soft-ban enforcement for precise timing control. - -```mermaid -flowchart TD -SyncRequest["Repeated sync request detected"] --> CheckFork["Check if peer block <= head"] -CheckFork --> |True| IncrementStrikes["Increment sync_spam_strikes"] -IncrementStrikes --> CheckThreshold{"Strikes >= 50?"} -CheckThreshold --> |Yes| TriggerSoftBan["Trigger 5-minute soft-ban:
Set fork_rejected_until
Reset strikes to 0"] -CheckThreshold --> |No| LogStrikes["Log current strike count"] -CheckFork --> |False| RestartSync["Restart sync with peer
Fetch missing blocks"] -TriggerSoftBan --> Broadcast["Broadcast to peers"] -LogStrikes --> Broadcast -RestartSync --> Broadcast -``` - -**Diagram sources** -- [node.cpp:2520-2590](file://libraries/network/node.cpp#L2520-L2590) -- [peer_connection.hpp:285-289](file://libraries/network/include/graphene/network/peer_connection.hpp#L285-L289) - -**Section sources** -- [node.cpp:2520-2590](file://libraries/network/node.cpp#L2520-L2590) -- [peer_connection.hpp:285-289](file://libraries/network/include/graphene/network/peer_connection.hpp#L285-L289) - -### Examples and Patterns -- Peer connection setup with enhanced error handling: - - Outbound: peer_connection::connect_to(endpoint) -> message_oriented_connection::connect_to -> stcp_socket::connect_to -> ECDH -> hello -> connection_accepted with improved logging. - - Inbound: accept_connection -> ECDH -> hello -> connection_accepted with enhanced error recovery. -- Message exchange with robust monitoring: - - send_message queues a real message with enhanced error handling; send_item queues a virtual message; send_queued_messages_task sends them with improved logging. -- Connection monitoring with enhanced reliability: - - get_total_bytes_sent/get_total_bytes_received, last_message_sent_time/last_message_received, get_connection_time/get_connection_terminated_time with improved error recovery. -- Peer selection and balancing with better exception safety: - - node maintains desired/max connections, peer database, and retry timers; balances by selecting candidates from peer_database and initiating connect_to with enhanced error handling. -- **Enhanced** Intelligent soft-ban management: - - Automatic soft-ban detection for peers sending unlinkable blocks; fork_rejected_until timestamp enforcement; inhibit_fetching_sync_blocks flag management; automatic soft-ban expiration handling; ANSI color-coded ban notifications; reduced soft-ban duration from 3600 seconds to 900 seconds; trusted peer-aware soft-ban duration calculation. -- **Enhanced** Closing reason tracking: - - Enhanced peer disconnect logging with closing_reason field; detailed reason storage and logging for improved troubleshooting. -- **Enhanced** Trusted peer integration: - - Automatic trusted peer registration from config.ini trusted-snapshot-peer options; efficient IP address lookup for trust detection; dual-tier soft-ban system with 5-minute duration for trusted peers; seamless P2P-snapshot plugin coordination. -- **Enhanced** Memory resize exception handling: - - Deferred shared memory resize operations during block processing; proper exception propagation through P2P layer; no peer penalization for transient memory resize operations; trusted peer consideration in exception handling. -- **Enhanced** Database dumping: - - Enhanced peer database dumping with improved JSON serialization; robust file operations with error handling; comprehensive logging for database management. -- **NEW** Intelligent reputation management: - - Configurable 20-strike threshold for unlinkable blocks at/below head; automatic soft-ban activation with fork_rejected_until timestamp; automatic strike counter reset to 0; tolerant handling of occasional stale fork violations; integration with existing soft-ban infrastructure. -- **NEW** Sync spam prevention: - - Configurable 50-strike threshold for repeated sync requests; automatic 5-minute soft-ban activation with fork_rejected_until timestamp; automatic strike counter reset to 0; prevention of sync ping-pong loops; protection against resource exhaustion attacks; fork_rejected_until mechanism for precise timing control. - -**Section sources** -- [peer_connection.cpp:208-242](file://libraries/network/peer_connection.cpp#L208-L242) -- [peer_connection.cpp:340-354](file://libraries/network/peer_connection.cpp#L340-L354) -- [peer_connection.cpp:371-399](file://libraries/network/peer_connection.cpp#L371-L399) -- [node.cpp:518-526](file://libraries/network/node.cpp#L518-L526) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Dependency Analysis -The peer connection subsystem exhibits clear layering and low coupling with enhanced error handling, intelligent soft-ban functionality, ANSI color-coded notifications, and **NEW** configurable strike-based soft-ban enforcement including sync spam prevention: -- peer_connection depends on message_oriented_connection and node delegate with improved exception safety. -- message_oriented_connection depends on stcp_socket and delegates to peer_connection with enhanced logging. -- stcp_socket depends on fc crypto primitives and tcp socket with robust error recovery. -- node orchestrates peer_connection instances and peer_database with better exception handling, soft-ban logic, ANSI notification support, and **NEW** intelligent strike-based enforcement including sync spam prevention. -- core_messages defines protocol contracts used across layers with reliable IP address handling. -- **Enhanced** database and fork_database depend on chain exceptions and propagate network exceptions to P2P layer. -- **Enhanced** p2p_plugin converts chain exceptions to network exceptions for consistent handling and manages trusted peer registration. -- **Enhanced** snapshot_plugin provides trusted-snapshot-peer configuration and peer discovery for trusted peer management. -- **Enhanced** database_exceptions defines deferred_resize_exception for memory resize operations. -- **Enhanced** Network stability features create dependencies between node and peer_connection for intelligent enforcement mechanisms. -- **NEW** Intelligent reputation system creates dependency between node and peer_connection for strike counter management and threshold enforcement. -- **NEW** Sync spam prevention creates dependency between node and peer_connection for sync_spam_strikes counter management and threshold enforcement using fork_rejected_until mechanism. - -```mermaid -graph LR -PC["peer_connection"] --> MOC["message_oriented_connection"] -MOC --> STCP["stcp_socket"] -PC --> CM["core_messages"] -N["node"] --> PC -N --> PD["peer_database"] -N --> DB["database"] -N --> SB["Intelligent Soft-ban
Configurable Strike Thresholds"] -N --> CR["Enhanced Logging
Detailed Status Reporting"] -N --> DBOPS["Database Operations
Comprehensive Tracking"] -N --> SS["Sync Spam Prevention
50-strike Threshold
5-minute Duration
fork_rejected_until Mechanism"] -P2P["p2p_plugin"] --> N -P2P --> SNAP["snapshot_plugin"] -SNAP --> N -DB --> FD["fork_database"] -DB --> EX["exceptions"] -N --> EX -EX --> DR["deferred_resize_exception"] -PC --> SB -PC --> SS -``` - -**Diagram sources** -- [peer_connection.hpp:79-351](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [message_oriented_connection.hpp:45-79](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [stcp_socket.hpp:37-93](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [core_messages.hpp:72-95](file://libraries/network/include/graphene/network/core_messages.hpp#L72-L95) -- [node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [peer_database.hpp:104-134](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message.hpp:42-106](file://libraries/network/include/graphene/network/message.hpp#L42-L106) -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [exceptions.hpp:33-45](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L45) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -**Section sources** -- [peer_connection.hpp:26-45](file://libraries/network/include/graphene/network/peer_connection.hpp#L26-L45) -- [message_oriented_connection.hpp:26-28](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L26-L28) -- [stcp_socket.hpp:26-28](file://libraries/network/include/graphene/network/stcp_socket.hpp#L26-L28) -- [core_messages.hpp:26-35](file://libraries/network/include/graphene/network/core_messages.hpp#L26-L35) -- [node.hpp:26-31](file://libraries/network/include/graphene/network/node.hpp#L26-L31) -- [peer_database.hpp:26-35](file://libraries/network/include/graphene/network/peer_database.hpp#L26-L35) -- [message.hpp:26-31](file://libraries/network/include/graphene/network/message.hpp#L26-L31) -- [database.cpp:1215-1246](file://libraries/chain/database.cpp#L1215-L1246) -- [fork_database.cpp:34-46](file://libraries/chain/fork_database.cpp#L34-L46) -- [exceptions.hpp:33-45](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L45) -- [node.cpp:593-601](file://libraries/network/node.cpp#L593-L601) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -## Performance Considerations -- Message sizing: MAX_MESSAGE_SIZE caps payload; padding to 16 bytes ensures AES compatibility with enhanced error handling. -- Queue limits: GRAPHENE_NET_MAXIMUM_QUEUED_MESSAGES_IN_BYTES prevents memory growth under heavy load with better exception safety. -- Throttling: Inventory lists and transaction fetching inhibition mitigate flooding with improved monitoring. -- Bandwidth monitoring: node tracks read/write rates and applies rate limiting groups with enhanced logging. -- Sync optimization: interleaved prefetching and prioritization reduce sync time with robust error recovery mechanisms. -- Enhanced error handling: Comprehensive try-catch fallbacks throughout peer statistics logging ensure more robust operation of the P2P network layer. -- **Enhanced** Soft-ban optimization: Intelligent soft-ban enforcement prevents cascading disconnections during emergency scenarios, improving network stability with reduced soft-ban duration from 3600 seconds to 900 seconds. -- **Enhanced** Block processing efficiency: Proper exception handling reduces unnecessary reprocessing and improves overall network performance. -- **Enhanced** Memory management: Deferred resize operations prevent blocking during shared memory expansion, improving system responsiveness. -- **Enhanced** Notification performance: ANSI color-coded logging provides visual emphasis without impacting performance significantly. -- **Enhanced** Trusted peer performance: O(1) IP address lookup for trusted peer detection minimizes overhead; efficient configuration parsing reduces startup time. -- **Enhanced** Dual-tier optimization: Separate soft-ban duration calculation eliminates redundant calculations while providing flexible peer management. -- **Enhanced** Intelligent reputation management: Configurable 20-strike threshold provides optimal balance between tolerance and enforcement; minimal performance impact through simple counter increment and comparison operations. -- **Enhanced** Sync spam prevention: Configurable 50-strike threshold provides optimal protection against resource exhaustion attacks; minimal performance impact through simple counter increment and comparison operations. -- **NEW** Intelligent enforcement efficiency: Configurable 20-strike threshold provides optimal balance between tolerance and enforcement; minimal performance impact through simple counter increment and comparison operations. -- **NEW** Sync spam prevention efficiency: Configurable 50-strike threshold provides optimal protection against resource exhaustion attacks; minimal performance impact through simple counter increment and comparison operations using fork_rejected_until mechanism. - -## Troubleshooting Guide -Common issues and remedies with enhanced error handling, intelligent soft-ban functionality, ANSI color-coded notifications, and **NEW** configurable strike-based soft-ban enforcement including sync spam prevention: -- Connection refused or rejected: Review rejection reasons in connection_rejected_message with improved logging; check protocol version, chain ID, and node policies with better error reporting. -- Handshake failures: Verify ECDH key exchange succeeded with enhanced error handling; inspect stcp_socket logs with improved monitoring; ensure endpoints are reachable with robust error recovery. -- Queue overflow: Monitor queue size with enhanced logging; adjust rate or reduce message sizes; consider disconnecting misbehaving peers with proper cleanup. -- Idle peers: Use inactivity timeouts with improved exception safety; terminate inactive connections; rebalance peers with better error handling. -- Peer reputation: Inspect peer_database entries with enhanced logging; prune failed peers; respect retry delays with improved error recovery mechanisms. -- IP address extraction issues: Enhanced safe static_cast operations with try-catch fallback mechanisms ensure reliable IP address extraction throughout peer information handling. -- **Enhanced** Soft-ban issues: Check fork_rejected_until timestamps and inhibit_fetching_sync_blocks flags; verify automatic soft-ban expiration handling; monitor soft-ban effectiveness; review ANSI color-coded ban notifications for quick identification; verify trusted peer soft-ban duration calculation; verify reduced soft-ban duration from 3600 seconds to 900 seconds. -- **Enhanced** Closing reason tracking: Verify closing_reason field logging; check enhanced peer disconnect logging for troubleshooting; review detailed reason information for improved debugging. -- **Enhanced** Trusted peer configuration: Verify trusted-snapshot-peer entries in config.ini are valid IP:port format; check automatic registration in P2P plugin logs; ensure IP address parsing succeeds; verify O(1) lookup functionality. -- **Enhanced** Block processing errors: Review unlinkable_block_exception handling and soft-ban enforcement; verify proper exception conversion from chain to network exceptions; check memory resize exception handling; verify trusted peer-aware soft-ban duration calculation. -- **Enhanced** Memory resize issues: Monitor deferred_resize_exception occurrences; verify proper exception propagation through P2P layer; ensure no peer penalization for transient memory resize operations. -- **Enhanced** Notification visibility: Verify ANSI color codes are properly displayed in terminal; check CLOG_RED and CLOG_RESET definitions for proper formatting. -- **Enhanced** Plugin integration: Verify snapshot plugin loads trusted-snapshot-peer configuration; check P2P plugin registration success; ensure seamless coordination between plugins. -- **Enhanced** Database dumping: Verify enhanced peer database dumping functionality; check JSON serialization and error handling; ensure proper database management capabilities. -- **NEW** Intelligent reputation issues: Monitor unlinkable_block_strikes counter values; verify 20-strike threshold enforcement; check automatic soft-ban activation and strike reset behavior; ensure tolerant handling of occasional stale fork violations; verify integration with existing soft-ban infrastructure. -- **NEW** Sync spam prevention issues: Monitor sync_spam_strikes counter values; verify 50-strike threshold enforcement; check automatic 5-minute soft-ban activation and fork_rejected_until mechanism; verify automatic strike reset behavior; ensure prevention of sync ping-pong loops; verify integration with existing sync management. -- **NEW** fork_rejected_until mechanism: Verify timestamp-based soft-ban enforcement; check 5-minute duration precision; ensure automatic soft-ban expiration handling; verify integration with sync spam prevention logic. - -**Section sources** -- [core_messages.hpp:285-306](file://libraries/network/include/graphene/network/core_messages.hpp#L285-L306) -- [config.hpp:48-50](file://libraries/network/include/graphene/network/config.hpp#L48-L50) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) -- [peer_connection.cpp:314-325](file://libraries/network/peer_connection.cpp#L314-L325) -- [node.cpp:3448-3470](file://libraries/network/node.cpp#L3448-L3470) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [node.cpp:5272-5274](file://libraries/network/node.cpp#L5272-L5274) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Conclusion -Peer Connection Management in this codebase provides a robust, layered architecture for secure, multiplexed peer communication with enhanced error handling, reliability, and **Enhanced** network stability features. It supports comprehensive lifecycle management, strict authentication via ECDH/AES, and sophisticated message queuing with priority and throttling. The node orchestrates peers, maintains reputation, and optimizes selection and balancing with improved exception safety. Enhanced peer information handling with reliable IP address extraction using safe static_cast operations with try-catch fallback mechanisms, combined with improved error handling and performance optimizations throughout peer statistics logging, ensures more robust operation of the P2P network layer. - -**Enhanced** The system now includes sophisticated network stability improvements featuring intelligent soft-ban mechanisms with configurable strike-based enforcement, comprehensive peer database operations with unlinkable_block_strikes tracking, improved peer synchronization logging with detailed status reporting, enhanced error diagnostics for peer synchronization issues, and intelligent reputation management systems. These enhancements provide superior network stability, improved operational visibility through color-coded terminal notifications, enhanced troubleshooting capabilities through detailed closing reason tracking, intelligent enforcement mechanisms through configurable strike thresholds, and intelligent reputation management through configurable enforcement that tolerates occasional stale fork violations while preventing systematic abuse. - -**NEW** Additionally, the system now features advanced sync spam prevention mechanisms that protect against resource exhaustion attacks through configurable strike thresholds and automatic soft-ban enforcement using fork_rejected_until mechanism, ensuring network resilience against malicious or misconfigured peers attempting to overwhelm the system with repeated sync requests. The implementation includes precise 5-minute soft-ban duration control and automatic strike counter reset to prevent permanent peer blocking while effectively mitigating spam attacks. - -## Appendices - -### Configuration Constants -Important tunables affecting peer connection behavior: -- GRAPHENE_NET_PROTOCOL_VERSION: Protocol version for compatibility. -- MAX_MESSAGE_SIZE: Maximum message size in bytes. -- GRAPHENE_NET_MAXIMUM_QUEUED_MESSAGES_IN_BYTES: Queue size cap with enhanced error handling. -- GRAPHENE_NET_DEFAULT_DESIRED_CONNECTIONS / GRAPHENE_NET_DEFAULT_MAX_CONNECTIONS: Target and hard limits. -- GRAPHENE_NET_PEER_HANDSHAKE_INACTIVITY_TIMEOUT / GRAPHENE_NET_PEER_DISCONNECT_TIMEOUT: Timeout thresholds with improved exception safety. -- **Enhanced** TRUSTED_SOFT_BAN_DURATION_SEC / SOFT_BAN_DURATION_SEC: 300 seconds (5 minutes) vs 900 seconds (15 minutes) for trusted vs regular peers. -- **Enhanced** DISCONNECT_RECONNECT_COOLDOWN_SEC: 30-second cooldown period for per-IP disconnect management. -- **NEW** UNLINKABLE_BLOCK_STRIKE_THRESHOLD: 20-strike threshold for configurable soft-ban enforcement on unlinkable blocks at/below head. -- **NEW** SYNC_SPAM_STRIKE_THRESHOLD: 50-strike threshold for configurable soft-ban enforcement on sync spam attacks. -- **NEW** SYNC_SPAM_BAN_DURATION_SEC: 300-second (5-minute) duration for sync spam soft-bans. -- **NEW** INTELLIGENT_SOFT_BAN_ENFORCEMENT: Configurable threshold with trusted peer awareness for optimal network stability. -- **NEW** fork_rejected_until mechanism: Timestamp-based soft-ban enforcement for precise timing control. - -**Section sources** -- [config.hpp:26-106](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [node.cpp:599-600](file://libraries/network/node.cpp#L599-L600) - -### Network Exception Types -**Enhanced** Exception types for improved error handling: -- unlinkable_block_exception: Used for blocks from dead forks with parents not in fork database. -- block_older_than_undo_history: Used for blocks too old for fork database processing. -- peer_is_on_an_unreachable_fork: Used when peers are on incompatible forks. -- **Enhanced** deferred_resize_exception: Used for shared memory resize operations during block processing, indicating transient memory expansion requiring block retry. -- Enhanced error propagation: Chain exceptions converted to network exceptions for consistent P2P layer handling. -- **Enhanced** Trusted peer consideration: Deferred resize exceptions do not trigger soft-bans as they represent local memory conditions. -- **Enhanced** Closing reason tracking: Enhanced peer disconnect logging with detailed reason information. -- **NEW** Intelligent enforcement: Configurable 20-strike threshold for unlinkable blocks at/below head with automatic soft-ban activation. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban activation using fork_rejected_until mechanism. - -**Section sources** -- [exceptions.hpp:33-45](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L45) -- [p2p_plugin.cpp:172-182](file://plugins/p2p/p2p_plugin.cpp#L172-L182) -- [database.cpp:1239-1241](file://libraries/chain/database.cpp#L1239-L1241) -- [database_exceptions.hpp:86-86](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L86-L86) - -### ANSI Color Code Definitions -**Enhanced** Terminal formatting support for enhanced notifications: -- CLOG_RED: ANSI escape sequence for red text formatting. -- CLOG_ORANGE: ANSI escape sequence for orange text formatting. -- CLOG_RESET: ANSI escape sequence to reset terminal formatting. -- Used extensively in soft-ban notifications and other important system messages for improved visual emphasis. - -**Section sources** -- [node.cpp:79-82](file://libraries/network/node.cpp#L79-L82) -- [node.cpp:3278-3281](file://libraries/network/node.cpp#L3278-L3281) -- [node.cpp:3633-3636](file://libraries/network/node.cpp#L3633-L3636) -- [node.cpp:3653-3656](file://libraries/network/node.cpp#L3653-L3656) -- [node.cpp:3671-3674](file://libraries/network/node.cpp#L3671-L3674) - -### Enhanced Network Stability Configuration -**Enhanced** Configuration options for network stability improvements: -- **Intelligent soft-ban mechanisms**: Soft-ban duration reduced from 3600 seconds (1 hour) to 900 seconds (15 minutes) for improved network responsiveness; trusted peers receive 5-minute soft-ban duration; regular peers receive 15-minute (reduced) soft-ban duration. -- **Intelligent strike-based enforcement**: Configurable 20-strike threshold for unlinkable blocks at/below head with automatic soft-ban activation. -- **Enhanced peer disconnect logging**: closing_reason field provides detailed information about why peers disconnect for improved troubleshooting. -- **Improved peer database dumping**: Enhanced JSON serialization and error handling for better database management. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban duration using fork_rejected_until mechanism for preventing resource exhaustion attacks. -- Automatic registration: P2P plugin automatically registers trusted peers from snapshot plugin configuration. -- IP-based trust detection: Efficient O(1) lookup using 32-bit IP address storage. -- Dual-tier soft-ban system: 5-minute duration for trusted peers, 15-minute (reduced) duration for regular peers. -- **NEW** Intelligent reputation management: Configurable 20-strike threshold for unlinkable blocks at/below head with automatic soft-ban activation. -- **NEW** Sync spam prevention: Configurable 50-strike threshold for repeated sync requests with 5-minute soft-ban duration using fork_rejected_until mechanism for preventing resource exhaustion attacks. - -**Section sources** -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) -- [plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [node.cpp:5240-5274](file://libraries/network/node.cpp#L5240-L5274) -- [node.cpp:4472-4479](file://libraries/network/node.cpp#L4472-L4479) -- [node.cpp:5016-5021](file://libraries/network/node.cpp#L5016-L5021) -- [node.cpp:5013-5014](file://libraries/network/node.cpp#L5013-L5014) -- [node.cpp:3061-3062](file://libraries/network/node.cpp#L3061-L3062) - -### Enhanced Peer Database Management -**Enhanced** Improved peer database management with enhanced capabilities: -- **Enhanced** JSON serialization: Improved JSON serialization for peer database records with better error handling. -- **Comprehensive** tracking: Enhanced peer database dumping with unlinkable_block_strikes tracking for improved reputation management. -- **Robust** file operations: Enhanced file operations with proper error handling for database loading and saving. -- **Comprehensive** logging: Detailed logging for database operations with improved troubleshooting capabilities. -- **Database** dumping: Enhanced peer database dumping functionality for debugging and maintenance purposes. -- **Error** handling: Comprehensive error handling for database operations with detailed logging for troubleshooting. - -**Section sources** -- [peer_database.cpp:120-137](file://libraries/network/peer_database.cpp#L120-L137) -- [peer_database.cpp:100-174](file://libraries/network/peer_database.cpp#L100-L174) - -### NEW Intelligent Reputation System -**NEW** Configurable intelligent reputation management system for unlinkable block violations: -- **Configurable** threshold: 20-strike maximum before soft-ban activation for tolerant handling of stale fork violations. -- **Automatic** enforcement: Soft-ban triggered when threshold reached with fork_rejected_until timestamp and inhibit_fetching_sync_blocks flag. -- **Automatic** reset: unlinkable_block_strikes counter reset to 0 after soft-ban enforcement. -- **Integration** with existing infrastructure: Seamless integration with existing soft-ban infrastructure and trusted peer considerations. -- **Performance** optimization: Minimal performance impact through simple counter operations and threshold comparison. -- **Intelligent** enforcement: Combines configurable thresholds with trusted peer awareness for optimal network stability. - -**Section sources** -- [peer_connection.hpp:279-283](file://libraries/network/include/graphene/network/peer_connection.hpp#L279-L283) -- [node.cpp:3874-3908](file://libraries/network/node.cpp#L3874-L3908) - -### NEW Sync Spam Prevention System -**NEW** Configurable intelligent sync spam prevention system for repeated sync requests: -- **Configurable** threshold: 50-strike maximum before 5-minute soft-ban activation for preventing resource exhaustion attacks. -- **Automatic** enforcement: Soft-ban triggered when threshold reached with fork_rejected_until timestamp mechanism. -- **Automatic** reset: sync_spam_strikes counter reset to 0 after soft-ban enforcement. -- **Integration** with existing infrastructure: Seamless integration with existing soft-ban infrastructure and sync management. -- **Performance** optimization: Minimal performance impact through simple counter operations and threshold comparison. -- **Security** enhancement: Prevents sync ping-pong loops and protects network resources from malicious attacks using fork_rejected_until mechanism for precise timing control. - -**Section sources** -- [peer_connection.hpp:285-289](file://libraries/network/include/graphene/network/peer_connection.hpp#L285-L289) -- [node.cpp:2520-2590](file://libraries/network/node.cpp#L2520-L2590) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Database and Discovery.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Database and Discovery.md deleted file mode 100644 index 633e9ab206..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Peer Database and Discovery.md +++ /dev/null @@ -1,419 +0,0 @@ -# Peer Database and Discovery - - -**Referenced Files in This Document** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [peer_database.cpp](file://libraries/network/peer_database.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [config.ini](file://share/vizd/config/config.ini) -- [seednodes](file://share/vizd/seednodes) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the Peer Database and Discovery subsystem responsible for: -- Persistent storage of peer addresses and connection history -- Network topology maintenance and peer reputation tracking -- Peer discovery via seed nodes and address exchange -- Connection diversity and load balancing strategies -- Network partition recovery and pruning policies - -It focuses on the peer_database implementation, the node’s discovery and connection orchestration, and the P2P plugin integration. - -## Project Structure -The peer database and discovery logic spans three primary areas: -- Network core: peer_database and node infrastructure -- P2P plugin: CLI configuration, seed node handling, and lifecycle integration -- Configuration and seed files: runtime configuration and bootstrap peers - -```mermaid -graph TB -subgraph "Network Core" -PD["peer_database.hpp/.cpp
Persistent peer records"] -N["node.hpp/.cpp
Discovery, connection loops,
address exchange, pruning"] -end -subgraph "P2P Plugin" -P2PH["p2p_plugin.hpp/.cpp
CLI options, seed parsing,
startup/connect workflow"] -end -subgraph "Configuration" -CFG["config.ini
p2p-endpoint, p2p-seed-node"] -SEED["seednodes
bootstrap endpoints"] -end -P2PH --> N -CFG --> P2PH -SEED --> P2PH -N --> PD -``` - -**Diagram sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L41-L82) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [config.ini](file://share/vizd/config/config.ini#L1-L10) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -**Section sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L1-L141) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L1-L262) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L355) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L1-L57) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [config.ini](file://share/vizd/config/config.ini#L1-L10) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -## Core Components -- Peer Database - - Stores potential peer records with endpoint, timestamps, connection disposition, counters, and last error - - Provides CRUD-like operations: open/close, clear, erase, update_entry, lookup_or_create_entry_for_endpoint, lookup_entry_for_endpoint, iterators - - Maintains a multi-index container keyed by endpoint and ordered by last_seen_time -- Node Discovery and Maintenance - - Connect loop selects peers based on retry timeouts and last disposition - - Periodic address requests refresh peer lists - - Inactivity watchdog disconnects idle peers - - Prunes stale entries and maintains database size limits -- P2P Plugin Integration - - Parses CLI options for p2p-endpoint, p2p-max-connections, p2p-seed-node - - Seeds initial connections and starts node listeners - -**Section sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L41-L186) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp](file://libraries/network/node.cpp#L1400-L1621) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) - -## Architecture Overview -The peer database underpins the node’s discovery and maintenance routines. The P2P plugin initializes the node, injects seed endpoints, and exposes configuration options. - -```mermaid -sequenceDiagram -participant CLI as "CLI/Config" -participant P2P as "p2p_plugin" -participant Node as "node" -participant DB as "peer_database" -participant Net as "Network" -CLI->>P2P : Parse p2p-endpoint, p2p-max-connections, p2p-seed-node -P2P->>Node : Construct node, load configuration -P2P->>Node : listen_on_endpoint(p2p-endpoint) -P2P->>Node : add_node(seed) -P2P->>Node : connect_to_endpoint(seed) -P2P->>Node : set_advanced_node_parameters(max connections) -P2P->>Node : listen_to_p2p_network() -P2P->>Node : connect_to_p2p_network() -Node->>DB : open(peers.json) -Node->>Net : Start connect loop -Net->>DB : Lookup candidate peers (ordered by last_seen_time) -Net->>Net : Retry policy based on last disposition and counters -Net->>Net : Periodic address requests to refresh peers -Net->>DB : Update entries on success/failure -Node->>DB : Close and persist on shutdown -``` - -**Diagram sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) - -## Detailed Component Analysis - -### Peer Database: Data Model and Operations -- Data model - - potential_peer_record fields: endpoint, last_seen_time, last_connection_disposition, last_connection_attempt_time, number_of_successful_connection_attempts, number_of_failed_connection_attempts, last_error - - Indexes: hashed endpoint for O(1) lookup; ordered last_seen_time for traversal -- Operations - - open(filename): loads JSON array of records; prunes to a maximum size - - close(): persists records to JSON - - update_entry(): insert or replace record by endpoint - - lookup_or_create_entry_for_endpoint(): return existing or new record - - lookup_entry_for_endpoint(): optional lookup - - begin()/end(): iterator over last_seen_time index - - size(): count of records - -```mermaid -classDiagram -class potential_peer_record { -+endpoint -+last_seen_time -+last_connection_disposition -+last_connection_attempt_time -+number_of_successful_connection_attempts -+number_of_failed_connection_attempts -+last_error -} -class peer_database { -+open(filename) -+close() -+clear() -+erase(endpoint) -+update_entry(record) -+lookup_or_create_entry_for_endpoint(endpoint) potential_peer_record -+lookup_entry_for_endpoint(endpoint) optional -+begin() iterator -+end() iterator -+size() size_t -} -class peer_database_impl { --potential_peer_set _potential_peer_set --path _peer_database_filename -+open() -+close() -+clear() -+erase() -+update_entry() -+lookup_or_create_entry_for_endpoint() -+lookup_entry_for_endpoint() -+begin() -+end() -+size() -} -peer_database --> peer_database_impl : "owns" -peer_database_impl --> potential_peer_record : "stores" -``` - -**Diagram sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L41-L82) - -**Section sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L186) - -### Peer Discovery and Connection Management -- Connect loop - - Iterates peers ordered by last_seen_time - - Applies retry policy based on last disposition and failed attempt counts - - Initiates connections when needed and updates records on outcomes -- Address exchange - - Periodically sends address_request_message and processes address_message to refresh peer lists - - Merges received addresses into the peer database -- Inactivity and pruning - - Disconnects inactive peers and sends keep-alives - - Prunes failed items cache periodically - - Database size capped at startup - -```mermaid -flowchart TD -Start(["Connect Loop Tick"]) --> CheckWants["Check desired/max connections"] -CheckWants --> |Need more| Iterate["Iterate peers ordered by last_seen_time"] -Iterate --> Candidate{"Candidate eligible?"} -Candidate --> |Yes| RetryDelay["Compute retry delay"] -RetryDelay --> Connect["connect_to_endpoint()"] -Connect --> Update["Update peer record on outcome"] -Update --> Next["Next candidate"] -Candidate --> |No| Next -Next --> Sleep["Sleep or wait for trigger"] -Sleep --> CheckWants -``` - -**Diagram sources** -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp](file://libraries/network/node.cpp#L1400-L1621) - -### P2P Plugin Initialization and Seed Configuration -- CLI options - - p2p-endpoint: local listen endpoint - - p2p-max-connections: maximum connections - - p2p-seed-node: bootstrap peers (supports multiple) -- Startup workflow - - Creates node, loads configuration directory - - Listens on endpoint, adds seeds, connects immediately - - Sets advanced parameters and starts network listeners - - Syncs from current head block - -```mermaid -sequenceDiagram -participant App as "Application" -participant P2P as "p2p_plugin" -participant Node as "node" -participant Seed as "Seed Endpoints" -App->>P2P : Initialize with CLI/config -P2P->>Node : new node(user_agent) -P2P->>Node : load_configuration(data_dir/p2p) -P2P->>Node : listen_on_endpoint(p2p-endpoint) -P2P->>Node : add_node(seed) x N -P2P->>Node : connect_to_endpoint(seed) x N -P2P->>Node : set_advanced_node_parameters(max connections) -P2P->>Node : listen_to_p2p_network() -P2P->>Node : connect_to_p2p_network() -P2P->>Node : sync_from(head_block, []) -``` - -**Diagram sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) - -**Section sources** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L467-L566) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [config.ini](file://share/vizd/config/config.ini#L1-L10) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -### Peer Address Validation and Reputation -- Validation - - Rejects self-connections and duplicates - - Validates chain_id and hard fork compatibility - - Verifies hello signatures and user data -- Reputation - - Tracks last_connection_disposition and attempt counters - - Uses last_seen_time ordering to prioritize fresh peers - - Records last_error on closure for diagnostics - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L2029-L2230) -- [node.cpp](file://libraries/network/node.cpp#L2251-L2280) -- [node.cpp](file://libraries/network/node.cpp#L3036-L3080) - -### Network Topology Maintenance and Diversity -- Load balancing - - Distributes item requests across peers based on idle status and pending requests - - Limits per-peer request volume during normal operation -- Diversity - - Periodic address requests from all active peers - - Merge logic updates last_seen_time for freshness - - Handshake and firewall detection influence inclusion decisions - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L1177-L1316) -- [node.cpp](file://libraries/network/node.cpp#L1844-L1860) -- [node.cpp](file://libraries/network/node.cpp#L2282-L2350) - -### Peer Selection Strategies and Recovery -- Selection - - Prefer peers with recent activity (last_seen_time) - - Respect retry timeouts and disposition to avoid stuck peers -- Recovery - - Re-trigger connect loop on new address information - - Periodic keep-alives and inactivity watchdogs - - Hard fork and chain_id checks to drop incompatible peers - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp](file://libraries/network/node.cpp#L2029-L2230) - -## Dependency Analysis -- peer_database depends on Boost.MultiIndex for composite indexing -- node integrates peer_database for discovery and persistence -- p2p_plugin orchestrates node lifecycle and seed injection -- Configuration and seed files feed the plugin and node - -```mermaid -graph LR -P2P["p2p_plugin.cpp"] --> Node["node.cpp"] -Node --> DB["peer_database.cpp"] -P2P --> CFG["config.ini"] -P2P --> Seed["seednodes"] -Node --> DB -``` - -**Diagram sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L41-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L10) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -**Section sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L566) -- [node.cpp](file://libraries/network/node.cpp#L952-L1047) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L41-L82) - -## Performance Considerations -- Database sizing - - Startup prune to a fixed maximum ensures bounded memory and IO -- Indexing - - Hashed endpoint index for fast updates/lookups - - Ordered last_seen_time index for fair rotation and freshness -- Connection scheduling - - Retry delays scale with failed attempts to reduce churn -- Request distribution - - Per-peer caps and idle checks prevent hot-spotting and improve throughput - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Peer database fails to load or corrupt - - The loader logs and continues with a clean database; inspect logs for errors -- Frequent rejections or timeouts - - Review last_connection_disposition and counters; adjust retry timeouts -- Stale peers overwhelming discovery - - Verify last_seen_time updates on address exchange and pruning -- Inactivity disconnects - - Confirm keep-alive messages and inactivity thresholds - -**Section sources** -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L114-L118) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp](file://libraries/network/node.cpp#L1400-L1621) - -## Conclusion -The peer database and discovery system combines a compact, indexed record store with robust connection orchestration. Together with the P2P plugin’s seed configuration, it provides resilient network bootstrapping, continuous topology refresh, and operational safeguards against stale or hostile peers. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Database Schema Notes -- File: peers.json (loaded at node startup; saved on shutdown) -- Fields: endpoint, last_seen_time, last_connection_disposition, last_connection_attempt_time, number_of_successful_connection_attempts, number_of_failed_connection_attempts, last_error -- Indexes: endpoint (hashed), last_seen_time (ordered) - -**Section sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) - -### Example Workflows - -- Peer database initialization - - Open: load peers.json; prune to maximum size - - Close: persist records to peers.json - -- Peer lookup operations - - lookup_or_create_entry_for_endpoint(endpoint) - - lookup_entry_for_endpoint(endpoint) - - Iterate over begin()/end() ordered by last_seen_time - -- Network discovery workflow - - Periodic address_request_message - - Merge received addresses into peer database - - Trigger connect loop on new information - -**Section sources** -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) -- [node.cpp](file://libraries/network/node.cpp#L1623-L1654) -- [node.cpp](file://libraries/network/node.cpp#L2307-L2350) - -### Backup and Migration Guidance -- Backup - - Copy peers.json from the node’s configuration directory before upgrades or restores -- Migration - - Ensure schema compatibility; if fields change, maintain backward-compatible parsing and prune as needed -- Maintenance - - Monitor prune behavior at startup and manual cleanup via clear() when debugging - -**Section sources** -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L284-L288) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Transport Layer and Sockets.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Transport Layer and Sockets.md deleted file mode 100644 index c03e750808..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Network Library/Transport Layer and Sockets.md +++ /dev/null @@ -1,349 +0,0 @@ -# Transport Layer and Sockets - - -**Referenced Files in This Document** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [node.cpp](file://libraries/network/node.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the Transport Layer and Sockets implementation for secure TCP communication in the project. It focuses on the stcp_socket class that provides encrypted messaging over TCP using Elliptic Curve Diffie-Hellman (ECDH) key exchange and AES encryption. It covers secure connection establishment, shared secret derivation, buffered I/O, lifecycle management, and integration with higher-level components such as message-oriented connections and peer connections. It also documents configuration options, buffer management, performance characteristics, error handling, recovery, and operational guidance for debugging and tuning. - -## Project Structure -The transport stack is organized into layered components: -- stcp_socket: Secure socket wrapper over TCP with ECDH key exchange and AES encryption. -- message_oriented_connection: Stream-based message framing over stcp_socket. -- peer_connection: Peer session manager that orchestrates handshake, negotiation, and message queuing. -- node: Top-level orchestrator managing peers, connection pools, and lifecycle. - -```mermaid -graph TB -subgraph "Transport Layer" -STCP["stcp_socket
ECDH + AES over TCP"] -MOC["message_oriented_connection
Message framing over stcp_socket"] -PC["peer_connection
Peer session & negotiation"] -N["node
Peer pool & lifecycle"] -end -N --> PC -PC --> MOC -MOC --> STCP -``` - -**Diagram sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [node.cpp](file://libraries/network/node.cpp#L424-L837) - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [node.cpp](file://libraries/network/node.cpp#L424-L837) - -## Core Components -- stcp_socket: Provides secure I/O over TCP with ECDH key exchange and AES encryption. It exposes read/write methods aligned to AES block sizes, maintains shared secrets, and integrates with fc::tcp_socket. -- message_oriented_connection: Wraps stcp_socket to deliver a stream of framed messages, handling padding, buffering, and read/write loops. -- peer_connection: Manages peer sessions, negotiates connection states, queues outgoing messages, and coordinates with message_oriented_connection. -- node: Maintains a pool of active peers, controls connection lifecycle, and enforces policies such as desired/max connections and timeouts. - -Key responsibilities: -- stcp_socket: Key exchange, shared secret derivation, AES encoder/decoder initialization, buffered read/write with alignment to AES blocks, and socket lifecycle. -- message_oriented_connection: Message framing, padding to 16-byte boundaries, read loop, send loop, and connection metrics. -- peer_connection: Session state machine, message queuing, rate limiting, and graceful close. -- node: Peer discovery, connection orchestration, and termination policies. - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L192) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L208-L242) -- [node.cpp](file://libraries/network/node.cpp#L424-L837) - -## Architecture Overview -The secure transport pipeline: -- TCP socket is established. -- ECDH key exchange is performed to derive a shared secret. -- AES encoders/decoders are initialized from the shared secret. -- Messages are framed and padded to 16-byte boundaries for AES streaming mode. -- Read/write loops handle encrypted I/O and maintain throughput. - -```mermaid -sequenceDiagram -participant Client as "peer_connection" -participant MOC as "message_oriented_connection" -participant STCP as "stcp_socket" -participant TCP as "TCP Socket" -Client->>MOC : connect_to(endpoint) -MOC->>STCP : connect_to(endpoint) -STCP->>TCP : connect_to(endpoint) -STCP->>TCP : write(public_key) -TCP-->>STCP : read(public_key) -STCP->>STCP : derive shared secret (ECDH) -STCP->>STCP : init AES encoders/decoders -MOC->>MOC : start read_loop() -Client->>MOC : send_message(msg) -MOC->>STCP : write(padded_msg) -STCP->>TCP : write(ciphertext) -TCP-->>STCP : read(ciphertext) -STCP->>MOC : decode plaintext -MOC-->>Client : on_message(msg) -``` - -**Diagram sources** -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L72) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L135-L145) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L208-L242) - -## Detailed Component Analysis - -### stcp_socket: Secure TCP Wrapper -Responsibilities: -- Establish TCP connection and perform ECDH key exchange. -- Derive shared secret and initialize AES encoder/decoder for bidirectional encryption. -- Provide read/write methods aligned to AES block size (16 bytes) with internal buffering. -- Expose shared secret for higher-level protocols and integrate with fc::tcp_socket. - -Implementation highlights: -- Key exchange: Generates ephemeral EC private key, serializes public key, exchanges with peer, and computes shared secret. -- Encryption: Initializes AES encoders/decoders using derived shared secret for confidentiality. -- Read path: Ensures reads are aligned to 16-byte boundaries, buffers leftover data, and decrypts into caller’s buffer. -- Write path: Pads plaintext to 16-byte boundaries, encrypts, and writes ciphertext. -- Lifecycle: Connect/bind/accept/close with proper exception handling. - -```mermaid -classDiagram -class stcp_socket { -+stcp_socket() -+~stcp_socket() -+get_socket() tcp_socket& -+accept() -+connect_to(endpoint) -+bind(endpoint) -+readsome(buffer, len) size_t -+readsome(buf, len, offset) size_t -+eof() bool -+writesome(buffer, len) size_t -+writesome(buf, len, offset) size_t -+flush() -+close() -+get_shared_secret() sha512 --do_key_exchange() --_shared_secret : sha512 --_priv_key : private_key --_buf : array --_sock : tcp_socket --_send_aes : aes_encoder --_recv_aes : aes_decoder --_read_buffer : shared_ptr --_write_buffer : shared_ptr -} -``` - -**Diagram sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L192) - -### message_oriented_connection: Message Framing Over stcp_socket -Responsibilities: -- Frame messages with headers and pad to 16-byte boundaries. -- Manage read loop to receive complete messages and dispatch to delegate. -- Track connection metrics (bytes sent/received, timestamps). -- Provide access to underlying stcp_socket and shared secret. - -Key behaviors: -- Padding: Rounds payload size to nearest 16-byte boundary to align with AES block size. -- Read loop: Reads fixed header, validates size, reads remainder, trims padding, and invokes delegate. -- Send loop: Copies message header and data into padded buffer, writes to stcp_socket, flushes. - -```mermaid -flowchart TD -Start(["send_message(msg)"]) --> Pad["Compute padded size to multiple of 16"] -Pad --> Build["Copy header + data into padded buffer"] -Build --> WriteSock["Write padded buffer to stcp_socket"] -WriteSock --> Flush["Flush to ensure delivery"] -Flush --> UpdateStats["Update bytes_sent + last_message_sent_time"] -UpdateStats --> End(["Return"]) -%% Read loop -RStart(["read_loop()"]) --> ReadHeader["Read fixed header (16 bytes)"] -ReadHeader --> ValidateSize{"Validate size <= MAX_MESSAGE_SIZE"} -ValidateSize --> |No| Error["Throw exception"] -ValidateSize --> |Yes| ReadRemainder["Read remaining padded payload"] -ReadRemainder --> Trim["Trim padding to original size"] -Trim --> Dispatch["Delegate.on_message(msg)"] -Dispatch --> LoopBack["Continue read_loop()"] -``` - -**Diagram sources** -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L237-L283) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) - -**Section sources** -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L237-L283) - -### peer_connection: Peer Session Management -Responsibilities: -- Orchestrate connection lifecycle: bind/connect, accept, negotiate, and close. -- Queue and send messages via message_oriented_connection. -- Track connection states, metrics, and peer identity. -- Integrate with node for peer pool management. - -Notable behaviors: -- Connection states: Enumerated states for “our” and “their” sides, plus negotiation statuses. -- Outgoing connections: Initiates bind/connect, transitions negotiation status, and logs successful connection. -- Incoming connections: Accepts via message_oriented_connection, performs key exchange, and transitions states. -- Graceful close: Sets negotiation status, closes underlying connection, and schedules deletion. - -```mermaid -stateDiagram-v2 -[*] --> Disconnected -Disconnected --> Connecting : "connect_to()" -Disconnected --> Accepting : "accept_connection()" -Connecting --> Connected : "connect_to() succeeds" -Accepting --> Accepted : "accept() succeeds" -Connected --> HelloSent : "send hello" -Accepted --> HelloSent : "send hello" -HelloSent --> NegotiationComplete : "exchange complete" -NegotiationComplete --> Closing : "close_connection()" -Closing --> Closed : "destroy_connection()" -Closed --> [*] -``` - -**Diagram sources** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L208-L242) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L356-L369) - -**Section sources** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L208-L242) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L356-L369) - -### node: Peer Pool and Lifecycle Management -Responsibilities: -- Maintain sets of handshaking, active, closing, and terminating connections. -- Enforce connection limits, retry policies, and inactivity timeouts. -- Trigger connect loops, advertise inventory, and manage bandwidth. - -Operational highlights: -- Connection limits: Desired and maximum connection counts influence connect loop behavior. -- Inactivity handling: Disconnects peers that exceed configured inactivity thresholds. -- Bandwidth monitoring: Tracks average read/write speeds and updates periodically. - -**Section sources** -- [node.cpp](file://libraries/network/node.cpp#L424-L837) -- [node.cpp](file://libraries/network/node.cpp#L1400-L1599) - -## Dependency Analysis -The transport stack composes tightly around fc::tcp_socket and fc crypto primitives: -- stcp_socket depends on fc::tcp_socket, fc::ecc::private_key, fc::sha512, fc::aes_encoder, fc::aes_decoder. -- message_oriented_connection depends on stcp_socket and message framing logic. -- peer_connection depends on message_oriented_connection and node for lifecycle. -- node orchestrates peer_connection instances and enforces policies. - -```mermaid -graph LR -TCP["fc::tcp_socket"] --> STCP["stcp_socket"] -ECC["fc::ecc::private_key"] --> STCP -SHA["fc::sha512"] --> STCP -AES["fc::aes_encoder / aes_decoder"] --> STCP -STCP --> MOC["message_oriented_connection"] -MOC --> PC["peer_connection"] -PC --> N["node"] -``` - -**Diagram sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L26-L28) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L66) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L26-L27) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L28-L29) -- [node.cpp](file://libraries/network/node.cpp#L527-L528) - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L26-L28) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L66) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L26-L27) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L28-L29) -- [node.cpp](file://libraries/network/node.cpp#L527-L528) - -## Performance Considerations -- Buffering: Internal buffers of fixed size (e.g., 4096 bytes) are reused for read/write to reduce allocations. -- Alignment: Read/write sizes are constrained to 16-byte multiples to satisfy AES block cipher requirements. -- Padding: Messages are padded to 16-byte boundaries; ensure message sizes are planned accordingly to minimize overhead. -- Throughput: The read loop reads fixed header size first, then remainder in chunks; batching messages can improve efficiency. -- Concurrency: Assertions guard single-threaded usage of read/write buffers; concurrent calls are not supported without modifications. - -Recommendations: -- Tune message sizes to align with 16-byte boundaries to avoid extra padding overhead. -- Monitor bytes_sent/bytes_received metrics exposed by message_oriented_connection to track throughput. -- Adjust node-level connection limits and retry timeouts to balance connectivity and resource usage. - -**Section sources** -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L107-L121) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L156-L173) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L237-L283) -- [node.cpp](file://libraries/network/node.cpp#L869-L902) - -## Troubleshooting Guide -Common issues and remedies: -- Handshake failures: Verify ECDH key exchange completes; inspect exceptions thrown during connect/accept. -- Read/write errors: Ensure readsome/writesome are called with 16-byte aligned lengths; check for EOF conditions. -- Connection drops: Review inactivity timeout logic and peer closure reasons; confirm graceful close sequences. -- Resource leaks: Confirm destroy_connection cancels read loops and closes sockets; verify peer deletion tasks complete. - -Operational tips: -- Enable logging around read_loop and send_message to capture exceptions and disconnections. -- Inspect shared secret availability via message_oriented_connection::get_shared_secret for debugging. -- Use node-level statistics and bandwidth monitors to diagnose performance regressions. - -**Section sources** -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L148-L235) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L285-L313) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L106-L157) -- [node.cpp](file://libraries/network/node.cpp#L1400-L1599) - -## Conclusion -The transport layer integrates a robust secure socket abstraction with message-oriented framing to deliver encrypted, reliable peer-to-peer communication. stcp_socket encapsulates ECDH key exchange and AES encryption, while message_oriented_connection ensures proper message framing and buffered I/O. Together with peer_connection and node, the system provides lifecycle management, connection pooling, and operational resilience. Following the guidance herein will help you deploy, tune, and troubleshoot secure TCP communications effectively. - -## Appendices - -### Security Features and Best Practices -- Encryption: AES-based symmetric encryption initialized from ECDH-derived shared secret. -- Authentication: Public keys exchanged during handshake; shared secret confirms mutual participation. -- Integrity: AES streaming mode with padding; ensure message size validation and bounds checking. -- Best practices: - - Keep shared secrets ephemeral and derive per-connection. - - Validate message sizes against maximum allowed limits. - - Use node-level policies to enforce connection limits and timeouts. - - Log and monitor connection states and metrics for anomaly detection. - -**Section sources** -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp#L49-L66) -- [message_oriented_connection.cpp](file://libraries/network/message_oriented_connection.cpp#L168-L170) -- [node.cpp](file://libraries/network/node.cpp#L869-L902) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Authority Management.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Authority Management.md deleted file mode 100644 index e6bcbf8f6d..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Authority Management.md +++ /dev/null @@ -1,404 +0,0 @@ -# Authority Management - - -**Referenced Files in This Document** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp) -- [authority.cpp](file://libraries/protocol/authority.cpp) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the Authority Management subsystem responsible for permission systems and access control in the blockchain. It covers: -- Authority structures and thresholds -- Weight calculations and validation -- Multi-signature authority requirements -- Permission hierarchies (master, active, regular) -- Signature validation and authority checking during transaction processing via sign_state -- Authority inheritance patterns and delegation -- Relationship between authorities and operations requiring specific permissions - -## Project Structure -The authority system spans protocol-level definitions and chain-level persistence and usage: -- Protocol-level authority definitions and helpers -- Transaction signing and authority checking -- Shared-memory compatible authority representation -- Account authority storage and hierarchical roles -- Operation definitions specifying which authorities are required - -```mermaid -graph TB -subgraph "Protocol Layer" -A["authority.hpp
authority.cpp"] -S["sign_state.hpp
sign_state.cpp"] -T["types.hpp"] -O["operations.hpp"] -CO["chain_operations.hpp"] -end -subgraph "Chain Layer" -SA["shared_authority.hpp"] -AO["account_object.hpp"] -end -A --> S -T --> A -O --> CO -CO --> A -SA --> AO -SA --> A -AO --> A -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [authority.cpp](file://libraries/protocol/authority.cpp#L1-L228) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L1-L107) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L1-L235) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L1-L113) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L565) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L200) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [authority.cpp](file://libraries/protocol/authority.cpp#L1-L228) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L1-L107) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L1-L235) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L1-L113) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L565) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L200) - -## Core Components -- Authority: A permission container combining weighted account and key authorities with a numeric threshold. Provides helpers to add authorities, compute weights, validate, and detect impossibilities. -- Sign State: Validates signatures and checks authority requirements against provided keys and approvals, recursively resolving nested authorities up to a configured depth. -- Types: Defines public key, account name, weight, and related types used by authorities. -- Shared Authority: A shared-memory-compatible variant of authority for persistent storage. -- Account Authority Object: Stores hierarchical authorities (master, active, regular) per account. -- Operations: Define which authorities are required for each operation (active/master/regular). - -Key responsibilities: -- Build and validate authority structures -- Enforce threshold-based multi-signature checks -- Resolve nested authorities via delegation -- Integrate with transaction signing and evaluation - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [authority.cpp](file://libraries/protocol/authority.cpp#L7-L48) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L6-L59) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L147) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L99) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) - -## Architecture Overview -Authority management integrates at three layers: -- Protocol-level definitions and helpers -- Transaction signing/validation pipeline -- Chain-level persistence and retrieval - -```mermaid -sequenceDiagram -participant OP as "Operation" -participant AU as "Authority (protocol)" -participant SS as "Sign State" -participant DB as "Account Authority Store" -OP->>AU : "Define required authorities" -OP->>SS : "Provide provided signatures/approvals" -SS->>DB : "Resolve active/master/regular authorities" -SS->>AU : "Check key weights vs threshold" -SS->>AU : "Recurse for account authorities" -AU-->>SS : "Pass/Fail" -SS-->>OP : "Final authority validation result" -``` - -**Diagram sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L19-L59) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) - -## Detailed Component Analysis - -### Authority Structure and Threshold Validation -The authority structure holds: -- A numeric threshold -- Two maps: account authorities (name -> weight) and key authorities (public key -> weight) - -Core behaviors: -- Add authorities for accounts and keys -- Compute total weight from included keys and accounts -- Detect impossible authorities (total weight below threshold) -- Validate account names -- Equality comparison - -Weight calculation and threshold validation: -- Sum weights from included keys and accounts -- Compare sum against threshold to decide pass/fail -- Early exit when threshold is met - -```mermaid -flowchart TD -Start(["Authority.validate"]) --> ForEachAcc["Iterate account_auths"] -ForEachAcc --> AccValid{"Account name valid?"} -AccValid --> |No| Fail["Fail validation"] -AccValid --> |Yes| NextKeys["Iterate key_auths"] -NextKeys --> SumWeights["Sum weights from accounts and keys"] -SumWeights --> CheckThreshold{"Total weight >= threshold?"} -CheckThreshold --> |Yes| Pass["Pass"] -CheckThreshold --> |No| Impossible["Impossible (below threshold)"] -``` - -**Diagram sources** -- [authority.cpp](file://libraries/protocol/authority.cpp#L44-L48) -- [authority.cpp](file://libraries/protocol/authority.cpp#L24-L33) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [authority.cpp](file://libraries/protocol/authority.cpp#L7-L48) - -### Multi-Signature Authority Requirements and Hierarchies -Hierarchical authorities per account: -- Master: typically backup control, can set master or active -- Active: monetary operations, can set active or regular -- Regular: voting and regular actions - -Operations specify which authorities are required: -- Some operations require active/master/regular -- Others require regular or none depending on payload - -```mermaid -classDiagram -class Authority { -+uint32_t weight_threshold -+account_authority_map account_auths -+key_authority_map key_auths -+add_authority(public_key_type, weight_type) -+add_authority(account_name_type, weight_type) -+get_keys() vector -+is_impossible() bool -+num_auths() uint32_t -+clear() void -+validate() void -} -class AccountAuthorityObject { -+account_name_type account -+shared_authority master -+shared_authority active -+shared_authority regular -} -class Operation { -+get_required_active_authorities(flat_set) -+get_required_master_authorities(flat_set) -+get_required_regular_authorities(flat_set) -} -AccountAuthorityObject --> Authority : "stores" -Operation --> Authority : "requires" -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) - -**Section sources** -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L99) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) - -### Signature Validation and Authority Checking via Sign State -Sign state orchestrates: -- Determining whether a key has been signed or can be produced -- Resolving account authorities via callbacks -- Recursively validating nested authorities up to a maximum recursion depth -- Tracking used and unused signatures/approvals - -Workflow: -- For each key authority, mark as signed if present in provided signatures or available keys -- For each account authority, resolve active authority and recurse if depth allows -- Accumulate weights and compare to threshold - -```mermaid -sequenceDiagram -participant TX as "Transaction" -participant SS as "Sign State" -participant AK as "Provided Keys" -participant AG as "Authority Getter" -participant AU as "Authority" -TX->>SS : "Initialize with provided signatures and keys" -SS->>AK : "Check availability" -SS->>AG : "Get active authority for account" -SS->>AU : "Check key weights" -SS->>AU : "Recurse for account authorities (depth-limited)" -SS-->>TX : "Pass/Fail" -``` - -**Diagram sources** -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L6-L59) - -**Section sources** -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L6-L59) - -### Authority Inheritance Patterns and Delegation -- Accounts maintain separate authorities for master, active, and regular roles -- Operations may require one or more of these roles -- Nested authority resolution occurs when an authority includes account names; sign_state resolves those accounts’ active authorities recursively up to a configured depth -- Shared authority enables persistent storage in shared memory - -```mermaid -flowchart TD -Req["Operation requires role X"] --> HasRole{"Account has role X?"} -HasRole --> |No| Fail["Reject"] -HasRole --> |Yes| CheckAuth["Load authority X"] -CheckAuth --> Keys["Check provided key weights"] -CheckAuth --> Accounts["Resolve account authorities (recursive)"] -Keys --> Threshold{"Meets threshold?"} -Accounts --> Threshold -Threshold --> |Yes| Approve["Approve"] -Threshold --> |No| Fail -``` - -**Diagram sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L28-L59) - -**Section sources** -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L20-L99) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L28-L59) - -### Custom Authority Types and Name Validation -- Public key and account name types are defined with strict validation rules -- Account name validation enforces length, character sets, and domain-like naming rules -- Domain name validation supports hierarchical naming patterns - -```mermaid -flowchart TD -N["Input name"] --> Len["Check length bounds"] -Len --> |Invalid| Reject["Reject"] -Len --> |Valid| Parts["Split by '.'"] -Parts --> EachPart["Validate each label"] -EachPart --> Chars["Chars allowed and positions"] -Chars --> |Invalid| Reject -Chars --> |Valid| Accept["Accept"] -``` - -**Diagram sources** -- [authority.cpp](file://libraries/protocol/authority.cpp#L66-L218) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L147) - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L147) -- [authority.cpp](file://libraries/protocol/authority.cpp#L50-L218) - -### Examples of Authority Configuration and Permission Scenarios -- Creating an account with master/active/regular authorities -- Updating an account’s authorities -- Performing a transfer requiring active/master authority depending on asset type -- Voting and content operations requiring regular authority - -These examples demonstrate: -- How authorities are attached to operations -- How thresholds and weights influence pass/fail -- How recursive resolution works when authorities include account names - -**Section sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L62) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -## Dependency Analysis -Authority management depends on: -- Types for cryptographic keys, account names, and weights -- Shared authority for persistent storage -- Account authority objects for role storage -- Operations for declaring required authorities - -```mermaid -graph LR -T["types.hpp"] --> A["authority.hpp"] -A --> S["sign_state.hpp"] -A --> SA["shared_authority.hpp"] -SA --> AO["account_object.hpp"] -CO["chain_operations.hpp"] --> A -O["operations.hpp"] --> CO -``` - -**Diagram sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L147) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L1-L113) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L565) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L200) - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L147) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [shared_authority.hpp](file://libraries/chain/include/graphene/chain/shared_authority.hpp#L1-L113) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L1-L565) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L200) - -## Performance Considerations -- Threshold short-circuit: weight accumulation stops once threshold is met -- Recursion depth limit prevents deep cycles and protects evaluation time -- Efficient maps and sets minimize lookup costs -- Shared authority reduces allocation overhead in persistent contexts - -## Troubleshooting Guide -Common issues and resolutions: -- Impossible authority: total weight below threshold; adjust weights or reduce threshold -- Invalid account names: ensure names meet length and character constraints -- Missing signatures/approvals: ensure provided keys match authority keys and required approvals are recorded -- Excessive recursion: verify nested authorities do not exceed configured depth - -**Section sources** -- [authority.cpp](file://libraries/protocol/authority.cpp#L24-L33) -- [authority.cpp](file://libraries/protocol/authority.cpp#L77-L218) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L41-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L61-L91) - -## Conclusion -Authority Management provides a robust, extensible framework for permission control: -- Clear separation of roles (master, active, regular) -- Threshold-based multi-signature enforcement -- Recursive authority resolution with depth limits -- Persistent storage support via shared authority -- Tight integration with operations and transaction signing - -## Appendices -- Data model summary: - - Authority: threshold, account_auths, key_auths - - Account Authority Object: master, active, regular authorities - - Sign State: provided signatures, approved by, recursion depth - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp#L145-L165) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Block Structures.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Block Structures.md deleted file mode 100644 index 8515728009..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Block Structures.md +++ /dev/null @@ -1,396 +0,0 @@ -# Block Structures - - -**Referenced Files in This Document** -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp) -- [block.cpp](file://libraries/protocol/block.cpp) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the blockchain block format and consensus mechanisms in the VIZ C++ node. It focuses on: -- Block header structure and metadata -- Transaction inclusion and Merkle root computation -- validator signature validation and block hashing -- Validation rules for blocks (Merkle root, validator signature, fork resolution) -- Block production and propagation workflows -- Network synchronization and state progression - -## Project Structure -The block-related logic spans protocol-level definitions and chain-level validation and persistence: -- Protocol-level block definitions and cryptographic helpers -- Chain-level validation, fork management, and block logging -- validator scheduling and participation metrics - -```mermaid -graph TB -subgraph "Protocol Layer" -P_Block["block.hpp"] -P_Header["block_header.hpp"] -P_Impl["block.cpp"] -P_Types["types.hpp"] -end -subgraph "Chain Layer" -C_DB_API["database.hpp"] -C_DB_IMPL["database.cpp"] -C_Fork["fork_database.hpp"] -C_Log["block_log.hpp"] -C_Wit["witness_objects.hpp"] -end -P_Block --> P_Impl -P_Header --> P_Impl -P_Types --> P_Impl -P_Block --> C_DB_API -P_Header --> C_DB_API -C_DB_API --> C_DB_IMPL -C_DB_IMPL --> C_Fork -C_DB_IMPL --> C_Log -C_DB_IMPL --> C_Wit -``` - -**Diagram sources** -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L105-L110) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L200) - -**Section sources** -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L105-L110) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L200) - -## Core Components -- Block header and signed header: define block metadata, hash computation, and validator signature validation. -- Signed block: extends the signed header with a transaction list and Merkle root calculation. -- Types: defines cryptographic primitives used by blocks and transactions. -- Fork database: manages unlinked and linked forks, head selection, and branch resolution. -- Database validation pipeline: validates block headers, Merkle roots, sizes, and validator scheduling; pushes blocks and updates state. -- Block log: persists blocks to disk for replay and synchronization. -- validator objects: track scheduling eligibility, participation, and penalties. - -**Section sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L35) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [block.cpp](file://libraries/protocol/block.cpp#L6-L64) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L105-L110) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) - -## Architecture Overview -The block lifecycle integrates protocol definitions, validation, persistence, and consensus: -- Protocol layer defines block structures and cryptographic helpers. -- Chain layer validates incoming blocks against local state and schedules. -- Fork database resolves competing chains and selects the heaviest branch. -- Block log persists blocks and supports fast random access by number. -- validator objects enforce scheduling and participation rules. - -```mermaid -sequenceDiagram -participant Peer as "Peer" -participant DB as "database.cpp" -participant Fork as "fork_database.hpp" -participant Log as "block_log.hpp" -Peer->>DB : "Push signed_block" -DB->>DB : "validate_block()" -DB->>Fork : "push_block(new_block)" -Fork-->>DB : "new_head" -DB->>DB : "apply_block() if needed" -DB->>Log : "append(block) on success" -DB-->>Peer : "result" -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L800-L925) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L91) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L50-L56) - -## Detailed Component Analysis - -### Block Header and Hashing -- The block header contains previous block identifier, timestamp, validator name, and the transaction Merkle root. -- The signed block header adds the validator signature and exposes signing and validation helpers. -- The block ID is derived from a compact hash with the block number embedded. - -```mermaid -classDiagram -class block_header { -+block_id_type previous -+time_point_sec timestamp -+string validator -+checksum_type transaction_merkle_root -+digest() digest_type -+num_from_id(id) uint32_t -} -class signed_block_header { -+block_id_type id() -+public_key signee() -+void sign(signer) -+bool validate_signee(expected) -+signature_type witness_signature -} -class signed_block { -+vector~signed_transaction~ transactions -+calculate_merkle_root() checksum_type -} -signed_block_header --|> block_header -signed_block --|> signed_block_header -``` - -**Diagram sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L35) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [block.cpp](file://libraries/protocol/block.cpp#L6-L33) - -**Section sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L35) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [block.cpp](file://libraries/protocol/block.cpp#L6-L33) - -### Merkle Root Computation -- The Merkle root is computed from transaction digests using a standard binary hash tree. -- The computation is exposed by the signed block and compared against the header’s Merkle root during validation. - -```mermaid -flowchart TD -Start(["Start calculate_merkle_root"]) --> Empty{"transactions empty?"} -Empty --> |Yes| Zero["Return zero checksum"] -Empty --> |No| Init["Init ids[] with tx.merkle_digest()"] -Init --> Loop["While current_number_of_hashes > 1"] -Loop --> Pair["Hash IDs in pairs"] -Pair --> Next["Advance indices"] -Next --> Done{"Done this round?"} -Done --> |No| Loop -Done --> |Yes| Reduce["Reduce to k elements"] -Reduce --> Loop -Loop --> Single{"== 1?"} -Single --> |Yes| HashEnd["Hash last digest"] -Single --> |No| Loop -HashEnd --> Cast["Cast to checksum_type"] -Cast --> End(["Return Merkle root"]) -``` - -**Diagram sources** -- [block.cpp](file://libraries/protocol/block.cpp#L35-L64) - -**Section sources** -- [block.cpp](file://libraries/protocol/block.cpp#L35-L64) - -### Block Validation Rules -- Merkle root verification: The computed Merkle root must match the header’s field. -- Block size check: Enforced against dynamic global properties. -- validator signature validation: The validator signature must be recoverable to the expected signing key. -- validator scheduling: The block must be produced by the scheduled validator for the slot derived from the timestamp. -- Fork resolution: If the new block does not extend the current head, the fork database chooses the heaviest chain and replays or undoes blocks as needed. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant FH as "validate_block_header" -participant Fork as "fork_database.hpp" -DB->>DB : "validate_block(new_block)" -DB->>DB : "calculate_merkle_root()" -DB->>DB : "compare with header" -DB->>FH : "validate_signee(validator.signing_key)" -FH-->>DB : "ok" -DB->>DB : "check scheduled validator" -DB->>Fork : "push_block(new_block)" -Fork-->>DB : "new_head" -DB->>DB : "apply_block() if needed" -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L737-L792) -- [database.cpp](file://libraries/chain/database.cpp#L3724-L3747) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L91) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L737-L792) -- [database.cpp](file://libraries/chain/database.cpp#L3724-L3747) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L91) - -### Block Production and Propagation -- Block production is governed by validator scheduling and participation. The validator that produces a block is determined by the slot derived from the block timestamp and the validator schedule. -- Propagation occurs when peers receive blocks and validate them before pushing to their chain. -- Persistence is handled by the block log, which stores blocks in an append-only manner and supports random access by block number. - -```mermaid -sequenceDiagram -participant W as "validator" -participant Net as "Network" -participant Node as "database.cpp" -participant Log as "block_log.hpp" -W->>W : "produce signed_block" -W->>Net : "broadcast block" -Net->>Node : "receive block" -Node->>Node : "validate_block()" -Node->>Log : "append(block)" -Node-->>Net : "accepted" -``` - -**Diagram sources** -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L50-L56) - -**Section sources** -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L50-L56) - -### Fork Resolution Criteria -- The fork database maintains linked forks and selects the head based on the longest chain. -- When a new block does not extend the current head, the system computes branches from the new head and current head, pops blocks from the current chain until the fork point, and replays blocks from the new branch. -- Invalid blocks are removed and the head restored to the previous valid state. - -```mermaid -flowchart TD -A["New block received"] --> B["fork_db.push_block()"] -B --> C{"new_head extends current head?"} -C --> |Yes| D["apply_block()"] -C --> |No| E["fetch_branch_from(new_head, head)"] -E --> F["pop blocks until fork point"] -F --> G["push blocks from new fork"] -G --> H["success"] -E --> I["exception"] -I --> J["remove invalid blocks"] -J --> K["restore head to previous valid"] -K --> L["abort"] -``` - -**Diagram sources** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L91) -- [database.cpp](file://libraries/chain/database.cpp#L847-L925) - -**Section sources** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L78-L91) -- [database.cpp](file://libraries/chain/database.cpp#L847-L925) - -### Relationship Between Blocks and Blockchain State Progression -- Dynamic global properties are updated per block, including head block number/id, timestamp, participation metrics, and reserve ratios. -- validator participation and penalties are tracked; missed blocks increment counters and can lead to penalties and potential shutdown of inactive validators. -- The irreversible block number advances when sufficient validator validations reach consensus thresholds. - -```mermaid -flowchart TD -S["Start apply_block"] --> U["update_global_dynamic_data()"] -U --> P["compute missed_blocks and participation"] -P --> W["modify validator stats (missed, penalties)"] -W --> D["update dgp fields (head, time, sizes)"] -D --> IR["check irreversible threshold"] -IR --> E["advance last_irreversible_block_num if met"] -E --> F["persist via block_log"] -F --> T["End"] -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L3759-L3873) -- [database.cpp](file://libraries/chain/database.cpp#L3875-L3899) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3759-L3873) -- [database.cpp](file://libraries/chain/database.cpp#L3875-L3899) - -## Dependency Analysis -- Protocol definitions depend on cryptographic types and reflection macros. -- Chain validation depends on protocol structures, fork database, and block log. -- validator objects provide scheduling and participation data used by validation. - -```mermaid -graph LR -Types["types.hpp"] --> Header["block_header.hpp"] -Header --> Block["block.hpp"] -Block --> Impl["block.cpp"] -Impl --> DBAPI["database.hpp"] -DBAPI --> DBIMPL["database.cpp"] -DBIMPL --> Fork["fork_database.hpp"] -DBIMPL --> Log["block_log.hpp"] -DBIMPL --> Wit["witness_objects.hpp"] -``` - -**Diagram sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L105-L110) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L200) - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L105-L110) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp](file://libraries/chain/database.cpp#L737-L929) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L1-L200) - -## Performance Considerations -- Merkle root computation is O(n log n) for n transactions due to the binary hash tree. -- Fork resolution involves popping and pushing blocks; keep the maximum reordering window reasonable to avoid excessive memory and CPU usage. -- Block size checks prevent oversized blocks from consuming resources. -- validator participation metrics and penalties help maintain network health and reduce spam. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common validation failures and remedies: -- Merkle mismatch: Verify transaction ordering and ensure the Merkle root is recomputed consistently. -- validator signature mismatch: Confirm the validator signing key matches the expected key and that the digest used for signing is correct. -- Incorrect validator scheduling: Ensure the block timestamp yields the correct slot and that the scheduled validator matches the block producer. -- Fork conflicts: Investigate why the new block did not extend the current head; check timestamps, validator assignments, and fork database logs. -- Disk or memory errors during block push: The system attempts to resize shared memory on allocation failure; ensure adequate disk space and memory. - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L757-L792) -- [database.cpp](file://libraries/chain/database.cpp#L3724-L3747) -- [database.cpp](file://libraries/chain/database.cpp#L847-L925) - -## Conclusion -Blocks in the VIZ node are defined by a clear protocol structure, validated rigorously by the chain layer, and persisted for resilience. Consensus relies on deterministic validator scheduling, strict signature validation, and robust fork resolution. Understanding these components enables reliable block construction, validation, propagation, and synchronization across the network. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Example Workflows -- Constructing a block: Build a signed block with transactions, compute the Merkle root, populate the header fields, and sign with the validator key. -- Validating a block: Compute the Merkle root, compare against the header; verify the validator signature; confirm the scheduled validator; enforce block size limits. -- Resolving a fork: Use the fork database to select the heaviest chain; if necessary, pop blocks from the current chain and push blocks from the new fork. - -[No sources needed since this section provides general guidance] \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Data Types and Serialization.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Data Types and Serialization.md deleted file mode 100644 index 9b50b03485..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Data Types and Serialization.md +++ /dev/null @@ -1,553 +0,0 @@ -# Data Types and Serialization - - -**Referenced Files in This Document** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [types.cpp](file://libraries/protocol/types.cpp) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the blockchain data types and serialization mechanisms used by the protocol layer. It focuses on: -- Basic and specialized blockchain types (keys, identifiers, amounts, authorities) -- Smart contract-like operation types and their variants -- Serialization/deserialization for operations, transactions, and blocks -- Utilities for operation introspection and helper functions -- Variant serialization, enum handling, and custom type serialization patterns -- Examples of usage and protocol versioning implications - -## Project Structure -The relevant data types and serialization logic live primarily under the protocol library’s include and implementation files. The most important areas are: -- Core types and cryptographic keys -- Operations and their static variants -- Transactions and blocks -- Asset and authority types -- Versioning and extension types - -```mermaid -graph TB -subgraph "Protocol Types" -T["types.hpp
Core types and aliases"] -A["asset.hpp
Asset and Price"] -AU["authority.hpp
Authority and classification"] -V["version.hpp
Version and Hardfork Version"] -end -subgraph "Operations" -O["operations.hpp
Operation static_variant"] -CO["chain_operations.hpp
Concrete operations"] -PO["proposal_operations.hpp
Proposal ops"] -VO["chain_virtual_operations.hpp
Virtual ops"] -B["base.hpp
base_operation/virtual_operation"] -end -subgraph "Serialization" -TR["transaction.hpp
transaction/singed_transaction"] -BLK["block.hpp
signed_block"] -BH["block_header.hpp
block_header/siged_block_header"] -OU["operation_util.hpp
DECLARE_OPERATION_TYPE macros"] -OUI["operation_util_impl.cpp
name_from_type"] -end -T --> O -O --> CO -O --> PO -O --> VO -B --> CO -B --> PO -B --> VO -TR --> O -BLK --> TR -BH --> BLK -AU --> TR -A --> CO -V --> BH -OU --> O -OUI --> OU -``` - -**Diagram sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L34-L209) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L10-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L8-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L9-L1189) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L129) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L62) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L34-L209) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L8-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L62) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L10-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L1189) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L129) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -## Core Components -- Basic types and aliases: identifiers, hashes, time, safe integers, and reflection-friendly containers -- Cryptographic keys: public, extended public/private keys with Base58-pack/unpack serialization -- Asset and price: token representation with string conversions and arithmetic -- Authority: weighted multi-signature structures with classification and validation -- Operations: static_variant of all operations and virtual operations -- Transaction and Block: container structures with digest, signing, and Merkle roots - -Key responsibilities: -- Provide compact, deterministic serialization via fc::raw and fc::reflector -- Support runtime polymorphism via static_variant for operations -- Encode cryptographic material in a standardized way for hashing and signing - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L36-L209) -- [types.cpp](file://libraries/protocol/types.cpp#L13-L178) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L14-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) - -## Architecture Overview -The serialization architecture centers on fc reflection and raw packing: -- Types are reflected with FC_REFLECT/FC_REFLECT_TYPENAME for deterministic field ordering -- Static variants (operation, versioned chain properties) serialize discriminant + payload -- Enumerations are handled via FC_REFLECT_ENUM or fc::enum_type -- Custom types (keys, asset) provide to_variant/from_variant for human-readable formats and pack/unpack for binary - -```mermaid -classDiagram -class PublicKeyType { -+key_data -+operator std : : string() -+operator fc : : ecc : : public_key() -} -class ExtendedPublicKeyType { -+key_data -+operator std : : string() -+operator fc : : ecc : : extended_public_key() -} -class ExtendedPrivateKeyType { -+key_data -+operator std : : string() -+operator fc : : ecc : : extended_private_key() -} -class Asset { -+amount -+symbol -+to_string() -+from_string() -} -class Authority { -+weight_threshold -+account_auths -+key_auths -+validate() -} -class Operation { -<> -} -class Transaction { -+ref_block_num -+ref_block_prefix -+expiration -+operations -+extensions -+id() -+sig_digest() -} -class SignedBlock { -+transactions -+calculate_merkle_root() -} -PublicKeyType <.. Asset : "used in ops" -ExtendedPublicKeyType <.. Transaction : "signing" -ExtendedPrivateKeyType <.. Transaction : "signing" -Asset <.. Operation : "fees" -Authority <.. Transaction : "required authorities" -Operation <.. Transaction : "payload" -Transaction <.. SignedBlock : "contains" -``` - -**Diagram sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L113-L207) -- [types.cpp](file://libraries/protocol/types.cpp#L13-L178) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L14-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) - -## Detailed Component Analysis - -### Basic Data Types and Keys -- Aliases: chain_id_type, block_id_type, transaction_id_type, digest_type, signature_type, share_type, weight_type -- Public keys and extended keys: encapsulate ECC data with binary_key for pack/unpack and Base58 string conversion -- String comparisons and ordering: string_less supports std::string and fc::fixed_string - -Serialization highlights: -- Binary form uses fc::raw::pack/unpack of binary_key structs -- Human-readable form uses Base58 with a chain-specific address prefix -- Reflection-based serialization via FC_REFLECT for key structs - -Usage examples (conceptual): -- Convert a public key to a string for display or storage -- Pack a key into bytes for inclusion in transactions or blocks -- Unpack bytes back into a key for signature verification - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [types.cpp](file://libraries/protocol/types.cpp#L13-L178) -- [types.cpp](file://libraries/protocol/types.cpp#L183-L206) - -### Asset and Price Types -- Asset stores amount and symbol; provides arithmetic, comparison, and string conversions -- Price pairs base and quote assets; includes normalization helpers and validation - -Serialization highlights: -- FC_REFLECT for asset and price -- to_variant/from_variant convert to/from human-readable strings - -Usage examples (conceptual): -- Serialize an asset to JSON for APIs -- Deserialize a string into an asset for validation and arithmetic - -**Section sources** -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L14-L181) - -### Authority and Classification -- Authority aggregates thresholds and maps of accounts/keys with weights -- Classification enumerates master, active, key, regular for operation authority derivation -- Validation ensures satisfiability and structural correctness - -Serialization highlights: -- FC_REFLECT for authority and its internal maps -- FC_REFLECT_ENUM for classification - -Usage examples (conceptual): -- Build an authority requiring multiple signatures -- Extract required authorities from an operation - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) - -### Operations and Variants -- operation is a static_variant over all concrete operations and virtual operations -- is_virtual_operation/is_data_operation classify variants -- operation_wrapper resolves circular dependencies for proposals - -Serialization highlights: -- FC_REFLECT_TYPENAME for operation and wrapper -- DECLARE_OPERATION_TYPE macro generates to_variant/from_variant and validation/authority extraction stubs - -Usage examples (conceptual): -- Serialize an operation to bytes for signing -- Deserialize bytes into the appropriate operation variant -- Validate an operation before applying - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) - -### Operation Utilities and Helpers -- DECLARE_OPERATION_TYPE macro defines to_variant, from_variant, operation_validate, and operation_get_required_authorities -- name_from_type extracts a concise name from a fully qualified type name - -Usage examples (conceptual): -- Implement to_variant/from_variant for a new operation type -- Use operation_get_required_authorities to compute signers for a transaction - -**Section sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -### Transactions and Blocks -- transaction: container with expiration, reference block fields, operations, and extensions -- signed_transaction: extends transaction with signatures and authority helpers -- annotated_signed_transaction: attaches block and transaction indices -- block_header/sigend_block_header: header with digest/signature; signed_block contains transactions and computes Merkle root - -Serialization highlights: -- FC_REFLECT for all structures -- visit pattern on operations for visitor-based processing -- Merkle root computation for block integrity - -Usage examples (conceptual): -- Build a transaction, add operations, compute digest, sign, and broadcast -- Verify signatures and required authorities for a signed transaction -- Serialize a block for persistence or P2P propagation - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) - -### Virtual Operations and Base Types -- base_operation/virtual_operation define the hierarchy; virtual operations are non-executed events -- block_header_extensions/future_extensions are static variants for extensibility - -Usage examples (conceptual): -- Emit virtual operations during evaluation to notify APIs and observers -- Extend block headers with versioning or hardfork votes - -**Section sources** -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L62) - -### Concrete Operations and Extensions -- chain_operations.hpp: account creation/update, transfers, vesting, validators, escrow, chain properties, invites, subscriptions, sales, awards, bids -- proposal_operations.hpp: proposal lifecycle operations -- chain_virtual_operations.hpp: reward payouts, hardfork triggers, committee actions, validator rewards, subscription actions, sales, and auction events - -Serialization highlights: -- FC_REFLECT for each operation struct -- Extensions fields for future extensibility - -Usage examples (conceptual): -- Construct a transfer operation with fee, amount, memo -- Create a proposal with multiple wrapped operations and expiration - -**Section sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L1189) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L129) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) - -### Versioning and Protocol Evolution -- version and hardfork_version represent semantic versioning -- hardfork_version_vote carries voting for hardfork activation -- block_header_extensions includes version reporting and hardfork votes - -Serialization highlights: -- FC_REFLECT for version types -- to_variant/from_variant for human-readable version strings - -Usage examples (conceptual): -- Report current node version in block headers -- Vote for a hardfork version and record timestamp - -**Section sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L43-L54) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L25-L35) - -## Architecture Overview - -```mermaid -sequenceDiagram -participant App as "Application" -participant Tx as "transaction" -participant Ops as "operations.hpp" -participant Var as "static_variant" -participant Ser as "fc : : raw / fc : : variant" -App->>Tx : "Add operations" -Tx->>Ops : "operations static_variant" -Ops->>Var : "Select operation type" -App->>Ser : "Serialize operations (bytes)" -Ser-->>App : "Raw bytes" -App->>Ser : "Serialize operations (JSON)" -Ser-->>App : "Variant (human-readable)" -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L18-L49) - -## Detailed Component Analysis - -### Variant Serialization and Enum Handling -- static_variant serializes the index of the contained type followed by the serialized payload -- enums are reflected via FC_REFLECT_ENUM or fc::enum_type -- Custom types provide to_variant/from_variant for JSON-friendly formats - -```mermaid -flowchart TD -Start(["Serialize Variant"]) --> GetIndex["Get type index"] -GetIndex --> SerializePayload["Serialize payload bytes"] -SerializePayload --> Combine["Write index + payload"] -Combine --> End(["Done"]) -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L114-L115) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L152-L156) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L114-L115) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L152-L156) - -### Custom Type Serialization Patterns -- Keys: pack/unpack binary_key, encode/decode Base58 with chain prefix -- Asset: string-based to/from variant for JSON compatibility -- Authorities: reflection-based serialization with weighted maps - -```mermaid -flowchart TD -KStart(["Key to_bytes"]) --> Pack["Pack binary_key"] -Pack --> Hash["Hash key data"] -Hash --> Check["Verify checksum"] -Check --> KEnd(["Bytes"]) -AStart(["Asset to_variant"]) --> ToString["Convert to string"] -ToString --> AEnd(["Variant"]) -``` - -**Diagram sources** -- [types.cpp](file://libraries/protocol/types.cpp#L51-L57) -- [types.cpp](file://libraries/protocol/types.cpp#L104-L110) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L170-L177) - -**Section sources** -- [types.cpp](file://libraries/protocol/types.cpp#L13-L178) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L170-L177) - -### Operation Utilities and Helper Functions -- DECLARE_OPERATION_TYPE macro centralizes the generation of serialization and validation hooks -- name_from_type helps derive operation names from type names for logging or UI - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Macro as "DECLARE_OPERATION_TYPE" -participant Impl as "operation_util_impl.cpp" -Dev->>Macro : "Define OperationType" -Macro-->>Dev : "to_variant/from_variant + validate + authorities" -Dev->>Impl : "Use name_from_type(type_name)" -Impl-->>Dev : "Clean name" -``` - -**Diagram sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -**Section sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -### Data Type Usage Scenarios -- Signing a transaction: compute sig_digest(chain_id), sign with private key, append signature -- Deserializing a block: unpack signed_block, iterate transactions, verify signatures and Merkle roots -- Validating an operation: call operation_validate and extract required authorities for permission checks - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L27-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) - -### Relationship Between Data Types and Protocol Versioning -- version and hardfork_version provide structured versioning -- block_header_extensions carry version reporting and hardfork votes -- Static variants (operation, versioned chain properties) evolve by adding new alternatives without breaking existing encodings - -**Section sources** -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L43-L54) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L635-L640) - -## Dependency Analysis - -```mermaid -graph LR -types_hpp["types.hpp"] --> operations_hpp["operations.hpp"] -operations_hpp --> chain_ops_hpp["chain_operations.hpp"] -operations_hpp --> proposal_ops_hpp["proposal_operations.hpp"] -operations_hpp --> virt_ops_hpp["chain_virtual_operations.hpp"] -operations_hpp --> base_hpp["base.hpp"] -transaction_hpp["transaction.hpp"] --> operations_hpp -block_hpp["block.hpp"] --> transaction_hpp -block_header_hpp["block_header.hpp"] --> block_hpp -asset_hpp["asset.hpp"] --> chain_ops_hpp -authority_hpp["authority.hpp"] --> transaction_hpp -version_hpp["version.hpp"] --> block_header_hpp -operation_util_hpp["operation_util.hpp"] --> operations_hpp -operation_util_impl_cpp["operation_util_impl.cpp"] --> operation_util_hpp -``` - -**Diagram sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L34-L209) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L8-L131) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L9-L1189) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L129) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L62) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L10-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L34-L209) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L8-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L62) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L10-L181) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L9-L1189) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L129) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) -- [version.hpp](file://libraries/protocol/include/graphene/protocol/version.hpp#L14-L156) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operation_util_impl.cpp](file://libraries/protocol/operation_util_impl.cpp#L5-L11) - -## Performance Considerations -- Prefer fc::raw serialization for compact binary storage and deterministic hashing -- Use fc::variant for human-readable interchange; avoid in hot paths -- Keep operation payloads minimal; leverage extensions for optional data -- Static variants enable efficient dispatch without virtual calls -- Avoid repeated pack/unpack cycles; cache digests when possible - -## Troubleshooting Guide -Common issues and remedies: -- Key deserialization failures: verify Base58 prefix and checksum match -- Asset parsing errors: ensure symbol and precision align with chain configuration -- Authority validation failures: confirm thresholds and weights satisfy required sets -- Operation variant mismatches: ensure the correct type is selected during deserialization -- Signature verification failures: recompute sig_digest with the correct chain_id and reference block - -**Section sources** -- [types.cpp](file://libraries/protocol/types.cpp#L24-L39) -- [types.cpp](file://libraries/protocol/types.cpp#L84-L97) -- [types.cpp](file://libraries/protocol/types.cpp#L137-L150) -- [asset.hpp](file://libraries/protocol/include/graphene/protocol/asset.hpp#L170-L177) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L49-L49) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L27-L101) - -## Conclusion -The protocol layer provides a robust, extensible foundation for blockchain data types and serialization. By combining fc reflection, static variants, and custom serializers, it achieves deterministic encoding, clear versioning, and flexible evolution. Developers can extend operations and types while maintaining backward compatibility and efficient serialization for production-grade nodes and applications. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Operations Definition.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Operations Definition.md deleted file mode 100644 index 279b4d4899..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Operations Definition.md +++ /dev/null @@ -1,318 +0,0 @@ -# Operations Definition - - -**Referenced Files in This Document** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp) -- [operations.cpp](file://libraries/protocol/operations.cpp) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp) -- [1.hf](file://libraries/chain/hardfork.d/1.hf) -- [10.hf](file://libraries/chain/hardfork.d/10.hf) -- [11.hf](file://libraries/chain/hardfork.d/11.hf) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the Operations Definition system in the VIZ blockchain protocol. It focuses on the static_variant-based operation type registry, the operation_wrapper mechanism, and the hierarchical categorization of operations into on-chain and virtual categories. It also documents validation and serialization hooks, deprecated operations and their replacements, operation ordering and hardfork implications, and practical examples of operation creation, validation, and serialization. - -## Project Structure -The operation system spans several protocol headers and a small implementation module: -- The central operation registry is defined as a static_variant in operations.hpp. -- Operation structs are declared in chain_operations.hpp and chain_virtual_operations.hpp. -- Validation and authority extraction are defined in operation_util.hpp and implemented in operations.cpp. -- Operation-specific validation logic is implemented in chain_operations.cpp. -- Proposal operations introduce operation_wrapper to resolve circular dependencies. -- Specialized operation families (invites, paid subscriptions) are defined alongside their domain objects. - -```mermaid -graph TB -subgraph "Protocol Layer" -OP["operations.hpp
static_variant"] -BO["base.hpp
base_operation / virtual_operation"] -CO["chain_operations.hpp
On-chain ops"] -VO["chain_virtual_operations.hpp
Virtual ops"] -PR["proposal_operations.hpp
proposal_* + operation_wrapper"] -OU["operation_util.hpp
DECLARE_OPERATION_TYPE / helpers"] -end -subgraph "Implementation" -OC["chain_operations.cpp
validate() impls"] -OI["operations.cpp
is_virtual_operation()
is_data_operation()"] -end -OP --> CO -OP --> VO -OP --> PR -OP --> OU -BO --> CO -BO --> VO -PR --> OP -OC --> CO -OI --> OP -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L102) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L112) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L304) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L37-L128) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L447) -- [operations.cpp](file://libraries/protocol/operations.cpp#L8-L57) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L102) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) - -## Core Components -- Static variant operation registry: A single type alias that aggregates all on-chain and virtual operations in a deterministic order. -- Base operation types: base_operation and virtual_operation define common behavior and virtual-only validation semantics. -- Operation wrapper: operation_wrapper is a thin container used to break circular definitions in proposals. -- Validation and authority helpers: Macros and functions to serialize/deserialize operations and compute required authorities. -- Operation families: Account, asset/vesting, content/vote, governance (proposals), virtual rewards, and specialized operations (committee, invites, paid subscriptions). - -Key responsibilities: -- Registry ordering controls hardfork sensitivity. -- Each operation defines validate() and required authority methods. -- Virtual operations are emitted by evaluators and not included in transactions. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L102) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L37-L62) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) - -## Architecture Overview -The operation architecture centers on a static_variant that enumerates all operations. Evaluators apply on-chain operations and emit virtual operations. Serialization is handled via the DECLARE_OPERATION_TYPE macro and fc::variant converters. - -```mermaid -classDiagram -class base_operation { -+validate() void -+get_required_authorities(...) -+get_required_active_authorities(...) -+get_required_master_authorities(...) -+get_required_regular_authorities(...) -+is_virtual() bool -} -class virtual_operation { -+is_virtual() bool -+validate() void -} -class operation { -<> -} -class operation_wrapper { -+op : operation -} -base_operation <|-- virtual_operation -operation ..> base_operation : "holds" -operation ..> virtual_operation : "holds" -operation_wrapper --> operation : "contains" -``` - -**Diagram sources** -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L37-L53) - -## Detailed Component Analysis - -### Static Variant Operation Registry -- The operation type is a static_variant that lists all on-chain operations followed by virtual operations. The comment explicitly warns that reordering prior to virtual operations triggers a hardfork. -- Categories include: - - Account operations: transfer, transfer_to_vesting, withdraw_vesting, account_update, account_create, account_metadata, account-related authorities and recovery. - - Asset/vesting operations: vesting transfers, withdrawals, delegation, and withdrawal routing. - - Content/vote operations: content, delete_content, vote (both marked deprecated in the registry). - - Governance operations: proposals (create, update, delete), chain property updates, versioned chain properties. - - Virtual reward operations: author_reward, curation_reward, content_reward, fill_vesting_withdraw, shutdown_witness, hardfork, content_payout_update, content_benefactor_reward, return_vesting_delegation. - - Committee operations: worker requests, cancellations, votes, payouts/payments. - - Invite operations: create_invite, claim_invite_balance, invite_registration, use_invite_balance. - - Award operations: award, receive_award, benefactor_award. - - Paid subscription operations: set_paid_subscription, paid_subscribe, paid_subscription_action, cancel_paid_subscription. - - Account sales operations: set_account_price, set_subaccount_price, buy_account, account_sale. - - Escrow and related: escrow_transfer, escrow_dispute, escrow_release, escrow_approve, expire_escrow_ratification. - - HF11 operations: fixed_award, target_account_sale, bid, outbid. - -Serialization and reflection: -- The registry exposes FC_REFLECT_TYPENAME and FC_REFLECT for operation_wrapper, enabling fc::variant conversions. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L102) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L115-L131) - -### Operation Wrapper and Circular Dependencies -- operation_wrapper is a minimal struct containing a single operation field. It is used inside proposal operations to avoid circular definitions between operation and proposal_create_operation. -- The proposal family declares operation_wrapper before defining proposal operations, ensuring the static_variant can reference it. - -```mermaid -sequenceDiagram -participant P as "proposal_create_operation" -participant W as "operation_wrapper" -participant O as "operation" -P->>W : proposed_operations.push_back(operation_wrapper(op)) -Note right of P : operation_wrapper holds operation -Note over P,O : Circular dependency avoided by forward-declaring operation_wrapper -``` - -**Diagram sources** -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L37-L53) -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L48-L62) - -**Section sources** -- [proposal_operations.hpp](file://libraries/protocol/include/graphene/protocol/proposal_operations.hpp#L37-L62) - -### Base Operation Types and Virtual Operations -- base_operation provides default no-op implementations for validation and authority extraction, plus is_virtual() returning false. -- virtual_operation inherits from base_operation and overrides is_virtual() to return true and enforces that virtual operations cannot be validated as on-chain operations. -- Virtual operations are emitted by evaluators and processed separately from transaction operations. - -**Section sources** -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) - -### Operation Validation and Authority Extraction -- Validation: Each operation implements validate(). The implementation performs domain-specific checks (e.g., account name validity, UTF-8, JSON, symbol types, amounts). -- Authority extraction: Each operation optionally implements get_required_*_authorities(...) to declare which accounts/keys must authorize the operation. -- Utility macros: DECLARE_OPERATION_TYPE declares to_variant/from_variant and operation_validate/operation_get_required_authorities for the operation type. - -```mermaid -flowchart TD -Start(["Operation Received"]) --> Validate["Call validate()"] -Validate --> Valid{"Valid?"} -Valid --> |No| Reject["Reject Transaction"] -Valid --> |Yes| Auth["Compute Required Authorities"] -Auth --> Sign["Collect Signatures"] -Sign --> Apply["Apply Evaluator (on-chain)"] -Apply --> EmitVirt["Emit Virtual Ops (if any)"] -EmitVirt --> End(["Done"]) -``` - -**Diagram sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L447) - -**Section sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L447) - -### Deprecated Operations and Replacements -- The registry marks vote_operation and content_operation as deprecated. These remain present in the static_variant for backward compatibility. -- Evaluators and APIs should route legacy votes and content creation to newer equivalents or deprecation pathways as per network policy. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L14-L15) - -### Operation Families and Hierarchical Organization -- Account operations: account_create, account_update, account_metadata, authorities and recovery operations. -- Asset/Vesting operations: transfer, transfer_to_vesting, withdraw_vesting, set_withdraw_vesting_route, delegate_vesting_shares. -- Content/Vote operations: content, delete_content, vote (deprecated). -- Governance: proposal_create, proposal_update, proposal_delete; chain_properties_update, versioned_chain_properties_update; witness_update, account_witness_vote, account_witness_proxy. -- Virtual reward operations: author_reward, curation_reward, content_reward, fill_vesting_withdraw, hardfork, content_payout_update, content_benefactor_reward, return_vesting_delegation. -- Committee operations: committee_worker_create_request, committee_worker_cancel_request, committee_vote_request, committee_cancel_request, committee_approve_request, committee_payout_request, committee_pay_request. -- Invite operations: create_invite, claim_invite_balance, invite_registration, use_invite_balance. -- Award operations: award, receive_award, benefactor_award. -- Paid subscription operations: set_paid_subscription, paid_subscribe, paid_subscription_action, cancel_paid_subscription. -- Account sales operations: set_account_price, set_subaccount_price, buy_account, account_sale. -- Escrow operations: escrow_transfer, escrow_dispute, escrow_release, escrow_approve, expire_escrow_ratification. -- HF11 operations: fixed_award, target_account_sale, bid, outbid. - -These families are organized as separate headers and are aggregated into the single operation static_variant. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L112) -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L304) -- [invite_objects.hpp](file://libraries/chain/include/graphene/chain/invite_objects.hpp#L14-L38) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L33) - -### Examples: Creation, Validation, and Serialization -- Creation: Instantiate an operation struct with required fields (e.g., account names, amounts, metadata). Populate extensions if applicable. -- Validation: Call validate() on the operation struct. This performs domain checks (names, UTF-8, JSON, symbol types, amounts). -- Serialization: Use fc::to_variant and fc::from_variant to convert between binary and human-readable forms. The DECLARE_OPERATION_TYPE macro ensures these functions are available for the operation type. - -Note: The repository does not include example client code; consult the macro declarations and fc::variant usage in the protocol headers for integration points. - -**Section sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L447) - -## Dependency Analysis -- The operation registry depends on: - - chain_operations.hpp for on-chain operation structs. - - chain_virtual_operations.hpp for virtual operation structs. - - proposal_operations.hpp for proposal operations and operation_wrapper. - - base.hpp for base_operation and virtual_operation. -- Implementation dependencies: - - operations.cpp implements is_virtual_operation and is_data_operation using static_variant visitors. - - chain_operations.cpp implements validate() for each operation struct. - -```mermaid -graph LR -OP["operations.hpp"] --> CO["chain_operations.hpp"] -OP --> VO["chain_virtual_operations.hpp"] -OP --> PR["proposal_operations.hpp"] -OP --> OU["operation_util.hpp"] -CO --> BO["base.hpp"] -VO --> BO -OI["operations.cpp"] --> OP -OC["chain_operations.cpp"] --> CO -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L3-L6) -- [operations.cpp](file://libraries/protocol/operations.cpp#L1-L57) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L1-L448) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L3-L6) -- [operations.cpp](file://libraries/protocol/operations.cpp#L1-L57) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L1-L448) - -## Performance Considerations -- static_variant dispatch is efficient for operation handling; keep the variant compact and avoid excessive nesting. -- Validation functions should short-circuit on failure and minimize allocations. -- Virtual operations are computed during evaluation and do not increase transaction size; they are processed separately. - -## Troubleshooting Guide -Common issues and remedies: -- Validation failures: Review operation.validate() constraints (account names, UTF-8, JSON, symbol types, amounts). Fix malformed inputs or incorrect asset symbols. -- Missing authorities: Ensure get_required_*_authorities(...) returns the correct set of accounts/keys. Verify multisig thresholds and key weights. -- Serialization errors: Confirm fc::to_variant and fc::from_variant are used consistently with the operation type. Check that the operation_wrapper is used for proposals. -- Hardfork ordering: Do not reorder operations before the virtual operations in the static_variant. Introduce new operations at the end of the appropriate category to avoid breaking changes. - -**Section sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L16-L34) -- [operations.cpp](file://libraries/protocol/operations.cpp#L8-L57) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L447) - -## Conclusion -The VIZ operation system is a robust, extensible framework built on a static_variant registry. It cleanly separates on-chain and virtual operations, supports flexible authority and validation semantics, and provides clear hooks for serialization and introspection. Careful adherence to ordering and deprecation policies ensures safe evolution across hardforks. - -## Appendices - -### Operation Ordering and Hardfork Implications -- The registry comment explicitly warns that changing the order of operations before virtual operations constitutes a hardfork. -- Hardfork markers in the codebase indicate activation points for protocol changes. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L12) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [10.hf](file://libraries/chain/hardfork.d/10.hf#L1-L7) -- [11.hf](file://libraries/chain/hardfork.d/11.hf#L1-L7) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Protocol Library.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Protocol Library.md deleted file mode 100644 index 6928acec34..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Protocol Library.md +++ /dev/null @@ -1,418 +0,0 @@ -# Protocol Library - - -**Referenced Files in This Document** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp) -- [operations.cpp](file://libraries/protocol/operations.cpp) -- [transaction.cpp](file://libraries/protocol/transaction.cpp) -- [authority.cpp](file://libraries/protocol/authority.cpp) -- [block.cpp](file://libraries/protocol/block.cpp) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the Protocol Library that defines the blockchain’s operational framework. It covers: -- Transaction operations and their categorization -- Transaction structure, validation, signature verification, and serialization -- Authority requirements, multi-signature validation, and permission checks -- Block and block header structures, Merkle roots, and consensus-related signing -- Blockchain-specific operations and their evaluation logic -- Core data types and serialization formats -- Practical examples of operation creation, transaction building, authority verification, and block validation -- The relationship between protocol definitions and chain library implementations - -## Project Structure -The Protocol Library resides under libraries/protocol and exposes headers for operations, transactions, authorities, blocks, types, and supporting utilities. Implementation files provide concrete behavior for validation, signing, and Merkle tree computation. - -```mermaid -graph TB -subgraph "Protocol Headers" -OP["operations.hpp"] -TX["transaction.hpp"] -AUTH["authority.hpp"] -BH["block_header.hpp"] -B["block.hpp"] -CO["chain_operations.hpp"] -TYPES["types.hpp"] -BASE["base.hpp"] -OU["operation_util.hpp"] -SS["sign_state.hpp"] -end -subgraph "Protocol Implementations" -OPCPP["operations.cpp"] -TXCPP["transaction.cpp"] -AUTHCPP["authority.cpp"] -BHC["block.cpp"] -COCPP["chain_operations.cpp"] -end -OP --> OU -OP --> CO -TX --> OP -TX --> SS -B --> BH -CO --> TYPES -CO --> BASE -AUTH --> TYPES -BH --> TYPES -TXCPP --> TX -TXCPP --> SS -AUTHCPP --> AUTH -BHC --> B -COCPP --> CO -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L1-L136) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L800) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L1-L235) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L1-L62) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L1-L35) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [operations.cpp](file://libraries/protocol/operations.cpp#L1-L58) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [authority.cpp](file://libraries/protocol/authority.cpp#L1-L228) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L1-L448) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L1-L136) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L1-L800) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L1-L235) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L1-L62) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L1-L35) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) - -## Core Components -- Operations: A static variant enumerating all transaction operations, including account, asset, content, governance, and virtual operations. Includes helpers to detect virtual and data operations. -- Transaction: Transaction and signed transaction structures with validation, signature digest computation, Merkle digest, and authority extraction/minimization. -- Authority: Multi-signature authority model with thresholds, account and key maps, validation, and account name rules. -- Blocks: Block header and signed block structures with Merkle root computation and validator signature verification. -- Chain Operations: Strongly-typed operation structs with validation logic and required authority hooks. -- Types: Core blockchain types (names, keys, amounts, hashes, digests) and serialization support. - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L10-L131) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L800) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) - -## Architecture Overview -The Protocol Library composes operations into transactions, validates each operation, computes digests for signing and Merkle roots, and enforces authority requirements. Blocks encapsulate transactions and enforce validator signatures. - -```mermaid -graph TB -OP["operation (static_variant)"] -TX["transaction
signed_transaction"] -AUTH["authority"] -SS["sign_state"] -BH["block_header
signed_block_header"] -SB["signed_block"] -CO["chain_operations (structs)"] -OP --> TX -TX --> AUTH -TX --> SS -SB --> BH -SB --> TX -CO --> TYPES["types.hpp"] -AUTH --> TYPES -BH --> TYPES -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L35) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L29) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L112) - -## Detailed Component Analysis - -### Operations: Transaction Operation Types -- The operation static variant enumerates all supported operations, including deprecated entries, regular operations, and virtual operations. It also exposes helpers to classify operations (virtual/data). -- The operation wrapper supports reflection and serialization. - -Key responsibilities: -- Define the canonical operation set -- Provide classification helpers -- Enable reflection-based serialization - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [operations.cpp](file://libraries/protocol/operations.cpp#L8-L52) - -### Transaction: Validation, Serialization, and Authority -- Transaction structure includes reference block fields, expiration, operations, and extensions. It computes digests for validation and signing. -- Signed transaction extends transaction with signatures and provides signing, signature minimization, and authority verification. -- Authority verification logic: - - Extracts required authorities from operations - - Supports regular authority vs active/master mixing constraints - - Uses sign_state to track provided signatures/approvals and validate recursively - -Processing highlights: -- Transaction::validate ensures at least one operation and delegates per-operation validation -- Transaction::sig_digest constructs the digest used for signing -- Signed transaction methods compute Merkle digest and minimize required signatures - -```mermaid -sequenceDiagram -participant U as "User" -participant TRX as "signed_transaction" -participant SIG as "sign_state" -participant AUTH as "Authority Getters" -U->>TRX : Build operations and set reference block/expiry -TRX->>TRX : validate() -U->>TRX : sign(private_key, chain_id) -TRX-->>U : signature appended -U->>TRX : verify_authority(chain_id, get_active, get_master, get_regular) -TRX->>SIG : construct with provided signatures -SIG->>AUTH : resolve authorities for accounts -SIG-->>TRX : pass/fail verification -``` - -**Diagram sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L222) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L11-L361) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L8-L45) - -### Authority: Requirement Calculation and Multi-Signature Validation -- Authority model supports thresholds and maps of account weights and key weights. -- Provides validation of account names, domain names, and impossibility checks. -- Offers helpers to enumerate keys and count authorities. - -Validation logic: -- Name validation enforces length, character sets, and domain rules -- Threshold satisfaction checked during verification -- Recursive checks via sign_state with configurable depth - -```mermaid -flowchart TD -Start(["Authority.validate()"]) --> CheckAccounts["Validate each account name"] -CheckAccounts --> End(["Done"]) -``` - -**Diagram sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L44-L48) -- [authority.cpp](file://libraries/protocol/authority.cpp#L44-L48) - -**Section sources** -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L115) -- [authority.cpp](file://libraries/protocol/authority.cpp#L7-L228) - -### Blocks and Block Headers: Validation and Consensus -- Block header includes previous ID, timestamp, validator, and Merkle root of transactions. -- Signed block header adds validator signature and methods to compute ID and validate signee. -- Signed block computes Merkle root over transaction digests. - -Consensus implications: -- validator signature verification ensures block validity -- Merkle root ensures transaction integrity - -```mermaid -flowchart TD -A["signed_block.calculate_merkle_root()"] --> B["Map transactions to merkle_digest()"] -B --> C["Pair-wise hash until single root"] -C --> D["Set signed_block.transaction_merkle_root"] -``` - -**Diagram sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L35) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [block.cpp](file://libraries/protocol/block.cpp#L35-L64) - -**Section sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L8-L43) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L19) -- [block.cpp](file://libraries/protocol/block.cpp#L6-L68) - -### Chain Operations: Evaluation Logic and Constraints -- Strongly typed operation structs define required authorities and validation rules. -- Examples include account creation/update/metadata, transfers, vesting, validator updates, chain property updates, escrow operations, custom operations, and governance-related operations (committee, invite, paid subscription, account sales, awards, etc.). -- Validation enforces symbol types, numeric bounds, UTF-8 and JSON constraints, permlink rules, and account name rules. - -Evaluation highlights: -- Each operation implements validate() and required authority hooks -- Static variants of chain properties support hardfork evolution - -**Section sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L800) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L39-L448) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L12-L41) - -### Types: Data Types and Serialization -- Defines blockchain primitives: account names, keys, amounts, digests, signatures, and hashes. -- Provides reflection and serialization support for types and public keys. -- Includes comparison functors and convenience typedefs. - -Serialization characteristics: -- Public keys support base58 encoding/decoding and binary representation -- Safe integer types and big-integer types for precise arithmetic - -**Section sources** -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) - -## Dependency Analysis -- operations.hpp depends on operation utilities and chain operations -- transaction.hpp depends on operations, sign_state, and types -- authority.hpp depends on types -- block.hpp depends on block_header.hpp and transaction.hpp -- chain_operations.hpp depends on base.hpp, block_header.hpp, and asset definitions -- Implementations depend on fc library for hashing, crypto, and serialization - -```mermaid -graph LR -OU["operation_util.hpp"] --> OP["operations.hpp"] -CO["chain_operations.hpp"] --> BASE["base.hpp"] -CO --> BH["block_header.hpp"] -TX["transaction.hpp"] --> OP -TX --> SS["sign_state.hpp"] -B["block.hpp"] --> BH -AUTH["authority.hpp"] --> TYPES["types.hpp"] -BH --> TYPES -TXCPP["transaction.cpp"] --> TX -AUTHCPP["authority.cpp"] --> AUTH -BHC["block.cpp"] --> B -COCPP["chain_operations.cpp"] --> CO -``` - -**Diagram sources** -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L1-L35) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L3-L6) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L3-L6) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L3-L6) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L3-L4) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L3-L5) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L3-L4) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L3-L4) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L3-L7) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L3-L4) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [authority.cpp](file://libraries/protocol/authority.cpp#L1-L228) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L1-L448) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L3-L6) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L3-L5) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L3-L4) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L3-L4) -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L3-L6) -- [base.hpp](file://libraries/protocol/include/graphene/protocol/base.hpp#L3-L6) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L3-L7) -- [operation_util.hpp](file://libraries/protocol/include/graphene/protocol/operation_util.hpp#L1-L35) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L3-L4) - -## Performance Considerations -- Authority verification recursion depth is bounded to prevent excessive computation -- Signature minimization prunes unnecessary signatures while preserving validity -- Merkle root computation scales logarithmically with transaction count -- Validation enforces early exits on constraint violations to reduce overhead - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and diagnostics: -- Transaction missing required signatures or approvals -- Irrelevant signatures or approvals detected during verification -- Authority thresholds not met or invalid account names -- Block header signature mismatch or invalid validator - -Diagnostics: -- verify_authority throws specific exceptions for missing authorities and irrelevant inputs -- assert_unused_approvals reports unused signatures/approvals -- Authority::is_impossible helps detect unsatisfiable authorities - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L76-L222) -- [authority.cpp](file://libraries/protocol/authority.cpp#L24-L33) - -## Conclusion -The Protocol Library provides a robust foundation for blockchain operations, transactions, authorities, and blocks. Its design emphasizes strong typing, clear separation of concerns, and extensibility for governance and content features. Implementations ensure correctness through rigorous validation, cryptographic signing, and Merkle integrity checks. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Example Workflows - -#### Operation Creation and Classification -- Create operations using strongly typed structs from chain_operations.hpp -- Use is_virtual_operation and is_data_operation helpers from operations.cpp to classify operations - -**Section sources** -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L138) -- [operations.cpp](file://libraries/protocol/operations.cpp#L17-L52) - -#### Transaction Building and Signing -- Assemble operations into a transaction, set reference block and expiration -- Sign with private key and append signature; verify authority using provided getters - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L45-L92) - -#### Authority Verification -- Extract required authorities from operations and verify via sign_state -- Respect mixing constraints between regular and active/master authorities - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) - -#### Block Validation -- Compute signed block header ID and validate validator signature -- Recompute Merkle root from transaction digests and compare with block header - -**Section sources** -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L25-L35) -- [block.cpp](file://libraries/protocol/block.cpp#L14-L64) - -### Relationship Between Protocol Definitions and Chain Library Implementations -- Protocol headers define operation semantics, types, and structures -- Chain library evaluators consume operations and apply state transitions -- Protocol implementations (transaction.cpp, authority.cpp, block.cpp, chain_operations.cpp) provide runtime behavior aligned with protocol definitions - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [authority.cpp](file://libraries/protocol/authority.cpp#L1-L228) -- [block.cpp](file://libraries/protocol/block.cpp#L1-L68) -- [chain_operations.cpp](file://libraries/protocol/chain_operations.cpp#L1-L448) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Transaction Processing.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Transaction Processing.md deleted file mode 100644 index a9add893f4..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Protocol Library/Transaction Processing.md +++ /dev/null @@ -1,468 +0,0 @@ -# Transaction Processing - - -**Referenced Files in This Document** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [transaction.cpp](file://libraries/protocol/transaction.cpp) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the Transaction Processing subsystem in the VIZ C++ node. It covers transaction structure, validation, signing, multi-signature authority checks, serialization, and network transport. It also describes the relationship between transactions and blocks, and outlines the transaction lifecycle from creation to inclusion in a block. - -## Project Structure -The transaction processing logic spans several libraries: -- Protocol layer: transaction definition, signing, authority verification, and types -- Chain layer: persistence and indexing of transactions -- Network layer: message framing for transaction broadcast -- Utilities: example signing tool - -```mermaid -graph TB -subgraph "Protocol Layer" -T["transaction.hpp
signed_transaction, annotated_signed_transaction"] -TS["sign_state.hpp
sign_state"] -OP["operations.hpp
operation variants"] -AU["authority.hpp
authority"] -TY["types.hpp
chain_id, digests, keys"] -BLK["block.hpp
signed_block"] -end -subgraph "Chain Layer" -TXO["transaction_object.hpp
transaction_object, index"] -end -subgraph "Network Layer" -CM["core_messages.hpp
trx_message"] -end -subgraph "Utilities" -STU["sign_transaction.cpp"] -end -T --> TS -T --> OP -T --> TY -BLK --> T -TXO --> T -CM --> T -STU --> T -TS --> AU -``` - -**Diagram sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L27) - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L1-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L1-L45) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L1-L107) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L1-L131) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L1-L115) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L1-L235) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L1-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L1-L73) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L1-L573) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L1-L54) - -## Core Components -- Transaction: Base structure with reference block fields, expiration, operation array, and extensions. Provides ID calculation, validation, and signature digest computation. -- Signed Transaction: Extends transaction with signatures and authority helpers for signing, verification, minimal signature sets, and Merkle hashing. -- Annotated Signed Transaction: Adds block number and transaction number metadata for post-inclusion reporting. -- Sign State: Multi-signature validation engine that tracks provided signatures, required authorities, recursion depth, and unused approvals/signatures filtering. -- Authority: Composite authority model supporting key weights, account delegations, thresholds, and classification. -- Operations: Static variant of supported operations; each operation contributes required authorities and validates itself. -- Types: Core cryptographic and identity types (chain ID, digests, signatures, keys). -- Block: Contains a vector of signed transactions forming the block payload. -- Transaction Object: Chain-side persisted representation for duplicate detection and expiration management. -- Network Messages: Defines the transaction message type for P2P broadcast. - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L17-L361) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L6-L107) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) - -## Architecture Overview -End-to-end flow from transaction creation to block inclusion and network propagation: - -```mermaid -sequenceDiagram -participant App as "Application" -participant Tx as "signed_transaction" -participant Sig as "sign_state" -participant Net as "Network Layer" -participant Chain as "Chain Database" -App->>Tx : "Construct transaction
set_expiration()
set_reference_block()" -App->>Tx : "Add operations
validate()" -App->>Tx : "sign(private_key, chain_id)" -Tx->>Sig : "verify_authority()
get_required_signatures()" -Sig-->>Tx : "Required keys / approvals" -Tx-->>App : "Ready to broadcast" -App->>Net : "Send trx_message" -Net-->>Peers : "Broadcast signed_transaction" -Peers->>Chain : "Receive and validate" -Chain-->>Peers : "Accept or reject" -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L45-L357) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L19-L59) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -## Detailed Component Analysis - -### Transaction Structure and Lifecycle -- Fields: - - Reference block number and prefix for replay protection - - Expiration timestamp - - Operation array (non-empty requirement enforced) - - Extensions placeholder -- Methods: - - ID calculation via digest - - Validation ensuring at least one operation and per-operation validation - - Signature digest computation for signing - - Helper setters for expiration and reference block - - Required authorities extraction from operations -- Lifecycle: - - Creation: set reference block and expiration - - Validation: validate operations and structure - - Signing: compute sig_digest and append signatures - - Broadcast: wrap in network message - - Execution: included in signed_block.transactions during block production/acceptance - - Persistence: indexed by transaction_object for duplicate detection and expiration cleanup - -```mermaid -classDiagram -class transaction { -+uint16_t ref_block_num -+uint32_t ref_block_prefix -+time_point_sec expiration -+vector~operation~ operations -+extensions_type extensions -+digest() digest_type -+id() transaction_id_type -+validate() void -+sig_digest(chain_id) digest_type -+set_expiration(time_point_sec) -+set_reference_block(block_id) -+get_required_authorities(...) -} -class signed_transaction { -+vector~signature_type~ signatures -+sign(private_key, chain_id) -+sign(private_key, chain_id) const -+get_required_signatures(...) -+verify_authority(...) -+minimize_required_signatures(...) -+get_signature_keys(chain_id) flat_set -+merkle_digest() digest_type -+clear() -} -class annotated_signed_transaction { -+transaction_id_type transaction_id -+uint32_t block_num -+uint32_t transaction_num -} -transaction <|-- signed_transaction -signed_transaction <|-- annotated_signed_transaction -``` - -**Diagram sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L17-L74) - -### Validation Rules -- Structural validation: - - Non-empty operations array - - Per-operation validation invoked during transaction.validate() -- Expiration: - - Expiration enforced by higher layers; transaction stores expiration and computes sig_digest using chain_id and transaction body -- Operation validation: - - Each operation’s validate() is called during transaction.validate() -- Authority verification: - - Extract required authorities from operations - - Enforce authority mixing rules (e.g., regular authority cannot mix with active/master in same transaction) - - Verify signatures against keys and account delegations up to recursion depth - -```mermaid -flowchart TD -Start(["validate()"]) --> CheckOps["Check operations not empty"] -CheckOps --> OpIter["For each operation"] -OpIter --> OpValidate["operation_validate(op)"] -OpValidate --> NextOp{"More operations?"} -NextOp --> |Yes| OpIter -NextOp --> |No| Done(["Validation OK"]) -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) - -### Multi-Signature Validation and Authority Checking -- sign_state tracks: - - Provided signatures keyed by public key - - Used vs unused signatures after verification - - Accounts approved by existing approvals - - Unused approvals filtered out -- Authority evaluation: - - Key weights meet threshold - - Account delegations evaluated via authority getters - - Recursion depth controlled by max_recursion -- Verification modes: - - Regular authority mode enforces stricter separation - - Active/master authority modes combine delegated checks -- Helpers: - - get_required_signatures(): determines minimal keys required given available keys - - minimize_required_signatures(): removes redundant signatures while preserving validity - - verify_authority(): end-to-end authority verification - -```mermaid -classDiagram -class sign_state { -+authority_getter get_active -+flat_set~public_key_type~ available_keys -+flat_map~public_key_type,bool~ provided_signatures -+vector~public_key_type~ unused_signatures -+vector~public_key_type~ used_signatures -+flat_map~account_name_type,bool~ approved_by -+uint32_t max_recursion -+signed_by(public_key_type) bool -+check_authority(account_name_type) bool -+check_authority(authority, depth) bool -+remove_unused_signatures() bool -+filter_unused_approvals() bool -} -``` - -**Diagram sources** -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) - -**Section sources** -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L6-L107) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L240-L357) - -### Serialization and Network Transmission -- Transaction serialization: - - Digest computed by raw packing of the transaction - - Signature digest computed by raw packing of chain_id followed by transaction - - Merkle digest for signed transactions computed by raw packing the signed transaction -- Network messages: - - trx_message carries a signed_transaction for P2P broadcast - - Core message type for transactions is defined and reflected -- Block integration: - - signed_block contains a vector of signed_transaction - -```mermaid -sequenceDiagram -participant Tx as "signed_transaction" -participant Net as "trx_message" -participant Peer as "Peer Nodes" -Tx->>Tx : "sig_digest(chain_id)" -Tx->>Tx : "merkle_digest()" -Tx-->>Net : "Wrap in trx_message" -Net-->>Peer : "Transmit" -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L11-L28) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L11-L28) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -### Relationship Between Transactions and Blocks -- A block is a signed container holding a sequence of signed transactions. -- Each block maintains a Merkle root derived from its transactions. -- On acceptance, transactions become part of the blockchain state transitions. - -```mermaid -classDiagram -class signed_block { -+vector~signed_transaction~ transactions -+calculate_merkle_root() checksum_type -} -signed_block --> "1..*" signed_transaction : "contains" -``` - -**Diagram sources** -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -**Section sources** -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -### Transaction Lifecycle Management -- Duplicate detection and expiration: - - transaction_object persists packed transactions with expiration and id - - Index supports lookup by id and expiration ordering - - Expiration-based cleanup occurs during block processing -- Lifecycle stages: - - Constructed locally - - Validated and signed - - Broadcast via P2P - - Verified by peers - - Included in a block - - Indexed for duplicate detection and eventual expiration removal - -```mermaid -stateDiagram-v2 -[*] --> Created -Created --> Validated : "validate()" -Validated --> Signed : "sign(...)" -Signed --> Broadcast : "trx_message" -Broadcast --> Accepted : "peer verification" -Accepted --> Included : "included in block" -Included --> Indexed : "persist via transaction_object" -Indexed --> Expired : "expiration passes" -Expired --> [*] -``` - -**Diagram sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [transaction_object.cpp](file://libraries/chain/transaction_object.cpp#L6-L73) - -## Dependency Analysis -Key dependencies among transaction processing components: - -```mermaid -graph LR -OP["operations.hpp"] --> TRX["transaction.hpp"] -AU["authority.hpp"] --> TRX -TY["types.hpp"] --> TRX -TRX --> TRXC["transaction.cpp"] -TRXC --> SS["sign_state.hpp"] -SS --> SSC["sign_state.cpp"] -TRX --> BLK["block.hpp"] -TRX --> TXO["transaction_object.hpp"] -TRX --> CM["core_messages.hpp"] -TRX --> STU["sign_transaction.cpp"] -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L1-L107) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L27) - -**Section sources** -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L136) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [sign_state.hpp](file://libraries/protocol/include/graphene/protocol/sign_state.hpp#L10-L42) -- [sign_state.cpp](file://libraries/protocol/sign_state.cpp#L1-L107) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L131) -- [authority.hpp](file://libraries/protocol/include/graphene/protocol/authority.hpp#L9-L57) -- [types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L235) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L56) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L27) - -## Performance Considerations -- Signature verification cost scales with number of operations and authorities; minimize required signatures using minimize_required_signatures. -- Authority recursion depth limits prevent deep traversal; tune max_recursion appropriately. -- Serialization overhead is linear in transaction size; keep operations minimal and avoid unnecessary extensions. -- Network bandwidth: broadcast only validated transactions; leverage peer inventory messages to reduce redundant transmissions. - -## Troubleshooting Guide -Common validation and signing issues: -- Missing or extra signatures: - - verify_authority reports unused signatures and missing authorities - - assert_unused_approvals filters and reports unused approvals -- Authority mismatches: - - Mixing regular authority with active/master in same transaction is disallowed - - Missing required active/master/regular authorities cause assertion failures -- Duplicate signatures: - - get_signature_keys enforces uniqueness of signatures -- Expiration: - - Ensure expiration is set and within acceptable range; transactions past expiration are rejected - -Operational tips: -- Use the signing utility to compute digest and sig_digest for debugging -- Inspect transaction id and block_num/transaction_num in annotated_signed_transaction for post-inclusion tracing - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L76-L92) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L225-L237) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L27) - -## Conclusion -The transaction processing subsystem integrates a robust transaction model, strong authority verification, efficient serialization, and clear lifecycle management. By leveraging signed_transaction helpers, sign_state, and transaction_object, the system ensures secure, deterministic, and efficient transaction handling across the network and into the blockchain. - -## Appendices - -### Example Workflows - -- Constructing and signing a transaction: - - Set reference block and expiration - - Add operations and validate - - Compute sig_digest and append signatures - - Broadcast via trx_message - -- Authority minimization: - - Determine required signatures given available keys - - Minimize signatures while preserving authority coverage - -- Network transmission: - - Wrap signed_transaction in trx_message - - Send to peers; handle inventory and fetch requests - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L58-L65) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L240-L357) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp#L99-L110) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L28-L54) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Wallet Library.md b/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Wallet Library.md deleted file mode 100644 index 2be020cd50..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Core Libraries/Wallet Library.md +++ /dev/null @@ -1,680 +0,0 @@ -# Wallet Library - - -**Referenced Files in This Document** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp) -- [api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp) -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp) -- [wallet.cpp](file://libraries/wallet/wallet.cpp) -- [api_documentation_standin.cpp](file://libraries/wallet/api_documentation_standin.cpp) -- [generate_api_documentation.pl](file://libraries/wallet/generate_api_documentation.pl) -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt) -- [main.cpp](file://programs/cli_wallet/main.cpp) -- [content_api_object.hpp](file://libraries/api/include/graphene/api/content_api_object.hpp) -- [committee_api_object.hpp](file://libraries/api/include/graphene/api/committee_api_object.hpp) -- [invite_api_object.hpp](file://libraries/api/include/graphene/api/invite_api_object.hpp) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp) -- [paid_subscription_api_object.hpp](file://libraries/api/include/graphene/api/paid_subscription_api_object.hpp) - - -## Update Summary -**Changes Made** -- Added comprehensive documentation for the new VIZ DNS nameserver helper system -- Documented DNS metadata validation functions, data structures, and transaction operations -- Updated wallet API surface to include DNS management operations -- Enhanced transaction builder API with DNS record management capabilities -- Added detailed coverage of DNS record validation, metadata creation, and extraction functions - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [DNS Nameserver Helper System](#dns-nameserver-helper-system) -7. [Advanced Wallet Operations](#advanced-wallet-operations) -8. [Dependency Analysis](#dependency-analysis) -9. [Performance Considerations](#performance-considerations) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Conclusion](#conclusion) -12. [Appendices](#appendices) - -## Introduction -This document describes the Wallet Library that provides transaction signing capabilities and wallet management functionality for the blockchain node. It covers: -- Wallet state management, key storage, and transaction building -- Remote node integration via JSON-RPC-like APIs -- API documentation system for dynamic API generation and type introspection -- Encryption, key derivation, and security best practices -- Transaction construction, signature aggregation, and broadcast mechanisms -- Examples of wallet creation, key import/export, transaction signing workflows, and remote node integration -- Backup strategies, recovery procedures, and security considerations for key management -- **Updated**: Comprehensive coverage of the VIZ DNS nameserver helper system for managing DNS records through blockchain metadata - -## Project Structure -The Wallet Library is organized around a public API header and an implementation module, with supporting utilities for documentation and reflection. The CLI wallet demonstrates integration with a remote node. - -```mermaid -graph TB -subgraph "Wallet Library" -H["wallet.hpp"] -R["remote_node_api.hpp"] -A["api_documentation.hpp"] -F["reflect_util.hpp"] -C["wallet.cpp"] -S["api_documentation_standin.cpp"] -P["generate_api_documentation.pl"] -M["CMakeLists.txt"] -end -subgraph "CLI Wallet" -CLI["main.cpp"] -end -subgraph "Advanced Features" -CO["content_api_object.hpp"] -CM["committee_api_object.hpp"] -IO["invite_api_object.hpp"] -PSO["paid_subscription_objects.hpp"] -PSAPI["paid_subscription_api_object.hpp"] -DNS["DNS Nameserver Helper"] -end -H --> C -R --> C -A --> C -F --> C -S --> A -P --> A -M --> C -CLI --> H -CLI --> R -H --> CO -H --> CM -H --> IO -H --> PSO -H --> PSAPI -H --> DNS -``` - -**Diagram sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1-L1569) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L1-L295) -- [api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L1-L79) -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp#L1-L91) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1-L2887) -- [api_documentation_standin.cpp](file://libraries/wallet/api_documentation_standin.cpp#L1-L64) -- [generate_api_documentation.pl](file://libraries/wallet/generate_api_documentation.pl#L1-L180) -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L1-L85) -- [main.cpp](file://programs/cli_wallet/main.cpp#L1-L340) -- [content_api_object.hpp](file://libraries/api/include/graphene/api/content_api_object.hpp#L1-L71) -- [committee_api_object.hpp](file://libraries/api/include/graphene/api/committee_api_object.hpp#L1-L63) -- [invite_api_object.hpp](file://libraries/api/include/graphene/api/invite_api_object.hpp#L1-L39) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L1-L121) -- [paid_subscription_api_object.hpp](file://libraries/api/include/graphene/api/paid_subscription_api_object.hpp#L1-L63) - -**Section sources** -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L26-L85) -- [main.cpp](file://programs/cli_wallet/main.cpp#L166-L175) - -## Core Components -- wallet_api: Public interface for wallet operations, including key management, account queries, transaction building, signing, and broadcasting. -- wallet_api_impl: Internal implementation managing remote connections, local key storage, transaction assembly, and cryptographic operations. -- remote_node_api: Dummy classes and FC_API declarations that define the remote API surface for interacting with plugins on a remote node. -- api_documentation: Runtime or generated documentation container for wallet API methods. -- reflect_util: Utilities for dynamic operation name-to-ID mapping and variant conversion. -- CLI integration: Demonstrates connecting to a remote node, registering the wallet API, and exposing it over WebSocket/HTTP/TLS endpoints. -- **Updated**: DNS nameserver helper system for managing DNS records through blockchain metadata, including validation functions, data structures, and transaction operations. - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1569) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L183-L2887) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L44-L295) -- [api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L43-L79) -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp#L9-L91) -- [main.cpp](file://programs/cli_wallet/main.cpp#L166-L226) - -## Architecture Overview -The wallet connects to a remote node via fc::api connections to multiple plugin APIs. It maintains an in-memory keystore and uses remote APIs to fetch blockchain state, compute required signatures, and broadcast transactions. - -```mermaid -sequenceDiagram -participant CLI as "CLI Wallet" -participant Wallet as "wallet_api" -participant Impl as "wallet_api_impl" -participant RemoteDB as "remote_database_api" -participant RemoteNet as "remote_network_broadcast_api" -CLI->>Wallet : "unlock/set_password/import_key" -CLI->>Wallet : "begin_builder_transaction/add_operation_to_builder_transaction" -Wallet->>Impl : "preview_builder_transaction/sign_builder_transaction" -Impl->>RemoteDB : "get_accounts/get_dynamic_global_properties" -Impl->>Impl : "minimize_required_signatures" -Impl->>Impl : "sign(tx)" -Impl->>RemoteNet : "broadcast_transaction_synchronous(tx)" -RemoteNet-->>Impl : "annotated_signed_transaction" -Impl-->>Wallet : "signed transaction" -Wallet-->>CLI : "result" -``` - -**Diagram sources** -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L673-L820) -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L44-L252) -- [main.cpp](file://programs/cli_wallet/main.cpp#L177-L226) - -## Detailed Component Analysis - -### Wallet API Surface (wallet_api) -The public API exposes: -- Wallet lifecycle: is_new, is_locked, lock, unlock, set_password, load_wallet_file, save_wallet_file, quit -- Key management: import_key, list_keys, get_private_key, get_private_key_from_password, normalize_brain_key -- Queries: info, database_info, about, list_my_accounts, list_accounts, list_witnesses, get_account, get_block, get_ops_in_block, get_account_history, get_withdraw_routes -- Transactions: begin_builder_transaction, add_operation_to_builder_transaction, replace_operation_in_builder_transaction, preview_builder_transaction, sign_builder_transaction, propose_builder_transaction, remove_builder_transaction, approve_proposal, get_proposed_transactions, get_prototype_operation, serialize_transaction, sign_transaction -- Operations: create_account, create_account_with_keys, update_account, update_account_auth_key, update_account_auth_account, update_account_auth_threshold, update_account_meta, update_account_memo_key, delegate_vesting_shares, update_witness, update_chain_properties, versioned_update_chain_properties, set_voting_proxy, vote_for_witness, transfer, escrow_transfer, escrow_approve, escrow_dispute, escrow_release, transfer_to_vesting, withdraw_vesting, set_withdraw_vesting_route, post_content, vote, set_transaction_expiration, request_account_recovery, recover_account, change_recovery_account, get_master_history, get_encrypted_memo, decrypt_memo, get_inbox, get_outbox, follow - -**Updated**: Advanced operations including custom operations broadcasting, content management, committee system operations, invite functionality, reward systems, subscription management, account marketplace features, and DNS nameserver helper operations. - -Security and privacy helpers: -- Memo encryption/decryption and safety checks -- Password-based key derivation for account roles -- Brain key suggestion and normalization - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L104-L1569) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1062-L2887) - -### Wallet Implementation Internals (wallet_api_impl) -Key responsibilities: -- Remote API connections to database_api, operation_history, account_history, social_network, network_broadcast_api, follow, private_message, account_by_key, witness_api -- Local keystore management: _keys, _checksum, encrypt_keys/decrypt_keys -- Transaction builder: _builder_transactions -- Prototype operations for dynamic operation creation -- Result formatters for CLI display -- Chain ID and expiration handling - -```mermaid -classDiagram -class wallet_api { -+help() -+gethelp(method) -+info() -+database_info() -+about() -+list_my_accounts() -+list_accounts(lowerbound, limit) -+list_witnesses(lowerbound, limit) -+get_account(name) -+get_block(num) -+get_ops_in_block(num, only_virtual) -+get_account_history(account, from, limit) -+get_withdraw_routes(account, type) -+begin_builder_transaction() -+add_operation_to_builder_transaction(handle, op) -+replace_operation_in_builder_transaction(handle, op_index, op) -+preview_builder_transaction(handle) -+sign_builder_transaction(handle, broadcast) -+propose_builder_transaction(handle, author, title, memo, expiration, review, broadcast) -+remove_builder_transaction(handle) -+approve_proposal(author, title, delta, broadcast) -+get_proposed_transactions(account, from, limit) -+get_prototype_operation(operation_name) -+serialize_transaction(tx) -+sign_transaction(tx, broadcast) -+create_account(...) -+create_account_with_keys(...) -+update_account(...) -+update_account_auth_key(...) -+update_account_auth_account(...) -+update_account_auth_threshold(...) -+update_account_meta(...) -+update_account_memo_key(...) -+delegate_vesting_shares(...) -+update_witness(...) -+update_chain_properties(...) -+versioned_update_chain_properties(...) -+set_voting_proxy(...) -+vote_for_witness(...) -+transfer(...) -+escrow_transfer(...) -+escrow_approve(...) -+escrow_dispute(...) -+escrow_release(...) -+transfer_to_vesting(...) -+withdraw_vesting(...) -+set_withdraw_vesting_route(...) -+post_content(...) -+vote(...) -+set_transaction_expiration(seconds) -+request_account_recovery(...) -+recover_account(...) -+change_recovery_account(...) -+get_master_history(account) -+get_encrypted_memo(from, to, memo) -+decrypt_memo(encrypted_memo) -+get_inbox(to, newest, limit, offset) -+get_outbox(from, newest, limit, offset) -+follow(follower, following, what, broadcast) -+get_result_formatters() -+lock() -+unlock(password) -+set_password(password) -+import_key(wif_key) -+list_keys() -+get_private_key(pubkey) -+get_private_key_from_password(account, role, password) -+normalize_brain_key(s) -+suggest_brain_key() -+serialize_transaction(tx) -+get_transaction(tx_id) -+get_active_witnesses() -+get_wallet_filename() -+set_wallet_filename(filename) -+copy_wallet_file(destination) -+quit() -} -class wallet_api_impl { --method_documentation : api_documentation --_remote_database_api : fc : : api --_remote_operation_history : fc : : api --_remote_account_history : fc : : api --_remote_social_network : fc : : api --_remote_network_broadcast_api : fc : : api --_remote_follow : fc : : api --_remote_private_message : fc : : api --_remote_account_by_key : fc : : api --_remote_witness_api : fc : : api --_keys : map --_checksum : fc : : sha512 --_builder_transactions : map --_prototype_ops : flat_map --_tx_expiration_seconds : uint32_t -+info() -+database_info() -+about() -+begin_builder_transaction() -+add_operation_to_builder_transaction(...) -+replace_operation_in_builder_transaction(...) -+preview_builder_transaction(handle) -+sign_builder_transaction(handle, broadcast) -+propose_builder_transaction(...) -+remove_builder_transaction(handle) -+approve_proposal(...) -+get_proposed_transactions(...) -+get_account(name) -+get_prototype_operation(name) -+encrypt_keys() -+copy_wallet_file(destination) -+is_locked() -+sign_transaction(tx, broadcast) -+get_result_formatters() -} -wallet_api --> wallet_api_impl : "owns" -``` - -**Diagram sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1569) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L183-L2887) - -**Section sources** -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L183-L2887) - -### Remote Node API Contracts (remote_node_api) -Dummy classes define the remote API surface for each plugin. FC_API macros declare the method names and signatures exposed to the wallet. - -- remote_database_api: get_block, get_block_header, get_config, get_dynamic_global_properties, get_chain_properties, get_hardfork_version, get_next_scheduled_hardfork, lookup_account_names, lookup_accounts, get_account_count, get_master_history, get_recovery_request, get_escrow, get_withdraw_routes, get_transaction_hex, get_required_signatures, get_potential_signatures, verify_authority, verify_account_authority, get_accounts, get_database_info, get_proposed_transactions -- remote_operation_history: get_ops_in_block, get_transaction -- remote_account_history: get_account_history -- remote_social_network: get_trending_tags, get_tags_used_by_author, get_active_votes, get_account_votes, get_content, get_content_replies, get_discussions_by_* variants, get_replies_by_last_update -- remote_network_broadcast_api: broadcast_transaction, broadcast_transaction_synchronous, broadcast_block -- remote_follow: get_followers, get_following, get_follow_count, get_feed_entries, get_feed, get_blog_entries, get_blog, get_reblogged_by, get_blog_authors -- remote_private_message: get_inbox, get_outbox -- remote_account_by_key: get_key_references -- remote_witness_api: get_active_witnesses, get_witness_schedule, get_witnesses, get_witnesses_by_vote, get_witness_by_account, lookup_witness_accounts, get_witness_count - -These are consumed by wallet_api_impl to fetch blockchain state and broadcast transactions. - -**Section sources** -- [remote_node_api.hpp](file://libraries/wallet/include/graphene/wallet/remote_node_api.hpp#L44-L295) - -### API Documentation System -There are two modes: -- Generated documentation: Uses Doxygen and Perl to parse comments and generate a static api_documentation.cpp with method descriptions. -- Runtime reflection: When Doxygen/Perl are unavailable, api_documentation_standin.cpp builds descriptions by reflecting the wallet API at runtime. - -The api_documentation class stores method_name -> brief/detailed descriptions and exposes get_brief_description, get_detailed_description, and get_method_names. - -```mermaid -flowchart TD -Start(["Build"]) --> CheckTools{"Doxygen + Perl available?"} -CheckTools --> |Yes| RunPerl["Run generate_api_documentation.pl
Generate api_documentation.cpp"] -CheckTools --> |No| UseStandin["Copy api_documentation_standin.cpp"] -RunPerl --> Compile["Compile api_documentation.cpp"] -UseStandin --> Compile -Compile --> Runtime["At runtime, api_documentation reads method names"] -Runtime --> Help["help()/gethelp() return formatted descriptions"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L6-L24) -- [generate_api_documentation.pl](file://libraries/wallet/generate_api_documentation.pl#L1-L180) -- [api_documentation_standin.cpp](file://libraries/wallet/api_documentation_standin.cpp#L1-L64) -- [api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L43-L79) - -**Section sources** -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L6-L24) -- [generate_api_documentation.pl](file://libraries/wallet/generate_api_documentation.pl#L34-L88) -- [api_documentation_standin.cpp](file://libraries/wallet/api_documentation_standin.cpp#L54-L60) -- [api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L43-L79) - -### Reflection Utilities (reflect_util) -Provides: -- Static variant mapping for operations to simplify parsing operations by name -- Helper visitors to populate name-to-which maps and reconstruct variants from which() - -This enables dynamic operation creation and parsing without hardcoding operation IDs. - -**Section sources** -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp#L9-L91) - -### CLI Wallet Integration -The CLI wallet: -- Connects to a remote node via WebSocket -- Creates a wallet_api instance bound to the connection -- Registers the wallet API over WebSocket/HTTP/TLS endpoints -- Supports non-interactive command execution -- Handles reconnection on server disconnect - -```mermaid -sequenceDiagram -participant User as "User" -participant CLI as "cli_wallet main.cpp" -participant WS as "WebSocket Client" -participant Wallet as "wallet_api" -participant RPC as "RPC Server" -User->>CLI : "Start cli_wallet" -CLI->>WS : "connect(ws_server)" -CLI->>Wallet : "create wallet_api(...)" -CLI->>Wallet : "load_wallet_file()" -CLI->>RPC : "register_api(wallet_api)" -RPC-->>User : "Expose JSON-RPC methods" -WS-->>CLI : "Closed event" -CLI->>WS : "Reconnect" -``` - -**Diagram sources** -- [main.cpp](file://programs/cli_wallet/main.cpp#L166-L226) - -**Section sources** -- [main.cpp](file://programs/cli_wallet/main.cpp#L166-L226) - -## DNS Nameserver Helper System - -### DNS Data Structures and Constants -The wallet library introduces a comprehensive DNS nameserver helper system with the following core data structures: - -- **ns_record**: Represents a single DNS record tuple [type, value] with string type ("A" or "TXT") and string value (IPv4 address or TXT content like "ssl=") -- **ns_metadata_options**: Options for creating NS metadata including vector of A records, optional SSL hash, and TTL value -- **ns_summary**: Summary of NS data extracted from account metadata with A records, SSL hash, TTL, and presence flag -- **ns_validation_result**: Result of NS metadata validation with boolean validity flag and error messages array - -DNS helper constants: -- NS_DEFAULT_TTL: Default TTL of 28800 seconds (8 hours) -- NS_MAX_TXT_LENGTH: Maximum TXT record length per NS standard (256 characters) -- NS_SHA256_HEX_LENGTH: SHA256 hash length in hex characters (64 characters) - -### DNS Validation Functions -The system provides comprehensive validation functions: - -- **ns_validate_ipv4()**: Validates IPv4 address format with proper octet ranges (0-255) and rejects invalid formats -- **ns_validate_sha256_hash()**: Validates SHA256 hash format requiring exactly 64 hexadecimal characters -- **ns_validate_ttl()**: Ensures TTL values are positive integers -- **ns_validate_ssl_txt_record()**: Validates SSL TXT record format "ssl=<64-char-hex-hash>" -- **ns_validate_metadata()**: Performs complete validation of NS metadata with comprehensive error reporting - -### DNS Metadata Operations -The system offers complete DNS record management through blockchain metadata: - -- **ns_create_metadata()**: Creates NS metadata JSON string from options, building ns arrays with A and TXT records -- **ns_get_summary()**: Extracts complete NS summary from account metadata, parsing A records and SSL hashes -- **ns_extract_a_records()**: Extracts IPv4 addresses from account metadata -- **ns_extract_ssl_hash()**: Extracts SSL certificate hash from TXT records -- **ns_extract_ttl()**: Extracts TTL value from account metadata -- **ns_set_records()**: Sets NS records for an account, merging with existing metadata while preserving other fields -- **ns_remove_records()**: Removes NS records from account metadata while preserving other metadata fields - -### Transaction Integration -DNS operations integrate seamlessly with the wallet's transaction system: -- All DNS operations return signed transactions that can be broadcast -- Uses account_metadata_operation for blockchain updates -- Maintains backward compatibility with existing account metadata -- Supports both validation-only operations and transaction creation - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L24-L62) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1311-L1420) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L2578-L2887) - -## Advanced Wallet Operations - -### Custom Operations Broadcasting -The wallet now supports broadcasting custom operations with flexible authorization requirements: - -- **custom()**: Broadcast custom operations with specified active and regular authority requirements -- Supports arbitrary JSON data payloads for custom business logic -- Enables decentralized application development on the blockchain - -### Content Management System -Comprehensive content creation, modification, and reward distribution capabilities: - -- **post_content()**: Create or update content with title, body, metadata, and curation settings -- **delete_content()**: Remove content with proper authorization validation -- **vote()**: Vote on content with weighted influence affecting reward distribution -- **Content API Objects**: Rich content metadata including voting statistics, payout information, and beneficiary configurations - -### Committee System Operations -Decentralized governance and funding mechanisms: - -- **committee_worker_create_request()**: Create funding requests for community projects -- **committee_worker_cancel_request()**: Cancel pending funding requests -- **committee_vote_request()**: Vote on funding requests with percentage-based weighting -- **Committee API Objects**: Request tracking, voting states, and funding distribution details - -### Invite System Operations -Account creation and fund transfer facilitation: - -- **create_invite()**: Generate invites with configurable balances and keys -- **claim_invite_balance()**: Claim funds from successful invites -- **invite_registration()**: Register new accounts using invite secrets -- **use_invite_balance()**: Transfer invite balance to vesting shares -- **Invite API Objects**: Invite lifecycle tracking, claiming states, and balance management - -### Reward Distribution System -Energy-based and fixed reward mechanisms: - -- **award()**: Energy-based rewards with customizable energy allocation and beneficiaries -- **fixed_award()**: Fixed amount rewards with maximum energy constraints -- **Beneficiary Routing**: Configurable reward distribution to multiple accounts -- **Virtual Operations**: Automatic reward processing and distribution tracking - -### Paid Subscription Management -Subscription-based content monetization: - -- **set_paid_subscription()**: Create subscription plans with pricing tiers -- **paid_subscribe()**: Subscribe to content creators with auto-renewal options -- **Subscription API Objects**: Active subscriber tracking, renewal scheduling, and revenue analytics -- **Marketplace Integration**: Creator earnings and subscriber management - -### Account Marketplace Operations -Secondary market for digital assets: - -- **set_account_price()**: Put accounts up for sale with listing parameters -- **set_subaccount_price()**: Offer subaccount creation services -- **buy_account()**: Purchase accounts with key replacement and delegation handling -- **target_account_sale()**: Direct sales to specific buyers with escrow protection -- **Auction Integration**: Bid management and sale completion tracking - -**Updated**: DNS nameserver helper operations including validation functions, metadata creation, record extraction, and transaction management for comprehensive DNS record management on the blockchain. - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L958-L1569) -- [content_api_object.hpp](file://libraries/api/include/graphene/api/content_api_object.hpp#L12-L58) -- [committee_api_object.hpp](file://libraries/api/include/graphene/api/committee_api_object.hpp#L23-L51) -- [invite_api_object.hpp](file://libraries/api/include/graphene/api/invite_api_object.hpp#L13-L30) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L75) -- [paid_subscription_api_object.hpp](file://libraries/api/include/graphene/api/paid_subscription_api_object.hpp#L32-L51) - -## Dependency Analysis -The wallet library depends on: -- Protocol and chain types for operations and signing -- Plugins for remote APIs (database_api, operation_history, account_history, social_network, tags, network_broadcast_api, follow, private_message, account_by_key, witness_api) -- Utilities for key conversion and word lists -- fc for networking, RPC, crypto, and containers -- **Updated**: Advanced feature dependencies for content management, committee operations, invite system, reward distribution, paid subscriptions, marketplace functionality, and DNS nameserver helper system. - -```mermaid -graph LR -Wallet["graphene_wallet"] --> Protocol["graphene_protocol"] -Wallet --> Chain["graphene_chain"] -Wallet --> Network["graphene_network"] -Wallet --> DB["graphene::database_api"] -Wallet --> OpHist["graphene::operation_history"] -Wallet --> AccHist["graphene::account_history"] -Wallet --> Social["graphene::social_network"] -Wallet --> Tags["graphene::tags"] -Wallet --> NetBCast["graphene::network_broadcast_api"] -Wallet --> Follow["graphene::follow"] -Wallet --> PM["graphene::private_message"] -Wallet --> AccByKey["graphene::account_by_key"] -Wallet --> validator["graphene::witness_api"] -Wallet --> Util["graphene_utilities"] -Wallet --> FC["fc"] -Wallet --> ContentAPI["content_api_object.hpp"] -Wallet --> CommitteeAPI["committee_api_object.hpp"] -Wallet --> InviteAPI["invite_api_object.hpp"] -Wallet --> PaidSubAPI["paid_subscription_api_object.hpp"] -Wallet --> DNSHelper["DNS Nameserver Helper"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) -- [content_api_object.hpp](file://libraries/api/include/graphene/api/content_api_object.hpp#L1-L71) -- [committee_api_object.hpp](file://libraries/api/include/graphene/api/committee_api_object.hpp#L1-L63) -- [invite_api_object.hpp](file://libraries/api/include/graphene/api/invite_api_object.hpp#L1-L39) -- [paid_subscription_api_object.hpp](file://libraries/api/include/graphene/api/paid_subscription_api_object.hpp#L1-L63) - -**Section sources** -- [CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) - -## Performance Considerations -- Minimal caching: The wallet assumes a high-bandwidth, low-latency connection to the node and performs minimal caching, optimizing for responsiveness over persistence. -- Transaction signing minimization: The implementation computes minimal required signatures to reduce signing overhead. -- Batched operations: Use builder transactions to assemble multiple operations efficiently before signing and broadcasting. -- Avoid unnecessary remote calls: Reuse cached account data where possible and batch queries. -- **Updated**: Advanced feature performance considerations including content indexing, committee voting calculations, subscription billing cycles, marketplace transaction optimization, and DNS metadata parsing efficiency. - -## Troubleshooting Guide -Common issues and remedies: -- Wallet locked/uninitialized: Use set_password to initialize a new wallet, then unlock with the password. -- Importing keys: Ensure the WIF key is valid; invalid keys will cause errors during import. -- Broadcasting failures: Verify network connectivity to the remote node and that the transaction is valid and within expiration. -- Memo decryption failures: Ensure the correct private key is present in the wallet for memo decryption. -- Authority errors: When updating authorities, ensure thresholds and weights are valid; impossible authorities can cause assertion failures. -- **Updated**: Advanced feature troubleshooting including content validation errors, committee request processing failures, invite claim issues, subscription payment problems, marketplace transaction conflicts, and DNS metadata validation failures. - -**Section sources** -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1203-L1232) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1006-L1023) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L807-L820) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1995-L2025) - -## Conclusion -The Wallet Library provides a robust, extensible framework for managing keys, constructing transactions, and interacting with a remote blockchain node. Its modular design, strong security practices, and dynamic API documentation system make it suitable for both interactive and automated use cases. **Updated**: The library now supports comprehensive advanced blockchain interaction capabilities including custom operations broadcasting, content management, committee governance, invite systems, reward distribution, subscription management, marketplace functionality, and a complete DNS nameserver helper system for managing DNS records through blockchain metadata, making it a complete solution for modern decentralized applications. - -## Appendices - -### Security Best Practices -- Protect wallet files: Use strong passwords and restrict filesystem permissions. -- Back up wallets: Regularly copy wallet files and verify backups. -- Avoid exposing private keys: Never paste private keys into untrusted terminals or logs. -- Validate memos: Use built-in memo safety checks to prevent accidental exposure of private keys. -- Use remote signing: Prefer offline signing workflows when possible. -- **Updated**: Advanced security considerations including content moderation, committee voting integrity, invite system protection, subscription billing security, marketplace transaction validation, and DNS metadata integrity verification. - -**Section sources** -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L243-L270) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1203-L1232) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1740-L1794) - -### Example Workflows - -- Wallet creation and initialization - - Create a new wallet file and set a password - - Unlock the wallet to perform operations - - Import keys or generate brain keys for new accounts - -- Key import/export - - Import WIF keys into the wallet - - List keys and export them securely - -- Transaction signing workflow - - Build a transaction using the builder API - - Preview and sign the transaction - - Optionally propose or broadcast the transaction - -- Remote node integration - - Connect to a remote node via WebSocket - - Register the wallet API over RPC endpoints - - Execute commands and receive formatted results - -- **Updated**: Advanced workflow examples including content creation with voting rewards, committee participation for project funding, invite-based account creation, subscription management, marketplace transactions, and DNS record management through blockchain metadata. - -**Section sources** -- [main.cpp](file://programs/cli_wallet/main.cpp#L166-L226) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L132-L179) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L1062-L1123) - -### Advanced Feature Usage Examples - -#### Content Management Workflow -1. Create content with post_content() operation -2. Monitor voting and reward accumulation -3. Update content with subsequent posts -4. Handle content deletion with proper authorization - -#### Committee Participation Workflow -1. Review active funding requests -2. Evaluate project proposals and technical merit -3. Cast weighted votes on funding requests -4. Track funding distribution and project completion - -#### Invite System Workflow -1. Generate invites with appropriate funding -2. Share invite secrets with intended recipients -3. Process successful claims and registrations -4. Manage invite lifecycle and expiration - -#### Subscription Management Workflow -1. Create subscription plans with pricing tiers -2. Monitor active subscribers and renewals -3. Process automatic payments and revenue distribution -4. Handle subscription cancellations and refunds - -#### Marketplace Operations Workflow -1. List accounts or subaccounts for sale -2. Monitor bidding activity and auction progress -3. Execute sales with proper key replacement -4. Handle target sales to specific buyers - -#### DNS Nameserver Helper Workflow -1. Validate DNS metadata using ns_validate_metadata() before creation -2. Create NS metadata with ns_create_metadata() including A records and SSL hashes -3. Extract existing DNS records using ns_get_summary() for verification -4. Set DNS records with ns_set_records() to update account metadata -5. Remove DNS records with ns_remove_records() when needed -6. Monitor TTL values and record validity through extraction functions - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L958-L1569) -- [content_object.hpp](file://libraries/chain/include/graphene/chain/content_object.hpp#L56-L114) -- [committee_api_object.hpp](file://libraries/api/include/graphene/api/committee_api_object.hpp#L23-L51) -- [invite_api_object.hpp](file://libraries/api/include/graphene/api/invite_api_object.hpp#L13-L30) -- [paid_subscription_objects.hpp](file://libraries/chain/include/graphene/chain/paid_subscription_objects.hpp#L15-L75) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1311-L1420) -- [wallet.cpp](file://libraries/wallet/wallet.cpp#L2578-L2887) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/API Request Processing.md b/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/API Request Processing.md deleted file mode 100644 index 9dcdb8f062..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/API Request Processing.md +++ /dev/null @@ -1,319 +0,0 @@ -# API Request Processing - - -**Referenced Files in This Document** -- [main.cpp](file://programs/vizd/main.cpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) -- [api.cpp](file://plugins/database_api/api.cpp) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp) -- [account_api_object.cpp](file://libraries/api/account_api_object.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains how API requests are processed from receipt to response generation in the node. It covers JSON-RPC request parsing, method routing, parameter validation, database query execution, result formatting, and the webserver plugin’s role in handling HTTP and WebSocket traffic. It also documents authentication support, error handling strategies, response formatting standards, and performance monitoring techniques. - -## Project Structure -The API request lifecycle spans several components: -- Application entry point initializes plugins and starts the node. -- Webserver plugin handles HTTP and WebSocket connections and forwards JSON-RPC payloads to the JSON-RPC plugin. -- JSON-RPC plugin parses requests, validates method signatures, routes to registered APIs, executes handlers, and serializes responses. -- Database API plugin implements core blockchain queries and returns formatted results. -- Authentication utility plugin provides signature verification APIs used by clients and services. - -```mermaid -graph TB -Client["Client"] -WS["WebSocket Endpoint
HTTP Endpoint"] -Web["Webserver Plugin"] -RPC["JSON-RPC Plugin"] -DB["Database API Plugin"] -Auth["Auth Utility Plugin"] -Client --> WS -WS --> Web -Web --> RPC -RPC --> DB -RPC --> Auth -``` - -**Diagram sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L402-L423) -- [api.cpp](file://plugins/database_api/api.cpp#L218-L223) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L86-L90) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L266-L331) - -## Core Components -- Webserver plugin: Accepts HTTP and WebSocket connections, defers HTTP responses, posts work to a thread pool, and delegates JSON-RPC payloads to the JSON-RPC plugin. -- JSON-RPC plugin: Parses JSON-RPC 2.0 requests, validates method names and parameters, routes to registered API methods, and serializes responses with proper error handling. -- Database API plugin: Implements core blockchain queries (blocks, accounts, globals, authority helpers) and returns typed results suitable for JSON serialization. -- Authentication utility plugin: Provides signature verification APIs for client-side or service-side authentication checks. - -**Section sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L151-L370) -- [api.cpp](file://plugins/database_api/api.cpp#L218-L353) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L69-L78) - -## Architecture Overview -The request processing pipeline is event-driven and asynchronous: -- Incoming HTTP requests are deferred and handled asynchronously; WebSocket messages are posted to a thread pool. -- The JSON-RPC plugin parses the request, validates the method and parameters, and invokes the appropriate API handler. -- Handlers execute database reads behind weak read locks and return results as fc::variant, which the JSON-RPC plugin serializes to JSON. -- Errors are captured and returned as JSON-RPC error objects with standardized codes and messages. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "WebSocket/HTTP" -participant Web as "Webserver Plugin" -participant RPC as "JSON-RPC Plugin" -participant DB as "Database API Plugin" -Client->>WS : "Send JSON-RPC request" -WS->>Web : "Dispatch message" -Web->>RPC : "Forward payload" -RPC->>RPC : "Parse & validate" -RPC->>DB : "Invoke API handler" -DB-->>RPC : "Return result" -RPC-->>Web : "Serialize response" -Web-->>Client : "JSON-RPC response" -``` - -**Diagram sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) -- [api.cpp](file://plugins/database_api/api.cpp#L218-L223) - -## Detailed Component Analysis - -### JSON-RPC Request Parsing and Method Routing -- Request parsing: - - Validates presence of jsonrpc equals "2.0" and method field. - - Supports two forms: direct "api.method" and legacy "call" with params array containing [api, method, args]. - - Extracts method name and parameters, sets msg_pack id for response correlation. -- Method routing: - - Maintains a registry of registered APIs keyed by plugin name and method. - - Resolves method to a callable handler and prepares arguments for invocation. -- Parameter validation: - - Enforces argument count and types via macros and assertions. - - Returns structured errors for parse failures, invalid params, and missing methods. - -```mermaid -flowchart TD -Start(["Receive JSON-RPC"]) --> CheckVersion["Check 'jsonrpc' == '2.0'"] -CheckVersion --> |Invalid| ErrVersion["Return INVALID_REQUEST"] -CheckVersion --> |Valid| CheckMethod["Check 'method' present"] -CheckMethod --> |Missing| ErrNoMethod["Return INVALID_REQUEST"] -CheckMethod --> ParseParams["Parse params (direct or 'call')"] -ParseParams --> FindMethod["Find registered API handler"] -FindMethod --> |Not Found| ErrNotFound["Return METHOD_NOT_FOUND"] -FindMethod --> ExecCall["Execute handler with args"] -ExecCall --> Result["Serialize result"] -ExecCall --> |Exception| ErrDuringCall["Return ERROR_DURING_CALL"] -Result --> End(["Send response"]) -ErrDuringCall --> End -ErrNotFound --> End -ErrNoMethod --> End -ErrVersion --> End -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L213) - -**Section sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L215-L256) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L213) - -### Parameter Validation and Error Handling -- Validation patterns: - - Argument count checks using macros to enforce exact or range-based counts. - - Type assertions during parameter extraction. -- Error handling: - - Dedicated JSON-RPC error codes for invalid requests, parse errors, method not found, and errors during call. - - Exceptions are caught and mapped to JSON-RPC error objects with optional data payloads. - - Unknown errors are captured and reported with a generic message. - -```mermaid -flowchart TD -A["Extract args"] --> B{"Arg count ok?"} -B --> |No| E1["Return INVALID_PARAMS"] -B --> |Yes| C["Cast types"] -C --> D{"Type ok?"} -D --> |No| E2["Return INVALID_PARAMS"] -D --> |Yes| F["Proceed to handler"] -``` - -**Diagram sources** -- [api.cpp](file://plugins/database_api/api.cpp#L17-L21) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L295-L310) - -**Section sources** -- [api.cpp](file://plugins/database_api/api.cpp#L17-L21) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L295-L310) - -### Database Query Execution and Result Formatting -- Handlers execute database reads behind a weak read lock to avoid blocking writers. -- Results are returned as typed structures (e.g., account objects, blocks) that serialize naturally to JSON. -- Example handlers: - - Block retrieval by number. - - Account lookup by names. - - Dynamic global properties and chain configuration. -- Result formatting: - - fc::variant is used internally; JSON serialization is performed by the JSON-RPC plugin. - -```mermaid -sequenceDiagram -participant RPC as "JSON-RPC Plugin" -participant DB as "Database API Plugin" -participant Chain as "Chain Database" -RPC->>DB : "get_block_header(args)" -DB->>Chain : "Fetch block by number" -Chain-->>DB : "Optional" -DB-->>RPC : "Return fc : : variant" -RPC-->>RPC : "Serialize to JSON-RPC response" -``` - -**Diagram sources** -- [api.cpp](file://plugins/database_api/api.cpp#L218-L223) -- [api.cpp](file://plugins/database_api/api.cpp#L225-L231) - -**Section sources** -- [api.cpp](file://plugins/database_api/api.cpp#L218-L223) -- [api.cpp](file://plugins/database_api/api.cpp#L225-L231) -- [account_api_object.cpp](file://libraries/api/account_api_object.cpp#L9-L45) - -### Webserver Plugin: HTTP/WS Handling and Response Serialization -- Endpoint configuration supports separate HTTP and WebSocket endpoints or a combined endpoint. -- Thread pool sizing controls concurrency for request handling. -- WebSocket: - - Text payloads are forwarded to the JSON-RPC plugin; non-string payloads return an error message. -- HTTP: - - Requests are deferred; the response body is set asynchronously and sent after completion. - - Errors during parsing are handled and a standardized HTTP response is returned. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "WebSocket Server" -participant Web as "Webserver Plugin" -participant RPC as "JSON-RPC Plugin" -Client->>WS : "Text frame" -WS->>Web : "handle_ws_message" -Web->>RPC : "api->call(payload, callback)" -RPC-->>Web : "Serialized JSON-RPC" -Web-->>WS : "Send response" -WS-->>Client : "Response" -``` - -**Diagram sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L214) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L216-L246) - -**Section sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L254-L264) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L112-L165) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L192-L246) - -### Authentication Mechanisms -- Signature verification API: - - Verifies signatures against account authorities (active/master/regular) for given digest and signatures. - - Returns the derived public keys used for verification. -- Integration: - - Clients can call this API to validate claims or proofs-of-authority before invoking protected operations. - -```mermaid -flowchart TD -Start(["Client provides account, level, digest, signatures"]) --> Verify["Verify authority signatures"] -Verify --> Result{"Has authority?"} -Result --> |Yes| ReturnKeys["Return derived public keys"] -Result --> |No| Err["Throw assertion error"] -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L67) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L69-L78) - -**Section sources** -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L31-L67) -- [plugin.cpp](file://plugins/auth_util/plugin.cpp#L69-L78) - -### Rate Limiting -- No explicit rate limiting is implemented in the analyzed components. Consider deploying external rate limiting at the reverse proxy or firewall level if needed. - -[No sources needed since this section provides general guidance] - -## Dependency Analysis -- Application bootstrap registers plugins and starts the node; the webserver plugin depends on the JSON-RPC plugin. -- JSON-RPC plugin depends on fc::variant serialization and websocketpp for transport. -- Database API plugin depends on the chain database and exposes typed API objects. -- Authentication utility plugin depends on chain database and protocol types. - -```mermaid -graph LR -App["Application Entry"] -Web["Webserver Plugin"] -RPC["JSON-RPC Plugin"] -DB["Database API Plugin"] -Auth["Auth Utility Plugin"] -App --> Web -Web --> RPC -RPC --> DB -RPC --> Auth -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L314-L327) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L378-L395) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L314-L327) - -## Performance Considerations -- Concurrency model: - - The webserver plugin uses a configurable thread pool to handle requests concurrently. - - WebSocket and HTTP paths both post work to the same pool, enabling efficient handling of mixed traffic. -- Monitoring: - - The JSON-RPC plugin logs timing for each request, including elapsed time and error conditions, aiding performance diagnostics. -- Recommendations: - - Tune thread pool size according to CPU cores and expected load. - - Monitor JSON-RPC timings and error rates to identify hotspots. - - Offload heavy operations to background tasks if necessary and keep the request path lightweight. - -**Section sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L266-L269) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L258-L288) - -## Troubleshooting Guide -- Common JSON-RPC errors: - - INVALID_REQUEST: Missing or invalid jsonrpc/version or missing method. - - METHOD_NOT_FOUND: Unknown method or API. - - INVALID_PARAMS: Wrong argument count or wrong types. - - ERROR_DURING_CALL: Exception thrown inside handler. -- Symptoms and fixes: - - Empty or malformed responses: Verify request payload and method naming. - - 500-class HTTP responses: Inspect server logs for exceptions and error messages. - - Slow responses: Review JSON-RPC timing logs and adjust thread pool size. - -**Section sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L295-L310) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L231-L244) - -## Conclusion -The API request processing pipeline is robust, modular, and designed for high concurrency. JSON-RPC parsing, method routing, and parameter validation occur early, while database queries are executed efficiently behind read locks. The webserver plugin provides flexible HTTP/WS handling with strong error reporting and performance logging. Authentication utilities complement the stack by offering signature verification capabilities. For production deployments, consider external rate limiting and continuous monitoring of request latency and error rates. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Block Processing and Validation.md b/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Block Processing and Validation.md deleted file mode 100644 index 92d302accc..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Block Processing and Validation.md +++ /dev/null @@ -1,447 +0,0 @@ -# Block Processing and Validation - - -**Referenced Files in This Document** -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [block_header.hpp](file://libraries/protocol/include/graphene/protocol/block_header.hpp) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) - - -## Update Summary -**Changes Made** -- Enhanced fork handling with comprehensive fallback mechanisms for missing irreversible blocks during fork resolution and chain reorganization events -- Improved block log accessibility with dual-path retrieval: block_log → dlt_block_log → fork_database fallback chain -- Added robust gap detection and logging for DLT block log gaps during LIB advancement -- Strengthened chain validation reliability by preventing chain stalls due to missing blocks -- Enhanced Validator Plugin block post-validation logic with defensive programming to prevent runtime errors when validator accounts aren't found during validation - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the complete block processing and validation pipeline in the VIZ node, including header validation, transaction extraction, state application, fork resolution, block persistence, and validator block production coordination. It also covers performance characteristics and optimization techniques used for high-throughput block processing. - -**Updated** Enhanced with comprehensive fallback mechanisms for missing irreversible blocks during fork resolution and chain reorganization events, improving chain validation reliability and preventing chain stalls. The block log accessibility system now provides a robust fallback chain: block_log → dlt_block_log → fork_database, ensuring blocks remain accessible even when intermediate storage systems are unavailable. - -## Project Structure -The block processing pipeline spans three primary subsystems: -- Protocol-level block representation and header definitions -- Chain database that orchestrates validation, fork management, and state application -- Dual block log system with fallback mechanisms for durable, append-only persistence of blocks - -```mermaid -graph TB -subgraph "Protocol Layer" -BH["block_header.hpp"] -SB["block.hpp"] -end -subgraph "Chain Layer" -DBH["database.hpp"] -DBC["database.cpp"] -FDH["fork_database.hpp"] -FDC["fork_database.cpp"] -BLH["block_log.hpp"] -BLC["block_log.cpp"] -DLTH["dlt_block_log.hpp"] -D LTCPP["dlt_block_log.cpp"] -end -subgraph "Plugins" -WIT["validator.hpp"] -WITCPP["validator.cpp"] -end -BH --> SB -SB --> DBH -DBH --> DBC -DBC --> FDH -DBC --> BLH -DBC --> DLTH -FDH --> FDC -BLH --> BLC -DLTH --> D LTCPP -WIT --> DBH -WITCPP --> DBH -``` - -**Diagram sources** -- [block_header.hpp:1-43](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp:1-19](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [database.cpp:737-913](file://libraries/chain/database.cpp#L737-L913) -- [fork_database.hpp:1-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [block_log.cpp:238-300](file://libraries/chain/block_log.cpp#L238-L300) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [dlt_block_log.cpp:162-242](file://libraries/chain/dlt_block_log.cpp#L162-L242) -- [validator.hpp:1-70](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L1-L70) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) - -**Section sources** -- [block_header.hpp:1-43](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [block.hpp:1-19](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp:1-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [validator.hpp:1-70](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L1-L70) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) - -## Core Components -- Protocol block model: Defines the signed block structure and signed block header, including merkle roots and validator signatures. -- Fork database: Maintains a tree of candidate blocks, supports branching, linking, and selection of the heaviest chain. -- Dual block log system: Provides append-only, random-access persistence of blocks with fallback mechanisms: - - Primary block_log for irreversible blocks - - DLT rolling block_log for recent blocks with sliding window capability - - Fork database as final fallback for reversible blocks -- Database: Orchestrates validation, fork resolution, state application, and block logging with comprehensive fallback logic. -- Validator Plugin: Coordinates block production for validator nodes and defines acceptance criteria with enhanced defensive programming. - -**Updated** The dual block log system now provides comprehensive fallback mechanisms, with block retrieval following the chain: block_log → dlt_block_log → fork_database. This ensures chain validation reliability by preventing chain stalls due to missing blocks in any single storage system. - -**Section sources** -- [block.hpp:9-13](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L13) -- [block_header.hpp:25-35](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L25-L35) -- [fork_database.hpp:53-96](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L96) -- [block_log.hpp:38-68](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L68) -- [dlt_block_log.hpp:13-33](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L13-L33) -- [database.hpp:36-287](file://libraries/chain/include/graphene/chain/database.hpp#L36-L287) -- [validator.hpp:20-32](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) - -## Architecture Overview -The block processing pipeline integrates protocol definitions, fork management, and dual persistent storage systems with comprehensive fallback mechanisms: - -```mermaid -sequenceDiagram -participant Net as "Network/P2P" -participant DB as "database.cpp" -participant FH as "fork_database.cpp" -participant BL as "block_log.cpp" -participant DLT as "dlt_block_log.cpp" -Net->>DB : "Receive signed_block" -DB->>DB : "validate_block()" -DB->>DB : "_validate_block() + validate_block_header()" -DB->>FH : "push_block(new_block)" -alt "Links to known chain" -FH-->>DB : "new_head" -DB->>DB : "apply_block() -> _apply_block()" -DB->>BL : "append(block) (optional)" -DB-->>Net : "accepted" -else "Unlinkable" -FH-->>DB : "store in unlinked cache" -DB-->>Net : "deferred" -end -DB->>DB : "update_last_irreversible_block()" -alt "LIB advancement" -DB->>BL : "append(block) to block_log" -DB->>DLT : "append(block) to dlt_block_log (fallback)" -DB->>FH : "fetch from fork_database" -end -``` - -**Diagram sources** -- [database.cpp:737-913](file://libraries/chain/database.cpp#L737-L913) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) -- [dlt_block_log.cpp:336-340](file://libraries/chain/dlt_block_log.cpp#L336-L340) -- [validator.hpp:20-32](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) - -## Detailed Component Analysis - -### Enhanced Block Validation Pipeline with Fallback Mechanisms -The validation pipeline is exposed via the database interface and now includes comprehensive fallback mechanisms: -- Header validation: Verifies cryptographic signatures and structural constraints. -- Transaction extraction: Iterates transactions embedded in the block. -- State application: Applies each transaction's operations against the current state. -- Hardfork handling: Enforces consensus rules per hardfork schedule. -- Optional checks: Signature verification, TAPoS, block size limits, and authority checks depending on skip flags. -- **Enhanced fallback chain**: Block retrieval follows block_log → dlt_block_log → fork_database hierarchy for maximum reliability. - -```mermaid -flowchart TD -Start(["validate_block()"]) --> CheckSkip["Compute skip flags"] -CheckSkip --> ValidateHeader["validate_block_header()"] -ValidateHeader --> ExtractTxs["Iterate transactions"] -ExtractTxs --> ApplyTx["apply_transaction() per tx"] -ApplyTx --> Hardforks["process_hardforks() / apply_hardfork()"] -Hardforks --> FallbackChain["Block Access Fallback Chain"] -FallbackChain --> BL["block_log.read_block_by_num()"] -BL --> |Missing| DLT["dlt_block_log.read_block_by_num()"] -DLT --> |Missing| FD["fork_database.fetch_block_on_main_branch_by_number()"] -FD --> |Found| Done(["Validation OK"]) -FD --> |Missing| Error["Return block_id_type()"] -Error --> Done -``` - -**Diagram sources** -- [database.hpp:194-206](file://libraries/chain/include/graphene/chain/database.hpp#L194-L206) -- [database.cpp:737-757](file://libraries/chain/database.cpp#L737-L757) -- [database.cpp:3443-3509](file://libraries/chain/database.cpp#L3443-L3509) -- [database.cpp:812-825](file://libraries/chain/database.cpp#L812-L825) - -**Section sources** -- [database.hpp:56-73](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [database.hpp:194-206](file://libraries/chain/include/graphene/chain/database.hpp#L194-L206) -- [database.cpp:737-757](file://libraries/chain/database.cpp#L737-L757) -- [database.cpp:3443-3509](file://libraries/chain/database.cpp#L3443-L3509) -- [database.cpp:812-825](file://libraries/chain/database.cpp#L812-L825) - -### Enhanced Fork Resolution and Chain Selection with Gap Detection -Fork resolution maintains a tree of candidate blocks and selects the heaviest chain with comprehensive gap detection: -- Unlinkable blocks are cached and later linked when their parent arrives. -- The head advances to the highest-numbered block. -- Branch-from algorithm computes divergent branches to a common ancestor for reorganization decisions. -- **Enhanced gap detection**: DLT block log gaps are logged and handled gracefully during LIB advancement. - -```mermaid -classDiagram -class fork_database { -+push_block(b) -+set_head(h) -+fetch_branch_from(first, second) -+walk_main_branch_to_num(n) -+fetch_block_on_main_branch_by_number(n) -+_push_block(item) -+_push_next(new_item) -} -class fork_item { -+num -+id -+data -+prev -+invalid -+previous_id() -} -fork_database --> fork_item : "stores" -``` - -**Diagram sources** -- [fork_database.hpp:53-96](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L96) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) - -**Section sources** -- [fork_database.hpp:53-96](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L96) -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [fork_database.cpp:168-210](file://libraries/chain/fork_database.cpp#L168-L210) - -### Enhanced Block Logging and Persistence with Fallback Chain -Blocks are persisted to dual log systems with comprehensive fallback mechanisms: -- Main file stores serialized blocks with forward pointers. -- Index file maps block number to file offset. -- DLT rolling block_log provides sliding window storage for recent blocks. -- Startup routines reconcile log and index, reconstructing the index if needed. -- Append operations are atomic with respect to index alignment. -- **Enhanced fallback chain**: During LIB advancement, blocks are written to both block_log and dlt_block_log, with graceful handling of gaps. - -```mermaid -flowchart TD -Open(["open(file)"]) --> CheckFiles["Check log/index existence"] -CheckFiles --> |Both present| CompareHeads["Compare heads"] -CompareHeads --> |Mismatch| RebuildIdx["construct_index()"] -CompareHeads --> |Match| Ready["Ready"] -RebuildIdx --> Ready -Ready --> Append["append(block)"] -Append --> WriteMain["Write block + forward ptr"] -WriteMain --> WriteIdx["Write index entry"] -WriteIdx --> UpdateHead["Update head"] -``` - -**Diagram sources** -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [block_log.cpp:115-132](file://libraries/chain/block_log.cpp#L115-L132) -- [block_log.cpp:195-219](file://libraries/chain/block_log.cpp#L195-L219) -- [dlt_block_log.cpp:162-242](file://libraries/chain/dlt_block_log.cpp#L162-L242) - -**Section sources** -- [block_log.hpp:13-36](file://libraries/chain/include/graphene/chain/block_log.hpp#L13-L36) -- [block_log.cpp:134-193](file://libraries/chain/block_log.cpp#L134-L193) -- [block_log.cpp:115-132](file://libraries/chain/block_log.cpp#L115-L132) -- [block_log.cpp:253-257](file://libraries/chain/block_log.cpp#L253-L257) -- [dlt_block_log.hpp:13-33](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L13-L33) -- [dlt_block_log.cpp:162-242](file://libraries/chain/dlt_block_log.cpp#L162-L242) - -### Role of Fork Database in Chain History and Reorganizations -- Maintains a bounded window of unlinked blocks to handle reordering up to a configured limit. -- Supports walking branches and selecting the heaviest chain head. -- Flags invalid blocks to prevent further growth on top of them. -- **Enhanced gap handling**: Graceful handling of missing blocks during LIB advancement with detailed logging. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant FD as "fork_database.cpp" -DB->>FD : "push_block(new_block)" -alt "Links to known chain" -FD-->>DB : "new_head" -DB->>DB : "apply_block(new_head)" -else "Unlinkable" -FD-->>DB : "cache in unlinked_index" -DB->>FD : "_push_next(new_item)" -loop "Recursive linking" -FD-->>DB : "insert linked blocks" -end -end -``` - -**Diagram sources** -- [fork_database.cpp:33-90](file://libraries/chain/fork_database.cpp#L33-L90) -- [database.cpp:846-913](file://libraries/chain/database.cpp#L846-L913) - -**Section sources** -- [fork_database.cpp:47-71](file://libraries/chain/fork_database.cpp#L47-L71) -- [fork_database.cpp:79-90](file://libraries/chain/fork_database.cpp#L79-L90) -- [database.cpp:846-913](file://libraries/chain/database.cpp#L846-L913) - -### Enhanced Block Production Coordination for validator Nodes -**Updated** validator nodes coordinate block production through a dedicated plugin with enhanced defensive programming: -- Acceptance criteria include synchronization status, turn-based scheduling, time windows, participation thresholds, and availability of signing keys. -- The plugin integrates with the chain plugin and P2P plugin to manage production loops. -- **Enhanced defensive programming**: Added error handling to gracefully skip validator accounts that aren't found in the validator index during block post-validation, preventing runtime errors and improving system reliability. -- **Enhanced gap detection**: DLT block log gaps are logged with detailed information about LIB advancement progress. - -```mermaid -flowchart TD -Init(["Initialize Validator Plugin"]) --> Options["Parse options"] -Options --> Startup["Startup"] -Startup --> Schedule["Compute slot times"] -Schedule --> PostValidation["Block Post-Validation Loop"] -PostValidation --> CheckWitness["Check validator account exists"] -CheckWitness --> |Exists| ValidateBlock["Validate block and sign"] -CheckWitness --> |Not Found| Skip["Skip with warning log"] -ValidateBlock --> Broadcast["Broadcast to peers"] -Skip --> Continue["Continue with next validator"] -Continue --> Produce{"Is validator turn?"} -Produce --> |Yes| Build["generate_block()"] -Produce --> |No| Wait["Wait for next slot"] -Build --> Sign["Sign block header"] -Sign --> Broadcast --> Apply["apply_block()"] -Apply --> Persist["append to block_log"] -``` - -**Diagram sources** -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) -- [database.hpp:214-226](file://libraries/chain/include/graphene/chain/database.hpp#L214-L226) -- [database.cpp:3443-3509](file://libraries/chain/database.cpp#L3443-L3509) - -**Section sources** -- [validator.hpp:20-32](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) -- [database.hpp:214-226](file://libraries/chain/include/graphene/chain/database.hpp#L214-L226) - -### Enhanced Transaction Extraction and State Application -- Transactions are extracted from the block and validated individually. -- Each transaction's operations are evaluated against the current state, with hooks for pre/post operation notifications and virtual operations. -- Hardforks and special processing steps are executed during block application. -- **Enhanced fallback chain**: Block retrieval follows block_log → dlt_block_log → fork_database hierarchy for maximum reliability. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant Tx as "Transaction" -DB->>Tx : "validate_transaction()" -Tx-->>DB : "OK" -DB->>DB : "apply_transaction()" -DB->>DB : "apply_operation() per op" -DB-->>DB : "notify_applied_block() / signals" -``` - -**Diagram sources** -- [database.hpp:423-428](file://libraries/chain/include/graphene/chain/database.hpp#L423-L428) -- [database.cpp:3443-3509](file://libraries/chain/database.cpp#L3443-L3509) - -**Section sources** -- [database.hpp:423-428](file://libraries/chain/include/graphene/chain/database.hpp#L423-L428) -- [database.cpp:3443-3509](file://libraries/chain/database.cpp#L3443-L3509) - -## Dependency Analysis -The following diagram shows key dependencies among components involved in block processing with enhanced fallback mechanisms: - -```mermaid -graph LR -PBlock["protocol::block.hpp"] --> DBH["database.hpp"] -PHeader["protocol::block_header.hpp"] --> DBH -DBH --> DBC["database.cpp"] -DBC --> FDH["fork_database.hpp"] -DBC --> BLH["block_log.hpp"] -DBC --> DLTH["dlt_block_log.hpp"] -FDH --> FDC["fork_database.cpp"] -BLH --> BLC["block_log.cpp"] -DLTH --> D LTCPP["dlt_block_log.cpp"] -WIT["validator.hpp"] --> DBH -WITCPP["validator.cpp"] --> DBH -``` - -**Diagram sources** -- [block.hpp:1-19](file://libraries/protocol/include/graphene/protocol/block.hpp#L1-L19) -- [block_header.hpp:1-43](file://libraries/protocol/include/graphene/protocol/block_header.hpp#L1-L43) -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp:1-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [validator.hpp:1-70](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L1-L70) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) - -**Section sources** -- [database.hpp:1-561](file://libraries/chain/include/graphene/chain/database.hpp#L1-L561) -- [fork_database.hpp:1-125](file://libraries/chain/include/graphene/chain/fork_database.hpp#L1-L125) -- [block_log.hpp:1-75](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [dlt_block_log.hpp:1-76](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L1-L76) -- [validator.hpp:1-70](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L1-L70) -- [validator.cpp:295-341](file://plugins/validator/validator.cpp#L295-L341) - -## Performance Considerations -- Skip flags: Validation and checks can be selectively disabled during reindexing or trusted operations to reduce overhead. -- Memory-mapped IO: Both block logs use memory-mapped files for efficient random access and reduced syscall overhead. -- Bounded fork cache: Limits memory usage by capping the number of unlinked blocks and pruning older entries. -- Flush intervals: Controlled flushing reduces disk sync frequency while preserving durability guarantees. -- Parallelism: Network and plugin layers can operate concurrently with chain operations under appropriate locking. -- **Enhanced fallback mechanisms**: Comprehensive fallback chain (block_log → dlt_block_log → fork_database) improves reliability without significant performance impact. -- **Gap detection optimization**: DLT block log gap detection prevents unnecessary retries and reduces logging overhead during normal operations. -- **Enhanced defensive programming**: The Validator Plugin now includes additional error checking and graceful degradation to prevent runtime errors during block post-validation, improving overall system stability. - -## Troubleshooting Guide -Common issues and diagnostics: -- Unlinkable blocks: Detected when a block's previous ID is not present in the fork database; the block is cached and linked when the parent arrives. -- Hardfork application errors: Exceptions indicate attempting to apply unknown hardforks or missing hardfork state. -- Block log inconsistencies: Startup reconciliation reconstructs the index if the log and index are out of sync. -- validator production failures: Conditions such as not being scheduled, insufficient participation, or missing private keys prevent block production. -- **Enhanced error handling**: validator accounts not found in validator index are now handled gracefully with warning logs, preventing runtime errors and allowing the system to continue processing other validators. -- **DLT gap detection**: DLT block log gaps are logged with detailed information about LIB advancement progress, helping diagnose synchronization issues. -- **Fallback chain failures**: When all fallback mechanisms fail, the system returns block_id_type(), indicating the block is not available in any storage system. - -**Section sources** -- [fork_database.cpp:38-44](file://libraries/chain/fork_database.cpp#L38-L44) -- [database_exceptions.hpp:83-83](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L83-L83) -- [block_log.cpp:163-193](file://libraries/chain/block_log.cpp#L163-L193) -- [validator.hpp:20-32](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) -- [validator.cpp:305-307](file://plugins/validator/validator.cpp#L305-L307) -- [database.cpp:5395-5419](file://libraries/chain/database.cpp#L5395-L5419) - -## Conclusion -The VIZ node implements a robust block processing pipeline that separates concerns between protocol definitions, fork management, and durable persistence with comprehensive fallback mechanisms. The fork database ensures resilient handling of out-of-order and conflicting blocks, while the dual block log system (block_log + dlt_block_log) provides efficient random access and reindexing support with graceful fallback to the fork database. - -**Updated** The enhanced fork handling system now includes comprehensive fallback mechanisms for missing irreversible blocks during fork resolution and chain reorganization events, significantly improving chain validation reliability and preventing chain stalls. The block log accessibility system provides a robust fallback chain: block_log → dlt_block_log → fork_database, ensuring blocks remain accessible even when intermediate storage systems are unavailable. - -The database orchestrates validation, state application, and integration with plugins such as the validator node coordinator. The enhanced defensive programming in the Validator Plugin prevents runtime errors when validator accounts aren't found during block post-validation, significantly improving system reliability and error handling. - -Performance is optimized through selective validation, memory-mapped IO, bounded caches, and controlled flushing, enabling high-throughput operation in production environments. The addition of comprehensive fallback mechanisms and gap detection further enhances the system's resilience and operational stability, making it highly reliable for production blockchain operations. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Data Flow and Processing.md b/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Data Flow and Processing.md deleted file mode 100644 index a8cfcaa554..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Data Flow and Processing.md +++ /dev/null @@ -1,367 +0,0 @@ -# Data Flow and Processing - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp) -- [operation_notification.hpp](file://libraries/chain/include/graphene/chain/operation_notification.hpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [block_log.cpp](file://libraries/chain/block_log.cpp) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the end-to-end data flow and processing patterns in the VIZ node. It covers how incoming JSON-RPC requests are routed to APIs, how transactions are validated and applied, how blocks are validated and integrated, and how state changes are persisted. It also documents the observer pattern used for event-driven architecture, the fork resolution mechanism, and performance-related strategies such as caching and memory management. - -## Project Structure -At a high level, the VIZ node is organized around: -- Protocol primitives (transactions, blocks, operations) -- Chain database and state management -- Fork database for out-of-order block handling -- Block log for durable storage -- Plugins for API exposure (JSON-RPC) -- Network layer for peer-to-peer synchronization - -```mermaid -graph TB -subgraph "Network Layer" -NET["network::node"] -end -subgraph "Plugins" -RPC["json_rpc::plugin"] -end -subgraph "Chain Core" -DB["chain::database"] -FD["chain::fork_database"] -BL["chain::block_log"] -end -subgraph "Protocol" -TRX["protocol::signed_transaction"] -BLOCK["protocol::signed_block"] -end -NET --> DB -RPC --> DB -DB --> FD -DB --> BL -DB --> TRX -DB --> BLOCK -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L180-L304) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L180-L304) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -## Core Components -- chain::database: central state machine managing blockchain lifecycle, validation, and persistence. Provides push_block, push_transaction, and related hooks. -- chain::fork_database: maintains a tree of candidate blocks for fork resolution and out-of-order pushes. -- chain::block_log: durable append-only storage of blocks with random access via index. -- protocol::signed_transaction and protocol::signed_block: typed structures for transactions and blocks. -- json_rpc::plugin: exposes APIs over JSON-RPC and dispatches calls to registered methods. -- network::node: handles peer synchronization and relaying of blocks/transactions. - -Key responsibilities: -- Validation flags and skip modes for performance tuning -- Merkle roots, TAPOS, and block size limits -- Undo sessions, revision management, and memory scaling -- Signals for observers (pre/post operation, applied block, pending transactions) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L194-L227) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) - -## Architecture Overview -The VIZ node follows a layered architecture: -- Application layer: JSON-RPC plugin receives requests and routes them to APIs. -- Chain layer: database orchestrates validation, evaluation, and persistence. -- Storage layer: fork_database caches reversible blocks; block_log persists irreversible blocks. -- Network layer: node manages synchronization and propagation. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant RPC as "json_rpc : : plugin" -participant DB as "chain : : database" -participant FD as "chain : : fork_database" -participant BL as "chain : : block_log" -Client->>RPC : "JSON-RPC request" -RPC->>DB : "Dispatch API call" -alt "Block push" -DB->>FD : "push_block()" -FD-->>DB : "head updated?" -DB->>BL : "append() when irreversible" -else "Transaction push" -DB->>DB : "validate_transaction()" -DB->>DB : "apply_transaction()" -end -DB-->>RPC : "Response" -RPC-->>Client : "JSON-RPC response" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L402-L423) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L194-L227) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L45) -- [block_log.cpp](file://libraries/chain/block_log.cpp#L253-L257) - -## Detailed Component Analysis - -### JSON-RPC Request Pipeline -- The JSON-RPC plugin parses incoming messages, validates method names, and dispatches to registered API methods. -- It supports batch requests and returns responses in order. -- Errors are normalized into JSON-RPC error codes. - -```mermaid -sequenceDiagram -participant C as "Client" -participant P as "json_rpc : : plugin" -participant D as "chain : : database" -C->>P : "Call {api, method, args}" -P->>P : "process_params()" -P->>D : "Invoke API method" -D-->>P : "Result or exception" -P-->>C : "JSON-RPC response" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L256) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L402-L423) - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L256) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L402-L423) - -### Transaction Processing Pipeline -- Incoming signed transactions are validated against chain parameters (TAPOS, expiration, signatures) and then applied to state. -- Validation can be partially skipped for performance (e.g., during reindex) via skip flags. -- Transactions are evaluated via registered evaluators; each operation triggers pre/post operation notifications. - -```mermaid -flowchart TD -Start(["Receive signed_transaction"]) --> Validate["validate_transaction(skip)"] -Validate --> Valid{"Valid?"} -Valid --> |No| Reject["Reject with error"] -Valid --> |Yes| Apply["apply_transaction(skip)"] -Apply --> Eval["Apply operations via evaluators"] -Eval --> NotifyPre["notify_pre_apply_operation"] -NotifyPre --> Ops["Each operation applied"] -Ops --> NotifyPost["notify_post_apply_operation"] -NotifyPost --> Done(["Transaction applied"]) -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L423-L424) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L468-L476) -- [operation_notification.hpp](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L11-L23) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L423-L424) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L468-L476) -- [operation_notification.hpp](file://libraries/chain/include/graphene/chain/operation_notification.hpp#L11-L23) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) - -### Block Processing Flow -- validate_block performs Merkle root and block size checks. -- push_block integrates a block into the chain, updating dynamic properties, validator participation, and last irreversible block. -- apply_block coordinates per-block state transitions and emits applied_block signals. - -```mermaid -sequenceDiagram -participant N as "network : : node" -participant D as "chain : : database" -participant F as "chain : : fork_database" -participant L as "chain : : block_log" -N->>D : "handle_block(signed_block)" -D->>D : "validate_block()" -D->>F : "push_block()" -F-->>D : "new head or cached" -D->>D : "apply_block()" -D->>L : "append() when irreversible" -D-->>N : "Fork switch?" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L79-L80) -- [database.cpp](file://libraries/chain/database.cpp#L738-L756) -- [database.cpp](file://libraries/chain/database.cpp#L794-L800) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L45) -- [block_log.cpp](file://libraries/chain/block_log.cpp#L253-L257) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L738-L756) -- [database.cpp](file://libraries/chain/database.cpp#L794-L800) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L45) -- [block_log.cpp](file://libraries/chain/block_log.cpp#L253-L257) - -### Observer Pattern and Signals -- The database exposes fc::signal callbacks for: - - pre_apply_operation and post_apply_operation - - applied_block - - on_pending_transaction and on_applied_transaction -- Plugins subscribe to these signals to react to state changes without tight coupling. - -```mermaid -classDiagram -class database { -+pre_apply_operation -+post_apply_operation -+applied_block -+on_pending_transaction -+on_applied_transaction -} -class plugin_json_rpc { -+subscribe_signals() -} -database --> plugin_json_rpc : "emits signals" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) - -### Data Persistence and Fork Resolution -- fork_database stores candidate blocks and resolves forks by walking branches to a common ancestor. -- block_log provides durable storage with an index enabling O(1) random access by block number. -- Memory management includes reserved/shared memory sizing and periodic resizing during reindex. - -```mermaid -flowchart TD -A["New block received"] --> B["fork_database.push_block()"] -B --> C{"Links to known chain?"} -C --> |No| D["Cache in unlinked_index"] -C --> |Yes| E["Insert into main index"] -E --> F{"Exceeds max size?"} -F --> |Yes| G["Trim older blocks"] -F --> |No| H["Update head"] -D --> I["Try linking later"] -I --> E -``` - -**Diagram sources** -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L90) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L92-L124) - -**Section sources** -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L33-L90) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L92-L124) -- [block_log.cpp](file://libraries/chain/block_log.cpp#L134-L193) -- [database.cpp](file://libraries/chain/database.cpp#L368-L430) - -## Dependency Analysis -- chain::database depends on: - - chain::fork_database for reversible blocks - - chain::block_log for persistent storage - - protocol::signed_transaction and signed_block for data structures - - evaluator registry for operation application -- json_rpc::plugin depends on appbase and fc variants for request/response handling. -- network::node delegates block and transaction handling to the chain database. - -```mermaid -graph LR -RPC["json_rpc::plugin"] --> DB["chain::database"] -NET["network::node"] --> DB -DB --> FD["chain::fork_database"] -DB --> BL["chain::block_log"] -DB --> EV["evaluator registry"] -DB --> TRX["protocol::signed_transaction"] -DB --> BLOCK["protocol::signed_block"] -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L180-L304) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L122) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L38-L71) -- [transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [block.hpp](file://libraries/protocol/include/graphene/protocol/block.hpp#L9-L18) - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L180-L304) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) - -## Performance Considerations -- Skip flags: The database supports extensive skip masks to bypass expensive validations during reindex or trusted operations. -- Memory scaling: Shared memory is resized dynamically when free memory drops below thresholds; reserved memory protects critical operations. -- Caching: TAPOS buffers and block summary indices accelerate block ID lookups; fork_database caches recent blocks up to a configurable maximum. -- Batch processing: JSON-RPC plugin supports batch requests and streams responses efficiently. - -Recommendations: -- Tune skip flags for trusted environments (e.g., skip signatures for non-validator nodes). -- Monitor free memory and adjust shared file sizing to avoid frequent resizes. -- Use checkpoints to reduce validation overhead on startup. -- Leverage evaluators’ early exits and minimal authority checks where safe. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [database.cpp](file://libraries/chain/database.cpp#L368-L430) -- [database.cpp](file://libraries/chain/database.cpp#L270-L350) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L313-L336) - -## Troubleshooting Guide -Common issues and diagnostics: -- Block validation failures: Check Merkle root mismatch and block size violations; consult fork database state and block log head consistency. -- Transaction rejection: Inspect TAPOS, expiration, and authority verification errors; review skip flags used during validation. -- Memory exhaustion: Watch logs indicating low free memory and automatic shared memory resizing; increase reserved size or shared file size. -- Fork instability: Verify fork database head and branch resolution; ensure block ordering and previous ID consistency. - -Operational tips: -- Use reindex mode with appropriate skip flags to recover from inconsistent state. -- Subscribe to on_applied_transaction and applied_block signals for observability. -- Validate chain state against block log head to detect divergence. - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L738-L792) -- [database.cpp](file://libraries/chain/database.cpp#L270-L350) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp#L47-L71) -- [block_log.cpp](file://libraries/chain/block_log.cpp#L134-L193) - -## Conclusion -The VIZ node implements a robust, event-driven data flow from JSON-RPC to state application and persistence. Its layered design separates concerns between networking, API exposure, state management, and storage, while providing powerful mechanisms for validation, fork resolution, and performance tuning. Observers can react to state changes via signals, and plugins integrate seamlessly with the core database through well-defined interfaces. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Event-Driven Communication Patterns.md b/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Event-Driven Communication Patterns.md deleted file mode 100644 index daf2e4c6c7..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Event-Driven Communication Patterns.md +++ /dev/null @@ -1,369 +0,0 @@ -# Event-Driven Communication Patterns - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp) -- [main.cpp](file://programs/cli_wallet/main.cpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the event-driven architecture and observer pattern implementation in the VIZ node. It focuses on how signals and slots enable decoupled communication between plugins and core components, how state changes propagate through event notifications, and how Boost.Signals2 and fc::signal are used to manage subscriptions and callbacks. It also covers plugin communication mechanisms, inter-component messaging patterns, and practical examples such as account updates, transaction confirmations, and block notifications. Finally, it addresses performance implications and optimization strategies for high-frequency events. - -## Project Structure -The event-driven design spans three primary layers: -- Core chain engine: emits domain-specific events (operations, blocks, transactions). -- Plugin layer: subscribes to events and implements specialized behaviors. -- Application integrations: CLI, web server, and RPC plugins consume events for user-facing features. - -```mermaid -graph TB -subgraph "Chain Core" -DB["database.hpp/.cpp
emits fc::signal events"] -end -subgraph "Plugins" -CHAIN_P["plugins/chain/plugin.hpp
Boost.Signals2 on_sync"] -BLOCK_INFO["plugins/block_info/plugin.cpp
applied_block.connect(...)"] -DB_API["plugins/database_api/api.cpp
block_applied_callback_info"] -DEBUG_NODE["plugins/debug_node/plugin.cpp
applied_block.connect(...)"] -NET_BROADCAST["plugins/network_broadcast_api/...
uses Boost.Signals2 connections"] -end -subgraph "Applications" -CLI["programs/cli_wallet/main.cpp
Boost.Signals2 scoped_connection"] -WEB["plugins/webserver/webserver_plugin.cpp
chain_sync_con"] -end -DB --> CHAIN_P -DB --> BLOCK_INFO -DB --> DB_API -DB --> DEBUG_NODE -DB --> NET_BROADCAST -CHAIN_P --> CLI -CHAIN_P --> WEB -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L78-L78) -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L78-L78) -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -## Core Components -- Chain database events: - - Operation lifecycle: pre_apply_operation and post_apply_operation. - - Block lifecycle: applied_block. - - Transaction lifecycle: on_pending_transaction and on_applied_transaction. -- Plugin-level synchronization: chain plugin emits on_sync via Boost.Signals2. -- Observer pattern in plugins: - - Plugins connect to database signals to receive notifications. - - Callbacks are wrapped in scoped_connection/connection to manage lifetime safely. - -Key event emitters and receivers: -- Emitters (database): - - notify_pre_apply_operation, notify_post_apply_operation, notify_applied_block, notify_on_pending_transaction, notify_on_applied_transaction. -- Receivers (plugins): - - block_info plugin connects to applied_block. - - database_api plugin manages block_applied_callback_info with connection-based callbacks. - - debug_node plugin connects to applied_block. - - chain plugin exposes on_sync for external synchronization. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L275) -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) - -## Architecture Overview -The event architecture follows a publish-subscribe model: -- Publishers: chain database emits fc::signal events during block/application processing. -- Subscribers: plugins register callbacks to receive notifications. -- Synchronization: chain plugin emits on_sync for coordination with external systems. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant OP as "pre/post_apply_operation" -participant BLK as "applied_block" -participant TX as "pending/applied_transaction" -participant BI as "block_info plugin" -participant DA as "database_api plugin" -participant DN as "debug_node plugin" -DB->>OP : emit pre_apply_operation(note) -OP-->>BI : notify subscribers -OP-->>DA : notify subscribers -OP-->>DN : notify subscribers -DB->>BLK : emit applied_block(block) -BLK-->>BI : on_applied_block(block) -BLK-->>DA : on_applied_block(block) -DB->>TX : emit on_pending_transaction(tx) -TX-->>DA : pending callback -DB->>TX : emit on_applied_transaction(tx) -TX-->>DA : applied callback -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) - -## Detailed Component Analysis - -### Chain Database Event Emission -The database defines and emits multiple fc::signal events: -- pre_apply_operation and post_apply_operation for operation lifecycle. -- applied_block for block lifecycle. -- on_pending_transaction and on_applied_transaction for transaction lifecycle. - -Implementation highlights: -- notify_* methods wrap CHAIN_TRY_NOTIFY to dispatch events to subscribers. -- Virtual operations and current context (block/trx/op indices) are attached to notifications. - -```mermaid -flowchart TD -Start(["Operation Applied"]) --> PreNotify["notify_pre_apply_operation(note)"] -PreNotify --> EmitPre["Emit pre_apply_operation"] -EmitPre --> PostNotify["notify_post_apply_operation(note)"] -PostNotify --> EmitPost["Emit post_apply_operation"] -Start2(["Block Applied"]) --> BlockNotify["notify_applied_block(block)"] -BlockNotify --> EmitBlock["Emit applied_block"] -Start3(["Transaction Added/Pending"]) --> PendingNotify["notify_on_pending_transaction(tx)"] -PendingNotify --> EmitPending["Emit on_pending_transaction"] -Start4(["Transaction Applied"]) --> AppliedNotify["notify_on_applied_transaction(tx)"] -AppliedNotify --> EmitApplied["Emit on_applied_transaction"] -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L275) -- [database.cpp](file://libraries/chain/database.cpp#L1157-L1198) - -### Chain Plugin Synchronization Signal -The chain plugin exposes on_sync via Boost.Signals2 to signal when the blockchain is syncing or live. This enables dependent components to coordinate their startup and state transitions. - -```mermaid -sequenceDiagram -participant CH as "chain plugin.hpp" -participant APP as "external consumers" -CH->>APP : emit on_sync() -APP-->>APP : synchronize local state -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) - -### Block Information Plugin Subscription -The block_info plugin subscribes to applied_block to maintain per-block metadata. It uses a scoped_connection to ensure automatic disconnection. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant BI as "block_info plugin.cpp" -DB->>BI : applied_block(block) -BI->>BI : on_applied_block(block)
update block_info_ -``` - -**Diagram sources** -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) - -**Section sources** -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) - -### Database API Plugin Callback Management -The database_api plugin maintains a container of block_applied_callback_info entries. Each entry holds a callback and a connection. Connections are disconnected upon callback exceptions to prevent leaks. - -```mermaid -classDiagram -class block_applied_callback_info { -+callback -+connection -+it -+connect(sig, free_cont, cb) -} -class api_impl { -+active_block_applied_callback -+free_block_applied_callback -} -api_impl --> block_applied_callback_info : "manages" -``` - -**Diagram sources** -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) - -**Section sources** -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) - -### Debug Node Plugin Subscription -The debug_node plugin subscribes to applied_block to conditionally re-apply debug updates on block application. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant DN as "debug_node plugin.cpp" -DB->>DN : applied_block(block) -DN->>DN : on_applied_block()
apply_debug_updates() -``` - -**Diagram sources** -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) - -**Section sources** -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) - -### Network Broadcast API Plugin Signal Connection -The network broadcast API plugin uses Boost.Signals2 connections to integrate with chain events. The header declares a scoped_connection member for lifecycle management. - -```mermaid -classDiagram -class network_broadcast_api_plugin { -+on_applied_block_connection : scoped_connection -} -``` - -**Diagram sources** -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L78-L78) - -**Section sources** -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L78-L78) - -### CLI Wallet Signal Usage -The CLI wallet registers scoped_connection instances for various signals (e.g., websocket closed, quit command, lock state changes) to react to runtime events. - -```mermaid -sequenceDiagram -participant CLI as "cli_wallet main.cpp" -participant WS as "websocket" -CLI->>WS : closed.connect(...) -CLI->>CLI : quit_command.connect(...) -CLI->>CLI : lock_changed.connect(...) -``` - -**Diagram sources** -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) - -**Section sources** -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) - -### Webserver Plugin Chain Sync Connection -The webserver plugin creates a scoped_connection to monitor chain synchronization events. - -```mermaid -classDiagram -class webserver_plugin { -+chain_sync_con : connection -} -``` - -**Diagram sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -**Section sources** -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -## Dependency Analysis -The event-driven architecture exhibits loose coupling: -- Database publishes events without knowing subscribers. -- Plugins subscribe independently, enabling modular extensions. -- External applications (CLI, webserver) subscribe to chain plugin’s on_sync. - -```mermaid -graph LR -DB["database.hpp/.cpp"] --> |fc::signal| SUB1["block_info"] -DB --> |fc::signal| SUB2["database_api"] -DB --> |fc::signal| SUB3["debug_node"] -CH["chain plugin.hpp"] --> |Boost.Signals2| EXT1["cli_wallet"] -CH --> |Boost.Signals2| EXT2["webserver"] -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L89-L90) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp#L140-L142) -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L27-L51) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L131-L133) -- [main.cpp](file://programs/cli_wallet/main.cpp#L180-L196) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L108-L108) - -## Performance Considerations -High-frequency event loops (transactions, operations, blocks) require careful optimization: -- Minimize work inside event handlers: - - Defer heavy computations to background threads or queues. - - Use lightweight callbacks that primarily enqueue work. -- Batch updates: - - Group frequent notifications (e.g., multiple transactions) into batches. -- Connection lifecycle: - - Use scoped_connection/connection to avoid dangling callbacks and reduce cleanup overhead. -- Throttle UI/API updates: - - Rate-limit or debounce notifications to clients to prevent overload. -- Lock contention: - - Keep event handlers short; avoid holding database write locks for extended periods. -- Memory pressure: - - Monitor callback containers and clean up inactive subscriptions promptly. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and remedies: -- Handlers crash or throw: - - database_api wraps callbacks in try/catch and disconnects failing connections to keep the system stable. -- Stale or missing subscriptions: - - Ensure scoped_connection/connection remains alive for the handler’s lifetime; verify plugin initialization order. -- Deadlocks or long-running handlers: - - Move blocking work off the event thread; use async dispatch patterns. -- Excessive event volume: - - Apply rate limiting or filtering; consider bloom filters for subscription items. - -**Section sources** -- [database_api_plugin.cpp](file://plugins/database_api/api.cpp#L42-L49) - -## Conclusion -The VIZ node employs a robust event-driven architecture centered on fc::signal emissions from the chain database and Boost.Signals2-based synchronization in plugins. This design enables decoupled communication, modular plugin development, and scalable inter-component messaging. By adhering to best practices—such as short handlers, safe connection lifecycles, batching, and throttling—developers can maintain responsiveness under high-frequency event loads while preserving system stability. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Transaction Processing Pipeline.md b/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Transaction Processing Pipeline.md deleted file mode 100644 index 0feac2c849..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Data Flow and Processing/Transaction Processing Pipeline.md +++ /dev/null @@ -1,370 +0,0 @@ -# Transaction Processing Pipeline - - -**Referenced Files in This Document** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp) -- [transaction.cpp](file://libraries/protocol/transaction.cpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the transaction processing pipeline in the VIZ node from reception to final application. It covers validation stages (syntax, signatures, authority), operation processing via evaluators, and state application. It also documents the evaluator registry mechanism, transaction object lifecycle, error handling, rollback, and performance optimizations such as batch-like pending transaction handling and caching via the database’s internal caches. - -## Project Structure -The transaction pipeline spans protocol-level transaction definitions, chain-level validation and application, and evaluator dispatch. Key areas: -- Protocol: transaction definition, validation, signature verification, authority computation -- Chain: database orchestration, validation flags, pending transactions, block application -- Evaluators: operation-specific logic and state mutations -- Registry: mapping operations to evaluators - -```mermaid -graph TB -subgraph "Protocol Layer" -P1["transaction.hpp
transaction.cpp"] -P2["operations.hpp"] -end -subgraph "Chain Layer" -C1["database.hpp"] -C2["transaction_object.hpp"] -C3["evaluator.hpp"] -C4["evaluator_registry.hpp"] -C5["chain_evaluator.cpp"] -end -P1 --> C1 -P2 --> C1 -C1 --> C3 -C3 --> C4 -C4 --> C5 -C1 --> C2 -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) - -## Core Components -- Transaction model and validation: syntax and operation validation, signature digest and verification, authority computation and verification -- Evaluator framework: base evaluator interface, typed evaluator implementation, and registry for dispatch -- Database orchestration: transaction validation entry points, pending transaction handling, block application, and state mutation hooks -- Transaction object: duplicate detection and expiration indexing - -Key responsibilities: -- Protocol layer validates transaction structure and operation semantics and verifies signatures and authorities -- Chain layer coordinates validation and application, manages pending state, and applies operations atomically -- Evaluators implement operation-specific logic and state transitions -- Registry ensures correct evaluator selection per operation type - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L240-L357) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -## Architecture Overview -End-to-end flow: -- Reception: client or plugin submits a signed transaction -- Validation: protocol-level checks (syntax, operations), signature verification, authority verification -- Application: database applies operations via evaluators, emitting notifications and virtual operations -- Persistence: successful transactions become eligible for inclusion in blocks - -```mermaid -sequenceDiagram -participant Client as "Client" -participant DB as "database.hpp" -participant Proto as "transaction.cpp" -participant Reg as "evaluator_registry.hpp" -participant Eval as "chain_evaluator.cpp" -Client->>DB : push_transaction(trx) -DB->>Proto : validate_transaction(trx) -Proto-->>DB : validation result -DB->>DB : _validate_transaction(trx, flags) -DB->>Reg : get_evaluator(op) -Reg-->>DB : evaluator instance -DB->>Eval : evaluator.apply(op) -Eval-->>DB : state changes -DB-->>Client : result -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L468-L476) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) - -## Detailed Component Analysis - -### Transaction Validation Stages -- Syntax and operation validation: transaction must contain at least one operation; each operation is validated -- Signature verification: computes signature digest and verifies signatures; enforces uniqueness -- Authority verification: computes required authorities and validates provided signatures/authorities against thresholds and recursion limits - -```mermaid -flowchart TD -Start(["Receive signed_transaction"]) --> Syntax["Validate transaction structure
and operations"] -Syntax --> SigDigest["Compute sig_digest(chain_id)"] -SigDigest --> VerifySigs["Verify signatures and detect duplicates"] -VerifySigs --> ComputeAuth["Compute required authorities"] -ComputeAuth --> VerifyAuth["Verify authorities vs provided keys/approvals"] -VerifyAuth --> Done(["Validation OK"]) -VerifyAuth --> |Fail| Error["Throw validation exception"] -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L45-L56) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L225-L237) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L240-L316) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L45-L56) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L225-L237) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L240-L316) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) - -### Evaluator Registry Mechanism -- Registry stores a vector of evaluators indexed by operation type tag -- Registration binds operation type to evaluator implementation -- Dispatch selects evaluator by operation’s static_variant index - -```mermaid -classDiagram -class evaluator_registry { -+register_evaluator(EvaluatorType, args...) -+get_evaluator(op) evaluator --_op_evaluators : vector> -} -class evaluator { -<> -+apply(op) -+get_type() int -} -class evaluator_impl { -+apply(op) -+get_type() int --db() database& -} -evaluator_registry --> evaluator : "holds" -evaluator_impl ..|> evaluator -``` - -**Diagram sources** -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) - -**Section sources** -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) - -### Operation Processing and State Application -- Database coordinates validation and application -- Pending transactions are stored and later applied in block context -- Virtual operations may be emitted during evaluation -- Notifications are emitted pre/post operation and post block - -```mermaid -sequenceDiagram -participant DB as "database.hpp" -participant Reg as "evaluator_registry.hpp" -participant Eval as "chain_evaluator.cpp" -participant Notif as "Notifications" -DB->>DB : apply_transaction(trx) -loop for each operation -DB->>Reg : get_evaluator(op) -Reg-->>DB : evaluator -DB->>Eval : evaluator.do_apply(op) -Eval-->>DB : state changes -DB->>Notif : notify_pre/post_apply_operation -end -DB->>Notif : notify_applied_block -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L468-L478) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L263) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L468-L478) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L238-L263) - -### Transaction Object Lifecycle -- Creation: upon receipt, transactions may be recorded to prevent duplicates -- Expiration: transactions are tracked by expiration time -- Cleanup: expired entries are removed at block processing boundaries - -```mermaid -flowchart TD -A["Receive trx"] --> B["Store in transaction_index
with expiration"] -B --> C{"Expired?"} -C --> |No| D["Pending until block inclusion"] -C --> |Yes| E["Remove from index"] -D --> F["Applied in block -> remove"] -``` - -**Diagram sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -**Section sources** -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -### Error Handling and Rollback -- Validation throws exceptions on failures (syntax, signatures, authority) -- Authority verification uses assertions to enforce thresholds and detect unused approvals/signatures -- Database maintains sessions and undo history; on reindex or errors, state can be rolled back -- Pending transactions cache allows reapplication after popping blocks - -```mermaid -flowchart TD -Start(["Validation"]) --> Check["Syntax/Operations OK?"] -Check --> |No| Throw["Throw exception"] -Check --> |Yes| Sig["Signatures verified?"] -Sig --> |No| Throw -Sig --> Auth["Authority satisfied?"] -Auth --> |No| Throw -Auth --> Apply["Apply operations"] -Apply --> Err{"Exception during apply?"} -Err --> |Yes| Undo["Rollback via undo history"] -Err --> |No| Commit["Commit changes"] -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L466-L472) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L466-L472) - -### Example: Transfer Operation Evaluation -- Demonstrates typical evaluator pattern: fetch accounts, validate balances, adjust assets, emit virtual operations if applicable - -```mermaid -sequenceDiagram -participant DB as "database.hpp" -participant Eval as "transfer_evaluator : : do_apply" -DB->>Eval : apply(transfer_operation) -Eval->>DB : get_account(from) -Eval->>DB : get_account(to) -Eval->>DB : adjust_balance(from, -amount) -Eval->>DB : adjust_balance(to, +amount) -Eval-->>DB : done -``` - -**Diagram sources** -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L857-L950) - -**Section sources** -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L857-L950) - -## Dependency Analysis -- Protocol depends on operations static variant to enumerate supported operations -- Database orchestrates validation and application and holds evaluator registry -- Evaluators depend on database for state queries and mutations -- Transaction object depends on protocol transaction types - -```mermaid -graph LR -OP["operations.hpp"] --> EV["evaluator.hpp"] -EV --> ER["evaluator_registry.hpp"] -ER --> CE["chain_evaluator.cpp"] -TR["transaction.cpp"] --> DB["database.hpp"] -DB --> CE -DB --> TO["transaction_object.hpp"] -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -## Performance Considerations -- Batch-like processing: pending transactions are accumulated and applied together during block processing, reducing repeated validations -- Caching: database caches frequently accessed state (accounts, validators, etc.) to avoid repeated lookups -- Validation flags: skip flags allow bypassing expensive checks during reindex or trusted contexts -- Indexing: transaction index supports duplicate detection and expiration cleanup - -Recommendations: -- Prefer local transaction submission with minimal signatures to reduce verification overhead -- Use appropriate skip flags only when safe (e.g., during reindex) -- Monitor shared memory growth and tune flush intervals for block production nodes - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L423-L423) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) - -## Troubleshooting Guide -Common issues and diagnostics: -- Transaction rejected due to missing or extra signatures: verify_authority enforces unused signature detection and throws explicit errors -- Insufficient authority: verify_authority enforces required active/master/regular thresholds and missing approvals -- Operation validation failure: transaction.validate triggers per-operation validation; inspect operation content and semantics -- Duplicate transaction: transaction_object prevents duplicate inclusion; check expiration and packing logic -- Pending transaction not applied: ensure node is not skipping transaction application or is not stalled on undo history - -Actions: -- Enable verbose logs around validation and application -- Temporarily disable skip flags for diagnosis -- Confirm authority getters return expected keys and weights -- Verify chain ID and reference block fields are correct - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L76-L92) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L105-L222) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction_object.hpp](file://libraries/chain/include/graphene/chain/transaction_object.hpp#L19-L49) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L200-L206) - -## Conclusion -The VIZ node implements a robust transaction pipeline with layered validation, a flexible evaluator registry, and careful state application. Protocol-level checks ensure syntactic correctness and cryptographic integrity, while authority verification enforces governance rules. The database coordinates validation and application, supports notifications and virtual operations, and leverages caching and indexing for performance. Proper use of skip flags, careful authority configuration, and monitoring of pending state help maintain reliability and throughput. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Design Patterns and Architectural Decisions.md b/.qoder/repowiki/en/content/Architecture Overview/Design Patterns and Architectural Decisions.md deleted file mode 100644 index c821194a29..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Design Patterns and Architectural Decisions.md +++ /dev/null @@ -1,387 +0,0 @@ -# Design Patterns and Architectural Decisions - - -**Referenced Files in This Document** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp) -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [main.cpp](file://programs/vizd/main.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Security and Monitoring](#security-and-monitoring) -9. [Scalability and Extensibility](#scalability-and-extensibility) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Conclusion](#conclusion) - -## Introduction -This document explains the design patterns and architectural decisions that define the VIZ C++ node. It focuses on the MVC-like separation between data (database), control (plugins), and view (APIs), event-driven architecture using signals, factory and strategy patterns for evaluators, and a plugin-based architecture. It also analyzes trade-offs, performance characteristics, maintainability, extensibility, security, monitoring, and scalability considerations. - -## Project Structure -The system is organized around three primary layers: -- Data layer: chain database and object model -- Control layer: plugins that orchestrate lifecycle, validation, and dispatch -- View layer: APIs exposed by plugins - -```mermaid -graph TB -subgraph "Programs" -VIZD["vizd main()
initializes app and plugins"] -end -subgraph "Plugins" -ChainPlugin["Chain Plugin
accepts blocks/txns, exposes DB"] -P2P["P2P Plugin"] -WebServer["Webserver Plugin"] -end -subgraph "Chain Library" -DB["Database
fork DB, block log, indexes"] -EvalReg["Evaluator Registry
factory for evaluators"] -Ops["Operations Type
static_variant"] -end -subgraph "Network Library" -NetNode["Network Node
peer management, sync"] -end -VIZD --> ChainPlugin -VIZD --> P2P -VIZD --> WebServer -ChainPlugin --> DB -ChainPlugin --> EvalReg -EvalReg --> Ops -P2P --> NetNode -NetNode --> ChainPlugin -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) - -## Core Components -- Database: central state machine managing chain state, indexes, fork database, block log, and event emissions for operations and blocks. -- Evaluator system: strategy/factory for applying operations to state. -- Plugins: lifecycle-managed modules that expose APIs, integrate with the database, and coordinate with the network. -- Network node: peer-to-peer synchronization and message propagation. - -Key responsibilities: -- Data (Database): persistence, validation, indexing, and event signaling. -- Control (Plugins): initialization, startup/shutdown, block/txn acceptance, and API exposure. -- View (APIs): presentation of chain state via plugin-provided endpoints. - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) - -## Architecture Overview -The system follows an event-driven, plugin-based architecture: -- The database emits signals for pre/post operation application, applied blocks, and pending/applied transactions. -- Plugins subscribe to these signals to implement cross-cutting concerns (e.g., API indexing, history tracking). -- The evaluator registry acts as a factory mapping operation types to specialized evaluators. -- The main executable initializes the application and registers plugins. - -```mermaid -sequenceDiagram -participant App as "Application" -participant Chain as "Chain Plugin" -participant DB as "Database" -participant Reg as "Evaluator Registry" -participant Eval as "Concrete Evaluator" -App->>Chain : "accept_block()/accept_transaction()" -Chain->>DB : "validate_* / push_*" -DB->>DB : "pre_apply_operation signal" -DB->>Reg : "get_evaluator(op)" -Reg-->>DB : "evaluator instance" -DB->>Eval : "apply(op)" -Eval-->>DB : "state changes" -DB->>DB : "post_apply_operation signal" -DB->>DB : "applied_block/on_applied_transaction signals" -DB-->>Chain : "callbacks processed by plugins" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L96-L121) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L29-L37) - -## Detailed Component Analysis - -### MVC-like Separation: Data, Control, View -- Data (Database): encapsulates chain state, indexes, fork database, block log, and validation logic. It exposes getters, push operations, and signals for observers. -- Control (Plugins): manage lifecycle, accept blocks/transactions, and coordinate with the database and network. -- View (APIs): provided by plugins that expose endpoints backed by the database. - -```mermaid -graph LR -DB["Database"] -PL["Plugins"] -API["API Layer"] -PL --> DB -API --> DB -API --> PL -``` - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L111-L287) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) - -### Event-Driven Architecture with Signals -The database emits signals for: -- Pre/post operation application -- Applied block -- Pending/applied transactions - -Plugins subscribe to these signals to implement features like API indexing, history tracking, and metrics. - -```mermaid -sequenceDiagram -participant DB as "Database" -participant Sub as "Subscriber Plugin" -DB->>DB : "notify_pre_apply_operation(note)" -DB-->>Sub : "pre_apply_operation signal" -DB->>DB : "notify_post_apply_operation(note)" -DB-->>Sub : "post_apply_operation signal" -DB->>DB : "notify_applied_block(block)" -DB-->>Sub : "applied_block signal" -DB->>DB : "notify_on_applied_transaction(tx)" -DB-->>Sub : "on_applied_transaction signal" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L275) - -### Factory Pattern for Object Creation (Evaluator Registry) -The evaluator registry is a factory that: -- Initializes a vector sized by the number of operation types -- Registers evaluators by operation type tag -- Retrieves the appropriate evaluator for an operation - -```mermaid -classDiagram -class EvaluatorRegistry { -+register_evaluator(EvaluatorType, args...) -+get_evaluator(Operation) evaluator --_op_evaluators : vector> -} -class Evaluator { -<> -+apply(op) -+get_type() int -} -class EvaluatorImpl { -+apply(op) -+get_type() int --db() database& -} -EvaluatorRegistry --> Evaluator : "stores" -EvaluatorImpl ..|> Evaluator -``` - -**Diagram sources** -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) - -**Section sources** -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) - -### Strategy Pattern for Evaluation Strategies -Each operation type has a dedicated evaluator implementation. The strategy is selected dynamically by the registry based on the operation’s static variant index. This enables: -- Clear separation of concerns per operation -- Easy addition of new operations and evaluators -- Testability and isolation of evaluation logic - -```mermaid -flowchart TD -Start(["Receive Operation"]) --> GetTag["Get operation tag"] -GetTag --> Lookup["Lookup evaluator in registry"] -Lookup --> Found{"Evaluator found?"} -Found --> |Yes| Apply["Call evaluator.do_apply(op)"] -Found --> |No| Error["Assert/throw 'No registered evaluator'"] -Apply --> End(["State updated"]) -Error --> End -``` - -**Diagram sources** -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L23-L36) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -**Section sources** -- [chain_evaluator.hpp](file://libraries/chain/include/graphene/chain/chain_evaluator.hpp#L14-L79) -- [chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp#L52-L141) - -### Plugin-Based Architecture -The application uses a plugin framework to modularize functionality: -- Plugins declare dependencies and lifecycle hooks -- The main executable registers and starts plugins -- Plugins expose APIs and interact with the database - -```mermaid -sequenceDiagram -participant Main as "vizd main" -participant App as "AppBase Application" -participant Chain as "Chain Plugin" -participant DB as "Database" -Main->>App : "register_plugin()" -Main->>App : "initialize(...)" -App->>Chain : "plugin_initialize(options)" -App->>Chain : "plugin_startup()" -Chain->>DB : "db.open()/db.reindex()" -App-->>Main : "exec() loop" -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L36-L42) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L181) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L181) - -### Network Synchronization and Peer Coordination -The network node provides: -- Peer discovery and connection management -- Block and transaction propagation -- Sync protocols and bandwidth controls - -```mermaid -sequenceDiagram -participant Node as "Network Node" -participant Peer as "Peer" -participant Chain as "Chain Plugin" -Node->>Peer : "connect_to_endpoint()" -Node->>Peer : "broadcast(block/trx)" -Peer-->>Node : "handle_block()/handle_transaction()" -Node->>Chain : "delegate.handle_block()/handle_transaction()" -Chain-->>Node : "validation result" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L79-L88) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L96-L121) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L96-L121) - -## Dependency Analysis -- The database depends on the evaluator registry and operation types to apply state changes. -- Plugins depend on the database and network node to accept blocks/transactions and propagate them. -- The main executable orchestrates plugin registration and lifecycle. - -```mermaid -graph TD -Main["vizd main.cpp"] --> Chain["Chain Plugin"] -Main --> P2P["P2P Plugin"] -Chain --> DB["Database"] -Chain --> Reg["Evaluator Registry"] -Reg --> Ops["Operations"] -P2P --> Net["Network Node"] -Net --> Chain -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) -- [evaluator_registry.hpp](file://libraries/chain/include/graphene/chain/evaluator_registry.hpp#L8-L40) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) - -## Performance Considerations -- C++ choice: provides low-level control, predictable performance, and efficient memory usage, suitable for high-throughput blockchain operations. -- Shared memory database: chainbase-backed database with configurable shared memory sizing and incremental growth to reduce IO overhead. -- Signal-based notifications: minimal coupling between components; however, subscribers must avoid heavy work in callbacks to prevent write-lock contention. -- Single write thread option: optional serialization of write operations via the application’s io_service to simplify concurrency control at the cost of throughput. -- Evaluator strategy: static variant dispatch minimizes branching overhead; registering evaluators once reduces runtime lookup costs. - -Trade-offs: -- Performance vs. safety: skipping validations (e.g., signatures) can improve speed but risks chain integrity. -- Throughput vs. simplicity: single write thread simplifies correctness but may bottleneck writes under load. - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L106-L121) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [database.cpp](file://libraries/chain/database.cpp#L198-L200) - -## Security and Monitoring -- Logging: centralized logging configuration via INI sections for console and file appenders; supports JSON console logging and rotation. -- Signal handling: signal guard sets up handlers for graceful shutdown and interruption. -- Validation: strict validation steps and hardfork-aware checks ensure consensus correctness. -- API exposure: plugins expose endpoints; monitor and rate-limit as needed at the webserver layer. - -Monitoring highlights: -- Logging configuration supports multiple appenders and loggers. -- Signals for applied operations and blocks enable real-time analytics. - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L167-L288) -- [database.cpp](file://libraries/chain/database.cpp#L134-L184) - -## Scalability and Extensibility -- Horizontal scaling: P2P network layer supports multiple peers and sync strategies; block and transaction propagation scales with peer count. -- Vertical scaling: shared memory database sizing and incremental growth support larger datasets; plugin architecture allows selective feature loading. -- Extensibility: new operations and evaluators can be added with minimal changes; plugins can subscribe to signals for cross-cutting features. - -Considerations: -- Shared memory limits: tune shared-file-size and increments to accommodate growth. -- Plugin selection: load only required plugins to reduce memory footprint. -- Network topology: optimize peer selection and bandwidth limits for large networks. - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L183-L200) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L290-L295) - -## Troubleshooting Guide -Common areas to inspect: -- Database initialization and reindexing failures -- Plugin startup/shutdown errors -- Signal handler exceptions during shutdown -- Transaction/Block acceptance errors (time checks, validation flags) - -Actions: -- Review logs configured via INI sections -- Enable/disable specific validation steps for diagnostics -- Use wipe/replay utilities for corrupted states -- Verify plugin dependencies and signal subscriptions - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L134-L146) -- [database.cpp](file://libraries/chain/database.cpp#L134-L184) -- [main.cpp](file://programs/vizd/main.cpp#L167-L288) - -## Conclusion -The VIZ C++ node employs a robust, event-driven, plugin-based architecture with clear separation of concerns. The database-centric design, combined with a factory/strategy evaluator system and strong plugin lifecycle management, yields a highly extensible and maintainable platform. Performance is optimized through C++, shared memory storage, and careful validation controls, while the P2P layer supports scalable horizontal growth. Security and observability are addressed through structured logging and signal handling, enabling reliable operations in production environments. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Custom Plugin Development.md b/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Custom Plugin Development.md deleted file mode 100644 index 14da93b61e..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Custom Plugin Development.md +++ /dev/null @@ -1,448 +0,0 @@ -# Custom Plugin Development - - -**Referenced Files in This Document** -- [newplugin.py](file://programs/util/newplugin.py) -- [plugin.md](file://documentation/plugin.md) -- [CMakeLists.txt](file://plugins/CMakeLists.txt) -- [config.ini](file://share/vizd/config/config.ini) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [account_history_plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [database_api_plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp) -- [testing.md](file://documentation/testing.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains how to develop custom plugins from scratch in the project’s plugin framework. It covers: -- The plugin template system and how to generate boilerplate code using the provided generator -- The plugin class structure, required methods, and interface implementation patterns -- Step-by-step tutorials for three plugin types: API plugins, database plugins, and network plugins -- The development workflow from template generation to deployment and testing -- Configuration options, command-line parameter handling, and integration with the main application -- Testing strategies, unit testing patterns, and integration testing approaches -- Practical examples of common plugin patterns and anti-patterns -- Guidelines for packaging, distribution, and version management -- Debugging techniques and common development issues - -## Project Structure -Plugins are organized under the plugins directory. Each plugin typically includes: -- A header file defining the plugin class and API declarations -- An implementation file implementing plugin lifecycle and API methods -- Optional API object headers for serialization and data structures -- A CMakeLists.txt to integrate the plugin into the build system -- A dedicated include/graphene/plugins// directory for public headers - -The top-level plugin registry is driven by a CMake script that discovers subdirectories and registers available plugins. Third-party plugins can be dropped into an external_plugins directory and built alongside internal ones. - -```mermaid -graph TB -subgraph "Build System" -PL_CMAKE["plugins/CMakeLists.txt"] -GEN["programs/util/newplugin.py"] -end -subgraph "Plugin Registry" -REG["Internal Plugins
CHAIN_INTERNAL_PLUGINS"] -EXT["External Plugins
external_plugins"] -end -subgraph "Example Plugins" -TEST_API["test_api_plugin.hpp/.cpp"] -WEB["webserver_plugin.hpp"] -P2P["p2p_plugin.hpp"] -MONGO["mongo_db_plugin.hpp"] -CHAIN["chain_plugin.hpp"] -JSONRPC["json_rpc_plugin.hpp"] -DBAPI["database_api_plugin.hpp"] -NB["network_broadcast_api_plugin.hpp"] -end -GEN --> |"Generates"| TEST_API -PL_CMAKE --> |"Scans subdirs"| REG -EXT --> |"Discovered by"| REG -TEST_API --> |"Requires"| JSONRPC -WEB --> |"Requires"| JSONRPC -P2P --> |"Requires"| CHAIN -MONGO --> |"Requires"| CHAIN -DBAPI --> |"Requires"| CHAIN -NB --> |"Requires"| CHAIN -NB --> |"Requires"| P2P -``` - -**Diagram sources** -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L1-L61) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L1-L57) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) -- [database_api_plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L1-L429) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L1-L91) - -**Section sources** -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [plugin.md](file://documentation/plugin.md#L1-L28) - -## Core Components -- Plugin template generator: A Python script that scaffolds a new plugin with standard files and boilerplate code. -- Plugin base class and lifecycle: Plugins derive from the application plugin base and implement initialization, startup, shutdown, and optional API registration. -- JSON-RPC integration: Many plugins depend on and register APIs with the JSON-RPC plugin to expose RPC endpoints. -- Chain integration: Plugins may subscribe to chain events (e.g., applied block signals) and access the database through the chain plugin. -- Configuration and CLI options: Plugins define program options and read configuration values during initialization. - -Key implementation patterns: -- Use APPBASE_PLUGIN_REQUIRES to declare dependencies on other plugins -- Implement plugin_initialize to parse options and register APIs -- Implement plugin_startup to connect signals and finalize initialization -- Implement plugin_shutdown to clean up resources -- Expose API methods via DECLARE_API and DEFINE_API macros - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L1-L61) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) - -## Architecture Overview -The plugin architecture centers around appbase, with plugins registering themselves and APIs with the JSON-RPC dispatcher. Plugins commonly depend on the chain plugin for database access and on p2p for networking. - -```mermaid -graph TB -subgraph "Application Layer" -APP["Application"] -CFG["Config Options"] -end -subgraph "Core Plugins" -CHAIN["chain::plugin"] -JSONRPC["json_rpc::plugin"] -end -subgraph "Feature Plugins" -API["database_api::plugin"] -NB["network_broadcast_api::plugin"] -P2P["p2p::plugin"] -WS["webserver::plugin"] -TEST["test_api::plugin"] -MONGO["mongo_db::plugin"] -end -APP --> CHAIN -APP --> JSONRPC -API --> CHAIN -API --> JSONRPC -NB --> CHAIN -NB --> P2P -NB --> JSONRPC -P2P --> CHAIN -WS --> JSONRPC -TEST --> JSONRPC -MONGO --> CHAIN -CFG --> APP -``` - -**Diagram sources** -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) -- [database_api_plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L1-L429) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L1-L91) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L1-L57) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L1-L61) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) - -## Detailed Component Analysis - -### Plugin Template System -The template generator creates a complete plugin scaffold with: -- A plugin header declaring the plugin class and required methods -- An API header declaring the API class and FC_API method list -- Implementation files for both plugin and API -- A CMakeLists.txt fragment for library integration - -The generator accepts provider and plugin name arguments and writes files into libraries/plugins/. - -```mermaid -flowchart TD -Start(["Run newplugin.py"]) --> ParseArgs["Parse provider and plugin name"] -ParseArgs --> BuildCtx["Build context dict"] -BuildCtx --> IterateTemplates["Iterate template dictionary"] -IterateTemplates --> FormatContent["Format template content"] -FormatContent --> EnsureDir["Ensure output directory exists"] -EnsureDir --> WriteFiles["Write files to disk"] -WriteFiles --> Done(["Scaffold ready"]) -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L251) - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L1-L251) - -### Plugin Class Structure and Lifecycle -A typical plugin class follows this structure: -- Public plugin class deriving from the application plugin base -- Private implementation class encapsulating logic -- Required methods: plugin_name, plugin_initialize, plugin_startup, plugin_shutdown -- Optional: signal connections and API registration - -```mermaid -classDiagram -class PluginBase { -<> -+plugin_name() string -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -} -class MyPlugin { --my : PluginImpl -+plugin_name() string -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -} -class PluginImpl { --app : Application -+plugin_name() string -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+on_applied_block(b) -} -PluginBase <|-- MyPlugin -MyPlugin --> PluginImpl : "owns" -``` - -**Diagram sources** -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L27-L53) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L23) - -**Section sources** -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L1-L61) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) - -### API Plugin Pattern -API plugins expose RPC endpoints via the JSON-RPC plugin. They: -- Define argument/result structs -- Declare APIs with DECLARE_API and implement with DEFINE_API -- Register themselves during plugin_initialize using JSON_RPC_REGISTER_API - -```mermaid -sequenceDiagram -participant App as "Application" -participant Test as "test_api_plugin" -participant RPC as "json_rpc : : plugin" -App->>Test : plugin_initialize(options) -Test->>RPC : JSON_RPC_REGISTER_API("test_api") -App->>Test : plugin_startup() -Test->>RPC : add_api_method("test_api_a", ...) -Test->>RPC : add_api_method("test_api_b", ...) -Note over Test,App : API methods now callable via JSON-RPC -``` - -**Diagram sources** -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L35) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L109-L113) - -**Section sources** -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L23-L53) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) - -### Database Plugin Pattern -Database plugins typically: -- Require the chain plugin -- Subscribe to chain events (e.g., applied block) -- Access the database through the chain plugin’s database interface -- Optionally maintain their own indices or state - -```mermaid -sequenceDiagram -participant Chain as "chain : : plugin" -participant Mongo as "mongo_db : : plugin" -participant DB as "Database" -Chain-->>Mongo : applied_block(signed_block) -Mongo->>DB : read/write operations -Mongo-->>Chain : signal handling complete -``` - -**Diagram sources** -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) - -**Section sources** -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) - -### Network Plugin Pattern -Network plugins: -- Depend on the chain plugin for blockchain data -- May broadcast blocks/transactions via the p2p plugin -- Often expose APIs for broadcasting and synchronization - -```mermaid -sequenceDiagram -participant NB as "network_broadcast_api : : plugin" -participant P2P as "p2p : : plugin" -participant Chain as "chain : : plugin" -NB->>P2P : broadcast_transaction(...) -NB->>P2P : broadcast_block(...) -P2P-->>NB : ack/nack -NB->>Chain : accept_transaction(...) (via chain plugin) -``` - -**Diagram sources** -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L47-L83) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L44-L46) - -**Section sources** -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L1-L91) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L1-L57) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) - -## Dependency Analysis -Plugins declare dependencies using APPBASE_PLUGIN_REQUIRES. The JSON-RPC plugin is central for exposing APIs. The chain plugin provides database access and event signals. Network plugins typically depend on p2p and chain. - -```mermaid -graph LR -JSONRPC["json_rpc::plugin"] --> TEST["test_api::plugin"] -JSONRPC --> DBAPI["database_api::plugin"] -JSONRPC --> WS["webserver::plugin"] -CHAIN["chain::plugin"] --> DBAPI -CHAIN --> MONGO["mongo_db::plugin"] -CHAIN --> NB["network_broadcast_api::plugin"] -CHAIN --> P2P["p2p::plugin"] -P2P --> NB -``` - -**Diagram sources** -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L35) -- [database_api_plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L49-L49) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L23-L23) - -**Section sources** -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L35) -- [database_api_plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L49-L49) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L23-L23) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) - -## Performance Considerations -- Minimize database contention by using single-write-thread options and tuned lock retries -- Avoid heavy operations in signal handlers; defer to background tasks when possible -- Use appropriate indexing and caching strategies in database plugins -- Keep API methods efficient; avoid blocking operations in RPC handlers - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Plugin not loading: Verify plugin is enabled in configuration and discovered by the build system -- API not available: Ensure JSON-RPC registration occurs in plugin_initialize and that public-api is configured if needed -- Chain-dependent plugin failing: Confirm chain plugin is enabled and that replay may be required when toggling history-related plugins -- Lock contention: Adjust read/write wait retries and consider single-write-thread mode - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) -- [config.ini](file://share/vizd/config/config.ini#L13-L47) - -## Conclusion -The project provides a robust, extensible plugin framework. By leveraging the template generator, following the plugin lifecycle, and integrating with core plugins (JSON-RPC, chain, p2p), developers can build API, database, and network plugins efficiently. Proper configuration, testing, and performance tuning ensure reliable deployments. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Step-by-Step Tutorial: API Plugin -1. Generate the plugin scaffold: - - Run the generator with provider and plugin name - - Review and customize the generated files -2. Implement API methods: - - Define argument/result structs - - Declare APIs in the plugin header - - Implement methods in the plugin source -3. Register the API: - - Call JSON-RPC registration in plugin_initialize -4. Configure and run: - - Enable the plugin in configuration - - Start the node and test via JSON-RPC - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L251) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L23-L53) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L35) -- [plugin.md](file://documentation/plugin.md#L21-L28) - -### Step-by-Step Tutorial: Database Plugin -1. Generate the plugin scaffold -2. Add chain dependency and database access patterns -3. Subscribe to chain events (e.g., applied block) -4. Implement persistence logic and indexing -5. Register and enable the plugin - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L251) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) - -### Step-by-Step Tutorial: Network Plugin -1. Generate the plugin scaffold -2. Add dependencies on chain and p2p -3. Implement broadcast methods and event handling -4. Integrate with network_broadcast_api if exposing RPC - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L251) -- [network_broadcast_api_plugin.hpp](file://plugins/network_broadcast_api/include/graphene/plugins/network_broadcast_api/network_broadcast_api_plugin.hpp#L49-L49) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) - -### Plugin Configuration and CLI -- Enable plugins via configuration entries -- Use public-api and api-user for access control -- Configure thread pools and endpoints for webserver plugins -- Adjust chain-related options affecting plugin behavior - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -### Testing Strategies -- Unit tests: Use the chain_test target and categorize tests -- Runtime configuration: Control logging and reporting via test harness options -- Code coverage: Enable coverage builds and generate HTML reports - -**Section sources** -- [testing.md](file://documentation/testing.md#L1-L43) - -### Packaging and Distribution -- Place third-party plugins under external_plugins and build with the same process -- Ensure each plugin includes a CMakeLists.txt and proper include layout -- Version management: Align plugin versions with the project’s release cycle - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L7-L7) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Inter-Plugin Communication.md b/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Inter-Plugin Communication.md deleted file mode 100644 index a95daf87f5..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Inter-Plugin Communication.md +++ /dev/null @@ -1,483 +0,0 @@ -# Inter-Plugin Communication - - -**Referenced Files in This Document** -- [main.cpp](file://programs/vizd/main.cpp) -- [CMakeLists.txt](file://plugins/CMakeLists.txt) -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp) -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [api.cpp (database_api)](file://plugins/database_api/api.cpp) - - -## Update Summary -**Changes Made** -- Enhanced memory management coordination between account_history and operation_history plugins -- Added purging coordination mechanisms to prevent dangling references -- Improved signal handler management with proper cleanup procedures -- Updated plugin dependency graph to reflect enhanced coordination patterns - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Memory Management Coordination](#memory-management-coordination) -7. [Dependency Analysis](#dependency-analysis) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction -This document explains inter-plugin communication patterns and mechanisms in the codebase built on the appbase framework. It focuses on: -- How plugins declare and consume dependencies via appbase's dependency injection system -- Event-driven communication using Boost.Signals2 signals and slots -- Practical examples of signal emission and subscription across plugins -- How plugins expose APIs to other plugins and establish communication channels -- The plugin dependency graph and initialization order -- Best practices for loose coupling and avoiding circular dependencies -- Thread-safety considerations and synchronization mechanisms -- **Enhanced memory management coordination between plugins for efficient resource utilization** - -## Project Structure -The application initializes a set of plugins and wires them together through appbase. Plugins declare required dependencies, and the runtime ensures they are initialized in dependency order. The main entrypoint registers and starts selected plugins. - -```mermaid -graph TB -Main["programs/vizd/main.cpp
Registers and starts plugins"] --> Chain["plugins/chain/plugin.hpp
Provides chain database and signals"] -Main --> P2P["plugins/p2p/p2p_plugin.hpp
Requires chain"] -Main --> Web["plugins/webserver/webserver_plugin.hpp
Requires json_rpc"] -Main --> DBAPI["plugins/database_api/plugin.hpp
Requires chain and json_rpc"] -Main --> OpHist["plugins/operation_history/plugin.hpp
Requires chain and json_rpc"] -Main --> AccHist["plugins/account_history/plugin.hpp
Requires chain, operation_history, json_rpc"] -Chain --> DBAPI -Chain --> OpHist -Chain --> AccHist -Chain --> P2P -Web --> DBAPI -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugin.hpp (p2p_plugin.hpp)](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L192) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L52-L58) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L66) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Core Components -- Plugin registration and startup: The main entrypoint registers all plugins and starts a configured subset. -- Dependency declaration: Plugins declare required plugins via APPBASE_PLUGIN_REQUIRES, enabling automatic initialization and injection. -- Signals and slots: Plugins emit and subscribe to Boost.Signals2 signals for event-driven communication. -- API exposure: Plugins expose read-only APIs (e.g., database queries) to other plugins and clients. -- **Memory management coordination: Enhanced coordination between plugins to prevent memory leaks and dangling references.** - -Key implementation references: -- Plugin registration and startup sequence - - [main.cpp](file://programs/vizd/main.cpp#L62-L90) - - [main.cpp](file://programs/vizd/main.cpp#L117-L122) -- Dependency declarations - - [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) - - [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) - - [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) - - [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) - - [plugin.hpp (p2p_plugin.hpp)](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) - - [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) -- Signals and slots - - [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) - - [api.cpp (database_api)](file://plugins/database_api/api.cpp#L35) -- **Memory management coordination** - - [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L107-L122) - - [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) -- [plugin.hpp (p2p_plugin.hpp)](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) -- [api.cpp (database_api)](file://plugins/database_api/api.cpp#L35) -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L107-L122) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) - -## Architecture Overview -The system composes plugins around the chain plugin as a central dependency provider. Other plugins depend on chain and/or json_rpc to expose APIs and coordinate events. **Enhanced memory management coordination ensures efficient resource utilization across plugins.** - -```mermaid -graph TB -subgraph "Runtime" -App["appbase::application"] -Chain["chain::plugin"] -JsonRpc["json_rpc::plugin"] -DBAPI["database_api::plugin"] -OpHist["operation_history::plugin"] -AccHist["account_history::plugin"] -P2P["p2p::p2p_plugin"] -Web["webserver::webserver_plugin"] -end -App --> Chain -App --> JsonRpc -App --> DBAPI -App --> OpHist -App --> AccHist -App --> P2P -App --> Web -DBAPI --> Chain -OpHist --> Chain -AccHist --> Chain -AccHist --> OpHist -P2P --> Chain -Web --> JsonRpc -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) -- [plugin.hpp (p2p_plugin.hpp)](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) - -## Detailed Component Analysis - -### Chain Plugin: Central Dependency Provider and Signal Emitter -- Purpose: Provides the blockchain database and emits synchronization signals. -- Signals: - - on_sync: emitted when the blockchain is syncing/live; useful for plugins that optionally depend on chain state. -- Dependencies: - - Requires json_rpc::plugin for RPC transport. - -```mermaid -classDiagram -class ChainPlugin { -+on_sync : "signal" -+plugin_initialize(...) -+plugin_startup() -+accept_block(...) -+accept_transaction(...) -+db() : "database&" -} -``` - -**Diagram sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L91) - -**Section sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L91) - -### Database API Plugin: API Exposure and Callback Subscription -- Purpose: Exposes read-only database queries and subscriptions to clients and other plugins. -- Dependencies: - - Requires chain::plugin and json_rpc::plugin. -- Subscriptions: - - set_block_applied_callback: allows plugins to receive notifications when blocks are applied. - - set_subscribe_callback and set_pending_transaction_callback: for streaming updates. -- Example usage patterns: - - Subscribe to block-applied events from another plugin via the callback mechanism. - - Query chain state through the chain database accessor exposed by chain::plugin. - -```mermaid -classDiagram -class DatabaseAPIPlugin { -+set_block_applied_callback(cb) -+set_subscribe_callback(cb, clear_filter) -+set_pending_transaction_callback(cb) -+cancel_all_subscriptions() -+plugin_initialize(...) -+plugin_startup() -} -DatabaseAPIPlugin --> ChainPlugin : "requires" -DatabaseAPIPlugin --> JsonRpcPlugin : "requires" -``` - -**Diagram sources** -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L226) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) - -**Section sources** -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L226) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) - -### Operation History Plugin: Event Producer for Operations -- Purpose: Tracks operations and exposes APIs to query operations in blocks and transactions. -- Dependencies: - - Requires chain::plugin and json_rpc::plugin. -- Purging mechanism: - - Implements automatic purging based on history_count_blocks configuration. - - Provides get_min_keep_block() API for other plugins to coordinate purging. -- Typical usage: - - Used by account_history to maintain per-account histories. - -```mermaid -classDiagram -class OperationHistoryPlugin { -+get_ops_in_block(...) -+get_transaction(...) -+get_min_keep_block() : "uint32_t" -+purge_old_history() -+plugin_initialize(...) -+plugin_startup() -} -OperationHistoryPlugin --> ChainPlugin : "requires" -OperationHistoryPlugin --> JsonRpcPlugin : "requires" -``` - -**Diagram sources** -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L52-L83) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L99-L122) - -**Section sources** -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L52-L83) -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L99-L122) - -### Account History Plugin: Consumer of Operation History Events -- Purpose: Maintains per-account operation histories by subscribing to operation streams. -- Dependencies: - - Requires chain::plugin, operation_history::plugin, and json_rpc::plugin. -- Purging coordination: - - Coordinates with operation_history plugin to avoid dangling references. - - Uses get_min_keep_block() from operation_history plugin for aggressive purging. -- Typical usage: - - Subscribes to operation updates and records them for later retrieval. - -```mermaid -classDiagram -class AccountHistoryPlugin { -+get_account_history(...) -+tracked_accounts() -+purge_old_history() -+plugin_initialize(...) -+plugin_startup() -+plugin_shutdown() -} -AccountHistoryPlugin --> ChainPlugin : "requires" -AccountHistoryPlugin --> OperationHistoryPlugin : "requires" -AccountHistoryPlugin --> JsonRpcPlugin : "requires" -``` - -**Diagram sources** -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L93) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) - -**Section sources** -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L93) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) - -### P2P Plugin: Broadcast and Event Propagation -- Purpose: Handles peer-to-peer networking and broadcasts blocks/transactions. -- Dependencies: - - Requires chain::plugin for block/transaction validation and context. -- Typical usage: - - Receives blocks from chain and broadcasts them to peers. - -```mermaid -classDiagram -class P2PPlugin { -+broadcast_block(...) -+broadcast_transaction(...) -+plugin_initialize(...) -+plugin_startup() -} -P2PPlugin --> ChainPlugin : "requires" -``` - -**Diagram sources** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) - -**Section sources** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) - -### Webserver Plugin: JSON-RPC Endpoint -- Purpose: Exposes HTTP/WS endpoints for JSON-RPC requests. -- Dependencies: - - Requires json_rpc::plugin for request routing and transport. -- Thread-safety note: - - The plugin documentation indicates handlers run on the appbase io_service thread, and callbacks can be invoked from any thread and are automatically propagated to the HTTP thread. - -```mermaid -classDiagram -class WebserverPlugin { -+plugin_initialize(...) -+plugin_startup() -+plugin_shutdown() -} -WebserverPlugin --> JsonRpcPlugin : "requires" -``` - -**Diagram sources** -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -**Section sources** -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -### Observer Pattern with Boost.Signals2 -- Signal emission: - - chain::plugin defines on_sync as a signal for synchronization events. -- Signal consumption: - - database_api::plugin subscribes to signals exposed by other components (e.g., block-applied signals) to react to blockchain events. -- Practical examples: - - chain::plugin emits on_sync during sync/live transitions. - - database_api::plugin uses a signal reference parameter to connect to block-applied events. - -```mermaid -sequenceDiagram -participant Chain as "chain : : plugin" -participant DB as "database_api : : plugin" -participant IO as "appbase io_service" -Chain->>Chain : "emit on_sync()" -Chain-->>IO : "signal event" -IO-->>DB : "invoke connected slot(s)" -DB->>DB : "handle block-applied callback" -``` - -**Diagram sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) -- [api.cpp (database_api)](file://plugins/database_api/api.cpp#L35) - -**Section sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) -- [api.cpp (database_api)](file://plugins/database_api/api.cpp#L35) - -## Memory Management Coordination - -### Enhanced Purging Coordination Mechanisms -The account_history and operation_history plugins now implement sophisticated memory management coordination to prevent memory leaks and dangling references. - -#### Operation History Purging -The operation_history plugin maintains a configurable history depth and provides purging capabilities: - -```mermaid -flowchart TD -A["Block Applied Event"] --> B["Check history_count_blocks"] -B --> C{"Need to purge?"} -C --> |Yes| D["Calculate min_keep_block"] -D --> E["Iterate through operation_index"] -E --> F["Remove old operations"] -F --> G["Complete purging"] -C --> |No| H["No action"] -``` - -**Diagram sources** -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L107-L122) - -#### Account History Coordination -The account_history plugin coordinates with operation_history to ensure consistent memory management: - -```mermaid -flowchart TD -A["Block Applied Event"] --> B["Calculate own min_keep_block"] -B --> C["Get operation_history min_keep_block"] -C --> D{"Compare values"} -D --> |operation_history > own| E["Use operation_history value"] -D --> |own >= operation_history| F["Use own value"] -E --> G["Purge old account history"] -F --> G["Purge old account history"] -G --> H["Update account range objects"] -``` - -**Diagram sources** -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) - -#### Signal Handler Management -Both plugins implement proper signal handler management for graceful shutdown: - -**Section sources** -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L107-L122) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L94-L163) -- [plugin.cpp (operation_history)](file://plugins/operation_history/plugin.cpp#L293-L299) -- [plugin.cpp (account_history)](file://plugins/account_history/plugin.cpp#L580-L586) - -## Dependency Analysis -Plugins declare dependencies using APPBASE_PLUGIN_REQUIRES. The runtime initializes plugins in dependency order and makes required plugins available to consumers. **Enhanced coordination ensures proper memory management across the plugin ecosystem.** - -```mermaid -graph LR -JsonRpc["json_rpc::plugin"] --> Chain["chain::plugin"] -JsonRpc --> DBAPI["database_api::plugin"] -JsonRpc --> Web["webserver::webserver_plugin"] -JsonRpc --> OpHist["operation_history::plugin"] -JsonRpc --> AccHist["account_history::plugin"] -JsonRpc --> PrivateMsg["private_message_plugin"] -JsonRpc --> TestAPI["test_api_plugin"] -Chain --> P2P["p2p::p2p_plugin"] -Chain --> OpHist -Chain --> AccHist -Chain --> DebugNode["debug_node::plugin"] -Chain --> RawBlock["raw_block::plugin"] -Chain --> BlockInfo["block_info::plugin"] -Chain --> Tags["tags::plugin"] -Chain --> Follow["follow::plugin"] -Chain --> validator["witness_plugin::witness_plugin"] -Chain --> CommitteeAPI["committee_api::committee_api"] -Chain --> InviteAPI["invite_api::invite_api"] -Chain --> PaidSubAPI["paid_subscription_api::paid_subscription_api"] -Chain --> CustomProtoAPI["custom_protocol_api::custom_protocol_api_plugin"] -OpHist -.-> AccHist -AccHist -.-> OpHist -``` - -**Diagram sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) - -**Section sources** -- [plugin.hpp (chain)](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugin.hpp (database_api)](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L187-L192) -- [plugin.hpp (operation_history)](file://plugins/operation_history/include/graphene/plugins/operation_history/plugin.hpp#L53-L58) -- [plugin.hpp (account_history)](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L60-L66) -- [plugin.hpp (webserver)](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L39) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L21) - -## Performance Considerations -- Prefer lightweight signals for event propagation to avoid heavy synchronous calls. -- Use asynchronous callbacks and appbase io_service threads for I/O-bound tasks (e.g., webserver). -- Minimize contention by keeping shared state protected and avoiding long-running work in signal handlers. -- Batch operations where possible to reduce overhead (e.g., bulk indexing in account_history). -- **Implement coordinated purging to prevent memory accumulation and improve performance.** -- **Use get_min_keep_block() API for consistent memory management across plugins.** - -## Troubleshooting Guide -- Initialization failures: - - Verify that all required plugins are registered and present in the dependency graph. - - Ensure APPBASE_PLUGIN_REQUIRES lists are correct and match actual dependencies. -- Signal not firing: - - Confirm that the emitting plugin actually emits the signal and that subscribers connect before the event occurs. - - Check that the signal lifetime exceeds the subscription duration. -- API not available: - - Ensure the plugin exposing the API is started and that dependent plugins are initialized in the correct order. -- **Memory issues:** - - Verify that both operation_history and account_history plugins are properly coordinating purging. - - Check that get_min_keep_block() values are consistent across plugins. - - Ensure signal handlers are properly disconnected during shutdown. - -## Conclusion -Inter-plugin communication in this codebase relies on a clean separation of concerns with enhanced memory management coordination: -- appbase manages dependency injection and initialization order -- Boost.Signals2 enables decoupled event propagation -- Plugins expose read-only APIs for others to consume -- The chain plugin acts as the central dependency provider -- **Enhanced coordination between operation_history and account_history prevents memory leaks and dangling references** -- **Proper signal handler management ensures graceful shutdown and resource cleanup** - -Following the patterns documented here helps maintain loose coupling, predictable initialization, robust event-driven workflows, and efficient memory utilization across the plugin ecosystem. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin API Design Patterns.md b/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin API Design Patterns.md deleted file mode 100644 index 4e7fe0c839..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin API Design Patterns.md +++ /dev/null @@ -1,327 +0,0 @@ -# Plugin API Design Patterns - - -**Referenced Files in This Document** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [api.cpp](file://plugins/database_api/api.cpp) -- [db_with.hpp](file://libraries/chain/include/graphene/chain/db_with.hpp) -- [history_object.hpp](file://plugins/account_history/include/graphene/plugins/account_history/history_object.hpp) -- [plugin.cpp](file://plugins/account_history/plugin.cpp) -- [follow_objects.hpp](file://plugins/follow/include/graphene/plugins/follow/follow_objects.hpp) -- [plugin.cpp](file://plugins/follow/plugin.cpp) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains plugin API design patterns and best practices for the VIZ blockchain node, focusing on how plugins access and interact with the blockchain database through the chainbase framework. It documents database access patterns (find, get, and index operations), demonstrates CRUD operations implemented by plugins, outlines API surface design principles, and covers error handling, validation, and performance considerations. Practical usage patterns and integration with other system components are also included. - -## Project Structure -The plugin system is organized around the appbase framework with plugins exposing JSON-RPC APIs backed by the chain database. The chain plugin owns the database and exposes template-based access helpers. Other plugins (e.g., database_api, account_history, follow) depend on the chain plugin and use the database to implement their APIs. - -```mermaid -graph TB -subgraph "Plugins" -CH["Chain Plugin
plugins/chain"] -DBAPI["Database API Plugin
plugins/database_api"] -AH["Account History Plugin
plugins/account_history"] -FOL["Follow Plugin
plugins/follow"] -end -subgraph "Core Chain" -DB["Chain Database
libraries/chain"] -CB["Chainbase Framework
thirdparty/chainbase"] -end -CH --> DB -DBAPI --> CH -AH --> CH -FOL --> CH -DB --> CB -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L181) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L1-L100) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L181) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) - -## Core Components -- Chain plugin: Provides the database handle and template-based accessors (has_index, get_index, find, get) to support type-safe object operations. It manages database lifecycle (open, reindex, replay, close) and exposes signals for synchronization. -- Database API plugin: Exposes read-only RPC queries against the chain database (blocks, transactions, globals, accounts, balances, authority/validations, database info). -- Account History plugin: Maintains per-account operation history and ranges, implementing CRUD-like operations to create, modify, and purge history entries. -- Follow plugin: Implements social features (followers, following, feed/blog caches) using database CRUD operations and custom operation interpretation. - -Key template-based database access patterns: -- has_index() -- get_index() -- find(key) -- find(object_id) -- get(key) -- get(object_id) - -These are thin wrappers around the underlying chainbase database and are exposed by the chain plugin for use by other plugins. - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L52-L86) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L181) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L13-L558) - -## Architecture Overview -The chain plugin owns the database and exposes a clean API surface to other plugins. Plugins requiring read/write access to the database use the chain plugin’s database handle and template-based helpers. Plugins that only need read access wrap their API calls with weak read locks to avoid blocking writers. - -```mermaid -sequenceDiagram -participant Client as "RPC Client" -participant DBAPI as "Database API Plugin" -participant CH as "Chain Plugin" -participant DB as "Chain Database" -Client->>DBAPI : "get_dynamic_global_properties" -DBAPI->>CH : "db()" -CH-->>DBAPI : "database reference" -DBAPI->>DB : "get(id)" -DB-->>DBAPI : "object reference" -DBAPI-->>Client : "API response" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [api.cpp](file://plugins/database_api/api.cpp#L333-L347) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L83-L86) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L164-L164) - -## Detailed Component Analysis - -### Chain Plugin: Template-Based Accessors and Lifecycle -- Template accessors: - - has_index() checks for the existence of a multi-index type. - - get_index() returns a reference to the generic index for type T. - - find(key) and find(id) locate objects without throwing if not found. - - get(key) and get(id) retrieve objects and throw if missing. -- Database lifecycle: - - Open/reindex/replay/close with configurable shared memory sizing and flushing intervals. - - Options for single-write-thread mode, virtual operations skipping, and plugin hooks on push_transaction. - -```mermaid -classDiagram -class ChainPlugin { -+plugin_initialize(opts) -+plugin_startup() -+plugin_shutdown() -+accept_block(block, currently_syncing, skip) -+accept_transaction(trx) -+has_index() -+get_index() -+find(key) -+find(id) -+get(key) -+get(id) -+db() : Database -+on_sync : signal -} -class Database { -+open(data_dir, shm_dir, ...) -+reindex(data_dir, shm_dir, from, ...) -+push_block(...) -+push_transaction(...) -+get_index(...) -+find(...) -+get(...) -} -ChainPlugin --> Database : "owns and exposes" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L424) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L558) - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L52-L86) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L424) - -### Database API Plugin: Read-Only Queries and Locking -- API surface includes blocks, transactions, globals, accounts, balances, authority/validations, and database info. -- Uses weak read locks around database queries to minimize contention with writers. -- Subscriptions and callbacks for block-applied events. - -```mermaid -sequenceDiagram -participant Client as "RPC Client" -participant DBAPI as "Database API Plugin" -participant DB as "Chain Database" -Client->>DBAPI : "get_accounts(names)" -DBAPI->>DB : "with_weak_read_lock(...)" -DBAPI->>DB : "get_index().indices().get()" -DBAPI->>DB : "find(name)" -DB-->>DBAPI : "account_api_object" -DBAPI-->>Client : "vector" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [api.cpp](file://plugins/database_api/api.cpp#L371-L399) -- [api.cpp](file://plugins/database_api/api.cpp#L401-L425) - -**Section sources** -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [api.cpp](file://plugins/database_api/api.cpp#L371-L399) -- [api.cpp](file://plugins/database_api/api.cpp#L401-L425) - -### Account History Plugin: CRUD Operations on Blockchain Objects -- Creates account history entries and maintains account range boundaries. -- Modifies existing range objects when sequences change. -- Purges old history based on configured block window. -- Uses database.create, database.modify, and database.remove for CRUD. - -```mermaid -flowchart TD -Start(["Operation Applied"]) --> Impact["Determine impacted accounts"] -Impact --> Iterate{"For each impacted account"} -Iterate --> |Create| CreateHist["create"] -Iterate --> |Update Range| UpdateRange["modify"] -Iterate --> |Purge Old| Purge["Iterate by_block index
remove entries outside window"] -CreateHist --> End(["Done"]) -UpdateRange --> End -Purge --> End -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L51-L82) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L93-L126) - -**Section sources** -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L51-L82) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L93-L126) -- [history_object.hpp](file://plugins/account_history/include/graphene/plugins/account_history/history_object.hpp#L76-L119) - -### Follow Plugin: Index-Based Reads and Writes -- Implements social graph and feed/blog caches using multi-index containers. -- Reads with lower_bound and equality checks on composite indices. -- Writes with create and remove operations, enforcing limits via old-index trimming. - -```mermaid -sequenceDiagram -participant OP as "Operation" -participant VIS as "post_operation_visitor" -participant DB as "Chain Database" -OP->>VIS : "visit(content_operation)" -VIS->>DB : "get_content(author, permlink)" -VIS->>DB : "get_index().indices().get()" -VIS->>DB : "find(account)" -VIS->>DB : "create() / create()" -VIS->>DB : "trim old entries via by_old_* indices" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/follow/plugin.cpp#L114-L188) -- [follow_objects.hpp](file://plugins/follow/include/graphene/plugins/follow/follow_objects.hpp#L144-L226) - -**Section sources** -- [plugin.cpp](file://plugins/follow/plugin.cpp#L114-L188) -- [follow_objects.hpp](file://plugins/follow/include/graphene/plugins/follow/follow_objects.hpp#L144-L226) - -### Plugin API Surface Design Principles -- Clean separation of concerns: chain plugin owns DB, other plugins depend on it. -- Type-safe accessors via templates to avoid runtime errors and promote compile-time safety. -- Read-only APIs use weak read locks to reduce contention. -- Strong validation and assertions for limits and invariants. -- Signals for synchronization and event-driven integrations. - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L52-L86) -- [api.cpp](file://plugins/database_api/api.cpp#L150-L175) -- [plugin.cpp](file://plugins/follow/plugin.cpp#L350-L395) - -## Dependency Analysis -- The chain plugin depends on chainbase and exposes a database interface to other plugins. -- The database API plugin depends on the chain plugin and the JSON-RPC plugin. -- Account History and Follow plugins depend on the chain plugin and define their own multi-indexes. - -```mermaid -graph LR -CH["Chain Plugin"] --> DB["Chain Database"] -DBAPI["Database API Plugin"] --> CH -AH["Account History Plugin"] --> CH -FOL["Follow Plugin"] --> CH -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L191) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L491-L492) -- [plugin.cpp](file://plugins/follow/plugin.cpp#L319-L323) - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L191) -- [plugin.cpp](file://plugins/account_history/plugin.cpp#L491-L492) -- [plugin.cpp](file://plugins/follow/plugin.cpp#L319-L323) - -## Performance Considerations -- Shared memory sizing and growth: - - Configure initial shared memory size, increment size, and minimum free space thresholds. - - Periodic checks for free space to avoid stalls. -- Single write thread: - - Optional single-write-thread mode to serialize block/transaction pushes for stability. -- Virtual operations: - - Skip virtual operations to reduce memory pressure during sync. -- Read locks: - - Use weak read locks for read-only APIs to minimize writer contention. -- Index traversal limits: - - Enforce reasonable limits on returned rows to prevent excessive CPU/memory usage. -- Flush interval: - - Tune flush interval to balance durability and performance. - -Practical tips: -- Prefer index-based lookups (lower_bound, equal_range) for efficient scans. -- Use composite indices for multi-key queries. -- Limit pagination sizes and enforce client-side caps. -- Monitor free shared memory and adjust increments accordingly. - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L183-L251) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L330-L346) -- [api.cpp](file://plugins/database_api/api.cpp#L436-L450) -- [api.cpp](file://plugins/database_api/api.cpp#L582-L591) - -## Troubleshooting Guide -Common issues and strategies: -- Database open failures: - - On revision mismatch or corruption, the chain plugin attempts to replay or resync automatically based on configuration flags. -- Exception propagation: - - Plugins should wrap API calls with weak read locks and handle exceptions gracefully. - - Internal exception macros and plugin exception handling ensure consistent logging and propagation. -- Operation validation and evaluation: - - Dedicated exception categories for validation and evaluation failures aid in diagnostics. -- Signal handling: - - Signal guard ensures proper cleanup and exception reporting during signal delivery. - -Best practices: -- Always validate inputs and enforce limits before querying the database. -- Use find vs get appropriately: find avoids exceptions for missing objects; get throws if not found. -- Log and rethrow plugin exceptions to preserve stack traces. - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L348-L386) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L45-L62) -- [api.cpp](file://plugins/database_api/api.cpp#L150-L175) - -## Conclusion -The VIZ plugin system leverages a clean, template-based API surface to safely and efficiently access the blockchain database. Plugins implement CRUD operations using chainbase multi-indexes, expose read-only RPC APIs with weak read locks, and integrate through signals and custom operation interpreters. Robust error handling, validation, and performance tuning enable scalable and maintainable plugin development. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Architecture.md b/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Architecture.md deleted file mode 100644 index 442d21c298..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Architecture.md +++ /dev/null @@ -1,902 +0,0 @@ -# Plugin Architecture - - -**Referenced Files in This Document** -- [main.cpp](file://programs/vizd/main.cpp) -- [newplugin.py](file://programs/util/newplugin.py) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp) -- [plugin.hpp](file://plugins/follow/include/graphene/plugins/follow/plugin.hpp) -- [CMakeLists.txt](file://plugins/CMakeLists.txt) -- [database.cpp](file://libraries/chain/database.cpp) -- [node.cpp](file://libraries/network/node.cpp) -- [snapshot_plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp) -- [snapshot_plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [snapshot_types.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp) -- [snapshot_serializer.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) - - -## Update Summary -**Changes Made** -- Added comprehensive documentation for RAII session guard implementation in snapshot plugin connection handling -- Documented enhanced retry logic for client-side connection establishment addressing race conditions in P2P communication -- Updated snapshot plugin system with improved session management and connection reliability -- Enhanced documentation of anti-spam protection mechanisms with race condition prevention -- Added detailed coverage of session_guard class and its role in preventing race conditions - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Lifecycle Management](#enhanced-lifecycle-management) -7. [Signal Handler Coordination](#signal-handler-coordination) -8. [Memory Leak Prevention](#memory-leak-prevention) -9. [Snapshot Plugin System](#snapshot-plugin-system) -10. [Custom Network Protocol](#custom-network-protocol) -11. [Anti-Spam Protection](#anti-spam-protection) -12. [Session Guard Implementation](#session-guard-implementation) -13. [Enhanced Retry Logic](#enhanced-retry-logic) -14. [Race Condition Prevention](#race-condition-prevention) -15. [Integration with Chain Plugin](#integration-with-chain-plugin) -16. [Dependency Analysis](#dependency-analysis) -17. [Performance Considerations](#performance-considerations) -18. [Troubleshooting Guide](#troubleshooting-guide) -19. [Conclusion](#conclusion) -20. [Appendices](#appendices) - -## Introduction -This document explains the plugin architecture of the node, focusing on the modular, plugin-based design enabled by the appbase framework. It covers how plugins are registered, initialized, started, and shut down with enhanced lifecycle management; how they interact with the chain database and each other; and how to develop custom plugins using the provided template generator. The architecture now includes improved shutdown procedures, signal handler coordination, memory leak prevention mechanisms, comprehensive snapshot plugin system with custom network protocols for efficient blockchain state synchronization, and robust session management with RAII-based race condition prevention. - -## Project Structure -The node organizes plugins under the plugins directory, with each plugin providing its own header and implementation files. The application entry point registers and initializes plugins, while a Python script generates boilerplate for new plugins. The enhanced lifecycle management ensures proper resource cleanup during shutdown. The new snapshot plugin extends this architecture with advanced state synchronization capabilities and sophisticated connection management. - -```mermaid -graph TB -subgraph "Application Entry Point" -A["programs/vizd/main.cpp
Registers plugins and starts app"] -end -subgraph "Core Plugins" -P1["plugins/chain
Chain plugin"] -P2["plugins/webserver
Webserver plugin"] -P3["plugins/p2p
P2P plugin"] -P4["plugins/snapshot
Snapshot plugin
Enhanced"] -end -subgraph "Feature Plugins" -P5["plugins/database_api
Database API plugin"] -P6["plugins/account_history
Account History plugin"] -P7["plugins/follow
Follow plugin"] -end -subgraph "Plugin Template Generator" -T["programs/util/newplugin.py
Generates plugin boilerplate"] -end -A --> P1 -A --> P2 -A --> P3 -A --> P4 -A --> P5 -A --> P6 -A --> P7 -T --> P1 -T --> P2 -T --> P3 -T --> P4 -T --> P5 -T --> P6 -T --> P7 -``` - -**Diagram sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) - -## Core Components -- Application bootstrap and plugin registration: The application entry point registers all built-in plugins and initializes the app with selected plugins. -- Chain plugin: Provides blockchain database access, block acceptance, transaction acceptance, and emits synchronization signals with enhanced shutdown handling. -- Webserver plugin: Exposes JSON-RPC endpoints and delegates routing to the JSON-RPC plugin with proper connection cleanup. -- P2P plugin: Depends on the chain plugin and broadcasts blocks/transactions with graceful shutdown support. -- Database API plugin: Depends on chain and JSON-RPC; provides read-only database queries and subscriptions. -- Account History plugin: Tracks per-account operation history and depends on chain and operation history. -- Follow plugin: Depends on chain and JSON-RPC; provides social graph APIs. -- **Snapshot plugin**: Enhanced - Provides DLT state snapshots, automatic snapshot creation, P2P synchronization, custom TCP protocol for efficient state distribution, and robust session management with RAII-based race condition prevention. -- Plugin template generator: Automates creation of new plugins with standardized structure and dependencies. - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [webserver_plugin.cpp:329-331](file://plugins/webserver/webserver_plugin.cpp#L329-L331) -- [p2p_plugin.cpp:568-573](file://plugins/p2p/p2p_plugin.cpp#L568-L573) -- [plugin.hpp:179-409](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L409) -- [plugin.hpp:59-97](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L97) -- [plugin.hpp:23-70](file://plugins/follow/include/graphene/plugins/follow/plugin.hpp#L23-L70) -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) -- [snapshot_plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) - -## Architecture Overview -The node uses appbase to manage plugins as independent, composable units with enhanced lifecycle management. Plugins declare their dependencies, receive lifecycle callbacks with proper shutdown handling, and can expose APIs and signals. The chain plugin owns the database and emits events; other plugins subscribe to chain events or depend on the chain plugin for read/write access with coordinated shutdown procedures. The enhanced snapshot plugin integrates seamlessly with this architecture through specialized callbacks for state management and sophisticated connection handling. - -```mermaid -graph TB -subgraph "Appbase Application" -APP["appbase::app()"] -end -subgraph "Core Plugins" -CHAIN["chain::plugin
owns database
enhanced shutdown"] -JSONRPC["json_rpc::plugin"] -SNAPSHOT["snapshot::plugin
Enhanced
DLT state management
RAII session guards"] -end -subgraph "Feature Plugins" -WS["webserver_plugin
proper cleanup"] -P2P["p2p_plugin
graceful shutdown"] -DBAPI["database_api::plugin"] -AH["account_history::plugin"] -FOLLOW["follow::plugin"] -end -APP --> CHAIN -APP --> JSONRPC -APP --> SNAPSHOT -APP --> WS -APP --> P2P -APP --> DBAPI -APP --> AH -APP --> FOLLOW -CHAIN --> JSONRPC -CHAIN --> SNAPSHOT -P2P --> CHAIN -DBAPI --> CHAIN -DBAPI --> JSONRPC -AH --> CHAIN -AH --> JSONRPC -FOLLOW --> CHAIN -FOLLOW --> JSONRPC -SNAPSHOT --> CHAIN -``` - -**Diagram sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [webserver_plugin.cpp:329-331](file://plugins/webserver/webserver_plugin.cpp#L329-L331) -- [p2p_plugin.cpp:568-573](file://plugins/p2p/p2p_plugin.cpp#L568-L573) -- [plugin.hpp:179-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L191) -- [plugin.hpp:59-65](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L65) -- [plugin.hpp:23-31](file://plugins/follow/include/graphene/plugins/follow/plugin.hpp#L23-L31) -- [snapshot_plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) - -## Detailed Component Analysis - -### Plugin Registration and Lifecycle -- Registration: The application registers each plugin via appbase::app().register_plugin(). -- Initialization: plugin_initialize parses options and prepares internal state. -- Startup: plugin_startup opens databases, subscribes to signals, and exposes APIs. -- Shutdown: plugin_shutdown closes resources and tears down state with proper cleanup. - -```mermaid -sequenceDiagram -participant Main as "vizd main.cpp" -participant App as "appbase : : app()" -participant Chain as "chain : : plugin" -participant Snapshot as "snapshot : : plugin" -participant WS as "webserver_plugin" -participant DB as "database_api : : plugin" -Main->>App : register_plugins() -App->>Chain : register_plugin() -App->>Snapshot : register_plugin() -App->>WS : register_plugin() -App->>DB : register_plugin() -Main->>App : initialize(argc, argv) -App->>Chain : plugin_initialize(options) -App->>Snapshot : plugin_initialize(options) -App->>WS : plugin_initialize(options) -App->>DB : plugin_initialize(options) -Main->>App : startup() -App->>Chain : plugin_startup() -App->>Snapshot : plugin_startup() -App->>WS : plugin_startup() -App->>DB : plugin_startup() -Main->>App : exec() -Note over Main,App : Runtime loop until shutdown -Main->>App : shutdown() -App->>Chain : plugin_shutdown() -App->>Snapshot : plugin_shutdown() -App->>WS : plugin_shutdown() -App->>DB : plugin_shutdown() -``` - -**Diagram sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [main.cpp:117-140](file://programs/vizd/main.cpp#L117-L140) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [webserver_plugin.cpp:329-331](file://plugins/webserver/webserver_plugin.cpp#L329-L331) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [snapshot_plugin.cpp:1956-1959](file://plugins/snapshot/plugin.cpp#L1956-L1959) - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [main.cpp:117-140](file://programs/vizd/main.cpp#L117-L140) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [snapshot_plugin.cpp:1956-1959](file://plugins/snapshot/plugin.cpp#L1956-L1959) - -### Chain Plugin: Database Access and Signals -- Database access: Provides db() getters and convenience helpers for indices and objects. -- Block/transaction acceptance: Validates and applies blocks/transactions via the underlying database. -- Synchronization signal: Emits on_sync to notify other plugins when the chain is ready. -- Enhanced shutdown: Properly closes database connections during plugin_shutdown. -- **Snapshot integration**: Provides specialized callbacks for snapshot loading, creation, and P2P synchronization. - -```mermaid -classDiagram -class chain_plugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+accept_block(block, currently_syncing, skip) bool -+accept_transaction(trx) -+db() database -+on_sync signal -+snapshot_load_callback function -+snapshot_create_callback function -+snapshot_p2p_sync_callback function -} -class database { -+open(...) -+push_block(...) -+push_transaction(...) -+close() -} -chain_plugin --> database : "owns and uses" -``` - -**Diagram sources** -- [plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) - -**Section sources** -- [plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) - -### Inter-Plugin Communication: Observer Pattern with Boost.Signals2 -- Chain plugin emits on_sync when synchronized. -- Other plugins subscribe during startup to coordinate behavior after chain readiness. -- Example: database_api and account_history rely on chain readiness for state queries. -- **Snapshot plugin**: Integrates through specialized callbacks rather than signals for state management operations. - -```mermaid -sequenceDiagram -participant Chain as "chain : : plugin" -participant DB as "database_api : : plugin" -participant AH as "account_history : : plugin" -participant Snapshot as "snapshot : : plugin" -Chain->>Chain : on_sync() -Chain-->>DB : connected observers -Chain-->>AH : connected observers -Chain-->>Snapshot : snapshot callbacks -DB->>DB : initialize state after on_sync -AH->>AH : initialize history after on_sync -Snapshot->>Snapshot : load/create snapshot state -``` - -**Diagram sources** -- [plugin.hpp:90-90](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L90-L90) -- [plugin.hpp:195-199](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L195-L199) -- [plugin.hpp:76-77](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L76-L77) -- [snapshot_plugin.hpp:92-105](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L92-L105) - -**Section sources** -- [plugin.hpp:90-90](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L90-L90) -- [plugin.hpp:195-199](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L195-L199) -- [plugin.hpp:76-77](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L76-L77) -- [snapshot_plugin.hpp:92-105](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L92-L105) - -### Plugin Template System: newplugin.py -- Generates boilerplate for a new plugin including: - - CMakeLists.txt for library definition and linking - - Plugin header with appbase::plugin base class and lifecycle methods - - Plugin implementation with API factory registration and event subscription - - API header and implementation stubs -- The template demonstrates: - - Declaring plugin dependencies via APPBASE_PLUGIN_REQUIRES - - Registering an API factory during plugin startup - - Subscribing to chain events (e.g., applied_block) - -```mermaid -flowchart TD -Start(["Run newplugin.py provider name"]) --> CreateDirs["Create plugin directory under libraries/plugins/name"] -CreateDirs --> WriteCMake["Write CMakeLists.txt"] -CreateDirs --> WriteHeaders["Write plugin and API headers"] -CreateDirs --> WriteSources["Write plugin and API sources"] -WriteCMake --> Done(["Done"]) -WriteHeaders --> Done -WriteSources --> Done -``` - -**Diagram sources** -- [newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) - -**Section sources** -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) - -### Practical Plugin Development Workflow -- Use the template generator to scaffold a new plugin. -- Implement plugin lifecycle methods and register API factories. -- Declare dependencies using APPBASE_PLUGIN_REQUIRES. -- Subscribe to chain signals or database events as needed. -- Integrate the plugin into the application's registration and initialization steps. - -```mermaid -flowchart TD -A["Generate plugin with newplugin.py"] --> B["Implement plugin.cpp"] -B --> C["Add API methods in plugin.hpp"] -C --> D["Register plugin in vizd main.cpp"] -D --> E["Initialize and startup via appbase"] -E --> F["Expose APIs and react to chain events"] -``` - -**Diagram sources** -- [newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.cpp:316-396](file://plugins/chain/plugin.cpp#L316-L396) - -**Section sources** -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.cpp:316-396](file://plugins/chain/plugin.cpp#L316-L396) - -## Enhanced Lifecycle Management - -### Improved Shutdown Procedures -The enhanced plugin lifecycle management includes comprehensive shutdown procedures designed to prevent memory leaks and ensure proper resource cleanup: - -- **Chain Plugin Shutdown**: The chain plugin implements proper database closure in plugin_shutdown(), ensuring all database connections are properly closed. -- **Webserver Plugin Cleanup**: The webserver plugin implements thorough cleanup of HTTP and WebSocket servers, thread pools, and connection handlers. -- **P2P Plugin Graceful Shutdown**: The P2P plugin ensures proper network node closure, connection termination, and thread cleanup. -- **Snapshot Plugin Shutdown**: The snapshot plugin properly stops TCP servers, cancels async operations, and cleans up file handles. - -```mermaid -sequenceDiagram -participant App as "Application" -participant Chain as "Chain Plugin" -participant Snapshot as "Snapshot Plugin" -participant WS as "Webserver Plugin" -participant P2P as "P2P Plugin" -App->>Chain : plugin_shutdown() -Chain->>Chain : db.close() -App->>Snapshot : plugin_shutdown() -Snapshot->>Snapshot : stop_server() -Snapshot->>Snapshot : cancel_async_ops() -App->>WS : plugin_shutdown() -WS->>WS : stop_webserver() -WS->>WS : thread_pool.join_all() -WS->>WS : connections.cleanup() -App->>P2P : plugin_shutdown() -P2P->>P2P : node.close() -P2P->>P2P : p2p_thread.quit() -P2P->>P2P : node.reset() -``` - -**Diagram sources** -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [webserver_plugin.cpp:167-190](file://plugins/webserver/webserver_plugin.cpp#L167-L190) -- [p2p_plugin.cpp:568-573](file://plugins/p2p/p2p_plugin.cpp#L568-L573) -- [snapshot_plugin.cpp:1956-1959](file://plugins/snapshot/plugin.cpp#L1956-L1959) - -**Section sources** -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [webserver_plugin.cpp:167-190](file://plugins/webserver/webserver_plugin.cpp#L167-L190) -- [p2p_plugin.cpp:568-573](file://plugins/p2p/p2p_plugin.cpp#L568-L573) -- [snapshot_plugin.cpp:1956-1959](file://plugins/snapshot/plugin.cpp#L1956-L1959) - -### Signal Handler Coordination -The enhanced architecture includes sophisticated signal handler coordination mechanisms for graceful shutdown and resource cleanup: - -- **Signal Guard Implementation**: The database layer implements a signal_guard class that manages signal handlers for SIGHUP, SIGINT, and SIGTERM. -- **Interrupt Detection**: Signal handlers set interrupt flags that can be checked during long-running operations like blockchain reindexing. -- **Graceful Termination**: Operations check for interruption signals and terminate gracefully when detected. - -```mermaid -flowchart TD -A["Signal Received"] --> B["signal_guard.setup()"] -B --> C["Install signal handlers"] -C --> D["Set is_interrupted = true"] -D --> E["Operations check get_is_interrupted()"] -E --> F{"Interrupted?"} -F --> |Yes| G["Cancel operations"] -F --> |No| H["Continue normally"] -G --> I["Cleanup resources"] -H --> J["Complete operation"] -``` - -**Diagram sources** -- [database.cpp:134-180](file://libraries/chain/database.cpp#L134-L180) -- [database.cpp:270-329](file://libraries/chain/database.cpp#L270-L329) - -**Section sources** -- [database.cpp:134-180](file://libraries/chain/database.cpp#L134-L180) -- [database.cpp:270-329](file://libraries/chain/database.cpp#L270-L329) - -### Memory Leak Prevention -The enhanced lifecycle management includes several mechanisms to prevent memory leaks during plugin operations: - -- **Connection Cleanup**: Webserver plugin properly cleans up WebSocket and HTTP connections, ensuring no lingering references. -- **Thread Pool Management**: Proper thread pool shutdown with join_all() prevents thread leaks. -- **Network Node Cleanup**: P2P plugin ensures complete network node shutdown with proper resource deallocation. -- **Scoped Connections**: Plugins use scoped_connection objects that automatically disconnect when going out of scope. -- **Snapshot Resource Management**: Snapshot plugin implements proper cleanup of TCP sockets, file handles, and async operations. - -**Section sources** -- [webserver_plugin.cpp:167-190](file://plugins/webserver/webserver_plugin.cpp#L167-L190) -- [p2p_plugin.cpp:568-573](file://plugins/p2p/p2p_plugin.cpp#L568-L573) -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [snapshot_plugin.cpp:1427-1436](file://plugins/snapshot/plugin.cpp#L1427-L1436) - -## Snapshot Plugin System - -### Overview -The snapshot plugin provides comprehensive DLT (Distributed Ledger Technology) state management capabilities for VIZ blockchain nodes. It enables efficient state synchronization through automatic snapshot creation, loading from existing snapshots, and P2P synchronization between nodes using a custom TCP protocol. The enhanced version includes robust session management with RAII-based race condition prevention and sophisticated retry logic for reliable connection establishment. - -### Key Features -- **Automatic Snapshot Creation**: Creates snapshots at specific block heights or periodically -- **State Loading**: Loads blockchain state from snapshot files instead of replaying blocks -- **P2P Synchronization**: Downloads snapshots from trusted peers for rapid node bootstrap -- **Custom TCP Protocol**: Implements a binary protocol for efficient snapshot distribution -- **Anti-Spam Protection**: Built-in rate limiting and connection management -- **Security Controls**: Trust model with optional trusted-only serving -- **Enhanced Session Management**: RAII-based session guards prevent race conditions -- **Robust Connection Handling**: Retry logic addresses timing issues in P2P communication - -### Snapshot Formats and Storage -The snapshot plugin supports two file formats: -- **.vizjson**: Compressed JSON format with zlib compression -- **.json**: Plain JSON format for debugging and compatibility - -Snapshots are stored with naming convention: `snapshot-block-{block_number}.{extension}` - -**Section sources** -- [snapshot_plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) -- [snapshot_types.hpp:16-43](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp#L16-L43) -- [snapshot-plugin.md:1-164](file://documentation/snapshot-plugin.md#L1-L164) - -## Custom Network Protocol - -### Protocol Design -The snapshot plugin implements a custom binary protocol over TCP for efficient state synchronization: - -#### Wire Format -``` -[4 bytes: payload_size][4 bytes: msg_type][payload_bytes] -``` - -#### Message Types -| Type | Name | Description | -|------|------|-------------| -| 1 | `SNAPSHOT_INFO_REQUEST` | Empty payload. "What's your latest snapshot?" | -| 2 | `SNAPSHOT_INFO_REPLY` | `{block_num, block_id, checksum, compressed_size}` | -| 3 | `SNAPSHOT_DATA_REQUEST` | `{block_num, offset, chunk_size}` | -| 4 | `SNAPSHOT_DATA_REPLY` | `{offset, data_bytes, is_last}` | -| 5 | `SNAPSHOT_NOT_AVAILABLE` | No snapshot available | - -### Protocol Flow -1. **Info Request**: Client sends `SNAPSHOT_INFO_REQUEST` -2. **Info Reply**: Server responds with snapshot metadata -3. **Data Requests**: Client requests snapshot in chunks -4. **Data Replies**: Server streams snapshot data -5. **Verification**: Client verifies checksum before accepting - -```mermaid -sequenceDiagram -participant Client as "Client Node" -participant Server as "Server Node" -Client->>Server : SNAPSHOT_INFO_REQUEST -Server->>Client : SNAPSHOT_INFO_REPLY {block_num, checksum, size} -Client->>Server : SNAPSHOT_DATA_REQUEST {offset, chunk_size} -Server->>Client : SNAPSHOT_DATA_REPLY {data, is_last} -loop Multiple Chunks -Client->>Server : SNAPSHOT_DATA_REQUEST {offset, chunk_size} -Server->>Client : SNAPSHOT_DATA_REPLY {data, is_last} -end -Client->>Client : Verify Checksum -Client->>Client : Load Snapshot State -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1249-1317](file://plugins/snapshot/plugin.cpp#L1249-L1317) -- [snapshot_plugin.cpp:1546-1617](file://plugins/snapshot/plugin.cpp#L1546-L1617) - -**Section sources** -- [snapshot_plugin.cpp:1249-1317](file://plugins/snapshot/plugin.cpp#L1249-L1317) -- [snapshot_plugin.cpp:1546-1617](file://plugins/snapshot/plugin.cpp#L1546-L1617) -- [snapshot-plugin.md:104-120](file://documentation/snapshot-plugin.md#L104-L120) - -## Anti-Spam Protection - -### Connection Management -The snapshot TCP server implements comprehensive anti-spam protection: - -#### Active Session Control -- **Single Active Session Per IP**: Prevents multiple concurrent downloads from the same IP -- **Connection Tracking**: Monitors active connections to enforce limits - -#### Rate Limiting -- **3 Connections Per Hour Per IP**: Prevents abuse through repeated connection attempts -- **Time Window Management**: Automatic cleanup of expired connection records -- **Dynamic Rate Adjustment**: Prevents unbounded memory growth in connection history - -#### Security Enforcement -- **Trusted Peer Bypass**: Anti-spam rules apply equally to all connections -- **Trust Model**: Separate from anti-spam enforcement for fairness -- **Connection Timeout**: 60-second timeout for idle connections - -```mermaid -flowchart TD -A["Incoming Connection"] --> B{"Trusted Only Mode?"} -B --> |Yes| C{"IP in Trusted List?"} -B --> |No| D["Accept Connection"] -C --> |Yes| E["Check Anti-Spam"] -C --> |No| F["Reject Connection"] -E --> G{"Max Concurrent Connections?"} -G --> |Yes| H["Reject - Too Many Active Sessions"] -G --> |No| I{"Rate Limit Exceeded?"} -I --> |Yes| J["Reject - Rate Limited"] -I --> |No| K["Accept Connection"] -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1438-1544](file://plugins/snapshot/plugin.cpp#L1438-L1544) - -**Section sources** -- [snapshot_plugin.cpp:1438-1544](file://plugins/snapshot/plugin.cpp#L1438-L1544) -- [snapshot-plugin.md:96-103](file://documentation/snapshot-plugin.md#L96-L103) - -## Session Guard Implementation - -### RAII Session Guard Design -The snapshot plugin implements a sophisticated RAII session guard to prevent race conditions in connection handling: - -#### Session Guard Class -The `session_guard` class provides automatic cleanup of active session records: - -```cpp -struct session_guard { - snapshot_plugin::plugin_impl& self; - uint32_t ip; - bool released = false; - session_guard(snapshot_plugin::plugin_impl& s, uint32_t i) : self(s), ip(i) {} - ~session_guard() { release(); } - void release() { - if (!released) { - released = true; - fc::scoped_lock lock(self.sessions_mutex); - self.active_sessions.erase(ip); - } - } -} guard(*this, remote_ip); -``` - -#### Race Condition Prevention -- **Eager Cleanup**: Session is removed from `active_sessions` immediately when the guard goes out of scope -- **Prevents Duplicate Connections**: Ensures no race condition where a client reconnects before async fiber cleanup -- **Thread Safety**: Uses mutex protection for session management operations - -#### Integration with Connection Handling -The session guard is integrated into the `handle_connection` method: - -```mermaid -flowchart TD -A["handle_connection Called"] --> B["Create session_guard"] -B --> C["Process Connection Requests"] -C --> D{"Function Returns?"} -D --> |Yes| E["Guard destructor called"] -E --> F["Remove from active_sessions"] -F --> G["Cleanup Complete"] -D --> |No Exception| H["Guard destructor called"] -H --> F -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1800-1820](file://plugins/snapshot/plugin.cpp#L1800-L1820) -- [snapshot_plugin.cpp:1780-1788](file://plugins/snapshot/plugin.cpp#L1780-L1788) - -**Section sources** -- [snapshot_plugin.cpp:1800-1820](file://plugins/snapshot/plugin.cpp#L1800-L1820) -- [snapshot_plugin.cpp:1780-1788](file://plugins/snapshot/plugin.cpp#L1780-L1788) - -## Enhanced Retry Logic - -### Client-Side Connection Retry Mechanism -The snapshot plugin implements sophisticated retry logic to address race conditions in P2P communication: - -#### Retry Strategy -- **Maximum 3 Retries**: Limits retry attempts to prevent infinite loops -- **2-Second Delays**: Allows time for server-side session cleanup -- **Exponential Backoff**: Gradual retry delays improve success probability -- **Resource Cleanup**: Proper cleanup between retry attempts - -#### Retry Implementation -The retry logic addresses timing issues where server-side cleanup may not complete: - -```mermaid -flowchart TD -A["Connect Attempt"] --> B{"Connection Success?"} -B --> |Yes| C["Connected Successfully"] -B --> |No| D{"Retry Attempts Left?"} -D --> |Yes| E["Close Socket"] -E --> F["Wait 2 Seconds"] -F --> G["Create New Socket"] -G --> A -D --> |No| H["Throw Exception"] -``` - -#### Specific Use Cases -- **Phase 1 to Phase 2 Transition**: Brief delay allows server to clean up Phase 1 session -- **Anti-Spam Duplicate Session Check**: Addresses timing window where duplicate session detection triggers -- **Async Fiber Cleanup**: Allows time for background fiber to complete cleanup operations - -**Diagram sources** -- [snapshot_plugin.cpp:2047-2064](file://plugins/snapshot/plugin.cpp#L2047-L2064) -- [snapshot_plugin.cpp:2036-2039](file://plugins/snapshot/plugin.cpp#L2036-L2039) - -**Section sources** -- [snapshot_plugin.cpp:2047-2064](file://plugins/snapshot/plugin.cpp#L2047-L2064) -- [snapshot_plugin.cpp:2036-2039](file://plugins/snapshot/plugin.cpp#L2036-L2039) - -## Race Condition Prevention - -### Comprehensive Race Condition Mitigation -The enhanced snapshot plugin addresses multiple race conditions through layered protection mechanisms: - -#### Connection Race Conditions -- **Duplicate Session Prevention**: Session guard ensures no overlap between connection attempts -- **Anti-Spam Race**: Mutex-protected session tracking prevents concurrent access issues -- **Cleanup Timing**: Proper sequencing of cleanup operations prevents timing gaps - -#### Session Management Race Conditions -- **Active Session Tracking**: Thread-safe tracking prevents concurrent modifications -- **Connection Count Synchronization**: Atomic operations ensure accurate connection counts -- **Resource Deallocation**: Proper cleanup order prevents dangling references - -#### P2P Communication Race Conditions -- **Phase Transition Delays**: Controlled timing prevents race between phases -- **Retry Logic Coordination**: Synchronized retry attempts with server cleanup -- **Timeout Management**: Coordinated timeouts prevent deadlocks - -```mermaid -sequenceDiagram -participant Client as "Client" -participant Server as "Server" -Client->>Server : Phase 1 Connection -Server->>Server : Session Created -Client->>Server : Close Phase 1 -Server->>Server : Async Cleanup Started -Client->>Server : Phase 2 Connection (Retry) -Note over Server : Session Guard prevents duplicate -Server->>Server : Cleanup Completes -Server->>Client : Connection Established -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1720-1761](file://plugins/snapshot/plugin.cpp#L1720-L1761) -- [snapshot_plugin.cpp:1804-1820](file://plugins/snapshot/plugin.cpp#L1804-L1820) - -**Section sources** -- [snapshot_plugin.cpp:1720-1761](file://plugins/snapshot/plugin.cpp#L1720-L1761) -- [snapshot_plugin.cpp:1804-1820](file://plugins/snapshot/plugin.cpp#L1804-L1820) - -## Integration with Chain Plugin - -### Callback System -The snapshot plugin integrates with the chain plugin through a sophisticated callback system that coordinates state management during node startup: - -#### Available Callbacks -1. **snapshot_load_callback**: Loads state from snapshot file -2. **snapshot_create_callback**: Creates snapshot after full database load -3. **snapshot_p2p_sync_callback**: Downloads and loads snapshot from trusted peers - -#### Execution Timing -- **snapshot_load_callback**: Executed BEFORE `on_sync()` fires -- **snapshot_create_callback**: Executed AFTER full DB load, BEFORE `on_sync()` -- **snapshot_p2p_sync_callback**: Executed when state is empty, BEFORE `on_sync()` - -```mermaid -sequenceDiagram -participant Chain as "Chain Plugin" -participant Snapshot as "Snapshot Plugin" -Chain->>Chain : Initialize Plugins -Chain->>Snapshot : Set snapshot_load_callback -Chain->>Snapshot : Set snapshot_create_callback -Chain->>Snapshot : Set snapshot_p2p_sync_callback -Chain->>Chain : Load Database State -alt State Exists -Chain->>Chain : Start Normal Operation -else Empty State -alt P2P Sync Enabled -Chain->>Snapshot : Call snapshot_p2p_sync_callback -Snapshot->>Snapshot : Download Snapshot -Snapshot->>Chain : Load Snapshot State -else Create Snapshot -Chain->>Snapshot : Call snapshot_create_callback -Snapshot->>Snapshot : Create Snapshot -end -end -Chain->>Chain : Fire on_sync() -Chain->>Chain : Start P2P/validator -``` - -**Diagram sources** -- [snapshot_plugin.cpp:1872-1919](file://plugins/snapshot/plugin.cpp#L1872-L1919) -- [snapshot_plugin.hpp:92-105](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L92-L105) - -**Section sources** -- [snapshot_plugin.cpp:1872-1919](file://plugins/snapshot/plugin.cpp#L1872-L1919) -- [snapshot_plugin.hpp:92-105](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L92-L105) - -### Configuration Options -The snapshot plugin provides extensive configuration options for different deployment scenarios: - -#### Basic Configuration -- `snapshot-at-block`: Create snapshot at specific block number -- `snapshot-every-n-blocks`: Automatic periodic snapshots -- `snapshot-dir`: Directory for auto-generated snapshots -- `snapshot-max-age-days`: Age-based snapshot cleanup - -#### P2P Synchronization -- `allow-snapshot-serving`: Enable TCP snapshot serving -- `allow-snapshot-serving-only-trusted`: Restrict to trusted peers -- `snapshot-serve-endpoint`: TCP listen endpoint -- `trusted-snapshot-peer`: Trusted peer endpoints (repeatable) - -#### CLI Options -- `--snapshot `: Load state from snapshot file -- `--create-snapshot `: Create snapshot and exit -- `--sync-snapshot-from-trusted-peer true`: Download snapshot on empty state - -**Section sources** -- [snapshot_plugin.cpp:1767-1797](file://plugins/snapshot/plugin.cpp#L1767-L1797) -- [snapshot-plugin.md:142-164](file://documentation/snapshot-plugin.md#L142-L164) - -## Dependency Analysis -- Plugin discovery: The plugins/CMakeLists.txt iterates subdirectories and adds those with a CMakeLists.txt, enabling automatic inclusion of internal plugins. -- Plugin dependencies: - - chain::plugin is required by p2p, database_api, account_history, follow, and **snapshot**. - - json_rpc::plugin is required by webserver, database_api, and follow. - - account_history additionally requires operation_history internally. - - **snapshot::plugin requires chain::plugin for database access**. - -```mermaid -graph LR -CHAIN["chain::plugin"] --> P2P["p2p::plugin"] -CHAIN --> DBAPI["database_api::plugin"] -CHAIN --> AH["account_history::plugin"] -CHAIN --> FOLLOW["follow::plugin"] -CHAIN --> SNAPSHOT["snapshot::plugin"] -JSONRPC["json_rpc::plugin"] --> WS["webserver::plugin"] -JSONRPC --> DBAPI -JSONRPC --> FOLLOW -SNAPSHOT --> CHAIN -``` - -**Diagram sources** -- [p2p_plugin.cpp:531-566](file://plugins/p2p/p2p_plugin.cpp#L531-L566) -- [plugin.hpp:188-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [plugin.hpp:28-31](file://plugins/follow/include/graphene/plugins/follow/plugin.hpp#L28-L31) -- [webserver_plugin.cpp:314-327](file://plugins/webserver/webserver_plugin.cpp#L314-L327) -- [snapshot_plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L44) - -**Section sources** -- [CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [p2p_plugin.cpp:531-566](file://plugins/p2p/p2p_plugin.cpp#L531-L566) -- [plugin.hpp:188-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [plugin.hpp:28-31](file://plugins/follow/include/graphene/plugins/follow/plugin.hpp#L28-L31) -- [webserver_plugin.cpp:314-327](file://plugins/webserver/webserver_plugin.cpp#L314-L327) -- [snapshot_plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L44) - -## Performance Considerations -- Single write thread: The chain plugin supports a single-write-thread mode to serialize block/transaction application, which can simplify locking but may reduce throughput. -- Shared memory sizing: Configurable shared memory size and increments help manage storage growth during replay or sync. -- Skipping virtual operations: Option to skip virtual operations reduces memory overhead for plugins not requiring them. -- Flush intervals: Periodic flushing of state to disk can be tuned for durability vs. performance trade-offs. -- **Snapshot compression**: Zlib compression reduces snapshot file sizes by 50-70% compared to uncompressed JSON. -- **Chunked transfers**: 1MB chunk size balances memory usage and network efficiency. -- **Connection limits**: Maximum 5 concurrent connections prevents resource exhaustion. -- **Anti-spam controls**: Prevents abuse while maintaining reasonable throughput. -- **Session guard overhead**: Minimal performance impact with significant race condition prevention benefits. -- **Retry logic efficiency**: Controlled retries with exponential backoff optimize connection success rates. - -**Section sources** -- [plugin.cpp:281-346](file://plugins/chain/plugin.cpp#L281-L346) -- [plugin.cpp:300-304](file://plugins/chain/plugin.cpp#L300-L304) -- [snapshot_plugin.cpp:1694-1700](file://plugins/snapshot/plugin.cpp#L1694-L1700) -- [snapshot-plugin.md:96-103](file://documentation/snapshot-plugin.md#L96-L103) - -## Troubleshooting Guide -- Database errors on startup: The chain plugin catches database revision and block log exceptions, optionally triggering a replay or wipe and resync path. -- Logging configuration: The application loads logging configuration from the config file and applies appenders/loggers accordingly. -- Graceful shutdown: Plugins should release connections and close databases in plugin_shutdown with proper cleanup procedures. -- Signal handling: The enhanced signal handling system provides better control over shutdown procedures and resource cleanup. -- **Snapshot issues**: - - Verify snapshot file integrity using checksum verification - - Check snapshot directory permissions for read/write access - - Monitor TCP server logs for connection errors - - Validate trusted peer configurations for P2P sync - - **Check session guard logs for race condition prevention** - - **Monitor retry attempts for connection establishment issues** -- **Performance issues**: - - Monitor snapshot creation time and adjust chunk sizes - - Check network bandwidth for P2P synchronization - - Verify anti-spam configuration isn't blocking legitimate connections - - **Review session guard effectiveness in preventing race conditions** - -```mermaid -flowchart TD -Start(["Startup"]) --> OpenDB["Open chain database"] -OpenDB --> DBErr{"Exception?"} -DBErr --> |Yes| ReplayOpt{"Replay-if-corrupted?"} -ReplayOpt --> |Yes| Replay["Replay or Wipe + Reindex"] -ReplayOpt --> |No| Quit["Exit gracefully"] -DBErr --> |No| Ready["on_sync and continue"] -Ready --> SnapshotCheck{"Snapshot Configured?"} -SnapshotCheck --> |Yes| SnapshotOp{"Load/Create/P2P Sync"} -SnapshotCheck --> |No| Normal["Normal Operation"] -SnapshotOp --> SnapshotOK{"Snapshot Success?"} -SnapshotOK --> |Yes| Ready -SnapshotOK --> |No| Error["Log Error and Continue"] -Error --> Normal -Shutdown(["Shutdown Requested"]) --> SignalCheck{"Signal Detected?"} -SignalCheck --> |Yes| InterruptOps["Check operations for interruption"] -InterruptOps --> Cleanup["Cleanup resources properly"] -SignalCheck --> |No| NormalShutdown["Normal shutdown procedure"] -Cleanup --> Finalize["Finalize shutdown"] -NormalShutdown --> Finalize -``` - -**Diagram sources** -- [plugin.cpp:348-386](file://plugins/chain/plugin.cpp#L348-L386) -- [database.cpp:270-329](file://libraries/chain/database.cpp#L270-L329) -- [snapshot_plugin.cpp:1872-1919](file://plugins/snapshot/plugin.cpp#L1872-L1919) - -**Section sources** -- [plugin.cpp:348-386](file://plugins/chain/plugin.cpp#L348-L386) -- [main.cpp:131-137](file://programs/vizd/main.cpp#L131-L137) -- [database.cpp:270-329](file://libraries/chain/database.cpp#L270-L329) -- [snapshot_plugin.cpp:1872-1919](file://plugins/snapshot/plugin.cpp#L1872-L1919) - -## Conclusion -The enhanced plugin architecture leverages appbase to provide a clean separation of concerns with improved lifecycle management, enabling flexible feature addition and removal. Plugins declare dependencies, participate in a standardized lifecycle with proper shutdown procedures, and communicate via signals and API factories. The enhanced shutdown mechanisms, signal handler coordination, and memory leak prevention ensure robust, maintainable extensions to the node. - -**The new snapshot plugin system significantly enhances the architecture by providing:** -- Efficient DLT state management through automatic snapshot creation and loading -- Custom TCP protocol for optimized P2P synchronization -- Comprehensive anti-spam protection and security controls -- Seamless integration with the chain plugin through specialized callbacks -- **Robust session management with RAII-based race condition prevention** -- **Sophisticated retry logic addressing P2P communication timing issues** -- **Layered protection mechanisms preventing various race conditions** - -The template generator accelerates development while the chain plugin centralizes database access and synchronization events with proper resource cleanup. The enhanced snapshot plugin exemplifies best practices for extending node functionality with specialized protocols, robust error handling, comprehensive configuration options, and sophisticated concurrency control mechanisms. - -## Appendices -- Best practices for extending node functionality: - - Use APPBASE_PLUGIN_REQUIRES to declare explicit dependencies. - - Register API factories in plugin_startup and expose only necessary methods. - - Subscribe to chain signals (e.g., on_sync) to coordinate with other plugins. - - Implement proper plugin_shutdown methods for resource cleanup. - - Use scoped_connection objects for automatic disconnection. - - Handle signals appropriately using the signal_guard mechanism. - - Keep plugin responsibilities narrow and focused on specific domains. - - Use configuration options to tune performance and behavior. - - Ensure graceful shutdown procedures for all long-running operations. - - **For network plugins**: Implement proper connection management, anti-abuse controls, and race condition prevention. - - **For state management plugins**: Provide validation and recovery mechanisms with proper cleanup procedures. - - **For protocol plugins**: Design efficient wire formats, implement proper error handling, and consider concurrency implications. - - **For plugins with shared resources**: Implement RAII-based resource management to prevent race conditions. - - **For client-side plugins**: Implement retry logic with proper backoff strategies for reliable operation. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Lifecycle and Registration.md b/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Lifecycle and Registration.md deleted file mode 100644 index 2c3ab84a00..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/Plugin Architecture/Plugin Lifecycle and Registration.md +++ /dev/null @@ -1,445 +0,0 @@ -# Plugin Lifecycle and Registration - - -**Referenced Files in This Document** -- [main.cpp](file://programs/vizd/main.cpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [snapshot_plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp) -- [snapshot_plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [plugin.md](file://documentation/plugin.md) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) - - -## Update Summary -**Changes Made** -- Enhanced plugin initialization order requirements section to reflect new coordination mechanisms -- Added comprehensive coverage of snapshot plugin integration with chain plugin callbacks -- Updated deferred execution model documentation for snapshot loading and creation -- Expanded coordination between chain and snapshot plugins during startup -- Added detailed explanation of P2P snapshot sync callback mechanism -- Updated dependency analysis to include snapshot plugin requirements - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Plugin Initialization Order Requirements](#enhanced-plugin-initialization-order-requirements) -7. [Deferred Execution Model for Snapshot Loading](#deferred-execution-model-for-snapshot-loading) -8. [Coordination Between Chain and Snapshot Plugins](#coordination-between-chain-and-snapshot-plugins) -9. [Dependency Analysis](#dependency-analysis) -10. [Performance Considerations](#performance-considerations) -11. [Troubleshooting Guide](#troubleshooting-guide) -12. [Conclusion](#conclusion) - -## Introduction -This document explains the plugin lifecycle and registration mechanisms in the application built on the appbase framework. It covers the three phases of plugin execution: initialization, startup, and shutdown. It also documents how plugins register themselves with the application, how dependencies are declared via the APPBASE_PLUGIN_REQUIRES macro, and how the application framework determines plugin loading order. The document has been updated to reflect enhanced plugin initialization order requirements, improved coordination between chain and snapshot plugins, and the deferred execution model for snapshot loading. - -## Project Structure -The application binary registers and initializes plugins in the main entry point. Plugins are organized under plugins// with a standard plugin interface that extends appbase::plugin. Dependencies between plugins are declared using APPBASE_PLUGIN_REQUIRES in each plugin's header. The snapshot plugin introduces a sophisticated callback system that coordinates with the chain plugin for deferred execution of snapshot operations. - -```mermaid -graph TB -A["programs/vizd/main.cpp
Entry point"] --> B["appbase::application
register_plugin()"] -B --> C["plugins/*/include/*.hpp
APPBASE_PLUGIN_REQUIRES(...)"] -C --> D["plugins/*/plugin.cpp
plugin_* methods"] -D --> E["Chain Plugin
Callback Registration"] -E --> F["Snapshot Plugin
Deferred Execution"] -``` - -**Diagram sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.hpp:21-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [snapshot_plugin.hpp:55-89](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L89) - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.md:1-28](file://documentation/plugin.md#L1-L28) - -## Core Components -- Application entry point and plugin registration: - - The application registers all plugins in the main entry point and then initializes the appbase application with a specific set of plugins. - - The application sets program options, initializes, starts up, and executes the event loop. - -- Plugin interface and lifecycle: - - Plugins derive from appbase::plugin and implement: - - plugin_initialize(options): parse configuration and prepare resources. - - plugin_startup(): open databases, bind services, start threads, and signal readiness. - - plugin_shutdown(): close resources and shut down gracefully. - -- Enhanced dependency management: - - Plugins declare dependencies using APPBASE_PLUGIN_REQUIRES in their header. - - The chain plugin requires json_rpc; snapshot plugin requires chain; p2p requires chain; webserver requires json_rpc. - - The appbase framework resolves dependencies and ensures required plugins are initialized before dependents. - -- Deferred execution coordination: - - The chain plugin provides callback mechanisms for snapshot operations. - - Snapshot plugin registers callbacks during initialization that execute during chain plugin startup. - - This ensures proper sequencing of snapshot loading, creation, and P2P sync operations. - -**Section sources** -- [main.cpp:108-160](file://programs/vizd/main.cpp#L108-L160) -- [plugin.hpp:21-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [plugin.cpp:254-396](file://plugins/chain/plugin.cpp#L254-L396) -- [snapshot_plugin.hpp:55-89](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L89) - -## Architecture Overview -The application controls plugin lifecycle through appbase. Plugins are registered centrally, then initialized and started in dependency-aware order. The chain plugin typically initializes first because many plugins require it. The snapshot plugin introduces a callback-driven coordination mechanism that allows it to defer operations until the chain plugin is ready. - -```mermaid -sequenceDiagram -participant Main as "main.cpp" -participant App as "appbase : : application" -participant Chain as "chain : : plugin" -participant Snapshot as "snapshot : : snapshot_plugin" -participant P2P as "p2p : : p2p_plugin" -participant WS as "webserver : : webserver_plugin" -Main->>App : register_plugin(chain) -Main->>App : register_plugin(snapshot) -Main->>App : register_plugin(p2p) -Main->>App : register_plugin(webserver) -Main->>App : initialize(argc, argv) -App->>Chain : plugin_initialize(options) -App->>Snapshot : plugin_initialize(options) -App->>P2P : plugin_initialize(options) -App->>WS : plugin_initialize(options) -App->>Chain : plugin_startup() -Chain->>Snapshot : trigger_snapshot_load() -Chain->>Chain : on_sync() -App->>Snapshot : plugin_startup() -Snapshot->>Snapshot : start_server() -``` - -**Diagram sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [plugin.cpp:254-396](file://plugins/chain/plugin.cpp#L254-L396) -- [snapshot_plugin.cpp:3031-3093](file://plugins/snapshot/plugin.cpp#L3031-L3093) - -## Detailed Component Analysis - -### Plugin Registration in main.cpp -- Centralized registration: - - The application registers each plugin via appbase::app().register_plugin(). - - Registration occurs before initialize() so dependencies can be resolved. - -- Enhanced initialization invocation: - - After registration, initialize() is called with a variadic list of plugins to initialize. - - The application then calls startup() and enters the event loop via exec(). - -- Practical pattern: - - Keep registration in one place (register_plugins()) and pass the same set to initialize(). - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [main.cpp:117-122](file://programs/vizd/main.cpp#L117-L122) -- [main.cpp:139-140](file://programs/vizd/main.cpp#L139-L140) - -### Plugin Lifecycle Phases - -#### plugin_initialize -- Purpose: - - Parse configuration options and prepare internal state. - - Set up paths, sizes, and flags required for later operations. - -- Enhanced behavior with snapshot coordination: - - The chain plugin prepares callback registration points for snapshot operations. - - The snapshot plugin registers callback functions that will execute during chain plugin startup. - - Dependencies are declared using APPBASE_PLUGIN_REQUIRES with enhanced coordination requirements. - -- Error handling: - - Exceptions during initialization should be allowed to propagate so the application can handle them gracefully. - -**Section sources** -- [plugin.cpp:254-314](file://plugins/chain/plugin.cpp#L254-L314) -- [snapshot_plugin.cpp:2821-2977](file://plugins/snapshot/plugin.cpp#L2821-L2977) - -#### plugin_startup -- Purpose: - - Open databases, bind services, start threads, and publish readiness signals. - - Perform actions that require dependencies to be ready. - -- Enhanced startup with deferred execution: - - The chain plugin triggers snapshot loading through registered callbacks. - - The snapshot plugin starts its TCP server and begins accepting connections. - - P2P snapshot sync callback is executed when state is empty and snapshot is available. - -- Startup timing: - - Occurs after plugin_initialize for all plugins and after all dependencies are initialized. - -**Section sources** -- [plugin.cpp:316-390](file://plugins/chain/plugin.cpp#L316-L390) -- [snapshot_plugin.cpp:3031-3093](file://plugins/snapshot/plugin.cpp#L3031-L3093) - -#### plugin_shutdown -- Purpose: - - Close databases, stop threads, and release resources. - - Ensure clean termination. - -- Enhanced shutdown coordination: - - The chain plugin ensures proper shutdown sequence. - - The snapshot plugin stops stalled sync detection and TCP server gracefully. - -**Section sources** -- [plugin.cpp:392-396](file://plugins/chain/plugin.cpp#L392-L396) -- [snapshot_plugin.cpp:3095-3100](file://plugins/snapshot/plugin.cpp#L3095-L3100) - -### Enhanced Plugin Initialization Order Requirements - -#### Dependency Resolution with Coordination -- Declaration: - - Plugins declare dependencies in their header using APPBASE_PLUGIN_REQUIRES((dep1)(dep2)...). - - The chain plugin requires json_rpc; snapshot plugin requires chain; p2p requires chain; webserver requires json_rpc. - -- Enhanced resolution: - - The appbase framework ensures dependencies are initialized before the dependent plugin. - - The chain plugin provides callback registration points that allow dependent plugins to coordinate operations. - - The snapshot plugin registers callbacks during initialization that execute during chain plugin startup. - -- Example declarations: - - chain plugin declares json_rpc as a requirement. - - snapshot plugin declares chain as a requirement. - - p2p plugin declares chain as a requirement. - - webserver plugin declares json_rpc as a requirement. - -**Section sources** -- [plugin.hpp:21-34](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L34) -- [snapshot_plugin.hpp:55-57](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L57) -- [p2p_plugin.hpp:18-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L20) -- [webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) - -### Plugin Naming Conventions and Static name() Method -- Naming convention: - - Plugins define a constant or macro for their name (e.g., P2P_PLUGIN_NAME, WEBSERVER_PLUGIN_NAME). - - The static name() method returns the plugin's string identifier. - -- Implementation pattern: - - A static std::string is constructed once and returned by name(). - - This enables consistent identification and logging. - -**Section sources** -- [p2p_plugin.hpp:29-32](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L29-L32) -- [webserver_plugin.hpp:40-43](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L40-L43) - -### Plugin Registration Patterns and Loading Order -- Registration pattern: - - Call appbase::app().register_plugin() for each plugin. - - Pass the same set of plugins to initialize(). - -- Enhanced loading order: - - The appbase framework resolves dependencies first, then initializes others in the order provided to initialize<...>(). - - The chain plugin typically initializes first, followed by snapshot plugin, then dependent plugins like p2p and webserver. - - Callback registration ensures proper sequencing of operations across plugin boundaries. - -- Practical example: - - The application registers chain, snapshot, p2p, and webserver, then initializes them in that order with enhanced coordination. - -**Section sources** -- [main.cpp:62-90](file://programs/vizd/main.cpp#L62-L90) -- [main.cpp:117-122](file://programs/vizd/main.cpp#L117-L122) - -### Error Handling During Initialization and Graceful Shutdown -- Initialization errors: - - The chain plugin catches database-related exceptions during startup and either replays or exits depending on configuration. - - The snapshot plugin handles various error scenarios including peer connection failures and snapshot validation errors. - - Other plugins should throw or log errors during plugin_initialize to prevent startup. - -- Enhanced graceful shutdown: - - The chain plugin closes the database in plugin_shutdown. - - The snapshot plugin stops stalled sync detection and TCP server gracefully. - - Other plugins should stop threads and release resources in plugin_shutdown. - -**Section sources** -- [plugin.cpp:348-396](file://plugins/chain/plugin.cpp#L348-L396) -- [snapshot_plugin.cpp:3095-3100](file://plugins/snapshot/plugin.cpp#L3095-L3100) - -## Enhanced Plugin Initialization Order Requirements - -### Advanced Dependency Coordination -The enhanced plugin initialization order requirements ensure proper sequencing of operations across plugin boundaries, particularly for the snapshot plugin's coordination with the chain plugin. - -```mermaid -graph LR -JSON["json_rpc::plugin"] --> CHAIN["chain::plugin"] -CHAIN --> SNAPSHOT["snapshot::snapshot_plugin"] -CHAIN --> P2P["p2p::p2p_plugin"] -JSON --> WS["webserver::webserver_plugin"] -SNAPSHOT -.-> CHAIN -P2P --> CHAIN -WS --> JSON -``` - -**Diagram sources** -- [plugin.hpp:21-23](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L23) -- [snapshot_plugin.hpp:55-57](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L57) -- [p2p_plugin.hpp:18-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L20) -- [webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) - -**Section sources** -- [plugin.hpp:21-34](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L34) -- [snapshot_plugin.hpp:55-57](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L57) -- [p2p_plugin.hpp:18-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L20) -- [webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) - -## Deferred Execution Model for Snapshot Loading - -### Snapshot Operation Coordination -The snapshot plugin implements a sophisticated deferred execution model that coordinates with the chain plugin through callback mechanisms. - -```mermaid -sequenceDiagram -participant Chain as "Chain Plugin" -participant Snapshot as "Snapshot Plugin" -participant DB as "Database" -Chain->>Chain : plugin_initialize() -Chain->>Chain : prepare_callbacks() -Snapshot->>Snapshot : plugin_initialize() -Snapshot->>Chain : register_callbacks() -Snapshot->>Snapshot : parse_config() -Snapshot->>Snapshot : setup_callbacks() -Chain->>Chain : plugin_startup() -Chain->>Snapshot : trigger_snapshot_load() -Snapshot->>DB : load_snapshot() -DB-->>Snapshot : snapshot_loaded -Snapshot->>DB : initialize_hardforks() -Chain->>Chain : on_sync() -Chain->>Chain : plugin_startup() -Chain->>Snapshot : check_state() -alt State empty -Chain->>Snapshot : snapshot_p2p_sync_callback() -Snapshot->>Snapshot : download_snapshot_from_peers() -Snapshot->>DB : load_snapshot() -Snapshot->>DB : set_dlt_mode() -Snapshot->>DB : initialize_hardforks() -else State not empty -Chain->>Chain : normal_startup() -end -``` - -**Diagram sources** -- [snapshot_plugin.cpp:2947-3028](file://plugins/snapshot/plugin.cpp#L2947-L3028) -- [plugin.cpp:437-532](file://plugins/chain/plugin.cpp#L437-L532) - -### Deferred Execution Mechanisms -The deferred execution model ensures that snapshot operations occur at the appropriate time in the plugin lifecycle: - -- **Snapshot Loading**: Executed during chain plugin startup, before on_sync() fires, ensuring P2P sync starts from the snapshot head block. -- **Snapshot Creation**: Executed after full database load (including replay), but before on_sync(), preventing P2P/validator startup. -- **P2P Snapshot Sync**: Executed when state is empty (head_block_num == 0), before on_sync(), enabling bootstrap from trusted peers. - -**Section sources** -- [snapshot_plugin.cpp:2947-3028](file://plugins/snapshot/plugin.cpp#L2947-L3028) -- [plugin.cpp:437-532](file://plugins/chain/plugin.cpp#L437-L532) - -## Coordination Between Chain and Snapshot Plugins - -### Callback Registration System -The chain plugin provides a callback registration system that enables the snapshot plugin to coordinate operations at specific points in the chain plugin's lifecycle. - -```mermaid -graph TD -A["Chain Plugin
plugin_initialize()"] --> B["Register Callback Points"] -B --> C["snapshot_load_callback"] -B --> D["snapshot_create_callback"] -B --> E["snapshot_p2p_sync_callback"] -F["Snapshot Plugin
plugin_initialize()"] --> G["Register Callback Functions"] -G --> H["load_snapshot()"] -G --> I["create_snapshot()"] -G --> J["download_snapshot_from_peers()"] -K["Chain Plugin
plugin_startup()"] --> L["Execute Registered Callbacks"] -L --> M["trigger_snapshot_load()"] -L --> N["Check State for P2P Sync"] -N --> O["snapshot_p2p_sync_callback()"] -``` - -**Diagram sources** -- [plugin.hpp:97-110](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L97-L110) -- [snapshot_plugin.cpp:2947-3028](file://plugins/snapshot/plugin.cpp#L2947-L3028) - -### Enhanced Coordination Features -The coordination between chain and snapshot plugins includes several advanced features: - -- **Trigger Mechanism**: The chain plugin provides `trigger_snapshot_load()` to activate deferred snapshot loading when the snapshot plugin is ready. -- **State Awareness**: The chain plugin checks if state is empty (head_block_num == 0) before executing P2P snapshot sync. -- **Execution Timing**: Callbacks execute at precisely defined points in the plugin lifecycle to ensure proper sequencing. -- **Error Handling**: Comprehensive error handling for snapshot operations including peer connection failures and validation errors. - -**Section sources** -- [plugin.hpp:52-55](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L52-L55) -- [snapshot_plugin.cpp:3031-3093](file://plugins/snapshot/plugin.cpp#L3031-L3093) - -## Dependency Analysis -This section maps plugin dependencies and their impact on initialization order, with enhanced focus on the coordination between chain and snapshot plugins. - -```mermaid -graph LR -JSON["json_rpc::plugin"] --> CHAIN["chain::plugin"] -CHAIN --> SNAPSHOT["snapshot::snapshot_plugin"] -CHAIN --> P2P["p2p::p2p_plugin"] -JSON --> WS["webserver::webserver_plugin"] -SNAPSHOT -.-> CHAIN -P2P --> CHAIN -WS --> JSON -subgraph "Enhanced Coordination" -CHAIN -.-> SNAPSHOT -SNAPSHOT -.-> CHAIN -end -``` - -**Diagram sources** -- [plugin.hpp:21-23](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L23) -- [snapshot_plugin.hpp:55-57](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L57) -- [p2p_plugin.hpp:18-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L20) -- [webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) - -**Section sources** -- [plugin.hpp:21-34](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L34) -- [snapshot_plugin.hpp:55-57](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L55-L57) -- [p2p_plugin.hpp:18-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L20) -- [webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) - -## Performance Considerations -- Minimize heavy work in plugin_initialize; defer expensive operations to plugin_startup. -- Use asynchronous I/O and dedicated threads where appropriate (e.g., webserver runs in its own thread). -- Configure shared memory and flush intervals thoughtfully to balance safety and performance. -- The snapshot plugin's deferred execution model prevents blocking operations during critical startup phases. -- Anti-spam protections in the snapshot TCP server prevent resource exhaustion during high-load scenarios. - -## Troubleshooting Guide -- Plugin fails to start due to missing dependency: - - Ensure the required plugin is registered and appears before the dependent plugin in the initialize<> list or rely on the framework to resolve dependencies. - - Verify that callback registration occurs before the chain plugin attempts to trigger snapshot operations. - -- Database errors during startup: - - The chain plugin attempts to replay on revision mismatch or block log errors. Adjust configuration flags to force replay or resync if needed. - - The snapshot plugin handles various error scenarios including peer connection failures and snapshot validation errors. - -- Snapshot loading issues: - - Verify that snapshot plugin is registered before chain plugin to ensure proper callback registration. - - Check that snapshot file paths are accessible and contain valid snapshot data. - - Monitor snapshot loading logs for detailed error information. - -- P2P snapshot sync problems: - - Ensure trusted snapshot peers are properly configured and reachable. - - Verify that snapshot serving is enabled on source nodes and that anti-spam configurations are appropriate. - - Check network connectivity and firewall settings for snapshot TCP connections. - -- Logging configuration issues: - - Review logging options and ensure the configuration file sections are correctly formatted. - -- Common pitfalls: - - Forgetting to register a plugin leads to unresolved dependencies. - - Not implementing plugin_shutdown properly can leave resources open. - - Performing blocking operations in plugin_initialize can delay startup. - - Missing callback registration prevents proper coordination between plugins. - -**Section sources** -- [plugin.cpp:348-396](file://plugins/chain/plugin.cpp#L348-L396) -- [snapshot_plugin.cpp:3095-3100](file://plugins/snapshot/plugin.cpp#L3095-L3100) -- [plugin.md:11-28](file://documentation/plugin.md#L11-L28) - -## Conclusion -The appbase framework provides a robust lifecycle for plugins with enhanced coordination capabilities: register them centrally, declare dependencies with APPBASE_PLUGIN_REQUIRES, implement plugin_initialize, plugin_startup, and plugin_shutdown, and rely on the framework to enforce dependency ordering. The chain plugin typically initializes first, followed by dependent plugins such as snapshot, p2p, and webserver. The enhanced coordination between chain and snapshot plugins through callback mechanisms ensures proper sequencing of snapshot operations. The deferred execution model prevents blocking operations during critical startup phases and enables sophisticated features like P2P snapshot synchronization. Proper error handling during initialization and graceful shutdown ensure reliable operation, while the callback-driven architecture provides flexible coordination between plugins for complex operational scenarios. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Architecture Overview/System Overview.md b/.qoder/repowiki/en/content/Architecture Overview/System Overview.md deleted file mode 100644 index 207137cfff..0000000000 --- a/.qoder/repowiki/en/content/Architecture Overview/System Overview.md +++ /dev/null @@ -1,384 +0,0 @@ -# System Overview - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [main.cpp](file://programs/vizd/main.cpp) -- [CMakeLists.txt](file://libraries/CMakeLists.txt) -- [CMakeLists.txt](file://plugins/CMakeLists.txt) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document presents a system overview of the VIZ C++ Node, focusing on how the main vizd process orchestrates the entire stack: the application framework (appbase), the blockchain core (chain library), protocol definitions (protocol library), networking (network library), wallet functionality (wallet library), and the plugin system. It explains the modular design that enables flexible feature addition and removal through plugins, describes the observer pattern used for event-driven architecture, and illustrates the data flow from JSON-RPC requests through plugins to database operations. It also outlines system boundaries for peer-to-peer interactions, API request handling, and persistent state management. - -## Project Structure -The repository is organized around a layered architecture: -- Application entrypoint and plugin orchestration live under programs/vizd. -- Libraries are grouped by domain: protocol, chain, network, wallet, api, and utilities. -- Plugins are feature modules that integrate with the appbase framework and the chain library. - -```mermaid -graph TB -subgraph "Application Layer" -VIZD["vizd main()
programs/vizd/main.cpp"] -end -subgraph "Plugin Layer" -ChainP["Chain Plugin
plugins/chain/plugin.hpp"] -P2P["P2P Plugin
plugins/p2p/p2p_plugin.hpp"] -Web["Webserver Plugin
plugins/webserver/webserver_plugin.hpp"] -end -subgraph "Core Libraries" -Protocol["Protocol Library
libraries/protocol/*"] -ChainLib["Chain Library
libraries/chain/*"] -Network["Network Library
libraries/network/*"] -Wallet["Wallet Library
libraries/wallet/*"] -API["API Objects
libraries/api/*"] -end -VIZD --> ChainP -VIZD --> P2P -VIZD --> Web -ChainP --> ChainLib -ChainP --> Protocol -ChainP --> API -P2P --> Network -P2P --> ChainP -Web --> ChainP -ChainLib --> Protocol -ChainLib --> Network -ChainLib --> API -Wallet --> ChainLib -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Core Components -- Application framework (appbase): Provides the plugin lifecycle, dependency injection, and runtime orchestration. The vizd entrypoint registers and initializes plugins, sets logging, and runs the event loop. -- Blockchain core (chain library): Implements the database, block validation, transaction processing, and event signals for observers. -- Protocol definitions (protocol library): Defines operations, transactions, blocks, and types used across the chain. -- Networking (network library): Offers a peer-to-peer node abstraction with delegate callbacks for block/transaction handling and synchronization. -- Wallet (wallet library): Provides wallet APIs and helpers for building and signing transactions. -- Plugin system: Feature modules that depend on appbase and optionally on the chain library, enabling modular extension. - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L287) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L60-L167) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) - -## Architecture Overview -The VIZ node follows an event-driven architecture: -- The vizd process initializes appbase, registers plugins, and starts the application loop. -- The chain plugin owns the blockchain state and emits signals for operations, blocks, and transactions. -- The P2P plugin consumes network events and forwards blocks/transactions to the chain. -- The webserver plugin exposes JSON-RPC endpoints that route to chain and API plugins. -- Plugins can subscribe to chain signals to react to state changes. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant Web as "Webserver Plugin" -participant Chain as "Chain Plugin" -participant DB as "Database" -participant Net as "P2P Plugin" -Client->>Web : "JSON-RPC Request" -Web->>Chain : "Dispatch to Chain API" -Chain->>DB : "Read/Write State" -DB-->>Chain : "Result" -Chain-->>Web : "Response" -Web-->>Client : "JSON-RPC Response" -Net->>Chain : "Accept Block" -Net->>Chain : "Accept Transaction" -Chain->>DB : "Apply Block/Transaction" -DB-->>Chain : "Applied" -Chain-->>Net : "Acknowledge" -``` - -**Diagram sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L287) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) - -## Detailed Component Analysis - -### Application Orchestration (vizd) -- Registers plugins including chain, p2p, webserver, and many others. -- Initializes logging and starts the appbase event loop. -- Ensures required plugins are available before startup. - -```mermaid -flowchart TD -Start(["Process Start"]) --> Register["Register Plugins"] -Register --> InitLogging["Initialize Logging Config"] -InitLogging --> Startup["Startup Plugins"] -Startup --> Exec["Run Event Loop"] -Exec --> Shutdown(["Shutdown"]) -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) - -### Plugin System and Dependencies -- Plugins declare dependencies using appbase macros. -- The chain plugin depends on json_rpc; webserver and p2p depend on json_rpc; p2p depends on chain. -- This ensures initialization order and decouples plugin lifecycles. - -```mermaid -classDiagram -class ChainPlugin { -+plugin_initialize() -+plugin_startup() -+accept_block() -+accept_transaction() -} -class P2PPlugin { -+broadcast_block() -+broadcast_transaction() -+plugin_initialize() -} -class WebserverPlugin { -+plugin_initialize() -+plugin_startup() -} -ChainPlugin --> WebserverPlugin : "uses JSON-RPC" -P2PPlugin --> ChainPlugin : "requires" -WebserverPlugin --> ChainPlugin : "uses JSON-RPC" -``` - -**Diagram sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -**Section sources** -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L38) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L38-L52) - -### Blockchain Core and Signals -- The database exposes signals for operation application, block application, pending/applied transactions, and plugin index registration. -- Plugins subscribe to these signals to implement features like history tracking, API indexing, and analytics. - -```mermaid -classDiagram -class Database { -+pre_apply_operation -+post_apply_operation -+applied_block -+on_pending_transaction -+on_applied_transaction -+_plugin_index_signal -} -class ChainPlugin { -+plugin_initialize() -+accept_block() -+accept_transaction() -} -Database --> ChainPlugin : "emits signals" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L287) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L287) - -### Protocol Definitions -- Operations are defined as a static variant covering on-chain actions and virtual operations. -- This type system underpins transaction validation and operation dispatch. - -```mermaid -classDiagram -class Operation { -<> -} -class Operations { -+transfer_operation -+account_update_operation -+proposal_create_operation -+virtual_operations... -} -Operations --> Operation : "static_variant" -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -### Networking and Peer Interactions -- The node delegate interface defines callbacks for handling blocks, transactions, and synchronization. -- The node manages peer connections, broadcasting, and sync status reporting. - -```mermaid -classDiagram -class NodeDelegate { -+has_item() -+handle_block() -+handle_transaction() -+get_item() -+get_blockchain_synopsis() -+sync_status() -+connection_count_changed() -} -class Node { -+set_node_delegate() -+listen_on_endpoint() -+connect_to_endpoint() -+broadcast() -+sync_from() -} -Node --> NodeDelegate : "calls back" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L60-L167) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L60-L167) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) - -### Wallet Integration -- The wallet API provides transaction building, signing, and proposal workflows. -- It integrates with remote node APIs and chain state for account and balance queries. - -```mermaid -classDiagram -class WalletAPI { -+begin_builder_transaction() -+add_operation_to_builder_transaction() -+sign_builder_transaction() -+propose_builder_transaction() -+get_account() -+get_dynamic_global_properties() -} -WalletAPI --> Database : "queries" -``` - -**Diagram sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -**Section sources** -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -### API Properties and State Exposure -- API objects encapsulate chain state for consumption by clients. -- Example: chain_api_properties mirrors chain configuration exposed via APIs. - -```mermaid -classDiagram -class ChainAPIProperties { -+account_creation_fee -+maximum_block_size -+create_account_delegation_ratio -+... (other fields) -} -ChainAPIProperties --> Database : "constructed from" -``` - -**Diagram sources** -- [chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp#L11-L44) - -**Section sources** -- [chain_api_properties.hpp](file://libraries/api/include/graphene/api/chain_api_properties.hpp#L11-L44) - -## Dependency Analysis -- The plugin layer depends on appbase and optionally on the chain library. -- The chain library depends on protocol definitions and network abstractions. -- The webserver and p2p plugins depend on json_rpc for request routing. -- The wallet library depends on chain and protocol types. - -```mermaid -graph LR -AppBase["appbase"] --> Plugins["Plugins"] -Plugins --> ChainLib["Chain Library"] -Plugins --> Protocol["Protocol Library"] -Plugins --> Network["Network Library"] -Webserver["Webserver Plugin"] --> JsonRPC["JSON-RPC"] -P2P["P2P Plugin"] --> ChainLib -ChainLib --> Protocol -ChainLib --> Network -Wallet["Wallet Library"] --> ChainLib -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -## Performance Considerations -- Signal-based event handling avoids tight coupling and supports efficient plugin reactions to chain state changes. -- The plugin model enables selective feature activation, reducing overhead when unnecessary modules are disabled. -- Proper logging configuration and network bandwidth limits help maintain responsiveness under load. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Verify plugin registration and initialization order in the main entrypoint. -- Confirm logging configuration is loaded and appropriate appenders/loggers are defined. -- Monitor network delegate callbacks for block/transaction acceptance and sync progress. -- Subscribe to chain signals to diagnose operation/application timing and failures. - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L117-L158) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L252-L287) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L60-L167) - -## Conclusion -The VIZ C++ Node is a modular, event-driven system centered on appbase and the chain library. The plugin architecture cleanly separates concerns across networking, API exposure, and specialized features, while the observer pattern enables responsive, decoupled reactions to blockchain state changes. Together, these components form a robust foundation for a production-grade blockchain node with flexible feature management and clear system boundaries. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Chain Plugin.md b/.qoder/repowiki/en/content/Chain Plugin.md deleted file mode 100644 index ca73407da8..0000000000 --- a/.qoder/repowiki/en/content/Chain Plugin.md +++ /dev/null @@ -1,815 +0,0 @@ -# Chain Plugin - - -**Referenced Files in This Document** -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [application.cpp](file://thirdparty/appbase/application.cpp) -- [README.md](file://README.md) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) -- [console_appender.cpp](file://thirdparty/fc/src/log/console_appender.cpp) -- [console_defines.h](file://thirdparty/fc/src/log/console_defines.h) -- [logger_config.cpp](file://thirdparty/fc/src/log/logger_config.cpp) -- [main.cpp](file://programs/vizd/main.cpp) - - -## Update Summary -**Changes Made** -- Added comprehensive automatic recovery system from shared memory corruption with new --auto-recover-from-snapshot flag -- Implemented new --snapshot-auto-latest command-line flag for automatic snapshot discovery -- Enhanced database error handling with shared_memory_corruption_exception for robust error reporting -- Improved chain plugin startup sequence with conditional on_sync() callback invocation to prevent conflicts during automatic recovery scenarios -- Added immediate auto-recovery mechanism that triggers during block processing when corruption is detected - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Logging System](#enhanced-logging-system) -7. [Automatic Recovery System](#automatic-recovery-system) -8. [Dependency Analysis](#dependency-analysis) -9. [Performance Considerations](#performance-considerations) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Conclusion](#conclusion) - -## Introduction -The Chain Plugin is the core component responsible for managing the blockchain state, accepting blocks and transactions, maintaining database consistency, and coordinating with other plugins in the VIZ node. It integrates tightly with the underlying database layer and provides APIs for block acceptance, transaction processing, and state queries. Recent enhancements focus on improved plugin coordination, deferred execution support for snapshot loading, comprehensive recovery system integration with DLT block log capabilities, expanded snapshot management infrastructure with consistent data directory usage, enhanced logging system with visual differentiation for better debugging experience, and most importantly, a comprehensive automatic recovery system that can detect and recover from shared memory corruption scenarios. - -## Project Structure -The Chain Plugin resides under the `plugins/chain` directory and interfaces with the `libraries/chain` database implementation. The plugin exposes a clean interface for other plugins and the application to interact with the blockchain state, with enhanced deferred execution support and comprehensive recovery capabilities. The data directory path has been standardized to use 'state' for improved organizational clarity. - -```mermaid -graph TB -subgraph "Plugins Layer" -ChainPlugin["Chain Plugin
plugins/chain"] -JSONRPC["JSON-RPC Plugin
plugins/json_rpc"] -SnapshotPlugin["Snapshot Plugin
plugins/snapshot"] -end -subgraph "Chain Library" -Database["Database Implementation
libraries/chain/database"] -ForkDB["Fork Database
libraries/chain/fork_database"] -BlockLog["Block Log
libraries/chain/block_log"] -DLBlockLog["DLT Block Log
libraries/chain/dlt_block_log"] -end -subgraph "Application" -App["Application
appbase"] -end -App --> JSONRPC -JSONRPC --> ChainPlugin -ChainPlugin --> Database -Database --> ForkDB -Database --> BlockLog -Database --> DLBlockLog -ChainPlugin --> SnapshotPlugin -``` - -**Diagram sources** -- [plugin.cpp:183-649](file://plugins/chain/plugin.cpp#L183-L649) -- [database.cpp:351-544](file://libraries/chain/database.cpp#L351-L544) -- [plugin.cpp:3031-3118](file://plugins/snapshot/plugin.cpp#L3031-L3118) - -**Section sources** -- [plugin.cpp:1-694](file://plugins/chain/plugin.cpp#L1-L694) -- [database.cpp:1-6314](file://libraries/chain/database.cpp#L1-L6314) - -## Core Components -The Chain Plugin consists of two primary parts: -- The plugin class that manages lifecycle, configuration, and external interfaces -- The database wrapper that handles block acceptance, transaction processing, and state management - -Key responsibilities include: -- Managing shared memory configuration and growth policies with updated default directory structure using 'state' -- Handling snapshot loading and recovery modes with enhanced deferred execution support -- Coordinating block and transaction acceptance with plugin synchronization -- Providing state queries and database accessors -- Supporting DLT (Dynamic Ledger Technology) block logging with comprehensive replay capabilities -- Implementing advanced recovery procedures with automatic snapshot detection and restoration -- Integrating with comprehensive snapshot management infrastructure including automatic discovery, rotation, and serving capabilities -- **Enhanced** Providing visual feedback through color-coded console logging for improved debugging experience -- **New** Implementing comprehensive automatic recovery system from shared memory corruption with immediate detection and restoration capabilities - -**Updated** Enhanced plugin coordination with deferred execution support allows seamless integration between chain and snapshot plugins, enabling flexible startup sequences and improved error recovery mechanisms. The default shared memory directory has been changed from 'blockchain' to 'state' for better organizational clarity and consistency across data directory usage. The enhanced logging system now provides visual differentiation through ANSI escape codes for better console output readability. The new automatic recovery system provides robust protection against shared memory corruption scenarios with immediate detection and restoration capabilities. - -**Section sources** -- [plugin.hpp:21-124](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L124) -- [plugin.cpp:21-93](file://plugins/chain/plugin.cpp#L21-L93) -- [database.cpp:351-544](file://libraries/chain/database.cpp#L351-L544) - -## Architecture Overview -The Chain Plugin follows a layered architecture with clear separation of concerns and enhanced plugin coordination: - -```mermaid -sequenceDiagram -participant App as "Application" -participant Chain as "Chain Plugin" -participant DB as "Database" -participant Fork as "Fork Database" -participant Log as "Block Log" -participant Snapshot as "Snapshot Plugin" -App->>Chain : set_program_options() -Chain->>Chain : parse CLI/config options -Chain->>Chain : validate snapshot_path -Chain->>DB : open()/open_from_snapshot() -DB->>Fork : initialize fork database -DB->>Log : initialize block log -Chain->>Snapshot : register callbacks -Note over Chain,Snapsho : Deferred Execution Support -Chain->>Chain : check pending_snapshot_load -alt snapshot plugin ready -Chain->>Chain : trigger_snapshot_load() -Chain->>DB : load snapshot via callback -else snapshot plugin not ready -Chain->>Chain : set pending_snapshot_load -Chain->>Snapshot : plugin_startup() -Snapshot->>Chain : trigger_snapshot_load() -end -Chain->>App : on_sync signal -App->>Chain : accept_block(block) -Chain->>Chain : check_time_in_block() -Chain->>DB : validate_block() -alt single_write_thread -Chain->>Chain : post to io_service -Chain->>DB : push_block() -else -Chain->>DB : push_block() -end -DB->>Fork : update fork database -DB->>Log : append to block log -DB-->>Chain : result -Chain-->>App : accepted -App->>Chain : accept_transaction(trx) -Chain->>DB : validate_transaction() -alt single_write_thread -Chain->>Chain : post to io_service -Chain->>DB : push_transaction() -else -Chain->>DB : push_transaction() -end -``` - -**Diagram sources** -- [plugin.cpp:103-183](file://plugins/chain/plugin.cpp#L103-L183) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) -- [plugin.cpp:650-666](file://plugins/chain/plugin.cpp#L650-L666) - -**Section sources** -- [plugin.cpp:197-272](file://plugins/chain/plugin.cpp#L197-L272) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) - -## Detailed Component Analysis - -### Chain Plugin Class -The plugin class serves as the main interface for blockchain operations and configuration management with enhanced plugin coordination and deferred execution support. - -```mermaid -classDiagram -class Plugin { -+set_program_options(cli, cfg) -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+accept_block(block, currently_syncing, skip) -+accept_transaction(trx) -+block_is_on_preferred_chain(block_id) -+check_time_in_block(block) -+db() database& -+on_sync signal -+snapshot_load_callback function -+snapshot_create_callback function -+snapshot_p2p_sync_callback function -+trigger_snapshot_load function -} -class PluginImpl { -+shared_memory_size uint64_t -+shared_memory_dir path -+replay bool -+resync bool -+readonly bool -+check_locks bool -+validate_invariants bool -+flush_interval uint32_t -+loaded_checkpoints map -+allow_future_time uint32_t -+read_wait_micro uint64_t -+max_read_wait_retries uint32_t -+write_wait_micro uint64_t -+max_write_wait_retries uint32_t -+inc_shared_memory_size size_t -+min_free_shared_memory_size size_t -+enable_plugins_on_push_transaction bool -+block_num_check_free_size uint32_t -+skip_virtual_ops bool -+snapshot_path string -+replay_from_snapshot bool -+auto_recover_from_snapshot bool -+db database -+single_write_thread bool -+sync_start_logged bool -+pending_snapshot_load bool -+check_time_in_block(block) -+accept_block(block, currently_syncing, skip) bool -+accept_transaction(trx) -+wipe_db(data_dir, wipe_block_log) -+replay_db(data_dir, force_replay) -+do_snapshot_load(data_dir, is_recovery) -+trigger_snapshot_load() -+attempt_auto_recovery() -} -Plugin --> PluginImpl : "owns" -``` - -**Diagram sources** -- [plugin.hpp:21-124](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L124) -- [plugin.cpp:21-93](file://plugins/chain/plugin.cpp#L21-L93) - -#### Configuration Options -The plugin supports extensive configuration through command-line and configuration file options with enhanced recovery and coordination capabilities: - -| Option | Type | Description | Default | -|--------|------|-------------|---------| -| shared-file-dir | path | Location of shared memory files (absolute path or relative to application data dir) | **state** | -| shared-file-size | size | Initial shared memory size | 2G | -| inc-shared-file-size | size | Memory growth increment | 2G | -| min-free-shared-file-size | size | Minimum free space threshold | 500M | -| block-num-check-free-size | uint32_t | Check free space every N blocks | 1000 | -| checkpoint | pairs | Enforced checkpoints | none | -| flush-state-interval | uint32_t | Flush interval | 10000 | -| read-wait-micro | uint64_t | Read lock timeout | db default | -| max-read-wait-retries | uint32_t | Read retry attempts | db default | -| write-wait-micro | uint64_t | Write lock timeout | db default | -| max-write-wait-retries | uint32_t | Write retry attempts | db default | -| single-write-thread | bool | Single thread mode | false | -| clear-votes-before-block | uint32_t | Clear votes before block | 0 | -| skip-virtual-ops | bool | Skip virtual ops | false | -| enable-plugins-on-push-transaction | bool | Enable plugins on tx | false | -| dlt-block-log-max-blocks | uint32_t | DLT log size | 100000 | -| **snapshot** | string | Load state from snapshot file | empty | -| **snapshot-auto-latest** | bool | Auto-find latest snapshot in snapshot-dir | false | -| **replay-from-snapshot** | bool | Snapshot + dlt_block_log replay | false | -| **snapshot-dir** | string | Directory for auto-generated snapshots | empty | -| **auto-recover-from-snapshot** | bool | Automatically recover from corruption | true | - -**Updated** Enhanced plugin coordination with deferred execution support for snapshot operations, allowing flexible startup sequences between chain and snapshot plugins. The default shared-file-dir has been changed from 'blockchain' to 'state' for improved organizational clarity and consistency across data directory usage. Enhanced logging system provides visual feedback through color-coded console output. **New** The --auto-recover-from-snapshot flag enables automatic recovery from shared memory corruption by importing the latest available snapshot and replaying DLT block log data. - -**Section sources** -- [plugin.cpp:197-272](file://plugins/chain/plugin.cpp#L197-L272) -- [plugin.cpp:274-386](file://plugins/chain/plugin.cpp#L274-L386) - -### Database Operations -The database layer provides comprehensive blockchain state management with enhanced recovery and DLT block log integration: - -```mermaid -flowchart TD -Start([Startup]) --> CheckResync{"Resync requested?"} -CheckResync --> |Yes| WipeDB["Wipe database and block log"] -CheckResync --> |No| OpenDB["Open existing database"] -OpenDB --> CheckHead{"Head block exists?"} -CheckHead --> |No| CheckSnapshot{"Snapshot available?"} -CheckHead --> |Yes| CheckReplay{"Need replay?"} -CheckSnapshot --> |Yes| ValidateSnapshotPath["Validate snapshot_path"] -ValidateSnapshotPath --> LoadSnapshot["Load snapshot state"] -CheckSnapshot --> |No| InitGenesis["Initialize genesis"] -LoadSnapshot --> InitHardforks["Initialize hardforks"] -InitHardforks --> ReplayDLT{"DLT log available?"} -ReplayDLT --> |Yes| ReindexDLT["Reindex from DLT log"] -ReplayDLT --> |No| StartSync["Start synchronization"] -CheckReplay --> |Yes| ReplayBlocks["Replay blockchain"] -CheckReplay --> |No| StartSync -ReplayBlocks --> StartSync -InitGenesis --> StartSync -StartSync --> Ready([Ready]) -``` - -**Diagram sources** -- [plugin.cpp:388-649](file://plugins/chain/plugin.cpp#L388-L649) -- [database.cpp:351-544](file://libraries/chain/database.cpp#L351-L544) -- [plugin.cpp:650-666](file://plugins/chain/plugin.cpp#L650-L666) - -#### Block Processing Pipeline -The block processing pipeline handles validation, application, and persistence with enhanced error handling and plugin coordination: - -```mermaid -sequenceDiagram -participant Chain as "Chain Plugin" -participant DB as "Database" -participant Fork as "Fork DB" -participant Log as "Block Log" -Chain->>DB : validate_block() -DB->>DB : _validate_block() -DB->>DB : validate_block_header() -DB->>DB : apply_transactions() -loop For each transaction -DB->>DB : apply_transaction() -DB->>DB : evaluate_operations() -end -DB->>DB : update_global_properties() -DB->>DB : update_witness_schedule() -DB->>DB : update_last_irreversible_block() -DB->>Fork : update fork database -DB->>Log : append to block log -DB-->>Chain : block applied -``` - -**Diagram sources** -- [database.cpp:4253-4323](file://libraries/chain/database.cpp#L4253-L4323) -- [database.cpp:4314-4323](file://libraries/chain/database.cpp#L4314-L4323) - -**Section sources** -- [database.cpp:351-544](file://libraries/chain/database.cpp#L351-L544) -- [database.cpp:4253-4323](file://libraries/chain/database.cpp#L4253-L4323) - -### Transaction Processing -Transaction processing involves validation, evaluation, and application within the block context: - -```mermaid -flowchart TD -TxIn([Transaction Input]) --> ValidateTx["Validate Transaction"] -ValidateTx --> CheckSig{"Authority Check"} -CheckSig --> |Pass| EvaluateOps["Evaluate Operations"] -CheckSig --> |Fail| RejectTx["Reject Transaction"] -EvaluateOps --> ApplyTx["Apply to State"] -ApplyTx --> CheckOps{"Operation Validation"} -CheckOps --> |Pass| StoreTx["Store Transaction"] -CheckOps --> |Fail| Rollback["Rollback Changes"] -StoreTx --> Done([Transaction Complete]) -RejectTx --> Done -Rollback --> Done -``` - -**Diagram sources** -- [database.cpp:4253-4323](file://libraries/chain/database.cpp#L4253-L4323) - -**Section sources** -- [database.cpp:4253-4323](file://libraries/chain/database.cpp#L4253-L4323) - -### Enhanced Plugin Coordination and Deferred Execution -Recent improvements focus on sophisticated plugin coordination mechanisms with deferred execution support: - -**Updated** Enhanced plugin coordination includes: -- Deferred snapshot loading when snapshot plugin isn't ready during chain startup -- Automatic callback registration and triggering between chain and snapshot plugins -- Comprehensive recovery system integration with DLT block log replay capabilities -- Improved error handling and fallback mechanisms for snapshot operations -- **New** Immediate auto-recovery mechanism that can trigger during block processing when corruption is detected - -```mermaid -flowchart TD -SnapshotInit["Snapshot Initialization"] --> CheckCallback{"snapshot_load_callback registered?"} -CheckCallback --> |Yes| ValidatePath["Validate snapshot_path"] -CheckCallback --> |No| CheckArgs{"snapshot args present?"} -CheckArgs --> |Yes| SetPending["Set pending_snapshot_load = true"] -CheckArgs --> |No| NormalStartup["Normal startup"] -SetPending --> WaitReady["Wait for snapshot plugin ready"] -WaitReady --> CheckReady{"snapshot plugin ready?"} -CheckReady --> |Yes| TriggerLoad["Call trigger_snapshot_load()"] -CheckReady --> |No| WaitReady -TriggerLoad --> ValidatePath -ValidatePath --> LoadSnapshot["Load snapshot state"] -LoadSnapshot --> InitHardforks["Initialize hardforks"] -InitHardforks --> ReplayDLT{"DLT log available?"} -ReplayDLT --> |Yes| ReindexDLT["Reindex from DLT log"] -ReplayDLT --> |No| StartSync["Start synchronization"] -``` - -**Diagram sources** -- [plugin.cpp:420-475](file://plugins/chain/plugin.cpp#L420-L475) -- [plugin.cpp:650-666](file://plugins/chain/plugin.cpp#L650-L666) -- [plugin.cpp:3031-3042](file://plugins/snapshot/plugin.cpp#L3031-L3042) - -**Section sources** -- [plugin.cpp:420-475](file://plugins/chain/plugin.cpp#L420-L475) -- [plugin.cpp:650-666](file://plugins/chain/plugin.cpp#L650-L666) -- [plugin.cpp:3031-3042](file://plugins/snapshot/plugin.cpp#L3031-L3042) - -### Comprehensive Recovery System Integration -The enhanced recovery system provides robust snapshot-based restoration with DLT block log integration: - -**Updated** Advanced recovery capabilities include: -- Automatic snapshot detection and loading with path validation -- DLT block log replay for incremental recovery from corrupted states -- Emergency consensus mode support for network recovery scenarios -- Comprehensive error reporting and fallback mechanisms -- **New** Immediate auto-recovery from shared memory corruption during block processing - -```mermaid -flowchart TD -RecoveryStart["Recovery Mode"] --> CheckSnapshot{"Snapshot available?"} -CheckSnapshot --> |Yes| LoadSnapshot["Load snapshot state"] -CheckSnapshot --> |No| CheckDLT{"DLT log available?"} -LoadSnapshot --> InitHardforks["Initialize hardforks"] -InitHardforks --> CheckDLT -CheckDLT --> |Yes| ReplayDLT["Replay DLT block log"] -CheckDLT --> |No| Fallback["Fallback to normal sync"] -ReplayDLT --> StartSync["Start synchronization"] -StartSync --> RecoveryComplete["Recovery Complete"] -Fallback --> RecoveryComplete -``` - -**Diagram sources** -- [plugin.cpp:566-649](file://plugins/chain/plugin.cpp#L566-L649) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) - -**Section sources** -- [plugin.cpp:566-649](file://plugins/chain/plugin.cpp#L566-L649) -- [database.cpp:438-544](file://libraries/chain/database.cpp#L438-L544) - -### Enhanced Snapshot Management Infrastructure -**Updated** The snapshot plugin now provides comprehensive snapshot management capabilities: - -- **Automatic Discovery**: `--snapshot-auto-latest` with `--snapshot-dir` for finding the latest snapshot -- **Periodic Snapshots**: `--snapshot-every-n-blocks` for automated snapshot creation -- **Snapshot Rotation**: `--snapshot-max-age-days` for automatic cleanup of old snapshots -- **Snapshot Serving**: `--allow-snapshot-serving` with trust model and anti-spam protection -- **Trusted Peers**: `--trusted-snapshot-peer` for P2P snapshot synchronization -- **Stalled Sync Detection**: Automatic detection and recovery from stalled synchronization - -```mermaid -flowchart TD -SnapshotConfig["Snapshot Configuration"] --> AutoDiscover["Auto-Discovery"] -AutoDiscover --> LatestSnap["Latest Snapshot Detection"] -LatestSnap --> ValidatePath["Validate Path"] -ValidatePath --> LoadState["Load Snapshot State"] -SnapshotConfig --> Periodic["Periodic Snapshots"] -Periodic --> EveryNBlocks["Every N Blocks"] -EveryNBlocks --> CreateSnap["Create Snapshot"] -CreateSnap --> RotateAges["Age-Based Rotation"] -RotateAges --> CleanupOld["Cleanup Old Snapshots"] -SnapshotConfig --> Serving["Snapshot Serving"] -Serving --> TrustModel["Trust Model"] -TrustModel --> PublicServing["Public Serving"] -TrustModel --> TrustedOnly["Trusted Only Serving"] -PublicServing --> AntiSpam["Anti-Spam Protection"] -TrustedOnly --> AntiSpam -AntiSpam --> RateLimiting["Rate Limiting"] -AntiSpam --> SessionLimits["Session Limits"] -AntiSpam --> ConnectionTimeout["Connection Timeout"] -SnapshotConfig --> P2PSync["P2P Sync"] -P2PSync --> TrustedPeers["Trusted Peers"] -TrustedPeers --> DownloadSnap["Download Snapshot"] -DownloadSnap --> LoadState -``` - -**Diagram sources** -- [plugin.cpp:344-382](file://plugins/chain/plugin.cpp#L344-L382) -- [plugin.cpp:2817-2861](file://plugins/snapshot/plugin.cpp#L2817-L2861) -- [plugin.cpp:2908-2920](file://plugins/snapshot/plugin.cpp#L2908-L2920) - -**Section sources** -- [plugin.cpp:344-382](file://plugins/chain/plugin.cpp#L344-L382) -- [plugin.cpp:2817-2861](file://plugins/snapshot/plugin.cpp#L2817-L2861) -- [plugin.cpp:2908-2920](file://plugins/snapshot/plugin.cpp#L2908-L2920) - -## Enhanced Logging System - -**Updated** The Chain Plugin now features an enhanced logging system with visual differentiation for improved debugging experience: - -### Color-Coded Console Output -The logging system uses ANSI escape codes to provide visual feedback: - -- **Green Color** (`\033[92m`): Used for sync mode start and completion messages -- **Brown/Yellow Color** (`\033[93m`): Used for periodic sync progress notifications -- **Default Colors**: Maintained for other log levels (debug, warn, error) - -### Sync Mode Status Messages -The enhanced logging provides clear visual indicators for different sync states: - -```mermaid -flowchart TD -SyncStart["Sync Mode Started"] --> GreenStart["\033[92m>>> Syncing Blockchain started from block #${n} (head: ${head})\033[0m"] -SyncProgress["Sync Progress"] --> YellowProgress["\033[93mSyncing Blockchain --- Got block: #${n} time: ${t} producer: ${p}\033[0m"] -SyncEnd["Sync Mode Ended"] --> GreenEnd["\033[92mSync mode ended: received normal block #${n} (head: ${head}), sync_start_logged reset\033[0m"] -``` - -**Diagram sources** -- [plugin.cpp:105-121](file://plugins/chain/plugin.cpp#L105-L121) - -### Logging Framework Enhancements -The underlying logging framework supports comprehensive color configuration: - -- **Default Configuration**: Debug (green), Warn (brown), Error (red) -- **Application Override**: Error level now uses cyan instead of red for better visual hierarchy -- **Platform Support**: Windows and Unix terminal color support through ANSI escape codes -- **File Output**: Color codes are stripped when logging to files to prevent garbled output - -### Visual Differentiation Benefits -The enhanced logging system improves debugging experience through: - -- **Immediate Visual Feedback**: Sync start and completion clearly highlighted in green -- **Progress Indicators**: Periodic sync progress shown in yellow/brown for easy scanning -- **Consistent Color Scheme**: Maintains visual hierarchy with appropriate colors for different log levels -- **Cross-Platform Compatibility**: ANSI escape codes work across different terminal environments - -**Section sources** -- [plugin.cpp:105-121](file://plugins/chain/plugin.cpp#L105-L121) -- [console_appender.cpp:71-84](file://thirdparty/fc/src/log/console_appender.cpp#L71-L84) -- [console_defines.h:146-188](file://thirdparty/fc/src/log/console_defines.h#L146-L188) -- [logger_config.cpp:69-89](file://thirdparty/fc/src/log/logger_config.cpp#L69-L89) -- [main.cpp:234-250](file://programs/vizd/main.cpp#L234-L250) - -## Automatic Recovery System - -**New** The Chain Plugin now implements a comprehensive automatic recovery system designed to detect and recover from shared memory corruption scenarios without manual intervention. This system provides multiple layers of protection and recovery mechanisms. - -### Recovery System Architecture - -```mermaid -flowchart TD -CorruptionDetected["Shared Memory Corruption Detected"] --> CheckAutoRecover{"--auto-recover-from-snapshot enabled?"} -CheckAutoRecover --> |Yes| FindLatestSnapshot["Find Latest Available Snapshot"] -CheckAutoRecover --> |No| ManualRecovery["Manual Recovery Required"] -FindLatestSnapshot --> CheckSnapshotExists{"Snapshot Found?"} -CheckSnapshotExists --> |Yes| CloseDatabase["Close Corrupted Database"] -CheckSnapshotExists --> |No| FallbackReplay["Fallback to Replay Mode"] -CloseDatabase --> SetSnapshotPath["Set Snapshot Path"] -SetSnapshotPath --> LoadSnapshot["Load Snapshot State"] -LoadSnapshot --> InitializeHardforks["Initialize Hardforks"] -InitializeHardforks --> ReplayDLT["Replay DLT Block Log"] -ReplayDLT --> ResumeNode["Resume Node Operation"] -ManualRecovery --> ExitNode["Exit Node with Error Message"] -FallbackReplay --> ReplayBlockchain["Replay Blockchain from Scratch"] -ReplayBlockchain --> ResumeNode -``` - -**Diagram sources** -- [plugin.cpp:757-816](file://plugins/chain/plugin.cpp#L757-L816) -- [plugin.cpp:547-600](file://plugins/chain/plugin.cpp#L547-L600) - -### Recovery Triggers - -The automatic recovery system can be triggered in multiple scenarios: - -1. **Startup Phase Recovery**: When the database fails to open due to shared memory corruption -2. **Runtime Recovery**: During block processing when shared memory corruption is detected -3. **Configuration-Based Recovery**: When the `--auto-recover-from-snapshot` flag is enabled - -### Recovery Process Implementation - -The recovery process follows a systematic approach: - -```mermaid -sequenceDiagram -participant Chain as "Chain Plugin" -participant DB as "Database" -participant Snapshot as "Snapshot Plugin" -Chain->>DB : Attempt to open database -DB-->>Chain : Throws shared_memory_corruption_exception -Chain->>Chain : check auto_recover_from_snapshot flag -alt Auto-recovery enabled -Chain->>Chain : find_latest_snapshot() -Chain->>Chain : snapshot_path = latest_snapshot -Chain->>Chain : do_snapshot_load(data_dir, is_recovery=true) -Chain->>DB : open_from_snapshot() -DB->>Snapshot : snapshot_load_callback() -Snapshot-->>DB : Load snapshot state -DB-->>Chain : Recovery complete -Chain->>Chain : Resume normal operation -else Auto-recovery disabled -Chain->>Chain : Log error and exit -end -``` - -**Diagram sources** -- [plugin.cpp:757-816](file://plugins/chain/plugin.cpp#L757-L816) -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) - -### Database Exception Handling - -The system leverages a dedicated exception type for shared memory corruption detection: - -```mermaid -classDiagram -class shared_memory_corruption_exception { -+inherits chain_exception -+code : 4140000 -+message : "shared memory corruption detected" -} -class chain_exception { -+inherits fc : : exception -+base exception for all chain-related errors -} -shared_memory_corruption_exception --> chain_exception : "inherits" -``` - -**Diagram sources** -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) - -### Command-Line Configuration - -The automatic recovery system introduces new command-line flags: - -| Flag | Type | Description | Default | -|------|------|-------------|---------| -| `--auto-recover-from-snapshot` | boolean | Automatically recover from shared memory corruption by importing latest snapshot | true | -| `--snapshot-auto-latest` | boolean | Auto-discover latest snapshot in snapshot-dir for recovery scenarios | false | - -### Recovery Validation and Safety - -The system includes multiple safety mechanisms: - -- **Snapshot Validation**: Ensures recovered snapshots are valid and compatible -- **Database Integrity Checks**: Verifies recovered state before resuming operations -- **DLT Block Log Replay**: Applies incremental updates from DLT log for complete state consistency -- **Graceful Degradation**: Falls back to traditional replay mode if snapshot recovery fails - -### Recovery Monitoring and Reporting - -The system provides comprehensive logging for recovery operations: - -- **Recovery Initiation**: Logs when automatic recovery is triggered -- **Snapshot Detection**: Reports found snapshot path and block number -- **Recovery Progress**: Tracks recovery stages and completion status -- **Error Handling**: Provides detailed error messages for recovery failures - -**Section sources** -- [plugin.cpp:757-816](file://plugins/chain/plugin.cpp#L757-L816) -- [plugin.cpp:547-600](file://plugins/chain/plugin.cpp#L547-L600) -- [database_exceptions.hpp:122](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L122) - -## Dependency Analysis -The Chain Plugin has well-defined dependencies and integration points with enhanced plugin coordination: - -```mermaid -graph TB -subgraph "External Dependencies" -AppBase["AppBase Framework"] -Boost["Boost Libraries"] -OpenSSL["OpenSSL Crypto"] -FC["FC Utilities"] -end -subgraph "Internal Dependencies" -ChainBase["ChainBase Database"] -Protocol["Protocol Definitions"] -Network["Network Layer"] -Wallet["Wallet Interface"] -SnapshotPlugin["Snapshot Plugin"] -end -ChainPlugin --> AppBase -ChainPlugin --> Boost -ChainPlugin --> OpenSSL -ChainPlugin --> FC -ChainPlugin --> ChainBase -ChainPlugin --> Protocol -ChainPlugin --> Network -ChainPlugin --> Wallet -ChainPlugin --> SnapshotPlugin -``` - -**Diagram sources** -- [plugin.cpp:1-12](file://plugins/chain/plugin.cpp#L1-L12) -- [database.cpp:1-10](file://libraries/chain/database.cpp#L1-L10) - -### Integration Points -The plugin integrates with several other components with enhanced coordination: -- JSON-RPC plugin for API exposure -- Snapshot plugin for state recovery with deferred execution support -- P2P plugin for block propagation -- Validator Plugin for block production -- Database plugin for state persistence - -**Updated** Enhanced integration with snapshot plugin includes sophisticated deferred execution mechanisms, automatic callback registration, and comprehensive recovery system coordination. The default shared memory directory has been changed from 'blockchain' to 'state' for better organizational structure and consistent data directory usage. The enhanced logging system provides visual feedback for better debugging experience. **New** The automatic recovery system provides seamless protection against shared memory corruption with immediate detection and restoration capabilities. - -**Section sources** -- [plugin.hpp:23-24](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L23-L24) -- [plugin.cpp:92-105](file://plugins/chain/plugin.cpp#L92-L105) - -## Performance Considerations -The Chain Plugin implements several performance optimizations with enhanced plugin coordination: - -### Shared Memory Management -- Configurable shared memory size with automatic growth -- Minimum free space thresholds to prevent fragmentation -- Periodic flushing to balance performance and safety - -### Concurrency Control -- Optional single-thread mode for deterministic processing -- Configurable read/write lock timeouts and retry limits -- Asynchronous processing through io_service for non-blocking operations - -### Storage Optimization -- DLT (Dynamic Ledger Technology) block logging for recovery scenarios -- Checkpoint enforcement for validation acceleration -- Efficient fork database management for chain reorganization - -### Enhanced Plugin Coordination Performance -**Updated** Optimized plugin coordination includes: -- Deferred execution support to avoid blocking during plugin initialization -- Efficient callback registration and triggering mechanisms -- Reduced redundant operations through intelligent state checking -- Optimized snapshot loading with automatic path validation -- Improved snapshot serving performance with trust model and anti-spam protection -- **Enhanced** Color-coded logging reduces visual scanning time for important sync events -- **New** Automatic recovery system minimizes downtime during corruption scenarios - -### Logging Performance Considerations -**Updated** The enhanced logging system maintains performance through: -- Minimal overhead for color code insertion -- Efficient ANSI escape code handling -- Platform-specific optimization for Windows and Unix terminals -- Stripping of color codes for file output to prevent performance degradation - -### Recovery System Performance Impact -**New** The automatic recovery system is designed to minimize performance impact: -- Fast snapshot discovery using optimized file system scanning -- Incremental DLT block log replay to reduce recovery time -- Graceful degradation to traditional replay mode if needed -- Background recovery operations to avoid blocking normal node operations - -**Section sources** -- [plugin.cpp:24-51](file://plugins/chain/plugin.cpp#L24-L51) -- [plugin.cpp:398-418](file://plugins/chain/plugin.cpp#L398-L418) - -## Troubleshooting Guide - -### Common Startup Issues -1. **Database Corruption**: The plugin automatically attempts to replay the blockchain when corruption is detected -2. **Missing State**: Uses snapshot recovery mode when available with enhanced deferred execution support -3. **Lock Conflicts**: Configurable lock timeouts and retry mechanisms -4. **Plugin Coordination Issues**: Enhanced error reporting for snapshot plugin initialization delays -5. ****New** Shared Memory Corruption**: Automatic recovery system provides immediate detection and restoration - -### Recovery Procedures -- Use `--replay-blockchain` to force blockchain replay -- Use `--resync-blockchain` to wipe and rebuild from scratch -- Use `--replay-from-snapshot` for recovery from corrupted state with DLT block log replay -- **Updated** Use `--snapshot-auto-latest` with proper `--snapshot-dir` configuration for automatic snapshot discovery -- **New** Enable `--auto-recover-from-snapshot` to automatically recover from corruption scenarios - -### Monitoring and Diagnostics -- Enable `--check-locks` for lock validation debugging -- Use `--validate-database-invariants` for state consistency checks -- Monitor shared memory usage and growth patterns -- **Updated** Enable verbose logging for snapshot plugin coordination failures -- Monitor snapshot serving metrics and trust model compliance -- **Enhanced** Use color-coded logs to quickly identify sync mode status and progress -- **New** Monitor automatic recovery system logs for corruption detection and restoration events - -### Enhanced Plugin Coordination Troubleshooting -**Updated** Specific troubleshooting for plugin coordination issues: -- Verify snapshot plugin is loaded before chain plugin for optimal performance -- Check deferred execution logs for snapshot loading delays -- Ensure proper callback registration between chain and snapshot plugins -- Monitor plugin startup order and initialization sequences -- Validate snapshot file compatibility and path accessibility -- Check snapshot directory permissions and disk space availability - -### Recovery System Troubleshooting -**Updated** Specific troubleshooting for recovery system issues: -- Verify DLT block log availability for incremental recovery -- Check snapshot file integrity and compatibility -- Monitor hardfork initialization during recovery processes -- Validate emergency consensus mode settings for network recovery scenarios -- Test snapshot serving configuration with trust model and anti-spam settings -- **New** Verify `--auto-recover-from-snapshot` flag is properly configured -- **New** Check snapshot directory permissions for automatic recovery access -- **New** Monitor recovery logs for corruption detection and restoration success - -### Snapshot Management Troubleshooting -**Updated** Specific troubleshooting for snapshot management issues: -- Verify snapshot directory exists and is writable -- Check snapshot rotation configuration with `--snapshot-max-age-days` -- Validate periodic snapshot creation with `--snapshot-every-n-blocks` -- Test snapshot serving configuration with `--allow-snapshot-serving` -- Configure trusted peers properly with `--trusted-snapshot-peer` -- Monitor snapshot P2P sync performance and reliability - -### Enhanced Logging Troubleshooting -**Updated** Specific troubleshooting for logging issues: -- Verify terminal supports ANSI escape codes for color output -- Check logging configuration for proper color scheme setup -- Ensure color codes are properly formatted in log messages -- Test color output in different terminal environments -- Verify color codes are stripped when logging to files -- Check for proper terminal reset sequences after color output - -### Sync Mode Troubleshooting -**Updated** Specific troubleshooting for sync mode logging: -- Verify green color appears for sync start and completion messages -- Check yellow/brown color for periodic sync progress notifications -- Ensure sync mode status messages appear only during active synchronization -- Verify sync mode completion messages reset properly when normal blocks arrive -- Check that sync mode guard variables work correctly to prevent duplicate messages - -### Automatic Recovery System Troubleshooting -**New** Specific troubleshooting for automatic recovery system issues: -- Verify `--auto-recover-from-snapshot` flag is enabled in configuration -- Check snapshot directory accessibility for automatic recovery operations -- Monitor recovery logs for corruption detection and restoration attempts -- Verify snapshot plugin is properly configured for recovery callbacks -- Test recovery system by simulating shared memory corruption scenarios -- Check DLT block log availability for incremental recovery after snapshot restoration - -**Section sources** -- [plugin.cpp:562-601](file://plugins/chain/plugin.cpp#L562-L601) -- [plugin.cpp:251-271](file://plugins/chain/plugin.cpp#L251-L271) - -## Conclusion -The Chain Plugin provides a robust foundation for blockchain state management in the VIZ node. Its modular design, comprehensive configuration options, and efficient database operations make it suitable for production deployments while maintaining flexibility for development and testing scenarios. Recent enhancements focus on improved plugin coordination with deferred execution support, comprehensive recovery system integration with DLT block log capabilities, and sophisticated snapshot loading mechanisms. The plugin's integration with snapshot technology, emergency consensus mode, and advanced recovery procedures provides strong operational resilience and enhanced error handling capabilities with improved plugin coordination and seamless user experience. - -**Updated** The default shared-memory directory has been changed from 'blockchain' to 'state' for better organizational clarity, ensuring consistency across data directory usage in plugin initialization and snapshot plugin deferred loading functionality. The comprehensive snapshot management infrastructure provides powerful automation capabilities including automatic discovery, periodic creation, rotation, serving, and P2P synchronization with trust models and anti-spam protection. The enhanced logging system significantly improves debugging experience through color-coded console output, providing immediate visual feedback for sync mode status and progress indicators with green color for important completion messages and yellow/brown for periodic progress notifications. - -**New** The comprehensive automatic recovery system represents a major advancement in operational resilience, providing seamless protection against shared memory corruption scenarios. The system automatically detects corruption during both startup and runtime, immediately initiates recovery procedures, and restores node operation with minimal downtime. This system includes sophisticated snapshot discovery, validation, and restoration mechanisms, along with incremental DLT block log replay for complete state consistency. The recovery system is fully configurable and can be enabled or disabled based on operational requirements, providing operators with control over their recovery strategy while ensuring maximum uptime and data integrity. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Configuration Management/Build Configuration.md b/.qoder/repowiki/en/content/Configuration Management/Build Configuration.md deleted file mode 100644 index f8f2d77d00..0000000000 --- a/.qoder/repowiki/en/content/Configuration Management/Build Configuration.md +++ /dev/null @@ -1,508 +0,0 @@ -# Build Configuration - - -**Referenced Files in This Document** -- [.gitmodules](file://.gitmodules) -- [thirdparty/fc/.gitmodules](file://thirdparty/fc/.gitmodules) -- [thirdparty/fc/CMakeLists.txt](file://thirdparty/fc/CMakeLists.txt) -- [thirdparty/chainbase/CMakeLists.txt](file://thirdparty/chainbase/CMakeLists.txt) -- [thirdparty/appbase/CMakeLists.txt](file://thirdparty/appbase/CMakeLists.txt) -- [CMakeLists.txt](file://CMakeLists.txt) -- [building.md](file://documentation/building.md) -- [.travis.yml](file://.travis.yml) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt) -- [programs/CMakeLists.txt](file://programs/CMakeLists.txt) -- [thirdparty/CMakeLists.txt](file://thirdparty/CMakeLists.txt) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt) -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) - - -## Update Summary -**Changes Made** -- Updated shared library configuration documentation to reflect consistent static library builds across all platforms -- Added comprehensive coverage of the BUILD_SHARED_LIBRARIES=OFF setting and its implications -- Enhanced platform-specific build behavior documentation for Linux, macOS, and Windows -- Updated Docker configuration references to show consistent static linking approach -- Revised build script documentation to highlight the unified static library approach - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the build configuration for VIZ CPP Node, focusing on the CMake build system, available build options, compiler flags, feature toggles, cross-platform compilation, dependency management, and third-party library integration. It also covers build variants (development, production, low-memory, testnet), environment variable requirements, toolchain configuration, and CI integration via Docker and GitHub Actions. Practical examples and troubleshooting guidance are included to help you build reliably across platforms. - -**Updated** Enhanced with comprehensive documentation of the unified static library approach across all platforms, ensuring consistent build behavior and simplified deployment. - -## Project Structure -The repository is organized around a top-level CMake project that orchestrates three major subtrees: -- thirdparty: Internal vendored libraries (appbase, fc, chainbase) with specified branch management -- libraries: Core libraries (api, chain, protocol, network, time, utilities, wallet) -- plugins: Optional plugin modules (e.g., chain, p2p, webserver, mongo_db) -- programs: Executables (vizd, cli_wallet, js_operation_serializer, size_checker, util) - -```mermaid -graph TB -Root["Top-level CMakeLists.txt"] -TP["thirdparty/CMakeLists.txt"] -LIB["libraries/CMakeLists.txt"] -PLG["plugins/CMakeLists.txt"] -PRG["programs/CMakeLists.txt"] -Submods[".gitmodules
Branch Specifications"] -Root --> TP -Root --> LIB -Root --> PLG -Root --> PRG -TP --> Submods -``` - -**Diagram sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -**Section sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -## Core Components -Key build options and toggles configured at the top-level CMake: -- CMAKE_BUILD_TYPE: Selects Release or Debug profiles -- BUILD_SHARED_LIBRARIES: Controls static vs shared library builds (UNIFIED STATIC APPROACH) -- BUILD_TESTNET: Enables testnet configuration via preprocessor defines -- LOW_MEMORY_NODE: Enables low-memory node configuration via preprocessor defines -- CHAINBASE_CHECK_LOCKING: Enables chainbase locking checks via preprocessor defines -- ENABLE_MONGO_PLUGIN: Enables MongoDB plugin and related preprocessor defines -- USE_PCH: Enables precompiled headers via cotire when set -- FULL_STATIC_BUILD: Forces static linking flags on Windows and Linux -- ENABLE_INSTALLER: Enables CPack packaging configuration (optional) - -**Updated** The BUILD_SHARED_LIBRARIES option is now consistently set to OFF across all build environments to ensure uniform static library behavior. - -Compiler and toolchain behavior: -- Minimum compiler versions enforced for GCC and Clang -- Platform-specific flags for MSVC, MinGW, Apple, and Linux -- Optional ccache launchers for compile and link stages -- Coverage instrumentation toggle -- Git revision injection for version metadata - -Platform specifics: -- Windows: Boost static linkage, MSVC/MinGW flags, TCL detection, static-linking options -- macOS: Shared libraries enabled by default, static linking available via --static flag -- Linux: Static libraries enabled by default through build scripts, static linking available via --static flag -- All platforms: Unified approach to ensure consistent deployment characteristics - -**Section sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [building.md:3-212](file://documentation/building.md#L3-L212) - -## Architecture Overview -The build system composes the final executable by linking together internal libraries and plugins, then installs the runtime artifacts. The vizd executable links against appbase, graphene core libraries, and enabled plugins. - -```mermaid -graph TB -subgraph "Build Targets" -VIZD["vizd (executable)"] -LIBS["Core Libraries
api, chain, protocol, network, time, utilities, wallet"] -PLUGINS["Plugins
chain, p2p, webserver, ..."] -THIRDPARTY["Third-party
appbase, fc, chainbase"] -SUBMODULES["Submodule Dependencies
Branch Specifications"] -end -VIZD --> LIBS -VIZD --> PLUGINS -VIZD --> THIRDPARTY -THIRDPARTY --> SUBMODULES -``` - -**Diagram sources** -- [programs/vizd/CMakeLists.txt:16-49](file://programs/vizd/CMakeLists.txt#L16-L49) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -## Detailed Component Analysis - -### Top-Level CMake Configuration -Highlights: -- Enforces minimum compiler versions for GCC and Clang -- Configures module paths for custom Find modules and Git version generation -- Sets export of compile_commands.json for tooling support -- Defines Boost components and static-linking preference -- Provides feature toggles (BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, ENABLE_MONGO_PLUGIN) -- Adds platform-specific compiler/linker flags and optional ccache -- Adds subdirectories for thirdparty, libraries, plugins, and programs -- Supports CPack packaging when enabled - -**Updated** The BUILD_SHARED_LIBRARIES option is now set to OFF by default, ensuring consistent static library behavior across all platforms and build methods. - -Common build invocations: -- Release build: cmake -DCMAKE_BUILD_TYPE=Release .. -- Low-memory node: cmake -DLowMemoryNode=TRUE .. -- Testnet build: cmake -DBUILD_TESTNET=TRUE .. -- Enable MongoDB plugin: cmake -DENABLE_MONGO_PLUGIN=TRUE .. -- Static build (all platforms): cmake -DBUILD_SHARED_LIBRARIES=OFF .. - -Environment variables: -- BOOST_ROOT (Windows): points to Boost installation -- TCL_ROOT (Windows): points to TCL include directory -- OPENSSL_ROOT_DIR (macOS): points to OpenSSL installation -- CCACHE: enables transparent caching of compilation/linking - -Toolchains and generators: -- Ninja generator benefits from color diagnostics on Clang -- Visual Studio and MinGW toolchains supported per documentation - -**Section sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [building.md:3-212](file://documentation/building.md#L3-L212) - -### Build Variants and Feature Toggles -- Debug vs Release: controlled by CMAKE_BUILD_TYPE; debug adds a debug macro and may enable coverage instrumentation when toggled -- Low-memory node: reduces storage footprint by disabling non-consensus data fields -- Testnet: switches to testnet configuration and seeds -- Chainbase locking checks: enables additional synchronization assertions -- MongoDB plugin: compiles and links the mongo_db plugin with appropriate preprocessor defines -- Static vs shared libraries: BUILD_SHARED_LIBRARIES controls library type (UNIFIED STATIC APPROACH) -- Full static build: FULL_STATIC_BUILD forces static linking flags on supported platforms - -**Updated** All build variants now consistently use static libraries (BUILD_SHARED_LIBRARIES=OFF) to ensure uniform deployment characteristics across environments. - -Preprocessor defines injected at configure time: -- BUILD_TESTNET, IS_LOW_MEM, CHAINBASE_CHECK_LOCKING, MONGODB_PLUGIN_BUILT - -**Section sources** -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) -- [CMakeLists.txt:196-208](file://CMakeLists.txt#L196-L208) - -### Cross-Platform Compilation -- Linux: - - C++ standard set to C++14 - - Threading and realtime libraries linked conditionally - - Optional static linking flags - - Ninja generator gains color diagnostics - - **Static libraries enabled by default through build scripts** -- macOS: - - Uses libc++ and shared libraries by default - - Static linking available via --static flag in build-mac.sh - - Optional TCMalloc discovery via gperftools -- Windows: - - MSVC flags: disables safe-seh, ensures debug info in Debug - - MinGW flags: C++11, permissiveness, SSE4.2, big object support, optimized debug flags - - TCL detection and adjusted library naming - - **Static libraries enabled by default through build scripts** - -**Updated** All platforms now use a unified approach with static libraries enabled by default, ensuring consistent behavior and simplified deployment. - -Dependencies: -- Boost 1.71+ required across all thirdparty libraries (appbase, chainbase, fc) -- Special handling for Boost 1.53 on Windows -- OpenSSL (via find_package or explicit root on macOS) -- Readline on Unix-like systems -- Optional: MongoDB C/C++ drivers when enabling the plugin - -**Section sources** -- [CMakeLists.txt:91-202](file://CMakeLists.txt#L91-L202) -- [building.md:25-212](file://documentation/building.md#L25-L212) -- [thirdparty/fc/CMakeLists.txt:115-130](file://thirdparty/fc/CMakeLists.txt#L115-L130) -- [thirdparty/chainbase/CMakeLists.txt](file://thirdparty/chainbase/CMakeLists.txt#L28) -- [thirdparty/appbase/CMakeLists.txt](file://thirdparty/appbase/CMakeLists.txt#L21) - -### Enhanced Submodule Management and Dependency Resolution - -#### Third-Party Submodule Branch Specifications -The repository now maintains explicit branch specifications for thirdparty submodules to ensure consistent dependency resolution: - -- fc submodule: Branch `update` for enhanced functionality -- chainbase submodule: Branch `lib-boost-1.71` for Boost 1.71 compatibility -- appbase submodule: Branch `lib-boost-1.71` for Boost 1.71 compatibility - -These branch specifications ensure that all thirdparty dependencies align with the required Boost 1.71 version and receive the latest updates for their respective functionality. - -#### fc Submodule Vendor Dependencies -The fc library manages its own vendor dependencies through nested submodules: -- websocketpp: WebSocket protocol implementation -- diff-match-patch-cpp-stl: Text comparison utilities -- secp256k1-zkp: Cryptographic elliptic curve implementation - -These dependencies are automatically managed during the fc build process and integrated into the final library. - -#### Streamlined Docker Configuration -The Docker build system has been streamlined to support multiple deployment variants with consistent static library approach: -- Production builds with Release configuration and static linking -- Testnet builds with testnet-specific configuration and static linking -- Low-memory builds optimized for resource-constrained environments with static linking -- MongoDB-enabled builds with database integration support and static linking - -**Updated** All Docker configurations now consistently use BUILD_SHARED_LIBRARIES=FALSE to ensure uniform behavior across containerized deployments. - -**Section sources** -- [.gitmodules:1-13](file://.gitmodules#L1-L13) -- [thirdparty/fc/.gitmodules:1-10](file://thirdparty/fc/.gitmodules#L1-L10) -- [thirdparty/fc/CMakeLists.txt:51-101](file://thirdparty/fc/CMakeLists.txt#L51-L101) -- [thirdparty/chainbase/CMakeLists.txt](file://thirdparty/chainbase/CMakeLists.txt#L28) -- [thirdparty/appbase/CMakeLists.txt](file://thirdparty/appbase/CMakeLists.txt#L21) - -### Dependency Management and Third-Party Integration -- Boost: 1.71+ required across all thirdparty libraries (appbase, chainbase, fc) -- OpenSSL: found automatically or via OPENSSL_ROOT_DIR on macOS -- Readline: optional on Unix-like systems -- gperftools: optional TCMalloc usage on Unix-like systems -- MongoDB: optional; when enabled, the mongo_c driver and mongo_cxx driver are built and linked - -**Updated** All thirdparty libraries now enforce Boost 1.71+ requirement, with specific branch targeting for compatibility and feature alignment. - -**Section sources** -- [CMakeLists.txt:97-104](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt:160-183](file://CMakeLists.txt#L160-L183) -- [CMakeLists.txt:106-110](file://CMakeLists.txt#L106-L110) -- [programs/vizd/CMakeLists.txt:10-14](file://programs/vizd/CMakeLists.txt#L10-L14) -- [thirdparty/fc/CMakeLists.txt:115-130](file://thirdparty/fc/CMakeLists.txt#L115-L130) -- [thirdparty/chainbase/CMakeLists.txt](file://thirdparty/chainbase/CMakeLists.txt#L28) -- [thirdparty/appbase/CMakeLists.txt](file://thirdparty/appbase/CMakeLists.txt#L21) - -### Executable Linkage (vizd) -The vizd executable links against: -- appbase and fc -- Core graphene libraries and plugins -- Optional MongoDB library when enabled -- Platform-specific libraries (readline on macOS/Unix, tcmalloc if found) - -Installation: -- Runtime, library, and archive targets are installed under standard prefixes - -**Section sources** -- [programs/vizd/CMakeLists.txt:1-58](file://programs/vizd/CMakeLists.txt#L1-L58) - -### Continuous Integration and Packaging -- Travis CI: - - Builds multiple Docker images for production, test, testnet, lowmem, and mongo variants - - Matrix builds tag/branch-aware image names - - Pushes images to registry on success -- GitHub Actions: - - Builds production and testnet Docker images on master branch pushes - - Uses Docker's build-push action with credentials from secrets - -**Updated** Docker configurations have been streamlined to support the enhanced submodule management and improved dependency resolution with consistent static library approach. - -Dockerfiles: -- Production: Release build with shared libs disabled, minimal flags -- Testnet: Same as production plus BUILD_TESTNET -- Low-memory: Same as production plus LOW_MEMORY_NODE -- Mongo: Installs MongoDB C/C++ drivers and enables ENABLE_MONGO_PLUGIN - -**Section sources** -- [.travis.yml:1-46](file://.travis.yml#L1-L46) -- [.github/workflows/docker-main.yml:1-41](file://.github/workflows/docker-main.yml#L1-L41) -- [share/vizd/docker/Dockerfile-testnet:46-54](file://share/vizd/docker/Dockerfile-testnet#L46-L54) -- [share/vizd/docker/Dockerfile-lowmem:45-53](file://share/vizd/docker/Dockerfile-lowmem#L45-L53) -- [share/vizd/docker/Dockerfile-mongo:74-82](file://share/vizd/docker/Dockerfile-mongo#L74-L82) - -## Dependency Analysis -The build system composes targets in a layered fashion. The top-level CMake orchestrates thirdparty, libraries, plugins, and programs. The vizd executable depends on core libraries and selected plugins. - -```mermaid -graph LR -Root["Root CMakeLists.txt"] -TP["thirdparty"] -LIB["libraries"] -PLG["plugins"] -PRG["programs"] -Submods[".gitmodules
Branch Specifications"] -Root --> TP -Root --> LIB -Root --> PLG -Root --> PRG -TP --> Submods -PRG --> VIZD["vizd"] -VIZD --> Core["Core Libraries"] -VIZD --> Plugins["Enabled Plugins"] -VIZD --> Third["Third-party Libraries"] -Third --> Boost["Boost 1.71+"] -Third --> OpenSSL["OpenSSL"] -Third --> Crypto["secp256k1-zkp"] -``` - -**Diagram sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [programs/vizd/CMakeLists.txt:16-49](file://programs/vizd/CMakeLists.txt#L16-L49) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) -- [thirdparty/fc/CMakeLists.txt:115-130](file://thirdparty/fc/CMakeLists.txt#L115-L130) - -**Section sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [programs/vizd/CMakeLists.txt:16-49](file://programs/vizd/CMakeLists.txt#L16-L49) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -## Performance Considerations -- Compiler flags: - - MinGW sets C++11, permissiveness, SSE4.2, and big object support for large translation units - - Linux sets fno-builtin-memcmp for performance-sensitive comparisons - - Ninja with Clang enables color diagnostics for readability -- Caching: - - ccache is detected and used globally for compile and link steps when available -- Static linking: - - FULL_STATIC_BUILD toggles static linking flags on Windows and Linux to reduce runtime dependencies - - **Unified static library approach reduces deployment complexity and improves portability** -- Coverage: - - ENABLE_COVERAGE_TESTING injects coverage flags for analysis workflows -- PCH: - - USE_PCH enables precompiled headers via cotire to speed up rebuilds - -**Updated** The unified static library approach simplifies performance optimization by eliminating shared library dependency issues across different environments. - -**Section sources** -- [CMakeLists.txt:147-156](file://CMakeLists.txt#L147-L156) -- [CMakeLists.txt:186-188](file://CMakeLists.txt#L186-L188) -- [CMakeLists.txt:190-194](file://CMakeLists.txt#L190-L194) -- [CMakeLists.txt:106-110](file://CMakeLists.txt#L106-L110) -- [CMakeLists.txt:204-208](file://CMakeLists.txt#L204-L208) -- [CMakeLists.txt:29-31](file://CMakeLists.txt#L29-L31) - -## Troubleshooting Guide -Common issues and resolutions: -- Boost version mismatch: - - Ubuntu 14.04 Boost in repos is too old; use Boost 1.71 manually installed - - Ubuntu 16.04 modern Boost packages are sufficient - - All thirdparty libraries now require Boost 1.71+ -- macOS Boost/OpenSSL paths: - - Set BOOST_ROOT and OPENSSL_ROOT_DIR to Homebrew locations when using non-system Boost/OpenSSL -- Windows toolchain: - - Ensure TCL_ROOT is set for TCL include path; MSVC flags disable safe-seh and enable debug info in Debug -- MinGW large object sizes: - - Debug builds use increased optimization level to avoid assembler "file too big" errors -- Coverage builds: - - ENABLE_COVERAGE_TESTING requires compatible toolchain and gcov/gcovr availability -- Plugin dependencies: - - Enabling ENABLE_MONGO_PLUGIN requires MongoDB C/C++ drivers; Dockerfile-mongo demonstrates the process -- Submodule branch conflicts: - - Ensure thirdparty submodules are checked out from the correct branches (lib-boost-1.71 for chainbase/appbase, update for fc) -- **Static library deployment issues**: - - **All builds now use static libraries by default, eliminating shared library dependency problems** - - **If encountering runtime linking issues, verify the unified static library approach is being used** - -**Updated** Added troubleshooting guidance for the unified static library approach and deployment-related issues. - -**Section sources** -- [building.md:76-137](file://documentation/building.md#L76-L137) -- [building.md:138-199](file://documentation/building.md#L138-L199) -- [CMakeLists.txt:91-156](file://CMakeLists.txt#L91-L156) -- [CMakeLists.txt:204-208](file://CMakeLists.txt#L204-L208) -- [thirdparty/fc/CMakeLists.txt:115-130](file://thirdparty/fc/CMakeLists.txt#L115-L130) -- [thirdparty/chainbase/CMakeLists.txt](file://thirdparty/chainbase/CMakeLists.txt#L28) -- [thirdparty/appbase/CMakeLists.txt](file://thirdparty/appbase/CMakeLists.txt#L21) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -## Conclusion -The VIZ CPP Node build system is designed for portability and flexibility across Linux, macOS, and Windows. It exposes a concise set of CMake options to tailor builds for development, production, testnet, and specialized configurations like low-memory nodes and MongoDB-enabled deployments. The enhanced submodule management ensures consistent dependency resolution with Boost 1.71+ across all thirdparty libraries, while streamlined Docker configurations support automated CI/CD workflows. **The unified static library approach across all platforms eliminates shared library dependency issues and ensures consistent deployment characteristics.** CI pipelines automate reproducible builds using Docker, ensuring consistent outcomes across environments. - -**Updated** The build system now includes enhanced submodule management with branch specifications, improved dependency resolution through Boost 1.71+ enforcement, and a unified static library approach that simplifies deployment across all supported platforms. - -## Appendices - -### Practical Build Scenarios -- Development build (Linux/macOS): - - Configure with Release profile and desired feature toggles - - Example: cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=TRUE .. - - **Static libraries enabled by default for consistent behavior** -- Production deployment (Linux): - - Use Dockerfile-production for a Release build with static linking and minimal flags - - Alternatively, cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBRARIES=OFF .. - - **All production builds use static libraries for simplified deployment** -- Low-memory node: - - cmake -DCMAKE_BUILD_TYPE=Release -DLOW_MEMORY_NODE=TRUE .. - - **Static libraries enabled for optimal performance** -- Testnet node: - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=TRUE .. - - **Consistent static library approach across all testnet deployments** -- MongoDB-enabled node: - - Build Dockerfile-mongo or cmake -DENABLE_MONGO_PLUGIN=TRUE .. with drivers installed - - **Static libraries ensure reliable MongoDB plugin deployment** -- Windows (MSVC): - - Ensure Boost and TCL roots are set; use Visual Studio generator - - **Static libraries enabled by default through build scripts** -- Windows (MinGW): - - cmake -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" .. - - **Static libraries enabled by default through build scripts** -- Submodule management: - - Ensure thirdparty submodules are properly initialized: git submodule update --init --recursive - - Verify branch specifications match required versions - -**Updated** Added comprehensive coverage of the unified static library approach across all build scenarios and platforms. - -### Environment Variables Reference -- BOOST_ROOT: Path to Boost installation (Windows) -- TCL_ROOT: Path to TCL include directory (Windows) -- OPENSSL_ROOT_DIR: Path to OpenSSL installation (macOS) -- CCACHE: Presence enables transparent compile/link caching - -### CI Integration Notes -- Travis CI builds multiple Docker images for production, test, testnet, lowmem, and mongo variants -- GitHub Actions builds production and testnet images on master branch pushes - -**Updated** Docker configurations have been streamlined to support the enhanced submodule management and improved dependency resolution with consistent static library approach. - -**Section sources** -- [share/vizd/docker/Dockerfile-testnet:46-54](file://share/vizd/docker/Dockerfile-testnet#L46-L54) -- [share/vizd/docker/Dockerfile-lowmem:45-53](file://share/vizd/docker/Dockerfile-lowmem#L45-L53) -- [share/vizd/docker/Dockerfile-mongo:74-82](file://share/vizd/docker/Dockerfile-mongo#L74-L82) -- [.travis.yml:12-42](file://.travis.yml#L12-L42) -- [.github/workflows/docker-main.yml:11-41](file://.github/workflows/docker-main.yml#L11-L41) -- [.gitmodules:1-13](file://.gitmodules#L1-L13) - -### Platform-Specific Build Behavior - -#### Linux Build Scripts -- **Default behavior**: Static libraries enabled (SHARED_LIBS="OFF") -- **Command-line option**: --static flag enables static linking -- **Build type**: Release by default with optional Debug -- **Feature toggles**: Low memory, testnet, MongoDB plugin support - -#### macOS Build Scripts -- **Default behavior**: Shared libraries enabled (SHARED_LIBS="ON") -- **Command-line option**: --static flag switches to static linking -- **Build type**: Release by default with optional Debug -- **Feature toggles**: Low memory, testnet support - -#### Windows Build Scripts -- **Default behavior**: Static libraries enabled (BUILD_SHARED_LIBRARIES=OFF) -- **Build type**: Release by default with optional Debug -- **Feature toggles**: Low memory, testnet, MongoDB plugin support - -**Updated** Platform-specific behaviors now reflect the unified static library approach, with macOS and Windows maintaining backward compatibility through command-line options. - -**Section sources** -- [build-linux.sh:39](file://build-linux.sh#L39) -- [build-mac.sh:35](file://build-mac.sh#L35) -- [build-mingw.bat:99](file://build-mingw.bat#L99) -- [build-msvc.bat:91](file://build-msvc.bat#L91) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Configuration Management/Configuration Management.md b/.qoder/repowiki/en/content/Configuration Management/Configuration Management.md deleted file mode 100644 index f6121ac762..0000000000 --- a/.qoder/repowiki/en/content/Configuration Management/Configuration Management.md +++ /dev/null @@ -1,662 +0,0 @@ -# Configuration Management - - -**Referenced Files in This Document** -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [vizd.sh](file://share/vizd/vizd.sh) -- [main.cpp](file://programs/vizd/main.cpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [building.md](file://documentation/building.md) -- [testnet.md](file://documentation/testnet.md) -- [plugin.md](file://documentation/plugin.md) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [application.cpp](file://thirdparty/appbase/application.cpp) - - -## Update Summary -**Changes Made** -- Updated snapshot directory default behavior section to reflect new data-directory-based default location -- Added documentation for enhanced snapshot configuration including trusted-snapshot-peer integration -- Updated snapshot configuration examples to show new default behavior and trusted peer options -- Enhanced troubleshooting guidance for snapshot-related configuration issues - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the configuration management system for VIZ CPP Node. It explains configuration file structure, runtime parameters, environment variable overrides, node types (full node, validator node, low-memory node), network configuration, plugin activation, performance tuning, logging, Docker-specific configuration, build-time options, and troubleshooting guidance. Practical deployment scenarios (production, testnet, development) are included. - -## Project Structure -The configuration system centers around: -- A primary configuration file template for mainnet -- Testnet-specific configuration -- validator-specific configuration -- MongoDB-enabled configuration variants -- Dockerfiles for production, testnet, and low-memory builds -- A container entrypoint script that supports environment variable overrides -- The node binary's program options and logging configuration loader - -```mermaid -graph TB -cfg_main["Config Template
share/vizd/config/config.ini"] -cfg_test["Testnet Config
share/vizd/config/config_testnet.ini"] -cfg_wit["validator Config
share/vizd/config/config_witness.ini"] -cfg_mongo["Mongo Config
share/vizd/config/config_mongo.ini"] -cfg_dbg["Debug Config
share/vizd/config/config_debug.ini"] -cfg_dbg_mongo["Debug+Mongo Config
share/vizd/config/config_debug_mongo.ini"] -df_prod["Dockerfile-production
share/vizd/docker/Dockerfile-production"] -df_test["Dockerfile-testnet
share/vizd/docker/Dockerfile-testnet"] -df_lowmem["Dockerfile-lowmem
share/vizd/docker/Dockerfile-lowmem"] -entry["Container Entrypoint
share/vizd/vizd.sh"] -node["Node Binary
programs/vizd/main.cpp"] -cfg_main --> node -cfg_test --> node -cfg_wit --> node -cfg_mongo --> node -cfg_dbg --> node -cfg_dbg_mongo --> node -df_prod --> entry -df_test --> entry -df_lowmem --> entry -entry --> node -``` - -**Diagram sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [Dockerfile-production:1-88](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet:1-88](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem:1-82](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- [main.cpp:106-158](file://programs/vizd/main.cpp#L106-L158) - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [Dockerfile-production:1-88](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet:1-88](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem:1-82](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- [main.cpp:106-158](file://programs/vizd/main.cpp#L106-L158) - -## Core Components -- Configuration file format: INI-style with sections for logging appenders and loggers. -- Runtime parameters: Passed via program options and loaded from configuration. -- Environment variable overrides: Container entrypoint sets CLI flags based on environment variables. -- Plugin activation: Controlled via configuration entries. -- Logging configuration: Program options and INI sections define appenders and logger routing. - -Key configuration categories: -- Network endpoints and connectivity -- RPC endpoints (HTTP/WebSocket) -- Lock/wait tuning for database operations -- Shared memory sizing and growth policy -- Plugin list and activation -- validator production controls -- Logging configuration -- **Snapshot configuration** (updated with new default behavior) - -**Section sources** -- [main.cpp:167-191](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp:194-289](file://programs/vizd/main.cpp#L194-L289) -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) - -## Architecture Overview -The configuration pipeline integrates configuration files, program options, and environment variables to initialize the node. - -```mermaid -sequenceDiagram -participant Entrypoint as "Container Entrypoint
vizd.sh" -participant Env as "Environment Variables" -participant Node as "Node Binary
main.cpp" -participant Config as "INI Loader
load_config_sections/load_logging_config" -Entrypoint->>Env : Read VIZD_* variables -Entrypoint->>Node : Pass CLI flags (--p2p-endpoint, --rpc-endpoint,
--p2p-seed-node, --validator, --private-key) -Node->>Node : Parse program options -Node->>Config : Load logging config from config path -Config-->>Node : fc : : logging_config -Node->>Node : Configure logging and startup -``` - -**Diagram sources** -- [vizd.sh:13-81](file://share/vizd/vizd.sh#L13-L81) -- [main.cpp:112-139](file://programs/vizd/main.cpp#L112-L139) -- [main.cpp:194-289](file://programs/vizd/main.cpp#L194-L289) - -## Detailed Component Analysis - -### Configuration File Structure and Sections -- Logging appenders: - - Console appenders - - File appenders -- Loggers: - - Route loggers to specific appenders with levels - -These sections are parsed by the node to configure logging at startup. - -**Section sources** -- [main.cpp:167-191](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp:211-289](file://programs/vizd/main.cpp#L211-L289) -- [config.ini:118-136](file://share/vizd/config/config.ini#L118-L136) - -### Runtime Parameters and Program Options -Program options include logging configuration and standard node options. The node parses configuration files and applies logging settings accordingly. - -**Section sources** -- [main.cpp:112-139](file://programs/vizd/main.cpp#L112-L139) -- [main.cpp:167-191](file://programs/vizd/main.cpp#L167-L191) - -### Environment Variable Overrides (Docker) -The container entrypoint supports the following environment variables: -- VIZD_SEED_NODES: Comma-separated seed nodes -- VIZD_WITNESS_NAME: validator name to operate -- VIZD_PRIVATE_KEY: Private key for signing -- VIZD_RPC_ENDPOINT: Override RPC endpoint -- VIZD_P2P_ENDPOINT: Override P2P endpoint -- VIZD_EXTRA_OPTS: Additional arguments appended to node invocation - -These variables override defaults and inject CLI flags at runtime. - -**Section sources** -- [vizd.sh:17-37](file://share/vizd/vizd.sh#L17-L37) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- [vizd.sh:74-81](file://share/vizd/vizd.sh#L74-L81) - -### Node Types and Their Configuration Requirements -- Full node (mainnet): - - Uses the main configuration template with default plugin sets suitable for full synchronization and API exposure. -- Testnet: - - Includes testnet-specific defaults and enables stale production for continuous block production. -- validator node: - - Activates validator and witness_api plugins, binds RPC endpoints to localhost by default, and includes validator credentials. -- Low-memory node: - - Built with a dedicated flag to reduce memory footprint; Dockerfile demonstrates enabling this build-time option. - -```mermaid -flowchart TD -Start(["Select Node Type"]) --> Full["Full Node
Mainnet"] -Start --> Testnet["Testnet Node"] -Start --> validator["validator Node"] -Start --> LowMem["Low-Memory Node"] -Full --> FullCfg["Use config.ini"] -Testnet --> TestCfg["Use config_testnet.ini"] -validator --> WitCfg["Use config_witness.ini"] -LowMem --> LowMemFlag["Build with LOW_MEMORY_NODE=TRUE"] -``` - -**Diagram sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [Dockerfile-lowmem:45-51](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) -- [building.md:11-15](file://documentation/building.md#L11-L15) - -**Section sources** -- [config.ini:73-85](file://share/vizd/config/config.ini#L73-L85) -- [config_testnet.ini:69-73](file://share/vizd/config/config_testnet.ini#L69-L73) -- [config_witness.ini:72-84](file://share/vizd/config/config_witness.ini#L72-L84) -- [building.md:11-15](file://documentation/building.md#L11-L15) -- [Dockerfile-lowmem:45-51](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) - -### Network Configuration -Network settings include: -- P2P endpoint binding and maximum connections -- Seed nodes for initial connectivity -- Checkpoint enforcement for block safety -- Peer connection and sync behavior governed by network constants - -```mermaid -flowchart TD -NetCfg["Network Settings"] --> P2PEndpoint["P2P Endpoint"] -NetCfg --> MaxConns["Max Incoming Connections"] -NetCfg --> SeedNodes["Seed Nodes"] -NetCfg --> Checkpoints["Block Checkpoints"] -P2PEndpoint --> PeerConn["Peer Connection Logic"] -MaxConns --> PeerConn -SeedNodes --> PeerConn -PeerConn --> Sync["Sync Behavior
network config constants"] -``` - -**Diagram sources** -- [config.ini:1-16](file://share/vizd/config/config.ini#L1-L16) -- [config_testnet.ini:1-11](file://share/vizd/config/config_testnet.ini#L1-L11) -- [config_witness.ini:1-15](file://share/vizd/config/config_witness.ini#L1-L15) -- [config.hpp:54-56](file://libraries/network/include/graphene/network/config.hpp#L54-L56) -- [config.hpp:105-106](file://libraries/network/include/graphene/network/config.hpp#L105-L106) - -**Section sources** -- [config.ini:1-16](file://share/vizd/config/config.ini#L1-L16) -- [config_testnet.ini:1-11](file://share/vizd/config/config_testnet.ini#L1-L11) -- [config_witness.ini:1-15](file://share/vizd/config/config_witness.ini#L1-L15) -- [config.hpp:54-56](file://libraries/network/include/graphene/network/config.hpp#L54-L56) -- [config.hpp:105-106](file://libraries/network/include/graphene/network/config.hpp#L105-L106) - -### Plugin Activation and Configuration -Plugins are activated via configuration entries. The node registers all built-in plugins and loads the configured set at startup. Some plugins maintain persistent state and may require replay when toggled. - -- Example plugin lists appear in the configuration templates. -- The plugin documentation outlines enabling/disabling and replay requirements. - -**Section sources** -- [config.ini:73-85](file://share/vizd/config/config.ini#L73-L85) -- [config_testnet.ini:69-73](file://share/vizd/config/config_testnet.ini#L69-L73) -- [config_witness.ini:72-84](file://share/vizd/config/config_witness.ini#L72-L84) -- [plugin.md:14-18](file://documentation/plugin.md#L14-L18) - -### Performance Tuning Parameters -Key tunables include: -- Thread pool size for RPC clients -- Read/write lock wait durations and retries -- Single-threaded write mode for database operations -- Skipping plugin notifications on push transactions -- Shared memory size, minimum free space, increment, and free-space check frequency - -These parameters influence throughput and stability under load. - -**Section sources** -- [config.ini:17-72](file://share/vizd/config/config.ini#L17-L72) -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) - -### Logging Configuration -Logging is configured via INI sections for appenders and loggers. The node exposes program options to define console/file appenders and logger routing. - -- Console and file appenders -- Logger levels and appender assignments - -**Section sources** -- [config.ini:118-136](file://share/vizd/config/config.ini#L118-L136) -- [main.cpp:167-191](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp:211-289](file://programs/vizd/main.cpp#L211-L289) - -### Snapshot Configuration and Default Directory Behavior - -**Updated** The snapshot plugin now uses a data-directory-based default location instead of the current working directory fallback: - -#### Default Directory Behavior -- **New default**: When `snapshot-dir` is not explicitly configured, the system now defaults to `/snapshots` instead of the current working directory -- **Data directory resolution**: The data directory is determined by the application's data_dir() method, typically located at `/var/lib/vizd` for production containers -- **Automatic creation**: The default snapshot directory is automatically created if it doesn't exist - -#### Enhanced Trusted Peer Integration -The snapshot plugin now includes comprehensive trusted peer configuration options: - -- **Trusted snapshot peers**: List of seed nodes that can serve snapshots to this node -- **Snapshot serving restrictions**: Control who can download snapshots from this node -- **Anti-spam protection**: Built-in rate limiting and connection management for snapshot serving -- **DLT mode support**: Optimized for distributed ledger technology nodes without full block history - -#### Configuration Examples - -**Basic snapshot configuration**: -```ini -plugin = snapshot -snapshot-dir = /var/lib/vizd/snapshots -snapshot-every-n-blocks = 2400 -snapshot-max-age-days = 2 -``` - -**Trusted peer configuration**: -```ini -plugin = snapshot -sync-snapshot-from-trusted-peer = true -trusted-snapshot-peer = 185.45.192.155:8092 -trusted-snapshot-peer = 62.109.17.82:8092 -snapshot-dir = /var/lib/vizd/snapshots -``` - -**Snapshot serving configuration**: -```ini -plugin = snapshot -allow-snapshot-serving = true -allow-snapshot-serving-only-trusted = false -snapshot-serve-endpoint = 0.0.0.0:8092 -snapshot-dir = /var/lib/vizd/snapshots -``` - -**Section sources** -- [plugin.cpp:2974-2983](file://plugins/snapshot/plugin.cpp#L2974-L2983) -- [plugin.cpp:3044-3050](file://plugins/snapshot/plugin.cpp#L3044-L3050) -- [plugin.cpp:3070-3090](file://plugins/snapshot/plugin.cpp#L3070-L3090) -- [plugin.cpp:352-355](file://plugins/chain/plugin.cpp#L352-L355) -- [application.cpp:298-300](file://thirdparty/appbase/application.cpp#L298-L300) -- [snapshot-plugin.md:1-365](file://documentation/snapshot-plugin.md#L1-L365) - -### Docker-Specific Configuration -- Production image: - - Copies main configuration and seednodes into /etc/vizd - - Exposes RPC and P2P ports - - Mounts persistent volumes for data and config -- Testnet image: - - Uses testnet configuration and snapshot - - Enables testnet build flag -- Low-memory image: - - Enables low-memory build flag - -```mermaid -graph TB -subgraph "Docker Images" -prod["Production Image"] -test["Testnet Image"] -lowmem["Low-Memory Image"] -end -prod --> vol1["Volumes:
/var/lib/vizd, /etc/vizd"] -test --> vol1 -lowmem --> vol1 -prod --> ports["Expose:
8090, 8091, 2001"] -test --> ports -lowmem --> ports -``` - -**Diagram sources** -- [Dockerfile-production:74-87](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet:75-87](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-lowmem:68-81](file://share/vizd/docker/Dockerfile-lowmem#L68-L81) - -**Section sources** -- [Dockerfile-production:74-87](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet:75-87](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-lowmem:68-81](file://share/vizd/docker/Dockerfile-lowmem#L68-L81) - -### Build-Time Configuration Options -Build-time flags and toggles: -- LOW_MEMORY_NODE: Builds a consensus-only low-memory node -- BUILD_TESTNET: Enables testnet-specific defaults -- CHAINBASE_CHECK_LOCKING: Debugging toggle -- ENABLE_MONGO_PLUGIN: Feature toggle for MongoDB plugin - -These are set via CMake flags in Dockerfiles and documented in the building guide. - -**Section sources** -- [building.md:11-15](file://documentation/building.md#L11-L15) -- [Dockerfile-production:46-52](file://share/vizd/docker/Dockerfile-production#L46-L52) -- [Dockerfile-testnet:46-52](file://share/vizd/docker/Dockerfile-testnet#L46-L52) -- [Dockerfile-lowmem:45-51](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) - -### Practical Configuration Scenarios - -- Production deployment (mainnet) - - Use the main configuration template and production Docker image. - - Persist data via mounted volumes. - - Optionally override endpoints and seed nodes via environment variables. - - **Updated**: Snapshot directory will default to `/var/lib/vizd/snapshots` if not explicitly configured. - -- Testnet setup - - Use the testnet Docker image and configuration. - - The testnet image enables testnet build flags and uses a testnet snapshot. - - **Updated**: Trusted snapshot peers are pre-configured for testnet bootstrap. - -- Development environment - - Use the debug configuration templates to enable additional plugins and adjust logging. - - Optionally enable MongoDB plugin configuration. - -- validator node - - Use the validator configuration template and bind RPC endpoints to localhost. - - Provide validator name and private key via environment variables. - - **Updated**: Snapshot configuration supports validator-aware deferral to prevent missed production slots. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [Dockerfile-production:74-87](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet:75-87](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [testnet.md:21-37](file://documentation/testnet.md#L21-L37) - -## Dependency Analysis -Configuration dependencies and interactions: -- The node binary depends on the configuration loader to parse logging and runtime settings. -- Docker entrypoint depends on environment variables to inject CLI flags. -- Network behavior is influenced by both configuration and compiled-in network constants. -- **Updated**: Snapshot configuration depends on the application's data_dir() method for default directory resolution. - -```mermaid -graph LR -ConfigINI["INI Config Files"] --> Loader["INI Loader
load_config_sections/load_logging_config"] -Loader --> NodeMain["Node Main
main.cpp"] -Entrypoint["Entrypoint Script
vizd.sh"] --> NodeMain -NodeMain --> Logging["Logging System"] -NodeMain --> Network["Network Constants
config.hpp"] -NodeMain --> DataDir["Data Directory
appbase::app().data_dir()"] -DataDir --> SnapshotDefault["Snapshot Default Dir
/snapshots"] -``` - -**Diagram sources** -- [main.cpp:194-289](file://programs/vizd/main.cpp#L194-L289) -- [vizd.sh:13-81](file://share/vizd/vizd.sh#L13-L81) -- [config.hpp:54-56](file://libraries/network/include/graphene/network/config.hpp#L54-L56) -- [application.cpp:298-300](file://thirdparty/appbase/application.cpp#L298-L300) - -**Section sources** -- [main.cpp:194-289](file://programs/vizd/main.cpp#L194-L289) -- [vizd.sh:13-81](file://share/vizd/vizd.sh#L13-L81) -- [config.hpp:54-56](file://libraries/network/include/graphene/network/config.hpp#L54-L56) -- [application.cpp:298-300](file://thirdparty/appbase/application.cpp#L298-L300) - -## Performance Considerations -- Tune read/write lock wait parameters to balance latency and contention. -- Use single-threaded writes to reduce database lock contention. -- Adjust shared memory size and growth thresholds to minimize resizing overhead. -- Limit plugin notifications on push transactions to improve responsiveness. -- Select appropriate node type (low-memory) for constrained environments. -- **Updated**: Configure snapshot directory on fast storage for optimal snapshot creation and loading performance. - -## Troubleshooting Guide - -### validator Configuration Issues - -**Updated** The validator configuration defaults have been updated to improve reliability and participation calculations: - -- **enable-stale-production default changed**: The default value for `enable-stale-production` has been changed from `false` to `true`. This means validator nodes will now automatically continue producing blocks even when the chain appears stale, improving network resilience during network partitions or temporary forks. - -- **required-participation calculation**: The `required-participation` parameter now uses the formula `33 * CHAIN_1_PERCENT` instead of a hardcoded percentage. With `CHAIN_1_PERCENT` equal to 100 (representing 1% in the 10000-point scale), this calculates to 3300, which represents 33% participation threshold. - -- **validator production failures**: If validator production is failing, check the participation threshold calculation. The system now requires at least 33% of validators to be participating for block production to continue. - -### Snapshot Configuration Issues - -**Updated** Common snapshot configuration issues and validation techniques: - -- **Snapshot directory default behavior** - - Verify that the data directory is properly mounted in Docker containers - - Check that `/var/lib/vizd/snapshots` exists and has proper permissions - - Use explicit `snapshot-dir` configuration when the default location is not suitable - -- **Trusted peer configuration** - - Verify that trusted snapshot peers are reachable and serving snapshots - - Check firewall rules for port 8092 (snapshot serving) - - Use `test-trusted-seeds` option to diagnose connectivity issues - -- **Snapshot auto-discovery** - - Ensure snapshot files follow the naming convention `snapshot-block-NNNNN.vizjson` - - Verify that snapshot files are readable and not corrupted - - Check that the snapshot directory contains valid snapshot files - -- **Snapshot serving issues** - - Verify that `allow-snapshot-serving` is properly configured - - Check anti-spam settings if clients are being rate-limited - - Monitor snapshot serving logs for connection errors - -Common configuration issues and validation techniques: -- Logging misconfiguration - - Verify INI sections for appenders and loggers. - - Confirm program options for logging are recognized by the node. -- RPC/P2P endpoint conflicts - - Ensure endpoints are reachable and not blocked by firewalls. - - Validate environment variable overrides for endpoints. -- Plugin activation problems - - Confirm plugin entries in configuration. - - Review plugin documentation for replay requirements when toggling stateful plugins. -- Memory and shared file sizing - - Adjust shared file size and growth increments based on observed free space checks. -- Docker volume and permissions - - Ensure persistent volumes are mounted and owned by the node user. - - Confirm snapshot extraction occurs when present. -- validator production issues - - Verify validator name and private key are correctly configured. - - Check participation threshold calculations using the CHAIN_1_PERCENT constant. - - Monitor for "low participation" errors indicating below-threshold validator participation. -- **Updated**: Snapshot configuration issues - - Verify snapshot directory permissions and disk space - - Check snapshot file integrity and naming conventions - - Validate trusted peer connectivity and snapshot availability - -**Section sources** -- [main.cpp:167-191](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp:211-289](file://programs/vizd/main.cpp#L211-L289) -- [config.ini:118-136](file://share/vizd/config/config.ini#L118-L136) -- [plugin.md:14-18](file://documentation/plugin.md#L14-L18) -- [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) -- [validator.cpp:125-130](file://plugins/validator/validator.cpp#L125-L130) -- [config_testnet.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L57-L59) -- [config.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config.hpp#L57-L59) -- [plugin.cpp:2974-2983](file://plugins/snapshot/plugin.cpp#L2974-L2983) -- [plugin.cpp:3044-3050](file://plugins/snapshot/plugin.cpp#L3044-L3050) -- [plugin.cpp:3070-3090](file://plugins/snapshot/plugin.cpp#L3070-L3090) - -## Conclusion -VIZ CPP Node offers a flexible configuration system combining INI-based settings, program options, and environment variable overrides. Different node types and deployment modes are supported through configuration templates and Docker images. Proper tuning of performance and logging parameters ensures reliable operation across production, testnet, and development environments. **Updated**: The snapshot configuration system now provides enhanced default behavior with data-directory-based snapshot directories and comprehensive trusted peer integration for improved bootstrap and distribution capabilities. - -## Appendices - -### Appendix A: Configuration Keys Reference -- Network - - p2p-endpoint - - p2p-max-connections - - p2p-seed-node - - checkpoint -- RPC - - webserver-thread-pool-size - - webserver-http-endpoint - - webserver-ws-endpoint -- Database locks - - read-wait-micro - - max-read-wait-retries - - write-wait-micro - - max-write-wait-retries - - single-write-thread - - enable-plugins-on-push-transaction -- Shared memory - - shared-file-size - - min-free-shared-file-size - - inc-shared-file-size - - block-num-check-free-size -- Plugins - - plugin (repeatable) -- validator - - enable-stale-production (default: true) - - required-participation (default: 33% calculated as 33 * CHAIN_1_PERCENT) - - validator - - private-key -- Logging - - log.console_appender.* - - log.file_appender.* - - logger.* -- **Updated** Snapshot - - snapshot-at-block (default: 0) - - snapshot-every-n-blocks (default: 0) - - snapshot-dir (default: `/snapshots`) - - snapshot-max-age-days (default: 0) - - allow-snapshot-serving (default: false) - - allow-snapshot-serving-only-trusted (default: false) - - snapshot-serve-endpoint (default: 0.0.0.0:8092) - - trusted-snapshot-peer (repeatable) - - sync-snapshot-from-trusted-peer (default: false) - - enable-stalled-sync-detection (default: false) - - stalled-sync-timeout-minutes (default: 5) - - test-trusted-seeds (default: false) - - dlt-block-log-max-blocks (default: 100000) - -**Updated** validator configuration defaults now use improved defaults for better network reliability and accurate participation calculations. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [validator.cpp:125-130](file://plugins/validator/validator.cpp#L125-L130) -- [config_testnet.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L57-L59) -- [config.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config.hpp#L57-L59) -- [plugin.cpp:2974-2983](file://plugins/snapshot/plugin.cpp#L2974-L2983) -- [plugin.cpp:3044-3050](file://plugins/snapshot/plugin.cpp#L3044-L3050) -- [plugin.cpp:3070-3090](file://plugins/snapshot/plugin.cpp#L3070-L3090) - -### Appendix B: Docker Environment Variables -- VIZD_SEED_NODES -- VIZD_WITNESS_NAME -- VIZD_PRIVATE_KEY -- VIZD_RPC_ENDPOINT -- VIZD_P2P_ENDPOINT -- VIZD_EXTRA_OPTS - -**Section sources** -- [vizd.sh:17-37](file://share/vizd/vizd.sh#L17-L37) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- [vizd.sh:74-81](file://share/vizd/vizd.sh#L74-L81) - -### Appendix C: validator Participation Calculation Details - -**New** The validator participation calculation system now uses the CHAIN_1_PERCENT constant for precise percentage calculations: - -- **CHAIN_1_PERCENT definition**: Defined as `CHAIN_100_PERCENT/100` where `CHAIN_100_PERCENT` equals 10000 -- **Participation threshold**: Default required participation is 33% (3300/10000) -- **Calculation method**: `required-participation = 33 * CHAIN_1_PERCENT` -- **Precision**: Uses 10000-point scale for accurate percentage representation - -This change ensures more accurate participation calculations and consistent behavior across mainnet and testnet configurations. - -**Section sources** -- [validator.cpp:125-130](file://plugins/validator/validator.cpp#L125-L130) -- [config_testnet.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L57-L59) -- [config.hpp:57-59](file://libraries/protocol/include/graphene/protocol/config.hpp#L57-L59) - -### Appendix D: Snapshot Configuration Best Practices - -**New** Best practices for snapshot configuration: - -- **Default directory behavior**: The system now defaults to `/snapshots` instead of current working directory -- **Volume mounting**: Ensure `/var/lib/vizd` volume is properly mounted in Docker containers -- **Trusted peer selection**: Choose reliable snapshot peers with good uptime and bandwidth -- **Anti-spam configuration**: Use `allow-snapshot-serving-only-trusted` for private networks -- **Monitoring**: Regularly check snapshot directory disk usage and cleanup old snapshots -- **Security**: Restrict snapshot serving to trusted peers in production environments -- **Performance**: Store snapshots on fast storage devices for optimal loading performance - -**Section sources** -- [plugin.cpp:2974-2983](file://plugins/snapshot/plugin.cpp#L2974-L2983) -- [plugin.cpp:3044-3050](file://plugins/snapshot/plugin.cpp#L3044-L3050) -- [plugin.cpp:3070-3090](file://plugins/snapshot/plugin.cpp#L3070-L3090) -- [snapshot-plugin.md:1-365](file://documentation/snapshot-plugin.md#L1-L365) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Configuration Management/Docker Configuration.md b/.qoder/repowiki/en/content/Configuration Management/Docker Configuration.md deleted file mode 100644 index fa03236047..0000000000 --- a/.qoder/repowiki/en/content/Configuration Management/Docker Configuration.md +++ /dev/null @@ -1,470 +0,0 @@ -# Docker Configuration - - -**Referenced Files in This Document** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [vizd.sh](file://share/vizd/vizd.sh) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [README.md](file://README.md) - - -## Update Summary -**Changes Made** -- Updated compression library dependencies section to reflect libbz2-dev, liblzma-dev, libzstd-dev, and zlib1g-dev additions -- Added documentation for sed command pattern fixes for test subdirectory removal -- Updated base image information to reflect newer phusion/baseimage:noble-1.0.3 variants -- Enhanced dependency analysis to include compression library requirements -- Updated troubleshooting section with compression-related issues - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive Docker configuration guidance for deploying the VIZ C++ Node in containers. It covers available Docker images (production, testnet, low-memory, and MongoDB variants), environment variables, persistent storage via volumes, network exposure, and operational patterns. It also documents image customization, base image selection, security considerations, monitoring and logging, and update procedures. - -## Project Structure -The Docker assets and configuration are organized under share/vizd/docker and share/vizd/config. The runtime bootstrap script is located at share/vizd/vizd.sh. Automated builds are defined in GitHub Actions workflows. - -```mermaid -graph TB -subgraph "Docker Build Artifacts" -DFProd["Dockerfile-production"] -DFTnet["Dockerfile-testnet"] -DFLowMem["Dockerfile-lowmem"] -DFMongo["Dockerfile-mongo"] -end -subgraph "Runtime Configurations" -CfgProd["config.ini"] -CfgTnet["config_testnet.ini"] -CfgMongo["config_mongo.ini"] -CfgDebug["config_debug.ini"] -CfgDebugMongo["config_debug_mongo.ini"] -end -Script["vizd.sh"] -DFProd --> Script -DFTnet --> Script -DFLowMem --> Script -DFMongo --> Script -DFProd --> CfgProd -DFTnet --> CfgTnet -DFMongo --> CfgMongo -DFLowMem --> CfgProd -``` - -**Diagram sources** -- [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103) -- [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103) -- [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -**Section sources** -- [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103) -- [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103) -- [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -## Core Components -- Production image: Built from Dockerfile-production, targeting the mainnet with standard configuration and exposed ports for RPC and P2P. -- Testnet image: Built from Dockerfile-testnet, configured for testnet with pre-set testnet endpoints and plugins. -- Low-memory image: Built from Dockerfile-lowmem, optimized for constrained environments with reduced memory footprint. -- MongoDB-enabled image: Built from Dockerfile-mongo, including MongoDB drivers and enabling the mongo_db plugin with a default connection URI. - -Key runtime behavior is orchestrated by the entrypoint script (vizd.sh), which sets up user permissions, applies environment overrides, initializes optional cached blockchain data, and starts the node with appropriate endpoints and arguments. - -**Section sources** -- [Dockerfile-production:81-103](file://share/vizd/docker/Dockerfile-production#L81-L103) -- [Dockerfile-testnet:82-103](file://share/vizd/docker/Dockerfile-testnet#L82-L103) -- [Dockerfile-lowmem:63-85](file://share/vizd/docker/Dockerfile-lowmem#L63-L85) -- [Dockerfile-mongo:92-114](file://share/vizd/docker/Dockerfile-mongo#L92-L114) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) - -## Architecture Overview -The container architecture consists of: -- Base image: phusion/baseimage:noble-1.0.3 variants for Debian-based environments. -- Build stage: installs build dependencies including compression libraries (libbz2-dev, liblzma-dev, libzstd-dev, zlib1g-dev), clones repository, initializes submodules, removes test subdirectories, builds release binaries, and installs artifacts. -- Runtime stage: creates a non-root user, prepares cache and config directories, exposes RPC and P2P ports, defines persistent volumes, and starts the node via an init service. - -```mermaid -graph TB -Base["phusion/baseimage:noble-1.0.3
Debian-based runtime"] -Builder["Builder Stage
Install deps, build, install"] -Runtime["Runtime Stage
User, cache, config, expose ports, volumes"] -Builder --> Base -Base --> Runtime -``` - -**Diagram sources** -- [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103) -- [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103) -- [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) - -## Detailed Component Analysis - -### Docker Images and Variants -- Production image - - Purpose: Run on the main VIZ network. - - Build parameters: standard build with MongoDB disabled. - - Exposed ports: RPC HTTP (8090), RPC WS (8091), P2P (2001). - - Persistent volumes: /var/lib/vizd (blockchain data), /etc/vizd (configuration). - - Entrypoint script: sets defaults and starts node. - - Reference: [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103), [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98), [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) - -- Testnet image - - Purpose: Run on the testnet. - - Build parameters: BUILD_TESTNET enabled, MongoDB disabled. - - Exposed ports: same as production. - - Persistent volumes: same as production. - - Entrypoint script: same behavior, with testnet-specific defaults. - - Reference: [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103), [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) - -- Low-memory image - - Purpose: Constrained environments. - - Build parameters: LOW_MEMORY_NODE enabled, MongoDB disabled. - - Exposed ports: same as production. - - Persistent volumes: same as production. - - Reference: [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) - -- MongoDB-enabled image - - Purpose: Enable historical indexing and analytics via MongoDB. - - Build parameters: ENABLE_MONGO_PLUGIN enabled, installs MongoDB C/C++ drivers. - - Exposed ports: same as production. - - Persistent volumes: same as production. - - MongoDB URI: configured in the MongoDB-enabled config. - - Reference: [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114), [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -```mermaid -flowchart TD -Start(["Image Build"]) --> DetectVariant{"Variant?"} -DetectVariant --> |Production| ProdBuild["cmake -DENABLE_MONGO_PLUGIN=FALSE
Install artifacts"] -DetectVariant --> |Testnet| TnetBuild["cmake -DBUILD_TESTNET=TRUE
Install artifacts"] -DetectVariant --> |Low-Memory| LowMemBuild["cmake -DLOW_MEMORY_NODE=TRUE
Install artifacts"] -DetectVariant --> |MongoDB| MongoBuild["Install MongoDB drivers
cmake -DENABLE_MONGO_PLUGIN=TRUE
Install artifacts"] -ProdBuild --> RuntimeStage["Prepare user, cache, config
Expose ports, define volumes"] -TnetBuild --> RuntimeStage -LowMemBuild --> RuntimeStage -MongoBuild --> RuntimeStage -RuntimeStage --> Entrypoint["Start via vizd.sh"] -``` - -**Diagram sources** -- [Dockerfile-production:55-74](file://share/vizd/docker/Dockerfile-production#L55-L74) -- [Dockerfile-testnet:55-74](file://share/vizd/docker/Dockerfile-testnet#L55-L74) -- [Dockerfile-lowmem:41-60](file://share/vizd/docker/Dockerfile-lowmem#L41-L60) -- [Dockerfile-mongo:62-90](file://share/vizd/docker/Dockerfile-mongo#L62-L90) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) - -**Section sources** -- [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103) -- [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103) -- [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) - -### Environment Variables -The container supports the following environment variables to customize runtime behavior: -- VIZD_SEED_NODES: Space-delimited list of seed nodes to connect to at startup. Overrides default seed list. -- VIZD_WITNESS_NAME: Name of the validator to operate when block production is enabled. -- VIZD_PRIVATE_KEY: Private key for signing blocks (when operating a validator). -- VIZD_RPC_ENDPOINT: RPC endpoint binding (default: 0.0.0.0:8090). -- VIZD_P2P_ENDPOINT: P2P endpoint binding (default: 0.0.0.0:2001). -- VIZD_EXTRA_OPTS: Additional command-line options appended to the node invocation. - -Behavior is implemented in the entrypoint script, which constructs arguments, copies the packaged config into the data directory, and starts the node with the chosen endpoints and optional cached blockchain initialization. - -**Section sources** -- [vizd.sh:13-97](file://share/vizd/vizd.sh#L13-L97) -- [config.ini:16-20](file://share/vizd/config/config.ini#L16-L20) -- [config_testnet.ini:16-20](file://share/vizd/config/config_testnet.ini#L16-L20) - -### Volume Mounting Strategies -Persistent data storage relies on two primary volumes: -- /var/lib/vizd: Contains blockchain data (including the blockchain directory and cache). -- /etc/vizd: Contains configuration files and seednode lists. - -Mounting strategy recommendations: -- Bind mounts for durability and backups: map /var/lib/vizd to a host directory for long-term persistence. -- Config override: mount a host config.ini into /etc/vizd/config.ini to customize RPC endpoints, plugins, and logging without rebuilding images. -- Seednodes override: mount a custom seednodes file into /etc/vizd/seednodes to tailor connectivity. - -Exposed ports: -- RPC HTTP: 8090/tcp -- RPC WS: 8091/tcp -- P2P: 2001/tcp - -These are defined in the Dockerfiles and used by the entrypoint script. - -**Section sources** -- [Dockerfile-production:94-103](file://share/vizd/docker/Dockerfile-production#L94-L103) -- [Dockerfile-testnet:94-103](file://share/vizd/docker/Dockerfile-testnet#L94-L103) -- [Dockerfile-lowmem:76-85](file://share/vizd/docker/Dockerfile-lowmem#L76-L85) -- [Dockerfile-mongo:105-114](file://share/vizd/docker/Dockerfile-mongo#L105-L114) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) - -### Network Configuration -- Default RPC endpoints are configurable via environment variables; otherwise, defaults bind to 0.0.0.0 on ports 8090 (HTTP) and 8091 (WS). -- P2P endpoint defaults to 0.0.0.0:2001. -- Port exposure is defined per image; ensure firewall and orchestration platforms allow inbound connections on these ports. -- Seed nodes are either taken from the packaged seednodes file or overridden via VIZD_SEED_NODES. - -**Section sources** -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- [config.ini:1-20](file://share/vizd/config/config.ini#L1-L20) -- [config_testnet.ini:1-20](file://share/vizd/config/config_testnet.ini#L1-L20) - -### Image Customization and Base Image Selection -- Base image: phusion/baseimage:noble-1.0.3 variants are used across all images, providing a modern Debian-based runtime environment. -- Build customization: - - Production: standard build with MongoDB disabled. - - Testnet: enables BUILD_TESTNET. - - Low-memory: enables LOW_MEMORY_NODE. - - MongoDB: installs MongoDB C/C++ drivers and enables ENABLE_MONGO_PLUGIN. -- Debug configurations: separate debug configs are provided for development and MongoDB-enabled debug setups. - -**Section sources** -- [Dockerfile-production:1-103](file://share/vizd/docker/Dockerfile-production#L1-L103) -- [Dockerfile-testnet:1-103](file://share/vizd/docker/Dockerfile-testnet#L1-L103) -- [Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) -- [config_debug.ini:1-135](file://share/vizd/config/config_debug.ini#L1-L135) -- [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) - -### Security Considerations -- Non-root execution: the runtime stage creates a dedicated non-root user and sets ownership on cache and data directories. -- Minimal attack surface: images exclude unnecessary packages post-build and rely on minimal base images. -- Secrets handling: private keys and sensitive configuration should be mounted from secure volumes or managed via secret stores in orchestrators. -- Network exposure: restrict inbound access to RPC and P2P ports using firewalls and reverse proxies as appropriate. - -**Section sources** -- [Dockerfile-production:84-87](file://share/vizd/docker/Dockerfile-production#L84-L87) -- [Dockerfile-testnet:85-88](file://share/vizd/docker/Dockerfile-testnet#L85-L88) -- [Dockerfile-lowmem:66-69](file://share/vizd/docker/Dockerfile-lowmem#L66-L69) -- [Dockerfile-mongo:95-98](file://share/vizd/docker/Dockerfile-mongo#L95-L98) - -### Monitoring and Logging -- Logging configuration is defined in the packaged config files. Logs are written to files under the data directory according to the configured appenders and loggers. -- For production deployments, consider mounting a writable logs directory or integrating with container-native logging stacks. -- Health checks and metrics are not defined in the images; deploy external monitoring and alerting as needed. - -**Section sources** -- [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- [config_testnet.ini:113-132](file://share/vizd/config/config_testnet.ini#L113-L132) -- [config_mongo.ini:116-135](file://share/vizd/config/config_mongo.ini#L116-L135) -- [config_debug.ini:107-135](file://share/vizd/config/config_debug.ini#L107-L135) -- [config_debug_mongo.ini:116-135](file://share/vizd/config/config_debug_mongo.ini#L116-L135) - -### Practical Deployment Patterns -- Standalone container - - Run the production image and map ports 8090, 8091, and 2001. - - Override RPC/P2P endpoints via environment variables if needed. - - Persist data via a bind mount to /var/lib/vizd. - - Reference: [README.md:21-29](file://README.md#L21-L29), [Dockerfile-production:94-103](file://share/vizd/docker/Dockerfile-production#L94-L103) - -- Testnet node - - Use the testnet image tag and adjust seed nodes if required. - - Reference: [README.md:16-20](file://README.md#L16-L20), [Dockerfile-testnet:94-103](file://share/vizd/docker/Dockerfile-testnet#L94-L103) - -- validator node - - Set VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY to operate a validator. - - Reference: [vizd.sh:31-37](file://share/vizd/vizd.sh#L31-L37) - -- MongoDB analytics node - - Use the MongoDB-enabled image and configure mongodb-uri in the mounted config. - - Reference: [Dockerfile-mongo:105-114](file://share/vizd/docker/Dockerfile-mongo#L105-L114), [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72) - -- Development environment - - Use debug configurations and enable debug plugins for development and testing. - - Reference: [config_debug.ini:69-135](file://share/vizd/config/config_debug.ini#L69-L135), [config_debug_mongo.ini:69-135](file://share/vizd/config/config_debug_mongo.ini#L69-L135) - -**Section sources** -- [README.md:12-53](file://README.md#L12-L53) -- [Dockerfile-production:94-103](file://share/vizd/docker/Dockerfile-production#L94-L103) -- [Dockerfile-testnet:94-103](file://share/vizd/docker/Dockerfile-testnet#L94-L103) -- [Dockerfile-mongo:105-114](file://share/vizd/docker/Dockerfile-mongo#L105-L114) -- [vizd.sh:31-37](file://share/vizd/vizd.sh#L31-L37) -- [config_debug.ini:69-135](file://share/vizd/config/config_debug.ini#L69-L135) -- [config_debug_mongo.ini:69-135](file://share/vizd/config/config_debug_mongo.ini#L69-L135) - -### Container Orchestration and Multi-Container Scenarios -- Single-node deployment: run one container with mapped volumes and ports. -- Multi-node deployment: run multiple containers with distinct data directories and optionally different seed nodes. -- MongoDB stack: when using the MongoDB-enabled image, deploy a MongoDB instance alongside the node container and configure the mongodb-uri accordingly. -- Reverse proxy: front RPC endpoints with a reverse proxy for TLS termination and rate limiting. - -### Docker Registry Usage, Versioning, and Updates -- Official image repository: vizblockchain/vizd on Docker Hub. -- Tags: - - latest: production image built from master. - - testnet: testnet image built from master. -- Automated builds: - - Master branch pushes trigger builds for both production and testnet images. - - Pull requests trigger testnet image builds with ref-based tagging. -- Update procedure: - - Pull the target tag. - - Stop the running container. - - Recreate the container with updated image and preserved volumes. - -**Section sources** -- [README.md:14-20](file://README.md#L14-L20) -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -## Dependency Analysis -The runtime depends on: -- Entrypoint script for argument construction and startup. -- Configuration files for RPC endpoints, plugins, and logging. -- Persistent volumes for blockchain data and configuration. -- Compression libraries (libbz2-dev, liblzma-dev, libzstd-dev, zlib1g-dev) for efficient blockchain data processing. - -**Updated** Added compression library dependencies to support modern blockchain data compression formats. - -```mermaid -graph LR -DFProd["Dockerfile-production"] --> Script["vizd.sh"] -DFTnet["Dockerfile-testnet"] --> Script -DFLowMem["Dockerfile-lowmem"] --> Script -DFMongo["Dockerfile-mongo"] --> Script -Script --> CfgProd["config.ini"] -Script --> CfgTnet["config_testnet.ini"] -Script --> CfgMongo["config_mongo.ini"] -``` - -**Diagram sources** -- [Dockerfile-production:94-96](file://share/vizd/docker/Dockerfile-production#L94-L96) -- [Dockerfile-testnet:95-97](file://share/vizd/docker/Dockerfile-testnet#L95-L97) -- [Dockerfile-mongo:106-108](file://share/vizd/docker/Dockerfile-mongo#L106-L108) -- [vizd.sh:39-42](file://share/vizd/vizd.sh#L39-L42) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -**Section sources** -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -## Performance Considerations -- Shared memory sizing: tune shared-file-size and related parameters in the configuration to balance memory usage and performance. -- Plugin selection: disable unused plugins to reduce overhead. -- Single write thread: the configuration encourages single-write-thread to mitigate lock contention. -- Low-memory variant: use the low-memory image when running on constrained hardware. -- Compression library optimization: modern compression libraries (libbz2, liblzma, libzstd, zlib) provide efficient blockchain data compression and decompression. - -**Updated** Added compression library optimization considerations for improved blockchain data processing performance. - -## Troubleshooting Guide -Common issues and resolutions: -- Ports already in use - - Ensure host ports 8090, 8091, and 2001 are free or remap to different host ports. - - Verify container port exposure matches published ports. - - References: [Dockerfile-production:94-103](file://share/vizd/docker/Dockerfile-production#L94-L103), [Dockerfile-testnet:94-103](file://share/vizd/docker/Dockerfile-testnet#L94-L103) - -- Permission denied on data directory - - Confirm the non-root user owns /var/lib/vizd after initial run. - - Reference: [Dockerfile-production:84-87](file://share/vizd/docker/Dockerfile-production#L84-L87) - -- No connectivity to peers - - Override seed nodes via VIZD_SEED_NODES or mount a custom seednodes file. - - Reference: [vizd.sh:17-29](file://share/vizd/vizd.sh#L17-L29), [README.md:31-39](file://README.md#L31-L39) - -- Blockchain initialization delays - - Cached blockchain data may be unpacked on first run; allow time for decompression. - - Reference: [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) - -- MongoDB plugin connectivity - - Ensure mongodb-uri is reachable from the container network and credentials are correct. - - Reference: [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72), [Dockerfile-mongo:105-108](file://share/vizd/docker/Dockerfile-mongo#L105-L108) - -- Compression library issues - - Verify compression libraries (libbz2, liblzma, libzstd, zlib) are properly installed and accessible. - - Check for compatibility between compression formats and blockchain data versions. - - Reference: [Dockerfile-production:32-41](file://share/vizd/docker/Dockerfile-production#L32-L41), [Dockerfile-testnet:32-41](file://share/vizd/docker/Dockerfile-testnet#L32-L41) - -**Updated** Added compression library troubleshooting section to address potential issues with blockchain data compression. - -**Section sources** -- [Dockerfile-production:84-103](file://share/vizd/docker/Dockerfile-production#L84-L103) -- [Dockerfile-testnet:85-103](file://share/vizd/docker/Dockerfile-testnet#L85-L103) -- [vizd.sh:17-53](file://share/vizd/vizd.sh#L17-L53) -- [README.md:31-39](file://README.md#L31-L39) -- [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72) - -## Conclusion -The VIZ C++ Node provides multiple Docker images tailored for production, testnet, low-memory, and MongoDB-enabled deployments. By leveraging environment variables, persistent volumes, and the packaged configurations, operators can quickly deploy reliable and secure nodes. Automated CI builds maintain official images, and the modular design allows for flexible customization and operational patterns. - -## Appendices - -### Environment Variable Reference -- VIZD_SEED_NODES: Seed nodes to connect to. -- VIZD_WITNESS_NAME: validator name for block production. -- VIZD_PRIVATE_KEY: Private key for signing blocks. -- VIZD_RPC_ENDPOINT: RPC endpoint binding. -- VIZD_P2P_ENDPOINT: P2P endpoint binding. -- VIZD_EXTRA_OPTS: Additional CLI options. - -**Section sources** -- [vizd.sh:17-97](file://share/vizd/vizd.sh#L17-L97) - -### Ports Reference -- RPC HTTP: 8090 -- RPC WS: 8091 -- P2P: 2001 - -**Section sources** -- [Dockerfile-production:94-103](file://share/vizd/docker/Dockerfile-production#L94-L103) -- [Dockerfile-testnet:94-103](file://share/vizd/docker/Dockerfile-testnet#L94-L103) -- [Dockerfile-lowmem:76-85](file://share/vizd/docker/Dockerfile-lowmem#L76-L85) -- [Dockerfile-mongo:105-114](file://share/vizd/docker/Dockerfile-mongo#L105-L114) - -### Compression Library Dependencies -The Docker images now include modern compression library dependencies: -- libbz2-dev: Bzip2 compression support for blockchain data -- liblzma-dev: LZMA compression support for efficient data compression -- libzstd-dev: Zstandard compression for high-speed compression/decompression -- zlib1g-dev: Standard zlib compression library for compatibility - -These libraries are essential for processing modern blockchain data formats and provide optimal compression ratios and performance. - -**Section sources** -- [Dockerfile-production:32-41](file://share/vizd/docker/Dockerfile-production#L32-L41) -- [Dockerfile-testnet:32-41](file://share/vizd/docker/Dockerfile-testnet#L32-L41) -- [Dockerfile-lowmem:19-29](file://share/vizd/docker/Dockerfile-lowmem#L19-L29) -- [Dockerfile-mongo:19-29](file://share/vizd/docker/Dockerfile-mongo#L19-L29) - -### Sed Command Pattern Fixes -All Dockerfiles now include sed command pattern fixes to remove test subdirectories during the build process: -- `sed -i '/add_subdirectory(tests)/d' thirdparty/fc/CMakeLists.txt` - -This ensures that test subdirectories are excluded from compilation, reducing build time and image size while maintaining functionality. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L58) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L58) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L44) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L73) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Configuration Management/Network Configuration.md b/.qoder/repowiki/en/content/Configuration Management/Network Configuration.md deleted file mode 100644 index 44835079c0..0000000000 --- a/.qoder/repowiki/en/content/Configuration Management/Network Configuration.md +++ /dev/null @@ -1,652 +0,0 @@ -# Network Configuration - - -**Referenced Files in This Document** -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [stcp_socket.cpp](file://libraries/network/stcp_socket.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp) -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) - - -## Update Summary -**Changes Made** -- Added comprehensive documentation for the new P2P stale sync detection feature -- Documented the p2p-stale-sync-detection configuration option (default: false) -- Documented the p2p-stale-sync-timeout-seconds configuration option (default: 120) -- Updated all configuration template examples to include the new stale sync detection options -- Enhanced troubleshooting section with stale sync detection guidance -- Updated practical deployment examples to include stale sync detection configuration - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive network configuration guidance for the VIZ CPP Node peer-to-peer (P2P) networking stack. It covers peer connection settings, seed node configuration, network discovery mechanisms, listen address and port configuration, firewall considerations, security settings, connection limits, performance tuning, bandwidth management, and monitoring. Practical examples are included for private networks, testnets, and mainnet-like deployments. - -**Updated** The configuration system now includes a sophisticated stale sync detection mechanism that automatically recovers from network stalls by resetting sync from the last irreversible block and reconnecting seed peers when no blocks are received for the configured timeout period. - -## Project Structure -The P2P networking is implemented in the network library and integrated via the P2P plugin. Configuration is primarily driven by command-line options and configuration files, with enhanced integration through the snapshot plugin for trusted peer management and stale sync detection capabilities. - -```mermaid -graph TB -subgraph "Application Layer" -P2PPlugin["P2P Plugin
p2p_plugin.cpp"] -SnapshotPlugin["Snapshot Plugin
plugin.cpp"] -ChainPlugin["Chain Plugin
plugin.cpp"] -StaleSync["Stale Sync Detection
p2p-stale-sync-detection"] -TimeoutConfig["Timeout Configuration
p2p-stale-sync-timeout-seconds"] -end -subgraph "Network Library" -Node["Node
node.cpp"] -PeerConn["PeerConnection
peer_connection.cpp"] -STCP["STCP Socket
stcp_socket.cpp"] -Config["Network Config Constants
config.hpp"] -Msg["Message Types
message.hpp"] -PeerDB["Peer Database
peer_database.hpp"] -end -subgraph "Configuration" -CfgIni["config.ini"] -TestCfg["config_testnet.ini"] -WitCfg["config_witness.ini"] -DebugCfg["config_debug.ini"] -MongoCfg["config_mongo.ini"] -StockCfg["config_stock_exchange.ini"] -TrustedPeers["Trusted Peer IPs
_trusted_peer_ips"] -SoftBan["Soft-Ban Duration
TRUSTED_SOFT_BAN_DURATION_SEC"] -end -P2PPlugin --> Node -Node --> PeerConn -PeerConn --> STCP -Node --> Config -Node --> Msg -Node --> PeerDB -P2PPlugin --> CfgIni -P2PPlugin --> TestCfg -P2PPlugin --> WitCfg -P2PPlugin --> DebugCfg -P2PPlugin --> MongoCfg -P2PPlugin --> StockCfg -P2PPlugin --> StaleSync -P2PPlugin --> TimeoutConfig -SnapshotPlugin --> TrustedPeers -SnapshotPlugin --> SoftBan -Node --> TrustedPeers -``` - -**Diagram sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) -- [node.cpp:592-600](file://libraries/network/node.cpp#L592-L600) - -**Section sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Core Components -- P2P Plugin: Parses CLI and config options, initializes the Node, sets advanced parameters, and starts listening/connecting. -- Node: Manages P2P lifecycle, connection orchestration, sync loops, rate limiting, bandwidth monitoring, trusted peer soft-ban management, and stale sync detection. -- PeerConnection: Encapsulates per-peer state, encryption handshake, send queues, and inventory tracking. -- STCP Socket: Provides encrypted transport using ephemeral ECDH key exchange and AES-based stream cipher. -- Configuration Constants: Defines protocol version, ports, defaults, timeouts, limits, and performance parameters. -- Message Types: Defines the wire-level message header and serialization. -- Peer Database: Tracks potential peers, connection attempts, and outcomes. -- **Stale Sync Detection**: New component that monitors block reception timing and automatically recovers from network stalls. -- **Trusted Peer System**: Enhanced component that manages trusted peer endpoints and reduces soft-ban duration for improved network bootstrapping. - -Key configuration entry points: -- CLI options: p2p-endpoint, p2p-max-connections, p2p-seed-node, p2p-force-validate, **p2p-stale-sync-detection**, **p2p-stale-sync-timeout-seconds**. -- Config file keys: p2p-endpoint, p2p-max-connections, p2p-seed-node, loggers, **p2p-stale-sync-detection**, **p2p-stale-sync-timeout-seconds**, **trusted-snapshot-peer**. -- **Stale Sync Configuration**: Two new configuration options for detecting and recovering from network stalls. -- **Trusted Peer Configuration**: Multiple trusted-snapshot-peer entries for reduced soft-ban duration. - -**Updated** Configuration now includes stale sync detection with two new configuration options and enhanced trusted peer support with reduced soft-ban duration. - -**Section sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Architecture Overview -High-level P2P flow from plugin initialization to network operation, including stale sync detection and trusted peer integration. - -```mermaid -sequenceDiagram -participant CLI as "CLI/Config" -participant P2P as "P2P Plugin" -participant Node as "Node" -participant Snapshot as "Snapshot Plugin" -participant Seed as "Seed Peers" -participant StaleSync as "Stale Sync Monitor" -CLI->>P2P : Parse options (p2p-endpoint, p2p-max-connections, p2p-seed-node, p2p-stale-sync-detection, p2p-stale-sync-timeout-seconds) -P2P->>Node : Construct node(user_agent) -P2P->>Node : load_configuration(p2p_dir) -P2P->>Node : set_node_delegate(...) -alt p2p-endpoint configured -P2P->>Node : listen_on_endpoint(endpoint, wait_if_busy=true) -end -P2P->>Node : add_node(seed) -P2P->>Node : connect_to_endpoint(seed) -P2P->>Node : set_advanced_node_parameters(max_connections) -P2P->>Node : listen_to_p2p_network() -P2P->>Node : connect_to_p2p_network() -P2P->>Node : sync_from(head, synopsis) -Note over Snapshot,Node : Trusted Peer Registration -Snapshot->>P2P : get_trusted_snapshot_peers() -P2P->>Node : set_trusted_peer_endpoints(trusted_eps) -Note over StaleSync,Node : Stale Sync Detection Setup -StaleSync->>P2P : Initialize stale sync monitor -Node->>Seed : Connect and handshake -Node-->>P2P : Status callbacks (connection_count_changed, sync_status) -``` - -**Diagram sources** -- [p2p_plugin.cpp:689-706](file://plugins/p2p/p2p_plugin.cpp#L689-L706) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) - -## Detailed Component Analysis - -### Peer Connection Settings and Security -- Encryption and Handshake: - - Ephemeral ECDH key exchange performed during connection establishment. - - Shared secret used to derive AES cipher keys for bidirectional encryption. - - Transport ensures confidentiality and integrity for all P2P messages. -- Connection States and Lifecycle: - - PeerConnection tracks direction, negotiation status, and connection states. - - Queued message transmission with backpressure and maximum queue size enforcement. - - Automatic closure on excessive queued message size. -- Inventory and Throttling: - - Per-peer inventory lists with time-based expiry. - - Transaction and block inventory limits to prevent memory pressure. -- Firewall and NAT Awareness: - - Node determines firewall status and tracks publicly visible listening endpoint. - - Peer records include inbound/outbound ports for NAT traversal hints. -- **Soft-Ban Management**: - - **Default duration**: 1 hour (3600 seconds) for regular peers. - - **Trusted peers**: Reduced to 5 minutes (300 seconds) soft-ban duration. - - Automatic soft-ban duration adjustment based on peer trust status. - -```mermaid -classDiagram -class PeerConnection { -+direction -+negotiation_status -+inventory tracking -+send_message() -+send_item() -+close_connection() -+get_remote_endpoint() -} -class STCP_Socket { -+connect_to() -+accept() -+readsome() -+writesome() -} -class Node { -+listen_on_endpoint() -+connect_to_endpoint() -+set_advanced_node_parameters() -+get_actual_listening_endpoint() -+set_trusted_peer_endpoints() -+is_trusted_peer() -+get_soft_ban_duration() -} -class StaleSyncDetection { -+_stale_sync_enabled -+_stale_sync_timeout_seconds -+_last_block_received_time -+stale_sync_check_task() -} -class TrustedPeerSystem { -+_trusted_peer_ips -+SOFT_BAN_DURATION_SEC = 3600 -+TRUSTED_SOFT_BAN_DURATION_SEC = 300 -} -PeerConnection --> STCP_Socket : "encrypted transport" -Node --> PeerConnection : "manages" -Node --> StaleSyncDetection : "uses" -Node --> TrustedPeerSystem : "uses" -``` - -**Diagram sources** -- [peer_connection.cpp:68-162](file://libraries/network/peer_connection.cpp#L68-L162) -- [stcp_socket.cpp:37-92](file://libraries/network/stcp_socket.cpp#L37-L92) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [node.cpp:592-600](file://libraries/network/node.cpp#L592-L600) - -**Section sources** -- [peer_connection.cpp:68-162](file://libraries/network/peer_connection.cpp#L68-L162) -- [stcp_socket.cpp:37-92](file://libraries/network/stcp_socket.cpp#L37-L92) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [node.cpp:592-600](file://libraries/network/node.cpp#L592-L600) - -### Stale Sync Detection System -- **Stale Sync Detection Configuration**: - - Enabled via `p2p-stale-sync-detection = true` in configuration files. - - Timeout configured via `p2p-stale-sync-timeout-seconds = 120` (default: 120 seconds = 2 minutes). - - Monitors block reception timing across all connected peers. -- **Automatic Recovery Mechanism**: - - Background task checks every 30 seconds for network stalls. - - When no blocks received for the configured timeout, automatically triggers recovery actions. - - Three sequential recovery actions: reset sync from LIB, resync with connected peers, reconnect seed peers. -- **Recovery Actions**: - - **Reset sync from LIB**: Sync start point moved to last irreversible block (safe fork-proof position). - - **Resync with connected peers**: Fresh synchronization requests sent to all currently connected peers. - - **Reconnect seed peers**: All seed nodes from configuration are reconnected. -- **Complementary to Snapshot Plugin**: - - P2P stale detection is lightweight and doesn't require snapshot downloads. - - Works alongside snapshot plugin's stalled sync detection for comprehensive recovery. - - Faster recovery compared to snapshot-based approach. - -```mermaid -flowchart TD -Start(["Stale Sync Detection Startup"]) --> CheckEnabled{"p2p-stale-sync-detection enabled?"} -CheckEnabled --> |No| End(["Disabled"]) -CheckEnabled --> |Yes| InitTimer["Initialize last_block_received_time"] -InitTimer --> ScheduleTask["Schedule 30-second check task"] -ScheduleTask --> Monitor["Monitor block reception"] -Monitor --> CheckStall{"Elapsed > timeout?"} -CheckStall --> |No| Wait["Wait 30 seconds"] -CheckStall --> |Yes| ResetSync["Reset sync from LIB"] -ResetSync --> ResyncPeers["Resync with connected peers"] -ResyncPeers --> ReconnectSeeds["Reconnect all seed peers"] -ReconnectSeeds --> ResetTimer["Reset last_block_received_time"] -ResetTimer --> Wait -Wait --> Monitor -``` - -**Diagram sources** -- [p2p_plugin.cpp:585-649](file://plugins/p2p/p2p_plugin.cpp#L585-L649) -- [p2p_plugin.cpp:812-820](file://plugins/p2p/p2p_plugin.cpp#L812-L820) - -**Section sources** -- [p2p_plugin.cpp:585-649](file://plugins/p2p/p2p_plugin.cpp#L585-L649) -- [p2p_plugin.cpp:812-820](file://plugins/p2p/p2p_plugin.cpp#L812-L820) - -### Trusted Peer Support System -- **Trusted Peer Configuration**: - - Configured via multiple `trusted-snapshot-peer` entries in config.ini. - - Supports IP:port format for each trusted peer endpoint. - - Automatically parsed and registered during P2P plugin initialization. -- **Automatic Integration**: - - P2P plugin automatically queries snapshot plugin for trusted peer endpoints. - - Trusted peer IPs are converted to 32-bit integers for O(1) lookup performance. - - Registered trusted peers receive reduced soft-ban duration (5 minutes vs 1 hour). -- **Soft-Ban Duration Management**: - - Default soft-ban: 3600 seconds (1 hour) for regular peers. - - Trusted peers: 300 seconds (5 minutes) soft-ban duration. - - Dynamic duration calculation based on peer trust status. -- **Logging and Monitoring**: - - Logs registration of trusted peers with count and duration information. - - Clear distinction between regular and trusted peer soft-ban behavior. - -```mermaid -flowchart TD -Start(["P2P Plugin Startup"]) --> LoadSnapshot["Load Snapshot Plugin"] -LoadSnapshot --> CheckTrusted["Check trusted-snapshot-peer Config"] -CheckTrusted --> HasPeers{"Any trusted peers?"} -HasPeers --> |Yes| GetEndpoints["Get trusted endpoints from snapshot plugin"] -GetEndpoints --> ConvertIP["Convert to 32-bit IP addresses"] -ConvertIP --> Register["Register with Node.set_trusted_peer_endpoints()"] -Register --> LogInfo["Log trusted peer registration"] -HasPeers --> |No| Continue["Continue with normal operation"] -LogInfo --> Continue -Continue --> End(["Ready"]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) - -**Section sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) - -### Seed Node Configuration and Discovery -- Seed Nodes: - - Configured via CLI option p2p-seed-node and/or config file key p2p-seed-node. - - Multiple seeds supported; each is added and connected to during startup. - - Integrated directly into config.ini without external file management. -- Peer Database: - - Tracks potential peers, last seen time, disposition, and connection attempt counts. - - Used to manage retry/backoff and selection of peers for outbound connections. - -```mermaid -flowchart TD -Start(["Startup"]) --> LoadCfg["Load CLI and Config"] -LoadCfg --> ParseSeeds["Parse p2p-seed-node(s)"] -ParseSeeds --> AddNodes["node.add_node(seed)"] -AddNodes --> Connect["node.connect_to_endpoint(seed)"] -Connect --> Loop["Connect Loop and Retry"] -Loop --> PeerDB["Update peer_database entries"] -PeerDB --> Sync["Start sync_from(head)"] -Sync --> End(["Ready"]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:497-521](file://plugins/p2p/p2p_plugin.cpp#L497-L521) -- [node.cpp:780-785](file://libraries/network/node.cpp#L780-L785) -- [peer_database.hpp:47-71](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) - -**Section sources** -- [p2p_plugin.cpp:497-521](file://plugins/p2p/p2p_plugin.cpp#L497-L521) -- [peer_database.hpp:47-71](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) - -### Listen Address, Port, and Endpoint Management -- Listen Endpoint: - - Configured via CLI p2p-endpoint or config key p2p-endpoint. - - Node binds to the specified IP:port; supports waiting if port is busy. - - Actual listening endpoint is recorded and exposed for diagnostics. -- Ports: - - Standardized default P2P port is 2001 for mainnet configurations. - - Testnet uses 4243 as specified in config_testnet.ini. - - Users can override port in config or CLI. - -**Updated** Mainnet now uses standardized port 2001 instead of legacy 4243. - -```mermaid -sequenceDiagram -participant P2P as "P2P Plugin" -participant Node as "Node" -P2P->>Node : listen_on_endpoint(endpoint, wait_if_busy=true) -Node-->>P2P : get_actual_listening_endpoint() -P2P-->>P2P : Log actual endpoint -``` - -**Diagram sources** -- [p2p_plugin.cpp:537-540](file://plugins/p2p/p2p_plugin.cpp#L537-L540) -- [node.cpp:786-792](file://libraries/network/node.cpp#L786-L792) - -**Section sources** -- [p2p_plugin.cpp:487-495](file://plugins/p2p/p2p_plugin.cpp#L487-L495) -- [node.cpp:786-792](file://libraries/network/node.cpp#L786-L792) -- [config.hpp:52-56](file://libraries/network/include/graphene/network/config.hpp#L52-L56) - -### Firewall and NAT Considerations -- Firewall Detection: - - Node periodically sends firewall check messages and tracks state. - - Publicly visible listening endpoint is recorded when known. -- Inbound vs Outbound: - - Inbound connections are accepted on the bound endpoint. - - Outbound connections are initiated to seed nodes and peers discovered via inventory. - -**Section sources** -- [node.cpp:441-445](file://libraries/network/node.cpp#L441-L445) -- [peer_connection.cpp:169-206](file://libraries/network/peer_connection.cpp#L169-L206) - -### Security Settings and Authentication -- Transport Security: - - STCP socket performs ECDH key exchange and AES encryption for all traffic. -- Node Identity: - - Node configuration includes a node identity keypair; used in hello/user data. -- Authentication: - - No explicit node authentication or TLS certificate verification is implemented in the referenced code; encryption is provided by STCP. - -**Section sources** -- [stcp_socket.cpp:49-66](file://libraries/network/stcp_socket.cpp#L49-L66) -- [node.cpp:223-239](file://libraries/network/node.cpp#L223-L239) - -### Connection Limits and Timeouts -- Connection Limits: - - Desired and maximum connections are configurable via advanced parameters. - - Node enforces acceptance policy based on current connection count. -- Timeouts: - - Handshake inactivity timeout and disconnect timeout constants are defined. - - Inactivity-based disconnection is enforced during operation. - -```mermaid -flowchart TD -A["Incoming Connection"] --> B{"Connections < max?"} -B --> |Yes| Accept["Accept and add to active"] -B --> |No| Reject["Reject inbound"] -Accept --> C["Monitor activity"] -C --> D{"Idle beyond timeout?"} -D --> |Yes| Close["Close connection"] -D --> |No| C -``` - -**Diagram sources** -- [config.hpp:48-50](file://libraries/network/include/graphene/network/config.hpp#L48-L50) -- [node.cpp:638-640](file://libraries/network/node.cpp#L638-L640) - -**Section sources** -- [config.hpp:48-50](file://libraries/network/include/graphene/network/config.hpp#L48-L50) -- [node.cpp:518-526](file://libraries/network/node.cpp#L518-L526) - -### Bandwidth Management and Rate Limiting -- Rate Limiting: - - Node maintains a rate limiting group for outbound traffic. -- Bandwidth Monitoring: - - Rolling averages for read/write speeds are tracked and updated periodically. -- Message Queue Backpressure: - - Maximum queued message size enforced per-peer; oversized queues trigger closure. - -**Section sources** -- [node.cpp:548-567](file://libraries/network/node.cpp#L548-L567) -- [peer_connection.cpp:314-325](file://libraries/network/peer_connection.cpp#L314-L325) - -### Network Performance Tuning Parameters -- Defaults and Limits: - - Default desired and maximum connections, retry intervals, and message sizes are defined. - - Transaction rate limit and inventory retention windows are tunable via constants. -- Sync Behavior: - - Prefetch thresholds and batch sizes influence sync throughput. -- **Stale Sync Optimization**: - - Configurable timeout (default: 120 seconds) prevents unnecessary recovery actions. - - Automatic recovery from temporary network partitions and peer disconnections. - - Complementary to snapshot plugin for comprehensive network stall recovery. -- **Soft-Ban Optimization**: - - Trusted peers benefit from reduced soft-ban duration for faster recovery. - - Improved network bootstrapping and sync performance. - -**Section sources** -- [config.hpp:55-106](file://libraries/network/include/graphene/network/config.hpp#L55-L106) -- [node.cpp:592-600](file://libraries/network/node.cpp#L592-L600) - -### Practical Deployment Examples - -#### Private Network -- Configure a private listen endpoint and a small set of seed nodes. -- Adjust p2p-max-connections for expected peer count. -- Disable external exposure by binding to localhost or internal subnet. -- Enable stale sync detection for automatic recovery from network partitions. - -Example keys: -- p2p-endpoint = 10.0.0.5:2001 -- p2p-max-connections = 10 -- p2p-seed-node = 10.0.0.10:2001 -- **p2p-stale-sync-detection = true** -- **p2p-stale-sync-timeout-seconds = 120** - -**Updated** Using standardized port 2001 instead of legacy 4243 and added stale sync detection configuration. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) - -#### Testnet -- Use testnet-specific defaults and endpoints. -- Enable validator participation and adjust required participation as needed. -- Configure stale sync detection with appropriate timeout for testnet conditions. - -Example keys: -- p2p-endpoint = 0.0.0.0:4243 -- p2p-seed-node = (testnet seed IPs) -- enable-stale-production = true -- **p2p-stale-sync-detection = true** -- **p2p-stale-sync-timeout-seconds = 120** - -**Section sources** -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) - -#### Mainnet-like Deployment -- Bind to public IP and port 2001; ensure firewall/NAT traversal is configured. -- Increase p2p-max-connections for high-throughput nodes. -- Monitor bandwidth and tune rate limiting. -- Enable stale sync detection with conservative timeout settings. - -Example keys: -- p2p-endpoint = 0.0.0.0:2001 -- p2p-max-connections = 200 -- p2p-seed-node = (mainnet seed IPs) -- **p2p-stale-sync-detection = true** -- **p2p-stale-sync-timeout-seconds = 180** - -**Updated** Mainnet now standardized to port 2001 for consistent deployment and added stale sync detection configuration. - -#### Trusted Peer Deployment -- Configure trusted-snapshot-peer entries for reliable network bootstrapping. -- Set sync-snapshot-from-trusted-peer to true for automatic snapshot-based bootstrapping. -- Benefit from reduced soft-ban duration (5 minutes vs 1 hour) for trusted peers. -- Enable stale sync detection for automatic recovery from network stalls. - -Example keys: -- p2p-endpoint = 0.0.0.0:2001 -- p2p-max-connections = 200 -- p2p-seed-node = (mainnet seed IPs) -- sync-snapshot-from-trusted-peer = true -- trusted-snapshot-peer = 185.45.192.155:8092 -- trusted-snapshot-peer = 62.109.17.82:8092 -- **p2p-stale-sync-detection = true** -- **p2p-stale-sync-timeout-seconds = 120** - -**Updated** Added trusted peer configuration for enhanced network bootstrapping and reduced soft-ban duration, plus stale sync detection configuration. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config.hpp:52-56](file://libraries/network/include/graphene/network/config.hpp#L52-L56) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Dependency Analysis -```mermaid -graph LR -P2P["plugins/p2p/p2p_plugin.cpp"] --> N["libraries/network/node.cpp"] -N --> PC["libraries/network/peer_connection.cpp"] -PC --> STCP["libraries/network/stcp_socket.cpp"] -N --> CFG["libraries/network/include/graphene/network/config.hpp"] -N --> MSG["libraries/network/include/graphene/network/message.hpp"] -N --> PDB["libraries/network/include/graphene/network/peer_database.hpp"] -P2P --> C1["share/vizd/config/config.ini"] -P2P --> C2["share/vizd/config/config_testnet.ini"] -P2P --> C3["share/vizd/config/config_witness.ini"] -P2P --> C4["share/vizd/config/config_debug.ini"] -P2P --> C5["share/vizd/config/config_mongo.ini"] -P2P --> C6["share/vizd/config/config_stock_exchange.ini"] -Snapshot["plugins/snapshot/plugin.cpp"] --> TrustedPeers["_trusted_peer_ips"] -N --> TrustedPeers -N --> StaleSync["Stale Sync Detection"] -``` - -**Diagram sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -**Section sources** -- [p2p_plugin.cpp:689-698](file://plugins/p2p/p2p_plugin.cpp#L689-L698) -- [node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) -- [plugin.cpp:714-715](file://plugins/snapshot/plugin.cpp#L714-L715) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) - -## Performance Considerations -- Tune p2p-max-connections to balance throughput and resource usage. -- Monitor bandwidth metrics and adjust rate limiting if necessary. -- Prefer outbound connections to stable, high-bandwidth peers. -- Keep inventory sizes reasonable to avoid memory pressure during floods. -- **Stale Sync Benefits**: - - Automatic recovery from temporary network partitions and peer disconnections. - - Configurable timeout prevents unnecessary recovery actions during normal operation. - - Lightweight recovery mechanism that doesn't require snapshot downloads. - - Complementary to snapshot plugin for comprehensive network stall handling. -- **Trusted Peer Benefits**: - - Reduced soft-ban duration (5 minutes vs 1 hour) for faster recovery from transient errors. - - Improved network bootstrapping performance with trusted snapshot peers. - - Enhanced sync reliability during network partitions or peer unavailability. - -## Troubleshooting Guide -Common issues and remedies: -- Connection Issues: - - Verify p2p-endpoint bind address and port availability. - - Ensure firewall allows inbound connections on the configured port. - - Confirm seed nodes are reachable and not rate-limited. -- Latency Problems: - - Reduce p2p-max-connections to lower contention. - - Monitor bandwidth metrics and adjust rate limiting. -- Peer Discovery Failures: - - Check peer_database entries for repeated failures. - - Increase retry delays and verify network connectivity. -- **Stale Sync Detection Issues**: - - Verify p2p-stale-sync-detection is set to true in configuration. - - Check that p2p-stale-sync-timeout-seconds is appropriately configured (default: 120 seconds). - - Monitor logs for stale sync detection messages and recovery actions. - - Ensure block reception is occurring normally before relying on stale sync recovery. -- **Trusted Peer Issues**: - - Verify trusted-snapshot-peer configuration entries are valid IP:port pairs. - - Check that snapshot plugin is properly loaded and reporting trusted peers. - - Monitor logs for trusted peer registration success messages. - - Ensure soft-ban duration is correctly applied (5 minutes vs 1 hour). - -Operational hooks: -- Node delegates connection_count_changed and sync_status for monitoring. -- Logs for P2P subsystem are configurable via logging appenders. -- **Stale Sync Logging**: Automatic detection and recovery actions are logged with timing information. -- **Trusted Peer Logging**: Automatic registration and soft-ban duration logging. - -**Section sources** -- [p2p_plugin.cpp:403-405](file://plugins/p2p/p2p_plugin.cpp#L403-L405) -- [config.ini:112-136](file://share/vizd/config/config.ini#L112-L136) -- [node.cpp:5259-5262](file://libraries/network/node.cpp#L5259-L5262) - -## Conclusion -The VIZ CPP Node P2P stack provides a robust, encrypted transport with configurable connection limits, bandwidth monitoring, and seed-driven discovery. The recent additions of stale sync detection significantly enhance network reliability by automatically recovering from network stalls through three sequential recovery actions: resetting sync from the last irreversible block, resynchronizing with connected peers, and reconnecting seed peers. The trusted peer support system further enhances network bootstrapping capabilities with reduced soft-ban duration (5 minutes vs 1 hour) and automatic integration with the snapshot plugin. The standardization of port 2001 for mainnet deployments and integration of seed node management through config.ini simplify configuration and improve consistency. The stale sync detection feature provides a lightweight, automatic recovery mechanism that complements the snapshot plugin's more comprehensive recovery approach. Correctly setting listen endpoints, ports, connection caps, trusted peer configurations, and stale sync detection parameters, combined with appropriate firewall and NAT configuration, enables reliable operation across private, testnet, and mainnet environments. Monitoring and tuning of rate limits, inventory sizes, trusted peer benefits, and stale sync detection further improves resilience under load. - -## Appendices - -### Configuration Options Summary -- p2p-endpoint: Local IP:port to listen for P2P connections (standardized to 2001 for mainnet). -- p2p-max-connections: Maximum number of simultaneous connections. -- p2p-seed-node: Remote peer IP:port to bootstrap discovery (configured in config.ini). -- p2p-force-validate: Force validation of all transactions. -- **p2p-stale-sync-detection**: Enable automatic recovery from network stalls (default: false). -- **p2p-stale-sync-timeout-seconds**: Timeout in seconds before stale sync detection triggers recovery (default: 120). -- **trusted-snapshot-peer**: Trusted peer IP:port for reduced soft-ban duration and enhanced bootstrapping. -- **sync-snapshot-from-trusted-peer**: Enable automatic snapshot-based bootstrapping from trusted peers. - -**Updated** Mainnet now uses standardized port 2001 and integrated seed node configuration, plus new stale sync detection system with two configuration options and enhanced trusted peer support system. - -**Section sources** -- [p2p_plugin.cpp:467-482](file://plugins/p2p/p2p_plugin.cpp#L467-L482) -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini:1-107](file://share/vizd/config/config_witness.ini#L1-L107) -- [config.ini:96-101](file://share/vizd/config/config.ini#L96-L101) -- [node.cpp:592-600](file://libraries/network/node.cpp#L592-L600) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Configuration Management/Node Configuration.md b/.qoder/repowiki/en/content/Configuration Management/Node Configuration.md deleted file mode 100644 index 18915da869..0000000000 --- a/.qoder/repowiki/en/content/Configuration Management/Node Configuration.md +++ /dev/null @@ -1,465 +0,0 @@ -# Node Configuration - - -**Referenced Files in This Document** -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini) -- [main.cpp](file://programs/vizd/main.cpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [witness_plugin.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive guidance for configuring a VIZ CPP Node. It explains the configuration file structure, available parameters, defaults, and acceptable ranges. It also covers different node types (full node, validator node, low-memory node, testnet node), essential settings (database location, plugin activation, network parameters, performance tuning), authentication and API access controls, security configurations, and practical deployment examples. Finally, it includes validation tips, syntax guidance, and organizational best practices for configuration files. - -## Project Structure -The configuration system centers around a primary configuration file and several prebuilt templates for different deployment profiles. The node binary loads plugins and applies logging configuration from the same file. - -```mermaid -graph TB -cfg_main["Config: config.ini"] -cfg_test["Config: config_testnet.ini"] -cfg_wit["Config: config_witness.ini"] -cfg_mongo["Config: config_mongo.ini"] -cfg_debug["Config: config_debug.ini"] -cfg_debug_mongo["Config: config_debug_mongo.ini"] -cfg_stock["Config: config_stock_exchange.ini"] -bin_main["Binary: programs/vizd/main.cpp"] -plug_web["Plugin: webserver_plugin.hpp"] -plug_p2p["Plugin: p2p_plugin.hpp"] -plug_chain["Plugin: chain_plugin.hpp"] -plug_wit["Plugin: witness_plugin.hpp"] -bin_main --> plug_web -bin_main --> plug_p2p -bin_main --> plug_chain -bin_main --> plug_wit -cfg_main --> bin_main -cfg_test --> bin_main -cfg_wit --> bin_main -cfg_mongo --> bin_main -cfg_debug --> bin_main -cfg_debug_mongo --> bin_main -cfg_stock --> bin_main -``` - -**Diagram sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [witness_plugin.hpp](file://plugins/validator/include/graphene/plugins/validator/witness_plugin.hpp#L34-L65) - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) - -## Core Components -This section enumerates the most important configuration parameters grouped by category, with purpose, default value, and acceptable ranges where applicable. - -- Network and P2P - - p2p-endpoint: IP:PORT for P2P listener. Default varies by template; see [config.ini](file://share/vizd/config/config.ini#L2-L2), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L2-L2), [config_witness.ini](file://share/vizd/config/config_witness.ini#L2-L2). - - p2p-max-connections: Integer; default unset (plugin-specific behavior). See [config.ini](file://share/vizd/config/config.ini#L5-L5). - - p2p-seed-node: Repeatable; default unset. See [config.ini](file://share/vizd/config/config.ini#L8-L8). - - checkpoint: Repeatable; pairs [BLOCK_NUM,BLOCK_ID]; default unset. See [config.ini](file://share/vizd/config/config.ini#L11-L11). - -- Webserver and RPC - - webserver-thread-pool-size: Integer; default 2. See [config.ini](file://share/vizd/config/config.ini#L14-L14). - - webserver-http-endpoint: IP:PORT; default 0.0.0.0:8090. See [config.ini](file://share/vizd/config/config.ini#L17-L17). - - webserver-ws-endpoint: IP:PORT; default 0.0.0.0:8091. See [config.ini](file://share/vizd/config/config.ini#L20-L20). - -- Locking and Concurrency - - read-wait-micro: Integer microseconds; default 500000. See [config.ini](file://share/vizd/config/config.ini#L23-L23). - - max-read-wait-retries: Integer retries; default 2. See [config.ini](file://share/vizd/config/config.ini#L27-L27). - - write-wait-micro: Integer microseconds; default 500000. See [config.ini](file://share/vizd/config/config.ini#L30-L30). - - max-write-wait-retries: Integer retries; default 3. See [config.ini](file://share/vizd/config/config.ini#L34-L34). - - single-write-thread: Boolean; default true. See [config.ini](file://share/vizd/config/config.ini#L40-L40). - - enable-plugins-on-push-transaction: Boolean; default false. See [config.ini](file://share/vizd/config/config.ini#L47-L47). - -- Shared Memory and Disk - - shared-file-size: Size string; default 2G. See [config.ini](file://share/vizd/config/config.ini#L54-L54). - - min-free-shared-file-size: Size string; default 500M. See [config.ini](file://share/vizd/config/config.ini#L58-L58). - - inc-shared-file-size: Size string; default 2G. See [config.ini](file://share/vizd/config/config.ini#L62-L62). - - block-num-check-free-size: Integer blocks; default 1000. See [config.ini](file://share/vizd/config/config.ini#L67-L67). - -- Plugin Activation - - plugin: Repeatable; list of plugin names. Defaults vary by template. See [config.ini](file://share/vizd/config/config.ini#L69-L73), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L73), [config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L68). - -- History and Tracking - - clear-votes-before-block: Integer block number; default 0. See [config.ini](file://share/vizd/config/config.ini#L76-L76). - - skip-virtual-ops: Boolean; default false. See [config.ini](file://share/vizd/config/config.ini#L79-L79). - - track-account-range: JSON pair ["from","to"]; default unset. See [config.ini](file://share/vizd/config/config.ini#L82-L82). - - history-whitelist-ops: List of operation types; default unset. See [config.ini](file://share/vizd/config/config.ini#L85-L85). - - history-blacklist-ops: List of operation types; default unset. See [config.ini](file://share/vizd/config/config.ini#L88-L88). - - history-start-block: Integer block number; default unset. See [config.ini](file://share/vizd/config/config.ini#L91-L91). - - follow-max-feed-size: Integer; default 500. See [config.ini](file://share/vizd/config/config.ini#L94-L94). - - pm-account-range: JSON pair ["from","to"]; default unset. See [config.ini](file://share/vizd/config/config.ini#L97-L97). - -- validator Production - - enable-stale-production: Boolean; default false (production), true (testnet). See [config.ini](file://share/vizd/config/config.ini#L100-L100), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L100-L100). - - required-participation: Integer percentage (0–99); default unset (plugin default). See [config.ini](file://share/vizd/config/config.ini#L103-L103), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L103-L103). - - validator: String name; default unset (non-validator), "committee" (testnet). See [config.ini](file://share/vizd/config/config.ini#L106-L106), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L106-L106). - - private-key: WIF key; default unset (non-validator), testnet committee key shown. See [config.ini](file://share/vizd/config/config.ini#L109-L109), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L111-L111). - -- MongoDB (when enabled) - - mongodb-uri: URI string; default unset. See [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L72-L72), [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L72-L72). - -- Logging Configuration - - log.console_appender..stream: Stream target; default std_error. See [config.ini](file://share/vizd/config/config.ini#L113-L113), [main.cpp](file://programs/vizd/main.cpp#L167-L191). - - log.file_appender..filename: Path; default logs/p2p/p2p.log. See [config.ini](file://share/vizd/config/config.ini#L117-L117), [main.cpp](file://programs/vizd/main.cpp#L252-L268). - - logger..level: Level string; default warn. See [main.cpp](file://programs/vizd/main.cpp#L167-L191). - - logger..appenders: Comma-separated appender names; default stderr. See [main.cpp](file://programs/vizd/main.cpp#L167-L191). - -Notes on defaults and ranges: -- Numeric parameters without explicit ranges should be validated against typical hardware constraints and plugin expectations. -- Boolean parameters accept common variants supported by the underlying configuration parser. -- Paths for file appenders are resolved relative to the config file location unless absolute. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) - -## Architecture Overview -The node binary initializes plugins and applies logging configuration from the selected configuration file. The webserver plugin exposes HTTP and WebSocket endpoints. The P2P plugin manages peer connections. The chain plugin coordinates block acceptance and transaction processing. The Validator Plugin participates in block production when configured. - -```mermaid -sequenceDiagram -participant CLI as "CLI" -participant Bin as "vizd main.cpp" -participant Log as "Logging Loader" -participant WS as "Webserver Plugin" -participant P2P as "P2P Plugin" -participant Chain as "Chain Plugin" -participant Wit as "Validator Plugin" -CLI->>Bin : Start process with config path -Bin->>Log : Load logging config from config file -Log-->>Bin : Apply logging configuration -Bin->>WS : Initialize webserver plugin -Bin->>P2P : Initialize p2p plugin -Bin->>Chain : Initialize chain plugin -Bin->>Wit : Initialize Validator Plugin (if enabled) -Bin->>Bin : Startup and exec loop -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [witness_plugin.hpp](file://plugins/validator/include/graphene/plugins/validator/witness_plugin.hpp#L34-L65) - -## Detailed Component Analysis - -### Node Types and Templates -- Full node (mainnet) - - Typical characteristics: Public P2P endpoint, broad plugin set, production RPC endpoints, validator disabled by default. - - Reference template: [config.ini](file://share/vizd/config/config.ini#L1-L130) -- Testnet node - - Characteristics: enable-stale-production=true, required-participation=0, validator="committee", private-key for committee. - - Reference template: [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- validator node - - Characteristics: webserver endpoints bound to localhost, validator and private-key configured, skip-virtual-ops=true. - - Reference template: [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- Low-memory node - - Build-time flag: LOW_MEMORY_NODE=TRUE via CMake; exposed via Dockerfile-lowmem. - - Reference: [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48) -- MongoDB-enabled node - - Characteristics: plugin list includes mongo_db, mongodb-uri configured. - - Reference templates: [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135), [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- Stock exchange node profile - - Characteristics: optimized plugin set for market data, localhost RPC, stricter history handling. - - Reference template: [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) - -Practical selection guidance: -- Choose config_testnet.ini for development and testing. -- Use config_witness.ini when operating a validating validator with private keys. -- Use config_mongo.ini when integrating external analytics or historical archiving. -- Use config_stock_exchange.ini for market data consumers requiring minimal overhead. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48) - -### Essential Settings: Database Location -- Shared memory sizing parameters control the size of the shared database file and growth thresholds. These influence disk usage and performance. - - shared-file-size, min-free-shared-file-size, inc-shared-file-size, block-num-check-free-size. -- References: - - [config.ini](file://share/vizd/config/config.ini#L54-L67) - - [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L54-L67) - - [config_witness.ini](file://share/vizd/config/config_witness.ini#L53-L66) - - [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L54-L67) - - [config_debug.ini](file://share/vizd/config/config_debug.ini#L54-L67) - - [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L54-L67) - - [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L54-L67) - -Operational notes: -- Adjust shared memory parameters to match expected chain growth and available disk space. -- Monitor free space checks to avoid excessive resizing during runtime. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L54-L67) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L54-L67) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L53-L66) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L54-L67) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L54-L67) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L54-L67) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L54-L67) - -### Plugin Activation -- The plugin directive enables or disables functionality. Different templates activate distinct sets of plugins tailored to their role. -- Examples: - - Full node: [config.ini](file://share/vizd/config/config.ini#L69-L73) - - Testnet: [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L73) - - validator: [config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L68) - - MongoDB: [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L69), [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L69-L69) - - Stock exchange: [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L69-L69) - -Validation tip: -- Ensure required plugins are present for your deployment (e.g., chain, p2p, webserver, json_rpc, database_api). - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L69-L73) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L73) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L68) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L69) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L69-L69) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L69-L69) - -### Network Parameters -- P2P endpoint and seed nodes define connectivity. - - p2p-endpoint: [config.ini](file://share/vizd/config/config.ini#L2-L2), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L2-L2), [config_witness.ini](file://share/vizd/config/config_witness.ini#L2-L2) - - p2p-seed-node: [config.ini](file://share/vizd/config/config.ini#L8-L8) -- RPC endpoints: - - webserver-http-endpoint: [config.ini](file://share/vizd/config/config.ini#L17-L17) - - webserver-ws-endpoint: [config.ini](file://share/vizd/config/config.ini#L20-L20) - -Security note: -- Bind RPC to localhost for validator nodes to prevent external exposure: [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20). - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L20) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L20) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L20) - -### Performance Tuning Options -- Concurrency and locking: - - single-write-thread: [config.ini](file://share/vizd/config/config.ini#L40-L40) - - enable-plugins-on-push-transaction: [config.ini](file://share/vizd/config/config.ini#L47-L47) - - read-wait-micro, max-read-wait-retries: [config.ini](file://share/vizd/config/config.ini#L23-L27) - - write-wait-micro, max-write-wait-retries: [config.ini](file://share/vizd/config/config.ini#L30-L34) -- Shared memory growth: - - shared-file-size, min-free-shared-file-size, inc-shared-file-size, block-num-check-free-size: [config.ini](file://share/vizd/config/config.ini#L54-L67) - -Recommendations: -- Keep single-write-thread enabled for high-throughput RPC workloads to reduce lock contention. -- Tune retries and wait intervals based on observed lock acquisition failures. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L23-L67) - -### Authentication, API Access Controls, and Security -- RPC endpoints: - - HTTP: [config.ini](file://share/vizd/config/config.ini#L17-L17) - - WebSocket: [config.ini](file://share/vizd/config/config.ini#L20-L20) -- Binding to localhost for validator nodes: - - [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20) -- validator credentials: - - validator and private-key: [config_witness.ini](file://share/vizd/config/config_witness.ini#L83-L86), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L106-L111) -- Logging security: - - Console and file appenders: [config.ini](file://share/vizd/config/config.ini#L112-L130) - - Program options for logging: [main.cpp](file://programs/vizd/main.cpp#L167-L191) - -Best practices: -- Restrict RPC access to trusted networks or bind to localhost for validator nodes. -- Rotate private keys and store them securely; avoid committing secrets to repositories. -- Use file appenders for persistent logs and monitor log rotation externally if needed. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L17-L130) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L86) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L106-L111) -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) - -### Practical Configuration Scenarios -- Full node for public API: - - Use [config.ini](file://share/vizd/config/config.ini#L1-L130) with public RPC endpoints and broad plugin set. -- Testnet validator: - - Use [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) with enable-stale-production and committee validator settings. -- validator operator: - - Use [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) with localhost RPC and configured validator/private-key. -- Low-memory deployment: - - Build with LOW_MEMORY_NODE=TRUE via [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48). -- MongoDB integration: - - Use [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) or [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) and ensure mongodb-uri is reachable. -- Stock exchange consumer: - - Use [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) for minimal overhead and focused plugins. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini#L1-L114) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48) - -### Parameter Validation and Syntax -- Configuration file syntax: - - Key-value pairs and repeatable directives (e.g., plugin, p2p-seed-node, checkpoint). - - Logging sections use dotted prefixes: log.console_appender.*, log.file_appender.*, logger.*. -- Validation steps: - - Ensure numeric values are within reasonable bounds for your hardware. - - Verify plugin names match available plugins. - - Confirm file paths for log appenders are writable. - - For validator nodes, confirm validator and private-key are set consistently. -- Example references: - - Logging program options: [main.cpp](file://programs/vizd/main.cpp#L167-L191) - - Config parsing and logging loader: [main.cpp](file://programs/vizd/main.cpp#L194-L288) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp](file://programs/vizd/main.cpp#L194-L288) - -### Configuration Organization, Backup, and Version Management -- Organization: - - Keep a base template (e.g., config.ini) and environment-specific overlays. - - Group related settings (network, RPC, plugins, logging) together. -- Backup: - - Back up the entire configuration directory and rotate logs. -- Version management: - - Track changes to configuration files alongside code releases. - - Use environment variables or separate files for secrets (e.g., private-key) while keeping non-secret settings under version control. - -[No sources needed since this section provides general guidance] - -## Dependency Analysis -The node binary registers and initializes plugins, which in turn depend on each other. The webserver plugin requires the JSON-RPC plugin. The P2P plugin depends on the chain plugin. The Validator Plugin depends on both chain and P2P. - -```mermaid -graph LR -Main["vizd main.cpp"] -Web["webserver_plugin.hpp"] -P2P["p2p_plugin.hpp"] -Chain["chain_plugin.hpp"] -Wit["witness_plugin.hpp"] -Main --> Web -Main --> P2P -Main --> Chain -Main --> Wit -Web --> Chain -P2P --> Chain -Wit --> Chain -Wit --> P2P -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L38-L43) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L21) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L23-L24) -- [witness_plugin.hpp](file://plugins/validator/include/graphene/plugins/validator/witness_plugin.hpp#L36-L37) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [chain_plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [witness_plugin.hpp](file://plugins/validator/include/graphene/plugins/validator/witness_plugin.hpp#L34-L65) - -## Performance Considerations -- Single write thread: Reduces lock contention for database writes; recommended for high RPC throughput. -- Plugin notifications on push: Disabling can improve performance by avoiding extra indexing work for transactions not included in the next block. -- Shared memory sizing: Proper sizing prevents frequent reallocations and reduces latency spikes. -- Logging verbosity: Lower log levels reduce I/O overhead in production. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Unable to acquire READ/WRITE lock: - - Increase retries or adjust wait microseconds; review single-write-thread setting. - - References: [config.ini](file://share/vizd/config/config.ini#L23-L34), [config.ini](file://share/vizd/config/config.ini#L40-L47) -- Insufficient disk space for shared memory: - - Increase min-free-shared-file-size and inc-shared-file-size; monitor growth. - - References: [config.ini](file://share/vizd/config/config.ini#L58-L62) -- validator not producing blocks: - - Verify validator name and private-key; ensure enable-stale-production and required-participation are appropriate for the network. - - References: [config_witness.ini](file://share/vizd/config/config_witness.ini#L83-L86), [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L100-L103) -- RPC endpoints unreachable: - - Confirm binding address and port; for validator nodes, ensure localhost binding is intended. - - References: [config.ini](file://share/vizd/config/config.ini#L17-L20), [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20) -- Logging misconfiguration: - - Validate dotted section names and file paths; ensure appenders are writable. - - References: [main.cpp](file://programs/vizd/main.cpp#L167-L191), [main.cpp](file://programs/vizd/main.cpp#L211-L288) - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L23-L67) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L83-L86) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L100-L103) -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [main.cpp](file://programs/vizd/main.cpp#L211-L288) - -## Conclusion -A well-tuned VIZ CPP Node configuration balances performance, security, and operational needs. Select the appropriate template for your deployment type, validate parameters carefully, and apply robust logging and backup practices. Use the provided references to align your configuration with the node’s plugin architecture and runtime behavior. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Configuration File Syntax Quick Reference -- Key-value pairs: key = value -- Repeatable directives: plugin = ..., p2p-seed-node = ... -- Logging sections: - - log.console_appender..stream - - log.file_appender..filename - - logger..level - - logger..appenders - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [config.ini](file://share/vizd/config/config.ini#L112-L130) - -### Appendix B: Build-Time Flags for Low-Memory Nodes -- LOW_MEMORY_NODE=TRUE via CMake; Dockerfile demonstrates usage. -- Reference: [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48) - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L48-L48) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Contributing and Development.md b/.qoder/repowiki/en/content/Contributing and Development.md deleted file mode 100644 index 1c0b1c909d..0000000000 --- a/.qoder/repowiki/en/content/Contributing and Development.md +++ /dev/null @@ -1,353 +0,0 @@ -# Contributing and Development - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testing.md](file://documentation/testing.md) -- [documentation/plugin.md](file://documentation/plugin.md) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [LICENSE.md](file://LICENSE.md) -- [.travis.yml](file://.travis.yml) -- [programs/util/newplugin.py](file://programs/util/newplugin.py) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive contributing and development guidance for VIZ CPP Node. It covers the development workflow, code style and commit conventions, review processes, contribution lifecycle from issue to merge, quality standards (testing, documentation, performance), plugin development contribution process, community contribution opportunities, and practical examples of common contribution scenarios. It also outlines the relationship between contributions and project governance, licensing, and intellectual property considerations, and offers guidance for new contributors to get started. - -## Project Structure -The repository is organized around a CMake-based build system, layered libraries (chain, protocol, network, utilities, wallet), plugins, and documentation. Key areas for contributors: -- Libraries: core blockchain logic, protocol definitions, network messaging, utilities, and wallet APIs -- Plugins: built-in and external plugin ecosystem -- Documentation: build instructions, testing, plugin development, and guidelines -- Tools: scripts for building helpers, CLI utilities, and plugin scaffolding - -```mermaid -graph TB -A["Root"] --> B["libraries"] -A --> C["plugins"] -A --> D["documentation"] -A --> E["programs"] -A --> F["share"] -A --> G[".travis.yml"] -B --> B1["chain"] -B --> B2["protocol"] -B --> B3["network"] -B --> B4["utilities"] -B --> B5["wallet"] -C --> C1["built-in plugins"] -C --> C2["external plugins"] -D --> D1["building.md"] -D --> D2["testing.md"] -D --> D3["plugin.md"] -D --> D4["debug_node_plugin.md"] -D --> D5["git_guildelines.md"] -E --> E1["util/newplugin.py"] -E --> E2["util/test_block_log.cpp"] -E --> E3["util/schema_test.cpp"] -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) - -## Core Components -- Build and CI: CMake-based build with Docker-based CI matrix covering multiple configurations -- Testing: unit tests via a dedicated target, runtime configuration options, and coverage generation -- Plugin system: built-in and external plugin support, registration, and API exposure -- Developer tools: plugin scaffolding script, schema and block log utilities for testing and validation - -Key references: -- Build options and platform-specific instructions -- Test categories and runtime configuration -- Plugin registration and enabling -- Debug node plugin usage and API surface -- Git branching, PR, and review policies -- Licensing and contribution terms - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [LICENSE.md](file://LICENSE.md#L1-L26) -- [.travis.yml](file://.travis.yml#L1-L46) - -## Architecture Overview -The development and contribution workflow integrates build, test, and release automation with explicit branching and review policies. Contributors develop on feature branches, submit PRs, and adhere to code quality gates enforced by CI. - -```mermaid -graph TB -Dev["Developer"] --> BR["Feature Branch
develop-based"] -BR --> PR["Pull Request
to develop/master"] -PR --> CI["CI Pipeline
.travis.yml matrix"] -CI --> |Pass| Merge["Merge to develop/master"] -Merge --> Release["Release Tagging
vMajor.Hardfork.Release"] -Release --> Images["Docker Images
latest/testnet variants"] -``` - -**Diagram sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L8-L24) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L49-L76) -- [.travis.yml](file://.travis.yml#L12-L46) - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [.travis.yml](file://.travis.yml#L1-L46) - -## Detailed Component Analysis - -### Development Workflow and Contribution Lifecycle -- Issue identification: Use repository issues to track work; non-issue patches still require an issue for documentation and traceability -- Branching: Feature branches originate from develop; naming convention for issue-related branches is issue-number-hyphen-shorthand; non-issue branches use YYYYMMDD-shortname -- Pull requests: All changes enter via PRs; automated testing is mandatory; maintainers enforce review and approval policies -- Merging: Master merges are single-commit PRs after feature consolidation; develop merges require passing tests and approvals - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Repo as "Repository" -participant CI as "CI Pipeline" -participant Maint as "Maintainers" -Dev->>Repo : Create feature branch from develop -Dev->>Repo : Commit changes and push -Dev->>Repo : Open PR to develop/master -Repo->>CI : Trigger tests -CI-->>Repo : Test results -alt Tests pass -Maint->>Repo : Code review and approval -Maint->>Repo : Merge PR -else Tests fail or review comments -Dev->>Repo : Update branch and address feedback -end -``` - -**Diagram sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L25-L48) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L49-L76) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L93-L111) - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) - -### Code Style Guidelines -- Commit messages: Reference related issues to create a documentation trail; ensure messages clearly explain the change and its rationale -- PRs: Include a summary of changes, rationale, and any special instructions for reviewers -- Branch hygiene: Keep commits focused; avoid mixing unrelated changes; rebase to resolve conflicts before resubmission - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L70-L76) - -### Review Processes and Governance -- Review requirements: At least two developers must review and approve changes; for releases and consensus-breaking changes, stricter requirements apply -- Author participation: Authors may review their own work; however, at least one independent reviewer is required -- Enforcement: PRs must pass automated tests; manual checks ensure adherence to style and correctness - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L93-L111) - -### Testing Requirements and Quality Standards -- Unit tests: Build and run via a dedicated target; tests are categorized (basic, block, operation, serialization, etc.) -- Runtime configuration: Control verbosity and filtering via runtime options -- Coverage: Enable coverage collection and generate HTML reports using lcov -- Validation utilities: Use provided tools to validate schema and block log behavior during development - -```mermaid -flowchart TD -Start(["Run Tests"]) --> Build["Build tests target"] -Build --> RunAll["Execute tests binary"] -RunAll --> Categories{"Select category/filter"} -Categories --> Report["Generate report"] -Report --> Coverage{"Coverage requested?"} -Coverage --> |Yes| Capture["Capture coverage data"] -Coverage --> |No| End(["Done"]) -Capture --> HTML["Generate HTML report"] -HTML --> End -``` - -**Diagram sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) - -### Documentation Expectations -- Build and usage docs: Follow the documented procedures for building and running the node -- Plugin docs: Use the plugin guide and debug plugin documentation as references for extending functionality -- Contribution docs: Adhere to the git guidelines and ensure PRs link to relevant issues - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) - -### Performance Criteria -- Build types: Prefer Release builds for production and benchmarking; use Debug with coverage for development and profiling -- Low-memory builds: Consider low-memory node builds for resource-constrained environments (e.g., validators) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L3-L16) - -### Plugin Development Contribution Process -- Template usage: Use the plugin scaffolding script to generate boilerplate for new plugins -- Registration and enabling: Configure plugins via configuration options; enable public APIs as needed -- Integration guidelines: Follow plugin registration patterns and integrate with the application’s plugin lifecycle - -```mermaid -flowchart TD -A["Choose provider/name"] --> B["Run newplugin.py"] -B --> C["Generated files in libraries/plugins/"] -C --> D["Add to CMake and build"] -D --> E["Enable plugin in config"] -E --> F["Expose public API if needed"] -F --> G["Test and iterate"] -``` - -**Diagram sources** -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [documentation/plugin.md](file://documentation/plugin.md#L14-L28) - -**Section sources** -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) - -### Community Contribution Opportunities -- Bug reports: Use repository issues to report reproducible bugs with clear steps and environment details -- Feature requests: Propose enhancements via issues; include motivation, acceptance criteria, and potential impact -- Documentation improvements: Submit PRs for docs; ensure clarity and completeness -- Code contributions: Follow the workflow outlined above; ensure tests and documentation accompany changes - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L49-L76) - -### Practical Examples of Common Contribution Scenarios -- Fixing a bug: - - Create a branch from develop - - Add or update unit tests to reproduce the issue - - Implement the fix and verify with tests - - Submit a PR referencing the issue -- Adding a feature: - - Open an issue to track the feature - - Develop on a feature branch; add tests and documentation - - Submit a PR; iterate based on feedback -- Improving documentation: - - Edit relevant documentation files - - Submit a PR with a concise description of changes - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L25-L48) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -### Licensing and Intellectual Property Considerations -- License: The repository uses the MIT License for VIZ-Blockchain-contributed code -- Dependencies: Third-party components remain under their respective licenses -- Contributions: By submitting code, contributors agree to license their work under the repository’s license - -**Section sources** -- [LICENSE.md](file://LICENSE.md#L1-L26) - -### Getting Started for New Contributors -- Set up the build environment per platform-specific instructions -- Explore the documentation for building, testing, and plugin development -- Pick an issue labeled as good first issue or similar; start with small tasks -- Follow the branching and PR workflow described above - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) - -## Dependency Analysis -The project relies on a CMake-based build system with Dockerized CI. The CI matrix builds multiple Docker images, ensuring compatibility across configurations. - -```mermaid -graph TB -CI[".travis.yml"] --> DF1["Dockerfile"] -CI --> DF2["share/vizd/docker/Dockerfile-test"] -CI --> DF3["share/vizd/docker/Dockerfile-testnet"] -CI --> DF4["share/vizd/docker/Dockerfile-lowmem"] -CI --> DF5["share/vizd/docker/Dockerfile-mongo"] -DF1 --> IMG1["Images"] -DF2 --> IMG2["Images"] -DF3 --> IMG3["Images"] -DF4 --> IMG4["Images"] -DF5 --> IMG5["Images"] -``` - -**Diagram sources** -- [.travis.yml](file://.travis.yml#L12-L18) -- [.travis.yml](file://.travis.yml#L22-L46) - -**Section sources** -- [.travis.yml](file://.travis.yml#L1-L46) - -## Performance Considerations -- Build type selection impacts performance and debugging capabilities -- Low-memory builds reduce storage and RAM usage for consensus roles -- Use coverage builds judiciously for profiling and optimization efforts - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L3-L16) - -## Troubleshooting Guide -- Build failures: Verify platform prerequisites and CMake options; consult platform-specific sections -- Test failures: Use runtime configuration to narrow down failing categories; inspect coverage output -- Plugin issues: Confirm plugin registration and configuration; validate API exposure settings -- CI failures: Review Docker build logs and ensure environment parity - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L212) -- [documentation/testing.md](file://documentation/testing.md#L16-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L14-L28) -- [.travis.yml](file://.travis.yml#L22-L46) - -## Conclusion -Contributions to VIZ CPP Node are governed by clear branching, PR, and review policies, supported by robust testing and CI infrastructure. Contributors should follow the documented workflow, ensure tests and documentation accompany changes, and leverage the plugin system and developer tools to deliver high-quality contributions. - -## Appendices -- Quick links to key documents: - - Build instructions: [documentation/building.md](file://documentation/building.md#L1-L212) - - Testing guide: [documentation/testing.md](file://documentation/testing.md#L1-L43) - - Plugin development: [documentation/plugin.md](file://documentation/plugin.md#L1-L28) - - Debug node plugin: [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) - - Git guidelines: [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) - - License: [LICENSE.md](file://LICENSE.md#L1-L26) - - CI configuration: [.travis.yml](file://.travis.yml#L1-L46) - - Plugin scaffolding: [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) - - Schema and block log utilities: [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57), [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Core Libraries/Core Libraries.md b/.qoder/repowiki/en/content/Core Libraries/Core Libraries.md deleted file mode 100644 index 69b97b12b0..0000000000 --- a/.qoder/repowiki/en/content/Core Libraries/Core Libraries.md +++ /dev/null @@ -1,1122 +0,0 @@ -# Core Libraries - - -**Referenced Files in This Document** -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [libraries/chain/database.cpp](file://libraries/chain/database.cpp) -- [libraries/chain/include/graphene/chain/evaluator.hpp](file://libraries/chain/include/graphene/chain/evaluator.hpp) -- [libraries/chain/include/graphene/chain/chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [libraries/chain/include/graphene/chain/db_with.hpp](file://libraries/chain/include/graphene/chain/db_with.hpp) -- [libraries/chain/include/graphene/chain/global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) -- [libraries/chain/include/graphene/chain/fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [libraries/chain/fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [libraries/protocol/include/graphene/protocol/transaction.hpp](file://libraries/protocol/include/graphene/protocol/transaction.hpp) -- [libraries/protocol/transaction.cpp](file://libraries/protocol/transaction.cpp) -- [libraries/protocol/include/graphene/protocol/types.hpp](file://libraries/protocol/include/graphene/protocol/types.hpp) -- [libraries/protocol/operations.cpp](file://libraries/protocol/operations.cpp) -- [libraries/protocol/include/graphene/protocol/chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) -- [libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp) -- [libraries/protocol/include/graphene/protocol/config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [libraries/network/node.cpp](file://libraries/network/node.cpp) -- [libraries/network/include/graphene/network/peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [libraries/network/peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [libraries/wallet/wallet.cpp](file://libraries/wallet/wallet.cpp) -- [libraries/wallet/include/graphene/wallet/api_documentation.hpp](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [plugins/validator/validator.cpp](file://plugins/validator/validator.cpp) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) - - -## Update Summary -**Changes Made** -- Enhanced validator scheduling system documentation with emergency mode integration -- Added comprehensive peer connection management for emergency consensus -- Updated validator scheduling with hybrid schedule implementation during emergency mode -- Expanded emergency consensus activation and deactivation logic -- Added peer soft-banning mechanism for emergency fork management -- Updated fork database tie-breaking with deterministic hash-based selection - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Blockchain Operations and Data Types](#blockchain-operations-and-data-types) -7. [Protocol Specifications](#protocol-specifications) -8. [Emergency Consensus Mode](#emergency-consensus-mode) -9. [Peer Connection Management](#peer-connection-management) -10. [DNS Nameserver Helper Functionality](#dns-nameserver-helper-functionality) -11. [Postponed Transactions Processing](#postponed-transactions-processing) -12. [Dependency Analysis](#dependency-analysis) -13. [Performance Considerations](#performance-considerations) -14. [Troubleshooting Guide](#troubleshooting-guide) -15. [Conclusion](#conclusion) - -## Introduction -This document explains the VIZ CPP Node core libraries that form the foundation of the blockchain node. The four main library categories are: -- Chain library: blockchain state management, validation, and consensus -- Protocol library: transaction and operation definitions and cryptographic signing -- Network library: peer-to-peer communication and synchronization -- Wallet library: transaction signing and key management - -These libraries interact closely: the Chain library validates and applies operations, the Protocol library defines operations and transactions, the Network library propagates blocks and transactions across peers, and the Wallet library signs transactions before they are broadcast. The system now includes enhanced emergency consensus mode with integrated validator scheduling and improved peer connection management for maintaining network stability during critical situations. - -**Updated** Enhanced documentation now includes comprehensive coverage of emergency consensus mode, hybrid validator scheduling, peer connection management, blockchain operations, data types, protocol specifications, DNS nameserver helper functionality, and accurate postponed transactions processing with corrected logging behavior. - -## Project Structure -The core libraries are organized under the libraries/ directory, with each library providing focused capabilities: -- libraries/chain: state machine, evaluators, database, fork management, block processing, emergency consensus -- libraries/protocol: operations, transactions, signing, types, chain constants, emergency mode configuration -- libraries/network: P2P node, peer connections, message handling, synchronization, emergency peer management -- libraries/wallet: transaction builder, signing, key management, APIs, DNS nameserver helpers - -Plugins integrate these libraries into a full node via the appbase framework. The main entry point initializes plugins and starts the node. Emergency consensus mode adds new components for validator scheduling and peer management. - -```mermaid -graph TB -subgraph "Core Libraries" -CHAIN["Chain Library
database.hpp, evaluator.hpp, chain_objects.hpp
db_with.hpp
global_property_object.hpp
fork_database.hpp"] -PROTO["Protocol Library
operations.hpp, transaction.hpp, types.hpp
config.hpp"] -NET["Network Library
node.hpp
peer_connection.hpp"] -WALLET["Wallet Library
wallet.hpp, api_documentation.hpp
DNS Nameserver Helpers"] -end -subgraph "Plugins" -PL_CHAIN["plugins/chain/plugin.hpp"] -PL_P2P["plugins/p2p/p2p_plugin.hpp"] -PL_WITNESS["plugins/validator/validator.hpp"] -end -subgraph "Emergency Consensus Components" -EMERGENCY_MODE["Emergency Consensus
Mode Activation
Deactivation Logic"] -HYBRID_SCHED["Hybrid validator Schedule
Real + Committee Slots"] -PEER_MANAGEMENT["Peer Connection
Management & Soft-Banning"] -END -MAIN["programs/vizd/main.cpp"] -MAIN --> PL_CHAIN -MAIN --> PL_P2P -MAIN --> PL_WITNESS -PL_CHAIN --> CHAIN -PL_P2P --> NET -PL_WITNESS --> CHAIN -CHAIN --> PROTO -CHAIN --> EMERGENCY_MODE -NET --> PEER_MANAGEMENT -NET --> PROTO -WALLET --> PROTO -``` - -**Diagram sources** -- [programs/vizd/main.cpp:106-140](file://programs/vizd/main.cpp#L106-L140) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L46) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-46](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L46) -- [plugins/validator/validator.cpp:170-198](file://plugins/validator/validator.cpp#L170-L198) -- [libraries/chain/include/graphene/chain/database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [libraries/network/include/graphene/network/node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:96-1067](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) - -**Section sources** -- [programs/vizd/main.cpp:62-91](file://programs/vizd/main.cpp#L62-L91) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L46) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-46](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L46) -- [plugins/validator/validator.cpp:170-198](file://plugins/validator/validator.cpp#L170-L198) - -## Core Components -This section introduces the primary responsibilities and key classes of each library. - -- Chain Library - - database: central state machine managing blockchain objects, fork database, block log, and applying operations - - evaluator: pluggable operation handlers that mutate state according to protocol rules - - chain_objects: persistent object model (accounts, content, escrow, vesting routes, etc.) - - db_with: pending transaction processing, postponed transactions handling, and restoration logic - - global_property_object: dynamic chain properties including emergency consensus state - - fork_database: fork management with emergency mode tie-breaking and state tracking - - Responsibilities: block validation, transaction validation, state transitions, hardfork handling, validator scheduling, emergency consensus management - -- Protocol Library - - operations: static_variant of all supported operations (transfers, governance, content, etc.) - - transaction: structure with operations, expiration, reference block, and cryptographic signing - - types: comprehensive data type definitions including cryptographic keys, asset types, and authority structures - - config: emergency consensus constants and validator scheduling parameters - - Responsibilities: define canonical operation semantics, transaction signing and verification, authority checks, emergency mode configuration - -- Network Library - - node: P2P node with peer connections, message propagation, sync protocol, and broadcasting - - peer_connection: individual peer connections with emergency mode soft-banning and fork management - - Responsibilities: block and transaction propagation, peer discovery, sync from peers, bandwidth limits, emergency peer management - -- Wallet Library - - wallet_api: transaction builder, signing, key management, proposal creation, account operations, DNS nameserver helpers - - api_documentation: method descriptions and help system for wallet operations - - DNS Nameserver Helpers: validation, extraction, and management of DNS records in account metadata - - Responsibilities: construct transactions, sign with private keys, manage encrypted key storage, expose APIs, handle DNS metadata - -**Updated** Enhanced with comprehensive emergency consensus mode integration, hybrid validator scheduling, peer connection management, and DNS nameserver helper functionality. - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [libraries/chain/include/graphene/chain/evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [libraries/chain/include/graphene/chain/chain_objects.hpp:20-200](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L200) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) -- [libraries/protocol/include/graphene/protocol/operations.hpp:13-102](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/protocol/include/graphene/protocol/transaction.hpp:12-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [libraries/protocol/include/graphene/protocol/types.hpp:75-207](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [libraries/network/include/graphene/network/node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:96-1067](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [libraries/wallet/include/graphene/wallet/api_documentation.hpp:37-75](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L37-L75) - -## Architecture Overview -The libraries integrate through explicit interfaces and signals. The Chain library exposes a database interface and signals for operation application. The Protocol library defines the canonical operation types and transaction structures. The Network library consumes blocks and transactions from the Chain library and broadcasts them to peers. The Wallet library constructs and signs transactions using the Protocol library and sends them to the Chain library via the P2P plugin. The DNS nameserver helper functionality extends the wallet library to manage DNS metadata within account JSON metadata. The db_with module handles postponed transactions processing with accurate counting and logging. Emergency consensus mode adds new components for validator scheduling and peer management. - -```mermaid -graph TB -WALLET["Wallet API
wallet.hpp
DNS Nameserver Helpers"] -API_DOC["API Documentation
api_documentation.hpp"] -PROTO["Protocol
transaction.hpp, operations.hpp, types.hpp, config.hpp"] -CHAIN["Chain Database
database.hpp"] -EVAL["Evaluators
evaluator.hpp"] -CHAIN_OBJ["Chain Objects
chain_objects.hpp"] -DB_WITH["Postponed Transactions
db_with.hpp"] -EMERGENCY_MODE["Emergency Consensus
Mode Management"] -HYBRID_SCHED["Hybrid validator Schedule
Real + Committee Slots"] -PEER_CONN["Peer Connections
Soft-Banning & Fork Management"] -NET["Network Node
node.hpp"] -PL_CHAIN["Chain Plugin
plugin.hpp"] -PL_P2P["P2P Plugin
p2p_plugin.hpp"] -PL_WITNESS["Validator Plugin
validator.hpp"] -DNS_HELPERS["DNS Nameserver Helpers
ns_validate_*
ns_create_metadata
ns_set_records"] -WITNESS_PLUGIN["Validator Plugin
Emergency Key Loading
Block Production"] -FORK_DB["Fork Database
Emergency Mode Tie-Breaking"] -WALLET --> API_DOC -WALLET --> PROTO -WALLET --> DNS_HELPERS -WALLET --> PL_P2P -PL_P2P --> NET -PL_CHAIN --> CHAIN -PL_WITNESS --> WITNESS_PLUGIN -CHAIN --> EVAL -CHAIN --> CHAIN_OBJ -CHAIN --> DB_WITH -CHAIN --> EMERGENCY_MODE -EMERGENCY_MODE --> HYBRID_SCHED -EMERGENCY_MODE --> PEER_CONN -EMERGENCY_MODE --> FORK_DB -NET --> PROTO -NET --> PEER_CONN -PROTO --> CHAIN -WITNESS_PLUGIN --> CHAIN -``` - -**Diagram sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:1310-1420](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1310-L1420) -- [libraries/wallet/include/graphene/wallet/api_documentation.hpp:43-75](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L43-L75) -- [libraries/protocol/include/graphene/protocol/transaction.hpp:12-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [libraries/protocol/include/graphene/protocol/operations.hpp:13-102](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/protocol/include/graphene/protocol/types.hpp:75-207](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [libraries/chain/include/graphene/chain/database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [libraries/chain/include/graphene/chain/evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [libraries/chain/include/graphene/chain/chain_objects.hpp:20-200](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L200) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) -- [libraries/network/include/graphene/network/node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L46) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-46](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L46) -- [plugins/validator/validator.cpp:170-198](file://plugins/validator/validator.cpp#L170-L198) - -## Detailed Component Analysis - -### Chain Library -The Chain library is the core state machine. It manages: -- Blockchain state: persistent objects, indexes, and undo history -- Validation pipeline: block and transaction validation with configurable skip flags -- Fork management: fork database and branch selection with emergency mode tie-breaking -- Operation application: dispatch to evaluators and emit notifications -- Hardfork handling: versioning and activation logic -- Postponed transactions: accurate counting and processing with proper logging -- Emergency consensus: automatic activation/deactivation based on network health -- validator scheduling: hybrid schedule during emergency mode with real and committee validators - -Key classes and responsibilities: -- database: open/reindex, push/pop blocks, push transactions, notify signals, hardfork control, emergency mode management -- evaluator: base class for operation-specific logic -- chain_objects: multi-index containers for persistent state -- db_with: pending transaction restoration, postponed transaction processing, execution limits -- global_property_object: dynamic chain properties including emergency consensus state -- fork_database: fork management with emergency mode tie-breaking and state tracking - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, ...) -+reindex(data_dir, shared_mem_dir, from_block_num, ...) -+push_block(signed_block, skip_flags) -+push_transaction(signed_transaction, skip_flags) -+validate_block(...) -+validate_transaction(...) -+pre_apply_operation -+post_apply_operation -+applied_block -+on_pending_transaction -+on_applied_transaction -+is_known_transaction(id) -+has_hardfork(hf) -+get_dynamic_global_properties() -+get_witness_schedule_object() -+update_median_witness_props() -+check_block_post_validation_chain() -} -class evaluator { -<> -+apply(op) -+get_type() -} -class evaluator_impl { --database& _db -+apply(op) -+get_type() -} -class chain_objects { -<> -} -class pending_transactions_restorer { -+pending_transactions_restorer(db, skip, pending_txs) -+~pending_transactions_restorer() -+process_popped_tx() -+process_pending_tx() -} -class global_property_object { -+emergency_consensus_active : bool -+emergency_consensus_start_block : uint32_t -} -class fork_database { -+set_emergency_mode(active) -+is_emergency_mode() bool -+_emergency_consensus_active : bool -} -database --> evaluator : "dispatches operations" -evaluator <|-- evaluator_impl : "implements" -database --> chain_objects : "manages" -database --> pending_transactions_restorer : "uses" -database --> global_property_object : "manages" -database --> fork_database : "uses" -``` - -**Diagram sources** -- [libraries/chain/include/graphene/chain/database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [libraries/chain/include/graphene/chain/evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [libraries/chain/include/graphene/chain/chain_objects.hpp:20-200](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L200) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp:36-561](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) -- [libraries/chain/database.cpp:198-200](file://libraries/chain/database.cpp#L198-L200) -- [libraries/chain/include/graphene/chain/evaluator.hpp:11-45](file://libraries/chain/include/graphene/chain/evaluator.hpp#L11-L45) -- [libraries/chain/include/graphene/chain/chain_objects.hpp:20-200](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L20-L200) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) - -### Protocol Library -The Protocol library defines the canonical operation types and transaction structures: -- operations: static_variant of all operations (transfers, governance, content, etc.) -- transaction: operations, expiration, reference block, and signing/verification helpers -- types: comprehensive data type definitions including cryptographic keys, asset types, and authority structures -- Authority and sign_state: required authorities and signature verification -- config: emergency consensus constants and validator scheduling parameters - -```mermaid -classDiagram -class operations { -<> -+transfer_operation -+account_update_operation -+proposal_create_operation -+content_reward_operation -+... -} -class transaction { -+vector~operation~ operations -+time_point_sec expiration -+extensions_type extensions -+validate() -+id() -+sig_digest(chain_id) -} -class signed_transaction { -+vector~signature_type~ signatures -+sign(private_key, chain_id) -+verify_authority(...) -+get_required_signatures(...) -} -class types { -<> -+public_key_type -+extended_public_key_type -+asset -+price -+authority -+... -} -class config { -<> -+CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC -+CHAIN_EMERGENCY_WITNESS_ACCOUNT -+CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY -+CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS -} -operations --> transaction : "composed in" -signed_transaction --> transaction : "extends" -types --> operations : "used by" -config --> database : "used by" -``` - -**Diagram sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp:13-102](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/protocol/include/graphene/protocol/transaction.hpp:12-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [libraries/protocol/include/graphene/protocol/types.hpp:75-207](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) - -**Section sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp:13-102](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/protocol/include/graphene/protocol/transaction.hpp:12-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [libraries/protocol/include/graphene/protocol/types.hpp:75-207](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) -- [libraries/protocol/transaction.cpp:30-200](file://libraries/protocol/transaction.cpp#L30-L200) - -### Network Library -The Network library provides peer-to-peer connectivity with enhanced emergency mode support: -- node: P2P node with delegate interface, peer connections, message propagation, sync protocol -- peer_connection: individual peer connections with emergency mode soft-banning and fork management -- Broadcasting: blocks and transactions to peers -- Sync: blockchain synopsis, block requests, and peer synchronization - -```mermaid -sequenceDiagram -participant NET as "Network Node" -participant PEER as "Peer Connection" -participant CHAIN as "Chain Plugin" -participant DB as "Database" -NET->>PEER : "connect_to_endpoint()" -NET->>PEER : "sync_from(current_head_block, hard_fork_block_numbers)" -PEER->>PEER : "fork_rejected_until soft-ban check" -PEER-->>NET : "block_message" -NET->>CHAIN : "accept_block(block)" -CHAIN->>DB : "push_block(block)" -DB->>DB : "emergency mode tie-breaking" -DB-->>CHAIN : "applied_block signal" -CHAIN-->>NET : "sync_status(item_type, count)" -``` - -**Diagram sources** -- [libraries/network/include/graphene/network/node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:44-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L44-L46) - -**Section sources** -- [libraries/network/include/graphene/network/node.hpp:190-304](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/network/node.cpp:1-200](file://libraries/network/node.cpp#L1-L200) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/network/peer_connection.cpp:150-349](file://libraries/network/peer_connection.cpp#L150-L349) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:44-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L44-L46) - -### Wallet Library -The Wallet library provides transaction construction and signing: -- wallet_api: builder APIs, signing, key management, proposal creation, account operations, DNS nameserver helpers -- api_documentation: method descriptions and help system for wallet operations -- DNS Nameserver Helpers: comprehensive DNS metadata management functionality -- Signing: uses Protocol transaction structures and private keys -- Integration: communicates with the node via plugins and remote APIs - -```mermaid -flowchart TD -Start(["Begin Builder Transaction"]) --> AddOp["Add Operation to Builder"] -AddOp --> Preview["Preview Builder Transaction"] -Preview --> Sign{"Sign?"} -Sign --> |Yes| SignTx["Sign Builder Transaction"] -Sign --> |No| End(["End"]) -SignTx --> Broadcast{"Broadcast?"} -Broadcast --> |Yes| Send["Send to Chain Plugin"] -Broadcast --> |No| End -Send --> End -``` - -**Diagram sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:132-180](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L132-L180) -- [libraries/wallet/include/graphene/wallet/api_documentation.hpp:43-75](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L43-L75) - -**Section sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:96-1067](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L96-L1067) -- [libraries/wallet/wallet.cpp:1-200](file://libraries/wallet/wallet.cpp#L1-L200) -- [libraries/wallet/include/graphene/wallet/api_documentation.hpp:37-75](file://libraries/wallet/include/graphene/wallet/api_documentation.hpp#L37-L75) - -### DNS Nameserver Helper Functionality -The wallet library now includes comprehensive DNS nameserver helper functionality for managing DNS records within VIZ account metadata. This functionality enables: - -- **Validation Functions**: IPv4 address validation, SHA256 hash validation, TTL validation, and SSL TXT record format validation -- **Metadata Creation**: Generation of DNS metadata JSON with A records and SSL hash TXT records -- **Extraction Functions**: Retrieval of A records, SSL hashes, and TTL values from account metadata -- **Management Operations**: Setting and removing DNS records while preserving other metadata fields - -Key data structures: -- `ns_record`: Represents a single DNS record tuple [type, value] -- `ns_metadata_options`: Configuration options for DNS metadata (A records, SSL hash, TTL) -- `ns_summary`: Extracted DNS metadata summary from account JSON -- `ns_validation_result`: Validation results with error reporting - -```mermaid -classDiagram -class ns_metadata_options { -+vector~string~ a_records -+optional~string~ ssl_hash -+uint32_t ttl -} -class ns_summary { -+vector~string~ a_records -+optional~string~ ssl_hash -+uint32_t ttl -+bool has_ns_data -} -class ns_validation_result { -+bool is_valid -+vector~string~ errors -} -class wallet_api { -+ns_validate_ipv4(ipv4) -+ns_validate_sha256_hash(hash) -+ns_validate_ttl(ttl) -+ns_validate_ssl_txt_record(txt) -+ns_validate_metadata(options) -+ns_create_metadata(options) -+ns_get_summary(account_name) -+ns_extract_a_records(account_name) -+ns_extract_ssl_hash(account_name) -+ns_extract_ttl(account_name) -+ns_set_records(account_name, options, broadcast) -+ns_remove_records(account_name, broadcast) -} -ns_metadata_options --> ns_summary : "creates" -ns_validation_result --> ns_metadata_options : "validates" -wallet_api --> ns_metadata_options : "uses" -wallet_api --> ns_summary : "returns" -``` - -**Diagram sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:24-62](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L24-L62) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:1310-1420](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1310-L1420) -- [libraries/wallet/wallet.cpp:2577-2884](file://libraries/wallet/wallet.cpp#L2577-L2884) - -**Section sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:24-62](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L24-L62) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:1310-1420](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1310-L1420) -- [libraries/wallet/wallet.cpp:2577-2884](file://libraries/wallet/wallet.cpp#L2577-L2884) - -### Postponed Transactions Processing -The Chain library includes sophisticated postponed transactions processing with accurate counting and logging. This system handles transactions that cannot be included in a block due to size constraints or execution limits. - -Key components: -- `pending_transactions_restorer`: Manages restoration of pending transactions during block production -- `postponed_tx_count`: Accurate counter for transactions postponed due to block size limits -- Execution limits: Configurable time-based limits for processing pending transactions -- Logging: Prevents false 'Postponed' messages for skipped known transactions - -```mermaid -classDiagram -class pending_transactions_restorer { -+pending_transactions_restorer(database&, uint32_t, vector~signed_transaction~) -+~pending_transactions_restorer() -+process_popped_tx() -+process_pending_tx() -} -class database { -+push_transaction(signed_transaction, uint32_t) -+_push_transaction(signed_transaction, uint32_t) -+clear_pending() -+is_known_transaction(transaction_id_type) -} -class postponed_transactions_processing { -+postponed_tx_count : uint64_t -+CHAIN_BLOCK_GENERATION_POSTPONED_TX_LIMIT : 5 -+CHAIN_PENDING_TRANSACTION_EXECUTION_LIMIT : 200ms -+process_transactions_with_size_limits() -+accurate_logging_behavior() -} -pending_transactions_restorer --> database : "restores" -postponed_transactions_processing --> database : "uses" -``` - -**Diagram sources** -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/database.cpp:1165-1202](file://libraries/chain/database.cpp#L1165-L1202) -- [libraries/chain/database.cpp:549-555](file://libraries/chain/database.cpp#L549-L555) - -**Section sources** -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/database.cpp:1165-1202](file://libraries/chain/database.cpp#L1165-L1202) -- [libraries/chain/database.cpp:549-555](file://libraries/chain/database.cpp#L549-L555) - -### Typical Operations: Transaction Processing and Block Validation - -#### Transaction Processing Flow -- Wallet builds and signs a transaction using Protocol structures -- P2P plugin broadcasts the signed transaction to peers -- Chain plugin receives and validates the transaction via the Chain library -- Chain library applies the transaction's operations through evaluators -- Database emits notifications for pre/post application and applied block - -```mermaid -sequenceDiagram -participant WALLET as "Wallet API" -participant PROTO as "Protocol" -participant P2P as "P2P Plugin" -participant CHAIN as "Chain Plugin" -participant DB as "Database" -participant EVAL as "Evaluators" -WALLET->>PROTO : "Build signed_transaction" -WALLET->>P2P : "broadcast_transaction(tx)" -P2P->>CHAIN : "accept_transaction(tx)" -CHAIN->>DB : "validate_transaction(tx)" -DB->>EVAL : "apply operations" -EVAL-->>DB : "state changes" -DB-->>CHAIN : "on_applied_transaction signal" -CHAIN-->>P2P : "transaction propagated" -``` - -**Diagram sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:132-180](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L132-L180) -- [libraries/protocol/include/graphene/protocol/transaction.hpp:57-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L57-L101) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:46-46](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L46-L46) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:46-46](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L46-L46) -- [libraries/chain/include/graphene/chain/database.hpp:200-275](file://libraries/chain/include/graphene/chain/database.hpp#L200-L275) - -#### Block Validation Flow -- Network receives a block from peers -- Chain plugin accepts the block and validates it -- Database validates block header, extensions, and applies block-level operations -- Database updates global properties, validator schedules, and emits applied_block signal - -```mermaid -sequenceDiagram -participant NET as "Network Node" -participant CHAIN as "Chain Plugin" -participant DB as "Database" -NET->>CHAIN : "accept_block(block)" -CHAIN->>DB : "validate_block(block)" -DB->>DB : "_validate_block(next_block)" -DB->>DB : "apply_block(next_block)" -DB-->>CHAIN : "applied_block signal" -``` - -**Diagram sources** -- [libraries/network/include/graphene/network/node.hpp:79-80](file://libraries/network/include/graphene/network/node.hpp#L79-L80) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:44-44](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L44-L44) -- [libraries/chain/include/graphene/chain/database.hpp:194-226](file://libraries/chain/include/graphene/chain/database.hpp#L194-L226) - -## Blockchain Operations and Data Types - -### Comprehensive Operation Coverage -The protocol library now provides extensive operation documentation covering all blockchain operations: - -#### Core Operations -- **Account Management**: account_create_operation, account_update_operation, account_metadata_operation -- **Token Operations**: transfer_operation, transfer_to_vesting_operation, withdraw_vesting_operation -- **Governance**: witness_update_operation, chain_properties_update_operation, proposal operations -- **Content Operations**: content_operation, delete_content_operation, vote_operation -- **Escrow Operations**: escrow_transfer_operation, escrow_approve_operation, escrow_dispute_operation, escrow_release_operation -- **Virtual Operations**: author_reward_operation, curation_reward_operation, content_reward_operation - -#### Advanced Operations -- **Committee Operations**: Various committee request and approval operations -- **Award Operations**: Award creation and distribution operations -- **Paid Subscription Operations**: Subscription management and billing operations -- **Account Sale Operations**: Account marketplace operations -- **Hardfork Operations**: System upgrade and maintenance operations - -#### Data Type Definitions -The types.hpp file provides comprehensive data type coverage: - -- **Cryptographic Types**: - - public_key_type, extended_public_key_type, extended_private_key_type - - signature_type, chain_id_type -- **Asset Types**: - - asset, price, share_type for token and share management -- **Authority Structures**: - - authority, weight_type for multi-signature requirements -- **Name Types**: - - account_name_type for account identification - -**Section sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp:13-102](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [libraries/protocol/include/graphene/protocol/chain_operations.hpp:11-800](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L800) -- [libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp:11-329](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) -- [libraries/protocol/include/graphene/protocol/types.hpp:75-207](file://libraries/protocol/include/graphene/protocol/types.hpp#L75-L207) -- [libraries/protocol/operations.cpp:17-52](file://libraries/protocol/operations.cpp#L17-L52) - -### Operation Categorization and Classification -Operations are systematically categorized for better understanding and implementation: - -#### Operation Categories -- **Regular Operations**: Standard blockchain operations that affect state -- **Virtual Operations**: System-generated operations for rewards and maintenance -- **Data Operations**: Operations carrying raw data payloads -- **Governance Operations**: Operations affecting chain parameters and governance - -#### Operation Properties -Each operation includes validation rules, authority requirements, and extension mechanisms for future enhancements. - -**Section sources** -- [libraries/protocol/operations.cpp:17-52](file://libraries/protocol/operations.cpp#L17-L52) -- [libraries/protocol/include/graphene/protocol/operations.hpp:104-113](file://libraries/protocol/include/graphene/protocol/operations.hpp#L104-L113) - -## Protocol Specifications - -### Detailed Operation Documentation -The protocol now includes comprehensive documentation for all operation types: - -#### Operation Structure -Each operation follows a standardized structure: -- Base class inheritance from base_operation or virtual_operation -- validate() method for input validation -- get_required_*_authorities() methods for authority determination -- Extension support for future compatibility - -#### Authority Requirements -Operations specify required authorities: -- Active authorities for standard operations -- Master authorities for sensitive operations -- Regular authorities for metadata operations -- Custom authorities for specialized operations - -#### Virtual Operations -Virtual operations represent system events: -- Reward distributions (author_reward_operation, curation_reward_operation) -- Maintenance operations (hardfork_operation, shutdown_witness_operation) -- State transitions (fill_vesting_withdraw_operation) - -**Section sources** -- [libraries/protocol/include/graphene/protocol/chain_operations.hpp:11-800](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp#L11-L800) -- [libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp:11-329](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp#L11-L329) - -### Transaction Structure and Validation -Transactions follow a strict validation pipeline: -- Operation composition and ordering -- Expiration handling and reference block validation -- Signature verification and authority checking -- Extension processing and custom operation support - -**Section sources** -- [libraries/protocol/include/graphene/protocol/transaction.hpp:12-101](file://libraries/protocol/include/graphene/protocol/transaction.hpp#L12-L101) -- [libraries/protocol/transaction.cpp:30-200](file://libraries/protocol/transaction.cpp#L30-L200) - -## Emergency Consensus Mode - -The VIZ blockchain now includes a comprehensive emergency consensus mode designed to maintain network stability during prolonged network stalls or validator failures. This system automatically activates when no blocks are produced for a specified timeout period and ensures continuous block production through committee validators. - -### Emergency Consensus Activation Logic - -Emergency mode is triggered when the time since the last irreversible block exceeds the configured timeout threshold: - -```mermaid -flowchart TD -Start(["Block Applied"]) --> CheckLIB["Check Last Irreversible Block Time"] -CheckLIB --> CalcTime["Calculate Time Since LIB"] -CalcTime --> Timeout{"Timeout Exceeded?
> CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC"} -Timeout --> |No| Normal["Normal Operation"] -Timeout --> |Yes| Activate["Activate Emergency Mode"] -Activate --> CreateWitness["Create/Update Emergency validator"] -CreateWitness --> ResetPenalties["Reset validator Penalties"] -ResetPenalties --> OverrideSchedule["Override validator Schedule"] -OverrideSchedule --> NotifyForkDB["Notify Fork Database"] -NotifyForkDB --> LogActivation["Log Emergency Mode Activation"] -``` - -**Diagram sources** -- [libraries/chain/database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-112](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L112) - -### Hybrid validator Scheduling System - -During emergency mode, the validator scheduling system operates as a hybrid between real validators and committee validators: - -- **Real validator Slots**: Maintained for validators with valid signing keys -- **Committee Slots**: Filled by the emergency validator account for offline or unavailable validators -- **Full Schedule Expansion**: The schedule expands to include all committee slots during emergency - -The hybrid schedule ensures that: -- Real validators keep their scheduled slots -- Offline validators are replaced by committee validators -- The full CHAIN_MAX_WITNESSES schedule is maintained for consistent block production -- Committee validators maintain neutral voting positions aligned with current hardfork state - -```mermaid -sequenceDiagram -participant SCHED as "validator Scheduler" -participant REAL as "Real validators" -participant COMMITTEE as "Committee validators" -participant DATABASE as "Database" -SCHED->>DATABASE : "Get Current Schedule" -DATABASE-->>SCHED : "wso.current_shuffled_witnesses" -SCHED->>SCHED : "Iterate Full Schedule (MAX_WITNESSES)" -loop For Each Slot -SCHED->>REAL : "Check validator Availability" -alt validator Available -SCHED->>SCHED : "Keep Real validator Slot" -else validator Unavailable -SCHED->>COMMITTEE : "Assign Emergency validator" -SCHED->>SCHED : "Replace with Committee Slot" -end -end -SCHED->>DATABASE : "Expand Schedule to MAX_WITNESSES" -DATABASE-->>SCHED : "Updated Schedule" -``` - -**Diagram sources** -- [libraries/chain/database.cpp:2047-2143](file://libraries/chain/database.cpp#L2047-L2143) -- [libraries/protocol/include/graphene/protocol/config.hpp:115-116](file://libraries/protocol/include/graphene/protocol/config.hpp#L115-L116) - -### Emergency Mode Exit Conditions - -Emergency mode automatically deactivates when: -- The last irreversible block advances beyond the emergency start block -- 21 consecutive blocks are produced by the emergency validator (full round completion) -- Network conditions return to normal with sufficient validator participation - -The exit process restores normal operations: -- Disables emergency consensus flag -- Resets fork database emergency mode state -- Removes emergency validator from schedule -- Restores normal validator participation requirements - -### Emergency Consensus Configuration - -Key configuration parameters: -- `CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC`: 3600 seconds (1 hour) timeout for emergency activation -- `CHAIN_EMERGENCY_WITNESS_ACCOUNT`: "committee" account for emergency block production -- `CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY`: Public key for emergency validator signature verification -- `CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS`: 21 blocks for automatic emergency mode exit - -**Section sources** -- [libraries/chain/database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [libraries/chain/database.cpp:2047-2143](file://libraries/chain/database.cpp#L2047-L2143) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/protocol/include/graphene/protocol/config.hpp:110-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L124) - -## Peer Connection Management - -The network library includes enhanced peer connection management specifically designed for emergency consensus mode. These improvements ensure network stability and prevent fork propagation during critical situations. - -### Emergency Mode Peer Soft-Banning - -During emergency consensus mode, the network implements a soft-banning mechanism to prevent peers from propagating losing forks: - -- **fork_rejected_until**: Timestamp-based soft-ban for peers that lose forks during emergency mode -- **Prevents Fork Propagation**: Peers with losing forks are temporarily ignored -- **Maintains Network Stability**: Reduces confusion and prevents split-brain scenarios -- **Automatic Recovery**: Soft-bans expire naturally as emergency mode progresses - -### Peer Connection State Management - -Enhanced peer connection states for emergency mode: -- **Soft-Ban Enforcement**: Peers with fork_rejected_until timestamps are ignored for block propagation -- **Emergency Fork Detection**: Improved detection of emergency-mode fork conflicts -- **Connection Rejection Handling**: Better handling of connection rejections during emergency periods -- **Firewall Check Integration**: Enhanced firewall detection with emergency mode awareness - -```mermaid -classDiagram -class peer_connection { -+fork_rejected_until : time_point -+soft_ban_check() -+emergency_fork_handling() -+connection_rejection_handling() -} -class node { -+emergency_mode_active : bool -+peer_soft_ban_management() -+fork_conflict_resolution() -} -class fork_database { -+emergency_mode_tie_breaking() -+deterministic_hash_selection() -} -peer_connection --> node : "interacts with" -node --> fork_database : "uses for tie-breaking" -``` - -**Diagram sources** -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/chain/fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) - -### Emergency Mode Fork Database Tie-Breaking - -The fork database implements deterministic hash-based tie-breaking during emergency mode: - -- **Hash Comparison**: When multiple blocks compete at the same height, compare block_id hashes -- **Consistent Selection**: Lower block_id hash always wins, ensuring network convergence -- **Deterministic Behavior**: All nodes make identical decisions regardless of P2P arrival order -- **Emergency Mode Activation**: Tie-breaking only active during emergency consensus mode - -This mechanism ensures that even if multiple emergency producers create competing blocks simultaneously, the network will converge to a single chain based on deterministic hash comparison. - -**Section sources** -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/network/peer_connection.cpp:150-349](file://libraries/network/peer_connection.cpp#L150-L349) -- [libraries/chain/fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) - -## DNS Nameserver Helper Functionality - -The wallet library now includes comprehensive DNS nameserver helper functionality that extends blockchain metadata management capabilities with DNS record support for VIZ accounts. - -### DNS Metadata Structure -DNS nameserver helpers manage DNS records stored within account JSON metadata. The metadata structure supports: - -- **NS Array**: Contains DNS record tuples with type and value pairs -- **TTL Value**: Time-to-live for DNS records in seconds -- **SSL Hash**: Optional SHA256 hash for SSL certificate verification - -### Validation Functions -The DNS helpers provide comprehensive validation for DNS metadata: - -- **IPv4 Validation**: Validates IPv4 address format with proper octet ranges -- **SHA256 Hash Validation**: Ensures 64-character hexadecimal hash format -- **TTL Validation**: Requires positive integer values for TTL -- **SSL TXT Record Validation**: Validates "ssl=" format - -### Extraction and Management Operations -The DNS helpers support complete DNS metadata lifecycle management: - -- **Metadata Creation**: Generates DNS metadata JSON with A records and SSL hash TXT records -- **Summary Extraction**: Retrieves complete DNS metadata summary from account JSON -- **Record Extraction**: Extracts specific DNS record types (A records, SSL hashes, TTL values) -- **Record Management**: Sets and removes DNS records while preserving other metadata fields - -### Practical Usage Examples - -#### Setting DNS Records -```cpp -// Configure DNS metadata options -ns_metadata_options options; -options.a_records = {"188.120.231.153", "192.168.1.100"}; -options.ssl_hash = "a1b2c3d4e5f67890123456789012345678901234567890123456789012345678"; -options.ttl = 28800; // 8 hours - -// Validate metadata -auto validation = wallet.ns_validate_metadata(options); -if (validation.is_valid) { - // Set DNS records for account - auto tx = wallet.ns_set_records("myaccount", options, true); -} -``` - -#### Extracting DNS Information -```cpp -// Extract A records -auto a_records = wallet.ns_extract_a_records("myaccount"); -for (const auto& ip : a_records) { - std::cout << "A record: " << ip << std::endl; -} - -// Extract SSL hash -auto ssl_hash = wallet.ns_extract_ssl_hash("myaccount"); -if (ssl_hash) { - std::cout << "SSL hash: " << *ssl_hash << std::endl; -} - -// Extract TTL -auto ttl = wallet.ns_extract_ttl("myaccount"); -std::cout << "TTL: " << ttl << " seconds" << std::endl; -``` - -#### Removing DNS Records -```cpp -// Remove DNS records while preserving other metadata -auto tx = wallet.ns_remove_records("myaccount", true); -``` - -**Section sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:24-62](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L24-L62) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:1310-1420](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L1310-L1420) -- [libraries/wallet/wallet.cpp:2577-2884](file://libraries/wallet/wallet.cpp#L2577-L2884) - -## Postponed Transactions Processing - -The Chain library implements sophisticated postponed transactions processing to handle transactions that cannot be included in a block due to size constraints or execution limits. This system ensures accurate counting and appropriate logging behavior. - -### Postponed Transaction Counting Logic -The system maintains an accurate `postponed_tx_count` variable that tracks transactions postponed due to block size limits: - -- **Size Limit Checking**: Each transaction is evaluated against the maximum block size -- **Counter Increment**: Only transactions that exceed size limits increment the counter -- **Limit Enforcement**: Processing stops when the configured limit is reached -- **Accurate Reporting**: Log messages reflect the actual number of postponed transactions - -### Execution Limits and Performance -The system implements time-based execution limits to prevent excessive processing time: - -- **Execution Window**: Configurable time limit (default 200ms) for processing pending transactions -- **Graceful Degradation**: When time limit is reached, remaining transactions are postponed -- **Known Transaction Filtering**: Skipped known transactions prevent false logging messages - -### Logging Behavior Improvements -Recent improvements ensure accurate logging behavior: - -- **False Positive Prevention**: Known transactions are skipped without generating 'Postponed' messages -- **Accurate Counting**: Only truly postponed transactions contribute to the counter -- **Performance Monitoring**: Proper logging helps monitor block production efficiency - -```mermaid -sequenceDiagram -participant DB as "Database" -participant RESTORER as "pending_transactions_restorer" -participant EXECUTOR as "Transaction Executor" -DB->>RESTORER : "without_pending_transactions()" -RESTORER->>EXECUTOR : "process_popped_tx()" -loop For each popped transaction -EXECUTOR->>DB : "is_known_transaction(tx.id())" -alt Known transaction -EXECUTOR-->>RESTORER : "Skip (no log message)" -else Unknown transaction -EXECUTOR->>DB : "_push_transaction(tx)" -alt Can be applied -EXECUTOR-->>RESTORER : "Applied (count++)" -else Size limit exceeded -EXECUTOR-->>RESTORER : "Postponed (count++)" -end -end -end -RESTORER->>EXECUTOR : "process_pending_tx()" -alt Time limit reached -EXECUTOR-->>RESTORER : "Graceful degradation" -else Continue processing -EXECUTOR-->>RESTORER : "Process remaining" -end -RESTORER-->>DB : "Log postponed transactions" -``` - -**Diagram sources** -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/database.cpp:1165-1202](file://libraries/chain/database.cpp#L1165-L1202) -- [libraries/chain/database.cpp:549-555](file://libraries/chain/database.cpp#L549-L555) - -**Section sources** -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/database.cpp:1165-1202](file://libraries/chain/database.cpp#L1165-L1202) -- [libraries/chain/database.cpp:549-555](file://libraries/chain/database.cpp#L549-L555) - -## Dependency Analysis -The libraries exhibit layered dependencies with enhanced emergency consensus integration: -- Chain depends on Protocol for operation types, transaction structures, and emergency mode configuration -- Network depends on Protocol for message serialization, types, and emergency peer management -- Wallet depends on Protocol for transaction construction and signing, plus includes DNS helpers -- Plugins depend on Chain for database access, on Network for P2P operations, and on Emergency Mode for validator scheduling -- db_with module depends on Chain database for transaction processing and logging -- Emergency consensus components depend on all core libraries for coordinated operation - -```mermaid -graph LR -WALLET["Wallet"] --> PROTO["Protocol"] -WALLET --> DNS_HELPERS["DNS Nameserver Helpers"] -NET["Network"] --> PROTO -NET --> PEER_CONN["Peer Connection
Emergency Management"] -CHAIN["Chain"] --> PROTO -CHAIN --> DB_WITH["Postponed Transactions"] -CHAIN --> EMERGENCY_MODE["Emergency Mode
Components"] -EMERGENCY_MODE --> HYBRID_SCHED["Hybrid Schedule"] -EMERGENCY_MODE --> FORK_DB["Fork Database
Tie-Breaking"] -PL_P2P["P2P Plugin"] --> NET -PL_CHAIN["Chain Plugin"] --> CHAIN -PL_WITNESS["Validator Plugin"] --> CHAIN -MAIN["Main Entry"] --> PL_CHAIN -MAIN --> PL_P2P -MAIN --> PL_WITNESS -``` - -**Diagram sources** -- [libraries/wallet/include/graphene/wallet/wallet.hpp:18-21](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L18-L21) -- [libraries/protocol/include/graphene/protocol/operations.hpp:3-6](file://libraries/protocol/include/graphene/protocol/operations.hpp#L3-L6) -- [libraries/network/include/graphene/network/node.hpp:26-30](file://libraries/network/include/graphene/network/node.hpp#L26-L30) -- [libraries/chain/include/graphene/chain/database.hpp:8-8](file://libraries/chain/include/graphene/chain/database.hpp#L8-L8) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:3-3](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L3-L3) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:7-7](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L7-L7) -- [plugins/validator/validator.cpp:170-198](file://plugins/validator/validator.cpp#L170-L198) -- [programs/vizd/main.cpp:106-140](file://programs/vizd/main.cpp#L106-L140) - -**Section sources** -- [programs/vizd/main.cpp:106-140](file://programs/vizd/main.cpp#L106-L140) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:7-7](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L7-L7) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:3-3](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L3-L3) -- [plugins/validator/validator.cpp:170-198](file://plugins/validator/validator.cpp#L170-L198) -- [libraries/chain/include/graphene/chain/database.hpp:8-8](file://libraries/chain/include/graphene/chain/database.hpp#L8-L8) -- [libraries/network/include/graphene/network/node.hpp:26-30](file://libraries/network/include/graphene/network/node.hpp#L26-L30) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:18-21](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L18-L21) -- [libraries/chain/include/graphene/chain/db_with.hpp:37-100](file://libraries/chain/include/graphene/chain/db_with.hpp#L37-L100) -- [libraries/chain/include/graphene/chain/global_property_object.hpp:134-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L134-L146) -- [libraries/chain/include/graphene/chain/fork_database.hpp:110-138](file://libraries/chain/include/graphene/chain/fork_database.hpp#L110-L138) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) - -## Performance Considerations -- Database tuning: shared memory sizing, flush intervals, and checkpoints reduce I/O overhead -- Validation skipping flags: during reindex or trusted scenarios, selective validation can accelerate startup -- Network bandwidth: rate limiting and propagation tracking help manage traffic -- Wallet caching: minimal caching assumptions favor local APIs with fast node connections -- Operation processing: efficient static_variant dispatch and lazy evaluation optimize performance -- DNS validation: lightweight validation functions minimize overhead for DNS metadata operations -- Postponed transactions: accurate counting prevents unnecessary processing and improves block production efficiency -- Execution limits: configurable time limits prevent excessive processing time during block production -- Emergency consensus: automatic activation reduces manual intervention overhead during network failures -- Peer soft-banning: prevents wasted bandwidth on fork propagation during emergency periods -- Hybrid scheduling: maintains consistent block production rates during emergency mode - -## Troubleshooting Guide -Common issues and diagnostics: -- Validation failures: inspect skip flags and hardfork versions; use validation steps to narrow down failure points -- Authority verification errors: ensure required signatures and approvals match operation requirements -- Network sync stalls: check peer counts, sync status callbacks, and bandwidth limits -- Wallet signing problems: verify chain ID, key derivation, and memo encryption -- Operation classification errors: verify operation type and category using is_virtual_operation and is_data_operation functions -- DNS metadata errors: validate DNS records using ns_validate_metadata and check for proper JSON formatting -- SSL hash validation failures: ensure 64-character hexadecimal format for SSL certificate hashes -- TTL validation errors: verify positive integer values for DNS record TTL settings -- Postponed transactions issues: check block size limits, execution time limits, and known transaction filtering -- Logging accuracy: verify postponed transaction counters and avoid false 'Postponed' messages for skipped known transactions -- Emergency mode activation: verify timeout thresholds and emergency validator configuration -- Hybrid schedule issues: check validator availability and schedule expansion during emergency mode -- Peer soft-banning: monitor fork_rejected_until timestamps and emergency peer connection management -- Fork database tie-breaking: ensure deterministic hash comparison during emergency mode conflicts - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp:56-73](file://libraries/chain/include/graphene/chain/database.hpp#L56-L73) -- [libraries/protocol/transaction.cpp:94-200](file://libraries/protocol/transaction.cpp#L94-L200) -- [libraries/network/include/graphene/network/node.hpp:143-148](file://libraries/network/include/graphene/network/node.hpp#L143-L148) -- [libraries/wallet/include/graphene/wallet/wallet.hpp:311-331](file://libraries/wallet/include/graphene/wallet/wallet.hpp#L311-L331) -- [libraries/protocol/operations.cpp:17-52](file://libraries/protocol/operations.cpp#L17-L52) -- [libraries/wallet/wallet.cpp:2640-2673](file://libraries/wallet/wallet.cpp#L2640-L2673) -- [libraries/chain/database.cpp:1165-1202](file://libraries/chain/database.cpp#L1165-L1202) -- [libraries/chain/database.cpp:549-555](file://libraries/chain/database.cpp#L549-L555) -- [libraries/chain/database.cpp:4334-4438](file://libraries/chain/database.cpp#L4334-L4438) -- [libraries/chain/database.cpp:2047-2143](file://libraries/chain/database.cpp#L2047-L2143) -- [libraries/network/include/graphene/network/peer_connection.hpp:276-277](file://libraries/network/include/graphene/network/peer_connection.hpp#L276-L277) -- [libraries/chain/fork_database.cpp:80-87](file://libraries/chain/fork_database.cpp#L80-L87) - -## Conclusion -The VIZ CPP Node core libraries form a cohesive architecture with enhanced emergency consensus capabilities: Protocol defines canonical operations and transactions, Chain manages state and validation with emergency mode integration, Network enables peer synchronization with emergency peer management, and Wallet provides signing and key management. The enhanced documentation now provides comprehensive coverage of emergency consensus mode, hybrid validator scheduling, peer connection management, blockchain operations, data types, protocol specifications, DNS nameserver helper functionality, and accurate postponed transactions processing with corrected logging behavior, supporting robust transaction processing, block validation, peer coordination, and emergency network stability essential to a production blockchain node. - -**Updated** Enhanced documentation provides expanded coverage of emergency consensus mode, hybrid validator scheduling, peer connection management, blockchain operations, data types, protocol specifications, DNS nameserver helper functionality, and accurate postponed transactions processing with corrected logging behavior, making it easier for developers to understand and work with the VIZ blockchain protocol, manage emergency network conditions, and implement DNS records within account metadata. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Core Libraries/Emergency Consensus System.md b/.qoder/repowiki/en/content/Core Libraries/Emergency Consensus System.md deleted file mode 100644 index b22f2019a7..0000000000 --- a/.qoder/repowiki/en/content/Core Libraries/Emergency Consensus System.md +++ /dev/null @@ -1,648 +0,0 @@ -# Emergency Consensus System - - -**Referenced Files in This Document** -- [database.cpp](file://libraries/chain/database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [12.hf](file://libraries/chain/hardfork.d/12.hf) -- [chainbase.cpp](file://thirdparty/chainbase/src/chainbase.cpp) -- [chainbase.hpp](file://thirdparty/chainbase/include/chainbase/chainbase.hpp) - - -## Update Summary -**Changes Made** -- Enhanced emergency recovery mechanisms with new emergency threshold constants and improved network resilience during critical failure scenarios -- Updated emergency consensus activation with comprehensive LIB availability validation and deterministic synchronization detection -- Improved emergency exit conditions with refined real validator recovery validation using 75% threshold -- Enhanced emergency mode flag management across fork database and Validator Plugin integration -- Strengthened emergency validator management with comprehensive penalty reset and schedule override logic -- Added enhanced memory management protection through operation guards during emergency mode operations - -## Table of Contents -1. [Introduction](#introduction) -2. [System Architecture](#system-architecture) -3. [Core Components](#core-components) -4. [Enhanced Emergency Consensus Activation](#enhanced-emergency-consensus-activation) -5. [Automatic Schedule Recovery](#automatic-schedule-recovery) -6. [Emergency Hybrid Schedule Override](#emergency-hybrid-schedule-override) -7. [Refined Emergency Exit Conditions](#refined-emergency-exit-conditions) -8. [Redesigned Emergency LIB Computation](#redesigned-emergency-lib-computation) -9. [Network Behavior](#network-behavior) -10. [Configuration and Constants](#configuration-and-constants) -11. [Comprehensive Concurrency Protection](#comprehensive-concurrency-protection) -12. [Implementation Details](#implementation-details) -13. [Troubleshooting Guide](#troubleshooting-guide) -14. [Conclusion](#conclusion) - -## Introduction - -The Emergency Consensus System is a critical safety mechanism implemented in the VIZ blockchain to maintain network continuity during extended periods of network stall or validator failure. This system automatically activates when the blockchain stops producing blocks for a predetermined timeout period, ensuring the network remains functional even when regular validator production is compromised. - -The system operates as a three-state safety enforcement mechanism, providing automatic recovery capabilities that prevent network paralysis during emergencies. It maintains consensus integrity while allowing the network to recover from various failure scenarios including validator failures, network partitions, or other catastrophic events. - -**Updated** Enhanced with comprehensive emergency consensus constants and configuration options including CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC, CHAIN_EMERGENCY_WITNESS_ACCOUNT, CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS, CHAIN_IRREVERSIBLE_THRESHOLD, and CHAIN_MAX_WITNESSES * 10 threshold that establishes the foundation for emergency consensus mode activation and operation with deterministic synchronization detection during replay, reindex, and live sync scenarios. - -## System Architecture - -The Emergency Consensus System is built on a distributed architecture that integrates multiple components working together to maintain blockchain functionality: - -```mermaid -graph TB -subgraph "Consensus Layer" -DB[Database Engine] -WS[validator Schedule] -DGP[Dynamic Global Properties] -END -subgraph "Emergency Components" -EW[Emergency validator] -FD[Fork Database] -WC[Validator Plugin] -OG[Operation Guards] -END -subgraph "Network Layer" -P2P[P2P Network] -BP[Block Production] -END -subgraph "Safety Mechanisms" -HC[Hardfork Control] -TM[Timeout Monitor] -EC[Emergency Checker] -MEM[Memory Manager] -ERR[Error Handler] -SD[Deterministic Sync Detector] -SR[Schedule Recovery] -HO[Hybrid Override] -IR[Irreversible Threshold] -END -DB --> WS -DB --> DGP -DB --> FD -DB --> OG -WS --> EW -DGP --> EC -EC --> HC -EC --> TM -EC --> SD -EC --> SR -EC --> HO -EC --> IR -EC --> MEM -EC --> ERR -WC --> BP -BP --> P2P -EC -.-> DB -TM -.-> DB -SD -.-> DB -SR -.-> DB -HO -.-> DB -IR -.-> DB -MEM -.-> DB -ERR -.-> DB -HC -.-> DB -OG -.-> DB -``` - -**Diagram sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [validator.cpp:422-427](file://plugins/validator/validator.cpp#L422-L427) -- [database.cpp:1556](file://libraries/chain/database.cpp#L1556) -- [chainbase.hpp:1097-1115](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1097-L1115) - -The architecture consists of several key layers: - -- **Consensus Layer**: Core blockchain state management and validator scheduling -- **Emergency Components**: Specialized emergency validator and fork database modifications with operation guards -- **Network Layer**: Peer-to-peer communication and block propagation -- **Safety Mechanisms**: Hardfork coordination, timeout monitoring, deterministic synchronization detection, memory management, error handling, automatic schedule recovery, hybrid schedule override, and irreversible threshold validation - -## Core Components - -### Dynamic Global Properties - -The emergency consensus state is maintained through the dynamic global properties object, which tracks critical consensus parameters: - -```mermaid -classDiagram -class dynamic_global_property_object { -+uint32_t head_block_number -+block_id_type head_block_id -+time_point_sec time -+account_name_type current_witness -+uint32_t last_irreversible_block_num -+bool emergency_consensus_active -+uint32_t emergency_consensus_start_block -+uint32_t last_irreversible_block_ref_num -+uint32_t last_irreversible_block_ref_prefix -} -class witness_object { -+account_name_type owner -+public_key_type signing_key -+version running_version -+hardfork_version hardfork_version_vote -+time_point_sec hardfork_time_vote -+uint32_t total_missed -+uint64_t last_aslot -} -class witness_schedule_object { -+fc : : uint128_t current_virtual_time -+uint32_t next_shuffle_block_num -+account_name_type[] current_shuffled_witnesses -+uint8_t num_scheduled_witnesses -+version majority_version -} -dynamic_global_property_object --> witness_schedule_object : "references" -witness_schedule_object --> witness_object : "contains" -``` - -**Diagram sources** -- [global_property_object.hpp:24-146](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L146) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) - -### Enhanced Emergency validator Implementation - -The emergency validator serves as the automated consensus producer during emergency conditions with comprehensive management: - -| Property | Value | Description | -|----------|-------|-------------| -| Account Name | `committee` | Emergency validator account identifier | -| Public Key | `VIZ75CRHVHPwYiUESy1bgN3KhVFbZCQQRA9jT6TnpzKAmpxMPD6Xv` | Block signing key | -| Role | Automated Producer | Produces blocks when network is stalled | -| Schedule Priority | Top | Takes precedence over all other validators | -| Version Synchronization | Automatic | Matches current binary version | -| Hardfork Alignment | Current Status | Votes for currently applied hardfork | -| Penalty Management | Reset | All penalties cleared during emergency | - -**Section sources** -- [config.hpp:114-124](file://libraries/protocol/include/graphene/protocol/config.hpp#L114-L124) -- [witness_objects.hpp:47-61](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L47-L61) - -## Enhanced Emergency Consensus Activation - -### Deterministic Synchronization Detection - -The emergency consensus activation is now protected by a deterministic synchronization detection mechanism that prevents false activations during node replay, reindex, or live sync scenarios: - -```mermaid -flowchart TD -Start([Block Applied]) --> CheckHF{"Hardfork 12 Active?"} -CheckHF --> |No| Normal[Normal Operation] -CheckHF --> |Yes| CheckActive{"Emergency Active?"} -CheckActive --> |Yes| Normal -CheckActive --> |No| CheckLIB["Check LIB Availability"] -CheckLIB --> CheckEmpty{"Is Block Log Empty?"} -CheckEmpty --> |Yes| SkipCheck["Skip Emergency Check"] -CheckEmpty --> |No| CalcTime["Calculate Time Since LIB"] -CalcTime --> CheckTimeout{"Seconds Since LIB ≥ 3600?"} -CheckTimeout --> |No| Normal -CheckTimeout --> |Yes| Activate["Activate Emergency Mode"] -Activate --> CreateWitness["Create/Update Emergency validator Object"] -CreateWitness --> ResetPenalties["Reset All validator Penalties"] -ResetPenalties --> OverrideSchedule["Override Schedule with Emergency validator"] -OverrideSchedule --> NotifyFork["Notify Fork Database"] -NotifyFork --> LogEvent["Log Emergency Activation"] -LogEvent --> Normal -SkipCheck --> Normal -Normal --> End([End]) -``` - -**Diagram sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [config.hpp:110-128](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L128) - -### Enhanced Activation Triggers with Deterministic Synchronization Detection - -The system now implements comprehensive validation with deterministic synchronization detection: - -1. **LIB Availability Validation**: Uses block_log to verify LIB timestamp before activation -2. **Timeout Threshold**: 3,600 seconds (1 hour) since last irreversible block -3. **Hardfork Activation**: Requires CHAIN_HARDFORK_12 to be active -4. **Network Stall Detection**: No blocks produced within timeout period -5. **Snapshot Compatibility**: Handles DLT mode scenarios with proper LIB availability checking -6. **Error Prevention**: Skips emergency check when LIB timestamp cannot be determined -7. **Deterministic Behavior**: Same results on replay as original application - -**Section sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [database.cpp:4887-4906](file://libraries/chain/database.cpp#L4887-L4906) - -## Automatic Schedule Recovery - -### Startup Schedule Repair Mechanism - -The system now includes comprehensive automatic schedule recovery that repairs broken validator schedules during node startup: - -```mermaid -sequenceDiagram -participant DB as Database -participant WSO as validator Schedule -participant DGP as Dynamic Global Properties -DB->>DB : Node Startup -DB->>DGP : Load DGP Object -DB->>WSO : Load validator Schedule -DB->>DB : Check for Empty Slots -alt Empty Slots Found -DB->>DGP : Activate Emergency Mode -DB->>WSO : Override All Slots with Committee -DB->>DB : Log Recovery -else Valid Schedule -DB->>DB : Restore Emergency Mode Flag -end -DB->>DB : Continue Normal Operation -``` - -**Diagram sources** -- [database.cpp:303-357](file://libraries/chain/database.cpp#L303-L357) - -### Comprehensive Schedule Repair Logic - -The automatic schedule recovery system addresses several critical scenarios: - -- **Crash Recovery**: Repairs schedules that became corrupted when nodes shut down during emergency mode -- **Empty Slot Detection**: Identifies validator schedules with null validator names in shuffled positions -- **Emergency Mode Restoration**: Reactivates emergency mode when broken schedules are detected -- **Complete Override**: Fills all schedule slots with emergency validator to ensure network stability -- **Next Shuffle Adjustment**: Updates next shuffle block number to ensure immediate schedule override - -**Section sources** -- [database.cpp:303-357](file://libraries/chain/database.cpp#L303-L357) - -## Emergency Hybrid Schedule Override - -### Dynamic Schedule Adjustment Logic - -The emergency system now implements sophisticated hybrid schedule override that dynamically adjusts validator assignments based on real validator availability: - -```mermaid -flowchart TD -Start([Schedule Update]) --> CheckHF{"Hardfork 12 Active?"} -CheckHF --> |No| Normal[Normal Operation] -CheckHF --> |Yes| CheckEmergency{"Emergency Active?"} -CheckEmergency --> |No| Normal -CheckEmergency --> |Yes| ScanSchedule["Scan Current Shuffled Schedule"] -ScanSchedule --> CountSlots["Count Real vs Committee Slots"] -CountSlots --> CheckAvailability{"Real validators Available?"} -CheckAvailability --> |Yes| FillCommittee["Fill Empty Slots with Committee"] -CheckAvailability --> |No| AllCommittee["All Slots = Committee"] -FillCommittee --> ExpandSchedule["Expand to Max validators"] -AllCommittee --> ExpandSchedule -ExpandSchedule --> UpdateNextShuffle["Update Next Shuffle Block"] -UpdateNextShuffle --> SyncCommittee["Sync Committee Props"] -SyncCommittee --> LogHybrid["Log Hybrid Schedule"] -LogHybrid --> End([End]) -Normal --> End -``` - -**Diagram sources** -- [database.cpp:2561-2591](file://libraries/chain/database.cpp#L2561-L2591) - -### Advanced Hybrid Schedule Features - -The emergency hybrid schedule override provides sophisticated validator management: - -- **Real validator Detection**: Identifies available real validators vs. empty/invalid slots -- **Dynamic Allocation**: Fills empty slots with emergency validator automatically -- **Schedule Expansion**: Expands schedule to include all 21 validators for proper rotation -- **Next Shuffle Optimization**: Adjusts next shuffle block to ensure immediate override -- **Committee Synchronization**: Keeps emergency validator properties synchronized with current state -- **Threshold-Based Logic**: Uses 75% threshold for emergency exit conditions - -**Section sources** -- [database.cpp:2561-2591](file://libraries/chain/database.cpp#L2561-L2591) -- [database.cpp:2596-2612](file://libraries/chain/database.cpp#L2596-L2612) - -## Refined Emergency Exit Conditions - -### Intelligent Automatic Deactivation - -The emergency consensus mode deactivates automatically when intelligent conditions are met: - -```mermaid -flowchart TD -Start([Emergency Active]) --> MonitorLIB["Monitor LIB Progress"] -MonitorLIB --> CheckProgress{"LIB > Start Block?"} -CheckProgress --> |No| Continue["Continue Emergency Mode"] -CheckProgress --> |Yes| CheckRecovery["Check Real validator Recovery"] -CheckRecovery --> CountReal["Count Real validator Slots"] -CountReal --> CheckThreshold{"Real validators ≥ 75%?"} -CheckThreshold --> |No| Continue -CheckThreshold --> |Yes| Deactivate["Deactivate Emergency Mode"] -Deactivate --> ClearFlag["Clear Emergency Flag"] -ClearFlag --> NotifyFork["Notify Fork Database"] -NotifyFork --> LogExit["Log Exit Condition Met"] -LogExit --> Continue -Continue --> End([End]) -``` - -**Diagram sources** -- [database.cpp:2614-2631](file://libraries/chain/database.cpp#L2614-L2631) - -### Advanced Exit Criteria with Enhanced Monitoring - -The system evaluates several sophisticated conditions for emergency mode exit: - -1. **LIB Advancement**: Last Irreversible Block number exceeds start block -2. **Network Recovery**: 75% of schedule slots are real validators (not committee) -3. **Automatic Trigger**: 21 consecutive blocks produced by emergency validator -4. **Manual Intervention**: System administrator override possible -5. **Real-time Monitoring**: Continuous LIB progress tracking during emergency -6. **Deterministic Synchronization**: Prevents premature exit during replay scenarios -7. **Consensus Validation**: Ensures network stability before deactivation - -**Section sources** -- [database.cpp:2614-2631](file://libraries/chain/database.cpp#L2614-L2631) -- [config.hpp:125-128](file://libraries/protocol/include/graphene/protocol/config.hpp#L125-L128) - -## Redesigned Emergency LIB Computation - -### Normal LIB Advancement During Emergency - -The emergency system now implements redesigned LIB computation that advances normally using all validators including committee: - -```mermaid -sequenceDiagram -participant DB as Database -participant WSO as validator Schedule -participant DPO as Dynamic Properties -DB->>DB : Update Last Irreversible Block -DB->>WSO : Get Scheduled validators -WSO-->>DB : Committee + Real validators -DB->>DB : Calculate Support Threshold -DB->>DB : Find Median Support -alt Emergency Mode -DB->>DB : Cap at Head-1 for Safety -DB->>DPO : Commit New LIB -else Normal Mode -DB->>DPO : Commit New LIB -end -DB->>DB : Update Block Log -``` - -**Diagram sources** -- [database.cpp:5473-5545](file://libraries/chain/database.cpp#L5473-L5545) - -### Enhanced LIB Computation Logic - -The redesigned emergency LIB computation provides: - -- **Normal Advancement**: LIB advances using all validators in schedule (including committee) -- **Safety Cap**: Caps LIB at head-1 during emergency to preserve undo protection -- **Median Calculation**: Uses validator support thresholds to determine LIB safely -- **Emergency Protection**: Prevents permanent state corruption during crashes -- **Seamless Transition**: Allows normal LIB computation to resume after emergency exit - -**Section sources** -- [database.cpp:5473-5545](file://libraries/chain/database.cpp#L5473-L5545) -- [database.cpp:5515-5529](file://libraries/chain/database.cpp#L5515-L5529) - -## Network Behavior - -### Enhanced Peer Connection Management - -During emergency mode, the system implements special peer connection handling with enhanced stability measures and deterministic synchronization: - -| Scenario | Action | Rationale | -|----------|--------|-----------| -| Multiple Emergency Producers | Prefer lower block ID hash | Prevents network splits | -| Cascade Disconnections | Prevention measures | Maintains network stability | -| Block Propagation | Normal P2P behavior | Ensures consensus continuity | -| Fork Collisions | Deterministic resolution | Reduces network fragmentation | -| Replay Scenarios | Deterministic handling | Prevents false activations | - -### Comprehensive validator Participation Override - -The emergency system bypasses normal validator participation requirements with enhanced error handling and deterministic synchronization: - -- **Participation Rate Checks**: Automatically enabled during emergency -- **Stale Block Production**: Allowed without penalties -- **Production Scheduling**: Emergency validator takes precedence -- **Conflict Resolution**: Enhanced tie-breaking algorithms -- **Schedule Updates**: Hybrid schedule during emergency mode -- **Deterministic Sync Detection**: Prevents immediate participation during replay -- **Penalty Management**: Comprehensive reset of all validator penalties - -**Section sources** -- [validator.cpp:422-427](file://plugins/validator/validator.cpp#L422-L427) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) - -## Configuration and Constants - -### Enhanced Emergency Consensus Parameters - -The system uses comprehensive configurable constants with enhanced monitoring and deterministic synchronization: - -| Parameter | Value | Unit | Description | -|-----------|-------|------|-------------| -| CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC | 3600 | Seconds | Timeout threshold | -| CHAIN_EMERGENCY_WITNESS_ACCOUNT | "committee" | Account | Emergency producer | -| CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY | VIZ75CR... | Key | Block signing key | -| CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS | 21 | Blocks | Consecutive blocks to exit | -| CHAIN_IRREVERSIBLE_THRESHOLD | 75% | Percent | Recovery threshold | -| CHAIN_MAX_WITNESSES | 21 | validators | Total validator count | -| CHAIN_MAX_WITNESSES * 10 | 210 | Blocks | Deterministic sync threshold | - -### Hardfork Configuration with Enhanced Protection - -The emergency consensus requires specific hardfork activation with comprehensive deterministic synchronization protection: - -- **Hardfork Version**: 12 -- **Activation Time**: 1776620500 (Unix timestamp) -- **Protocol Version**: 3.1.0 -- **Required Nodes**: Majority consensus for activation -- **Deterministic Sync Detection**: Prevents false activations during replay -- **Emergency Activation**: Requires both hardfork and sync detection validation - -**Section sources** -- [config.hpp:110-128](file://libraries/protocol/include/graphene/protocol/config.hpp#L110-L128) -- [12.hf:1-7](file://libraries/chain/hardfork.d/12.hf#L1-L7) - -## Comprehensive Concurrency Protection - -### Advanced Operation Guard Implementation - -The system now implements comprehensive concurrency protection through operation guards that ensure thread-safe emergency mode operations: - -```mermaid -classDiagram -class operation_guard { -+database& _db -+bool _active -+operation_guard(database& db) -+~operation_guard() -+void release() -+operation_guard(operation_guard&& other) -} -class database { -+void enter_operation() -+void exit_operation() -+operation_guard make_operation_guard() -+bool _resize_in_progress -+uint32_t _active_operations -} -class chainbase { -+void begin_resize_barrier() -+void end_resize_barrier() -+void with_read_lock() -+void with_write_lock() -} -operation_guard --> database : "manages" -database --> chainbase : "extends" -``` - -**Diagram sources** -- [chainbase.hpp:1097-1115](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1097-L1115) -- [database.cpp:1721](file://libraries/chain/database.cpp#L1721) -- [database.cpp:1556](file://libraries/chain/database.cpp#L1556) - -### Enhanced Memory Management with Operation Guards - -The enhanced memory management system includes comprehensive operation guard integration: - -- **Pre-resize Protection**: Operation guards prevent concurrent access during memory resizing -- **Thread Safety**: All emergency mode operations are protected by operation guards -- **Concurrent Access Control**: Prevents race conditions during emergency activation -- **Resource Management**: Automatic cleanup of operation guards on scope exit -- **Exception Safety**: Operation guards are properly cleaned up on exceptions - -**Section sources** -- [chainbase.hpp:1097-1115](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1097-L1115) -- [database.cpp:1721](file://libraries/chain/database.cpp#L1721) -- [database.cpp:1556](file://libraries/chain/database.cpp#L1556) - -## Implementation Details - -### Enhanced Database Integration - -The emergency consensus system integrates deeply with the blockchain database with comprehensive error handling and deterministic synchronization: - -```mermaid -classDiagram -class database { -+bool has_hardfork(uint32_t) -+void update_global_dynamic_data() -+void update_signing_witness() -+void update_last_irreversible_block() -+void check_block_post_validation_chain() -+void process_hardforks() -+bool _resize(uint32_t block_num) -+void check_free_memory(bool skip_print, uint32_t current_block_num) -+operation_guard make_operation_guard() -+void _node_startup_time -+bool _enable_emergency_mode -} -class emergency_consensus_system { -+bool emergency_consensus_active -+uint32_t emergency_consensus_start_block -+void activate_emergency_mode() -+void deactivate_emergency_mode() -+bool check_timeout_conditions() -+bool check_deterministic_sync_detection() -+void repair_schedule_on_startup() -+void apply_hybrid_schedule_override() -} -database --> emergency_consensus_system : "manages" -``` - -**Diagram sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [database.hpp:37-612](file://libraries/chain/include/graphene/chain/database.hpp#L37-L612) - -### Advanced Error Handling with Deterministic Synchronization Protection - -The system implements comprehensive error handling throughout the consensus process with enhanced deterministic synchronization protection: - -- **LIB Availability Checks**: Validates LIB timestamp before emergency activation -- **Snapshot Compatibility**: Handles DLT mode scenarios gracefully -- **Memory Management Errors**: Provides detailed logging for memory operations -- **Fork Database Exceptions**: Enhanced error reporting for fork operations -- **validator Creation Failures**: Comprehensive error handling for emergency validator setup -- **Operation Guard Protection**: Thread-safe emergency mode operations -- **Deterministic Behavior**: Same results on replay as original application - -**Section sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [database.cpp:4887-4906](file://libraries/chain/database.cpp#L4887-L4906) - -## Troubleshooting Guide - -### Enhanced Common Issues - -| Issue | Symptoms | Solution | -|-------|----------|----------| -| Emergency Mode Not Activating | No automatic blocks produced | Verify hardfork 12 activation, LIB availability, and sync detection | -| Emergency Mode Stuck | Cannot exit emergency mode | Check LIB advancement, memory management logs, and sync detection validation | -| Network Instability | Frequent disconnections | Review fork database settings, memory usage, and deterministic sync detection | -| validator Production Failures | Emergency validator cannot produce blocks | Verify emergency key configuration, memory allocation, and operation guard protection | -| Memory Issues | Low free memory warnings | Check memory management configuration, resize logs, and operation guard usage | -| Replay Scenarios | Delayed emergency activation | Verify replay detection and ensure CHAIN_MAX_WITNESSES * 10 threshold is observed | -| False Activations | Premature emergency activation | Check deterministic sync detection and LIB timestamp availability | -| Snapshot Restores | Deadlock during emergency activation | Verify DLT mode handling and LIB timestamp validation | -| Broken Schedules | Empty validator slots after crash | Check automatic schedule recovery and emergency mode flags | -| Hybrid Schedule Issues | Incorrect validator assignments | Verify hybrid schedule override logic and real validator detection | - -### Advanced Diagnostic Commands - -To troubleshoot emergency consensus issues with enhanced monitoring: - -1. **Check Emergency Status**: Verify `emergency_consensus_active` flag and start block -2. **Monitor Sync Detection**: Check replay/reindex detection and large block gap validation -3. **Monitor LIB Progress**: Track irreversible block advancement and timestamp -4. **Validate Timeout Logs**: Check activation/deactivation timestamps and LIB availability -5. **Validate Deterministic Sync**: Ensure sync detection passes during replay scenarios -6. **Check Operation Guards**: Monitor thread safety and concurrent access protection -7. **Validate validator Configuration**: Ensure emergency validator exists with correct key and schedule -8. **Monitor Memory Usage**: Check free, reserved, and maximum memory states with operation guard protection -9. **Check Schedule Recovery**: Verify automatic schedule repair and emergency mode restoration -10. **Validate Hybrid Override**: Monitor dynamic validator assignment during emergency - -### Performance Considerations - -- **Memory Usage**: Emergency mode may increase fork database size with detailed logging and operation guard overhead -- **Network Bandwidth**: Additional block propagation during emergency with enhanced monitoring -- **CPU Load**: Extra processing for emergency block validation with deterministic sync detection -- **Storage Impact**: Extended fork database retention during emergencies with better memory management -- **Logging Overhead**: Enhanced detailed logging for troubleshooting with comprehensive operation guard tracking -- **Thread Safety**: Operation guards add minimal overhead for thread-safe emergency mode operations -- **Deterministic Performance**: CHAIN_MAX_WITNESSES * 10 threshold prevents immediate emergency activation during sync -- **Replay Compatibility**: Same results on replay as original application with deterministic behavior - -**Section sources** -- [database.cpp:4863-5004](file://libraries/chain/database.cpp#L4863-L5004) -- [fork_database.cpp:81-88](file://libraries/chain/fork_database.cpp#L81-L88) -- [database.cpp:1556](file://libraries/chain/database.cpp#L1556) - -## Conclusion - -The Emergency Consensus System represents a sophisticated safety mechanism designed to maintain blockchain functionality during critical network failures. By implementing automatic activation, deterministic network behavior, and clear exit conditions, the system provides robust protection against network stalls while maintaining consensus integrity. - -**Updated** The enhanced system now features comprehensive emergency consensus constants and configuration options including CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC for timeout threshold control, CHAIN_EMERGENCY_WITNESS_ACCOUNT for emergency producer configuration, CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS for automatic exit conditions, CHAIN_IRREVERSIBLE_THRESHOLD for recovery validation, and CHAIN_MAX_WITNESSES * 10 threshold for deterministic synchronization detection. These constants establish the foundation for emergency consensus mode that activates when no blocks have been produced for the specified timeout period while preventing false activations during replay, reindex, and live sync scenarios. - -The system's three-state safety enforcement approach ensures that the network can recover from various failure scenarios without requiring manual intervention. Through careful integration with existing consensus mechanisms, network protocols, and comprehensive operation guard protection, the emergency system operates seamlessly with minimal disruption to normal network operations. - -Key enhancements include: -- **Automatic Schedule Recovery**: Comprehensive repair of broken validator schedules during node startup -- **Emergency Hybrid Schedule Override**: Dynamic adjustment of validator assignments based on real validator availability -- **Refined Exit Conditions**: Improved real validator recovery validation using 75% threshold -- **Redesigned LIB Computation**: Normal LIB advancement using all validators during emergency -- **Deterministic Sync Detection**: CHAIN_MAX_WITNESSES * 10 threshold prevents false activations during replay and catch-up scenarios -- **Automatic Recovery**: No manual intervention required for activation with comprehensive validation -- **Network Stability**: Prevents cascade failures during emergencies with enhanced tie-breaking -- **Consensus Integrity**: Maintains blockchain validity during recovery with improved error handling -- **Operational Continuity**: Ensures service availability during outages with comprehensive monitoring -- **Enhanced Reliability**: Improved detection algorithms, memory management, and operation guard protection -- **Better Troubleshooting**: Detailed logging and monitoring capabilities for easier diagnostics -- **Configurable Parameters**: Flexible timeout thresholds, exit conditions, and sync detection for different network conditions -- **Robust Emergency validator**: Dedicated emergency validator with proper key configuration, schedule override, and comprehensive penalty management -- **Thread-Safe Operations**: Comprehensive operation guard protection ensures concurrent access safety -- **Deterministic Behavior**: Same results on replay as original application with comprehensive sync detection -- **Advanced Concurrency Control**: Operation guards provide comprehensive thread safety for emergency mode operations - -The implementation demonstrates best practices in distributed systems design, providing a reliable foundation for blockchain resilience and operational continuity with significantly improved reliability, monitoring capabilities, and thread safety through comprehensive operation guard protection. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Core Libraries/NTP Synchronization System.md b/.qoder/repowiki/en/content/Core Libraries/NTP Synchronization System.md deleted file mode 100644 index d2c044bd59..0000000000 --- a/.qoder/repowiki/en/content/Core Libraries/NTP Synchronization System.md +++ /dev/null @@ -1,582 +0,0 @@ -# NTP Synchronization System - - -**Referenced Files in This Document** -- [ntp.hpp](file://thirdparty/fc/include/fc/network/ntp.hpp) -- [ntp.cpp](file://thirdparty/fc/src/network/ntp.cpp) -- [time.hpp](file://libraries/time/include/graphene/time/time.hpp) -- [time.cpp](file://libraries/time/time.cpp) -- [main.cpp](file://programs/vizd/main.cpp) -- [ntp_test.cpp](file://thirdparty/fc/tests/network/ntp_test.cpp) -- [validator.cpp](file://plugins/validator/validator.cpp) - - -## Update Summary -**Changes Made** -- Enhanced NTP server configuration validation with improved port parsing error handling -- Added comprehensive error validation for NTP server configuration strings -- Updated configuration parsing section to reflect new error handling mechanisms -- Revised troubleshooting guide to address new validation scenarios - -## Table of Contents -1. [Introduction](#introduction) -2. [System Architecture](#system-architecture) -3. [Core Components](#core-components) -4. [NTP Implementation Details](#ntp-implementation-details) -5. [Time Management Layer](#time-management-layer) -6. [Integration with Blockchain Operations](#integration-with-blockchain-operations) -7. [Configuration and Tuning](#configuration-and-tuning) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction - -The NTP (Network Time Protocol) Synchronization System in the VIZ blockchain node provides accurate time synchronization across distributed network participants. This system ensures that all nodes maintain consistent time references, which is critical for blockchain operations such as transaction validation, block production scheduling, and consensus mechanisms. - -The NTP system operates independently of the main blockchain processing but integrates seamlessly with the time management layer to provide synchronized time services to all components of the VIZ node. It implements robust error handling, statistical filtering, and automatic failover mechanisms to maintain reliable time synchronization even in challenging network conditions. - -**Updated** Enhanced with comprehensive server configuration validation and improved port parsing error handling for more reliable NTP server setup. - -## System Architecture - -The NTP synchronization system follows a layered architecture with clear separation of concerns: - -```mermaid -graph TB -subgraph "Application Layer" -VIZD[vizd Main Application] -Plugins[Blockchain Plugins] -end -subgraph "Time Management Layer" -GrapheneTime[Graphene Time Manager] -Config[Configuration Manager] -Validation[Server Validation] -end -subgraph "NTP Service Layer" -FCNTP[FC NTP Service] -Thread[NTP Worker Thread] -Socket[UDP Socket] -end -subgraph "Network Layer" -NTPServers[NTP Server Pool] -Network[Internet] -end -VIZD --> GrapheneTime -Plugins --> GrapheneTime -GrapheneTime --> Validation -GrapheneTime --> FCNTP -FCNTP --> Thread -Thread --> Socket -Socket --> NTPServers -Network --> NTPServers -Config -.-> GrapheneTime -Validation -.-> GrapheneTime -``` - -**Diagram sources** -- [main.cpp:108-142](file://programs/vizd/main.cpp#L108-L142) -- [time.cpp:53-79](file://libraries/time/time.cpp#L53-L79) -- [ntp.cpp:19-61](file://thirdparty/fc/src/network/ntp.cpp#L19-L61) - -The architecture consists of three main layers: - -1. **Application Layer**: The main VIZ node application and blockchain plugins that consume time services -2. **Time Management Layer**: Graphene's time management system that provides a unified interface for time operations and includes enhanced server validation -3. **NTP Service Layer**: The underlying FC (Fast Crypto) NTP implementation with dedicated worker threads - -## Core Components - -### FC NTP Service - -The FC NTP service provides the core time synchronization functionality through a sophisticated UDP-based implementation: - -```mermaid -classDiagram -class ntp { -+ntp() -+~ntp() -+add_server(hostname, port) -+set_servers(servers) -+set_request_interval(interval_sec) -+set_retry_interval(interval_sec) -+set_round_trip_threshold_ms(ms) -+set_delta_history_size(size) -+set_rejection_threshold_pct(pct) -+set_rejection_min_threshold_ms(ms) -+request_now() -+get_time() optional~time_point~ -} -class ntp_impl { --_ntp_thread thread --_ntp_hosts vector~pair~string,uint16_t~~ --_sock udp_socket --_request_interval_sec uint32_t --_retry_failed_request_interval_sec uint32_t --_last_valid_ntp_reply_received_time time_point --_last_ntp_delta_initialized atomic_bool --_last_ntp_delta_microseconds atomic_int64_t --_delta_history deque~int64_t~ --_round_trip_threshold_us uint32_t --_rejection_threshold_pct uint32_t --_rejection_min_threshold_us uint32_t -+start_read_loop() -+read_loop() -+request_time_task() -+request_now() -+ntp_timestamp_to_fc_time_point(ts) -+fc_time_point_to_ntp_timestamp(tp) -} -ntp --> ntp_impl : "owns" -ntp_impl --> udp_socket : "uses" -ntp_impl --> thread : "creates" -``` - -**Diagram sources** -- [ntp.hpp:17-52](file://thirdparty/fc/include/fc/network/ntp.hpp#L17-L52) -- [ntp.cpp:19-61](file://thirdparty/fc/src/network/ntp.cpp#L19-L61) - -### Graphene Time Manager - -The Graphene time manager provides a higher-level interface that integrates NTP services with the broader blockchain ecosystem: - -```mermaid -classDiagram -class time_manager { --_ntp_service atomic~ntp*~ --_ntp_config_mutex mutex --_ntp_service_initialization_mutex mutex --_pending_ntp_config ntp_config -+configure_ntp(config) -+ntp_time() optional~time_point~ -+now() time_point -+nonblocking_now() time_point -+update_ntp_time() -+ntp_error() microseconds -+shutdown_ntp_time() -+start_simulated_time(sim_time) -+advance_simulated_time_to(sim_time) -+advance_time(delta_seconds) -+time_discontinuity_signal signal -} -class ntp_config { -+servers vector~string~ -+request_interval_sec uint32_t -+retry_interval_sec uint32_t -+round_trip_threshold_ms uint32_t -+history_size uint32_t -+rejection_threshold_pct uint32_t -+rejection_min_threshold_ms uint32_t -} -time_manager --> ntp : "manages" -time_manager --> ntp_config : "applies" -``` - -**Diagram sources** -- [time.hpp:17-61](file://libraries/time/include/graphene/time/time.hpp#L17-L61) -- [time.cpp:19-51](file://libraries/time/time.cpp#L19-L51) - -**Section sources** -- [ntp.hpp:17-52](file://thirdparty/fc/include/fc/network/ntp.hpp#L17-L52) -- [time.hpp:17-61](file://libraries/time/include/graphene/time/time.hpp#L17-L61) - -## NTP Implementation Details - -### Time Synchronization Algorithm - -The NTP implementation uses the standard NTPv4 algorithm with several enhancements for blockchain-specific requirements: - -```mermaid -sequenceDiagram -participant Client as "Client Request" -participant NTP as "NTP Service" -participant Server as "NTP Server" -participant Filter as "Statistical Filter" -Client->>NTP : request_now() -NTP->>Server : Send NTP Packet -Server-->>NTP : Receive NTP Response -Note over NTP : Calculate RTT and Offset -NTP->>NTP : Calculate round-trip delay -NTP->>NTP : Calculate time offset -alt Valid Response -NTP->>Filter : Validate against thresholds -Filter-->>NTP : Accept/Reject Decision -alt Accepted -NTP->>NTP : Update delta history -NTP->>NTP : Calculate moving average -NTP->>NTP : Update last valid time -else Rejected -NTP->>NTP : Log rejection -NTP->>Server : Send new request -end -else Stale Response -NTP->>NTP : Request new time -end -Client-->>Client : Return synchronized time -``` - -**Diagram sources** -- [ntp.cpp:176-236](file://thirdparty/fc/src/network/ntp.cpp#L176-L236) - -### Statistical Filtering Mechanism - -The system implements a sophisticated statistical filtering mechanism to reject outliers and maintain accuracy: - -| Parameter | Default Value | Purpose | -|-----------|---------------|---------| -| `request_interval_sec` | 900 (15 minutes) | Time between regular updates | -| `retry_failed_request_interval_sec` | 300 (5 minutes) | Retry interval for failed requests | -| `round_trip_threshold_us` | 150,000 (150ms) | Maximum acceptable round-trip delay | -| `history_size` | 5 | Number of samples in moving average | -| `rejection_threshold_pct` | 50% | Percentage deviation threshold | -| `rejection_min_threshold_us` | 5,000 (5ms) | Minimum absolute deviation threshold | - -**Section sources** -- [ntp.cpp:43-57](file://thirdparty/fc/src/network/ntp.cpp#L43-L57) -- [time.cpp:27-50](file://libraries/time/time.cpp#L27-L50) - -## Time Management Layer - -### Enhanced Server Configuration Validation - -**Updated** The Graphene time manager now includes comprehensive validation for NTP server configuration strings with improved error handling: - -```mermaid -flowchart TD -Start([Server Configuration Input]) --> ParseString["Parse Server String"] -ParseString --> CheckColon{"Contains ':'?"} -CheckColon --> |Yes| ExtractHostPort["Extract Host and Port"] -CheckColon --> |No| UseDefaultPort["Use Default Port 123"] -ExtractHostPort --> ValidatePort["Validate Port Number"] -ValidatePort --> ParseSuccess{"Parse Success?"} -ParseSuccess --> |Yes| AddToParsed["Add to Parsed Servers"] -ParseSuccess --> |No| LogWarning["Log Warning: Invalid Port"] -LogWarning --> UseDefaultPort["Use Default Port 123"] -UseDefaultPort --> AddToParsed -AddToParsed --> NextServer{"More Servers?"} -NextServer --> |Yes| ParseString -NextServer --> |No| ApplyToService["Apply to NTP Service"] -ApplyToService --> ServiceReady([Service Ready]) -``` - -**Diagram sources** -- [time.cpp:29-57](file://libraries/time/time.cpp#L29-L57) - -The validation process includes: - -1. **String Parsing**: Each server string is parsed for host:port format -2. **Port Extraction**: Port numbers are extracted using `rfind(':')` method -3. **Error Handling**: Invalid port numbers are caught with try-catch blocks -4. **Fallback Logic**: Invalid ports fall back to default port 123 -5. **Logging**: Warning messages are logged for invalid configurations - -### Time Service Lifecycle - -The Graphene time manager implements a lazy initialization pattern to ensure efficient resource usage: - -```mermaid -flowchart TD -Start([Application Startup]) --> CheckConfig{"NTP Config Available?"} -CheckConfig --> |Yes| LoadConfig["Load Pending Configuration"] -CheckConfig --> |No| DefaultConfig["Use Defaults"] -LoadConfig --> InitService["Initialize NTP Service"] -DefaultConfig --> InitService -InitService --> CheckService{"Service Exists?"} -CheckService --> |No| CreateService["Create New NTP Service"] -CheckService --> |Yes| UseExisting["Use Existing Service"] -CreateService --> ApplyConfig["Apply Configuration with Validation"] -ApplyConfig --> ValidateServers["Validate Server Configurations"] -ValidateServers --> ApplyToService["Apply Validated Configuration"] -ApplyToService --> Ready([Service Ready]) -UseExisting --> Ready -Ready --> RequestTime["Handle Time Requests"] -RequestTime --> UpdateCheck{"Update Needed?"} -UpdateCheck --> |Yes| ForceUpdate["Force Immediate Update"] -UpdateCheck --> |No| ReturnTime["Return Cached Time"] -ForceUpdate --> ReturnTime -``` - -**Diagram sources** -- [time.cpp:53-79](file://libraries/time/time.cpp#L53-L79) - -### Time Discontinuity Handling - -The system provides mechanisms to handle time discontinuities gracefully: - -```mermaid -stateDiagram-v2 -[*] --> NormalOperation -NormalOperation --> TimeJumpDetected : "Large Time Change" -TimeJumpDetected --> GracefulRecovery : "Signal Handlers" -GracefulRecovery --> NormalOperation : "Stabilized" -state TimeJumpDetected { -[*] --> DetectJump -DetectJump --> LogEvent["Log Time Jump"] -LogEvent --> NotifyListeners["Notify Discontinuity Listeners"] -NotifyListeners --> AdjustOffset["Adjust Time Offset"] -AdjustOffset --> [*] -} -``` - -**Diagram sources** -- [time.cpp:134-137](file://libraries/time/time.cpp#L134-L137) - -**Section sources** -- [time.cpp:53-79](file://libraries/time/time.cpp#L53-L79) -- [time.cpp:134-137](file://libraries/time/time.cpp#L134-L137) - -## Integration with Blockchain Operations - -### Block Production Timing - -The NTP system integrates with the blockchain's block production mechanism to ensure proper timing: - -| Component | Integration Point | Purpose | -|-----------|-------------------|---------| -| Validator Plugin | Block slot calculation | Determines when validators can produce blocks | -| Chain Database | Block timestamp validation | Ensures block timestamps are reasonable | -| P2P Plugin | Peer synchronization | Maintains time consistency across network | -| Wallet | Transaction timestamping | Provides accurate timestamps for operations | - -### Transaction Validation Dependencies - -The time synchronization affects several critical validation processes: - -```mermaid -graph LR -subgraph "Transaction Validation" -T1[Expiration Check] -T2[Signature Validation] -T3[Authority Check] -end -subgraph "Time Dependencies" -NTPT[NTPT Time Source] -NOW[Current Time] -LATE[Late Block Detection] -end -NTPT --> T1 -NTPT --> T2 -NOW --> T1 -LATE --> T1 -style T1 fill:#ffcccc -style T2 fill:#ccffcc -style T3 fill:#ffffcc -``` - -**Diagram sources** -- [p2p_plugin.cpp:158-161](file://plugins/p2p/p2p_plugin.cpp#L158-L161) - -**Section sources** -- [p2p_plugin.cpp:158-161](file://plugins/p2p/p2p_plugin.cpp#L158-L161) - -## Configuration and Tuning - -### Runtime Configuration Options - -The NTP system provides extensive runtime configuration capabilities: - -| Configuration Option | Type | Default | Description | -|---------------------|------|---------|-------------| -| `servers` | `vector` | `["pool.ntp.org:123", "time.google.com:123", "time.cloudflare.com:123"]` | NTP server pool with host:port format | -| `request_interval_sec` | `uint32_t` | 900 | Interval between regular updates (seconds) | -| `retry_interval_sec` | `uint32_t` | 300 | Retry interval for failed requests (seconds) | -| `round_trip_threshold_ms` | `uint32_t` | 150 | Maximum acceptable round-trip delay (milliseconds) | -| `history_size` | `uint32_t` | 5 | Number of samples in moving average | -| `rejection_threshold_pct` | `uint32_t` | 50 | Percentage deviation threshold | -| `rejection_min_threshold_ms` | `uint32_t` | 5 | Minimum absolute deviation threshold (milliseconds) | - -### Enhanced Configuration Application Process - -**Updated** The configuration application process now includes comprehensive server validation: - -```mermaid -flowchart TD -Config[New Configuration] --> ParseServers["Parse Server Strings with Validation"] -ParseServers --> ValidateIntervals["Validate Intervals"] -ValidateIntervals --> ValidateThresholds["Validate Thresholds"] -ValidateThresholds --> ApplyToService["Apply to Active Service"] -ApplyToService --> UpdateExisting["Update Existing Service"] -ApplyToService --> CreateNew["Create New Service Instance"] -UpdateExisting --> RestartTasks["Restart Background Tasks"] -CreateNew --> InitializeTasks["Initialize New Tasks"] -RestartTasks --> ServiceReady([Service Updated]) -InitializeTasks --> ServiceReady -``` - -**Diagram sources** -- [time.cpp:29-57](file://libraries/time/time.cpp#L29-L57) - -### Server Configuration Validation - -**New** The system now validates NTP server configurations with comprehensive error handling: - -The server configuration validation process includes: - -1. **Format Validation**: Each server string is checked for proper host:port format -2. **Port Parsing**: Port numbers are extracted and validated using `std::stoul()` -3. **Error Recovery**: Invalid port numbers trigger fallback to default port 123 -4. **Logging**: Warning messages are generated for invalid configurations -5. **Graceful Degradation**: Invalid entries don't prevent service initialization - -**Section sources** -- [time.hpp:17-40](file://libraries/time/include/graphene/time/time.hpp#L17-L40) -- [time.cpp:29-57](file://libraries/time/time.cpp#L29-L57) - -## Performance Considerations - -### Memory Management - -The NTP system implements efficient memory management strategies: - -- **Thread-Safe Design**: Uses atomic operations for shared state -- **Circular Buffer**: Implements a deque-based history buffer with fixed capacity -- **Lazy Initialization**: Creates NTP service instances only when needed -- **Resource Cleanup**: Properly manages socket connections and thread resources - -### Network Efficiency - -The system optimizes network usage through: - -- **Connection Reuse**: Reuses UDP sockets across requests -- **Batch Processing**: Processes multiple NTP servers in sequence -- **Timeout Handling**: Implements appropriate timeouts for network operations -- **Error Recovery**: Automatically handles temporary network failures - -### Scalability Factors - -Key factors affecting NTP system scalability: - -| Factor | Impact | Optimization Strategy | -|--------|--------|----------------------| -| Server Pool Size | Directly affects reliability | Monitor response rates and adjust dynamically | -| History Window Size | Affects smoothing quality | Balance between responsiveness and stability | -| Update Frequency | Affects network traffic | Tune based on network conditions | -| Threshold Values | Affects accuracy vs. reliability | Calibrate based on deployment environment | - -## Troubleshooting Guide - -### Common Issues and Solutions - -#### NTP Service Not Starting - -**Symptoms**: Time functions return invalid results or throw exceptions - -**Causes**: -- Network connectivity issues -- Firewall blocking UDP port 123 -- DNS resolution failures -- Insufficient privileges - -**Solutions**: -1. Verify network connectivity to NTP servers -2. Check firewall settings for UDP port 123 -3. Test DNS resolution manually -4. Run with appropriate privileges - -#### Time Drift Problems - -**Symptoms**: Persistent time differences between nodes - -**Causes**: -- Incorrect system clock -- Network latency variations -- Server pool configuration issues - -**Solutions**: -1. Check system clock synchronization -2. Adjust round-trip delay thresholds -3. Modify server pool configuration -4. Review network topology - -#### Performance Degradation - -**Symptoms**: Slow response times or frequent timeouts - -**Causes**: -- Network congestion -- Excessive update frequency -- Insufficient history window - -**Solutions**: -1. Reduce update frequency -2. Increase retry intervals -3. Expand history window -4. Optimize network routing - -### Server Configuration Issues - -**Updated** New troubleshooting scenarios for enhanced server validation: - -#### Invalid Server Configuration Entries - -**Symptoms**: Warning messages about invalid port numbers in logs - -**Causes**: -- Malformed server strings (missing or invalid port numbers) -- Non-numeric port values -- Missing colons in server format - -**Solutions**: -1. Verify server strings use format `host:port` -2. Ensure port numbers are valid integers between 1-65535 -3. Check for typos in server hostnames -4. Remove entries with invalid configurations - -#### Port Parsing Errors - -**Symptoms**: Automatic fallback to default port 123 in logs - -**Causes**: -- Invalid port numbers in configuration -- Out-of-range port values -- Non-integer port specifications - -**Solutions**: -1. Use valid port numbers (1-65535) -2. Ensure ports are accessible and not blocked by firewalls -3. Test port connectivity using network tools -4. Consider using default port 123 for standard NTP servers - -### Diagnostic Commands - -The system provides several diagnostic capabilities: - -```bash -# Check current NTP status -curl -s http://localhost:8090/get_ntp_status - -# Monitor time synchronization -watch -n 1 'echo "Current time offset: $(./cli_wallet get_ntp_offset)"' - -# Verify NTP server connectivity -nslookup pool.ntp.org - -# Check for server configuration warnings -tail -f logs/vizd.log | grep "NTP: invalid port" -``` - -**Section sources** -- [ntp_test.cpp:9-28](file://thirdparty/fc/tests/network/ntp_test.cpp#L9-L28) - -## Conclusion - -The NTP Synchronization System in the VIZ blockchain node represents a robust, production-ready solution for maintaining accurate time across distributed network participants. The system's architecture balances reliability, performance, and ease of maintenance through several key design principles: - -**Key Strengths**: -- **Fault Tolerance**: Multiple NTP server support with automatic failover -- **Statistical Filtering**: Advanced outlier detection prevents time corruption -- **Thread Safety**: Concurrent access patterns with proper synchronization -- **Configurability**: Extensive runtime tuning options for various environments -- **Enhanced Validation**: Comprehensive server configuration validation with error recovery -- **Integration**: Seamless integration with blockchain operations and APIs - -**Operational Benefits**: -- **Consistent Timekeeping**: Ensures all blockchain operations use synchronized time -- **Network Coordination**: Enables proper block production and transaction validation -- **Reliability**: Maintains service availability even under adverse conditions -- **Performance**: Optimized for minimal resource usage while maximizing accuracy -- **Resilience**: Graceful handling of configuration errors and network issues - -**Updated** The recent enhancements to server configuration validation significantly improve the system's robustness by automatically handling malformed server entries and providing clear error feedback. This makes the NTP system more resilient to configuration mistakes while maintaining backward compatibility. - -The system's modular design allows for easy maintenance and extension, making it well-suited for the evolving needs of blockchain infrastructure. Its integration with the broader VIZ ecosystem demonstrates thoughtful engineering that prioritizes both technical excellence and operational practicality. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Cloud and Infrastructure.md b/.qoder/repowiki/en/content/Deployment and Operations/Cloud and Infrastructure.md deleted file mode 100644 index 6f7deab33e..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Cloud and Infrastructure.md +++ /dev/null @@ -1,360 +0,0 @@ -# Cloud and Infrastructure - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides cloud and infrastructure deployment guidance for the VIZ CPP Node. It focuses on containerized deployment using the official Docker images, highlights runtime configuration via environment variables and configuration files, and outlines operational practices for high availability, scaling, and observability. Where applicable, it references the repository’s Dockerfiles, configuration templates, and CI/CD workflows to ground recommendations in the existing build and packaging artifacts. - -## Project Structure -The repository includes: -- Container build definitions for production, low-memory, and testnet variants -- Runtime configuration templates for mainnet and testnet -- A container entrypoint script that initializes data directories, applies optional overrides, and starts the node -- GitHub Actions workflows that build and publish Docker images - -```mermaid -graph TB -subgraph "Container Images" -prod["Dockerfile-production"] -lowmem["Dockerfile-lowmem"] -testnet["Dockerfile-testnet"] -end -subgraph "Runtime" -cfg_main["config.ini"] -cfg_test["config_testnet.ini"] -entry["vizd.sh"] -end -gh_main[".github/workflows/docker-main.yml"] -gh_pr[".github/workflows/docker-pr-build.yml"] -prod --> cfg_main -lowmem --> cfg_main -testnet --> cfg_test -entry --> cfg_main -entry --> cfg_test -gh_main --> prod -gh_main --> testnet -gh_pr --> testnet -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -**Section sources** -- [README.md](file://README.md#L12-L29) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Core Components -- Container images - - Production image: optimized for mainnet operation - - Low-memory image: tuned for constrained environments - - Testnet image: preconfigured for testnet operation -- Runtime configuration - - Mainnet configuration template - - Testnet configuration template -- Entrypoint script - - Initializes data directory - - Applies environment-driven overrides - - Starts the node process - -Key runtime ports exposed by the images: -- RPC HTTP: 8090 -- RPC WS: 8091 -- P2P: 2001 - -Volumes: -- Data directory: persists blockchain data -- Config directory: allows mounting custom configuration - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L74-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L68-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L75-L88) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L16-L20) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L16-L20) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L74-L81) - -## Architecture Overview -The recommended deployment model is container-first: -- Run one or more VIZ node containers behind a load balancer -- Persist blockchain data via volumes -- Mount configuration files and seed node lists as needed -- Use environment variables to override endpoints and enable validator operation when required - -```mermaid -graph TB -LB["Load Balancer
HTTP 8090 / WS 8091"] -subgraph "Nodes" -N1["vizd Container 1"] -N2["vizd Container 2"] -Nn["... n replicas"] -end -VOL["Persistent Volume
/var/lib/vizd"] -CFG["Config Volume
/etc/vizd"] -LB --> N1 -LB --> N2 -LB --> Nn -N1 --> VOL -N2 --> VOL -Nn --> VOL -N1 --> CFG -N2 --> CFG -Nn --> CFG -``` - -[No sources needed since this diagram shows conceptual workflow, not actual code structure] - -## Detailed Component Analysis - -### Container Images and Build Artifacts -- Production image - - Multi-stage build with a base image and a final runtime stage - - Installs compiled binaries and sets up a dedicated user - - Exposes RPC and P2P ports - - Declares persistent volumes for data and config -- Low-memory image - - Similar structure to production but enables a low-memory mode during build -- Testnet image - - Includes testnet-specific configuration and snapshot - - Enables validator operation by default - -Operational notes: -- The images are published by the CI/CD workflows -- The workflows build and push images tagged as latest and testnet - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) - -### Runtime Configuration and Environment Overrides -The node reads configuration from a mounted config file and supports environment-driven overrides via the entrypoint script. Notable runtime parameters include: -- RPC endpoint binding -- P2P endpoint binding -- validator name and private key -- Seed nodes list -- Optional extra arguments - -Configuration templates: -- Mainnet template defines default endpoints, plugin list, and logging configuration -- Testnet template adds validator operation and adjusts participation thresholds - -```mermaid -flowchart TD -Start(["Container Start"]) --> LoadCfg["Load config.ini or config_testnet.ini"] -LoadCfg --> ApplyEnv["Apply environment overrides
RPC, P2P, Seed, validator, Private Key"] -ApplyEnv --> InitData["Initialize data directory
and blockchain cache if present"] -InitData --> RunNode["Start vizd with merged args"] -RunNode --> End(["Running"]) -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L39-L81) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L39) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -### CI/CD and Image Publishing -- The main workflow builds and pushes: - - testnet image on push to master - - latest image on push to master -- The PR workflow builds a testnet image and tags it with the PR ref - -These workflows provide a baseline for automated image creation and can be extended to support cloud-native deployment pipelines. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Dependency Analysis -The runtime depends on: -- Base OS packages installed in the image -- Compiled node binary and shared libraries -- Persistent volumes for data and configuration -- Network connectivity to peers and clients - -```mermaid -graph LR -IMG["Docker Image"] --> BIN["vizd Binary"] -IMG --> LIBS["Shared Libraries"] -IMG --> CFG["Config Files"] -BIN --> DATA["/var/lib/vizd"] -BIN --> LOGS["Logs"] -NET["Network Ports
8090/8091/2001"] --> PEERS["Peers"] -NET --> CLIENTS["Clients"] -``` - -[No sources needed since this diagram shows conceptual relationships, not specific code structure] - -## Performance Considerations -- Single write thread: the configuration encourages a single-threaded write path to reduce contention on the database lock -- Shared memory sizing: initial and incremental sizes are configurable to balance memory footprint and growth overhead -- Thread pool sizing: the HTTP server thread pool can be tuned to match CPU cores -- Lock wait limits: read/write lock wait microsecond and retry counts help manage concurrency under load - -Recommendations: -- Size shared memory according to expected chain state growth and available host memory -- Adjust thread pool size based on CPU cores and expected concurrent requests -- Monitor lock wait metrics and tune retries if contention is observed - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L36-L47) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) - -## Troubleshooting Guide -Common operational checks: -- Verify ports 8090 (HTTP), 8091 (WS), and 2001 (P2P) are reachable -- Confirm persistent volume is mounted and writable -- Review logs written to the configured log directories -- Validate seed nodes connectivity and adjust seed list if needed -- For validator nodes, confirm validator name and private key are set appropriately - -Environment overrides: -- Override RPC and P2P endpoints if necessary -- Provide custom seed nodes via environment variable -- Enable validator operation by setting validator name and private key - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L31-L37) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L111-L130) - -## Conclusion -The repository provides a solid foundation for deploying VIZ CPP Node in containers with production-ready images and configuration templates. By leveraging environment-driven overrides, persistent volumes, and a load-balanced deployment pattern, operators can achieve high availability and scalability. The CI/CD workflows automate image creation, which can be extended to support cloud-native deployment pipelines. - -## Appendices - -### Cloud Provider Deployment Strategies -- AWS - - Compute: choose general-purpose or compute-optimized instances depending on workload; consider EBS gp3 or io2 for IOPS-sensitive workloads - - Networking: place nodes in private subnets behind NAT for outbound access; expose RPC via Application Load Balancer with WSS support - - Storage: provision EBS volumes or EFS for shared data; enable snapshots for backups - - IAM: attach least-privilege roles for metadata and logging -- Google Cloud - - Compute: use sustained use discounts or committed use commitments; SSD persistent disks for performance - - Networking: Cloud Load Balancing with internal and external tiers; firewall rules for RPC and P2P ports - - Storage: Persistent Disk or Filestore; Cloud Backup for snapshots -- Azure - - Compute: burstable or DC-series VMs; Premium SSD disks for IOPS - - Networking: Load Balancer or Application Gateway; NSGs for port-based access - - Storage: Managed Disks or NetApp Files; Automation Account for scheduled snapshots - -[No sources needed since this section provides general guidance] - -### Infrastructure-as-Code Approaches -- Terraform - - Define VPC, subnets, security groups, autoscaling groups, and load balancers - - Provision managed volumes and attach to instances - - Use data sources to fetch latest container image digests for immutability -- CloudFormation (AWS) - - StackSets for multi-account/multi-region rollouts - - Parameterized templates for environment-specific tuning -- Other IaC tools - - Pulumi, Ansible playbooks, or Helm charts for Kubernetes-native deployments - -[No sources needed since this section provides general guidance] - -### Load Balancing, Auto Scaling, and High Availability -- Load balancing - - Distribute traffic across multiple node instances - - Enable health checks on RPC endpoints -- Auto scaling - - Scale on CPU, network I/O, or request latency - - Use predictive scaling for predictable traffic patterns -- High availability - - Deploy across multiple AZs - - Use standby nodes with failover mechanisms - -[No sources needed since this section provides general guidance] - -### CDN Integration, SSL/TLS, and Security Groups -- CDN - - Offload static assets and public APIs via CDN fronting -- SSL/TLS - - Terminate TLS at the load balancer; secure backend-to-backend communication -- Security groups/firewall - - Allow inbound RPC only from trusted networks - - Permit P2P egress to seed nodes and restrict ingress to necessary ports - -[No sources needed since this section provides general guidance] - -### Monitoring, Alerting, Log Aggregation, and Metrics -- Cloud-native tools - - Use platform-native observability suites for metrics and logs -- Log aggregation - - Stream node logs to centralized logging systems -- Metrics - - Track RPC latency, throughput, peer count, and disk usage - -[No sources needed since this section provides general guidance] - -### Cost Optimization, Reserved/Spot Instances -- Reserved instances - - Commit to steady-state capacity with savings plans or reserved instances -- Spot instances - - Use for fault-tolerant, stateless workers; avoid critical validator slots - -[No sources needed since this section provides general guidance] - -### Disaster Recovery, Backups, and Multi-Region -- Backups - - Snapshot persistent volumes regularly; retain offsite copies -- DR - - Replicate volumes across regions; automate failover procedures -- Multi-region - - Operate secondary region for read replicas or cold standby - -[No sources needed since this section provides general guidance] - -### Migration, Blue-Green, and Rolling Upgrades -- Blue-green - - Deploy new version alongside live; switch traffic on validation -- Rolling upgrades - - Upgrade nodes in batches with health checks between batches -- Migration - - Use snapshots to migrate between providers or regions - -[No sources needed since this section provides general guidance] \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Containerization and Docker.md b/.qoder/repowiki/en/content/Deployment and Operations/Containerization and Docker.md deleted file mode 100644 index c5d88b64b9..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Containerization and Docker.md +++ /dev/null @@ -1,440 +0,0 @@ -# Containerization and Docker - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini) -- [share/vizd/config/config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive guidance for containerizing and deploying the VIZ C++ Node using Docker. It covers image variants (production, testnet, low-memory, and MongoDB-enabled), Dockerfile construction and multi-stage builds, configuration and runtime customization, orchestration patterns, volume and network management, security and resource best practices, monitoring integration, deployment workflows, scaling, upgrades, and troubleshooting. - -## Project Structure -The repository includes Dockerfiles and configuration templates under share/vizd/docker and share/vizd/config, along with CI/CD workflows for automated image builds. - -```mermaid -graph TB -A["Dockerfiles"] --> A1["Dockerfile-production"] -A --> A2["Dockerfile-testnet"] -A --> A3["Dockerfile-lowmem"] -A --> A4["Dockerfile-mongo"] -B["Config Templates"] --> B1["config.ini"] -B --> B2["config_testnet.ini"] -B --> B3["config_mongo.ini"] -B --> B4["config_debug.ini"] -B --> B5["config_debug_mongo.ini"] -C["Entrypoint Script"] --> C1["vizd.sh"] -D["CI/CD Workflows"] --> D1[".github/workflows/docker-main.yml"] -D --> D2[".github/workflows/docker-pr-build.yml"] -E["MongoDB Plugin"] --> E1["mongo_db_plugin.hpp"] -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini#L1-L126) -- [share/vizd/config/config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) - -**Section sources** -- [README.md](file://README.md#L12-L52) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Core Components -- Docker image variants: - - Production: Built from master, intended for the main VIZ network. - - Testnet: Built from master, suitable for local/regression test networks. - - Low-memory: Optimized for constrained environments. - - MongoDB-enabled: Includes the mongo_db plugin for external database indexing/export. -- Entrypoint script: Initializes volumes, applies environment overrides, seeds peers, and starts the node. -- Configuration templates: Provide defaults for RPC endpoints, P2P, logging, plugins, and optional MongoDB connectivity. - -Key runtime environment variables supported by the entrypoint: -- VIZD_SEED_NODES: Override seed nodes. -- VIZD_WITNESS_NAME: Configure validator name for block production. -- VIZD_PRIVATE_KEY: Private key for signing blocks. -- VIZD_RPC_ENDPOINT: Override RPC HTTP endpoint. -- VIZD_P2P_ENDPOINT: Override P2P endpoint. -- VIZD_EXTRA_OPTS: Additional arguments appended to the node command. - -Exposed ports: -- 8090 TCP (HTTP RPC) -- 8091 TCP (WebSocket RPC) -- 2001 TCP (P2P) - -Volumes: -- /var/lib/vizd: Blockchain data directory (blocks, databases, caches). -- /etc/vizd: Configuration directory (config.ini, seednodes). - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L89-L111) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L81) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L16-L20) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L16-L20) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L16-L20) - -## Architecture Overview -The container architecture consists of a multi-stage build that compiles the node in a builder stage and installs artifacts into a minimal runtime base. The runtime stage sets up a non-root user, exposes ports, mounts volumes, and starts the node via an entrypoint script. - -```mermaid -graph TB -subgraph "Builder Stage" -B1["Install build deps
cmake, gcc, boost, python3"] -B2["Clone repo and submodules"] -B3["Configure with CMake
Release build"] -B4["Compile and install"] -end -subgraph "Runtime Stage" -R1["Minimal base image"] -R2["Create non-root user 'vizd'"] -R3["Set up cache and config dirs"] -R4["Copy installed binaries and assets"] -R5["Expose ports 8090, 8091, 2001"] -R6["Mount volumes /var/lib/vizd, /etc/vizd"] -R7["Entrypoint script 'vizd.sh'"] -end -B4 --> R4 -R7 --> R8["Start vizd process"] -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L74-L81) - -## Detailed Component Analysis - -### Dockerfile-production -- Purpose: Production image for the main VIZ network. -- Build characteristics: - - Multi-stage build with a dedicated builder stage. - - Installs build dependencies and compiles Release binaries. - - Copies installed artifacts to the runtime stage. -- Runtime characteristics: - - Creates non-root user and cache directories. - - Copies default config and seednodes. - - Exposes RPC and P2P ports. - - Declares volumes for data and config. - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -### Dockerfile-testnet -- Purpose: Testnet image for local/regression testing. -- Differences from production: - - Enables BUILD_TESTNET during CMake configuration. - - Uses testnet-specific snapshot and config template. -- Runtime characteristics: - - Same runtime setup as production. - -**Section sources** -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) - -### Dockerfile-lowmem -- Purpose: Low-memory footprint variant for constrained environments. -- Differences: - - Configures LOW_MEMORY_NODE during CMake. - - Uses an older base image tag for smaller size. -- Runtime characteristics: - - Same runtime setup and exposed ports. - -**Section sources** -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) - -### Dockerfile-mongo -- Purpose: MongoDB-enabled image for external indexing/export. -- Differences: - - Installs MongoDB C/C++ drivers in the builder stage. - - Configures ENABLE_MONGO_PLUGIN during CMake. - - Copies mongo-specific config template. -- Runtime characteristics: - - Same runtime setup and volumes. - -**Section sources** -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) - -### Entrypoint Script (vizd.sh) -Responsibilities: -- Initialize ownership for data/config directories. -- Seed peers from /etc/vizd/seednodes if no explicit override is provided. -- Apply environment overrides for validator name/private key, RPC/P2P endpoints, and extra options. -- Optionally initialize blockchain from a cached snapshot if present. -- Start the node with chpst under the non-root user. - -```mermaid -flowchart TD -Start(["Entrypoint Start"]) --> InitDirs["Initialize ownership for /var/lib/vizd and /etc/vizd"] -InitDirs --> LoadSeed["Load default seednodes from /etc/vizd/seednodes"] -LoadSeed --> CheckEnvSeed{"VIZD_SEED_NODES set?"} -CheckEnvSeed --> |Yes| UseEnvSeed["Append user-provided seed nodes"] -CheckEnvSeed --> |No| UseDefaultSeed["Append default seed nodes"] -UseEnvSeed --> ApplyWitness["Apply VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY if provided"] -UseDefaultSeed --> ApplyWitness -ApplyWitness --> CopyCfg["Copy /etc/vizd/config.ini to /var/lib/vizd/config.ini"] -CopyCfg --> CheckSnapshot{"Cached snapshot exists?"} -CheckSnapshot --> |Yes| Replay["Enable replay and extract snapshot to database"] -CheckSnapshot --> |No| PrepareArgs["Prepare default args"] -Replay --> PrepareArgs -PrepareArgs --> OverrideEndpoints["Apply VIZD_RPC_ENDPOINT and VIZD_P2P_ENDPOINT"] -OverrideEndpoints --> ExecNode["Exec vizd with args and VIZD_EXTRA_OPTS"] -ExecNode --> End(["Container Running"]) -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -### Configuration Templates -- config.ini: Default production configuration with RPC endpoints, plugin list, and logging. -- config_testnet.ini: Testnet-specific configuration with validator participation enabled and test keys. -- config_mongo.ini: MongoDB-enabled configuration with mongodb-uri and mongo_db plugin enabled. -- Debug configs: Smaller shared memory and debug logging for development/testing. - -Key configurable areas: -- RPC endpoints (HTTP and WS) -- P2P endpoint and seed nodes -- Plugin list and options -- Logging appenders and levels -- Optional MongoDB URI for mongo_db plugin - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini#L1-L126) -- [share/vizd/config/config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini#L1-L135) - -### MongoDB Plugin Integration -- The mongo_db plugin is declared in the mongo-enabled configuration and requires a MongoDB connection URI. -- The plugin header defines the plugin lifecycle hooks and dependencies. - -**Section sources** -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) - -## Dependency Analysis -- Dockerfiles depend on: - - Base image (phusion/baseimage) for runtime. - - Builder stage installing build tools and dependencies. - - CMake configuration flags controlling features (BUILD_TESTNET, LOW_MEMORY_NODE, ENABLE_MONGO_PLUGIN). -- Entrypoint depends on: - - Presence of config and seednodes in /etc/vizd. - - Optional cached snapshot in /var/cache/vizd. -- CI/CD workflows depend on Docker build-push action and Docker Hub credentials. - -```mermaid -graph LR -DFProd["Dockerfile-production"] --> |builds| IMGProd["Image: latest"] -DFTnet["Dockerfile-testnet"] --> |builds| IMGTnet["Image: testnet"] -DFLowmem["Dockerfile-lowmem"] --> |builds| IMGLowmem["Image: lowmem variant"] -DFMongo["Dockerfile-mongo"] --> |builds| IMGMongo["Image: mongo variant"] -IMGProd --> CFGProd["config.ini"] -IMGTnet --> CFGTnet["config_testnet.ini"] -IMGMongo --> CFGMongo["config_mongo.ini"] -Entryp["vizd.sh"] --> IMGProd -Entryp --> IMGTnet -Entryp --> IMGMongo -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) - -## Performance Considerations -- Multi-stage builds reduce final image size by discarding build tools and intermediate artifacts. -- Using Release builds and disabling shared library builds reduces binary size and improves runtime performance characteristics. -- Low-memory variant reduces shared memory footprint and related allocations for constrained environments. -- MongoDB driver installation adds overhead; enable only when required. -- Tune webserver-thread-pool-size and shared memory parameters per workload and CPU cores. -- Prefer pre-seeded snapshots to accelerate initial sync on first run. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Ports already in use: - - Ensure host ports 8090, 8091, and 2001 are available or map to different host ports. -- Permission denied on data directory: - - Verify /var/lib/vizd is writable by the non-root user. -- No connectivity to seed nodes: - - Override VIZD_SEED_NODES with reachable nodes or ensure default seednodes are present. -- MongoDB plugin failures: - - Confirm mongodb-uri is reachable from the container network and plugin is enabled in config. -- Slow initial sync: - - Provide a cached snapshot in /var/cache/vizd to enable automatic replay on first run. -- Logs not visible: - - Check default and p2p log appenders configured in the active config template. - -Operational tips: -- Use docker logs -f to stream logs. -- Adjust log levels in config for verbose diagnostics. -- Validate configuration syntax by mounting a custom config.ini to /etc/vizd and copying it into /var/lib/vizd during startup. - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L44-L53) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L112-L129) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L116-L134) - -## Conclusion -The VIZ C++ Node provides a robust set of Docker images tailored for production, testnet, low-memory, and MongoDB-enabled deployments. The multi-stage Dockerfiles, entrypoint-driven configuration, and modular config templates enable flexible, secure, and efficient containerized operations. By leveraging volumes, environment overrides, and CI/CD automation, operators can reliably deploy, scale, and maintain VIZ nodes in containerized environments. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Image Variants and Use Cases -- Production (latest): - - Use for main VIZ network. - - Built from master with standard production settings. -- Testnet (testnet): - - Use for local/regression testing. - - Includes testnet-specific snapshot and configuration. -- Low-memory: - - Use on constrained systems. - - Optimized shared memory and build settings. -- MongoDB-enabled: - - Use when external indexing/export to MongoDB is required. - - Includes MongoDB drivers and plugin configuration. - -**Section sources** -- [README.md](file://README.md#L16-L29) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L54) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L53) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L82) - -### Dockerfile Construction and Optimization -- Multi-stage builds: - - Builder stage installs build tools and compiles Release binaries. - - Runtime stage copies installed artifacts and sets up a minimal environment. -- Optimization techniques: - - Clean package manager caches after installs. - - Remove temporary build artifacts post-install. - - Use non-root user and restrict filesystem permissions. - - Keep base image versions pinned for reproducibility. - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L61-L64) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L62-L65) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L55-L58) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L32-L57) - -### Container Orchestration and Service Discovery -- Docker Compose: - - Define services with port mappings, volumes, environment variables, and restart policies. - - Use networks to connect vizd with MongoDB (for mongo-enabled variant). -- Kubernetes: - - Deploy as a StatefulSet with persistent volume claims for /var/lib/vizd. - - Use ConfigMaps for config.ini and seednodes. - - Expose services for RPC (TCP 8090/8091) and P2P (TCP 2001). - - Implement readiness/liveness probes against RPC endpoints. - -[No sources needed since this section provides general guidance] - -### Volume Management and Network Configuration -- Volumes: - - /var/lib/vizd: Persistent blockchain data and caches. - - /etc/vizd: Configuration and seednodes. -- Network: - - Publish 8090/8091 for RPC and 2001 for P2P. - - For mongo-enabled, ensure MongoDB is reachable via mongodb-uri. - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L87-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L87-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L81-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L110-L111) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L71-L72) - -### Security Best Practices and Resource Limits -- Security: - - Run as non-root user. - - Limit container capabilities and mount only necessary volumes. - - Pin base image versions and rebuild periodically. -- Resource limits: - - Set CPU/memory limits appropriate for workload. - - Monitor shared memory growth and adjust shared-file-size accordingly. - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L70-L72) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L70-L72) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L63-L66) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) - -### Monitoring Integration -- Logs: - - Use console and file appenders defined in config templates. - - Stream container logs and ship to centralized logging systems. -- Health checks: - - Probe RPC endpoints for readiness. -- Metrics: - - Expose metrics via plugins if available; otherwise monitor logs and container stats. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L112-L129) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L113-L131) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L116-L134) - -### Deployment Workflows, Scaling, and Upgrades -- Workflows: - - Automated builds for master branch (latest) and PRs (testnet). -- Scaling: - - Stateless RPC: Scale horizontally behind a load balancer. - - P2P: Coordinate seed nodes and network topology carefully. -- Upgrades: - - Pull new image tag, stop container, backup /var/lib/vizd, start with same volumes and env. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) -- [README.md](file://README.md#L40-L52) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Deployment and Operations.md b/.qoder/repowiki/en/content/Deployment and Operations/Deployment and Operations.md deleted file mode 100644 index 069f172ab3..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Deployment and Operations.md +++ /dev/null @@ -1,425 +0,0 @@ -# Deployment and Operations - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [building.md](file://documentation/building.md) -- [testnet.md](file://documentation/testnet.md) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [vizd.sh](file://share/vizd/vizd.sh) -- [main.cpp](file://programs/vizd/main.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive deployment and operations guidance for the VIZ CPP Node. It covers production deployment strategies, hardware and security considerations, containerization with multiple image variants, orchestration options, cloud deployment, high availability, node types (full, validator, seed), monitoring and maintenance, security hardening, troubleshooting, and backup/disaster recovery. - -## Project Structure -The repository organizes deployment assets and operational artifacts primarily under share/vizd, with configuration templates, Dockerfiles, and scripts for containerized deployments. Documentation for building and testnet operations resides under documentation/. - -```mermaid -graph TB -A["Repository Root"] --> B["share/vizd"] -B --> B1["config/ (configs)"] -B --> B2["docker/ (Dockerfiles)"] -B --> B3["vizd.sh (entrypoint)"] -A --> C["documentation/ (build, testnet, debug_node)"] -A --> D["programs/vizd/main.cpp (node entry)"] -A --> E[".github/workflows/ (CI/CD)"] -``` - -**Diagram sources** -- [README.md](file://README.md#L1-L53) -- [building.md](file://documentation/building.md#L1-L212) -- [testnet.md](file://documentation/testnet.md#L1-L54) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [main.cpp](file://programs/vizd/main.cpp#L1-L291) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [building.md](file://documentation/building.md#L1-L212) -- [testnet.md](file://documentation/testnet.md#L1-L54) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [main.cpp](file://programs/vizd/main.cpp#L1-L291) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Core Components -- Container images - - Production image: Built from Dockerfile-production, intended for mainnet. - - Testnet image: Built from Dockerfile-testnet, intended for test networks. - - Low-memory image: Built from Dockerfile-lowmem, optimized for resource-constrained environments. -- Configuration templates - - config.ini: General-purpose configuration for mainnet. - - config_testnet.ini: Testnet-specific configuration with validator participation enabled. - - config_witness.ini: validator node configuration with RPC bound to localhost and virtual ops skipped. - - config_mongo.ini: Extended configuration including MongoDB plugin for analytics. -- Entrypoint script - - vizd.sh: Orchestrates seed node injection, RPC/P2P endpoints, replay initialization, and runtime arguments. -- Node binary - - programs/vizd/main.cpp: Registers plugins and initializes the node runtime. - -Key operational parameters and behaviors: -- P2P and RPC endpoints are configurable via environment variables and config files. -- Shared memory sizing and growth thresholds are tunable to manage memory pressure. -- Lock wait timeouts and retries are configurable to balance throughput and latency. -- Plugin selection determines node capabilities (e.g., validator, mongo, debug_node). - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [main.cpp](file://programs/vizd/main.cpp#L60-L91) - -## Architecture Overview -The VIZ node is a modular application with pluggable subsystems for chain processing, P2P networking, webserver APIs, and optional plugins (e.g., validator, mongo, debug_node). Containerization encapsulates dependencies and exposes standardized ports for RPC (HTTP/WebSocket) and P2P communication. - -```mermaid -graph TB -subgraph "Container Runtime" -C1["vizd container"] -end -subgraph "Node Process" -N1["vizd binary
plugins: chain, p2p, webserver, validator, mongo, etc."] -end -subgraph "Storage" -S1["/var/lib/vizd (data dir)"] -S2["/etc/vizd (config)"] -end -subgraph "Networking" -P1["P2P: 2001/tcp"] -P2["RPC HTTP: 8090/tcp"] -P3["RPC WS: 8091/tcp"] -end -C1 --> N1 -N1 --> S1 -N1 --> S2 -N1 --> P1 -N1 --> P2 -N1 --> P3 -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L68-L79) -- [vizd.sh](file://share/vizd/vizd.sh#L74-L81) -- [config.ini](file://share/vizd/config/config.ini#L1-L20) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L20) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L20) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L87) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L87) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L79) -- [vizd.sh](file://share/vizd/vizd.sh#L74-L81) -- [config.ini](file://share/vizd/config/config.ini#L1-L20) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L20) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L20) - -## Detailed Component Analysis - -### Container Images and Orchestration -- Production image - - Purpose: Run mainnet nodes. - - Build: Uses Dockerfile-production with Release build and standard plugins. - - Ports exposed: 8090 (HTTP RPC), 8091 (WS RPC), 2001 (P2P). - - Volumes: /var/lib/vizd (blockchain data), /etc/vizd (config). -- Testnet image - - Purpose: Local testnet and development. - - Build: Uses Dockerfile-testnet with BUILD_TESTNET enabled. - - Ports and volumes same as production. -- Low-memory image - - Purpose: Resource-constrained environments; consensus-only behavior. - - Build: Uses Dockerfile-lowmem with LOW_MEMORY_NODE enabled. -- CI/CD - - docker-main.yml builds and pushes latest and testnet tags. - - docker-pr-build.yml builds testnet images for pull requests. - -Operational notes: -- Environment overrides for endpoints and seed nodes are supported via vizd.sh. -- Snapshot caching enables fast startup when blocks are prepackaged. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -### Configuration Templates and Node Types -- Full node (mainnet) - - Use config.ini as baseline. - - Typical plugins include chain, p2p, webserver, database_api, account_history, operation_history, and others. -- Full node (testnet) - - Use config_testnet.ini; includes validator participation and a default validator identity. -- validator node - - Use config_witness.ini; RPC endpoints bound to localhost, skip virtual ops for reduced overhead. - - Configure validator name and private key for block production. -- Analytics node (MongoDB) - - Use config_mongo.ini; includes mongo_db plugin and market history settings. - -Key tuning knobs: -- Shared memory sizing and growth thresholds. -- Read/write lock wait and retries. -- Single write thread for improved database contention handling. -- Plugin notifications on push_transaction can be disabled to improve performance. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L1-L135) - -### Entrypoint Script Behavior -The entrypoint script sets ownership, injects seed nodes (from image or environment), optionally replays from cached snapshot, binds RPC/P2P endpoints, and launches the node with merged arguments. - -```mermaid -flowchart TD -Start(["Start"]) --> SetOwner["Set ownership on /var/lib/vizd"] -SetOwner --> LoadSeed["Load default seednodes or use VIZD_SEED_NODES"] -LoadSeed --> CopyConfig["Copy /etc/vizd/config.ini to $HOME/config.ini"] -CopyConfig --> InitSnapshot{"Snapshot exists?"} -InitSnapshot --> |Yes| Replay["Replay cached snapshot"] -InitSnapshot --> |No| SkipReplay["Skip replay"] -Replay --> BindEndpoints["Bind RPC/P2P endpoints"] -SkipReplay --> BindEndpoints -BindEndpoints --> ExecNode["Launch vizd with merged args"] -ExecNode --> End(["Run"]) -``` - -**Diagram sources** -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -### Node Binary and Plugin Registration -The node binary registers a comprehensive set of plugins, including chain, p2p, webserver, validator, database_api, social_network, account_history, private_message, tags, follow, and optional mongo_db plugin. This defines the node’s capabilities and API surface. - -```mermaid -classDiagram -class VizNode { -+registers plugins -+initializes logging -+starts network and RPC -} -class ChainPlugin -class P2PPlugin -class WebserverPlugin -class WitnessPlugin -class DatabaseApiPlugin -class MongoDbPlugin -VizNode --> ChainPlugin : "registers" -VizNode --> P2PPlugin : "registers" -VizNode --> WebserverPlugin : "registers" -VizNode --> WitnessPlugin : "registers" -VizNode --> DatabaseApiPlugin : "registers" -VizNode --> MongoDbPlugin : "registers (optional)" -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L60-L91) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L60-L91) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) - -### API Workflows and Health Checks -- RPC endpoints - - HTTP: 8090 - - WebSocket: 8091 -- Health checks - - Use HTTP RPC to query dynamic global properties or chain info. - - Monitor P2P connectivity and sync progress. -- validator operations - - Configure validator name and private key for block production. - - Bind RPC to localhost for validator nodes to minimize exposure. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L16-L20) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L16-L20) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L16-L20) - -## Dependency Analysis -The node depends on: -- Build-time: CMake, compiler toolchain, Boost, OpenSSL, Python3, and optional MongoDB plugin support. -- Runtime: Shared memory for chain state, persistent storage for blockchain data, and network connectivity for P2P. - -```mermaid -graph LR -A["CMake/Build Tools"] --> B["vizd binary"] -C["Boost"] --> B -D["OpenSSL"] --> B -E["Python3"] --> B -F["MongoDB Plugin (optional)"] --> B -G["Shared Memory"] --> B -H["Block Storage (/var/lib/vizd)"] --> B -I["Network (P2P/RPC)"] --> B -``` - -**Diagram sources** -- [building.md](file://documentation/building.md#L3-L16) -- [main.cpp](file://programs/vizd/main.cpp#L1-L31) - -**Section sources** -- [building.md](file://documentation/building.md#L3-L16) -- [main.cpp](file://programs/vizd/main.cpp#L1-L31) - -## Performance Considerations -- Shared memory sizing - - Adjust initial size and increment thresholds to reduce allocation pressure during replay or rapid growth. -- Lock tuning - - Increase single write thread to reduce database contention; tune read/write wait micros and retries to balance latency and throughput. -- Plugin overhead - - Disable plugin notifications on push_transaction to reduce CPU usage. - - Skip virtual operations for nodes not requiring them. -- Concurrency - - Tune webserver thread pool size according to CPU cores. -- Disk I/O - - Use SSD-backed storage for blockchain data and logs. -- Network - - Limit inbound P2P connections and prefer stable peers for consistent sync. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [config.ini](file://share/vizd/config/config.ini#L13-L14) -- [config.ini](file://share/vizd/config/config.ini#L42-L47) -- [config.ini](file://share/vizd/config/config.ini#L78-L79) - -## Troubleshooting Guide -Common operational issues and remedies: -- Startup hangs or slow sync - - Verify seed nodes and P2P connectivity; adjust p2p-max-connections. - - Check shared memory thresholds and free space triggers. -- RPC lock errors - - Increase write/read wait micros and retries; consider single-write-thread. -- Insufficient disk space - - Monitor free space thresholds and ensure adequate headroom for shared memory growth. -- validator node not producing blocks - - Confirm validator name and private key are set; ensure required participation threshold is appropriate. -- Debugging state changes - - Use debug_node plugin in isolated, localhost-bound RPC for controlled experiments. - -Security hardening tips: -- Bind RPC to localhost for validator nodes; expose externally via reverse proxy with authentication. -- Use firewalls to restrict P2P ingress to trusted peers. -- Rotate private keys and restrict filesystem permissions on /var/lib/vizd. - -Backup and recovery: -- Back up /var/lib/vizd regularly; maintain snapshots for quick recovery. -- For disaster scenarios, restore snapshot and replay minimal blocks to synchronize. - -**Section sources** -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L100-L103) -- [config.ini](file://share/vizd/config/config.ini#L22-L34) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) - -## Conclusion -This guide consolidates deployment and operations practices for VIZ CPP Node across containerized, cloud, and bare-metal environments. By leveraging the provided Dockerfiles, configuration templates, and entrypoint script, operators can deploy production-grade nodes, optimize performance, harden security, and maintain reliability with robust monitoring and recovery procedures. - -## Appendices - -### Appendix A: Node Types and Operational Procedures -- Full node - - Use config.ini; expose RPC publicly as needed; monitor P2P connectivity. -- validator node - - Use config_witness.ini; bind RPC to localhost; configure validator and private key. -- Seed node - - Use config.ini; focus on stable connectivity and minimal external exposure; consider low-memory image for constrained environments. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [building.md](file://documentation/building.md#L11-L15) - -### Appendix B: Monitoring and Maintenance -- Logs - - Console and file appenders configured; ensure log rotation and retention policies. -- Health checks - - Query dynamic global properties via HTTP RPC endpoint. -- Database maintenance - - Monitor shared memory growth and free space thresholds; adjust increments and thresholds as needed. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L111-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L113-L132) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L116-L135) - -### Appendix C: Security Hardening Checklist -- Network - - Restrict P2P ingress; whitelist seed nodes; use reverse proxy for RPC. -- Credentials - - Protect private keys; restrict filesystem permissions on data directory. -- Logging - - Avoid verbose logs in production; rotate and retain logs securely. -- Updates - - Pin container image tags; automate updates with CI/CD. - -**Section sources** -- [config_witness.ini](file://share/vizd/config/config_witness.ini#L17-L20) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L72) - -### Appendix D: Cloud Deployment and High Availability -- Orchestration - - Use Kubernetes or Docker Swarm to manage replicas and rolling updates. -- Load balancing - - Place a reverse proxy in front of RPC endpoints; distribute P2P traffic across nodes. -- High availability - - Run multiple full nodes behind a load balancer; maintain hot standby with snapshot-based recovery. - -[No sources needed since this section provides general guidance] - -### Appendix E: Backup and Disaster Recovery -- Snapshots - - Package blockchain snapshot into image for fast startup; store offsite backups. -- Recovery - - Restore snapshot and replay minimal blocks; validate chain integrity. - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L44-L53) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Monitoring and Maintenance.md b/.qoder/repowiki/en/content/Deployment and Operations/Monitoring and Maintenance.md deleted file mode 100644 index 56f6e3179d..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Monitoring and Maintenance.md +++ /dev/null @@ -1,499 +0,0 @@ -# Monitoring and Maintenance - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [config.ini](file://share/vizd/config/config.ini) -- [vizd.sh](file://share/vizd/vizd.sh) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [json_rpc_plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [database_api_plugin.cpp](file://plugins/database_api/plugin.cpp) -- [account_history_plugin.cpp](file://plugins/account_history/plugin.cpp) -- [operation_history_plugin.cpp](file://plugins/operation_history/plugin.cpp) -- [mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [network_broadcast_api_plugin.cpp](file://plugins/network_broadcast_api/network_broadcast_api.cpp) -- [witness_api_plugin.cpp](file://plugins/witness_api/plugin.cpp) -- [block_info_plugin.cpp](file://plugins/block_info/plugin.cpp) -- [raw_block_plugin.cpp](file://plugins/raw_block/plugin.cpp) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [chain_plugin.cpp](file://plugins/chain/plugin.cpp) -- [building.md](file://documentation/building.md) -- [testnet.md](file://documentation/testnet.md) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) - - -## Update Summary -**Changes Made** -- Added new section on P2P Peer Statistics System for real-time network observability -- Updated Health Checks and Readiness section to include peer statistics monitoring -- Enhanced Performance Monitoring section with P2P network metrics -- Added P2P statistics configuration and operational procedures -- Updated troubleshooting guide with peer statistics diagnostics - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive monitoring and maintenance guidance for VIZ CPP Node operations. It covers health checks, performance metrics collection, system monitoring integration with Prometheus, Grafana, and the ELK stack, log management and rotation, centralized logging, database maintenance (compaction, optimization, backup verification), performance monitoring (CPU, memory, disk I/O, network), proactive maintenance (updates, patches, configuration audits), incident response, capacity planning, and automation via scripts and dashboards. - -**Updated** Added new monitoring capabilities through P2P peer statistics system providing real-time peer health monitoring, latency measurements, and blocking status reporting for improved network observability. - -## Project Structure -The VIZ node is organized around a modular plugin architecture. The runtime is configured via a central configuration file and launched through a shell script wrapper. The webserver and JSON-RPC plugins expose HTTP and WebSocket endpoints for API access. Logging is configured via the configuration file's logging sections. Operational scripts support Docker-based deployments and seed node selection. - -```mermaid -graph TB -subgraph "Runtime" -CFG["Config File
share/vizd/config/config.ini"] -SH["Launcher Script
share/vizd/vizd.sh"] -BIN["vizd Binary"] -end -subgraph "Web/API Layer" -WS["Webserver Plugin
plugins/webserver"] -JR["JSON-RPC Plugin
plugins/json_rpc"] -APIs["Database/Chain APIs
plugins/*/api"] -end -subgraph "Network Monitoring" -P2P["P2P Plugin
plugins/p2p"] -STATS["Peer Statistics System
Real-time Metrics"] -end -subgraph "Storage" -DB["Object Database
chainbase/leveldb"] -LOGS["Logs
logs/"] -end -SH --> BIN -BIN --> CFG -BIN --> WS -WS --> JR -JR --> APIs -BIN --> P2P -P2P --> STATS -BIN --> DB -BIN --> LOGS -``` - -**Diagram sources** -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- [webserver_plugin.hpp:1-62](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [json_rpc_plugin.hpp:1-146](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L1-L146) -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -**Section sources** -- [README.md:1-53](file://README.md#L1-L53) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) - -## Core Components -- Webserver and JSON-RPC: Provide HTTP and WebSocket endpoints for API access and dispatch JSON-RPC requests to registered APIs. -- Logging: Configured via file appenders and loggers in the configuration file. -- P2P Peer Statistics System: Real-time monitoring of peer connections, latency, bandwidth usage, and blocking status for network observability. -- Plugins: Chain, Account History, Operation History, Mongo DB, P2P, Network Broadcast API, validator API, Block Info, Raw Block, Debug Node, and others. -- Runtime launcher: Sets endpoints, seed nodes, and replay options for Docker-based deployments. - -Key configuration and runtime elements: -- Endpoints: P2P, HTTP, WebSocket, and RPC endpoints are defined in the configuration file and can be overridden by environment variables in the launcher script. -- Plugins: Enabled via plugin directives; database API and chain are enabled by default. -- Logging: Console and file appenders with configurable log levels. -- P2P Statistics: Configurable interval-based peer monitoring with latency and bandwidth metrics. - -**Section sources** -- [webserver_plugin.hpp:19-31](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L19-L31) -- [json_rpc_plugin.hpp:13-36](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L13-L36) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [vizd.sh:62-81](file://share/vizd/vizd.sh#L62-L81) -- [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) - -## Architecture Overview -The VIZ node exposes an HTTP and WebSocket interface backed by JSON-RPC. Requests are dispatched to registered API methods. Logging is handled centrally via appenders and loggers. Storage relies on an object database with shared memory sizing controls. Plugins extend functionality and integrate with the chain and APIs. The P2P peer statistics system provides real-time network observability through periodic peer health monitoring. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "Webserver Plugin" -participant JR as "JSON-RPC Plugin" -participant API as "Registered API" -participant P2P as "P2P Plugin" -participant STATS as "Statistics System" -participant DB as "Object Database" -Client->>WS : "HTTP/WS Request" -WS->>JR : "Dispatch JSON-RPC" -JR->>API : "Invoke API Method" -API->>DB : "Read/Write Operations" -DB-->>API : "Result" -API-->>JR : "Response" -JR-->>WS : "JSON-RPC Response" -WS-->>Client : "HTTP/WS Response" -P2P->>STATS : "Collect Peer Metrics" -STATS-->>P2P : "Latency, Bandwidth, Status" -``` - -**Diagram sources** -- [webserver_plugin.hpp:19-31](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L19-L31) -- [json_rpc_plugin.hpp:103-113](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L103-L113) -- [database_api_plugin.cpp:1-200](file://plugins/database_api/plugin.cpp#L1-L200) -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -## Detailed Component Analysis - -### Health Checks and Readiness -- HTTP/WS endpoints: Configure readiness by ensuring the webserver plugin is active and reachable on the configured HTTP and WebSocket endpoints. -- JSON-RPC health: Use a lightweight method (e.g., a read-only chain property) to validate API responsiveness. -- P2P connectivity: Confirm peers are connected and block production is progressing (for validator nodes). -- **Updated** P2P peer statistics: Monitor peer health through the statistics system for real-time network observability. - -Operational references: -- Endpoints: [config.ini:16-20](file://share/vizd/config/config.ini#L16-L20) -- Webserver lifecycle: [webserver_plugin.hpp:48-52](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L48-L52) -- JSON-RPC lifecycle: [json_rpc_plugin.hpp:103-107](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L103-L107) -- **Updated** P2P statistics configuration: [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) - -**Section sources** -- [config.ini:16-20](file://share/vizd/config/config.ini#L16-L20) -- [webserver_plugin.hpp:48-52](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L48-L52) -- [json_rpc_plugin.hpp:103-107](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L103-L107) -- [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) - -### P2P Peer Statistics System -**New Section** The P2P peer statistics system provides comprehensive real-time monitoring of network peer health and performance metrics. - -#### Statistics Collection Features -- **Peer Connection Monitoring**: Tracks connected peers, IP addresses, and ports -- **Latency Measurements**: Real-time round-trip delay in milliseconds -- **Bandwidth Tracking**: Bytes received metrics with delta calculations -- **Blocking Status Reporting**: Identifies peers under soft-ban or inhibition -- **Reason Analysis**: Provides blocking reasons for network policy enforcement - -#### Configuration Options -- `p2p-stats-enabled`: Enable/disable periodic peer statistics logging (default: true) -- `p2p-stats-interval`: Interval between statistics dumps in seconds (default: 300) - -#### Statistics Fields -- **IP Address**: Peer's network address -- **Port**: Peer's listening port -- **Latency**: Round-trip delay in milliseconds -- **Bytes Received**: Delta bytes received since last measurement -- **Blocked Status**: Boolean indicating soft-ban/inhibition state -- **Blocked Reason**: Network policy reason for blocking - -#### Implementation Details -The statistics system runs as a scheduled task that: -1. Queries connected peers from the network node -2. Extracts peer information from variant objects -3. Calculates byte delta values for bandwidth monitoring -4. Logs formatted peer statistics with ANSI color coding -5. Schedules next execution based on configured interval - -**Section sources** -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) -- [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) -- [node.hpp:172-179](file://libraries/network/include/graphene/network/node.hpp#L172-L179) -- [peer_connection.hpp:320-342](file://libraries/network/include/graphene/network/peer_connection.hpp#L320-L342) - -### Performance Metrics Collection -- Built-in metrics: The node does not expose Prometheus metrics endpoints by default. Metrics must be collected externally or via custom instrumentation. -- External collection: Use system-level collectors (e.g., Node Exporter) for CPU, memory, disk I/O, and network utilization. -- API latency: Instrument JSON-RPC endpoints to capture request durations and error rates. -- **Updated** P2P network metrics: Utilize peer statistics for network performance monitoring and bandwidth analysis. - -Integration references: -- Endpoints: [config.ini:16-20](file://share/vizd/config/config.ini#L16-L20) -- Webserver threading model: [webserver_plugin.hpp:28-30](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L28-L30) -- **Updated** P2P statistics scheduling: [p2p_plugin.cpp:685-692](file://plugins/p2p/p2p_plugin.cpp#L685-L692) - -**Section sources** -- [config.ini:16-20](file://share/vizd/config/config.ini#L16-L20) -- [webserver_plugin.hpp:28-30](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L28-L30) -- [p2p_plugin.cpp:685-692](file://plugins/p2p/p2p_plugin.cpp#L685-L692) - -### System Monitoring Integration (Prometheus, Grafana, ELK) -- Prometheus: Scrape system metrics via Node Exporter; optionally scrape custom JSON-RPC metrics if instrumented. -- Grafana: Build dashboards for CPU, memory, disk I/O, network, and API latency. -- ELK: Ship logs to Logstash/Beats and visualize in Kibana for centralized log analysis. -- **Updated** Network monitoring: Integrate P2P statistics with monitoring systems for peer health visualization. - -Operational references: -- Logging configuration: [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- Launcher script for endpoint overrides: [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- **Updated** P2P statistics configuration: [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) - -**Section sources** -- [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) - -### Log Management Strategies -- Console and file appenders: Configure loggers and appenders for different subsystems (e.g., default, p2p). -- Log levels: Adjust severity thresholds per logger. -- Log rotation: Use external log rotation tools (e.g., logrotate) to manage file sizes and retention. -- Centralized logging: Forward logs to a centralized collector (e.g., rsyslog, Fluent Bit) for aggregation. -- **Updated** P2P statistics logging: ANSI color-coded peer statistics with periodic dumps for network monitoring. - -References: -- Appenders and loggers: [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- Docker-based deployment and seed nodes: [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- **Updated** P2P statistics color coding: [p2p_plugin.cpp:15-17](file://plugins/p2p/p2p_plugin.cpp#L15-L17) - -**Section sources** -- [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- [p2p_plugin.cpp:15-17](file://plugins/p2p/p2p_plugin.cpp#L15-L17) - -### Database Maintenance Tasks -- Shared memory sizing: Tune shared file size, minimum free space, and increment steps to avoid allocation failures. -- Compaction and optimization: Rely on underlying storage engine defaults; monitor free space and adjust thresholds periodically. -- Backup verification: Periodically snapshot the blockchain database and verify replay integrity. - -References: -- Shared memory settings: [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- Replay option in launcher: [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) - -**Section sources** -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) - -### Performance Monitoring (CPU, Memory, Disk I/O, Network) -- CPU: Track utilization and context switches; correlate with API throughput. -- Memory: Monitor RSS, shared memory usage, and free space thresholds. -- Disk I/O: Observe read/write latencies and queue depths; ensure adequate free space. -- Network: Measure P2P and RPC traffic; watch connection counts and bandwidth. -- **Updated** P2P network performance: Monitor peer latency, bandwidth usage, and connection health through statistics system. - -References: -- Endpoints and threading: [config.ini:13-47](file://share/vizd/config/config.ini#L13-L47) -- Webserver threading note: [webserver_plugin.hpp:28-30](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L28-L30) -- **Updated** Peer statistics metrics: [p2p_plugin.cpp:510-530](file://plugins/p2p/p2p_plugin.cpp#L510-L530) - -**Section sources** -- [config.ini:13-47](file://share/vizd/config/config.ini#L13-L47) -- [webserver_plugin.hpp:28-30](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L28-L30) -- [p2p_plugin.cpp:510-530](file://plugins/p2p/p2p_plugin.cpp#L510-L530) - -### Proactive Maintenance Procedures -- Regular updates: Rebuild from source or pull updated Docker images; validate against release notes. -- Security patches: Keep dependencies updated; scan for vulnerabilities. -- Configuration audits: Review enabled plugins, endpoints, and log levels; ensure least privilege exposure. -- **Updated** Network maintenance: Regularly review P2P statistics for peer health trends and network performance optimization. - -References: -- Build instructions: [building.md:1-212](file://documentation/building.md#L1-L212) -- Docker usage: [README.md:12-29](file://README.md#L12-L29) - -**Section sources** -- [building.md:1-212](file://documentation/building.md#L1-L212) -- [README.md:12-29](file://README.md#L12-L29) - -### Incident Response Procedures -- Initial assessment: Verify health endpoints, P2P connectivity, and log levels. -- Isolation: Temporarily disable non-essential plugins to reduce load. -- Recovery: Trigger replay if necessary; restore from verified snapshots; recheck shared memory thresholds. -- **Updated** Network incident response: Analyze P2P statistics for peer blocking patterns, latency spikes, and bandwidth anomalies to identify network issues. - -References: -- Replay option: [vizd.sh:47-48](file://share/vizd/vizd.sh#L47-L48) -- Shared memory tuning: [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- **Updated** P2P statistics monitoring: [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -**Section sources** -- [vizd.sh:47-48](file://share/vizd/vizd.sh#L47-L48) -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -### Capacity Planning and Resource Optimization -- Forecasting: Track block production rate, transaction volume, and plugin indexing overhead. -- Resource optimization: Adjust shared memory increments, thread pools, and plugin sets based on observed load. -- **Updated** Network capacity planning: Monitor P2P statistics for peer distribution, latency trends, and bandwidth utilization to optimize network topology and peer selection. - -References: -- Shared memory sizing: [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- Thread pool size: [config.ini:13-14](file://share/vizd/config/config.ini#L13-L14) - -**Section sources** -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- [config.ini:13-14](file://share/vizd/config/config.ini#L13-L14) - -### Automated Maintenance Scripts and Dashboards -- Maintenance scripts: Use the launcher script to initialize data directories, inject seed nodes, and set endpoints; extend for periodic checks and backups. -- Dashboards: Create Prometheus/Grafana dashboards for system metrics and API performance; integrate ELK for log analytics. -- **Updated** Network dashboards: Develop Grafana dashboards for P2P peer health, latency distributions, bandwidth utilization, and peer blocking status. - -References: -- Launcher script: [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- Testnet guidance: [testnet.md:21-37](file://documentation/testnet.md#L21-L37) - -**Section sources** -- [vizd.sh:1-82](file://share/vizd/vizd.sh#L1-L82) -- [testnet.md:21-37](file://documentation/testnet.md#L21-L37) - -## Dependency Analysis -The webserver plugin depends on the JSON-RPC plugin, which registers API methods exposed by various plugins. The chain plugin integrates with the database and provides core state access. Logging is configured centrally via the configuration file. The P2P plugin provides network connectivity and statistics collection for network observability. - -```mermaid -graph LR -WS["Webserver Plugin"] --> JR["JSON-RPC Plugin"] -JR --> APIs["Database/Chain APIs"] -APIs --> CHAIN["Chain Plugin"] -WS --> LOG["Logging Config"] -JR --> LOG -P2P["P2P Plugin"] --> NET["Network Layer"] -NET --> STATS["Statistics System"] -P2P --> LOG -``` - -**Diagram sources** -- [webserver_plugin.hpp:38-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L38-L38) -- [json_rpc_plugin.hpp:84-92](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L92) -- [database_api_plugin.cpp:1-200](file://plugins/database_api/plugin.cpp#L1-L200) -- [chain_plugin.cpp:1-200](file://plugins/chain/plugin.cpp#L1-L200) -- [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -**Section sources** -- [webserver_plugin.hpp:38-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L38-L38) -- [json_rpc_plugin.hpp:84-92](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L92) -- [database_api_plugin.cpp:1-200](file://plugins/database_api/plugin.cpp#L1-L200) -- [chain_plugin.cpp:1-200](file://plugins/chain/plugin.cpp#L1-L200) -- [config.ini:111-130](file://share/vizd/config/config.ini#L111-L130) -- [p2p_plugin.cpp:489-560](file://plugins/p2p/p2p_plugin.cpp#L489-L560) - -## Performance Considerations -- Single write thread: Writing operations are serialized to reduce contention; ensure adequate write lock retries and wait intervals. -- Read/write lock tuning: Adjust microsecond waits and retries to balance latency and throughput. -- Shared memory growth: Monitor free space thresholds and increment steps to prevent allocation failures. -- **Updated** P2P statistics overhead: Configure appropriate intervals to balance monitoring granularity with system performance impact. - -References: -- Single write thread: [config.ini:36-40](file://share/vizd/config/config.ini#L36-L40) -- Read/write waits: [config.ini:22-34](file://share/vizd/config/config.ini#L22-L34) -- Shared memory sizing: [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- **Updated** P2P statistics scheduling: [p2p_plugin.cpp:685-692](file://plugins/p2p/p2p_plugin.cpp#L685-L692) - -**Section sources** -- [config.ini:36-40](file://share/vizd/config/config.ini#L36-L40) -- [config.ini:22-34](file://share/vizd/config/config.ini#L22-L34) -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- [p2p_plugin.cpp:685-692](file://plugins/p2p/p2p_plugin.cpp#L685-L692) - -## Troubleshooting Guide -- No connectivity: Verify P2P endpoint and seed nodes; confirm firewall rules and DNS resolution. -- API unresponsive: Check JSON-RPC registration and method availability; review log levels for errors. -- Lock contention: Increase read/write wait retries or tune single write thread behavior. -- Out-of-memory: Inspect shared memory free space thresholds and increments; consider reducing plugin sets or replay options. -- **Updated** Network connectivity issues: Analyze P2P statistics for peer blocking patterns, excessive latency, or bandwidth saturation; review peer connection states and reasons for blocking. - -References: -- P2P and seed nodes: [config.ini:1-8](file://share/vizd/config/config.ini#L1-L8) -- Seed node injection: [vizd.sh:9-29](file://share/vizd/vizd.sh#L9-L29) -- Lock settings: [config.ini:22-40](file://share/vizd/config/config.ini#L22-L40) -- Shared memory: [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- **Updated** P2P statistics diagnostics: [p2p_plugin.cpp:508-552](file://plugins/p2p/p2p_plugin.cpp#L508-L552) - -**Section sources** -- [config.ini:1-8](file://share/vizd/config/config.ini#L1-L8) -- [vizd.sh:9-29](file://share/vizd/vizd.sh#L9-L29) -- [config.ini:22-40](file://share/vizd/config/config.ini#L22-L40) -- [config.ini:49-67](file://share/vizd/config/config.ini#L49-L67) -- [p2p_plugin.cpp:508-552](file://plugins/p2p/p2p_plugin.cpp#L508-L552) - -## Conclusion -This guide outlines how to operate, monitor, and maintain VIZ CPP Node instances effectively. By leveraging the configuration-driven logging and endpoints, integrating external monitoring stacks, utilizing the new P2P peer statistics system for network observability, and following the maintenance and troubleshooting procedures, operators can achieve reliable and scalable node operations with comprehensive network visibility. - -## Appendices - -### API Surface and Plugin Exposure -- Database API: Provides chain state queries and operations. -- Account History and Operation History: Index and expose historical data. -- P2P and Network Broadcast API: Manage peer connections and broadcast transactions. -- validator API: Expose validator-specific operations. -- Block Info and Raw Block: Provide block-level insights. -- Debug Node: Simulate chain state for testing and development. - -References: -- Database API plugin: [database_api_plugin.cpp:1-200](file://plugins/database_api/plugin.cpp#L1-L200) -- Account History plugin: [account_history_plugin.cpp:1-200](file://plugins/account_history/plugin.cpp#L1-L200) -- Operation History plugin: [operation_history_plugin.cpp:1-200](file://plugins/operation_history/plugin.cpp#L1-L200) -- P2P plugin: [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) -- Network Broadcast API plugin: [network_broadcast_api_plugin.cpp:1-200](file://plugins/network_broadcast_api/network_broadcast_api.cpp#L1-L200) -- validator API plugin: [witness_api_plugin.cpp:1-200](file://plugins/witness_api/plugin.cpp#L1-L200) -- Block Info plugin: [block_info_plugin.cpp:1-200](file://plugins/block_info/plugin.cpp#L1-L200) -- Raw Block plugin: [raw_block_plugin.cpp:1-200](file://plugins/raw_block/plugin.cpp#L1-L200) -- Debug Node plugin: [debug_node_plugin.cpp:1-200](file://plugins/debug_node/plugin.cpp#L1-L200) -- Chain plugin: [chain_plugin.cpp:1-200](file://plugins/chain/plugin.cpp#L1-L200) - -**Section sources** -- [database_api_plugin.cpp:1-200](file://plugins/database_api/plugin.cpp#L1-L200) -- [account_history_plugin.cpp:1-200](file://plugins/account_history/plugin.cpp#L1-L200) -- [operation_history_plugin.cpp:1-200](file://plugins/operation_history/plugin.cpp#L1-L200) -- [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) -- [network_broadcast_api_plugin.cpp:1-200](file://plugins/network_broadcast_api/network_broadcast_api.cpp#L1-L200) -- [witness_api_plugin.cpp:1-200](file://plugins/witness_api/plugin.cpp#L1-L200) -- [block_info_plugin.cpp:1-200](file://plugins/block_info/plugin.cpp#L1-L200) -- [raw_block_plugin.cpp:1-200](file://plugins/raw_block/plugin.cpp#L1-L200) -- [debug_node_plugin.cpp:1-200](file://plugins/debug_node/plugin.cpp#L1-L200) -- [chain_plugin.cpp:1-200](file://plugins/chain/plugin.cpp#L1-L200) - -### Testnet and Snapshot Usage -- Testnet launch: Use Docker images or build locally; inspect logs for initialization. -- Snapshots: Initialize data directories with prebuilt snapshots to accelerate bootstrapping. - -References: -- Testnet instructions: [testnet.md:21-37](file://documentation/testnet.md#L21-L37) -- Snapshot initialization: [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) - -**Section sources** -- [testnet.md:21-37](file://documentation/testnet.md#L21-L37) -- [vizd.sh:44-53](file://share/vizd/vizd.sh#L44-L53) - -### Debugging and Simulation -- Debug Node plugin: Simulate chain state changes and test features without affecting the live network. -- Example workflows: Push blocks, generate blocks, and update objects for experimentation. - -References: -- Debug Node documentation: [debug_node_plugin.md:50-134](file://documentation/debug_node_plugin.md#L50-L134) - -**Section sources** -- [debug_node_plugin.md:50-134](file://documentation/debug_node_plugin.md#L50-L134) - -### P2P Statistics Configuration Reference -**New Section** Complete reference for P2P statistics configuration and monitoring. - -#### Command Line Options -- `--p2p-stats-enabled`: Enable/disable peer statistics logging -- `--p2p-stats-interval`: Set statistics collection interval in seconds - -#### Statistics Output Format -``` -P2P peer | ip: 192.168.1.100 | port: 1776 | latency: 45ms | bytes_in: 12345 | blocked: false | reason: -P2P peer | ip: 10.0.0.5 | port: 1776 | latency: 120ms | bytes_in: 8765 | blocked: true | reason: soft_ban -``` - -#### Peer Status Indicators -- **Latency**: Round-trip delay in milliseconds -- **Bytes Received**: Delta bytes since last measurement -- **Blocked**: Soft-ban or inhibition status -- **Reason**: Network policy enforcement reason - -#### Monitoring Best Practices -- Set appropriate intervals based on network size and monitoring requirements -- Monitor for unusual latency spikes or bandwidth patterns -- Track peer blocking reasons for network policy analysis -- Correlate statistics with system performance metrics - -**Section sources** -- [p2p_plugin.cpp:570-589](file://plugins/p2p/p2p_plugin.cpp#L570-L589) -- [p2p_plugin.cpp:508-552](file://plugins/p2p/p2p_plugin.cpp#L508-L552) -- [node.hpp:172-179](file://libraries/network/include/graphene/network/node.hpp#L172-L179) -- [peer_connection.hpp:320-342](file://libraries/network/include/graphene/network/peer_connection.hpp#L320-L342) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Installation and Setup.md b/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Installation and Setup.md deleted file mode 100644 index 19071642e2..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Installation and Setup.md +++ /dev/null @@ -1,400 +0,0 @@ -# Installation and Setup - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/building.md](file://documentation/building.md) -- [CMakeLists.txt](file://CMakeLists.txt) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [.travis.yml](file://.travis.yml) -- [documentation/testing.md](file://documentation/testing.md) -- [documentation/testnet.md](file://documentation/testnet.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive installation and setup guidance for the VIZ CPP Node. It covers system requirements, platform-specific build instructions using CMake, dependency management, cross-compilation considerations, Docker containerization for production and development, verification procedures, and troubleshooting tips. The goal is to enable reliable installation and operation across Linux, macOS, and Windows environments, while also supporting containerized deployments. - -## Project Structure -At a high level, the repository is organized into: -- Top-level build configuration and CI scripts -- Libraries implementing blockchain logic, networking, and utilities -- Plugins extending functionality -- Programs (executables) such as the node and CLI wallet -- Documentation and Docker configurations for deployment - -```mermaid -graph TB -Root["Repository Root"] -CMake["Top-level CMakeLists.txt"] -Docs["Documentation"] -Libs["libraries/"] -Plugs["plugins/"] -Progs["programs/"] -Share["share/vizd/"] -Third["thirdparty/"] -Root --> CMake -Root --> Docs -Root --> Libs -Root --> Plugs -Root --> Progs -Root --> Share -Root --> Third -``` - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [README.md](file://README.md#L1-L53) - -## Core Components -- Build system: CMake with configurable options for build type, memory profile, and plugin selection -- Executables: vizd (node), cli_wallet (command-line wallet) -- Plugins: modular extensions for APIs and services -- Docker images: prebuilt and multi-stage Dockerfiles for production, low-memory, testnet, and MongoDB variants -- Configuration templates: config.ini and config_testnet.ini for runtime behavior - -Key build options and flags are defined in the top-level CMake configuration and documented in the building guide. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L3-L104) -- [documentation/building.md](file://documentation/building.md#L3-L16) - -## Architecture Overview -The build and runtime architecture integrates CMake-driven compilation of libraries and plugins into node and wallet executables, with Docker encapsulating dependencies and runtime configuration. - -```mermaid -graph TB -subgraph "Build" -CMake["CMakeLists.txt"] -Libs["libraries/*"] -Plugs["plugins/*"] -Progs["programs/*"] -Third["thirdparty/*"] -end -subgraph "Executables" -VIZD["vizd (node)"] -CLI["cli_wallet"] -end -subgraph "Runtime Config" -CfgProd["config.ini"] -CfgTest["config_testnet.ini"] -Seed["seednodes"] -end -subgraph "Containerization" -DProd["Dockerfile-production"] -DLow["Dockerfile-lowmem"] -DTest["Dockerfile-testnet"] -Script["vizd.sh"] -end -CMake --> Libs -CMake --> Plugs -CMake --> Progs -CMake --> Third -Libs --> VIZD -Plugs --> VIZD -Progs --> VIZD -Progs --> CLI -CfgProd --> VIZD -CfgTest --> VIZD -Seed --> VIZD -DProd --> VIZD -DLow --> VIZD -DTest --> VIZD -Script --> VIZD -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -## Detailed Component Analysis - -### System Requirements and Dependencies -- Compiler requirements: - - GCC minimum version and Clang minimum version are enforced by the build system -- Operating systems: - - Official guidance supports Linux and macOS; Windows build instructions are not provided in the repository -- Core dependencies: - - Boost (minimum version requirement explicitly stated) - - OpenSSL - - CMake, compiler toolchain, and standard Unix utilities -- Optional dependencies: - - Tools for documentation and development experience - -Platform-specific package lists and notes are provided in the building guide. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L76-L137) -- [documentation/building.md](file://documentation/building.md#L138-L201) - -### Platform-Specific Installation Procedures - -#### Linux (Ubuntu LTS) -- Install required and optional packages via the package manager -- Clone the repository and initialize submodules -- Configure with CMake and build node and wallet targets -- Optional: install to system prefix - -```mermaid -flowchart TD -Start(["Start"]) --> Pkgs["Install packages
apt dependencies"] -Pkgs --> Clone["Clone repo and init submodules"] -Clone --> Cfg["Configure with CMake
Release build"] -Cfg --> Build["Build vizd and cli_wallet"] -Build --> Install{"Install system-wide?"} -Install --> |Yes| DoInstall["make install"] -Install --> |No| SkipInstall["Skip install"] -DoInstall --> End(["Done"]) -SkipInstall --> End -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) - -#### macOS -- Install Xcode command line tools and accept license -- Use Homebrew to install dependencies including a compatible Boost version -- Export OpenSSL and Boost prefixes for CMake discovery -- Configure and build - -```mermaid -flowchart TD -Start(["Start"]) --> Xcode["Install Xcode command line tools"] -Xcode --> Brew["Install deps via Homebrew"] -Brew --> Prefixes["Set OPENSSL_ROOT_DIR and BOOST_ROOT"] -Prefixes --> Cfg["Configure with CMake"] -Cfg --> Build["Build targets"] -Build --> End(["Done"]) -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L138-L189) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L138-L189) - -#### Windows -- No official build instructions are provided in the repository -- The build system includes Windows-specific logic, indicating potential support with appropriate toolchains and environment setup - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L202-L212) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L157) - -### CMake Build Options and Flags -Key options exposed by the build system: -- Build type: Release or Debug -- Low memory node: consensus-only mode -- Testnet build: compile-time switch for testnet configuration -- Chainbase locking checks: optional debug/validation -- MongoDB plugin: optional inclusion -- Shared/static libraries: choice of linkage - -These options influence compilation flags and conditional compilation macros. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [CMakeLists.txt](file://CMakeLists.txt#L264-L274) - -### Cross-Compilation Considerations -- The repository does not include explicit cross-compilation instructions -- For cross-platform builds, ensure the target toolchain and SDKs are configured appropriately -- Respect compiler and dependency version constraints documented in the build system - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L157) - -### Docker Containerization - -#### Prebuilt Images -- Production image tag latest is available on Docker Hub -- Testnet image tag testnet is available on Docker Hub -- Example run commands and environment overrides are provided - -**Section sources** -- [README.md](file://README.md#L12-L29) - -#### Multi-Stage Dockerfiles -- Production: full-featured node with optimized runtime -- Low memory: consensus-only node for resource-constrained environments -- Testnet: preconfigured for local testnet with snapshot and default validator -- Each Dockerfile: - - Installs build dependencies - - Copies minimal source subsets - - Builds with CMake and installs - - Produces a runtime image with non-root user and volumes for persistent data - -```mermaid -graph LR -Builder["Builder Stage"] --> Runtime["Runtime Stage"] -Builder --> |Debian/Ubuntu base| Deps["Install build deps"] -Deps --> Source["Copy source subsets"] -Source --> CMake["CMake configure and build"] -CMake --> Install["make install"] -Install --> Runtime -Runtime --> Image["Final image with vizd"] -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) - -#### Container Entrypoint and Environment -- The container entrypoint script sets up seed nodes, optional validator configuration, copies configuration, initializes blockchain cache if present, and launches the node with environment-provided endpoints and arguments. - -```mermaid -sequenceDiagram -participant Docker as "Docker Engine" -participant Script as "vizd.sh" -participant Node as "vizd" -Docker->>Script : Start container -Script->>Script : Resolve seed nodes and env args -Script->>Script : Copy config.ini to data dir -Script->>Script : Optionally extract snapshot -Script->>Node : exec vizd with resolved args -Node-->>Docker : Logs and runtime -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -#### Manual Docker Builds -- CI matrix defines multiple Dockerfiles and tags for automated builds and pushes -- Local builds can mirror the CI stages - -**Section sources** -- [.travis.yml](file://.travis.yml#L12-L42) - -### Configuration Management -- Production configuration template defines P2P endpoints, RPC endpoints, threading, shared memory sizing, plugin list, and logging -- Testnet configuration template adds validator-related settings and enables stale production for local testing - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -## Dependency Analysis -The build system declares and locates required libraries and sets compiler/linker flags per platform. The Dockerfiles enumerate runtime dependencies. - -```mermaid -graph TB -CMake["CMakeLists.txt"] -Boost["Boost (>= 1.57)"] -SSL["OpenSSL"] -Readline["Readline (Linux/macOS)"] -Crypto["Crypto library (Linux)"] -CMake --> Boost -CMake --> SSL -CMake --> Readline -CMake --> Crypto -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L160-L184) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L160-L184) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L9-L30) - -## Performance Considerations -- Build type: Use Release for production to enable optimizations -- Low memory node: Recommended for consensus roles to reduce memory footprint -- Plugin selection: Disable unused plugins to minimize overhead -- Shared memory sizing: Adjust shared file size and increments according to expected load -- Threading: Tune RPC thread pool and consider single-write-thread for reduced contention - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L3-L16) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L13-L14) - -## Troubleshooting Guide -Common issues and remedies: -- Boost version mismatch: - - Ensure Boost meets the minimum version requirement; on older distributions, manual installation of a compatible version may be necessary -- OpenSSL discovery failures: - - On macOS, export the OpenSSL prefix for CMake to locate headers and libraries -- Missing readline on Linux/macOS: - - Install readline development packages if linking fails -- Windows build: - - No official instructions exist; consult Windows-specific CMake and toolchain setup if attempting unsupported builds -- Docker runtime: - - Verify exposed ports and mounted volumes - - Override seed nodes via environment variable - - Confirm configuration file is copied into the data directory - -Verification steps: -- Build artifacts: - - Confirm successful generation of vizd and cli_wallet -- Docker: - - Tail container logs to observe startup and synchronization progress - - Connect to RPC endpoints and query node status -- Testnet: - - Use provided testnet image and configuration for quick local validation - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L103-L112) -- [documentation/building.md](file://documentation/building.md#L176-L184) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [README.md](file://README.md#L21-L29) -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) - -## Conclusion -With the provided instructions, you can build and run the VIZ CPP Node on Linux and macOS, and optionally use Docker for streamlined deployment. Ensure dependencies meet the minimum requirements, select appropriate build options for your role (full node vs. low-memory), and leverage Docker for repeatable production and development setups. Use the verification procedures to confirm successful installation and basic functionality. - -## Appendices - -### A. Build Targets Reference -- vizd: primary node executable -- cli_wallet: command-line wallet -- chain_test: unit test suite - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L190-L200) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -### B. Testnet Quickstart -- Use the provided Dockerfile-testnet to build and run a local testnet node -- Predefined users and keys are available for immediate testing - -**Section sources** -- [documentation/testnet.md](file://documentation/testnet.md#L21-L54) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Deployment.md b/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Deployment.md deleted file mode 100644 index a5a1779740..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Deployment.md +++ /dev/null @@ -1,373 +0,0 @@ -# Node Deployment - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testnet.md](file://documentation/testnet.md) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/seednodes](file://share/vizd/seednodes) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Security Hardening](#security-hardening) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) -11. [Appendices](#appendices) - -## Introduction -This document provides comprehensive deployment guidance for VIZ CPP Node across production, testnet, and specialized configurations. It covers hardware and system prerequisites, installation procedures for multiple operating systems, Docker-based deployments, node types (full, validator, seed), configuration management, service integration, performance tuning, capacity planning, security hardening, and troubleshooting. - -## Project Structure -At a high level, the repository provides: -- A production-ready node binary (vizd) with extensive plugin support -- Multiple configuration templates for different node roles and networks -- Docker images for production, testnet, and low-memory deployments -- Scripts to bootstrap and run the node with seed nodes and optional snapshot replay - -```mermaid -graph TB -subgraph "Host" -OS["Operating System"] -Runtime["Container Runtime
Docker/Podman"] -end -subgraph "Docker Image" -IMG["Image Layers"] -BIN["vizd Binary"] -CFG["Config Template
config.ini / config_witness.ini / config_testnet.ini"] -SEED["Seed Nodes List"] -RUN["Startup Script
vizd.sh"] -end -subgraph "Node Process" -VIZD["vizd"] -PLUGINS["Plugins Loaded at Startup"] -LOG["Logging Config"] -end -OS --> Runtime -Runtime --> IMG -IMG --> BIN -IMG --> CFG -IMG --> SEED -IMG --> RUN -BIN --> VIZD -CFG --> VIZD -SEED --> VIZD -RUN --> VIZD -VIZD --> PLUGINS -VIZD --> LOG -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) - -## Core Components -- Node binary: vizd, which initializes plugins and starts the P2P and RPC services -- Configuration: INI-style configuration files for endpoints, plugins, logging, and runtime behavior -- Docker images: production, testnet, and low-memory variants with preconfigured volumes and ports -- Bootstrap script: sets up seed nodes, optional snapshot replay, and passes environment overrides to vizd - -Key behaviors: -- Plugin registration and initialization occur at startup -- Logging configuration is parsed from the config file sections -- Docker entrypoint supports environment-driven customization (RPC, P2P, validator identity, private key) - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L117-L140) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L194-L289) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Architecture Overview -The node startup flow integrates CLI arguments, configuration files, and environment variables to initialize plugins and services. - -```mermaid -sequenceDiagram -participant Entrypoint as "Docker Entrypoint
vizd.sh" -participant Env as "Environment Variables" -participant Vizd as "vizd" -participant Cfg as "Config Loader" -participant Log as "Logging Config" -participant P2P as "P2P Plugin" -participant RPC as "Webserver Plugin" -Entrypoint->>Env : Read VIZD_* variables -Entrypoint->>Vizd : Pass --p2p-endpoint, --rpc-endpoint, --data-dir, seed nodes, validator, private-key -Vizd->>Cfg : Load config.ini and parse sections -Cfg-->>Log : Build logging config from [log.*] and [logger.*] -Vizd->>Log : Configure logging -Vizd->>P2P : Initialize P2P with endpoints and seeds -Vizd->>RPC : Initialize RPC with HTTP/WebSocket endpoints -Vizd-->>Entrypoint : Running -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L81) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L117-L140) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L194-L289) - -## Detailed Component Analysis - -### Node Types and Roles -- Full node: Participates in P2P gossip, serves RPC APIs, optionally tracks history and feeds -- validator node: Produces blocks; requires a configured validator name and private key -- Seed node: Minimal footprint, connects peers and advertises connectivity; recommended low-memory build - -Configuration templates: -- Production template: [config.ini](file://share/vizd/config/config.ini#L1-L130) -- validator template: [config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- Testnet template: [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -Operational differences: -- validator nodes enable block production and require private keys -- Seed nodes typically bind RPC to localhost and disable verbose plugins -- Testnet enables special participation rules and snapshot-based initialization - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [documentation/testnet.md](file://documentation/testnet.md#L1-L54) - -### Configuration Management -- Endpoints: P2P, HTTP RPC, WebSocket RPC -- Locking and threading: Read/write wait limits and single-write-thread behavior -- Shared memory sizing: Initial size, minimum free space, increment step, and periodic checks -- Plugins: Enabled via plugin directives; validator and API plugins commonly enabled -- Logging: Console and file appenders, logger levels, and appender routing - -Environment overrides: -- Docker entrypoint supports VIZD_RPC_ENDPOINT, VIZD_P2P_ENDPOINT, VIZD_SEED_NODES, VIZD_WITNESS_NAME, VIZD_PRIVATE_KEY, and VIZD_EXTRA_OPTS - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L81) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L167-L191) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L194-L289) - -### Service Integration -- Docker volumes: - - /var/lib/vizd: persistent data directory (blockchain, logs, config) - - /etc/vizd: read-only config and seednodes -- Exposed ports: - - 2001: P2P - - 8090: HTTP RPC - - 8091: WebSocket RPC - -Dockerfiles: -- Production: [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- Testnet: [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) -- Low-memory: [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) - -**Section sources** -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) - -### Installation Procedures - -#### Docker (Recommended for Production) -- Pull or build the production image and run with mapped volumes and exposed ports -- Optionally override seed nodes via environment variable - -```mermaid -flowchart TD -Start(["Start"]) --> Pull["Pull or Build Image"] -Pull --> Run["Run Container with Volumes and Ports"] -Run --> Seed["Set VIZD_SEED_NODES (optional)"] -Seed --> validator["Set VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY (optional)"] -validator --> Logs["Monitor Logs"] -Logs --> End(["Ready"]) -``` - -**Diagram sources** -- [README.md](file://README.md#L12-L29) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L17-L37) - -**Section sources** -- [README.md](file://README.md#L12-L29) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) - -#### Ubuntu (Native Build) -- Install dependencies, clone repository, initialize submodules, configure with CMake, build, and optionally install - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) - -#### macOS (Native Build) -- Install dependencies via Homebrew, export OpenSSL and Boost paths, configure with CMake, and build - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L138-L189) - -#### Low-Memory Builds -- Use the low-memory Dockerfile or build with LOW_MEMORY_NODE enabled to reduce memory footprint - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L11-L16) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) - -### Node Startup Process -- The entrypoint script prepares seed nodes, optionally replays a cached snapshot, and executes vizd with environment-derived arguments -- The binary registers plugins, loads logging configuration, and starts P2P and RPC services - -```mermaid -sequenceDiagram -participant Init as "vizd.sh" -participant FS as "Filesystem" -participant Bin as "vizd" -participant Net as "P2P" -participant API as "RPC" -Init->>FS : Read /etc/vizd/seednodes -Init->>Bin : exec vizd with --p2p-endpoint, --rpc-endpoint, --data-dir, --p2p-seed-node, --validator, --private-key -Bin->>Bin : Register plugins -Bin->>Bin : Load logging config -Bin->>Net : Start P2P -Bin->>API : Start RPC HTTP/WebSocket -Bin-->>Init : Running -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L11-L81) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) - -### Testnet Deployment -- Use the testnet Dockerfile or image to spin up a local test network -- Snapshot-based initialization is supported for quick bootstrapping - -**Section sources** -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L88) - -### Debugging and Simulation -- The debug_node plugin allows loading historical blocks and generating synthetic blocks for development and testing - -**Section sources** -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) - -## Dependency Analysis -- Build-time dependencies: CMake, compiler toolchain, Boost, OpenSSL, and related libraries -- Runtime dependencies: Shared libraries linked at build time; Docker images package all required runtime libraries -- Plugin ecosystem: Extensible via the appbase framework; plugins are registered at startup - -```mermaid -graph LR -CMake["CMake Build"] --> Bin["vizd Binary"] -Boost["Boost Libraries"] --> Bin -SSL["OpenSSL"] --> Bin -Libs["System Libraries"] --> Bin -Bin --> Plugins["Registered Plugins"] -Plugins --> P2P["P2P"] -Plugins --> RPC["Webserver"] -Plugins --> Chain["Chain"] -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L30-L63) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L30-L63) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) - -## Performance Considerations -- Thread pool sizing: Tune webserver-thread-pool-size to match CPU cores minus one for optimal throughput -- Locking behavior: Single-write-thread reduces contention; adjust read-wait-micro and max-read-wait-retries to balance latency and reliability -- Shared memory: Configure shared-file-size, min-free-shared-file-size, and inc-shared-file-size to avoid frequent resizing during replay or growth -- Plugin selection: Disable unused plugins to reduce memory and CPU overhead -- Network: Limit inbound connections via p2p-max-connections and leverage seednodes for faster bootstrapping - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L13-L67) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L13-L66) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L13-L67) - -## Security Hardening -- Bind RPC to localhost for validator nodes to prevent external exposure -- Use environment variables to inject secrets (private keys) and restrict filesystem access -- Restrict P2P exposure to trusted networks; consider firewall rules to allow only necessary ports -- Monitor logs and set appropriate logger levels to detect anomalies early - -**Section sources** -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L16-L20) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L167-L191) - -## Troubleshooting Guide -Common issues and resolutions: -- Startup failures due to missing configuration or invalid endpoints - - Verify config.ini presence and correctness; ensure endpoints are reachable -- Insufficient shared memory during replay - - Increase shared-file-size and min-free-shared-file-size -- Excessive lock wait timeouts - - Adjust read-wait-micro and max-read-wait-retries; consider single-write-thread -- No peers or slow bootstrapping - - Confirm p2p-seed-node entries; validate network accessibility on port 2001 -- validator node not producing blocks - - Ensure validator name and private key are set; verify required-participation and enable-stale-production as appropriate -- Testnet initialization problems - - Confirm snapshot availability and permissions; check testnet-specific configuration - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L76-L86) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L99-L111) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L44-L53) -- [share/vizd/seednodes](file://share/vizd/seednodes#L1-L6) - -## Conclusion -Deploying a VIZ CPP Node involves selecting the appropriate configuration template, preparing the environment (native or Docker), and integrating with monitoring and security controls. Use the provided Docker images for production, leverage validator and testnet configurations for specialized roles, and tune performance parameters according to workload profiles. - -## Appendices - -### Appendix A: Node Type Reference -- Full node: General-purpose node with comprehensive plugins -- validator node: Block producer with configured validator and private key -- Seed node: Minimal footprint, focused on peer connectivity - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L69-L73) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L86) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L73) - -### Appendix B: Environment Variables (Docker) -- VIZD_RPC_ENDPOINT: Override RPC endpoint -- VIZD_P2P_ENDPOINT: Override P2P endpoint -- VIZD_SEED_NODES: Comma-separated seed nodes -- VIZD_WITNESS_NAME: validator name for block production -- VIZD_PRIVATE_KEY: Private key for validator signing -- VIZD_EXTRA_OPTS: Additional arguments to pass to vizd - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L17-L37) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L81) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Types and Configurations.md b/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Types and Configurations.md deleted file mode 100644 index 157ede7a73..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Node Types and Configurations.md +++ /dev/null @@ -1,458 +0,0 @@ -# Node Types and Configurations - - -**Referenced Files in This Document** -- [main.cpp](file://programs/vizd/main.cpp) -- [config.ini](file://share/vizd/config/config.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) -- [config_stock_exchange.ini](file://share/vizd/config/config_stock_exchange.ini) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [testnet.md](file://documentation/testnet.md) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp) - - -## Update Summary -**Changes Made** -- Updated P2P endpoint configuration section to reflect standardized port 2001 across all configuration files -- Removed references to external seed node file management system -- Updated seed node configuration to show direct integration into config.ini templates -- Added config_stock_exchange.ini to the configuration templates section -- Updated section sources to reflect current configuration files - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the different VIZ node types and their specific configurations. It covers full node setup with blockchain synchronization and API exposure, validator node configuration for block production and key management, seed node configuration for network bootstrap, and specialized configurations for testnet, debug, and MongoDB-integrated nodes. It also provides configuration file templates, parameter explanations, operational differences, performance tuning, resource allocation recommendations, monitoring requirements, and a comparison matrix across node configurations. - -## Project Structure -The repository organizes node configuration templates under share/vizd/config, Dockerfiles for different deployment modes under share/vizd/docker, and documentation under documentation. The main executable initializes plugins and loads configuration. - -```mermaid -graph TB -A["programs/vizd/main.cpp"] --> B["share/vizd/config/config.ini"] -A --> C["share/vizd/config/config_witness.ini"] -A --> D["share/vizd/config/config_debug.ini"] -A --> E["share/vizd/config/config_mongo.ini"] -A --> F["share/vizd/config/config_testnet.ini"] -A --> G["share/vizd/config/config_debug_mongo.ini"] -A --> H["share/vizd/config/config_stock_exchange.ini"] -I["share/vizd/docker/Dockerfile-production"] --> B -J["share/vizd/docker/Dockerfile-testnet"] --> F -K["share/vizd/docker/Dockerfile-mongo"] --> E -L["share/vizd/docker/Dockerfile-lowmem"] --> B -``` - -**Diagram sources** -- [main.cpp:106-158](file://programs/vizd/main.cpp#L106-L158) -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- [config_stock_exchange.ini:1-114](file://share/vizd/config/config_stock_exchange.ini#L1-L114) -- [Dockerfile-production:74-87](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet:75-87](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-mongo:97-110](file://share/vizd/docker/Dockerfile-mongo#L97-L110) -- [Dockerfile-lowmem:68-81](file://share/vizd/docker/Dockerfile-lowmem#L68-L81) - -**Section sources** -- [main.cpp:106-158](file://programs/vizd/main.cpp#L106-L158) -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [Dockerfile-production:74-87](file://share/vizd/docker/Dockerfile-production#L74-L87) -- [Dockerfile-testnet:75-87](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-mongo:97-110](file://share/vizd/docker/Dockerfile-mongo#L97-L110) -- [Dockerfile-lowmem:68-81](file://share/vizd/docker/Dockerfile-lowmem#L68-L81) - -## Core Components -- Full node: default configuration with broad plugin set for general-purpose operation and API exposure. -- validator node: enables block production with validator and witness_api plugins, requires validator name and private key. -- Debug node: specialized configuration for simulation and experimentation with debug_node plugin. -- Testnet node: minimal configuration optimized for testnet operation with enabled stale production. -- MongoDB-integrated node: includes mongo_db plugin for external database indexing and analytics. -- Stock exchange node: specialized configuration for trading infrastructure with optimized performance settings. -- Seed node: bootstrap configuration with predefined seed peers for network discovery. - -Key configuration parameters: -- P2P endpoint (standardized to port 2001) and seed nodes for connectivity. -- Webserver endpoints for HTTP and WebSocket APIs. -- Plugin selection for functional capabilities. -- Shared memory sizing and growth thresholds for database performance. -- Lock wait timeouts and retries for RPC concurrency. -- validator participation and block production controls. -- Logging configuration via appenders and loggers. - -**Updated** Standardized P2P endpoint configuration to port 2001 across all configuration files, removing the previous inconsistency where some configurations used different ports. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_witness.ini:68-138](file://share/vizd/config/config_witness.ini#L68-L138) -- [config_debug.ini:69-126](file://share/vizd/config/config_debug.ini#L69-L126) -- [config_mongo.ini:69-135](file://share/vizd/config/config_mongo.ini#L69-L135) -- [config_testnet.ini:69-132](file://share/vizd/config/config_testnet.ini#L69-L132) -- [config_debug_mongo.ini:69-135](file://share/vizd/config/config_debug_mongo.ini#L69-L135) -- [config_stock_exchange.ini:69-114](file://share/vizd/config/config_stock_exchange.ini#L69-L114) - -## Architecture Overview -The VIZ node is a modular application built on appbase with a plugin architecture. The main program registers and initializes plugins, loads configuration, and starts the server loop. Different node types are achieved by selecting different plugins and configuration files. - -```mermaid -graph TB -subgraph "Executable" -MAIN["programs/vizd/main.cpp
Registers plugins and starts app"] -end -subgraph "Plugins" -CHAIN["chain"] -P2P["p2p"] -WEBSERVER["webserver"] -NB["network_broadcast_api"] -DBAPI["database_api"] -ACC_HIST["account_history"] -OP_HIST["operation_history"] -WIT["validator"] -WIT_API["witness_api"] -DEBUG["debug_node"] -MONGO["mongo_db"] -TESTAPI["test_api"] -TAGS["tags"] -FOLLOW["follow"] -SOCIAL["social_network"] -PRIVATE_MSG["private_message"] -COMMITTEE["committee_api"] -INVITE["invite_api"] -PAID_SUB["paid_subscription_api"] -CUSTOM["custom_protocol_api"] -STOCK_EX["stock_exchange"] -end -MAIN --> CHAIN -MAIN --> P2P -MAIN --> WEBSERVER -MAIN --> NB -MAIN --> DBAPI -MAIN --> ACC_HIST -MAIN --> OP_HIST -MAIN --> WIT -MAIN --> WIT_API -MAIN --> DEBUG -MAIN --> MONGO -MAIN --> TESTAPI -MAIN --> TAGS -MAIN --> FOLLOW -MAIN --> SOCIAL -MAIN --> PRIVATE_MSG -MAIN --> COMMITTEE -MAIN --> INVITE -MAIN --> PAID_SUB -MAIN --> CUSTOM -MAIN --> STOCK_EX -``` - -**Diagram sources** -- [main.cpp:62-91](file://programs/vizd/main.cpp#L62-L91) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) - -**Section sources** -- [main.cpp:62-91](file://programs/vizd/main.cpp#L62-L91) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) - -## Detailed Component Analysis - -### Full Node Configuration -- Purpose: General-purpose node with comprehensive API coverage and history tracking. -- Key parameters: - - P2P endpoint standardized to port 2001 with integrated seed nodes for connectivity. - - HTTP and WebSocket webserver endpoints for API access. - - Broad plugin set including chain, p2p, json_rpc, webserver, network_broadcast_api, database_api, account_history, operation_history, committee_api, invite_api, paid_subscription_api, custom_protocol_api, account_by_key, block_info, raw_block. - - Shared memory sizing and growth thresholds to manage database capacity. - - Lock wait and retry settings for RPC client concurrency. - - Optional virtual operations skipping and vote clearing to optimize performance. -- Operational differences: - - Exposes APIs publicly by default. - - Tracks extensive operation history. - - Suitable for production and public API services. - -**Updated** P2P endpoint now standardized to port 2001 with integrated seed node configuration directly in the template. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) - -### validator Node Configuration -- Purpose: Block production node with validator and witness_api plugins. -- Key parameters: - - P2P endpoint standardized to port 2001 with integrated seed nodes. - - Local webserver endpoints for internal access. - - Plugins: chain, p2p, json_rpc, webserver, network_broadcast_api, database_api, validator, witness_api. - - validator participation and stale production controls. - - Required validator name and private key for block signing. - - Optimized logging configuration. -- Operational differences: - - Requires valid validator credentials. - - Can operate with stricter network isolation (local webserver endpoints). - - Enables validator-specific APIs. - -```mermaid -sequenceDiagram -participant Operator as "Operator" -participant Node as "VIZ Node" -participant validator as "Validator Plugin" -participant Chain as "Chain Plugin" -Operator->>Node : Start with validator config -Node->>validator : Initialize with validator name and private key -validator->>Chain : Request scheduled slot -Chain-->>validator : Block production slot -validator->>Chain : Produce block with private key -Chain-->>Node : Accept block -Node-->>Operator : Report block production status -``` - -**Diagram sources** -- [config_witness.ini:82-86](file://share/vizd/config/config_witness.ini#L82-L86) -- [validator.hpp:20-32](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) - -**Section sources** -- [config_witness.ini:68-138](file://share/vizd/config/config_witness.ini#L68-L138) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) - -### Debug Node Configuration -- Purpose: Simulation and experimentation with debug_node plugin for "what-if" scenarios. -- Key parameters: - - Minimal plugin set including chain, p2p, json_rpc, webserver, network_broadcast_api, database_api, debug_node, test_api, and others for deep inspection. - - Shared memory tuned for smaller footprint during development. - - Stale production enabled for accelerated simulation. - - Local webserver endpoints for secure access. -- Operational differences: - - Designed for local-only access. - - Provides APIs to push blocks, generate blocks, and update objects for simulation. - - Useful for hardfork testing and state experimentation. - -```mermaid -flowchart TD -Start(["Start Debug Node"]) --> LoadBlocks["Load blocks from directory"] -LoadBlocks --> Simulate["Simulate block production"] -Simulate --> UpdateState["Update chain state via debug APIs"] -UpdateState --> Verify["Verify operations and history"] -Verify --> End(["Stop and analyze"]) -``` - -**Diagram sources** -- [config_debug.ini:69-126](file://share/vizd/config/config_debug.ini#L69-L126) -- [plugin.hpp:62-90](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L62-L90) - -**Section sources** -- [config_debug.ini:69-126](file://share/vizd/config/config_debug.ini#L69-L126) -- [debug_node_plugin.md:50-134](file://documentation/debug_node_plugin.md#L50-L134) -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) - -### Testnet Node Configuration -- Purpose: Lightweight testnet node with stale production enabled for rapid iteration. -- Key parameters: - - P2P endpoint on port 4243 (different from mainnet) with integrated seed nodes. - - HTTP and WebSocket endpoints. - - Minimal plugin set focused on chain, p2p, json_rpc, webserver, network_broadcast_api, database_api, validator, witness_api. - - Stale production enabled and validator participation set to minimal. - - Predefined testnet validator and private key. -- Operational differences: - - Optimized for testnet with snapshot support. - - Simplified plugin set reduces overhead. - - Suitable for CI and automated testing. - -**Section sources** -- [config_testnet.ini:69-132](file://share/vizd/config/config_testnet.ini#L69-L132) -- [testnet.md:21-37](file://documentation/testnet.md#L21-L37) - -### MongoDB-Integrated Node Configuration -- Purpose: Node with mongo_db plugin for external analytics and off-chain indexing. -- Key parameters: - - P2P endpoint on port 4243 with integrated seed nodes. - - HTTP and WebSocket endpoints. - - Plugin set including mongo_db alongside standard plugins. - - MongoDB connection URI for external database. - - Market history bucket sizes and retention. -- Operational differences: - - Requires MongoDB instance and drivers. - - Adds significant I/O overhead; monitor storage and network. - - Enables advanced analytics and historical reporting. - -**Section sources** -- [config_mongo.ini:69-135](file://share/vizd/config/config_mongo.ini#L69-L135) - -### Stock Exchange Node Configuration -- Purpose: Specialized trading infrastructure node with optimized performance settings. -- Key parameters: - - P2P endpoint on port 4243 with integrated seed nodes. - - Local webserver endpoints for internal trading systems. - - Optimized plugin set focusing on chain, p2p, json_rpc, webserver, network_broadcast_api, validator, database_api, block_info, raw_block, operation_history, account_history, witness_api. - - Skip virtual operations and clear votes before block for improved performance. - - Reduced read wait retries for faster response times. -- Operational differences: - - Designed for high-frequency trading scenarios. - - Optimized for minimal latency and maximum throughput. - - Suitable for production trading infrastructure. - -**Section sources** -- [config_stock_exchange.ini:69-114](file://share/vizd/config/config_stock_exchange.ini#L69-L114) - -### Seed Node Configuration -- Purpose: Bootstrap and peer discovery for network formation. -- Key parameters: - - P2P endpoint bound to port 2001 for standard network compatibility. - - Integrated seed nodes configured directly in the template for immediate connectivity. - - Minimal plugin set to reduce resource usage. -- Operational differences: - - Does not synchronize the chain automatically. - - Serves as a discovery anchor for other nodes. - - Useful for private networks or isolated environments. - -**Updated** Removed references to external seed node file management system as seed nodes are now integrated directly into the config.ini templates. - -**Section sources** -- [config.ini:7-12](file://share/vizd/config/config.ini#L7-L12) - -## Dependency Analysis -The main executable registers and initializes plugins. validator and MongoDB plugins depend on the chain plugin. The debug node plugin depends on the chain plugin for state manipulation. Dockerfiles embed configuration templates and expose ports for RPC and P2P. - -```mermaid -graph LR -MAIN["programs/vizd/main.cpp"] --> REG["Register plugins"] -REG --> WIT["validator.hpp"] -REG --> MONGO["mongo_db_plugin.hpp"] -REG --> DEBUG["plugin.hpp"] -MAIN --> CFG["Config files"] -CFG --> DOCKER["Dockerfiles"] -``` - -**Diagram sources** -- [main.cpp:62-91](file://programs/vizd/main.cpp#L62-L91) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) - -**Section sources** -- [main.cpp:62-91](file://programs/vizd/main.cpp#L62-L91) -- [validator.hpp:34-65](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) - -## Performance Considerations -- Shared memory sizing: - - Increase shared-file-size and adjust min-free-shared-file-size and inc-shared-file-size to accommodate larger histories and reduce resizing pressure. - - Monitor free space checks via block-num-check-free-size to balance safety and performance. -- Concurrency and locks: - - single-write-thread reduces contention on database writes. - - Tune read-wait-micro and max-read-wait-retries, write-wait-micro and max-write-wait-retries to match workload patterns. -- Plugin selection: - - Disable unused plugins to reduce memory and CPU overhead. - - Skip virtual operations and clear old votes to improve performance on full nodes. -- validator node specifics: - - Keep participation thresholds low for testnet; raise for production. - - Ensure private key availability and secure storage. -- Debug node specifics: - - Use local-only endpoints and smaller shared memory for development. - - Enable stale production for fast simulation. -- MongoDB node specifics: - - Provision adequate disk IOPS and network bandwidth for MongoDB. - - Monitor write amplification and index maintenance costs. -- Stock exchange node specifics: - - Optimize for high-frequency trading with reduced read wait retries. - - Enable skip-virtual-ops and clear-votes-before-block for maximum throughput. -- Resource allocation recommendations: - - Full node: moderate CPU, substantial RAM for shared memory, fast SSD for block log and database. - - validator node: dedicated CPU cores, reliable network, secure key management. - - Debug node: modest resources, local SSD, restricted network access. - - Testnet node: minimal resources, ephemeral data. - - MongoDB node: high IOPS storage, separate MongoDB cluster, network isolation. - - Stock exchange node: high-performance hardware, low-latency networking, optimized storage. - -## Troubleshooting Guide -- RPC lock errors: - - Adjust read-wait-micro/read-wait-retries and write-wait-micro/write-wait-retries. - - Consider enabling single-write-thread to reduce lock contention. -- Insufficient shared memory: - - Increase shared-file-size and tune min-free-shared-file-size and inc-shared-file-size. - - Monitor block-num-check-free-size frequency. -- validator production issues: - - Verify validator name and private key. - - Check participation thresholds and network synchronization. -- Debug node anomalies: - - Confirm local-only endpoints and secure access. - - Validate block pushing and generation commands. -- MongoDB integration: - - Verify mongodb-uri and connectivity. - - Monitor MongoDB performance and replica set health. -- P2P connectivity issues: - - Verify p2p-endpoint is set to port 2001 for standard network compatibility. - - Check p2p-seed-node configuration for proper peer discovery. -- Stock exchange performance: - - Monitor read-wait-micro settings for optimal latency. - - Ensure skip-virtual-ops and clear-votes-before-block are enabled. - -**Section sources** -- [config.ini:22-67](file://share/vizd/config/config.ini#L22-L67) -- [config_witness.ini:76-86](file://share/vizd/config/config_witness.ini#L76-L86) -- [config_debug.ini:95-105](file://share/vizd/config/config_debug.ini#L95-L105) -- [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72) -- [config_stock_exchange.ini:22-34](file://share/vizd/config/config_stock_exchange.ini#L22-L34) - -## Conclusion -Different VIZ node types serve distinct operational needs. Full nodes provide broad API coverage, validator nodes enable consensus participation, debug nodes support experimentation, testnet nodes accelerate development, MongoDB-integrated nodes enable advanced analytics, and stock exchange nodes optimize for trading infrastructure. Proper configuration, performance tuning, and monitoring are essential for each type to achieve reliable operation. The standardized P2P endpoint configuration ensures consistent network compatibility across all node types. - -## Appendices - -### Configuration Templates and Parameters -- Full node template: [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- validator node template: [config_witness.ini:1-138](file://share/vizd/config/config_witness.ini#L1-L138) -- Debug node template: [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- MongoDB node template: [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- Testnet template: [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- Debug + MongoDB template: [config_debug_mongo.ini:1-135](file://share/vizd/config/config_debug_mongo.ini#L1-L135) -- Stock exchange template: [config_stock_exchange.ini:1-114](file://share/vizd/config/config_stock_exchange.ini#L1-L114) - -### Node Type Comparison Matrix - -| Feature | Full Node | validator Node | Debug Node | Testnet Node | MongoDB Node | Stock Exchange Node | -|---|---|---|---|---|---|---| -| P2P endpoint | 0.0.0.0:2001 | 0.0.0.0:2001 | Not set | 0.0.0.0:4243 | 0.0.0.0:4243 | 0.0.0.0:4243 | -| Seed nodes | Integrated | Integrated | Not set | Integrated | Integrated | Integrated | -| Webserver endpoints | Public | Local | Local | Public | Public | Local | -| Plugins | Broad | Essential + validator | Debug + test | Minimal | Mongo + essentials | Optimized trading | -| Shared memory | Large | Large | Small | Large | Large | Large | -| Stale production | Off | On (configurable) | On | On | Off | Off | -| validator participation | N/A | Configurable | N/A | Configurable | N/A | N/A | -| Private key | N/A | Required | N/A | N/A | N/A | N/A | -| MongoDB integration | No | No | No | No | Yes | No | -| Typical use | Production API | Consensus | Dev/Test | CI/Testing | Analytics | Trading Infrastructure | -| Port standardization | ✅ 2001 | ✅ 2001 | ❌ Not set | ❌ 4243 | ❌ 4243 | ❌ 4243 | - -**Updated** Added stock exchange node to the comparison matrix and updated P2P endpoint port information to reflect the standardized configuration. - -**Section sources** -- [config.ini:1-136](file://share/vizd/config/config.ini#L1-L136) -- [config_witness.ini:68-138](file://share/vizd/config/config_witness.ini#L68-L138) -- [config_debug.ini:69-126](file://share/vizd/config/config_debug.ini#L69-L126) -- [config_testnet.ini:69-132](file://share/vizd/config/config_testnet.ini#L69-L132) -- [config_mongo.ini:69-135](file://share/vizd/config/config_mongo.ini#L69-L135) -- [config_stock_exchange.ini:69-114](file://share/vizd/config/config_stock_exchange.ini#L69-L114) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Security Hardening.md b/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Security Hardening.md deleted file mode 100644 index 80ea17902e..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Security Hardening.md +++ /dev/null @@ -1,300 +0,0 @@ -# Security Hardening - - -**Referenced Files in This Document** -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [main.cpp](file://programs/vizd/main.cpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive security hardening guidance for deploying VIZ CPP Node across environments from development to production. It focuses on network security, API security, cryptography, system-level controls, monitoring, vulnerability management, updates, and incident response. The guidance is grounded in the repository’s configuration, plugin architecture, and network/cryptography components. - -## Project Structure -VIZ CPP Node is organized around: -- Application entry and plugin registration -- Network stack with P2P and secure transport -- Webserver and JSON-RPC API surface -- Configuration-driven runtime behavior -- Containerized production packaging - -```mermaid -graph TB -A["programs/vizd/main.cpp"] --> B["plugins/p2p/p2p_plugin.hpp"] -A --> C["plugins/webserver/webserver_plugin.hpp"] -A --> D["plugins/json_rpc/plugin.hpp"] -C --> D -B --> E["libraries/network/node.hpp"] -E --> F["libraries/network/config.hpp"] -E --> G["libraries/network/stcp_socket.hpp"] -H["share/vizd/config/config.ini"] --> A -I["share/vizd/docker/Dockerfile-production"] --> A -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) - -## Core Components -- P2P networking and peer management -- Secure transport via ECDH/AES -- HTTP/WebSocket API via webserver plugin backed by JSON-RPC -- Configuration-driven behavior and logging - -Key security-relevant elements: -- Network limits and timeouts -- Logging configuration -- Plugin exposure surface -- Transport encryption - -**Section sources** -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -## Architecture Overview -The node exposes: -- P2P endpoint for peer-to-peer synchronization -- HTTP and WebSocket endpoints for API access -- Optional validator production and related APIs - -```mermaid -graph TB -subgraph "Node Process" -N["Network Layer
node.hpp"] -S["Secure Transport
stcp_socket.hpp"] -W["Webserver Plugin
webserver_plugin.hpp"] -R["JSON-RPC Dispatcher
plugin.hpp"] -P["P2P Plugin
p2p_plugin.hpp"] -end -Internet["External Clients"] --> W -W --> R -N --> S -N --> P -P --> N -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) - -## Detailed Component Analysis - -### Network Security Configuration -- P2P endpoint binding and advertised ports -- Connection limits and timeouts -- Message size limits and bandwidth parameters -- Logging for P2P subsystem - -Recommendations: -- Restrict P2P listen address to internal or DMZ interfaces as appropriate -- Limit maximum connections and desired connections per operational profile -- Harden message size and rate parameters to mitigate resource exhaustion -- Enable and tune logging for anomaly detection - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L200-L304) - -### Port Management and Network Isolation -- Exposed ports in production container: - - HTTP API: 8090 - - WebSocket API: 8091 - - P2P: 2001 -- Default configuration binds P2P to 0.0.0.0:4243 - -Guidance: -- Apply firewall rules to restrict inbound access to only required ports -- Segment networks via VLANs or namespaces; prefer loopback/internal binding for P2P where feasible -- Use reverse proxies or gateways for external API access with TLS termination - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L79-L86) -- [config.ini](file://share/vizd/config/config.ini#L2-L20) - -### API Security: Authentication, Rate Limiting, Access Control -- Current configuration does not define explicit authentication or rate limiting for RPC endpoints -- JSON-RPC is the transport mechanism; API exposure depends on loaded plugins - -Recommendations: -- Deploy API behind an authenticating gateway or reverse proxy -- Enforce per-endpoint quotas and sliding window rate limits -- Restrict sensitive RPC methods to trusted IPs or VPN -- Rotate secrets and enforce mutual TLS where applicable - -Note: The repository does not include built-in authentication or rate limiting in the referenced files. - -**Section sources** -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [config.ini](file://share/vizd/config/config.ini#L13-L20) - -### Cryptographic Security Measures -- Secure TCP socket uses ECDH key exchange and AES encryption for P2P transport -- Shared secret derived per-connection - -Recommendations: -- Ensure private keys for signing are managed externally and rotated regularly -- Use hardware security modules or key management systems for key storage -- Validate certificates and enforce strict TLS policies at ingress - -**Section sources** -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L105-L111) - -### System-Level Security -- Production container creates a dedicated node user and separates volumes -- Logging configuration supports console and file appenders - -Recommendations: -- Run as non-root user with minimal privileges -- Bind mount persistent volumes with restrictive filesystem permissions -- Enable filesystem integrity monitoring and immutable logs where possible -- Disable unnecessary plugins to reduce attack surface - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L69-L88) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [config.ini](file://share/vizd/config/config.ini#L111-L130) - -### Security Monitoring and Threat Detection -- Logging configuration supports separate loggers and appenders -- P2P subsystem tracks propagation timing and peer status - -Recommendations: -- Centralize logs and correlate P2P and API events -- Monitor for unusual spikes in transactions or blocks -- Alert on repeated handshake failures, unexpected disconnects, or malformed messages - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L167-L289) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L173-L179) - -### Vulnerability Assessment and Patch Management -- Build-time toggles for optional components and memory safety checks -- Release builds recommended for production - -Recommendations: -- Perform static/dynamic analysis on release artifacts -- Establish a patch cadence aligned with upstream releases and security advisories -- Maintain SBOM and track third-party dependencies - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) - -### Incident Response Protocols -- Graceful shutdown hooks and structured logging -- Clear separation of concerns between plugins and network layers - -Recommendations: -- Define runbooks for high load, connectivity issues, and crypto key rotation -- Automate log collection and isolate affected nodes immediately -- Review and update configurations post-incident - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L220) - -## Dependency Analysis -The API stack depends on the webserver plugin and JSON-RPC dispatcher. The P2P stack depends on the node and secure transport components. - -```mermaid -graph LR -WS["webserver_plugin.hpp"] --> JR["plugin.hpp"] -P2P["p2p_plugin.hpp"] --> NET["node.hpp"] -NET --> CFG["config.hpp"] -NET --> STCP["stcp_socket.hpp"] -``` - -**Diagram sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -**Section sources** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp#L26-L106) -- [stcp_socket.hpp](file://libraries/network/include/graphene/network/stcp_socket.hpp#L37-L93) - -## Performance Considerations -- Lock wait and retry parameters influence resilience under load -- Single write thread reduces contention but may bottleneck high-throughput scenarios -- Adjust thread pool sizes and connection limits according to workload - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common areas to inspect: -- P2P connectivity and peer counts -- API latency and throughput -- Log levels and destinations -- Resource exhaustion symptoms (locks, memory, disk) - -Operational tips: -- Temporarily increase log verbosity for diagnosis -- Verify endpoint reachability and firewall rules -- Confirm plugin initialization order and dependencies - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L22-L47) -- [main.cpp](file://programs/vizd/main.cpp#L167-L289) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L248-L253) - -## Conclusion -This guide consolidates security hardening practices for VIZ CPP Node deployments using repository-provided configuration and components. By applying network isolation, robust logging, transport encryption, and operational controls, teams can significantly improve security posture across environments. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Compliance and Audit Considerations -- Maintain audit trails for sensitive operations -- Enforce least privilege and segregation of duties -- Document configuration baselines and deviations -- Align logging retention and immutability policies with compliance requirements - -[No sources needed since this section provides general guidance] \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Service Integration.md b/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Service Integration.md deleted file mode 100644 index fe26eefa46..0000000000 --- a/.qoder/repowiki/en/content/Deployment and Operations/Node Deployment/Service Integration.md +++ /dev/null @@ -1,339 +0,0 @@ -# Service Integration - - -**Referenced Files in This Document** -- [vizd.sh](file://share/vizd/vizd.sh) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [main.cpp](file://programs/vizd/main.cpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive service integration guidance for deploying and operating the VIZ CPP Node across Linux and Windows environments. It covers: -- Linux service configuration via containerized runtime with Phusion baseimage and runit-style supervision -- Windows service installation and management procedures -- Reverse proxy, load balancer, and API gateway integration -- Monitoring, health checks, metrics, and alerting -- Log rotation, centralized logging, and log aggregation -- Cloud platform, container orchestration, and CI/CD pipeline integration -- Backup and recovery, disaster recovery, and high availability -- Integration examples with monitoring/logging/infrastructure platforms - -## Project Structure -The repository organizes the VIZ node around: -- A main executable entry point -- A modular plugin architecture for P2P networking and HTTP/WebSocket APIs -- Container images and scripts for Linux deployment -- Configuration templates for mainnet and testnet - -```mermaid -graph TB -subgraph "Executable" -MAIN["programs/vizd/main.cpp"] -end -subgraph "Plugins" -WS["plugins/webserver/webserver_plugin.cpp"] -P2P["plugins/p2p/p2p_plugin.cpp"] -end -subgraph "Containerization" -DPROD["share/vizd/docker/Dockerfile-production"] -DTEST["share/vizd/docker/Dockerfile-testnet"] -DLOW["share/vizd/docker/Dockerfile-lowmem"] -RUN["share/vizd/vizd.sh"] -CFG["share/vizd/config/config.ini"] -CFGT["share/vizd/config/config_testnet.ini"] -end -MAIN --> WS -MAIN --> P2P -DPROD --> RUN -DPROD --> CFG -DTEST --> RUN -DTEST --> CFGT -DLOW --> RUN -DLOW --> CFG -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L248-L335) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L461-L603) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L87) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L87) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L81) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L248-L335) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L461-L603) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L87) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L87) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L81) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -## Core Components -- Executable entry point initializes plugins and starts the application lifecycle. -- Webserver plugin exposes HTTP and WebSocket endpoints for JSON-RPC. -- P2P plugin manages peer-to-peer connectivity, block synchronization, and transaction propagation. -- Container images define runtime user, exposed ports, and supervised startup script. -- Configuration files define endpoints, plugins, and logging behavior for mainnet and testnet. - -Key runtime and configuration touchpoints: -- HTTP and WebSocket endpoints are configurable via program options and configuration files. -- Logging configuration is loaded from the configuration file and supports console and file appenders. -- P2P endpoint and seed nodes are configurable via program options and environment variables in the container script. - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L254-L312) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L467-L529) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L81) - -## Architecture Overview -The VIZ node runs as a single binary with pluggable components. The containerized runtime supervises the process, injects configuration, and exposes network endpoints. The webserver plugin serves HTTP and WebSocket JSON-RPC traffic, while the P2P plugin handles blockchain synchronization and gossip. - -```mermaid -graph TB -subgraph "Host OS" -SVC["Supervision (Phusion baseimage)"] -NET["Network Interfaces"] -end -subgraph "Container Runtime" -IMG["Image: phusion/baseimage"] -RUN["/etc/service/vizd/run (vizd.sh)"] -BIN["/usr/local/bin/vizd"] -CFG["/etc/vizd/config.ini"] -DATA["/var/lib/vizd"] -end -subgraph "Node Process" -MAIN["main.cpp
registers plugins"] -WS["webserver_plugin.cpp
HTTP/WS JSON-RPC"] -P2P["p2p_plugin.cpp
P2P sync/gossip"] -end -SVC --> IMG -IMG --> RUN -RUN --> BIN -BIN --> WS -BIN --> P2P -BIN --> CFG -BIN --> DATA -NET --> WS -NET --> P2P -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L87) -- [vizd.sh](file://share/vizd/vizd.sh#L74-L81) -- [main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L248-L335) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L531-L566) - -## Detailed Component Analysis - -### Linux Service Configuration (Containerized) -The repository provides a production-ready container image that: -- Creates a dedicated node user -- Copies a supervision script to run the node under runit-style supervision -- Exposes RPC and P2P ports -- Mounts persistent volumes for configuration and data - -Operational guidance: -- Use the provided Dockerfile-production or testnet variant to build images. -- Run the container with volume mounts for configuration and data directories. -- Configure environment variables in the container to override endpoints and seed nodes as needed. -- The supervision script ensures the node restarts on failure and applies environment overrides. - -```mermaid -flowchart TD -Start(["Container Start"]) --> CopyCfg["Copy config.ini to /etc/vizd"] -CopyCfg --> SeedNodes["Load seednodes from /etc/vizd/seednodes"] -SeedNodes --> EnvOverride{"Environment overrides present?"} -EnvOverride --> |Yes| ApplyEnv["Apply VIZD_* env vars"] -EnvOverride --> |No| Defaults["Use defaults from config.ini"] -ApplyEnv --> Prepare["Prepare data-dir and cache"] -Defaults --> Prepare -Prepare --> Exec["Execute /usr/local/bin/vizd with args"] -Exec --> Supervise["Supervised by runit-style /etc/service/vizd/run"] -Supervise --> End(["Healthy Running"]) -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L69-L87) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L87) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L67-L87) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L81) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -### Windows Service Installation and Management -The repository does not include Windows-specific service files or scripts. To deploy on Windows: -- Package the VIZ node binary and required configuration files into a Windows-compatible artifact. -- Create a Windows service wrapper using a launcher such as NSSM or WinSW to manage the process lifecycle. -- Configure the service to run under a dedicated user account with appropriate permissions. -- Use the configuration files from the repository to define endpoints and plugins. -- Integrate with Windows Event Log for logging and monitoring. - -[No sources needed since this section provides general guidance] - -### Integration with Reverse Proxies, Load Balancers, and API Gateways -The node exposes: -- HTTP JSON-RPC endpoint -- WebSocket JSON-RPC endpoint -- P2P endpoint for peers - -Recommended integration patterns: -- Place an HTTP load balancer or reverse proxy in front of the HTTP and WebSocket endpoints. -- Configure health checks against the HTTP endpoint and/or a dedicated health path if available. -- Use sticky sessions only if required by client workflows; otherwise, distribute across multiple node instances. -- For API gateways, expose only the JSON-RPC endpoints and apply rate limiting and authentication policies at the gateway layer. - -[No sources needed since this section provides general guidance] - -### Monitoring Integration (Health Checks, Metrics, Alerting) -Monitoring capabilities: -- Health checks: Poll the HTTP endpoint to verify node responsiveness. -- Logs: The node supports console and file appenders configured via the configuration file. -- Metrics: No built-in metrics endpoint is present in the referenced code; integrate external metrics collection at the host/container level. - -Operational recommendations: -- Centralize logs from the node’s file appender to a SIEM or log aggregation platform. -- Use host/container metrics (CPU, memory, disk) and network throughput for alerting. -- Define alerts for restart storms, high latency, low free disk, and P2P connection counts. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L111-L130) -- [main.cpp](file://programs/vizd/main.cpp#L167-L191) - -### Log Rotation, Centralized Logging, and Log Aggregation -Logging configuration: -- Console and file appenders are supported and configurable. -- File appender rotation and flushing are programmatically enabled during configuration loading. - -Integration guidance: -- Route node logs to a centralized logging system (e.g., ELK, Loki, Splunk) using standard collectors. -- Ensure log paths are persisted via mounted volumes and managed by the container runtime. -- Rotate logs at the collector level to avoid blocking the node process. - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L211-L288) -- [config.ini](file://share/vizd/config/config.ini#L111-L130) - -### Cloud Platforms, Container Orchestration, and Automated Pipelines -Container images: -- Production and testnet images are built from the provided Dockerfiles. -- GitHub Actions workflow builds and publishes images on pushes to master. - -Orchestration and CI/CD: -- Deploy containers to Kubernetes, ECS, or similar orchestrators using the published images. -- Use the workflow as a template for automated image builds and publishing. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) - -### Backup and Recovery, Disaster Recovery, and High Availability -Backup and recovery: -- Back up the data directory (blockchain state) regularly. -- Snapshot the configuration directory to preserve runtime settings. -- Test restoration procedures in isolated environments before applying to production. - -High availability: -- Run multiple node instances behind a load balancer. -- Prefer validator nodes with redundant infrastructure and monitoring. -- Use rolling updates to minimize downtime during maintenance. - -[No sources needed since this section provides general guidance] - -### Integration Examples with Monitoring, Logging, and Infrastructure Platforms -- Monitoring: Prometheus node_exporter + custom JSON-RPC health exporter; Grafana dashboards for latency and peer counts. -- Logging: Fluent Bit or Filebeat shipping logs to Elasticsearch/OpenSearch; centralized dashboards. -- Infrastructure: Terraform/AWS/GCP/Azure for provisioning; Helm/Kustomize for Kubernetes deployments. - -[No sources needed since this section provides general guidance] - -## Dependency Analysis -The node executable registers and initializes plugins. The webserver plugin depends on the JSON-RPC plugin and chain plugin state. The P2P plugin depends on the chain plugin for database operations. - -```mermaid -graph LR -MAIN["main.cpp"] --> REG["register_plugins()"] -REG --> WSPLUG["webserver_plugin.cpp"] -REG --> P2PPLUG["p2p_plugin.cpp"] -WSPLUG --> JRPC["JSON-RPC plugin"] -WSPLUG --> CHAIN["chain plugin"] -P2PPLUG --> CHAIN -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L314-L326) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L531-L566) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L314-L326) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L531-L566) - -## Performance Considerations -- Thread pool sizing: Tune the webserver thread pool size according to CPU cores and expected concurrency. -- Lock contention: The configuration enables single-write-thread mode to reduce database lock contention. -- Shared memory sizing: Adjust shared file size and thresholds to prevent frequent resizing during operation. -- P2P connections: Limit maximum connections and carefully select seed nodes to balance connectivity and resource usage. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L13-L67) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L254-L263) - -## Troubleshooting Guide -Common operational issues and resolutions: -- Startup failures: Verify configuration file syntax and required directories exist inside the container. -- Network connectivity: Confirm P2P endpoint binding and firewall rules; ensure seed nodes are reachable. -- Log visibility: Check file appender paths and permissions; confirm log levels are set appropriately. -- Health checks failing: Validate HTTP/WS endpoints and ensure plugins are fully synced before exposing to clients. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L111-L130) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L531-L566) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp#L314-L326) - -## Conclusion -The VIZ CPP Node is designed for containerized deployment with robust supervision and flexible configuration. By leveraging the provided Docker images, configuration templates, and plugin architecture, operators can integrate the node into modern infrastructure with reverse proxies, load balancers, monitoring, logging, and CI/CD pipelines. For Windows environments, a Windows service wrapper should be created alongside the configuration artifacts. Disaster recovery and high availability are achieved through multiple node instances, regular backups, and careful orchestration. - -## Appendices -- Environment variable overrides in the container script: - - RPC and P2P endpoints - - validator name and private key - - Seed nodes - - Extra options - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L62-L81) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Scripts.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Scripts.md deleted file mode 100644 index 14a2884e4e..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Scripts.md +++ /dev/null @@ -1,416 +0,0 @@ -# Build Helper Scripts - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [programs/build_helpers/CMakeLists.txt](file://programs/build_helpers/CMakeLists.txt) -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [libraries/chain/hardfork.d/0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [libraries/chain/hardfork.d/1.hf](file://libraries/chain/hardfork.d/1.hf) -- [documentation/building.md](file://documentation/building.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document explains the build helper scripts and automation tools used to compile the VIZ blockchain node across multiple platforms. It covers the shell and batch scripts for Linux/macOS/Windows, the CMake-based build system, and specialized helper utilities that assist with hardfork file concatenation, reflection validation, and cross-platform configuration. - -## Project Structure -The build system is organized around: -- Platform-specific build scripts for quick configuration and compilation -- A centralized CMake configuration that defines compile-time options and platform flags -- Helper utilities under programs/build_helpers for specialized tasks like hardfork file assembly and reflection consistency checks -- Documentation that describes all supported build options and workflows - -```mermaid -graph TB -subgraph "Platform Build Scripts" -LNX["build-linux.sh"] -MAC["build-mac.sh"] -MGW["build-mingw.bat"] -MSC["build-msvc.bat"] -end -subgraph "CMake Configuration" -CML["CMakeLists.txt"] -HF0["libraries/chain/hardfork.d/0-preamble.hf"] -HF1["libraries/chain/hardfork.d/1.hf"] -end -subgraph "Build Helpers" -CATCPP["programs/build_helpers/cat-parts.cpp"] -CATPY["programs/build_helpers/cat_parts.py"] -REFCHK["programs/build_helpers/check_reflect.py"] -CFGPY["programs/build_helpers/configure_build.py"] -end -LNX --> CML -MAC --> CML -MGW --> CML -MSC --> CML -CML --> HF0 -CML --> HF1 -CML --> CATCPP -CML --> CATPY -CML --> REFCHK -CML --> CFGPY -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt) -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [programs/build_helpers/CMakeLists.txt](file://programs/build_helpers/CMakeLists.txt) -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [libraries/chain/hardfork.d/0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [libraries/chain/hardfork.d/1.hf](file://libraries/chain/hardfork.d/1.hf) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) - -## Core Components -- Platform build scripts: - - Linux: automated dependency installation, submodule initialization, CMake configuration, parallel build, and optional install - - macOS: Xcode/Homebrew checks, OpenSSL detection, CMake configuration, parallel build, and optional install - - Windows MSVC: CMake configuration with Visual Studio generator, build execution, and optional install - - Windows MinGW: CMake configuration with MinGW generator, build execution, and optional install -- CMake configuration: - - Centralized compile-time options (build type, memory mode, testnet, MongoDB plugin, shared/static libs) - - Platform-specific compiler flags and static linking policies - - Hardfork file inclusion and generation pipeline -- Build helper utilities: - - Concatenate hardfork .hf files into a single header - - Validate FC_REFLECT declarations match Doxygen-extracted class members - - Cross-platform CMake configuration helper for Windows builds - - Python-based file concatenation utility - -**Section sources** -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) - -## Architecture Overview -The build architecture integrates platform scripts with CMake and helper utilities to provide a unified, repeatable build experience across platforms. - -```mermaid -graph TB -subgraph "User Workflow" -U1["Select platform script"] -U2["Configure options"] -U3["Run build"] -end -subgraph "Build System" -S1["Platform script"] -S2["CMake configuration"] -S3["Compiler and linker"] -S4["Helper utilities"] -end -subgraph "Outputs" -O1["Executable binaries"] -O2["Documentation artifacts"] -O3["Hardfork headers"] -end -U1 --> S1 -U2 --> S2 -U3 --> S2 -S4 --> S2 -S2 --> O1 -S2 --> O3 -S4 --> O2 -``` - -**Diagram sources** -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) - -## Detailed Component Analysis - -### Linux Build Script -The Linux script automates dependency installation (based on detected package manager), submodule initialization, CMake configuration with configurable options, parallel build execution, and optional installation. - -```mermaid -flowchart TD -Start(["Script start"]) --> ParseArgs["Parse CLI arguments"] -ParseArgs --> DetectJobs["Detect parallel jobs"] -DetectJobs --> CheckDir["Verify source directory"] -CheckDir --> InstallDeps{"Skip deps?"} -InstallDeps --> |Yes| InitSubmodules["Initialize submodules"] -InstallDeps --> |No| InstallDepsFn["Install dependencies"] -InstallDepsFn --> InitSubmodules -InitSubmodules --> Configure["CMake configure with options"] -Configure --> Build["Parallel build"] -Build --> InstallOpt{"Install?"} -InstallOpt --> |Yes| DoInstall["Install to system"] -InstallOpt --> |No| SkipInstall["Skip install"] -DoInstall --> Done(["Complete"]) -SkipInstall --> Done -``` - -**Diagram sources** -- [build-linux.sh](file://build-linux.sh) - -**Section sources** -- [build-linux.sh](file://build-linux.sh) -- [documentation/building.md](file://documentation/building.md) - -### macOS Build Script -The macOS script verifies Xcode Command Line Tools and Homebrew, detects OpenSSL path, initializes submodules, configures CMake, builds in parallel, and optionally installs. - -```mermaid -flowchart TD -Start(["Script start"]) --> CheckXcode["Check Xcode Command Line Tools"] -CheckXcode --> CheckBrew["Check Homebrew"] -CheckBrew --> InstallDeps{"Skip deps?"} -InstallDeps --> |Yes| DetectOpenSSL["Detect OpenSSL path"] -InstallDeps --> |No| InstallDepsFn["Install dependencies via Homebrew"] -InstallDepsFn --> DetectOpenSSL -DetectOpenSSL --> InitSubmodules["Initialize submodules"] -InitSubmodules --> Configure["CMake configure with options"] -Configure --> Build["Parallel build"] -Build --> InstallOpt{"Install?"} -InstallOpt --> |Yes| DoInstall["Install to system"] -InstallOpt --> |No| SkipInstall["Skip install"] -DoInstall --> Done(["Complete"]) -SkipInstall --> Done -``` - -**Diagram sources** -- [build-mac.sh](file://build-mac.sh) - -**Section sources** -- [build-mac.sh](file://build-mac.sh) -- [documentation/building.md](file://documentation/building.md) - -### Windows Build Scripts -Two Windows scripts support different toolchains: -- MSVC: Uses Visual Studio generator and CMake configuration with optional extra flags -- MinGW: Uses MinGW Makefiles generator and CMake configuration with static/full-static options - -```mermaid -sequenceDiagram -participant User as "User" -participant Script as "Windows Build Script" -participant CMake as "CMake" -participant Generator as "Generator (MSVC/MinGW)" -participant Build as "Build System" -User->>Script : Invoke script with environment variables -Script->>CMake : Configure with generators and options -CMake->>Generator : Select generator and toolchain -Generator-->>CMake : Toolchain configured -CMake-->>Script : Configuration complete -Script->>Build : Build with selected generator -Build-->>Script : Build complete -Script-->>User : Report completion -``` - -**Diagram sources** -- [build-msvc.bat](file://build-msvc.bat) -- [build-mingw.bat](file://build-mingw.bat) - -**Section sources** -- [build-msvc.bat](file://build-msvc.bat) -- [build-mingw.bat](file://build-mingw.bat) -- [documentation/building.md](file://documentation/building.md) - -### CMake Configuration and Compile-Time Options -CMake centralizes build configuration, compile-time flags, and platform-specific settings. Key options include build type, memory mode, testnet, MongoDB plugin, shared/static libraries, and chainbase lock checking. - -```mermaid -flowchart TD -Start(["CMake configure"]) --> ReadOptions["Read compile-time options"] -ReadOptions --> PlatformFlags["Apply platform-specific flags"] -PlatformFlags --> FindDeps["Find Boost/OpenSSL"] -FindDeps --> GenerateTargets["Generate build targets"] -GenerateTargets --> WriteFiles["Write compile_commands.json"] -WriteFiles --> End(["Ready to build"]) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) - -### Hardfork File Concatenation Utility (C++) -The C++ utility scans a directory for .hf files, sorts them, concatenates their contents, and writes a single output file if the content differs from existing output. - -```mermaid -flowchart TD -Start(["Start"]) --> Args["Validate arguments"] -Args --> Scan["Scan directory for .hf files"] -Scan --> Sort["Sort files lexicographically"] -Sort --> Read["Read concatenated content"] -Read --> Compare{"Compare with existing output?"} -Compare --> |Same| UpToDate["Mark as up-to-date"] -Compare --> |Different| Write["Write new output"] -UpToDate --> End(["Exit"]) -Write --> End -``` - -**Diagram sources** -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) - -**Section sources** -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [libraries/chain/hardfork.d/0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [libraries/chain/hardfork.d/1.hf](file://libraries/chain/hardfork.d/1.hf) - -### Hardfork File Concatenation Utility (Python) -The Python utility provides equivalent functionality to the C++ version with robust error handling and directory creation. - -```mermaid -flowchart TD -Start(["Start"]) --> Args["Validate arguments"] -Args --> Exists{"Output exists?"} -Exists --> |Yes| ReadOld["Read existing output"] -ReadOld --> Compute["Compute new concatenated content"] -Compute --> Same{"Content same?"} -Same --> |Yes| Exit0["Exit 0 (up-to-date)"] -Same --> |No| Write["Write new content"] -Exists --> |No| MkDir["Ensure parent directory exists"] -MkDir --> Compute -Write --> Exit0 -``` - -**Diagram sources** -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) - -**Section sources** -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) - -### Reflection Consistency Checker -The Python script validates that FC_REFLECT declarations match Doxygen-extracted class members, reporting mismatches and duplicates. - -```mermaid -flowchart TD -Start(["Start"]) --> ParseDoxygen["Parse Doxygen XML index"] -ParseDoxygen --> ExtractMembers["Extract class members"] -ExtractMembers --> WalkSources["Walk source tree for FC_REFLECT"] -WalkSources --> Compare["Compare member sets"] -Compare --> Report["Report OK/Not Evaluated/Error items"] -Report --> Exit(["Exit with status"]) -``` - -**Diagram sources** -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) - -**Section sources** -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) - -### Cross-Platform CMake Configuration Helper (Windows) -The Python helper constructs CMake commands with platform-specific flags, environment variable support, and optional additional options. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Helper as "configure_build.py" -participant CMake as "CMake" -participant FS as "Filesystem" -Dev->>Helper : Provide options (paths, flags) -Helper->>FS : Resolve paths and validate -Helper->>Helper : Detect Boost version -Helper->>CMake : Build command with flags -CMake-->>Helper : Execute configuration -Helper-->>Dev : Print command and exit code -``` - -**Diagram sources** -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) - -**Section sources** -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) - -## Dependency Analysis -The build system exhibits clear separation of concerns: -- Platform scripts depend on CMake and system tools -- CMake depends on Boost and OpenSSL availability -- Helper utilities are standalone and can be invoked independently -- Hardfork concatenation utilities depend on filesystem access and input ordering - -```mermaid -graph TB -LNX["build-linux.sh"] --> CML["CMakeLists.txt"] -MAC["build-mac.sh"] --> CML -MGW["build-mingw.bat"] --> CML -MSC["build-msvc.bat"] --> CML -CATCPP["cat-parts.cpp"] --> HFDIR["hardfork.d/*.hf"] -CATPY["cat_parts.py"] --> HFDIR -REFCHK["check_reflect.py"] --> SRC["Source tree"] -CFGPY["configure_build.py"] --> CML -CML --> BOOST["Boost libraries"] -CML --> SSL["OpenSSL libraries"] -``` - -**Diagram sources** -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/build_helpers/cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [libraries/chain/hardfork.d/0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [libraries/chain/hardfork.d/1.hf](file://libraries/chain/hardfork.d/1.hf) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/build_helpers/CMakeLists.txt](file://programs/build_helpers/CMakeLists.txt) - -## Performance Considerations -- Parallel builds: All platform scripts support parallel job counts to speed up compilation -- Dependency caching: CMake and ccache integration reduce rebuild times -- Static linking: Windows scripts offer full static builds to simplify deployment -- Hardfork concatenation: Efficient sorting and streaming minimize I/O overhead - -## Troubleshooting Guide -- Linux/macOS dependency issues: Use the provided scripts to install required packages; verify submodules are initialized -- Windows environment variables: Ensure BOOST_ROOT and OPENSSL_ROOT_DIR are set and point to valid directories -- Hardfork header mismatch: Re-run the concatenation utility to regenerate the combined header -- Reflection validation failures: Fix FC_REFLECT declarations to match Doxygen-extracted members -- CMake configuration errors: Confirm compiler versions meet minimum requirements and required libraries are discoverable - -**Section sources** -- [documentation/building.md](file://documentation/building.md) -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) - -## Conclusion -The build helper scripts and CMake configuration provide a robust, cross-platform build system for the VIZ node. They automate dependency management, platform-specific configurations, and quality checks, enabling contributors and operators to build reliably across Linux, macOS, and Windows environments. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Build Helper Tools.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Build Helper Tools.md deleted file mode 100644 index b323302dd9..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Build Helper Tools.md +++ /dev/null @@ -1,686 +0,0 @@ -# Build Helper Tools - - -**Referenced Files in This Document** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [newplugin.py](file://programs/util/newplugin.py) -- [pretty_schema.py](file://programs/util/pretty_schema.py) -- [schema_test.cpp](file://programs/util/schema_test.cpp) -- [configure_build.py](file://programs/build_helpers/configure_build.py) -- [install-deps-linux.sh](file://install-deps-linux.sh) -- [build-linux.sh](file://build-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [CMakeLists.txt (build_helpers)](file://programs/build_helpers/CMakeLists.txt) -- [CMakeLists.txt (util)](file://programs/util/CMakeLists.txt) -- [building.md](file://documentation/building.md) -- [README.md](file://README.md) - - -## Update Summary -**Changes Made** -- Added comprehensive documentation for the new install-deps-linux.sh dependency installer script -- Updated build system architecture documentation to reflect the separation of dependency management from the main build process -- Revised build-linux.sh documentation to reflect the use of --clean instead of --skip-deps option -- Enhanced security practices documentation highlighting the improved build system architecture -- Updated practical examples to demonstrate the new two-script build workflow - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Compilation Correctness and Best Practices](#compilation-correctness-and-best-practices) -9. [Security and Build System Architecture](#security-and-build-system-architecture) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Conclusion](#conclusion) -12. [Appendices](#appendices) - -## Introduction -This document describes the VIZ C++ Node build helper tools that streamline development tasks such as assembling source fragments, validating reflection metadata, scaffolding custom plugins, generating formatted schema representations, and validating database schemas. It explains command-line usage, input/output formats, and integration with the main build process. The build system has been enhanced with a new dependency installer script that separates system dependency management from the main build process, improving security and maintainability. - -**Updated** Enhanced with new dependency management capabilities and improved build system architecture. - -## Project Structure -The build helper tools live under programs/build_helpers and programs/util. They integrate with CMake via dedicated CMakeLists.txt files and complement the broader build system described in documentation/building.md. The system now includes a new dependency installer script that manages system-level dependencies separately from the main build process. - -```mermaid -graph TB -subgraph "Build System Scripts" -IDL["install-deps-linux.sh
✓ New Dependency Installer"] -BL["build-linux.sh
✓ Updated with --clean Option"] -BM["build-mac.sh
✓ Maintains --skip-deps Option"] -end -subgraph "Build Helpers" -CP["cat-parts.cpp
✓ Algorithm Header Included"] -CPY["cat_parts.py"] -CR["check_reflect.py"] -CFG["configure_build.py"] -end -subgraph "Utilities" -NP["newplugin.py"] -PS["pretty_schema.py"] -ST["schema_test.cpp"] -end -subgraph "CMake Integration" -CL1["programs/build_helpers/CMakeLists.txt"] -CL2["programs/util/CMakeLists.txt"] -end -IDL --> BL -BL --> CL1 -BM --> CL1 -CP --> CL1 -CPY --> CL1 -CR --> CL1 -CFG --> CL1 -NP --> CL2 -PS --> CL2 -ST -. "commented in CMake" .-> CL2 -``` - -**Diagram sources** -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) -- [CMakeLists.txt (build_helpers):1-8](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (util):1-69](file://programs/util/CMakeLists.txt#L1-L69) - -**Section sources** -- [CMakeLists.txt (build_helpers):1-8](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (util):1-69](file://programs/util/CMakeLists.txt#L1-L69) -- [building.md:183-220](file://documentation/building.md#L183-L220) - -## Core Components -- **install-deps-linux.sh**: New dependency installer script that installs all required system dependencies for VIZ C++ Node builds. Requires root privileges and supports both Ubuntu/Debian (apt-get) and Fedora/RHEL (dnf) package managers. -- **build-linux.sh**: Enhanced Linux build script that uses --clean option instead of --skip-deps, improving build system architecture and security practices by separating dependency management from the main build process. -- **build-mac.sh**: macOS build script that maintains the --skip-deps option for Homebrew dependency management. -- **cat-parts**: Concatenates hardfork fragment files (.hf) from a directory into a single output file, with up-to-date checks and minimal rebuild behavior. **Enhanced with proper algorithm header inclusion for compilation correctness**. -- **cat_parts.py**: Python counterpart to cat-parts with similar behavior and robustness for directory creation and file existence checks. -- **check_reflect.py**: Validates FC_REFLECT and FC_REFLECT_DERIVED declarations against Doxygen XML class member lists to ensure reflection parity. -- **newplugin.py**: Generates a complete plugin skeleton with standardized file structure and boilerplate code for a given provider and plugin name. -- **pretty_schema.py**: Queries a local debug node JSON-RPC endpoint to fetch and pretty-print the schema representation. -- **schema_test.cpp**: Demonstrates retrieving and printing schema information for specific chain objects using the schema API. -- **configure_build.py**: A helper to invoke cmake with sensible defaults and optional cross-compilation and external library flags. - -**Section sources** -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) -- [build-linux.sh:17-29](file://build-linux.sh#L17-L29) -- [build-mac.sh:15-26](file://build-mac.sh#L15-L26) -- [cat-parts.cpp:1-68](file://programs/build_helpers/cat-parts.cpp#L1-L68) -- [cat_parts.py:1-74](file://programs/build_helpers/cat_parts.py#L1-L74) -- [check_reflect.py:1-160](file://programs/build_helpers/check_reflect.py#L1-L160) -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) -- [pretty_schema.py:1-28](file://programs/util/pretty_schema.py#L1-L28) -- [schema_test.cpp:1-57](file://programs/util/schema_test.cpp#L1-L57) -- [configure_build.py:1-202](file://programs/build_helpers/configure_build.py#L1-L202) - -## Architecture Overview -The tools are designed to be invoked from the command line and integrated into higher-level build scripts or CI. They rely on: -- Standard filesystem operations for reading/writing files -- Regular expressions for parsing reflection declarations -- XML parsing for Doxygen-generated class member lists -- JSON-RPC calls for schema retrieval -- CMake targets for compilation and installation -- **New**: Separated dependency management system for improved security and maintainability - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Dep as "System Dependencies" -participant CMake as "CMake Targets" -participant Tool as "Build Helper Tool" -participant FS as "Filesystem" -Dev->>Dep : "Install system dependencies (root)" -Dep-->>Dev : "Dependencies ready" -Dev->>CMake : "Configure and build (regular user)" -CMake->>Tool : "Execute helper (e.g., cat_parts.py)" -Tool->>FS : "Read input directory and write output" -FS-->>Tool : "Success/Failure" -Tool-->>CMake : "Exit code" -CMake-->>Dev : "Build artifacts ready" -``` - -**Updated** Enhanced with new dependency management workflow that separates system-level operations from build operations. - -[No sources needed since this diagram shows conceptual workflow, not actual code structure] - -## Detailed Component Analysis - -### install-deps-linux.sh (New) -A comprehensive dependency installer script that manages all system-level dependencies required for VIZ C++ Node builds. This script separates dependency management from the main build process, improving security and maintainability. - -Key behaviors: -- Requires root privileges (sudo) for system-level package installation -- Supports Ubuntu/Debian systems using apt-get package manager -- Supports Fedora/RHEL systems using dnf package manager -- Installs essential build tools: cmake, git, ccache, build-essential -- Installs Boost libraries with comprehensive development headers -- Installs compression libraries: bzip2, lzma, zstd, zlib -- Installs SSL/TLS support and development tools -- Provides color-coded status messages and error handling -- Automatically detects package manager and installs appropriate dependencies - -```mermaid -flowchart TD -Start(["Start"]) --> RootCheck["Check for root privileges"] -RootCheck --> |No| Error["Print error and exit"] -RootCheck --> |Yes| Detect["Detect package manager"] -Detect --> |apt-get| Ubuntu["Install Ubuntu/Debian deps"] -Detect --> |dnf| Fedora["Install Fedora/RHEL deps"] -Detect --> |Other| Warn["Warn unsupported package manager"] -Ubuntu --> Success["Print success message"] -Fedora --> Success -Warn --> Exit["Exit with error"] -Error --> Exit -Success --> Next["Next step: ./build-linux.sh"] -``` - -**Diagram sources** -- [install-deps-linux.sh:28-106](file://install-deps-linux.sh#L28-L106) - -**Section sources** -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) - -### build-linux.sh (Enhanced) -Enhanced Linux build script that now uses --clean option instead of --skip-deps, reflecting the improved separation between dependency management and build processes. This change improves security by ensuring clean builds and better maintainability. - -Key behaviors: -- **Updated**: Uses --clean option for clean build directory management -- **Enhanced**: Improved argument parsing with comprehensive build options -- **Maintained**: Preserves all existing build configurations -- **Improved**: Better error handling and user feedback -- **Security**: Refuses to run as root (build must run as regular user) - -```mermaid -flowchart TD -Start(["Start"]) --> Parse["Parse CLI arguments"] -Parse --> Clean{"--clean option?"} -Clean --> |Yes| Remove["Remove existing build directory"] -Clean --> |No| Continue["Continue with existing build dir"] -Remove --> Continue -Continue --> Config["Configure with CMake"] -Config --> Build["Build with make"] -Build --> Install{"--install option?"} -Install --> |Yes| DoInstall["Run make install"] -Install --> |No| Skip["Skip installation"] -DoInstall --> Done(["Complete"]) -Skip --> Done -``` - -**Diagram sources** -- [build-linux.sh:63-98](file://build-linux.sh#L63-L98) -- [build-linux.sh:120-128](file://build-linux.sh#L120-L128) - -**Section sources** -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) - -### build-mac.sh (Maintained) -macOS build script that maintains the --skip-deps option for Homebrew dependency management. This preserves the existing workflow for macOS development environments. - -Key behaviors: -- **Maintained**: Uses --skip-deps option for Homebrew dependency management -- **Enhanced**: Improved Xcode Command Line Tools detection -- **Improved**: Better OpenSSL path detection and configuration -- **Preserved**: All existing build configurations and options - -**Section sources** -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) - -### cat-parts (C++) -Concatenates .hf files from a directory into a single output file, skipping non-.hf entries and sorting filenames numerically. It compares the generated content with existing output to avoid unnecessary writes. - -**Updated** Enhanced with proper algorithm header inclusion for improved compilation reliability across different environments. - -Key behaviors: -- Command-line arguments: input directory and output file path -- Filters files by extension and sorts them using std::sort -- Compares new content with existing output to skip redundant writes -- Uses Boost filesystem and streams - -```mermaid -flowchart TD -Start(["Start"]) --> Args["Validate CLI args"] -Args --> DirOK{"Input dir exists?"} -DirOK --> |No| ErrArgs["Print usage and exit"] -DirOK --> |Yes| Scan["Scan directory for .hf files"] -Scan --> Sort["Sort files by name
std::sort(v.begin(), v.end())"] -Sort --> Read["Read all files in order"] -Read --> Compare{"Output exists?"} -Compare --> |Yes| Exists["Compare content with new data"] -Exists --> |Same| UpToDate["Mark as up-to-date and exit"] -Exists --> |Different| Write["Write concatenated data"] -Compare --> |No| Write -Write --> Done(["Done"]) -UpToDate --> Done -ErrArgs --> Done -``` - -**Diagram sources** -- [cat-parts.cpp:7-68](file://programs/build_helpers/cat-parts.cpp#L7-L68) - -**Section sources** -- [cat-parts.cpp:1-68](file://programs/build_helpers/cat-parts.cpp#L1-L68) - -### cat_parts.py (Python) -A Python reimplementation of cat-parts with explicit checks for directory creation and file existence. It supports filtering by file suffix and writes the concatenated content to the output file. - -Key behaviors: -- Command-line arguments: input directory and output file path -- Creates parent directories if missing -- Reads and concatenates files in sorted order -- Skips writing if content is identical to existing output - -```mermaid -flowchart TD -Start(["Start"]) --> Parse["Parse CLI args"] -Parse --> Valid{"Valid input dir?"} -Valid --> |No| Usage["Print usage and exit"] -Valid --> |Yes| List["List files with suffix filter"] -List --> Sorted["Sort files"] -Sorted --> Read["Read file contents"] -Read --> Exists{"Output exists?"} -Exists --> |Yes| Same{"Content same?"} -Same --> |Yes| Skip["Skip write and exit"] -Same --> |No| Write["Write concatenated content"] -Exists --> |No| MkDir["Ensure parent dir exists"] -MkDir --> Write -Write --> Done(["Done"]) -Skip --> Done -Usage --> Done -``` - -**Diagram sources** -- [cat_parts.py:28-74](file://programs/build_helpers/cat_parts.py#L28-L74) - -**Section sources** -- [cat_parts.py:1-74](file://programs/build_helpers/cat_parts.py#L1-L74) - -### check_reflect.py (Python) -Validates that FC_REFLECT and FC_REFLECT_DERIVED declarations match Doxygen XML class member lists. It scans source files for reflection macros, parses Doxygen XML, and reports mismatches, duplicates, and missing items. - -Key behaviors: -- Parses Doxygen XML index.xml to extract class member lists -- Scans libraries/, programs/, tests/ for .cpp/.hpp files -- Extracts reflection declarations using regular expressions -- Compares member sets and prints categorized results -- Exits with success if no errors are found - -```mermaid -flowchart TD -Start(["Start"]) --> LoadXML["Load Doxygen XML index.xml"] -LoadXML --> ExtractDoxy["Extract class member lists"] -ExtractDoxy --> ScanSrc["Walk source directories for .cpp/.hpp"] -ScanSrc --> ParseReflect["Find FC_REFLECT(_DERIVED) declarations"] -ParseReflect --> Compare["Compare member sets"] -Compare --> Report["Report OK, Not Evaluated, Errors"] -Report --> ExitCode{"Any errors?"} -ExitCode --> |No| Success["Exit 0"] -ExitCode --> |Yes| Failure["Exit 1"] -``` - -**Diagram sources** -- [check_reflect.py:44-160](file://programs/build_helpers/check_reflect.py#L44-L160) - -**Section sources** -- [check_reflect.py:1-160](file://programs/build_helpers/check_reflect.py#L1-L160) - -### newplugin.py (Python) -Generates a complete plugin skeleton under libraries/plugins/ with standardized files and boilerplate. It supports templating for CMakeLists.txt, plugin headers, plugin implementation, API headers, and API implementation. - -Key behaviors: -- Command-line arguments: provider and plugin name -- Renders templates with placeholders -- Creates directories and writes files atomically -- Outputs generated file paths to console - -```mermaid -flowchart TD -Start(["Start"]) --> Args["Parse provider and plugin name"] -Args --> Render["Render templates with context"] -Render --> Mkdir["Ensure output directory exists"] -Mkdir --> Write["Write files to disk"] -Write --> Done(["Done"]) -``` - -**Diagram sources** -- [newplugin.py:225-247](file://programs/util/newplugin.py#L225-L247) - -**Section sources** -- [newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) - -### pretty_schema.py (Python) -Connects to a local debug node JSON-RPC endpoint to retrieve the schema, parses it, pretty-prints it, and handles embedded JSON strings. - -Key behaviors: -- Sends a JSON-RPC POST request to the debug node API -- Converts the returned string schema to JSON -- Pretty-prints the schema with indentation and sorted keys - -```mermaid -sequenceDiagram -participant Script as "pretty_schema.py" -participant RPC as "Local Debug Node" -Script->>RPC : "POST JSON-RPC call" -RPC-->>Script : "Schema JSON string" -Script->>Script : "Parse and pretty-print" -Script-->>Script : "Print formatted schema" -``` - -**Diagram sources** -- [pretty_schema.py:9-27](file://programs/util/pretty_schema.py#L9-L27) - -**Section sources** -- [pretty_schema.py:1-28](file://programs/util/pretty_schema.py#L1-L28) - -### schema_test.cpp (C++) -Demonstrates retrieving and printing schema information for specific chain objects. It uses the schema API to gather dependent schemas and prints names, dependencies, and serialized schema strings. - -Key behaviors: -- Includes schema headers and chain objects -- Defines a test struct with FC_REFLECT -- Retrieves schemas for chain objects and dependent schemas -- Prints schema metadata to stdout - -```mermaid -flowchart TD -Start(["Start"]) --> Include["Include schema headers"] -Include --> Define["Define test struct with FC_REFLECT"] -Define --> GetSchemas["Get schemas for chain objects"] -GetSchemas --> Deps["Add dependent schemas"] -Deps --> Print["Iterate and print schema info"] -Print --> End(["End"]) -``` - -**Diagram sources** -- [schema_test.cpp:15-56](file://programs/util/schema_test.cpp#L15-L56) - -**Section sources** -- [schema_test.cpp:1-57](file://programs/util/schema_test.cpp#L1-L57) - -### configure_build.py (Python) -A helper to invoke cmake with sensible defaults and optional flags for cross-compilation and external libraries. It supports environment variables for locating Boost and OpenSSL, and passes through additional cmake options. - -Key behaviors: -- Parses command-line arguments with mutually exclusive groups -- Resolves environment variables for SYS_ROOT, BOOST_ROOT, OPENSSL_ROOT_DIR -- Detects Boost version and adds appropriate flags -- Supports Windows cross-compilation with MinGW -- Builds and executes cmake with collected options - -```mermaid -flowchart TD -Start(["Start"]) --> Parse["Parse CLI args and env vars"] -Parse --> Boost{"Boost dir provided?"} -Boost --> |Yes| Ver["Detect Boost version"] -Ver --> Flags["Add Boost/OpenSSL flags"] -Boost --> |No| Flags -Flags --> Win{"Windows cross-compile?"} -Win --> |Yes| Mingw["Add MinGW flags"] -Win --> |No| Cfg["Set LOW_MEMORY_NODE and BUILD_TYPE"] -Mingw --> Cfg -Cfg --> RootPath["Assemble root search paths"] -RootPath --> Exec["Execute cmake with options"] -Exec --> Done(["Done"]) -``` - -**Diagram sources** -- [configure_build.py:143-196](file://programs/build_helpers/configure_build.py#L143-L196) - -**Section sources** -- [configure_build.py:1-202](file://programs/build_helpers/configure_build.py#L1-L202) - -## Dependency Analysis -The build helper tools depend on standard libraries and external systems: -- **install-deps-linux.sh**: Depends on system package managers (apt-get/dnf) and root privileges -- **build-linux.sh**: Depends on CMake, make, and system-level build tools -- **build-mac.sh**: Depends on Homebrew, Xcode Command Line Tools, and macOS-specific tools -- cat-parts and cat_parts.py depend on filesystem semantics and sorting -- check_reflect.py depends on Doxygen XML and regular expressions -- newplugin.py depends on Python's string templating and filesystem operations -- pretty_schema.py depends on a running debug node and JSON-RPC -- schema_test.cpp depends on schema headers and chain objects -- configure_build.py depends on cmake, environment variables, and optional toolchains - -```mermaid -graph LR -IDL["install-deps-linux.sh
✓ New"] --> SYS["System Package Managers"] -BL["build-linux.sh
✓ Enhanced"] --> CMAKE["CMake"] -BM["build-mac.sh
✓ Maintained"] --> HB["Homebrew"] -CP["cat-parts.cpp
✓ Algorithm Header"] --> FS["Boost Filesystem"] -CPY["cat_parts.py"] --> PY["Python Pathlib"] -CR["check_reflect.py"] --> RX["Regex"] -CR --> XML["xml.etree.ElementTree"] -NP["newplugin.py"] --> PY -PS["pretty_schema.py"] --> REQ["requests"] -ST["schema_test.cpp"] --> SCH["graphene/db/schema"] -CFG["configure_build.py"] --> CMK["cmake"] -CFG --> ENV["Environment Variables"] -``` - -**Diagram sources** -- [install-deps-linux.sh:34-106](file://install-deps-linux.sh#L34-L106) -- [build-linux.sh:155-165](file://build-linux.sh#L155-L165) -- [build-mac.sh:126-171](file://build-mac.sh#L126-L171) -- [cat-parts.cpp:1-6](file://programs/build_helpers/cat-parts.cpp#L1-L6) -- [cat_parts.py:3-4](file://programs/build_helpers/cat_parts.py#L3-L4) -- [check_reflect.py:3-6](file://programs/build_helpers/check_reflect.py#L3-L6) -- [newplugin.py:1-2](file://programs/util/newplugin.py#L1-L2) -- [pretty_schema.py:3-5](file://programs/util/pretty_schema.py#L3-L5) -- [schema_test.cpp:1-3](file://programs/util/schema_test.cpp#L1-L3) -- [configure_build.py:3-6](file://programs/build_helpers/configure_build.py#L3-L6) - -**Section sources** -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) -- [cat-parts.cpp:1-6](file://programs/build_helpers/cat-parts.cpp#L1-L6) -- [cat_parts.py:3-4](file://programs/build_helpers/cat_parts.py#L3-L4) -- [check_reflect.py:3-6](file://programs/build_helpers/check_reflect.py#L3-L6) -- [newplugin.py:1-2](file://programs/util/newplugin.py#L1-L2) -- [pretty_schema.py:3-5](file://programs/util/pretty_schema.py#L3-L5) -- [schema_test.cpp:1-3](file://programs/util/schema_test.cpp#L1-L3) -- [configure_build.py:3-6](file://programs/build_helpers/configure_build.py#L3-L6) - -## Performance Considerations -- **install-deps-linux.sh**: Package installation performance varies by distribution and network connectivity; consider caching and offline installation for CI environments -- **build-linux.sh**: Enhanced with --clean option for guaranteed clean builds, which may take longer but ensures reproducibility -- **build-mac.sh**: Maintains --skip-deps option for efficient Homebrew dependency management -- cat-parts and cat_parts.py: Sorting and reading many small .hf files is efficient; the up-to-date check avoids unnecessary writes -- check_reflect.py: Walking source trees and parsing XML can be slow on large projects; restrict scanning to necessary directories if needed -- pretty_schema.py: Network latency to the debug node can dominate; cache results locally if regenerating frequently -- schema_test.cpp: Schema traversal is lightweight for a small set of types; adding many types increases runtime linearly -- configure_build.py: cmake invocation overhead is minimal compared to the build itself; passing additional flags can increase configuration time slightly - -[No sources needed since this section provides general guidance] - -## Compilation Correctness and Best Practices - -### Header Management Standards -The cat-parts utility demonstrates proper C++ header management practices that enhance compilation reliability: - -**Algorithm Header Inclusion** -- The `` header is properly included to support std::sort operations -- This prevents compilation issues across different compiler environments -- Ensures consistent behavior regardless of platform-specific header implementations - -**Best Practices for Header Management** -- Always include headers for functions you use (std::sort requires ) -- Place standard library headers before third-party headers -- Keep header includes minimal and specific -- Consider header ordering for compilation speed and predictability - -**Cross-Platform Compatibility** -- Proper header inclusion prevents environment-specific compilation failures -- Reduces reliance on implicit declarations that vary between compilers -- Enhances portability across different development environments - -**Section sources** -- [cat-parts.cpp:4-33](file://programs/build_helpers/cat-parts.cpp#L4-L33) - -## Security and Build System Architecture - -### Enhanced Build System Security -The new dependency installer script and improved build architecture significantly enhance security practices: - -**Separation of Privileges** -- System-level dependency installation requires root privileges (sudo) -- Main build process runs as regular user for security isolation -- Prevents privilege escalation during build operations - -**Clean Build Architecture** -- The --clean option ensures fresh build directories are created -- Eliminates potential contamination from previous builds -- Improves reproducibility and debugging capabilities - -**Improved Error Handling** -- Comprehensive error checking and user feedback -- Clear separation between dependency management and build processes -- Better logging and diagnostic information - -**Section sources** -- [install-deps-linux.sh:28-31](file://install-deps-linux.sh#L28-L31) -- [build-linux.sh:57-61](file://build-linux.sh#L57-L61) -- [build-linux.sh:83-84](file://build-linux.sh#L83-L84) - -## Troubleshooting Guide -Common issues and resolutions: -- **install-deps-linux.sh** - - Symptom: Permission denied error - - Resolution: Run with sudo privileges as required by the script - - Symptom: Unsupported package manager detected - - Resolution: Install dependencies manually or use supported distributions -- **build-linux.sh** - - Symptom: Cannot run as root - - Resolution: Install dependencies first with sudo ./install-deps-linux.sh, then run build as regular user - - Symptom: Clean build takes too long - - Resolution: Use --clean option for guaranteed clean builds; consider incremental builds for development - - Symptom: Build fails due to missing dependencies - - Resolution: Re-run dependency installer or install missing packages manually -- **build-mac.sh** - - Symptom: Xcode Command Line Tools not found - - Resolution: Install Xcode Command Line Tools using xcode-select --install - - Symptom: Homebrew not detected - - Resolution: Install Homebrew from https://brew.sh/ and ensure it's in PATH - - Symptom: --skip-deps option not working - - Resolution: This option is maintained for macOS compatibility; use --skip-deps to skip Homebrew installation -- **cat-parts/cat_parts.py** - - Symptom: Incorrect number of arguments or invalid directory. - - Resolution: Ensure two arguments are provided: input directory and output file. Verify the directory exists and is readable. - - Symptom: Output not written despite changes. - - Resolution: Confirm that the concatenated content differs from the existing output; otherwise, the tool considers it up-to-date. -- **check_reflect.py** - - Symptom: No Doxygen XML found. - - Resolution: Run doxygen to generate XML before invoking the tool. - - Symptom: Reflection mismatch reported. - - Resolution: Align FC_REFLECT declarations with actual class members; remove duplicates and ensure completeness. -- **newplugin.py** - - Symptom: Permission denied when writing files. - - Resolution: Ensure the destination directory is writable; run with appropriate privileges. - - Symptom: Generated files not linked into the build. - - Resolution: Add the plugin's CMakeLists.txt to the parent CMakeLists.txt and ensure target_link_libraries includes required libraries. -- **pretty_schema.py** - - Symptom: Connection refused or timeout. - - Resolution: Start the debug node and ensure the JSON-RPC endpoint is reachable on the configured address. -- **schema_test.cpp** - - Symptom: Link errors for schema headers. - - Resolution: Ensure the schema headers are available and the target links against graphene_chain and fc. -- **configure_build.py** - - Symptom: cmake cannot find Boost or OpenSSL. - - Resolution: Set BOOST_ROOT and OPENSSL_ROOT_DIR environment variables or pass --boost-dir and --openssl-dir. - - Symptom: Cross-compilation fails. - - Resolution: Ensure MinGW toolchain is installed and CMAKE_FIND_ROOT_PATH_MODE settings are correct. - -**Section sources** -- [install-deps-linux.sh:28-31](file://install-deps-linux.sh#L28-L31) -- [build-linux.sh:57-61](file://build-linux.sh#L57-L61) -- [build-linux.sh:83-84](file://build-linux.sh#L83-L84) -- [build-mac.sh:108-114](file://build-mac.sh#L108-L114) -- [build-mac.sh:118-122](file://build-mac.sh#L118-L122) -- [build-mac.sh:71-72](file://build-mac.sh#L71-L72) -- [cat-parts.cpp:8-11](file://programs/build_helpers/cat-parts.cpp#L8-L11) -- [cat_parts.py:29-36](file://programs/build_helpers/cat_parts.py#L29-L36) -- [check_reflect.py:44-49](file://programs/build_helpers/check_reflect.py#L44-L49) -- [newplugin.py:236-244](file://programs/util/newplugin.py#L236-L244) -- [pretty_schema.py:9-12](file://programs/util/pretty_schema.py#L9-L12) -- [schema_test.cpp:1-3](file://programs/util/schema_test.cpp#L1-L3) -- [configure_build.py:114-118](file://programs/build_helpers/configure_build.py#L114-L118) - -## Conclusion -These build helper tools automate repetitive tasks, enforce consistency, and integrate cleanly with the CMake-based build system. The recent enhancements, particularly the addition of the install-deps-linux.sh dependency installer script and the improved build architecture with --clean option, demonstrate best practices for C++ development that enhance security, maintainability, and reproducibility. The separation of dependency management from the main build process provides better security isolation and cleaner build environments. By following the documented usage patterns and best practices, developers can maintain organized codebases, validate reflection integrity, scaffold plugins efficiently, and inspect schemas reliably while benefiting from improved security and build system architecture. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples - -- **Install system dependencies (Linux)** - - Use install-deps-linux.sh to install all required system dependencies with root privileges - - Example command: sudo ./install-deps-linux.sh - -- **Build VIZ node (Linux)** - - Use build-linux.sh to configure and build the VIZ node after dependencies are installed - - Example command: ./build-linux.sh --clean --install - - Note: Must run as regular user (not root) - -- **Build VIZ node (macOS)** - - Use build-mac.sh to configure and build the VIZ node with Homebrew dependencies - - Example command: ./build-mac.sh --skip-deps --install - -- Assemble hardfork fragments - - Use cat_parts.py to concatenate .hf files from a directory into a single output file. The tool ensures the output is only rewritten when content changes. - - Example command: python3 programs/build_helpers/cat_parts.py libraries/chain/hardfork.d build/hardforks.inc - -- Validate reflection declarations - - Run check_reflect.py after generating Doxygen XML to compare FC_REFLECT declarations with class members. Fix reported mismatches and duplicates. - - Example command: python3 programs/build_helpers/check_reflect.py - -- Scaffold a new plugin - - Use newplugin.py to generate a plugin skeleton under libraries/plugins/. Customize the generated files and integrate with CMake. - - Example command: python3 programs/util/newplugin.py viz myplugin - -- Pretty-print schema - - Use pretty_schema.py to fetch and format the schema from a running debug node. Pipe to a file for inspection. - - Example command: python3 programs/util/pretty_schema.py > schema.json - -- Test schema retrieval - - Build and run schema_test.cpp to print schema information for specific chain objects. Useful for debugging schema-related issues. - - Example command: make schema_test && ./bin/schema_test - -- Configure and build - - Use configure_build.py to invoke cmake with sensible defaults and optional flags for cross-compilation and external libraries. - - Example command: python3 programs/build_helpers/configure_build.py --boost-dir /opt/boost --openssl-dir /opt/openssl - -**Section sources** -- [install-deps-linux.sh:8-9](file://install-deps-linux.sh#L8-L9) -- [build-linux.sh:14-15](file://build-linux.sh#L14-L15) -- [build-linux.sh:204](file://build-linux.sh#L204) -- [build-mac.sh:12-13](file://build-mac.sh#L12-L13) -- [build-mac.sh:349](file://build-mac.sh#L349) -- [cat_parts.py:28-69](file://programs/build_helpers/cat_parts.py#L28-L69) -- [check_reflect.py:153-160](file://programs/build_helpers/check_reflect.py#L153-L160) -- [newplugin.py:225-247](file://programs/util/newplugin.py#L225-L247) -- [pretty_schema.py:9-27](file://programs/util/pretty_schema.py#L9-L27) -- [schema_test.cpp:44-56](file://programs/util/schema_test.cpp#L44-L56) -- [configure_build.py:143-196](file://programs/build_helpers/configure_build.py#L143-L196) - -### Integration with Main Build Process -- **CMake targets** - - cat-parts is built as an executable and linked against fc and platform libs. Use it in custom targets or prebuild steps. - - Utilities like pretty_schema.py and schema_test.cpp are standalone scripts/executables; integrate them into CI or developer workflows as needed. -- **Build options** - - Refer to documentation/building.md for CMAKE_BUILD_TYPE and LOW_MEMORY_NODE options. configure_build.py sets these defaults and forwards additional cmake options. -- **New dependency management** - - The install-deps-linux.sh script is designed to be run separately from the main build process - - Dependencies are installed once (per system) and cached for subsequent builds - - Build scripts automatically detect and use installed dependencies - -**Section sources** -- [CMakeLists.txt (build_helpers):1-8](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (util):46-56](file://programs/util/CMakeLists.txt#L46-L56) -- [building.md:189-220](file://documentation/building.md#L189-L220) -- [README.md:7-10](file://README.md#L7-L10) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Code Assembly Tools.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Code Assembly Tools.md deleted file mode 100644 index 9e8df50c4c..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Code Assembly Tools.md +++ /dev/null @@ -1,390 +0,0 @@ -# Code Assembly Tools - - -**Referenced Files in This Document** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt) -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf) -- [1.hf](file://libraries/chain/hardfork.d/1.hf) -- [2.hf](file://libraries/chain/hardfork.d/2.hf) -- [3.hf](file://libraries/chain/hardfork.d/3.hf) -- [configure_build.py](file://programs/build_helpers/configure_build.py) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the code assembly tools used by the VIZ C++ Node build pipeline. It focuses on: -- The C++ utility cat-parts.cpp for assembling hardfork header files from a directory of fragments. -- The Python counterpart cat_parts.py for similar automation, including change detection and output directory creation. -- The integration of these tools into the CMake build system via custom targets. -- Practical usage scenarios for schema assembly and automated builds. -- Command-line options, input validation, error handling, and troubleshooting guidance. - -## Project Structure -The code assembly tools live under programs/build_helpers and are consumed by the libraries/chain module, which organizes hardfork-related fragments in a dedicated directory. - -```mermaid -graph TB -subgraph "Build Helpers" -CP["programs/build_helpers/cat-parts.cpp"] -PY["programs/build_helpers/cat_parts.py"] -CH["programs/build_helpers/CMakeLists.txt"] -end -subgraph "Chain Module" -HFDIR["libraries/chain/hardfork.d/"] -HFBASE["libraries/chain/include/graphene/chain/hardfork.hpp"] -LCCMAKE["libraries/chain/CMakeLists.txt"] -end -CP --> LCCMAKE -PY --> LCCMAKE -HFDIR --> CP -HFDIR --> PY -LCCMAKE --> HFBASE -``` - -**Diagram sources** -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L1-L68) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L1-L74) - -**Section sources** -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) - -## Core Components -- cat-parts.cpp: A C++ program that scans a directory for files ending with .hf, sorts them, concatenates their contents, and writes the result to an output file. It compares the new content with the existing output file and exits early if unchanged. -- cat_parts.py: A Python script that performs equivalent logic with explicit input validation, output directory creation, and change detection. -- CMake integration: Custom targets generate the hardfork.hpp file from hardfork.d fragments during the build. - -Key behaviors: -- Directory scanning: Filters entries by extension and constructs a sorted list of fragment files. -- Concatenation: Reads each file and appends its content to a buffer. -- Change detection: Compares the computed content with the existing output file; if equal, skips writing. -- Output: Writes the assembled content to the target file. - -**Section sources** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L7-L68) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L11-L69) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) - -## Architecture Overview -The build system orchestrates code assembly through CMake custom targets. On Unix-like systems, the Python script is invoked; on Windows, the native C++ utility is used. Both produce the same output file from the same input directory of fragments. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant CMake as "CMake" -participant Py as "cat_parts.py" -participant Cpp as "cat-parts.cpp" -participant HFDir as "hardfork.d/" -participant Out as "hardfork.hpp" -Dev->>CMake : Configure and generate -CMake->>CMake : add_custom_target(build_hardfork_hpp) -alt UNIX (non-Windows) -CMake->>Py : Run with (HFDir, Out) -Py->>HFDir : List and read .hf files -Py->>Py : Sort filenames -Py->>Out : Write assembled content (if changed) -else MSVC (Windows) -CMake->>Cpp : Run with (HFDir, Out) -Cpp->>HFDir : Scan .hf files -Cpp->>Cpp : Sort paths -Cpp->>Out : Write assembled content (if changed) -end -CMake-->>Dev : Build target ready -``` - -**Diagram sources** -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L9) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L28-L69) -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L15-L66) - -## Detailed Component Analysis - -### cat-parts.cpp -Purpose: -- Assemble hardfork fragments into a single header file. -- Provide change detection to avoid unnecessary rebuilds. - -Command-line syntax: -- Syntax: cat-parts DIR OUTFILE -- Exits with non-zero status on invalid arguments or filesystem errors. - -Directory scanning logic: -- Iterates over directory entries. -- Filters entries whose names end with ".hf". -- Collects matching paths into a vector. - -Sorting algorithm: -- Sorts collected paths lexicographically. - -Concatenation process: -- Opens each file and appends its content to a string buffer. -- Writes the buffer to the output file if it differs from the existing content. - -Change detection: -- Reads the existing output file into memory. -- Compares the computed content with the existing content. -- Prints a message and exits early if identical. - -Error handling: -- Catches filesystem errors and prints diagnostic messages. -- Returns non-zero status on failure. - -```mermaid -flowchart TD -Start(["Start main(argc, argv)"]) -CheckArgs["Validate argument count"] -ArgsOK{"argc == 3?"} -MakePath["Create path from argv[1]"] -Iterate["Iterate directory entries"] -Filter["Filter entries ending with '.hf'"] -Collect["Collect matching paths"] -Sort["Sort paths"] -ReadAll["Read all files and concatenate"] -ComputeNew["Compute new content"] -Exists{"Output exists?"} -ReadOld["Read existing output"] -Compare{"Content equals?"} -UpToDate["Print 'up-to-date' and exit"] -Write["Write new content to output"] -Done(["Exit 0"]) -Start --> CheckArgs --> ArgsOK -ArgsOK --> |No| ExitErr["Exit 1"] -ArgsOK --> |Yes| MakePath --> Iterate --> Filter --> Collect --> Sort --> ReadAll --> ComputeNew --> Exists -Exists --> |No| Write --> Done -Exists --> |Yes| ReadOld --> Compare -Compare --> |Yes| UpToDate --> Done -Compare --> |No| Write --> Done -``` - -**Diagram sources** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L7-L68) - -**Section sources** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L7-L68) - -### cat_parts.py -Purpose: -- Provide a portable, Python-based alternative to cat-parts.cpp. -- Offer robust input validation and automatic output directory creation. - -Command-line syntax: -- Syntax: cat_parts.py DIR OUTFILE -- Prints usage and exits with non-zero status if arguments are missing or invalid. - -Input validation: -- Validates that the input directory exists and is a directory. -- Ensures the output path is a file (not a directory) when it exists. - -Change detection: -- Reads the existing output file and compares it with newly computed content. -- Skips writing if contents match. - -Output directory creation: -- Creates parent directories recursively if they do not exist. -- Handles common exceptions during directory creation. - -```mermaid -flowchart TD -Start(["Start main(program_name, args)"]) -ArgsLen["Check number of arguments"] -Usage["Print usage and exit"] -ParseDir["Parse input directory"] -DirValid{"Is directory?"} -ParseOut["Parse output file path"] -OutExists{"Does output exist?"} -ReadExisting["Read existing content"] -Compare{"Content equals?"} -UpToDate["Print 'up-to-date' and exit"] -EnsureDir["Ensure parent directory exists"] -Compute["Compute concatenated content"] -Write["Write content to output"] -Exit(["Exit 0"]) -Start --> ArgsLen --> ArgsLenOK{">= 2?"} -ArgsLenOK --> |No| Usage -ArgsLenOK --> |Yes| ParseDir --> DirValid -DirValid --> |No| Usage -DirValid --> |Yes| ParseOut --> OutExists -OutExists --> |Yes| ReadExisting --> Compare -Compare --> |Yes| UpToDate -Compare --> |No| EnsureDir --> Compute --> Write --> Exit -OutExists --> |No| EnsureDir --> Compute --> Write --> Exit -``` - -**Diagram sources** -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L28-L69) - -**Section sources** -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L1-L74) - -### CMake Integration -- Adds a custom target that generates hardfork.hpp from hardfork.d. -- Uses cat-parts.cpp on Windows and cat_parts.py on UNIX-like systems. -- Marks the generated file as GENERATED for proper build semantics. -- Adds a dependency so the chain library links against the generated header. - -```mermaid -graph LR -CMake["libraries/chain/CMakeLists.txt"] -Target["add_custom_target(build_hardfork_hpp)"] -Py["cat_parts.py"] -Cpp["cat-parts.cpp"] -HFDir["hardfork.d/"] -Out["hardfork.hpp"] -CMake --> Target -Target --> |Windows| Cpp -Target --> |UNIX| Py -Cpp --> HFDir -Py --> HFDir -HFDir --> Out -Target --> Out -``` - -**Diagram sources** -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) - -**Section sources** -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) - -### Hardfork Directory Processing Mechanism -- Fragment files are named with .hf extension and placed under hardfork.d. -- The assembly tools sort these files lexicographically to define the order of inclusion. -- Example fragments include preamble definitions and version/time constants for specific hardforks. - -```mermaid -graph TB -HFDir["hardfork.d/"] -F0["0-preamble.hf"] -F1["1.hf"] -F2["2.hf"] -F3["3.hf"] -Fragments["Fragments (sorted)"] -Out["hardfork.hpp"] -HFDir --> F0 -HFDir --> F1 -HFDir --> F2 -HFDir --> F3 -F0 --> Fragments -F1 --> Fragments -F2 --> Fragments -F3 --> Fragments -Fragments --> Out -``` - -**Diagram sources** -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf#L1-L56) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [2.hf](file://libraries/chain/hardfork.d/2.hf#L1-L7) -- [3.hf](file://libraries/chain/hardfork.d/3.hf#L1-L7) - -**Section sources** -- [0-preamble.hf](file://libraries/chain/hardfork.d/0-preamble.hf#L1-L56) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) -- [2.hf](file://libraries/chain/hardfork.d/2.hf#L1-L7) -- [3.hf](file://libraries/chain/hardfork.d/3.hf#L1-L7) - -## Dependency Analysis -- cat-parts.cpp depends on Boost.Filesystem for directory traversal and file I/O. -- cat_parts.py uses pathlib for path manipulation and file I/O. -- The CMake build integrates both tools into the chain library build process. -- Additional build helpers exist for reflection checks and build configuration, complementing the assembly workflow. - -```mermaid -graph TB -CP["cat-parts.cpp"] -PY["cat_parts.py"] -CH["CMakeLists.txt (build helpers)"] -LC["CMakeLists.txt (libraries/chain)"] -CR["check_reflect.py"] -CB["configure_build.py"] -CP --> CH -PY --> LC -LC --> CP -LC --> PY -CR --> LC -CB --> LC -``` - -**Diagram sources** -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) -- [configure_build.py](file://programs/build_helpers/configure_build.py#L1-L202) - -**Section sources** -- [CMakeLists.txt (build helpers)](file://programs/build_helpers/CMakeLists.txt#L1-L8) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L12) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) -- [configure_build.py](file://programs/build_helpers/configure_build.py#L1-L202) - -## Performance Considerations -- Sorting cost: Lexicographic sorting of fragment paths is O(n log n); acceptable for small to moderate numbers of fragments typical in hardfork.d. -- I/O cost: Reading all fragments and writing the output is linear in total content size; efficient for typical hardfork fragment sizes. -- Change detection avoids unnecessary writes and rebuilds, reducing downstream compilation work. -- Using the native C++ tool on Windows and Python tool on UNIX leverages platform-specific strengths. - -## Troubleshooting Guide -Common issues and resolutions: -- Incorrect command syntax: - - Ensure the utility receives exactly two arguments: the input directory and the output file path. -- Input directory does not exist or is not a directory: - - Verify the path to hardfork.d and permissions to read it. -- Output path is not a file: - - Ensure the output path points to a regular file; the Python tool validates this and exits with an error if not. -- Output directory creation fails: - - The Python tool attempts to create parent directories; check write permissions for the parent directory. -- Filesystem errors: - - The C++ tool catches filesystem errors and prints diagnostics; review stderr output for details. -- Permission problems: - - Ensure read access to all .hf files and write access to the output file’s directory. -- Fragment ordering concerns: - - Confirm lexicographic sorting matches intended order; rename files if necessary to achieve desired sequence. - -Integration tips: -- On Windows, the CMake target invokes the C++ utility; on UNIX-like systems, the Python script is used. -- The generated header is marked as GENERATED and included in the chain library build. - -**Section sources** -- [cat-parts.cpp](file://programs/build_helpers/cat-parts.cpp#L8-L11) -- [cat_parts.py](file://programs/build_helpers/cat_parts.py#L28-L43) -- [CMakeLists.txt (libraries/chain)](file://libraries/chain/CMakeLists.txt#L1-L9) - -## Conclusion -The VIZ C++ Node code assembly tools provide a reliable, cross-platform mechanism to generate hardfork.hpp from a collection of .hf fragments. The C++ and Python utilities implement consistent logic with change detection and robust error handling, while CMake integrates them seamlessly into the build pipeline. These tools enable maintainable schema assembly and automated build processes for the chain module. - -## Appendices - -### Practical Examples -- Generating hardfork.hpp from hardfork.d: - - Windows: cat-parts hardfork.d hardfork.hpp - - UNIX-like: python3 cat_parts.py hardfork.d hardfork.hpp -- Automated build integration: - - CMake adds a custom target that runs the appropriate tool and produces hardfork.hpp. -- Schema assembly: - - Place preprocessor definitions and version/time constants in .hf files within hardfork.d; the tools will assemble them in lexicographic order. - -### Related Build Helpers -- Reflection validation: check_reflect.py compares Doxygen-derived member lists with FC_REFLECT declarations to detect mismatches. -- Build configuration: configure_build.py helps set up CMake with optional flags and environment-driven paths. - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) -- [configure_build.py](file://programs/build_helpers/configure_build.py#L1-L202) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Plugin Development Tools.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Plugin Development Tools.md deleted file mode 100644 index f586942b0f..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Plugin Development Tools.md +++ /dev/null @@ -1,340 +0,0 @@ -# Plugin Development Tools - - -**Referenced Files in This Document** -- [newplugin.py](file://programs/util/newplugin.py) -- [plugin.md](file://documentation/plugin.md) -- [building.md](file://documentation/building.md) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt) -- [CMakeLists.txt (main)](file://CMakeLists.txt) -- [account_by_key_plugin.cpp](file://plugins/account_by_key/plugin.cpp) -- [account_by_key_plugin.hpp](file://plugins/account_by_key/include/graphene/plugins/account_by_key/account_by_key_plugin.hpp) -- [account_by_key_objects.hpp](file://plugins/account_by_key/include/graphene/plugins/account_by_key/account_by_key_objects.hpp) -- [chain_plugin.cpp](file://plugins/chain/plugin.cpp) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the VIZ CPP Node plugin development tool and the template system used to generate custom plugin boilerplate code. It covers the directory structure generation, header and implementation skeleton templates, plugin naming conventions, file organization patterns, and integration requirements into the main application. It also provides step-by-step examples for creating new plugins, modifying generated code, and integrating plugins into the application, along with command-line options, customization parameters, best practices, common pitfalls, testing strategies, and deployment considerations. - -## Project Structure -The plugin development workflow centers around a Python script that generates a standardized plugin skeleton under the libraries/plugins directory. The generated plugin integrates with the application via CMake discovery and registration mechanisms. - -```mermaid -graph TB -subgraph "Tooling" -NP["programs/util/newplugin.py"] -end -subgraph "Generated Plugin Skeleton" -OUTDIR["libraries/plugins//"] -INC["include/graphene/plugins//"] -SRC["_plugin.cpp"] -API["_api.cpp"] -HP["_plugin.hpp"] -AP["_api.hpp"] -CL["CMakeLists.txt"] -end -subgraph "Application Build" -PCML["plugins/CMakeLists.txt"] -MCML["CMakeLists.txt"] -end -NP --> OUTDIR -OUTDIR --> INC -OUTDIR --> SRC -OUTDIR --> API -OUTDIR --> HP -OUTDIR --> AP -OUTDIR --> CL -PCML --> MCML -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L236-L246) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) -- [CMakeLists.txt (main)](file://CMakeLists.txt#L210-L213) - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [plugin.md](file://documentation/plugin.md#L1-L28) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) -- [CMakeLists.txt (main)](file://CMakeLists.txt#L210-L213) - -## Core Components -- Template engine: A dictionary of file templates keyed by destination paths. Each template contains placeholders for provider and plugin name. -- CLI interface: Accepts provider and plugin name arguments to drive template instantiation. -- Directory generation: Creates include directories and writes all generated files into a new plugin folder under libraries/plugins/. -- Integration hooks: Generated CMakeLists.txt links against core libraries and registers the plugin via a macro. - -Key behaviors: -- Provider naming convention: The provider is a namespace identifier (e.g., viz) used to prefix namespaces and plugin factories. -- Plugin naming convention: The plugin name becomes part of the namespace and filenames. -- Generated files: Header and implementation files for plugin and API classes, plus a CMakeLists.txt tailored for linking and inclusion. - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L3-L218) -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) - -## Architecture Overview -The plugin generation tool produces a complete, buildable skeleton that integrates with the application’s CMake-based plugin discovery and registration system. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Tool as "newplugin.py" -participant FS as "Filesystem" -participant CMake as "CMake Discovery" -participant App as "Application" -Dev->>Tool : Run with provider and plugin_name -Tool->>FS : Create include/graphene/plugins// -Tool->>FS : Write _plugin.cpp, _api.cpp,
_plugin.hpp, _api.hpp, CMakeLists.txt -FS-->>Tool : Files written -Tool-->>Dev : Skeleton ready in libraries/plugins/ -Dev->>CMake : Build application -CMake->>CMake : Discover plugins via plugins/CMakeLists.txt -CMake->>App : Register plugin factory and link libraries -App-->>Dev : Plugin available at runtime -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) -- [CMakeLists.txt (main)](file://CMakeLists.txt#L210-L213) - -## Detailed Component Analysis - -### Template System and File Generation -The template system defines: -- CMakeLists.txt: Adds the library, links against core libraries, and sets include directories. -- Plugin header: Declares the plugin class inheriting from the framework’s plugin base. -- Plugin implementation: Implements lifecycle methods and connects to the chain database. -- API header: Declares the API class and FC_API method list. -- API implementation: Provides API factory registration and helper accessors. - -```mermaid -flowchart TD -Start(["Run newplugin.py"]) --> ParseArgs["Parse provider and plugin_name"] -ParseArgs --> BuildCtx["Build context dict"] -BuildCtx --> OutDir["Compute output directory
libraries/plugins/"] -OutDir --> IterateTemplates["Iterate templates"] -IterateTemplates --> FormatContent["Format template with context"] -FormatContent --> MakeDirs["Ensure include directory exists"] -MakeDirs --> WriteFiles["Write files to disk"] -WriteFiles --> Done(["Skeleton ready"]) -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L3-L218) -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) - -### Plugin Naming Conventions and File Organization -- Provider: Used as a namespace prefix for plugin and API classes. -- Plugin Name: Used as the base for class names, filenames, and CMake target names. -- Include Path Pattern: include/graphene/plugins//_*.hpp -- Implementation Files: _plugin.cpp and _api.cpp -- CMake Target: {provider}_{plugin_name} - -Best practices: -- Choose a concise, lowercase provider name. -- Use a descriptive, lowercase plugin name. -- Keep include paths aligned with the pattern to ensure CMake discovery works correctly. - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L3-L218) - -### Integration Requirements -- CMake Discovery: The plugins root CMakeLists.txt scans subdirectories and adds discovered plugin directories to a list used by the application. -- Link Libraries: Generated CMakeLists.txt links against core libraries (application, chain, protocol). -- Registration Macro: The plugin implementation uses a macro to register the plugin factory with the application. - -```mermaid -graph LR -PRoot["plugins/CMakeLists.txt"] --> PSub["/CMakeLists.txt"] -PSub --> Lib["{provider}_{plugin_name} library"] -Lib --> App["Application loads plugin"] -``` - -**Diagram sources** -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) -- [newplugin.py](file://programs/util/newplugin.py#L4-L16) - -**Section sources** -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) -- [newplugin.py](file://programs/util/newplugin.py#L4-L16) - -### Step-by-Step Example: Creating a New Plugin -- Prepare: Ensure the environment supports building the project. -- Generate: Run the tool with provider and plugin name to scaffold the plugin. -- Review: Confirm include paths, class names, and CMake target names match expectations. -- Customize: Implement plugin initialization, API methods, and database connections. -- Build: Configure and build the application; the plugin is discovered and linked automatically. -- Enable: Configure the application to enable the plugin and any required dependencies. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Tool as "newplugin.py" -participant Cfg as "Application Config" -participant Build as "CMake/Build" -participant App as "Application" -Dev->>Tool : Execute with provider and plugin_name -Tool-->>Dev : Generated files in libraries/plugins/ -Dev->>Cfg : Add enable-plugin and public-api settings -Dev->>Build : Configure and build -Build-->>App : Discover and link plugin -App-->>Dev : Plugin active at runtime -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) -- [plugin.md](file://documentation/plugin.md#L11-L28) - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) -- [building.md](file://documentation/building.md#L1-L212) - -### Command-Line Options and Customization Parameters -- Provider: Namespace identifier for plugin and API classes. -- Plugin Name: Base name for all generated files and targets. -- CMake Parameters: Adjust include directories and link libraries as needed in the generated CMakeLists.txt. - -Customization tips: -- Modify the generated CMakeLists.txt to add extra include directories or link additional libraries. -- Update plugin and API headers to declare new methods and reflection lists. -- Implement plugin lifecycle methods to register signal handlers and API factories. - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) -- [newplugin.py](file://programs/util/newplugin.py#L4-L16) - -### Best Practices for Plugin Development -- Keep plugin logic decoupled from UI; expose functionality via APIs. -- Use the plugin’s startup/shutdown methods to register/unregister signal handlers. -- Reflect API methods in the FC_API declaration to expose them to clients. -- Avoid heavy computations in hot paths; defer to worker threads when necessary. -- Use database snapshots and weak read locks for safe reads in APIs. - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L21-L28) - -### Common Plugin Development Pitfalls -- Incorrect include paths preventing CMake discovery. -- Missing API method declarations in FC_API leading to unavailable RPC endpoints. -- Forgetting to register the API factory during plugin startup. -- Not handling chain events properly, causing missed updates or crashes. -- Enabling/disabling plugins that maintain persistent state without replaying the chain. - -Mitigation: -- Verify include directories match the expected pattern. -- Ensure all declared API methods are implemented and reflected. -- Connect to chain signals in plugin startup and disconnect in shutdown. -- Rebuild and replay when toggling stateful plugins. - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) - -### Testing Strategies -- Unit tests: Test isolated logic in plugin internals and API helpers. -- Integration tests: Exercise plugin APIs against a live or mocked chain database. -- Replay tests: Validate behavior changes when enabling/disabling stateful plugins by replaying blocks. -- API tests: Use JSON-RPC calls to verify exposed endpoints. - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) - -### Deployment Considerations -- Build variants: Release vs. Debug configurations affect performance and debugging capabilities. -- Low-memory nodes: Specialized builds reduce memory footprint for resource-constrained environments. -- Docker: Containerized builds simplify environment setup and reproducibility. -- External plugins: Third-party plugins can be dropped into external directories and built alongside internal plugins. - -**Section sources** -- [building.md](file://documentation/building.md#L1-L212) - -## Dependency Analysis -The plugin system relies on a few key relationships: -- The generator depends on Python’s standard library and argparse. -- Generated plugins depend on core libraries (application, chain, protocol). -- Application discovery depends on CMake scanning plugin directories. - -```mermaid -graph TB -Gen["programs/util/newplugin.py"] --> Tpl["Template Definitions"] -Gen --> FS["Filesystem"] -FS --> Lib["libraries/plugins/"] -Lib --> CMake["CMakeLists.txt"] -CMake --> App["Application"] -App --> Chain["Chain Database"] -``` - -**Diagram sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L225-L246) -- [CMakeLists.txt (plugins root)](file://plugins/CMakeLists.txt#L1-L12) - -## Performance Considerations -- Minimize work in event callbacks; offload to worker threads when appropriate. -- Use weak read locks for database reads in APIs to avoid contention. -- Avoid unnecessary allocations and copies in hot paths. -- Tune shared memory and flush intervals for chain performance. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Plugin not discovered: - - Verify the plugin directory exists under libraries/plugins/. - - Ensure the directory contains a CMakeLists.txt and that it is processed by the plugins root CMakeLists.txt. -- API not available: - - Confirm API methods are declared in the header and reflected in FC_API. - - Ensure the API factory is registered during plugin startup. -- Chain state inconsistencies: - - If a plugin maintains persistent state, rebuild and replay the chain when toggling its enablement. - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) - -## Conclusion -The VIZ CPP Node plugin development tool streamlines the creation of new plugins by generating a complete, buildable skeleton that adheres to established naming and organizational conventions. By following the template system, CMake integration, and best practices outlined here, developers can quickly implement robust plugins that integrate seamlessly with the application and support scalable testing and deployment strategies. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Generated File Reference -- CMakeLists.txt: Adds the library, sets include directories, and links core libraries. -- _plugin.hpp: Declares the plugin class and its lifecycle methods. -- _plugin.cpp: Implements plugin lifecycle, signal connections, and API registration. -- _api.hpp: Declares the API class and FC_API method list. -- _api.cpp: Implements API factory registration and helper accessors. - -**Section sources** -- [newplugin.py](file://programs/util/newplugin.py#L3-L218) - -### Appendix B: Example Plugin Patterns -- Signal-driven plugins: Connect to chain database signals in plugin startup and disconnect in shutdown. -- API-only plugins: Expose read-only or write APIs via the API class and FC_API declaration. -- Stateful plugins: Maintain indices or caches and handle replay when toggled on/off. - -**Section sources** -- [account_by_key_plugin.cpp](file://plugins/account_by_key/plugin.cpp#L197-L222) -- [account_by_key_plugin.hpp](file://plugins/account_by_key/include/graphene/plugins/account_by_key/account_by_key_plugin.hpp#L19-L44) -- [account_by_key_objects.hpp](file://plugins/account_by_key/include/graphene/plugins/account_by_key/account_by_key_objects.hpp#L18-L67) -- [chain_plugin.cpp](file://plugins/chain/plugin.cpp#L254-L396) -- [debug_node_plugin.cpp](file://plugins/debug_node/plugin.cpp#L117-L156) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Reflection Validation Tools.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Reflection Validation Tools.md deleted file mode 100644 index 6f3ed73e5c..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Reflection Validation Tools.md +++ /dev/null @@ -1,339 +0,0 @@ -# Reflection Validation Tools - - -**Referenced Files in This Document** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [Doxyfile](file://Doxyfile) -- [CMakeLists.txt](file://CMakeLists.txt) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [node.cpp](file://libraries/network/node.cpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) -- [docker-main.yml](file://.github/workflows/docker-main.yml) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the VIZ CPP Node reflection validation tool, check_reflect.py, which ensures that reflection metadata for blockchain objects and operations remains consistent between: -- Doxygen-generated documentation of class members -- Actual FC_REFLECT and FC_REFLECT_DERIVED declarations in the codebase - -The tool cross-validates reflected member lists to guarantee proper serialization/deserialization behavior across the system, preventing subtle bugs in binary protocols, APIs, and persistence layers. - -## Project Structure -The reflection validation pipeline spans three stages: -- Code scanning: Extracts FC_REFLECT and FC_REFLECT_DERIVED declarations from C++ sources -- Documentation extraction: Parses Doxygen XML to obtain documented member lists -- Validation: Compares both sets and reports mismatches - -```mermaid -graph TB -A["C++ Sources
libraries/, programs/, tests/"] --> B["Regex Scanner
check_reflect.py"] -B --> C["name2members_re
Parsed Reflection Members"] -D["Doxygen XML
doxygen/xml/index.xml"] --> E["XML Parser
check_reflect.py"] -E --> F["name2members_doxygen
Documented Members"] -C --> G["Validator
validate_members()"] -F --> G -G --> H["Results
ok/error/not evaluated"] -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L84-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) -- [Doxyfile](file://Doxyfile#L783-L786) - -## Core Components -- Regex-based scanner for FC_REFLECT and FC_REFLECT_DERIVED -- Doxygen XML parser for documented members -- Validation engine comparing reflected vs documented members -- Exit-code driven integration for CI - -Key behaviors: -- Scans libraries/, programs/, tests/ recursively for .cpp/.hpp files -- Builds a map of class names to reflected member lists -- Filters out static members (space_id, type_id) from validation -- Reports duplicates, missing members, and symmetric differences - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L61-L77) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L84-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L51-L54) - -## Architecture Overview -The validation tool orchestrates three major phases: discovery, documentation ingestion, and comparison. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Tool as "check_reflect.py" -participant FS as "Filesystem" -participant DX as "Doxygen XML" -participant Val as "Validator" -Dev->>Tool : Run validation -Tool->>FS : Walk libraries/, programs/, tests/ -FS-->>Tool : Match .cpp/.hpp files -Tool->>Tool : Scan FC_REFLECT/DERIVED -Tool->>DX : Parse doxygen/xml/index.xml -DX-->>Tool : Struct/class member lists -Tool->>Val : validate_members(reflected, documented) -Val-->>Tool : {ok, error, not evaluated} -Tool-->>Dev : Exit code + summary -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L86-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L153-L160) - -## Detailed Component Analysis - -### Reflection Scanner (FC_REFLECT/FC_REFLECT_DERIVED) -- Purpose: Extract reflected member lists from C++ sources -- Scope: Recursively scans libraries/, programs/, tests/ for .cpp/.hpp -- Patterns: - - FC_REFLECT(class, (member1)(member2)...) - - FC_REFLECT_DERIVED(class, (base), (member1)(member2)...) - -Validation rules: -- Member names are captured via a helper that splits parenthesized lists -- Duplicate members are detected and reported -- Case-sensitive ordering is normalized for comparison - -```mermaid -flowchart TD -Start(["Scan Files"]) --> Walk["Walk directories
libraries/, programs/, tests/"] -Walk --> Filter["Filter .cpp/.hpp"] -Filter --> Read["Read file content"] -Read --> MatchReflect{"Match FC_REFLECT?"} -MatchReflect --> |Yes| CaptureReflect["Capture class + members"] -MatchReflect --> |No| MatchDerived{"Match FC_REFLECT_DERIVED?"} -MatchDerived --> |Yes| CaptureDerived["Capture class + derived members"] -MatchDerived --> |No| Next["Next file"] -CaptureReflect --> Next -CaptureDerived --> Next -Next --> End(["name2members_re populated"]) -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L86-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L61-L77) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L80-L82) - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L61-L77) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L80-L82) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L84-L105) - -### Doxygen XML Ingestion -- Purpose: Obtain documented member lists for structs/classes -- Mechanism: Parses doxygen/xml/index.xml and collects member names per class -- Post-processing: Removes static members (space_id, type_id) from validation - -```mermaid -flowchart TD -A["Parse doxygen/xml/index.xml"] --> B["Iterate compounds (class/struct)"] -B --> C["Collect and "] -C --> D["Build name2members_doxygen"] -D --> E["Remove static members:
space_id, type_id"] -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L51-L54) - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L51-L54) - -### Validation Engine -- Purpose: Compare reflected vs documented members -- Checks: - - Presence of class in both sets - - Duplicate members in documented set - - Symmetric difference between reflected and documented members -- Outputs: - - Lists of ok, not evaluated, and error classes - - Detailed diffs for mismatches - -```mermaid -flowchart TD -Start(["validate_members"]) --> ForEach["For each reflected class"] -ForEach --> Present{"Present in documented?"} -Present --> |No| MarkNE["Add to 'not evaluated'"] -Present --> |Yes| Dupes{"Duplicates in documented?"} -Dupes --> |Yes| ReportDupe["Report duplicates"] -Dupes --> |No| Compare["Compare sorted member lists"] -Compare --> Same{"Equal?"} -Same --> |Yes| MarkOK["Add to 'ok'"] -Same --> |No| ReportDiff["Report diff"] -MarkNE --> Next["Next class"] -ReportDupe --> Next -ReportDiff --> Next -MarkOK --> Next -Next --> End(["Return results"]) -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -### Practical Usage Examples -- Running the validator: - - Ensure Doxygen XML exists (generate docs with Doxygen) - - Execute the script from the repository root - - Interpret exit code and printed summaries - -- Interpreting results: - - ok: Classes with consistent reflected and documented members - - not evaluated: Classes reflected but not documented - - error: Classes with duplicates or differing members - -- Fixing reflection issues: - - Align FC_REFLECT/FC_REFLECT_DERIVED member lists with actual class members - - Remove duplicates in reflected declarations - - Add missing members to reflected declarations if they should be serialized - -[No sources needed since this subsection provides general guidance] - -### Integration with Build System and CI -- Doxygen configuration: - - INPUT includes libraries/chain, libraries/wallet, libraries/plugins, and libraries/app - - Output directory configured for documentation/doxygen - -- CMake export: - - CMAKE_EXPORT_COMPILE_COMMANDS enabled to aid tooling - -- CI integration: - - Docker build workflows exist for production/testnet images - - Validation can be added as a pre-submit step to run check_reflect.py and Doxygen - -**Section sources** -- [Doxyfile](file://Doxyfile#L783-L786) -- [Doxyfile](file://Doxyfile#L61-L61) -- [CMakeLists.txt](file://CMakeLists.txt#L24-L24) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) - -## Dependency Analysis -The validator depends on: -- Filesystem traversal and regex parsing for reflection declarations -- Doxygen XML output for documented members -- Consistent class naming conventions across FC_REFLECT and Doxygen - -Potential coupling and risks: -- If Doxygen is not regenerated, documented members may lag behind code changes -- If FC_REFLECT declarations are inconsistent, validation will fail -- Static members filtering must remain synchronized with actual class definitions - -```mermaid -graph LR -SRC["C++ Sources"] --> REGEX["Regex Scanner"] -DOX["Doxygen XML"] --> PARSER["XML Parser"] -REGEX --> MAPR["name2members_re"] -PARSER --> MAPD["name2members_doxygen"] -MAPR --> VAL["Validator"] -MAPD --> VAL -VAL --> OUT["Validation Report"] -``` - -**Diagram sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L86-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L44-L50) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L86-L105) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -## Performance Considerations -- File scanning is linear in total source lines; typical repositories process quickly -- Regex compilation occurs once; repeated scans are efficient -- XML parsing overhead is bounded by documented class count -- Recommendations: - - Limit scan scope to modified directories during development - - Regenerate Doxygen incrementally when only specific modules change - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- No documented members found: - - Ensure Doxygen is run and doxygen/xml/index.xml exists - - Verify Doxyfile INPUT paths include relevant modules - -- Unexpected "error" items: - - Check for typos in FC_REFLECT/FC_REFLECT_DERIVED member names - - Confirm member ordering does not matter (validation normalizes order) - - Resolve duplicates flagged by the validator - -- "not evaluated" items: - - Add FC_REFLECT/FC_REFLECT_DERIVED declarations for newly added classes - - Ensure Doxygen documents the class and members - -- Static member filtering: - - space_id and type_id are intentionally excluded from validation - - Do not add these to reflected lists if they are not real data fields - -Debugging tips: -- Temporarily print intermediate maps (name2members_doxygen, name2members_re) to inspect discrepancies -- Run Doxygen with verbose output to confirm XML generation -- Use smaller file subsets to localize issues - -**Section sources** -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L51-L54) -- [check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L151) - -## Conclusion -The check_reflect.py tool provides a robust mechanism to maintain reflection consistency across the VIZ CPP Node codebase. By validating FC_REFLECT declarations against Doxygen documentation, it helps prevent serialization inconsistencies and improves reliability of blockchain operations, APIs, and persistence layers. Integrating this tool into CI and adopting the best practices outlined here will keep reflection metadata accurate and maintainable. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Example Reflection Declarations in the Codebase -- Chain objects: - - withdraw_vesting_route_object - - escrow_object - - award_shares_expire_object - - block_post_validation_object - -- Network and plugins: - - node_configuration - - json_rpc_error - - json_rpc_response - -These declarations demonstrate the use of FC_REFLECT for serialization and are validated by the tool. - -**Section sources** -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L208-L225) -- [node.cpp](file://libraries/network/node.cpp#L244-L244) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L427-L428) - -### Wallet Reflection Utilities -- Utility functions for static_variant mapping and variant conversion -- Support for operation name-to-ID mapping and variant parsing - -These utilities complement reflection by enabling runtime handling of polymorphic types. - -**Section sources** -- [reflect_util.hpp](file://libraries/wallet/include/graphene/wallet/reflect_util.hpp#L1-L91) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Schema Generation Tools.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Schema Generation Tools.md deleted file mode 100644 index 34ef36e1fc..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build Helper Tools/Schema Generation Tools.md +++ /dev/null @@ -1,281 +0,0 @@ -# Schema Generation Tools - - -**Referenced Files in This Document** -- [pretty_schema.py](file://programs/util/pretty_schema.py) -- [schema_test.cpp](file://programs/util/schema_test.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the schema generation and validation tools used in the VIZ CPP Node project. It focuses on: -- The pretty_schema.py utility for fetching, parsing, and formatting JSON schema representations from the running node’s debug interface. -- The schema_test.cpp utility for validating and inspecting object schemas and their dependencies at compile-time and runtime. -- How these tools integrate into development workflows, support schema evolution, and help maintain backward compatibility. - -These tools enable: -- Generating human-readable schema documentation from blockchain object definitions. -- Validating schema correctness and dependency relationships during development and CI. -- Supporting schema evolution by ensuring consistent type naming, dependency resolution, and unique schema IDs. - -## Project Structure -The schema-related capabilities are implemented across: -- A Python script that queries the node’s debug API and prints a formatted JSON schema. -- A C++ program that introspects object schemas and their dependencies via the database schema API. -- Core node logic that builds and stores the canonical JSON schema representation. - -```mermaid -graph TB -subgraph "Utilities" -PS["pretty_schema.py"] -ST["schema_test.cpp"] -end -subgraph "Node Runtime" -DN["Debug Node API
JSON Schema Endpoint"] -end -subgraph "Core Libraries" -DB["database.cpp
Schema Assembly"] -CO["custom_operation_interpreter.hpp
abstract_schema"] -end -PS --> DN -ST --> DB -DB --> CO -``` - -**Diagram sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L20) - -**Section sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L20) - -## Core Components -- pretty_schema.py - - Purpose: Connects to the local debug node API endpoint to retrieve the current JSON schema, parses and normalizes types, and prints a sorted, indented JSON schema for documentation. - - Key steps: HTTP POST to the debug API, JSON parsing, safe conversion of string fields to JSON where applicable, and pretty-printing. - - Output customization: Indentation and sorting are controlled by the printing routine. -- schema_test.cpp - - Purpose: Validates and inspects schemas for selected blockchain objects, collects dependent schemas, and prints schema metadata and dependency lists. - - Key steps: Obtain schemas for target types, add dependent schemas, iterate and print schema names, dependencies, and serialized schema strings. - - Output customization: Console output formatting is handled by the program itself. - -Practical usage examples: -- Documentation generation: Run pretty_schema.py against a running node to produce a stable, sorted schema for inclusion in docs or CI artifacts. -- Validation: Build and run schema_test.cpp to verify schema correctness and dependency resolution for core objects. - -**Section sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) - -## Architecture Overview -The schema generation pipeline integrates a Python client with the node’s debug API and a C++ introspection utility with the schema subsystem. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant PS as "pretty_schema.py" -participant Node as "VIZ Node Debug API" -participant ST as "schema_test.cpp" -participant DB as "database.cpp" -Dev->>PS : Execute to fetch JSON schema -PS->>Node : HTTP POST debug_get_json_schema -Node-->>PS : JSON schema string -PS->>PS : Parse and normalize types -PS-->>Dev : Pretty-printed JSON schema -Dev->>ST : Build and run schema validator -ST->>DB : Request schemas for types -DB-->>ST : Schema list with dependencies -ST-->>Dev : Printed schema info and dependencies -``` - -**Diagram sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L9-L13) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L44-L56) -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) - -## Detailed Component Analysis - -### pretty_schema.py -- Fetching the schema: - - Sends a JSON-RPC 2.0 request to the debug node API endpoint. - - Reads the response and extracts the schema string. -- Normalizing types: - - Attempts to parse each type value as JSON; if it fails, keeps the original string. -- Formatting and output: - - Prints the entire schema with indentation and sorted keys for readability. - -```mermaid -flowchart TD -Start(["Start"]) --> Post["POST to debug_get_json_schema"] -Post --> Receive{"Response OK?"} -Receive --> |No| Error["Report error and exit"] -Receive --> |Yes| Parse["Parse result and extract schema string"] -Parse --> Normalize["Normalize types to JSON where possible"] -Normalize --> Print["Pretty-print JSON with indentation and sorted keys"] -Print --> End(["Done"]) -Error --> End -``` - -**Diagram sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L9-L27) - -**Section sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) - -### schema_test.cpp -- Schema collection: - - Requests schemas for specific blockchain object types. - - Adds dependent schemas to ensure complete dependency coverage. -- Inspection: - - Iterates over collected schemas, extracting names, dependencies, and serialized schema strings. -- Output: - - Prints schema metadata to console for inspection and validation. - -```mermaid -flowchart TD -Init(["Initialize"]) --> Collect["Collect schemas for target types"] -Collect --> AddDeps["Add dependent schemas"] -AddDeps --> Iterate{"More schemas?"} -Iterate --> |Yes| Inspect["Get name, deps, and serialized schema"] -Inspect --> Print["Print schema info"] -Print --> Iterate -Iterate --> |No| Exit(["Exit"]) -``` - -**Diagram sources** -- [schema_test.cpp](file://programs/util/schema_test.cpp#L44-L56) - -**Section sources** -- [schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) - -### Core Schema Assembly in the Node -- The node compiles a comprehensive list of object schemas, operation schemas, and custom operation schemas. -- It ensures uniqueness and ordering by schema ID, then serializes the final schema map for use by APIs and tools. - -```mermaid -sequenceDiagram -participant DB as "database.cpp" -participant Types as "Object/Operation Types" -participant Deps as "add_dependent_schemas" -participant Out as "Final Schema Map" -DB->>Types : Gather object schemas -DB->>Types : Get operation schema -DB->>Types : Collect custom operation schemas -DB->>Deps : Add dependent schemas -Deps-->>DB : Expanded schema list -DB->>DB : Sort and deduplicate by schema ID -DB->>Out : Serialize to JSON map -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) - -## Dependency Analysis -- pretty_schema.py depends on: - - A running node exposing the debug API endpoint. - - The node’s JSON schema serialization mechanism. -- schema_test.cpp depends on: - - The schema subsystem in the node’s chain library. - - The presence of specific object types whose schemas are requested. -- Core schema assembly depends on: - - The schema registry and the abstract schema interface used by custom operation interpreters. - -```mermaid -graph LR -PS["pretty_schema.py"] --> API["Debug Node API"] -ST["schema_test.cpp"] --> DB["database.cpp"] -DB --> AS["abstract_schema (custom_operation_interpreter.hpp)"] -``` - -**Diagram sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L9-L13) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L10-L13) -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L20) - -**Section sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) -- [database.cpp](file://libraries/chain/database.cpp#L2997-L3050) -- [custom_operation_interpreter.hpp](file://libraries/chain/include/graphene/chain/custom_operation_interpreter.hpp#L1-L20) - -## Performance Considerations -- pretty_schema.py: - - Network latency to the local debug API is minimal but still present; consider caching outputs when iterating on documentation. - - JSON parsing and normalization are lightweight; avoid repeated runs in tight loops. -- schema_test.cpp: - - Schema collection and dependency addition are O(n log n) due to sorting; keep the number of target types reasonable for quick iteration. - - Printing to console is I/O bound; avoid excessive logging in production builds. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- pretty_schema.py cannot connect to the debug API: - - Ensure the node is running and the debug API is enabled. - - Verify the endpoint URL and port match the node configuration. -- Unexpected schema output: - - Confirm the node is fully initialized so that all schemas are populated. - - Re-run after applying recent schema changes to ensure the latest schema is retrieved. -- schema_test.cpp missing types: - - Ensure the requested types are compiled into the binary and exposed via the schema subsystem. - - Confirm that dependent schemas are included by invoking the dependency collector before printing. -- Dependency mismatches: - - Use the printed dependency lists to verify that all referenced types are present and uniquely named. - - Resolve naming conflicts by adjusting type names or aliases to ensure uniqueness. - -Interpreting results: -- Schema names and IDs must be unique; duplicates indicate conflicting definitions. -- Dependencies should form a directed acyclic graph; cycles suggest incorrect schema composition. -- Serialized schema strings should be valid JSON; malformed entries require fixing the underlying type definitions. - -**Section sources** -- [pretty_schema.py](file://programs/util/pretty_schema.py#L9-L13) -- [schema_test.cpp](file://programs/util/schema_test.cpp#L25-L42) -- [database.cpp](file://libraries/chain/database.cpp#L3040-L3047) - -## Conclusion -The VIZ CPP Node provides robust schema generation and validation tools: -- pretty_schema.py offers a quick way to export a formatted JSON schema for documentation and review. -- schema_test.cpp enables developers to validate schema correctness and dependencies during development. -Together with the node’s schema assembly logic, these tools support reliable schema evolution and backward compatibility checks. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Workflows -- Documentation generation: - - Start the node with the debug API enabled. - - Run pretty_schema.py to capture the current schema. - - Save the output to a documentation artifact or CI cache. -- Development validation: - - Build schema_test.cpp and run it against the current binary. - - Review printed schema names, dependencies, and serialized forms. - - Fix any naming conflicts or missing dependencies before merging changes. -- Automated schema testing: - - Integrate schema_test.cpp into CI to validate schema integrity on pull requests. - - Optionally wrap pretty_schema.py in CI to compare diffs in schema outputs across commits. - -[No sources needed since this section provides general guidance] \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Build System.md b/.qoder/repowiki/en/content/Development Tools/Build System/Build System.md deleted file mode 100644 index 289f783151..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Build System.md +++ /dev/null @@ -1,960 +0,0 @@ -# Build System - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/CMakeLists.txt](file://programs/CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt) -- [thirdparty/CMakeLists.txt](file://thirdparty/CMakeLists.txt) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [programs/build_helpers/cat_parts.py](file://programs/build_helpers/cat_parts.py) -- [programs/util/newplugin.py](file://programs/util/newplugin.py) -- [documentation/building.md](file://documentation/building.md) -- [build-linux.sh](file://build-linux.sh) -- [install-deps-linux.sh](file://install-deps-linux.sh) -- [build-mac.sh](file://build-mac.sh) -- [build-mingw.bat](file://build-mingw.bat) -- [build-msvc.bat](file://build-msvc.bat) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) - - -## Update Summary -**Changes Made** -- Enhanced build system architecture with dedicated dependency management using install-deps-linux.sh + build-linux.sh two-script process -- Improved error handling and security practices with root privilege separation and user permission enforcement -- Updated platform-specific build scripts with enhanced validation and security measures -- Revised Docker configurations to use Boost 1.71 packages (libboost-coroutine-dev, libboost-context-dev) -- Added comprehensive troubleshooting guidance for the new two-script build process - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Two-Script Build Process](#enhanced-two-script-build-process) -7. [Platform-Specific Build Scripts](#platform-specific-build-scripts) -8. [Dependency Analysis](#dependency-analysis) -9. [Performance Considerations](#performance-considerations) -10. [Security Best Practices](#security-best-practices) -11. [Troubleshooting Guide](#troubleshooting-guide) -12. [Conclusion](#conclusion) -13. [Appendices](#appendices) - -## Introduction -This document explains the build system for VIZ CPP Node, focusing on the enhanced CMake-based configuration with dedicated dependency management, cross-platform compilation support, and improved security practices. The build system now features a two-script architecture (install-deps-linux.sh + build-linux.sh) that separates dependency installation (requiring root) from the build process (running as a regular user), providing better security and reliability. The system supports Ubuntu 24.04+, macOS with Homebrew, and Windows with both MSVC and MinGW toolchains, all requiring Boost 1.71+ with mandatory coroutine component. - -## Project Structure -The build system is organized around a top-level CMake project with enhanced dependency management and platform-specific build automation: -- Top-level CMake project defines compiler checks, options, platform-specific flags, and includes subdirectories for thirdparty, libraries, plugins, and programs -- Dedicated dependency management scripts provide secure, validated dependency installation -- Platform-specific build scripts offer automated configuration and building with enhanced error handling -- Subprojects: - - libraries: API, chain, protocol, network, time, utilities, wallet - - plugins: dynamically discovered via a scanning mechanism - - thirdparty: appbase, fc, chainbase - - programs: build_helpers, cli_wallet, vizd, js_operation_serializer, size_checker, util - -```mermaid -graph TB -Root["Top-level CMakeLists.txt"] -TP["thirdparty/CMakeLists.txt"] -LIB["libraries/CMakeLists.txt"] -PLG["plugins/CMakeLists.txt"] -PRG["programs/CMakeLists.txt"] -LinuxDeps["install-deps-linux.sh"] -LinuxBuild["build-linux.sh"] -Mac["build-mac.sh"] -MinGW["build-mingw.bat"] -MSVC["build-msvc.bat"] -Root --> TP -Root --> LIB -Root --> PLG -Root --> PRG -LinuxDeps --> LinuxBuild -LinuxBuild --> Root -Mac --> Root -MinGW --> Root -MSVC --> Root -``` - -**Diagram sources** -- [CMakeLists.txt:206-209](file://CMakeLists.txt#L206-L209) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) -- [build-mingw.bat:1-125](file://build-mingw.bat#L1-L125) -- [build-msvc.bat:1-116](file://build-msvc.bat#L1-L116) - -**Section sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) - -## Core Components -- Top-level CMake project: - - Enforces minimum CMake version 3.16 and compiler versions for GCC and Clang - - Configures Boost usage with version 1.71 and coroutine component requirement, optional static/shared libraries, and PCH support - - Provides compile-time options: BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, ENABLE_MONGO_PLUGIN - - Sets platform-specific flags for Windows (MSVC/Mingw), macOS, and Linux - - Enables ccache globally when available - - Supports optional CPack installer generation -- Enhanced dependency management: - - **install-deps-linux.sh**: Secure dependency installation script requiring root privileges with comprehensive package management for Ubuntu/Debian (apt-get) and Fedora/RHEL (dnf) - - **build-linux.sh**: User-friendly build script with enhanced error handling, argument validation, and security enforcement -- Platform-specific build scripts: - - **build-mac.sh**: Automated Xcode/Homebrew dependency installation, OpenSSL detection, and building for macOS with comprehensive validation - - **build-mingw.bat**: Windows MinGW build with environment variable configuration and static linking - - **build-msvc.bat**: Windows MSVC build with Visual Studio generator configuration -- Helper scripts: - - configure_build.py: wraps cmake with sensible defaults and cross-compilation support - - cat_parts.py: concatenates files from a directory tree into a single output file - - newplugin.py: scaffolds a new plugin directory and files - -**Section sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) -- [build-mingw.bat:1-125](file://build-mingw.bat#L1-L125) -- [build-msvc.bat:1-116](file://build-msvc.bat#L1-L116) -- [programs/build_helpers/configure_build.py:1-202](file://programs/build_helpers/configure_build.py#L1-L202) -- [programs/build_helpers/cat_parts.py:1-74](file://programs/build_helpers/cat_parts.py#L1-L74) -- [programs/util/newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) - -## Architecture Overview -The enhanced build pipeline integrates CMake configuration, secure dependency management, platform detection, and helper tools to produce binaries with improved security and reliability. The new two-script architecture separates dependency installation (requiring root) from the build process (running as a regular user), providing better security boundaries while maintaining consistency with the core CMake configuration. - -```mermaid -graph TB -subgraph "Secure Host Environment" -DepsScript["install-deps-linux.sh (root)"] -BuildScript["build-linux.sh (user)"] -MacScript["build-mac.sh"] -MinGWScript["build-mingw.bat"] -MSVCScript["build-msvc.bat"] -CFG["configure_build.py"] -CC["Compiler (GCC/Clang/MSVC/Mingw)"] -CMake["CMake (Top-level)"] -Helpers["cat_parts.py / newplugin.py"] -end -subgraph "Source Tree" -Root["CMakeLists.txt"] -Libs["libraries/*"] -Plugins["plugins/*"] -Third["thirdparty/*"] -Progs["programs/*"] -end -subgraph "Artifacts" -Bin["Binaries (vizd, cli_wallet, ...)"] -Inst["Installed Layout (/usr/local or CPack)"] -end -DepsScript --> BuildScript -BuildScript --> CMake -MacScript --> CMake -MinGWScript --> CMake -MSVCScript --> CMake -CFG --> CMake -CMake --> Root -Root --> Libs -Root --> Plugins -Root --> Third -Root --> Progs -CC --> CMake -CMake --> Bin -Helpers --> Root -CMake --> Inst -``` - -**Diagram sources** -- [CMakeLists.txt:206-209](file://CMakeLists.txt#L206-L209) -- [install-deps-linux.sh:28-31](file://install-deps-linux.sh#L28-L31) -- [build-linux.sh:57-61](file://build-linux.sh#L57-L61) -- [build-linux.sh:214-229](file://build-linux.sh#L214-L229) -- [build-mac.sh:210-224](file://build-mac.sh#L210-L224) -- [build-mingw.bat:90-111](file://build-mingw.bat#L90-L111) -- [build-msvc.bat:82-102](file://build-msvc.bat#L82-L102) -- [programs/build_helpers/configure_build.py:143-195](file://programs/build_helpers/configure_build.py#L143-L195) -- [programs/build_helpers/cat_parts.py:11-69](file://programs/build_helpers/cat_parts.py#L11-L69) -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) - -## Detailed Component Analysis - -### CMake Configuration and Options -Key behaviors: -- CMake minimum version: Requires CMake 3.16 or higher for modern C++ features and improved dependency management -- Compiler enforcement: Fails early if GCC < 4.8 or Clang < 3.3 -- Boost configuration: Uses Boost 1.71 with coroutine component requirement; supports static usage; removes deprecated 1.53 compatibility logic -- Platform flags: - - Windows (MSVC): Adds warning suppressions, disables safe-seh, ensures debug info, locates TCL - - Windows (MinGW): Enables C++11, permissive mode, SSE4.2, big obj, sets Release/Debug optimization flags, supports full static build - - macOS: Uses libc++, C++14, sets common warnings - - Linux: Uses C++14, enables rt and pthread, optional crypto library, supports full static build -- Coverage/testing: Optional --coverage flag when enabled -- Options: - - BUILD_TESTNET: Adds preprocessor defines and prints configuration status - - LOW_MEMORY_NODE: Adds preprocessor defines and prints configuration status - - CHAINBASE_CHECK_LOCKING: Adds preprocessor defines and prints configuration status - - ENABLE_MONGO_PLUGIN: Adds MongoDB plugin linkage and preprocessor defines - - BUILD_SHARED_LIBRARIES: Defaults to off - - USE_PCH: Optional cotire precompiled headers support - - ENABLE_INSTALLER: Optional CPack packaging - -Build targets: -- The top-level project includes subprojects for thirdparty, libraries, plugins, and programs. Programs include build_helpers, cli_wallet, vizd, js_operation_serializer, size_checker, and util. - -**Section sources** -- [CMakeLists.txt:2-3](file://CMakeLists.txt#L2-L3) -- [CMakeLists.txt:11-20](file://CMakeLists.txt#L11-L20) -- [CMakeLists.txt:38-49](file://CMakeLists.txt#L38-L49) -- [CMakeLists.txt:51-53](file://CMakeLists.txt#L51-L53) -- [CMakeLists.txt:55-80](file://CMakeLists.txt#L55-L80) -- [CMakeLists.txt:82-88](file://CMakeLists.txt#L82-L88) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:108-152](file://CMakeLists.txt#L108-L152) -- [CMakeLists.txt:154-198](file://CMakeLists.txt#L154-L198) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) - -### Cross-Platform Compilation Flags and Toolchains -- Windows: - - MSVC: Warning suppressions, safe-seh disable, ensures debug info, finds TCL - - MinGW: C++11, permissive mode, SSE4.2, big obj, Release/Debug optimization, optional full static build -- macOS: - - C++14, libc++, common warnings, disables certain conversion warnings -- Linux: - - C++14, rt and pthread libraries, optional crypto library, optional full static build -- Ninja + Clang diagnostics: colorized diagnostics when generator is Ninja and compiler is Clang -- Debug build: defines DEBUG automatically - -**Section sources** -- [CMakeLists.txt:108-152](file://CMakeLists.txt#L108-L152) -- [CMakeLists.txt:154-198](file://CMakeLists.txt#L154-L198) - -### Dependency Management -- Boost: Required version 1.71 with components including thread, date_time, system, filesystem, program_options, serialization, chrono, unit_test_framework, context, locale, and coroutine. Static usage is preferred; coroutine is now a mandatory component for Boost >= 1.71 -- OpenSSL: Optional via OPENSSL_ROOT_DIR; used when present -- Readline: Found on non-Windows platforms; included if available -- Crypto library: Defaults to crypto on Linux; configurable -- ccache: Detected and used globally for compile/link steps when available - -**Updated** Enhanced Boost dependency requirements with version 1.71 and mandatory coroutine component - -**Section sources** -- [CMakeLists.txt:38-49](file://CMakeLists.txt#L38-L49) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:102-106](file://CMakeLists.txt#L102-L106) -- [CMakeLists.txt:156-160](file://CMakeLists.txt#L156-L160) -- [CMakeLists.txt:172-176](file://CMakeLists.txt#L172-L176) - -### Build Targets -- Programs: - - vizd: main node binary - - cli_wallet: command-line wallet - - js_operation_serializer: utility for JS operation serialization - - size_checker: utility for size analysis - - build_helpers: helper utilities - - util: various utilities -- Libraries: - - api, chain, protocol, network, time, utilities, wallet -- Plugins: - - Discovered dynamically via scanning for subdirectories with CMakeLists.txt - -**Section sources** -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) - -### Build Helper Tools - -#### configure_build.py -- Purpose: Simplifies invoking cmake with sensible defaults and cross-compilation support -- Features: - - Accepts --sys-root, --boost-dir, --openssl-dir to guide find modules - - Supports LOW_MEMORY_NODE and CMAKE_BUILD_TYPE toggles - - Supports Windows cross-compilation via MinGW with static linking flags and root path modes - - Passes additional cmake options after a separator -- Typical usage: - - Configure for Release with LOW_MEMORY_NODE=OFF - - Configure for Debug with LOW_MEMORY_NODE=ON - - Cross-compile for Windows using MinGW with static linking - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Script as "configure_build.py" -participant CMake as "CMake" -participant FS as "Filesystem" -Dev->>Script : Invoke with options (--boost-dir, --openssl-dir, --sys-root, -w/--windows, -f/-w, -r/-d, -- [CMAKEOPTS]) -Script->>Script : Parse arguments and validate paths -Script->>Script : Detect Boost version and construct flags -Script->>Script : Optionally enable Windows cross-compilation flags -Script->>Script : Set LOW_MEMORY_NODE and CMAKE_BUILD_TYPE -Script->>CMake : Run cmake with constructed arguments -CMake->>FS : Discover Boost/OpenSSL/dependencies -CMake-->>Dev : Configure result and build instructions -``` - -**Diagram sources** -- [programs/build_helpers/configure_build.py:35-119](file://programs/build_helpers/configure_build.py#L35-L119) -- [programs/build_helpers/configure_build.py:143-195](file://programs/build_helpers/configure_build.py#L143-L195) - -**Section sources** -- [programs/build_helpers/configure_build.py:1-202](file://programs/build_helpers/configure_build.py#L1-L202) - -#### cat_parts.py -- Purpose: Concatenates files from a directory tree into a single output file, preserving order and skipping non-files -- Behavior: - - Validates input directory and output file path - - Skips non-file entries and filters by suffix if requested - - Compares generated content with existing output to avoid unnecessary writes - - Creates parent directories if missing - -```mermaid -flowchart TD -Start(["Start"]) --> Args["Parse input_dir and out_file"] -Args --> Validate{"input_dir is dir
out_file path valid?"} -Validate --> |No| Error["Print usage and exit"] -Validate --> |Yes| Scan["Scan files in input_dir"] -Scan --> Filter["Filter by suffix (optional)"] -Filter --> Sort["Sort files lexicographically"] -Sort --> Read["Read file contents in order"] -Read --> Compare{"Output exists and matches?"} -Compare --> |Yes| UpToDate["Print 'up-to-date' and exit"] -Compare --> |No| Write["Write concatenated content to out_file"] -Write --> Done(["Done"]) -Error --> Done -UpToDate --> Done -``` - -**Diagram sources** -- [programs/build_helpers/cat_parts.py:11-69](file://programs/build_helpers/cat_parts.py#L11-L69) - -**Section sources** -- [programs/build_helpers/cat_parts.py:1-74](file://programs/build_helpers/cat_parts.py#L1-L74) - -#### newplugin.py -- Purpose: Generates boilerplate files for a new plugin under libraries/plugins/ -- Templates: - - CMakeLists.txt for the plugin target - - Plugin header and implementation - - API header and implementation -- Behavior: - - Accepts provider and plugin name - - Writes files into a dedicated directory under libraries/plugins/ - -```mermaid -flowchart TD -Start(["Start"]) --> Parse["Parse provider and name"] -Parse --> MakeDir["Ensure output directory exists"] -MakeDir --> WriteFiles["Write template files:
CMakeLists.txt,
plugin header/impl,
api header/impl"] -WriteFiles --> Done(["Done"]) -``` - -**Diagram sources** -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) - -**Section sources** -- [programs/util/newplugin.py:1-251](file://programs/util/newplugin.py#L1-L251) - -### Docker-Based Builds -The repository ships Dockerfiles for multiple environments: -- Production: Full node build with Release, shared libraries disabled, lock checking disabled, MongoDB plugin disabled -- Low-memory: Same as production but with LOW_MEMORY_NODE enabled -- Mongo: Installs MongoDB C/C++ drivers and enables ENABLE_MONGO_PLUGIN -- Testnet: Builds with BUILD_TESTNET enabled - -Each Dockerfile: -- Uses a two-stage build to minimize image size -- Copies only necessary source files to reduce rebuilds -- Runs cmake with explicit options and compiles with parallel jobs -- Installs artifacts and prepares runtime configuration files and volumes - -**Updated** Docker configurations now use Boost 1.71 packages (libboost-coroutine-dev, libboost-context-dev) instead of older versions - -```mermaid -graph TB -subgraph "Builder Stage" -Dkfile["Dockerfile-*"] -Deps["Install build deps"] -CopySrc["Copy minimal sources"] -GitSub["Init submodules"] -CMakeCfg["Run cmake with options"] -Make["Compile with make -j$(nproc)"] -Install["make install"] -end -subgraph "Runtime Stage" -Runtime["Base image"] -User["Create vizd user"] -Vars["Set volumes and ports"] -Cfg["Copy configs and snapshots"] -end -Dkfile --> Deps --> CopySrc --> GitSub --> CMakeCfg --> Make --> Install --> Runtime -Runtime --> User --> Vars --> Cfg -``` - -**Diagram sources** -- [share/vizd/docker/Dockerfile-production:1-102](file://share/vizd/docker/Dockerfile-production#L1-L102) -- [share/vizd/docker/Dockerfile-lowmem:1-85](file://share/vizd/docker/Dockerfile-lowmem#L1-L85) -- [share/vizd/docker/Dockerfile-mongo:1-114](file://share/vizd/docker/Dockerfile-mongo#L1-L114) -- [share/vizd/docker/Dockerfile-testnet:1-102](file://share/vizd/docker/Dockerfile-testnet#L1-L102) - -**Section sources** -- [share/vizd/docker/Dockerfile-production:56-62](file://share/vizd/docker/Dockerfile-production#L56-L62) -- [share/vizd/docker/Dockerfile-lowmem:43-49](file://share/vizd/docker/Dockerfile-lowmem#L43-L49) -- [share/vizd/docker/Dockerfile-mongo:72-78](file://share/vizd/docker/Dockerfile-mongo#L72-L78) -- [share/vizd/docker/Dockerfile-testnet:56-62](file://share/vizd/docker/Dockerfile-testnet#L56-L62) - -## Enhanced Two-Script Build Process - -### install-deps-linux.sh - Secure Dependency Management -The `install-deps-linux.sh` script provides secure, automated dependency installation for Linux systems with comprehensive error handling and validation: - -**Security Features:** -- Requires root privileges with explicit EUID validation -- Comprehensive package manager detection (apt-get for Ubuntu/Debian, dnf for Fedora/RHEL) -- Color-coded logging with error/warn/info categorization -- Graceful fallback for unsupported package managers - -**Ubuntu/Debian Dependencies Installed:** -- Core build tools: cmake, gcc/g++, git, make, pkg-config, ccache -- Boost components: chrono, context, coroutine, date_time, filesystem, iostreams, locale, program-options, serialization, system, test, thread -- Compression libraries: bzip2, lzma, zstd, zlib -- Security: OpenSSL development headers -- Optional: readline, ncurses - -**Fedora/RHEL Dependencies Installed:** -- Core build tools: cmake, gcc-c++, git, ccache -- Boost development: boost-devel -- Compression libraries: bzip2-devel, lzma-devel, zstd-devel, zlib-devel -- Security: openssl-devel -- Optional: readline-devel, ncurses-devel, libtool - -**Error Handling:** -- Immediate termination on dependency installation failures -- Clear error messages with remediation suggestions -- Support for retry logic in Docker environments - -**Section sources** -- [install-deps-linux.sh:1-113](file://install-deps-linux.sh#L1-L113) - -### build-linux.sh - Enhanced Build Script -The `build-linux.sh` script provides a comprehensive automated build solution with enhanced security and validation: - -**Security Enhancements:** -- Refuses to run as root (enforced with EUID check) -- Validates source directory structure before proceeding -- Comprehensive argument parsing with validation -- Secure temporary directory handling - -**Enhanced Features:** -- Automatic dependency detection and installation for Ubuntu and Fedora -- Support for both Debian-style (apt) and RPM-style (dnf) package managers -- Comprehensive Boost 1.71+ dependency management with all required components -- Flexible configuration options for different build types and requirements -- Parallel job control and optional installation step -- Enhanced error handling and user feedback - -**Key Dependencies Installed:** -- Core build tools: cmake, gcc/g++, git, make, pkg-config -- Boost components: chrono, context, coroutine, date_time, filesystem, iostreams, locale, program-options, serialization, system, test, thread -- Compression libraries: bzip2, lzma, zstd, zlib -- Security: OpenSSL development headers -- Optional: readline, ccache, ncurses - -**Usage Examples:** -```bash -# Basic build with enhanced security -./build-linux.sh - -# Low memory node for validators -./build-linux.sh -l - -# Testnet build -./build-linux.sh -n - -# Debug build with 4 parallel jobs -./build-linux.sh -t Debug -j 4 - -# Skip dependency installation (already installed) -./build-linux.sh --skip-deps - -# Install to system after build -./build-linux.sh --install - -# Custom Boost and OpenSSL paths -./build-linux.sh --boost-root /opt/boost_1_74_0 --openssl-root /opt/openssl -``` - -**Section sources** -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) - -## Platform-Specific Build Scripts - -### Linux Build Script (build-linux.sh) -The `build-linux.sh` script provides a comprehensive automated build solution for Ubuntu 24.04+ and Fedora systems with enhanced security: - -**Security Features:** -- Refuses to run as root (EUID check at line 59-61) -- Validates CMakeLists.txt presence in source directory -- Comprehensive argument validation and error handling - -**Features:** -- Automatic dependency detection and installation for Ubuntu and Fedora -- Support for both Debian-style (apt) and RPM-style (dnf) package managers -- Comprehensive Boost 1.71+ dependency management with all required components -- Flexible configuration options for different build types and requirements -- Parallel job control and optional installation step - -**Key Dependencies Installed:** -- Core build tools: cmake, gcc/g++, git, make, pkg-config -- Boost components: chrono, context, coroutine, date_time, filesystem, iostreams, locale, program-options, serialization, system, test, thread -- Compression libraries: bzip2, lzma, zstd, zlib -- Security: OpenSSL development headers -- Optional: readline, ccache, ncurses - -**Usage Examples:** -```bash -# Basic build -./build-linux.sh - -# Low memory node for validators -./build-linux.sh -l - -# Testnet build -./build-linux.sh -n - -# Debug build with 4 parallel jobs -./build-linux.sh -t Debug -j 4 - -# Skip dependency installation (already installed) -./build-linux.sh --skip-deps - -# Install to system after build -./build-linux.sh --install - -# Custom Boost and OpenSSL paths -./build-linux.sh --boost-root /opt/boost_1_74_0 --openssl-root /opt/openssl -``` - -**Section sources** -- [build-linux.sh:1-191](file://build-linux.sh#L1-L191) - -### macOS Build Script (build-mac.sh) -The `build-mac.sh` script streamlines macOS development with Homebrew integration: - -**Features:** -- Xcode Command Line Tools verification and automatic installation -- Homebrew dependency management with modern Boost 1.71+ -- Automatic OpenSSL path detection from Homebrew -- Comprehensive error handling and validation -- Flexible configuration options mirroring Linux script capabilities - -**Key Dependencies Installed via Homebrew:** -- Core: autoconf, automake, boost, cmake, git, libtool, python3, readline -- Security: openssl -- Optional: google-perftools (for LevelDB TCMalloc) - -**macOS-Specific Features:** -- Xcode Command Line Tools detection and installation -- Homebrew prefix detection and validation -- OpenSSL path resolution from Homebrew installation -- Automatic environment setup for successful CMake configuration - -**Usage Examples:** -```bash -# Basic macOS build -./build-mac.sh - -# Low memory node for validator operations -./build-mac.sh -l - -# Testnet configuration -./build-mac.sh -n - -# Debug build with custom Boost path -./build-mac.sh --boost-root /opt/boost_1_74_0 - -# Skip dependency installation -./build-mac.sh --skip-deps -``` - -**Section sources** -- [build-mac.sh:1-242](file://build-mac.sh#L1-L242) - -### Windows MinGW Build Script (build-mingw.bat) -The `build-mingw.bat` script provides Windows development support with MinGW-w64: - -**Environment Requirements:** -- MinGW-w64 with g++ supporting C++11 and SSE4.2 -- CMake 3.16+ installed -- Git for Windows -- Boost 1.71+ built with specific configuration: `link=static threading=multi runtime-link=shared` -- OpenSSL for Windows (Win32OpenSSL) - -**Required Environment Variables:** -- `BOOST_ROOT`: Path to Boost installation (e.g., `C:\Boost`) -- `OPENSSL_ROOT_DIR`: Path to OpenSSL installation (e.g., `C:\OpenSSL-Win64`) - -**Optional Environment Variables:** -- `VIZ_BUILD_TYPE`: Release or Debug (default: Release) -- `VIZ_LOW_MEMORY`: ON or OFF (default: OFF) -- `VIZ_BUILD_TESTNET`: ON or OFF (default: OFF) -- `VIZ_FULL_STATIC`: ON or OFF (default: OFF, produces static exe) -- `VIZ_CMAKE_EXTRA`: Additional CMake options - -**Usage Examples:** -```cmd -REM Set environment variables -set BOOST_ROOT=C:\Boost -set OPENSSL_ROOT_DIR=C:\OpenSSL-Win64 - -REM Basic MinGW build -build-mingw.bat - -REM Full static build for distribution -set VIZ_FULL_STATIC=ON -build-mingw.bat - -REM Testnet build -set VIZ_BUILD_TESTNET=ON -build-mingw.bat -``` - -**Section sources** -- [build-mingw.bat:1-125](file://build-mingw.bat#L1-L125) - -### Windows MSVC Build Script (build-msvc.bat) -The `build-msvc.bat` script provides Visual Studio integration for Windows development: - -**Requirements:** -- Visual Studio 2019+ with "Desktop development with C++" workload -- CMake 3.16+ (installed or via VS CMake workload) -- Git for Windows -- Boost 1.71+ built with static linking configuration -- OpenSSL for Windows (Win32OpenSSL) - -**Environment Requirements:** -- Same as MinGW script: `BOOST_ROOT` and `OPENSSL_ROOT_DIR` environment variables -- Visual Studio generators available for CMake - -**Optional Environment Variables:** -- `VIZ_VS_VERSION`: Visual Studio generator version (default: "Visual Studio 17 2022") -- `VIZ_BUILD_TYPE`: Release or Debug (default: Release) -- `VIZ_LOW_MEMORY`: ON or OFF (default: OFF) -- `VIZ_BUILD_TESTNET`: ON or OFF (default: OFF) -- `VIZ_CMAKE_EXTRA`: Additional CMake options - -**Usage Examples:** -```cmd -REM Set environment variables -set BOOST_ROOT=C:\Boost -set OPENSSL_ROOT_DIR=C:\OpenSSL-Win64 - -REM Basic MSVC build -build-msvc.bat - -REM Specify Visual Studio version -set VIZ_VS_VERSION=Visual Studio 16 2019 -build-msvc.bat -``` - -**Section sources** -- [build-msvc.bat:1-116](file://build-msvc.bat#L1-L116) - -## Dependency Analysis -- Coupling: - - Top-level CMake depends on subproject CMakeLists.txt files to register targets - - configure_build.py depends on filesystem layout and optional environment variables for Boost/OpenSSL - - cat_parts.py depends on directory structure and file suffix filtering - - newplugin.py depends on the libraries/plugins directory layout - - Platform-specific build scripts depend on CMake configuration and system package managers -- External dependencies: - - Boost 1.71 (required), OpenSSL (optional), Readline (optional), ccache (optional), MongoDB drivers (optional) - - Platform-specific: Ubuntu/Fedora package managers, Homebrew, Visual Studio/MinGW toolchains -- Indirect dependencies: - - Plugins are discovered dynamically; their presence affects the build graph - - Platform scripts handle dependency installation automatically - -```mermaid -graph LR -CMakeTop["CMakeLists.txt"] -Libs["libraries/CMakeLists.txt"] -Plugins["plugins/CMakeLists.txt"] -Third["thirdparty/CMakeLists.txt"] -Progs["programs/CMakeLists.txt"] -CFGPy["configure_build.py"] -CATPy["cat_parts.py"] -NEWPy["newplugin.py"] -LinuxDeps["install-deps-linux.sh"] -LinuxBuild["build-linux.sh"] -MacScript["build-mac.sh"] -MinGWScript["build-mingw.bat"] -MSVCScript["build-msvc.bat"] -CMakeTop --> Libs -CMakeTop --> Plugins -CMakeTop --> Third -CMakeTop --> Progs -CFGPy --> CMakeTop -CATPy --> CMakeTop -NEWPy --> Libs -LinuxDeps --> LinuxBuild -LinuxBuild --> CMakeTop -MacScript --> CMakeTop -MinGWScript --> CMakeTop -MSVCScript --> CMakeTop -``` - -**Diagram sources** -- [CMakeLists.txt:206-209](file://CMakeLists.txt#L206-L209) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [programs/CMakeLists.txt:1-8](file://programs/CMakeLists.txt#L1-L8) -- [programs/build_helpers/configure_build.py:143-195](file://programs/build_helpers/configure_build.py#L143-L195) -- [programs/build_helpers/cat_parts.py:11-69](file://programs/build_helpers/cat_parts.py#L11-L69) -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) -- [install-deps-linux.sh:98-106](file://install-deps-linux.sh#L98-L106) -- [build-linux.sh:107-178](file://build-linux.sh#L107-L178) -- [build-mac.sh:125-171](file://build-mac.sh#L125-L171) -- [build-mingw.bat:32-56](file://build-mingw.bat#L32-L56) -- [build-msvc.bat:32-56](file://build-msvc.bat#L32-L56) - -**Section sources** -- [CMakeLists.txt:206-209](file://CMakeLists.txt#L206-L209) -- [programs/build_helpers/configure_build.py:143-195](file://programs/build_helpers/configure_build.py#L143-L195) -- [programs/build_helpers/cat_parts.py:11-69](file://programs/build_helpers/cat_parts.py#L11-L69) -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) -- [install-deps-linux.sh:98-106](file://install-deps-linux.sh#L98-L106) -- [build-linux.sh:107-178](file://build-linux.sh#L107-L178) -- [build-mac.sh:125-171](file://build-mac.sh#L125-L171) -- [build-mingw.bat:32-56](file://build-mingw.bat#L32-L56) -- [build-msvc.bat:32-56](file://build-msvc.bat#L32-L56) - -## Performance Considerations -- Compiler flags: - - Release builds use aggressive optimization for MinGW and Linux - - Debug builds define DEBUG and can be paired with coverage instrumentation when enabled -- Precompiled headers: - - USE_PCH enables cotire for faster incremental builds -- Static vs shared libraries: - - BUILD_SHARED_LIBRARIES defaults to off, reducing runtime dependencies and potentially improving startup performance -- Memory profile: - - LOW_MEMORY_NODE reduces storage overhead by excluding non-consensus data, beneficial for resource-constrained nodes -- Lock checking: - - CHAINBASE_CHECK_LOCKING can be disabled for production builds to reduce overhead -- ccache: - - Global launch wrappers accelerate rebuilds when available -- Platform-specific optimizations: - - Linux builds leverage system Boost 1.71+ packages for optimal performance - - macOS builds utilize Homebrew's optimized dependencies - - Windows builds support both static and dynamic linking configurations - -Practical implications: -- Choose Release for production builds to maximize runtime performance -- Disable CHAINBASE_CHECK_LOCKING and LOW_MEMORY_NODE unless required for specific roles -- Enable USE_PCH for faster local development cycles -- Use platform-specific build scripts for optimal dependency management and performance - -**Section sources** -- [CMakeLists.txt:144-152](file://CMakeLists.txt#L144-L152) -- [CMakeLists.txt:176-183](file://CMakeLists.txt#L176-L183) -- [CMakeLists.txt:51-53](file://CMakeLists.txt#L51-L53) -- [CMakeLists.txt:65-73](file://CMakeLists.txt#L65-L73) -- [CMakeLists.txt:75-80](file://CMakeLists.txt#L75-L80) -- [CMakeLists.txt:102-106](file://CMakeLists.txt#L102-L106) - -## Security Best Practices - -### Root Privilege Separation -The enhanced build system implements strict security boundaries: -- **install-deps-linux.sh**: Must run as root with explicit EUID validation -- **build-linux.sh**: Must run as regular user (refuses to run as root) -- **Automatic validation**: Both scripts verify they're in the correct directory structure - -### Enhanced Error Handling -- **Comprehensive validation**: All scripts validate inputs, dependencies, and environment variables -- **Color-coded logging**: Clear distinction between info, warning, and error messages -- **Graceful degradation**: Scripts handle missing optional dependencies gracefully -- **Clear error messages**: Specific guidance for resolving dependency issues - -### Secure Environment Setup -- **macOS**: Verifies Xcode Command Line Tools and Homebrew installation -- **Windows**: Validates environment variables and required tool availability -- **Linux**: Detects and installs appropriate package manager dependencies - -### Dependency Management Security -- **Package manager detection**: Automatically detects and uses appropriate package managers -- **Repository validation**: Ensures dependencies are installed from trusted repositories -- **Version validation**: Confirms minimum required versions for all dependencies - -**Section sources** -- [install-deps-linux.sh:28-31](file://install-deps-linux.sh#L28-L31) -- [build-linux.sh:57-61](file://build-linux.sh#L57-L61) -- [build-linux.sh:109-112](file://build-linux.sh#L109-L112) -- [build-mac.sh:102-115](file://build-mac.sh#L102-L115) - -## Troubleshooting Guide -Common issues and resolutions: - -### Enhanced Two-Script Build Process Issues -- **Root privilege errors**: `Do not run this script as root` - Use `sudo ./install-deps-linux.sh` for dependencies, then run `./build-linux.sh` as regular user -- **Dependency installation failures**: Check package manager logs and retry with `--no-cache` option in Docker environments -- **Permission errors**: Ensure proper file permissions and run scripts from repository root directory - -### Boost Version Issues -- **Problem**: Boost version below 1.71 -- **Solution**: Ensure Boost 1.71+ is installed via package manager or built from source -- **Platform-specific**: Ubuntu 24.04 provides Boost 1.74, macOS Homebrew provides recent versions, Windows requires manual installation - -### Dependency Installation Problems -- **Linux**: Package manager failures (apt/dnf) - verify internet connectivity and retry -- **macOS**: Homebrew installation issues - run `brew doctor` and fix any reported problems -- **Windows**: Missing Visual Studio/MinGW components - install required workloads and tools - -### Environment Variable Issues -- **Windows MinGW**: `BOOST_ROOT` and `OPENSSL_ROOT_DIR` must be set and point to valid installations -- **Windows MSVC**: Same environment variables required for Visual Studio builds -- **macOS**: OpenSSL path detection may fail - set `OPENSSL_ROOT_DIR` manually - -### Platform-Specific Issues -- **Linux**: Ensure system Boost 1.71+ packages are installed (coroutine, context components) -- **macOS**: Xcode Command Line Tools must be installed and accepted -- **Windows**: MinGW requires C++11 support and SSE4.2 capability - -### Build Script Issues -- **Permission errors**: Make scripts executable with `chmod +x install-deps-linux.sh build-linux.sh` or `build-*.bat` -- **Path issues**: Run scripts from repository root directory -- **Parallel job issues**: Adjust `-j` parameter based on available CPU cores - -**Updated** Enhanced Boost dependency requirements and platform-specific build script troubleshooting with new two-script architecture - -**Section sources** -- [install-deps-linux.sh:28-31](file://install-deps-linux.sh#L28-L31) -- [build-linux.sh:57-61](file://build-linux.sh#L57-L61) -- [build-linux.sh:109-112](file://build-linux.sh#L109-L112) -- [build-linux.sh:189-191](file://build-linux.sh#L189-L191) -- [build-mac.sh:102-115](file://build-mac.sh#L102-L115) -- [build-mac.sh:166-171](file://build-mac.sh#L166-L171) -- [build-mingw.bat:32-56](file://build-mingw.bat#L32-L56) -- [build-msvc.bat:32-56](file://build-msvc.bat#L32-L56) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) - -## Conclusion -The VIZ CPP Node build system has evolved significantly with the introduction of a secure, two-script architecture that enhances both security and reliability. The new `install-deps-linux.sh` script handles dependency installation with proper root privilege separation, while `build-linux.sh` provides a user-friendly build experience with comprehensive error handling and validation. The system continues to support Ubuntu 24.04+, macOS with Homebrew, and Windows with both MSVC and MinGW toolchains, all requiring Boost 1.71+ with mandatory coroutine component. Recent updates include upgrading to CMake 3.16, Boost 1.71, and adding coroutine component requirements. The platform-specific scripts handle dependency management, configuration, and building automatically, while the traditional CMake approach remains available for advanced users. Dockerfiles continue to streamline both development and production workflows with updated dependency specifications. By leveraging the appropriate build script for your platform and following the enhanced security practices, developers can quickly set up consistent builds with optimal performance characteristics and improved security boundaries. - -## Appendices - -### Practical Build Scenarios - -#### Enhanced Linux Development Build -```bash -# Clone repository -git clone --recursive https://github.com/VIZ-Blockchain/viz-cpp-node -cd viz-cpp-node - -# Install dependencies (requires root) -chmod +x install-deps-linux.sh -sudo ./install-deps-linux.sh - -# Make build script executable -chmod +x build-linux.sh - -# Basic development build (runs as user) -./build-linux.sh - -# Low memory node for validator operations -./build-linux.sh -l - -# Testnet build -./build-linux.sh -n - -# Debug build with custom jobs -./build-linux.sh -t Debug -j 4 -``` - -#### macOS Development Build -```bash -# Clone repository -git clone --recursive https://github.com/VIZ-Blockchain/viz-cpp-node -cd viz-cpp-node - -# Make script executable -chmod +x build-mac.sh - -# Basic macOS build -./build-mac.sh - -# Custom Boost path -./build-mac.sh --boost-root /opt/boost_1_74_0 - -# Skip dependencies if already installed -./build-mac.sh --skip-deps -``` - -#### Windows MinGW Build -```cmd -REM Set environment variables -set BOOST_ROOT=C:\Boost -set OPENSSL_ROOT_DIR=C:\OpenSSL-Win64 - -REM Basic MinGW build -build-mingw.bat - -REM Full static build for distribution -set VIZ_FULL_STATIC=ON -build-mingw.bat - -REM Testnet configuration -set VIZ_BUILD_TESTNET=ON -build-mingw.bat -``` - -#### Windows MSVC Build -```cmd -REM Set environment variables -set BOOST_ROOT=C:\Boost -set OPENSSL_ROOT_DIR=C:\OpenSSL-Win64 - -REM Basic MSVC build -build-msvc.bat - -REM Specify Visual Studio version -set VIZ_VS_VERSION=Visual Studio 16 2019 -build-msvc.bat -``` - -#### Advanced CMake Configuration -```bash -# Traditional CMake approach with configure_build.py -python3 programs/build_helpers/configure_build.py --release --src ../.. - -# Cross-compilation for Windows using MinGW -python3 programs/build_helpers/configure_build.py --win --release - -# Custom Boost and OpenSSL paths -python3 programs/build_helpers/configure_build.py --boost-dir /opt/boost_1_74_0 --openssl-dir /opt/openssl --release -``` - -**Updated** Enhanced platform-specific build script usage examples and advanced configuration options with new two-script architecture - -**Section sources** -- [install-deps-linux.sh:108-113](file://install-deps-linux.sh#L108-L113) -- [build-linux.sh:189-191](file://build-linux.sh#L189-L191) -- [build-mac.sh:330-351](file://build-mac.sh#L330-L351) -- [build-mingw.bat:12-22](file://build-mingw.bat#L12-L22) -- [build-msvc.bat:12-22](file://build-msvc.bat#L12-L22) -- [programs/build_helpers/configure_build.py:168-184](file://programs/build_helpers/configure_build.py#L168-L184) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Build Targets.md b/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Build Targets.md deleted file mode 100644 index dfa4ce8d6d..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Build Targets.md +++ /dev/null @@ -1,526 +0,0 @@ -# Build Targets - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [programs/CMakeLists.txt](file://programs/CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt) -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt) -- [programs/build_helpers/CMakeLists.txt](file://programs/build_helpers/CMakeLists.txt) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document describes the build targets for the VIZ CPP Node CMake configuration. It focuses on the main executables (vizd, cli_wallet, js_operation_serializer), library targets (libraries/*), plugin targets (plugins/*), and supporting utilities. It also covers static vs shared library compilation, test-related options, installation targets, and platform-specific considerations. The goal is to help developers customize the build scope for efficient development workflows. - -## Project Structure -The top-level CMake configuration orchestrates subdirectories for third-party dependencies, libraries, plugins, and programs. Library and plugin targets are built conditionally based on shared/static selection and optional features. - -```mermaid -graph TB -Root["Root CMakeLists.txt"] -ThirdParty["thirdparty (external deps)"] -Libs["libraries/ (CMakeLists.txt)"] -Plugins["plugins/ (CMakeLists.txt)"] -Programs["programs/ (CMakeLists.txt)"] -Root --> ThirdParty -Root --> Libs -Root --> Plugins -Root --> Programs -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt](file://programs/CMakeLists.txt#L1-L8) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [programs/CMakeLists.txt](file://programs/CMakeLists.txt#L1-L8) - -## Core Components -This section summarizes the primary build targets and their roles. - -- Executables - - vizd: Full node executable with numerous internal plugins linked statically by default. - - cli_wallet: Command-line wallet application linking against chain, protocol, utilities, and wallet libraries plus selected plugins. - - js_operation_serializer: Operation serialization tool for JavaScript consumers. -- Libraries - - libraries/chain, api, protocol, network, utilities, wallet: Core libraries compiled either as static or shared depending on BUILD_SHARED_LIBRARIES. -- Plugins - - plugins/*: Dynamically loaded modules compiled as static or shared per BUILD_SHARED_LIBRARIES; discovery via globbing. -- Utilities - - programs/util/*: Developer and testing utilities (signing, block log tests, etc.). - -Key configuration toggles: -- BUILD_SHARED_LIBRARIES: Controls whether libraries are built as static or shared. -- ENABLE_MONGO_PLUGIN: Enables MongoDB plugin linkage and defines a preprocessor macro. -- BUILD_TESTNET: Adds a preprocessor definition for testnet builds. -- LOW_MEMORY_NODE: Adds a preprocessor definition for low-memory builds. -- CHAINBASE_CHECK_LOCKING: Adds a preprocessor definition enabling chainbase locking checks. -- USE_PCH: Optional precompiled header support via cotire. -- FULL_STATIC_BUILD: Platform-specific static linking flags for MinGW/MSVC. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L52-L89) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L16-L124) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L28-L49) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L40-L57) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L24-L44) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L22-L31) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L38-L70) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) - -## Architecture Overview -The build architecture links applications to libraries and plugins. vizd links to many internal plugins and core libraries. cli_wallet links to core libraries and selected plugins. js_operation_serializer links to minimal core libraries. - -```mermaid -graph TB -subgraph "Applications" -VIZD["vizd"] -CLI["cli_wallet"] -SER["js_operation_serializer"] -end -subgraph "Core Libraries" -Chain["graphene_chain"] -Protocol["graphene_protocol"] -Network["graphene_network"] -Utilities["graphene_utilities"] -Wallet["graphene_wallet"] -Api["graphene_api"] -end -subgraph "Plugins" -PChain["graphene::chain_plugin"] -PWeb["graphene::webserver_plugin"] -PJson["graphene::json_rpc"] -PWitness["graphene::validator"] -PTags["graphene::tags"] -PFollow["graphene::follow"] -PCommittee["graphene::committee_api"] -PMongo["graphene::mongo_db (optional)"] -end -VIZD --> PChain -VIZD --> PWeb -VIZD --> PWitness -VIZD --> PTags -VIZD --> PFollow -VIZD --> PCommittee -VIZD --> PMongo -VIZD --> Chain -VIZD --> Protocol -VIZD --> Utilities -VIZD --> Network -VIZD --> Api -CLI --> Chain -CLI --> Protocol -CLI --> Utilities -CLI --> Wallet -CLI --> Api -SER --> Chain -SER --> Protocol -SER --> Utilities -``` - -**Diagram sources** -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L21-L41) -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt#L6-L7) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L126-L128) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L43-L49) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L55-L57) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L31) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt#L26-L33) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt#L26-L32) - -## Detailed Component Analysis - -### vizd (Full Node Executable) -- Purpose: The primary node executable with a broad set of enabled plugins. -- Linkage: Links to appbase, webserver plugin, p2p, chain plugin, network broadcast API, validator, validator API, database API, test API, social network, tags, operation history, account by key, account history, private message, auth utility, debug node, raw block, block info, JSON RPC, follow, committee API, invite API, paid subscription API, custom protocol API, and optionally MongoDB plugin. Also links to protocol, fc, and platform-specific libraries. -- Installation: Installable under bin with standard DESTINATION entries. -- Platform specifics: - - UNIX (non-Apple): Links to rt if found. - - Apple: Links to readline if found. - - Gperftools detection: If found, links to tcmalloc. -- Static vs shared: Libraries are controlled by BUILD_SHARED_LIBRARIES; vizd itself is an executable. - -```mermaid -sequenceDiagram -participant CMake as "CMake" -participant VIZD as "vizd target" -participant Libs as "Core Libraries" -participant Plugs as "Internal Plugins" -CMake->>VIZD : "add_executable(vizd)" -VIZD->>Plugs : "link graphene : : webserver_plugin" -VIZD->>Plugs : "link graphene : : p2p" -VIZD->>Plugs : "link graphene : : chain_plugin" -VIZD->>Plugs : "link graphene : : network_broadcast_api" -VIZD->>Plugs : "link graphene : : validator" -VIZD->>Plugs : "link graphene : : witness_api" -VIZD->>Plugs : "link graphene : : database_api" -VIZD->>Plugs : "link graphene : : test_api_plugin" -VIZD->>Plugs : "link graphene : : social_network" -VIZD->>Plugs : "link graphene : : tags" -VIZD->>Plugs : "link graphene : : operation_history" -VIZD->>Plugs : "link graphene : : account_by_key" -VIZD->>Plugs : "link graphene : : account_history" -VIZD->>Plugs : "link graphene : : private_message" -VIZD->>Plugs : "link graphene : : auth_util" -VIZD->>Plugs : "link graphene : : debug_node" -VIZD->>Plugs : "link graphene : : raw_block" -VIZD->>Plugs : "link graphene : : block_info" -VIZD->>Plugs : "link graphene : : json_rpc" -VIZD->>Plugs : "link graphene : : follow" -VIZD->>Plugs : "link graphene : : committee_api" -VIZD->>Plugs : "link graphene : : invite_api" -VIZD->>Plugs : "link graphene : : paid_subscription_api" -VIZD->>Plugs : "link graphene : : custom_protocol_api" -VIZD->>Libs : "link graphene_protocol, fc" -VIZD-->>CMake : "install(TARGETS vizd ...)" -``` - -**Diagram sources** -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L1-L58) - -**Section sources** -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L1-L58) - -### cli_wallet (Command-Line Wallet) -- Purpose: A command-line wallet for interacting with the node. -- Linkage: Links to graphene_network, graphene_chain, graphene_protocol, graphene_utilities, graphene_wallet, and several API plugins (database_api, account_history, social_network, private_message, follow, network_broadcast_api, witness_api). Also links to fc, readline (on Apple), dl libs, platform-specific libs, and Boost regex. -- Installation: Installable under bin with standard DESTINATION entries. -- Platform specifics: - - UNIX (non-Apple): Links to rt if found. - - Apple: Links to readline if found. - - Gperftools detection: If found, links to tcmalloc. - - MSVC: Applies /bigobj to main.cpp. - -```mermaid -sequenceDiagram -participant CMake as "CMake" -participant CLI as "cli_wallet target" -participant Libs as "Core Libraries" -participant Plugs as "Selected Plugins" -CMake->>CLI : "add_executable(cli_wallet)" -CLI->>Libs : "link graphene_network" -CLI->>Libs : "link graphene_chain" -CLI->>Libs : "link graphene_protocol" -CLI->>Libs : "link graphene_utilities" -CLI->>Libs : "link graphene_wallet" -CLI->>Plugs : "link graphene : : database_api" -CLI->>Plugs : "link graphene : : account_history" -CLI->>Plugs : "link graphene : : social_network" -CLI->>Plugs : "link graphene : : private_message" -CLI->>Plugs : "link graphene : : follow" -CLI->>Plugs : "link graphene : : network_broadcast_api" -CLI->>Plugs : "link graphene : : witness_api" -CLI->>Libs : "link fc" -CLI-->>CMake : "install(TARGETS cli_wallet ...)" -``` - -**Diagram sources** -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L1-L54) - -**Section sources** -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L1-L54) - -### js_operation_serializer (Operation Serialization Tool) -- Purpose: Generates serialized operation schemas for JavaScript. -- Linkage: Minimal linkage to graphene_chain, graphene_protocol, graphene_utilities, and fc with dl libs and platform-specific libs. -- Installation: Installable under bin with standard DESTINATION entries. - -```mermaid -sequenceDiagram -participant CMake as "CMake" -participant SER as "js_operation_serializer target" -participant Libs as "Core Libraries" -CMake->>SER : "add_executable(js_operation_serializer)" -SER->>Libs : "link graphene_chain" -SER->>Libs : "link graphene_protocol" -SER->>Libs : "link graphene_utilities" -SER->>Libs : "link fc" -SER-->>CMake : "install(TARGETS js_operation_serializer ...)" -``` - -**Diagram sources** -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt#L1-L16) - -**Section sources** -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt#L1-L16) - -### Library Targets (libraries/*) -- graphene_chain - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on graphene_protocol, graphene_utilities, fc, chainbase, appbase. - - Includes generated hardfork.hpp via a custom target. - - MSVC: Applies /bigobj to database.cpp. -- graphene_api - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on graphene_chain, graphene_protocol, graphene_utilities, fc. -- graphene_protocol - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on fc; includes version headers. -- graphene_network - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on fc and graphene_protocol; supports PCH via cotire if enabled. - - MSVC: Applies /bigobj to node.cpp. -- graphene_utilities - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on fc; generates git_revision.cpp via configure_file. - - Supports PCH via cotire if enabled. -- graphene_wallet - - Static or shared based on BUILD_SHARED_LIBRARIES. - - Depends on multiple API plugins and core libraries; supports PCH via cotire if enabled. - - MSVC: Applies /bigobj to wallet.cpp. - -```mermaid -classDiagram -class Chain["graphene_chain"] -class Api["graphene_api"] -class Protocol["graphene_protocol"] -class Network["graphene_network"] -class Utilities["graphene_utilities"] -class Wallet["graphene_wallet"] -Chain --> Protocol : "depends on" -Chain --> Utilities : "depends on" -Chain --> Network : "generated header" -Api --> Chain : "depends on" -Api --> Protocol : "depends on" -Api --> Utilities : "depends on" -Protocol --> Utilities : "depends on" -Network --> Protocol : "depends on" -Network --> Utilities : "depends on" -Wallet --> Network : "depends on" -Wallet --> Chain : "depends on" -Wallet --> Protocol : "depends on" -Wallet --> Utilities : "depends on" -``` - -**Diagram sources** -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L126-L128) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L43-L49) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L55-L57) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L31) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) - -**Section sources** -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L16-L142) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L28-L60) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L40-L70) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L24-L64) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L22-L47) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L38-L85) - -### Plugin Targets (plugins/*) -Plugin discovery is automated via globbing over plugin directories. Each plugin target is built as static or shared according to BUILD_SHARED_LIBRARIES and exposes an alias graphene::. - -- Example: chain plugin - - Provides graphene::chain_plugin alias. - - Depends on graphene_chain, graphene_protocol, fc, appbase, and json_rpc. -- Example: webserver plugin - - Provides graphene::webserver_plugin alias. - - Depends on graphene::json_rpc, graphene_chain, graphene::chain_plugin, appbase, fc. - -```mermaid -flowchart TD -Scan["Scan plugins/*"] --> Found{"Has CMakeLists.txt?"} -Found --> |Yes| Add["add_subdirectory(plugin)"] -Found --> |No| Skip["Skip"] -Add --> Target["graphene:: (STATIC|SHARED)"] -Target --> Alias["ALIAS graphene::"] -Alias --> Link["Link dependencies"] -``` - -**Diagram sources** -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt#L10-L33) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt#L11-L32) - -**Section sources** -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt#L1-L12) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt#L1-L44) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt#L1-L43) - -### Utility Programs (programs/util/*) -- get_dev_key, test_shared_mem, sign_digest, sign_transaction, test_block_log: Each links to core libraries and installs under bin. - -```mermaid -graph LR -Util["programs/util/CMakeLists.txt"] -GD["get_dev_key"] -TSM["test_shared_mem"] -SD["sign_digest"] -ST["sign_transaction"] -TBL["test_block_log"] -Util --> GD -Util --> TSM -Util --> SD -Util --> ST -Util --> TBL -``` - -**Diagram sources** -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) - -**Section sources** -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) - -### Build Helpers (programs/build_helpers) -- cat-parts: A small helper tool linking to fc and platform libs. - -**Section sources** -- [programs/build_helpers/CMakeLists.txt](file://programs/build_helpers/CMakeLists.txt#L1-L8) - -## Dependency Analysis -This section maps how targets depend on each other and external libraries. - -```mermaid -graph TB -Root["Root CMakeLists.txt"] -Libs["libraries/*"] -Plugins["plugins/*"] -Progs["programs/*"] -Root --> Libs -Root --> Plugins -Root --> Progs -subgraph "Programs" -VIZD["vizd"] -CLI["cli_wallet"] -SER["js_operation_serializer"] -UTIL["programs/util/*"] -end -subgraph "Libraries" -Chain["graphene_chain"] -Protocol["graphene_protocol"] -Network["graphene_network"] -Utilities["graphene_utilities"] -Wallet["graphene_wallet"] -Api["graphene_api"] -end -subgraph "Plugins" -PChain["graphene::chain_plugin"] -PWeb["graphene::webserver_plugin"] -PJson["graphene::json_rpc"] -end -VIZD --> Chain -VIZD --> Protocol -VIZD --> Network -VIZD --> Utilities -VIZD --> Api -VIZD --> PChain -VIZD --> PWeb -VIZD --> PJson -CLI --> Chain -CLI --> Protocol -CLI --> Utilities -CLI --> Wallet -CLI --> Api -CLI --> PJson -SER --> Chain -SER --> Protocol -SER --> Utilities -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L21-L41) -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt#L6-L7) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L126-L128) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L43-L49) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L55-L57) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L31) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt#L26-L33) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt#L26-L32) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L21-L41) -- [programs/js_operation_serializer/CMakeLists.txt](file://programs/js_operation_serializer/CMakeLists.txt#L6-L7) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L126-L128) -- [libraries/api/CMakeLists.txt](file://libraries/api/CMakeLists.txt#L43-L49) -- [libraries/protocol/CMakeLists.txt](file://libraries/protocol/CMakeLists.txt#L55-L57) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/utilities/CMakeLists.txt](file://libraries/utilities/CMakeLists.txt#L31) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt#L50-L70) -- [plugins/chain/CMakeLists.txt](file://plugins/chain/CMakeLists.txt#L26-L33) -- [plugins/webserver/CMakeLists.txt](file://plugins/webserver/CMakeLists.txt#L26-L32) - -## Performance Considerations -- Precompiled Headers (PCH): Optional cotire support exists for some libraries (e.g., network, utilities) to speed up compilation. Enable via USE_PCH. -- Compiler flags: - - Windows (MSVC): Applies /wd4503, /wd4267, /wd4244 warnings suppressions and /SAFESEH:NO linker flags; Debug adds /DEBUG. - - MinGW: Uses -std=c++11, -fpermissive, -msse4.2, -Wa,-mbig-obj; Debug optimized to -O2; Release to -O3; optional static linking flags via FULL_STATIC_BUILD. - - Clang on macOS: -stdlib=libc++; Ninja generator adds -fcolor-diagnostics; enables -DDEBUG in Debug. - - GCC on Linux: Adds -fno-builtin-memcmp; Ninja adds -fcolor-diagnostics; enables -DDEBUG in Debug; optional static linking flags via FULL_STATIC_BUILD. -- Memory profiling: Gperftools detection enables tcmalloc linkage for vizd and cli_wallet when available. -- Coverage: ENABLE_COVERAGE_TESTING toggles --coverage in CXX flags. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L123-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L166-L202) -- [CMakeLists.txt](file://CMakeLists.txt#L206-L208) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L10-L14) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L10-L14) - -## Troubleshooting Guide -- Boost static/shared linkage: - - Boost_USE_STATIC_LIBS defaults to TRUE globally. - - On Windows, BOOST_ALL_DYN_LINK is OFF to force static linking; ensure compatible Boost libraries. -- MongoDB plugin: - - ENABLE_MONGO_PLUGIN adds graphene::mongo_db to vizd and defines DMONGODB_PLUGIN_BUILT macros. -- Testnet and Low-Memory: - - BUILD_TESTNET and LOW_MEMORY_NODE inject -DBUILD_TESTNET and -DIS_LOW_MEM respectively. -- Chainbase locking checks: - - CHAINBASE_CHECK_LOCKING adds -DCHAINBASE_CHECK_LOCKING when enabled. -- Hardfork header generation: - - chain library depends on a generated hardfork.hpp via a custom target; ensure cat-parts is available on Windows or Python-based script on Unix-like systems. -- Platform-specific libraries: - - UNIX (non-Apple): rt library linkage. - - Apple: readline linkage. - - dl libs automatically linked via ${CMAKE_DL_LIBS}. -- Static vs shared: - - BUILD_SHARED_LIBRARIES controls library type for libraries/* and plugins/*. - - FULL_STATIC_BUILD toggles static linking flags for MinGW/MSVC. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L52-L89) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L158-L202) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L1-L9) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L4-L8) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt#L2-L8) - -## Conclusion -The VIZ CPP Node build system organizes targets into libraries, plugins, and applications. Libraries support both static and shared modes controlled by BUILD_SHARED_LIBRARIES. Applications link to core libraries and selected plugins, with platform-specific optimizations and optional features like MongoDB plugin, testnet/low-memory configurations, and PCH support. Developers can tailor builds by toggling options and selectively enabling/disabling components. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/CMake Configuration.md b/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/CMake Configuration.md deleted file mode 100644 index fd9799f367..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/CMake Configuration.md +++ /dev/null @@ -1,381 +0,0 @@ -# CMake Configuration - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testing.md](file://documentation/testing.md) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the CMake configuration for the VIZ CPP Node, focusing on the top-level CMake project setup, compiler requirements, platform-specific configurations, build options, Boost library configuration, compiler flags, and practical CMake invocation examples. It also covers how options affect compilation flags and feature availability, and provides troubleshooting guidance for common build issues. - -## Project Structure -The build system is organized around a top-level CMake project that orchestrates subprojects: -- Top-level project defines compiler requirements, options, and platform flags. -- Subprojects include thirdparty libraries, internal libraries, plugins, and programs. -- Platform-specific logic configures flags for Windows, macOS, and Linux. -- Optional MongoDB plugin integrates via dedicated CMake logic gated by an option. - -```mermaid -graph TB -Root["Top-level CMakeLists.txt
Defines project, options, platform flags"] --> ThirdParty["thirdparty/<...>
Subproject"] -Root --> Libraries["libraries/<...>
Subproject"] -Root --> Plugins["plugins/<...>
Subproject"] -Root --> Programs["programs/<...>
Subproject"] -subgraph "Plugins" -Mongo["plugins/mongo_db/CMakeLists.txt
Conditional MongoDB plugin build"] -end -subgraph "Programs" -Vizd["programs/vizd/CMakeLists.txt
Links to enabled plugins and libs"] -end -Plugins --> Mongo -Programs --> Vizd -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L1-L58) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) - -## Core Components -This section documents the primary CMake configuration elements defined in the top-level CMakeLists.txt. - -- Project setup and minimum CMake version - - The project is named and requires a minimum CMake version. - - Compiler requirement enforcement for GCC and Clang is performed early in configuration. - -- Build options and their effects - - BUILD_TESTNET: Adds preprocessor definitions enabling testnet-specific code paths. - - LOW_MEMORY_NODE: Adds preprocessor definitions enabling low-memory node behavior. - - CHAINBASE_CHECK_LOCKING: Adds preprocessor definitions enabling chainbase locking checks. - - ENABLE_MONGO_PLUGIN: Enables MongoDB plugin build and adds a preprocessor definition; links the plugin target when found. - -- Boost library configuration - - Declares required Boost components. - - Forces static Boost usage by default. - - Adjusts Windows-specific Boost settings and handles coroutine component detection. - - Requires a minimum Boost version and locates Boost with COMPONENTS. - -- Platform-specific configurations - - Windows (MSVC/MINGW): Applies Windows-specific compiler and linker flags, TLS/CCache integration, and TCL library discovery. - - macOS: Uses C++ standard and libc++, sets warning flags, and applies platform-specific behavior. - - Linux: Uses C++ standard, sets warning flags, locates readline, and applies platform-specific libraries. - -- Compiler flags and optimization - - Sets C++ standard per platform. - - Configures debug and release flags, including debug macro definitions. - - Adds coverage flags when enabled. - - Uses ccache when detected. - -- Subproject inclusion - - Includes thirdparty, libraries, plugins, and programs subdirectories. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) - -## Architecture Overview -The CMake configuration enforces compiler requirements, exposes build options, configures platform flags, locates dependencies, and wires subprojects together. The MongoDB plugin is conditionally included and linked into the node executable when enabled. - -```mermaid -graph TB -A["CMakeLists.txt
Compiler checks, options, platform flags"] --> B["Boost
Components and linkage"] -A --> C["Compiler Flags
Per-platform"] -A --> D["Options
BUILD_TESTNET, LOW_MEMORY_NODE,
CHAINBASE_CHECK_LOCKING, ENABLE_MONGO_PLUGIN"] -D --> E["plugins/mongo_db/CMakeLists.txt
Conditional plugin build"] -A --> F["Subprojects
thirdparty, libraries, plugins, programs"] -F --> G["programs/vizd/CMakeLists.txt
Executable and link targets"] -E --> G -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L38-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L112-L202) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) - -## Detailed Component Analysis - -### Compiler Requirements and Toolchain -- GCC minimum version enforced during configuration. -- Clang minimum version enforced during configuration. -- Early failure if requirements are not met prevents downstream build issues. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L12-L20) - -### Build Options and Feature Flags -- BUILD_TESTNET - - Adds preprocessor definitions for both C and C++. - - Prints configuration status and final mode selection. -- LOW_MEMORY_NODE - - Adds preprocessor definitions for both C and C++. - - Prints configuration status and final mode selection. -- CHAINBASE_CHECK_LOCKING - - Adds preprocessor definitions for both C and C++. -- ENABLE_MONGO_PLUGIN - - Enables MongoDB plugin build and adds a preprocessor definition. - - Links the plugin target into dependent executables. - -```mermaid -flowchart TD -Start(["Configure"]) --> CheckOptions["Evaluate Options:
BUILD_TESTNET, LOW_MEMORY_NODE,
CHAINBASE_CHECK_LOCKING, ENABLE_MONGO_PLUGIN"] -CheckOptions --> Testnet{"BUILD_TESTNET?"} -Testnet --> |Yes| AddDef1["Add -DBUILD_TESTNET to C/C++ flags"] -Testnet --> |No| Skip1["Skip"] -LowMem{"LOW_MEMORY_NODE?"} -LowMem --> |Yes| AddDef2["Add -DIS_LOW_MEM to C/C++ flags"] -LowMem --> |No| Skip2["Skip"] -Locking{"CHAINBASE_CHECK_LOCKING?"} -Locking --> |Yes| AddDef3["Add -DCHAINBASE_CHECK_LOCKING to C/C++ flags"] -Locking --> |No| Skip3["Skip"] -Mongo{"ENABLE_MONGO_PLUGIN?"} -Mongo --> |Yes| AddDef4["Add -DMONGODB_PLUGIN_BUILT to C/C++ flags"] -Mongo --> |No| Skip4["Skip"] -AddDef1 --> End(["Proceed"]) -AddDef2 --> End -AddDef3 --> End -AddDef4 --> End -Skip1 --> End -Skip2 --> End -Skip3 --> End -Skip4 --> End -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) - -### Boost Library Configuration -- Declares required components and forces static usage by default. -- On Windows, sets multithreading and disables automatic dynamic linking. -- Locates Boost with a minimum version and augments with coroutine when available. - -```mermaid -flowchart TD -S(["Find Boost"]) --> SetStatic["Set static usage"] -SetStatic --> WinCheck{"Windows?"} -WinCheck --> |Yes| WinFlags["Enable multithreading and disable automatic dynamic linking"] -WinCheck --> |No| SkipWin["Skip"] -S --> FindBoost["Find Boost with required components"] -FindBoost --> VersionCheck{"Boost version != 1.53.x?"} -VersionCheck --> |Yes| AddCoroutine["Find coroutine component and append to libraries"] -VersionCheck --> |No| SkipCoro["Skip"] -WinFlags --> End(["Continue"]) -SkipWin --> End -AddCoroutine --> End -SkipCoro --> End -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L104) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L104) - -### Platform-Specific Configurations -- Windows (MSVC/MINGW) - - Adds MSVC warnings suppressions and linker flags. - - Ensures debug info presence in Debug configuration. - - Detects and configures TCL library for Windows toolchains. - - Applies C++11 flags and optimizations for MinGW. -- macOS - - Uses C++ standard and libc++. - - Applies warning flags and macOS-specific behavior. -- Linux - - Uses C++ standard and warning flags. - - Locates readline and sets platform-specific libraries. - - Supports static linking when requested. - -```mermaid -flowchart TD -PStart(["Platform Detection"]) --> Win{"WIN32?"} -Win --> |Yes| WConf["Apply Windows flags and linker settings"] -Win --> |No| UnixCheck{"APPLE?"} -UnixCheck --> |Yes| MacConf["Apply macOS flags and settings"] -UnixCheck --> |No| LinConf["Apply Linux flags and settings"] -WConf --> PEnd(["Done"]) -MacConf --> PEnd -LinConf --> PEnd -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L112-L202) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L112-L202) - -### Compiler Flags, Optimization, and Debug/Release -- Debug and Release configurations receive distinct flags. -- Debug configuration adds a debug macro. -- Coverage testing can be enabled to inject coverage flags. -- Ninja generator receives color diagnostics for Clang. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L196-L208) -- [CMakeLists.txt](file://CMakeLists.txt#L190-L194) - -### MongoDB Plugin Integration -- When enabled, the plugin is discovered and built conditionally. -- The plugin target is linked into the node executable. -- Preprocessor definitions enable MongoDB-related code paths. - -```mermaid -sequenceDiagram -participant Root as "Root CMakeLists.txt" -participant MongoCMake as "plugins/mongo_db/CMakeLists.txt" -participant Vizd as "programs/vizd/CMakeLists.txt" -Root->>Root : Evaluate ENABLE_MONGO_PLUGIN -alt Enabled -Root->>MongoCMake : Include plugin build logic -MongoCMake->>MongoCMake : Find MongoDB driver libraries -MongoCMake-->>Root : Define MONGO_LIB target -Root->>Vizd : Link MONGO_LIB into vizd -else Disabled -Root->>Vizd : Skip MongoDB linkage -end -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L44-L44) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L44-L44) - -## Dependency Analysis -The build system composes the final executable by linking together appbase, internal libraries, enabled plugins, and platform-specific libraries. The MongoDB plugin target is conditionally included when enabled. - -```mermaid -graph LR -Vizd["vizd Executable"] --> AppBase["appbase"] -Vizd --> WebServer["graphene::webserver_plugin"] -Vizd --> P2P["graphene::p2p"] -Vizd --> Utilities["graphene_utilities"] -Vizd --> ChainPlugin["graphene::chain_plugin"] -Vizd --> NetworkBroadcast["graphene::network_broadcast_api"] -Vizd --> validator["graphene::validator"] -Vizd --> WitnessApi["graphene::witness_api"] -Vizd --> DatabaseApi["graphene::database_api"] -Vizd --> TestApi["graphene::test_api_plugin"] -Vizd --> SocialNetwork["graphene::social_network"] -Vizd --> Tags["graphene::tags"] -Vizd --> OperationHistory["graphene::operation_history"] -Vizd --> AccountByKey["graphene::account_by_key"] -Vizd --> AccountHistory["graphizen::account_history"] -Vizd --> PrivateMessage["graphene::private_message"] -Vizd --> AuthUtil["graphene::auth_util"] -Vizd --> DebugNode["graphene::debug_node"] -Vizd --> RawBlock["graphene::raw_block"] -Vizd --> BlockInfo["graphene::block_info"] -Vizd --> JsonRpc["graphene::json_rpc"] -Vizd --> Follow["graphene::follow"] -Vizd --> CommitteeApi["graphene::committee_api"] -Vizd --> InviteApi["graphene::invite_api"] -Vizd --> PaidSubscriptionApi["graphene::paid_subscription_api"] -Vizd --> CustomProtocolApi["graphene::custom_protocol_api"] -Vizd --> MongoLib["MONGO_LIB (optional)"] -Vizd --> Protocol["graphene_protocol"] -Vizd --> FC["fc"] -Vizd --> DL["CMAKE_DL_LIBS"] -Vizd --> Readline["readline (optional)"] -``` - -**Diagram sources** -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) - -**Section sources** -- [programs/vizd/CMakeLists.txt](file://programs/vizd/CMakeLists.txt#L16-L49) - -## Performance Considerations -- Static vs shared libraries - - Static libraries are default; shared libraries can be enabled via an option. -- Coverage testing - - Coverage flags can be injected when coverage testing is enabled. -- ccache - - When detected, ccache is configured globally for compile and link steps to speed up rebuilds. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L54-L54) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [CMakeLists.txt](file://CMakeLists.txt#L106-L110) - -## Troubleshooting Guide -- Compiler version mismatch - - Ensure GCC meets the minimum version requirement or Clang meets its requirement; otherwise configuration fails early. -- Boost version and components - - Verify Boost version meets the minimum requirement and that all declared components are available. - - On Windows, ensure Boost static usage is appropriate for your toolchain. -- Missing MongoDB drivers - - When the MongoDB plugin is enabled, driver libraries must be discoverable; otherwise the plugin build is skipped. -- Platform-specific issues - - Windows: Confirm toolchain compatibility and linker flags; ensure debug info is emitted in Debug configuration. - - macOS: Confirm C++ standard and libc++ usage. - - Linux: Confirm readline availability and platform-specific libraries. -- Static linking - - Static builds require compatible static variants of all dependencies; adjust flags accordingly. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L15-L22) -- [CMakeLists.txt](file://CMakeLists.txt#L112-L202) - -## Conclusion -The VIZ CPP Node’s CMake configuration enforces compiler requirements, exposes configurable build options, and adapts to Windows, macOS, and Linux environments. By leveraging options like BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, and ENABLE_MONGO_PLUGIN, developers can tailor builds for different deployment scenarios. Correct Boost configuration and platform-specific flags ensure reliable builds across environments. - -## Appendices - -### Practical CMake Invocation Examples -- Development build (Linux/macOS) - - Configure with Release and enable shared libraries if desired. - - Example invocation: cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBRARIES=FALSE .. -- Production build (Linux) - - Use Release, disable extra checks, and disable MongoDB plugin. - - Example invocation: cmake -DCMAKE_BUILD_TYPE=Release -DLOW_MEMORY_NODE=FALSE -DCHAINBASE_CHECK_LOCKING=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. -- Testnet build (Linux) - - Enable testnet mode and Release configuration. - - Example invocation: cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=TRUE .. -- Coverage build (Linux) - - Enable coverage and Debug build type. - - Example invocation: cmake -DENABLE_COVERAGE_TESTING=true -DCMAKE_BUILD_TYPE=Debug .. - -These examples align with documented defaults and options. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L5-L9) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L53) -- [documentation/testing.md](file://documentation/testing.md#L30-L32) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Core Build Options.md b/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Core Build Options.md deleted file mode 100644 index 7210dbb231..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Core Build Options.md +++ /dev/null @@ -1,343 +0,0 @@ -# Core Build Options - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the core build options and flags that control VIZ CPP Node compilation and runtime behavior. It focuses on four primary options: -- BUILD_TESTNET: Enables test network compilation and configuration. -- LOW_MEMORY_NODE: Optimizes the node for reduced memory usage. -- CHAINBASE_CHECK_LOCKING: Enables chainbase locking correctness checks. -- ENABLE_MONGO_PLUGIN: Compiles the MongoDB integration plugin. - -For each option, this guide describes how it affects compiler flags, feature availability, and runtime behavior, and provides practical CMake invocation examples for development, testing, and production scenarios. It also documents how these options influence the resulting executables, shared libraries, and plugin availability. - -## Project Structure -The build system is orchestrated from the repository’s root CMake configuration. Key areas involved in build option handling and downstream effects include: -- Root CMake configuration that defines and applies the build options. -- Protocol configuration headers that switch constants and behavior for mainnet vs. testnet. -- Plugin build configuration for MongoDB integration. -- Dockerfiles demonstrating typical option combinations for different environments. - -```mermaid -graph TB -A["Root CMakeLists.txt
Defines build options and flags"] --> B["Protocol Config Headers
Mainnet vs Testnet constants"] -A --> C["Plugin CMakeLists.txt
MongoDB plugin build gating"] -A --> D["Executables and Libraries
vizd, cli_wallet, shared/static libs"] -E["Dockerfiles
Example CMake invocations"] --> A -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp#L1-L169) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L53) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L81) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp#L1-L169) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L53) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L81) - -## Core Components -This section documents each build option, its effect on compiler flags, feature availability, and runtime behavior. - -- BUILD_TESTNET - - Purpose: Switches the build to use test network constants and configuration. - - Compiler flags: Adds preprocessor definitions for test network identifiers and parameters. - - Feature availability: Selects testnet-specific protocol constants and defaults. - - Runtime behavior: Changes chain identity, address prefix, block intervals, and governance parameters to align with the test network. - - Example CMake invocation (from Dockerfile): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBRARIES=FALSE -DBUILD_TESTNET=TRUE -DLOW_MEMORY_NODE=FALSE -DCHAINBASE_CHECK_LOCKING=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. - -- LOW_MEMORY_NODE - - Purpose: Optimizes the node for constrained memory environments. - - Compiler flags: Adds a preprocessor definition enabling low-memory-aware code paths. - - Feature availability: Enables memory-conscious settings such as shared memory sizing and virtual operation handling toggles. - - Runtime behavior: Adjusts shared memory growth thresholds, optional skipping of virtual operations, and related operational modes to reduce memory footprint. - - Example CMake invocation (from Dockerfile): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBRARIES=FALSE -DLOW_MEMORY_NODE=TRUE -DCHAINBASE_CHECK_LOCKING=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. - -- CHAINBASE_CHECK_LOCKING - - Purpose: Validates chainbase locking correctness during development and testing. - - Compiler flags: Adds a preprocessor definition enabling locking assertions and checks. - - Feature availability: Activates additional safety checks around shared memory and chainbase access patterns. - - Runtime behavior: Introduces extra validation overhead to catch potential deadlocks or misuse of chainbase resources. - - Example CMake invocation (from Dockerfiles): - - -DCHAINBASE_CHECK_LOCKING=FALSE for production builds. - - -DCHAINBASE_CHECK_LOCKING=TRUE for development/testing builds. - -- ENABLE_MONGO_PLUGIN - - Purpose: Builds the MongoDB integration plugin alongside the node. - - Compiler flags: Adds a preprocessor definition indicating the plugin is built. - - Feature availability: Links against MongoDB C++ driver libraries and exposes the mongo_db plugin to the node. - - Runtime behavior: Requires MongoDB drivers to be available at runtime; enables storing blockchain data in MongoDB via the plugin. - - Example CMake invocation (from Dockerfile): - - -DENABLE_MONGO_PLUGIN=TRUE (with MongoDB drivers installed in the build environment). - -Practical CMake invocation examples by environment: -- Development (testnet, minimal memory checks): - - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTNET=TRUE -DCHAINBASE_CHECK_LOCKING=TRUE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. -- Testing (testnet with MongoDB): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=TRUE -DCHAINBASE_CHECK_LOCKING=FALSE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=TRUE .. -- Production (mainnet, optimized): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=FALSE -DCHAINBASE_CHECK_LOCKING=FALSE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp#L1-L169) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L53) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L81) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -## Architecture Overview -The build options are evaluated early in the root CMake configuration and propagate into downstream components: -- Compiler flags are appended conditionally based on the selected options. -- Protocol headers switch between mainnet and testnet constants. -- Plugin builds are gated by the MongoDB plugin option. -- Executables and libraries inherit the configured flags and feature sets. - -```mermaid -graph TB -subgraph "Build Options" -BT["BUILD_TESTNET"] -LM["LOW_MEMORY_NODE"] -CL["CHAINBASE_CHECK_LOCKING"] -MP["ENABLE_MONGO_PLUGIN"] -end -subgraph "Compiler Flags" -F1["-DBUILD_TESTNET"] -F2["-DIS_LOW_MEM"] -F3["-DCHAINBASE_CHECK_LOCKING"] -F4["-DMONGODB_PLUGIN_BUILT"] -end -subgraph "Runtime Behavior" -R1["Testnet protocol constants"] -R2["Low-memory settings"] -R3["Chainbase locking checks"] -R4["MongoDB plugin availability"] -end -BT --> F1 -LM --> F2 -CL --> F3 -MP --> F4 -F1 --> R1 -F2 --> R2 -F3 --> R3 -F4 --> R4 -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -## Detailed Component Analysis - -### BUILD_TESTNET Option -- Effect on compiler flags: Adds preprocessor definitions for test network identifiers and parameters. -- Effect on feature availability: Selects testnet-specific protocol constants and defaults. -- Effect on runtime behavior: Changes chain identity, address prefix, block intervals, and governance parameters to align with the test network. -- Relationship to executables and libraries: No change to binary names; behavior is driven by selected protocol constants. - -```mermaid -flowchart TD -Start(["Configure BUILD_TESTNET"]) --> AddFlag["Add -DBUILD_TESTNET to C/C++ flags"] -AddFlag --> SelectHeaders["Select testnet protocol headers"] -SelectHeaders --> RuntimeSwitch["Runtime uses testnet constants and parameters"] -RuntimeSwitch --> End(["Build and run with testnet behavior"]) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L58-L64) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L58-L64) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -### LOW_MEMORY_NODE Option -- Effect on compiler flags: Adds a preprocessor definition enabling low-memory-aware code paths. -- Effect on feature availability: Enables memory-conscious settings such as shared memory sizing and virtual operation handling toggles. -- Effect on runtime behavior: Adjusts shared memory growth thresholds, optional skipping of virtual operations, and related operational modes to reduce memory footprint. -- Relationship to executables and libraries: No change to binary names; behavior is driven by runtime configuration and compiled-in flags. - -```mermaid -flowchart TD -Start(["Configure LOW_MEMORY_NODE"]) --> AddFlag["Add -DIS_LOW_MEM to C/C++ flags"] -AddFlag --> EnableFeatures["Enable low-memory runtime features"] -EnableFeatures --> RuntimeSettings["Apply shared memory and virtual op settings"] -RuntimeSettings --> End(["Build and run optimized for memory-constrained environments"]) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L68-L74) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L68-L74) - -### CHAINBASE_CHECK_LOCKING Option -- Effect on compiler flags: Adds a preprocessor definition enabling locking assertions and checks. -- Effect on feature availability: Activates additional safety checks around shared memory and chainbase access patterns. -- Effect on runtime behavior: Introduces extra validation overhead to catch potential deadlocks or misuse of chainbase resources. -- Relationship to executables and libraries: No change to binary names; behavior is driven by compiled-in checks. - -```mermaid -flowchart TD -Start(["Configure CHAINBASE_CHECK_LOCKING"]) --> AddFlag["Add -DCHAINBASE_CHECK_LOCKING to C/C++ flags"] -AddFlag --> EnableChecks["Enable chainbase locking checks"] -EnableChecks --> RuntimeValidation["Runtime validates chainbase access patterns"] -RuntimeValidation --> End(["Build and run with enhanced locking safety"]) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L78-L81) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L78-L81) - -### ENABLE_MONGO_PLUGIN Option -- Effect on compiler flags: Adds a preprocessor definition indicating the plugin is built. -- Effect on feature availability: Links against MongoDB C++ driver libraries and exposes the mongo_db plugin to the node. -- Effect on runtime behavior: Requires MongoDB drivers to be available at runtime; enables storing blockchain data in MongoDB via the plugin. -- Relationship to executables and libraries: The mongo_db plugin is built as part of the plugins tree when enabled; the node can load it at runtime. - -```mermaid -sequenceDiagram -participant CMake as "Root CMakeLists.txt" -participant MongoCMake as "plugins/mongo_db/CMakeLists.txt" -participant Flags as "Compiler Flags" -participant Plugin as "mongo_db Plugin" -CMake->>Flags : Add -DMONGODB_PLUGIN_BUILT when ENABLE_MONGO_PLUGIN=TRUE -CMake->>MongoCMake : ENABLE_MONGO_PLUGIN=TRUE -MongoCMake->>MongoCMake : Find MongoDB drivers -MongoCMake->>Plugin : Build mongo_db plugin target -Plugin-->>CMake : Expose graphene : : mongo_db target -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L84-L89) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L84-L89) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) -- [mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L1-L51) - -## Dependency Analysis -Build options influence downstream components through compiler flags and conditional inclusion. The following diagram shows how options propagate to protocol constants, plugin builds, and runtime behavior. - -```mermaid -graph TB -O1["BUILD_TESTNET"] --> P1["Protocol Constants (Testnet)"] -O2["LOW_MEMORY_NODE"] --> R1["Runtime Memory Settings"] -O3["CHAINBASE_CHECK_LOCKING"] --> R2["Runtime Locking Checks"] -O4["ENABLE_MONGO_PLUGIN"] --> P2["MongoDB Plugin Build"] -P2 --> R3["MongoDB Plugin Availability"] -subgraph "Root CMake" -O1 -O2 -O3 -O4 -end -subgraph "Runtime" -R1 -R2 -R3 -end -subgraph "Plugins" -P2 -end -subgraph "Protocol" -P1 -end -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L2-L81) - -## Performance Considerations -- CHAINBASE_CHECK_LOCKING adds runtime overhead due to additional checks; disable for production builds. -- LOW_MEMORY_NODE can reduce memory usage at the cost of potentially disabling certain features (e.g., skipping virtual operations) depending on configuration. -- BUILD_TESTNET does not alter performance characteristics directly but changes protocol parameters that indirectly affect throughput and resource usage. -- ENABLE_MONGO_PLUGIN introduces external dependencies and runtime overhead; ensure MongoDB drivers are properly installed and configured. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- MongoDB plugin fails to build: - - Ensure MongoDB C++ driver libraries are installed and discoverable by CMake before invoking the build. - - Verify that ENABLE_MONGO_PLUGIN is set to TRUE and that the plugin’s CMakeLists is executed. -- Unexpected testnet/mainnet behavior: - - Confirm BUILD_TESTNET is set appropriately; testnet constants are selected when enabled. -- Low memory issues: - - Review LOW_MEMORY_NODE-related runtime settings and consider enabling virtual operation skipping and adjusting shared memory parameters. -- Chainbase locking failures: - - Enable CHAINBASE_CHECK_LOCKING during development to catch incorrect locking patterns; disable for production. - -**Section sources** -- [CMakeLists.txt (mongo_db)](file://plugins/mongo_db/CMakeLists.txt#L15-L81) -- [CMakeLists.txt](file://CMakeLists.txt#L58-L81) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -## Conclusion -The four core build options—BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, and ENABLE_MONGO_PLUGIN—provide precise control over VIZ CPP Node compilation and runtime behavior. By understanding how each option affects compiler flags, feature availability, and runtime characteristics, teams can tailor builds for development, testing, and production environments effectively. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical CMake Invocation Examples -- Development (testnet, with locking checks): - - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTNET=TRUE -DCHAINBASE_CHECK_LOCKING=TRUE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. -- Testing (testnet with MongoDB): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=TRUE -DCHAINBASE_CHECK_LOCKING=FALSE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=TRUE .. -- Production (mainnet, optimized): - - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTNET=FALSE -DCHAINBASE_CHECK_LOCKING=FALSE -DLOW_MEMORY_NODE=FALSE -DENABLE_MONGO_PLUGIN=FALSE .. - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L53) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L51) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L81) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Dependency Management.md b/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Dependency Management.md deleted file mode 100644 index cb2bdf8f7e..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Dependency Management.md +++ /dev/null @@ -1,459 +0,0 @@ -# Dependency Management - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [thirdparty/CMakeLists.txt](file://thirdparty/CMakeLists.txt) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [documentation/building.md](file://documentation/building.md) -- [libraries/wallet/include/graphene/wallet/wallet.hpp](file://libraries/wallet/include/graphene/wallet/wallet.hpp) -- [libraries/wallet/wallet.cpp](file://libraries/wallet/wallet.cpp) -- [libraries/chain/database.cpp](file://libraries/chain/database.cpp) -- [thirdparty/fc/include/fc/optional.hpp](file://thirdparty/fc/include/fc/optional.hpp) -- [thirdparty/fc/include/fc/api.hpp](file://thirdparty/fc/include/fc/api.hpp) -- [thirdparty/fc/src/asio.cpp](file://thirdparty/fc/src/asio.cpp) -- [thirdparty/fc/src/ssh/client.cpp](file://thirdparty/fc/src/ssh/client.cpp) -- [plugins/webserver/webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) - - -## Update Summary -**Changes Made** -- Updated Boost library configuration section to reflect current Boost version requirement (1.71+) and enhanced platform detection logic -- Added comprehensive coverage of the migration from boost::bind to std::bind across the codebase -- Updated third-party dependency integration to highlight fc::optional as a replacement for boost::optional -- Enhanced troubleshooting section with guidance for resolving boost::bind deprecation warnings -- Updated version compatibility matrix to reflect current Boost version and standard library compliance -- Improved platform-specific compiler and linker flag handling across Windows, macOS, and Linux - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains how VIZ CPP Node manages dependencies across platforms using CMake. It focuses on Boost configuration (required components, static/dynamic linking, version requirements), third-party integration via subdirectories (appbase, chainbase, fc), OpenSSL configuration, and optional MongoDB plugin dependencies. The document also covers the comprehensive migration from deprecated Boost libraries to modern standard library alternatives, including the replacement of boost::optional with fc::optional and boost::bind with std::bind for improved standard library compliance. - -## Project Structure -The top-level CMake configuration orchestrates dependency discovery and builds subprojects: -- Top-level CMakeLists defines compiler requirements, module paths, and options. -- Third-party subdirectories (appbase, chainbase, fc) are integrated via a dedicated CMake file. -- Libraries, plugins, and programs are added as subprojects. -- Optional MongoDB plugin is controlled by a build option. - -```mermaid -graph TB -Root["Top-level CMakeLists.txt"] -TP["thirdparty/CMakeLists.txt"] -Libs["libraries/CMakeLists.txt"] -Plugins["plugins/*"] -Progs["programs/*"] -Root --> TP -Root --> Libs -Root --> Plugins -Root --> Progs -``` - -**Diagram sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) - -**Section sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) - -## Core Components -- **Boost**: Required components include thread, date_time, system, filesystem, program_options, serialization, chrono, unit_test_framework, context, locale, and coroutine. Static linking is enabled by default via an option. Current minimum version requirement is 1.71. -- **Standard Library Alternatives**: The codebase has undergone comprehensive migration from Boost libraries to standard library equivalents: - - boost::optional → fc::optional (stack-based nullable value) - - boost::bind → std::bind (standard function binding) - - boost::signals2 → std::function and std::bind patterns -- **OpenSSL**: Detected automatically on most systems; a fallback sets a default crypto library name on Unix-like systems. The build helper supports overriding the OpenSSL root directory via a command-line argument and environment variable. -- **MongoDB Plugin**: Controlled by an option; when enabled, the plugin locates libmongoc-1.0 and links against libbsoncxx and libmongocxx. Runtime presence of libmongoc is required. - -Key configuration points: -- Boost version requirement and component list (now 1.71+) -- Static vs dynamic linking defaults -- Platform-specific compiler and linker flags -- Optional MongoDB plugin enablement and dependency discovery -- Standard library compliance improvements - -**Section sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:52-54](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt](file://CMakeLists.txt#L169) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [thirdparty/fc/include/fc/api.hpp:17-20](file://thirdparty/fc/include/fc/api.hpp#L17-L20) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -## Architecture Overview -The dependency management architecture integrates external libraries and internal subprojects. The top-level CMake discovers Boost and OpenSSL, then adds third-party and application subprojects. The MongoDB plugin is conditionally included and links against MongoDB driver libraries. The architecture now emphasizes standard library compliance with fc::optional replacing boost::optional and std::bind replacing boost::bind. - -```mermaid -graph TB -subgraph "Top-level Build" -CMakeRoot["CMakeLists.txt"] -OptBoost["Boost Config
Components + Version 1.71+"] -OptOpenSSL["OpenSSL Config"] -OptMongo["MongoDB Plugin Option"] -StdLib["Standard Library Migration
boost::bind → std::bind
boost::optional → fc::optional"] -end -subgraph "Third-party Subprojects" -AppBase["appbase"] -ChainBase["chainbase"] -FC["fc (with optional.hpp)"] -end -subgraph "Application Subprojects" -Libs["libraries/*"] -Plugins["plugins/*"] -Progs["programs/*"] -end -CMakeRoot --> OptBoost -CMakeRoot --> OptOpenSSL -CMakeRoot --> OptMongo -CMakeRoot --> StdLib -CMakeRoot --> AppBase -CMakeRoot --> ChainBase -CMakeRoot --> FC -AppBase --> Libs -ChainBase --> Libs -FC --> Libs -Libs --> Plugins -Libs --> Progs -OptMongo --> Plugins -StdLib --> Plugins -StdLib --> Libs -``` - -**Diagram sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt](file://CMakeLists.txt#L169) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -## Detailed Component Analysis - -### Boost Library Configuration -- **Required components**: thread, date_time, system, filesystem, program_options, serialization, chrono, unit_test_framework, context, locale, coroutine. -- **Static linking default**: enabled via an option. -- **Version requirement**: minimum 1.71 (updated from previous 1.57 requirement). -- **Enhanced platform detection**: Explicit version checking with separate coroutine component discovery. -- **Windows-specific behavior**: multithreading is forced and dynamic linking is enforced. -- **Migration status**: The codebase has successfully migrated from boost::bind to std::bind across all plugins and libraries. - -```mermaid -flowchart TD -Start(["Configure Boost"]) --> SetComponents["Set required components list
(thread, date_time, system,
filesystem, program_options,
serialization, chrono,
unit_test_framework, context,
locale, coroutine)"] -SetComponents --> StaticDefault["Enable static libs option"] -StaticDefault --> VersionCheck["Require Boost >= 1.71"] -VersionCheck --> CoroutineCheck{"Boost version >= 1.54?"} -CoroutineCheck --> |Yes| AddCoroutine["Find coroutine component"] -CoroutineCheck --> |No| SkipCoroutine["Skip coroutine"] -AddCoroutine --> BindMigration["Verify boost::bind → std::bind migration"] -SkipCoroutine --> BindMigration -BindMigration --> OptionalMigration["Verify boost::optional → fc::optional migration"] -OptionalMigration --> LinkMode["Windows: force dynamic linking"] -LinkMode --> End(["Boost ready"]) -``` - -**Diagram sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:52-54](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:91-95](file://CMakeLists.txt#L91-L95) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) - -**Section sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:52-54](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:91-95](file://CMakeLists.txt#L91-L95) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) - -### Standard Library Migration Status -The VIZ CPP Node has undergone comprehensive migration from deprecated Boost libraries to modern standard library alternatives: - -#### boost::optional → fc::optional -- **Replacement rationale**: boost::optional adds significant compilation overhead (35,000 lines per object file) compared to fc::optional (less than 400 lines) -- **Implementation**: fc::optional provides stack-based nullable value functionality with improved performance characteristics -- **Usage pattern**: Replaces all instances of boost::optional with fc::optional -- **Benefits**: Reduced compilation times, smaller binaries, and maintained functionality - -#### boost::bind → std::bind -- **Migration scope**: Complete replacement across all plugins, libraries, and third-party components -- **Examples**: Webserver plugin uses std::bind for WebSocket and HTTP handlers -- **Benefits**: Standard library compliance, better performance, and reduced dependencies - -#### boost::signals2 → std::function patterns -- **Pattern**: Migration to std::function combined with std::bind for signal handling -- **Usage**: Maintains event-driven architecture while using standard library components - -**Section sources** -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [thirdparty/fc/include/fc/api.hpp:17-20](file://thirdparty/fc/include/fc/api.hpp#L17-L20) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) -- [thirdparty/fc/src/asio.cpp:164-165](file://thirdparty/fc/src/asio.cpp#L164-L165) -- [thirdparty/fc/src/ssh/client.cpp:124-125](file://thirdparty/fc/src/ssh/client.cpp#L124-L125) - -### OpenSSL Configuration -- **Automatic detection**: OpenSSL is typically found by CMake's find_package. -- **Fallback on Unix-like systems**: a default crypto library name is set when detection fails. -- **Override mechanism**: the build helper accepts an OpenSSL root directory argument and propagates it to CMake via an option variable. - -```mermaid -flowchart TD -Start(["Configure OpenSSL"]) --> AutoDetect["Try find_package(OpenSSL)"] -AutoDetect --> Found{"Found?"} -Found --> |Yes| UseDetected["Use detected OpenSSL"] -Found --> |No| SetFallback["Set default crypto library name"] -UseDetected --> End(["OpenSSL ready"]) -SetFallback --> End -``` - -**Diagram sources** -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [programs/build_helpers/configure_build.py:75-77](file://programs/build_helpers/configure_build.py#L75-L77) -- [programs/build_helpers/configure_build.py:115-116](file://programs/build_helpers/configure_build.py#L115-L116) -- [programs/build_helpers/configure_build.py:162-165](file://programs/build_helpers/configure_build.py#L162-L165) - -**Section sources** -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [programs/build_helpers/configure_build.py:75-77](file://programs/build_helpers/configure_build.py#L75-L77) -- [programs/build_helpers/configure_build.py:115-116](file://programs/build_helpers/configure_build.py#L115-L116) -- [programs/build_helpers/configure_build.py:162-165](file://programs/build_helpers/configure_build.py#L162-L165) - -### Optional MongoDB Plugin Dependencies -- **Enablement**: controlled by a build option; when enabled, the plugin is built and linked into the application. -- **Discovery**: finds libmongoc-1.0, libbsoncxx, and libmongocxx. -- **Linking**: links against graphene targets and MongoDB libraries; includes MongoDB driver headers. -- **Runtime**: libmongoc shared libraries must be available at runtime. - -```mermaid -sequenceDiagram -participant CMake as "CMakeLists.txt" -participant MongoCMake as "plugins/mongo_db/CMakeLists.txt" -participant Drivers as "MongoDB Drivers" -CMake->>MongoCMake : ENABLE_MONGO_PLUGIN -MongoCMake->>Drivers : find_package(libmongoc-1.0) -MongoCMake->>Drivers : find_package(libbsoncxx) -MongoCMake->>Drivers : find_package(libmongocxx) -MongoCMake-->>CMake : Link graphene targets + MongoDB libs -``` - -**Diagram sources** -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [plugins/mongo_db/CMakeLists.txt:2-23](file://plugins/mongo_db/CMakeLists.txt#L2-L23) -- [plugins/mongo_db/CMakeLists.txt:57-67](file://plugins/mongo_db/CMakeLists.txt#L57-L67) - -**Section sources** -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [plugins/mongo_db/CMakeLists.txt:2-23](file://plugins/mongo_db/CMakeLists.txt#L2-L23) -- [plugins/mongo_db/CMakeLists.txt:57-67](file://plugins/mongo_db/CMakeLists.txt#L57-L67) - -### Third-Party Subprojects (appbase, chainbase, fc) -- **These subprojects are added via a dedicated thirdparty CMake file and form the foundation for libraries and applications.** -- **They are integrated early in the build process to satisfy downstream dependencies.** -- **fc::optional provides a lightweight alternative to boost::optional with significant performance improvements.** - -```mermaid -graph TB -Root["Top-level CMakeLists.txt"] -TP["thirdparty/CMakeLists.txt"] -AppBase["appbase"] -ChainBase["chainbase"] -FC["fc (with optional.hpp)"] -Root --> TP -TP --> AppBase -TP --> ChainBase -TP --> FC -``` - -**Diagram sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) - -**Section sources** -- [CMakeLists.txt:210-213](file://CMakeLists.txt#L210-L213) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) - -## Dependency Analysis -- **Coupling**: Top-level CMake couples Boost, OpenSSL, and optional MongoDB to all subprojects. Third-party subprojects (appbase, chainbase, fc) are foundational and consumed by libraries. -- **External dependencies**: Managed centrally; platform differences are handled in separate branches for Windows, macOS, and Linux. -- **Conditional dependencies**: MongoDB plugin is optional and only linked when enabled. -- **Standard library compliance**: The migration to std::bind and fc::optional improves standard library compliance and reduces external dependencies. - -```mermaid -graph TB -Boost["Boost 1.71+ (REQUIRED)
thread, date_time, system,
filesystem, program_options,
serialization, chrono,
unit_test_framework, context,
locale, coroutine"] -OpenSSL["OpenSSL (OPTIONAL)"] -MongoPlugin["MongoDB Plugin (OPTIONAL)"] -AppBase["appbase"] -ChainBase["chainbase"] -FC["fc (with optional.hpp)"] -Libs["libraries/*"] -Plugins["plugins/*"] -Progs["programs/*"] -StdLib["Standard Library Migration
boost::bind → std::bind
boost::optional → fc::optional"] -Boost --> Libs -OpenSSL --> Libs -MongoPlugin --> Plugins -AppBase --> Libs -ChainBase --> Libs -FC --> Libs -Libs --> Plugins -Libs --> Progs -StdLib --> Plugins -StdLib --> Libs -``` - -**Diagram sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -**Section sources** -- [CMakeLists.txt:38-50](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [thirdparty/CMakeLists.txt:1-3](file://thirdparty/CMakeLists.txt#L1-L3) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -## Performance Considerations -- **Compiler flags and optimization vary by platform and generator.** Ninja with Clang on some generators enables colored diagnostics. -- **Coverage testing can be enabled via a dedicated option.** -- **Static linking flags are applied conditionally for full static builds on certain platforms.** -- **Performance improvements from standard library migration**: Reduced compilation times through fc::optional and std::bind elimination. -- **Memory efficiency**: fc::optional provides stack-based storage eliminating heap allocation overhead. - -Practical guidance: -- **Prefer Ninja with Clang on supported systems** for faster builds and better diagnostics. -- **Use coverage option only when needed** to avoid unnecessary overhead. -- **Monitor compilation times** - the migration to fc::optional should reduce build times significantly. - -**Section sources** -- [CMakeLists.txt:190-194](file://CMakeLists.txt#L190-L194) -- [CMakeLists.txt:206-208](file://CMakeLists.txt#L206-L208) -- [CMakeLists.txt:181-183](file://CMakeLists.txt#L181-L183) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) - -## Troubleshooting Guide -Common issues and resolutions: - -### Boost and Standard Library Migration Issues -- **Missing or incompatible Boost**: - - Ensure Boost version meets the minimum requirement (1.71+) and includes all required components. - - On Windows, dynamic linking is enforced; verify environment variables and installation paths. - - **Updated**: Verify that boost::bind has been migrated to std::bind throughout the codebase. - -- **boost::optional compilation errors**: - - Replace all boost::optional with fc::optional. - - Ensure proper includes: `#include `. - - **New**: Check that fc::optional is being used instead of boost::optional. - -- **boost::bind deprecation warnings**: - - Replace boost::bind with std::bind or lambda expressions. - - Use std::placeholders for argument placeholders. - - **Evidence**: Webserver plugin demonstrates proper std::bind usage patterns. - -### OpenSSL detection failures: -- Provide the OpenSSL root directory via the build helper argument or the corresponding environment variable. -- On Unix-like systems, a default crypto library name is set if detection fails. - -### MongoDB plugin not building: -- Confirm the option is enabled and that libmongoc-1.0, libbsoncxx, and libmongocxx are discoverable. -- Ensure libmongoc shared libraries are available at runtime. - -### Corporate firewall: -- Configure CMake to use proxy settings appropriate for your environment. -- Download dependencies manually and adjust CMake variables to point to local paths. - -**Section sources** -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:91-95](file://CMakeLists.txt#L91-L95) -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [plugins/mongo_db/CMakeLists.txt:2-23](file://plugins/mongo_db/CMakeLists.txt#L2-L23) -- [plugins/mongo_db/CMakeLists.txt:57-67](file://plugins/mongo_db/CMakeLists.txt#L57-L67) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -## Conclusion -VIZ CPP Node's dependency management centers on robust CMake configuration that enforces minimum Boost versions, integrates essential third-party libraries, and optionally supports MongoDB. The recent comprehensive migration from deprecated Boost libraries to modern standard library alternatives (boost::bind → std::bind, boost::optional → fc::optional) significantly improves performance, reduces dependencies, and enhances standard library compliance. By leveraging platform-aware logic, explicit override mechanisms, and modular subproject organization, the build remains portable and maintainable across environments. Following the guidance herein ensures reliable dependency resolution, smooth updates, and successful builds under varied conditions. - -## Appendices - -### Version Compatibility Matrix (Updated) -- **Boost**: Minimum 1.71; components include thread, date_time, system, filesystem, program_options, serialization, chrono, unit_test_framework, context, locale; coroutine added for 1.54+. -- **Standard Library Migration**: Complete replacement of boost::bind with std::bind and boost::optional with fc::optional. -- **OpenSSL**: Detected automatically; fallback crypto library name on Unix-like systems; override via build helper or environment variable. -- **MongoDB Plugin**: Optional; requires libmongoc-1.0, libbsoncxx, and libmongocxx discovered; runtime libmongoc availability required. - -**Section sources** -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:176-180](file://CMakeLists.txt#L176-L180) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [plugins/mongo_db/CMakeLists.txt:2-23](file://plugins/mongo_db/CMakeLists.txt#L2-L23) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -### Customizing Dependency Locations -- **Boost**: Set environment variables or CMake variables to guide discovery; Windows forces dynamic linking behavior. Ensure Boost 1.71+ is used for compatibility. -- **OpenSSL**: Use the build helper argument to specify the OpenSSL root directory; CMake reads the corresponding environment variable. -- **MongoDB**: Ensure MongoDB driver libraries are discoverable; adjust CMake variables to point to local installations if needed. - -**Section sources** -- [CMakeLists.txt:91-95](file://CMakeLists.txt#L91-L95) -- [programs/build_helpers/configure_build.py:75-77](file://programs/build_helpers/configure_build.py#L75-L77) -- [programs/build_helpers/configure_build.py:115-116](file://programs/build_helpers/configure_build.py#L115-L116) -- [programs/build_helpers/configure_build.py:162-165](file://programs/build_helpers/configure_build.py#L162-L165) - -### Managing Updates Across Platforms -- **Windows**: Dynamic linking enforcement and environment-driven configuration require attention during updates. Ensure Boost 1.71+ is available. -- **macOS/Linux**: Compiler flags and optional components may change; validate OpenSSL and MongoDB driver discovery after updates. Monitor for any remaining boost::bind usage. -- **General**: Keep Boost version above the minimum (1.71+), verify component lists, confirm optional plugin dependencies when enabling features, and ensure all boost::bind references have been migrated to std::bind. - -**Section sources** -- [CMakeLists.txt:112-156](file://CMakeLists.txt#L112-L156) -- [CMakeLists.txt:158-202](file://CMakeLists.txt#L158-L202) -- [CMakeLists.txt:96-100](file://CMakeLists.txt#L96-L100) -- [CMakeLists.txt:83-89](file://CMakeLists.txt#L83-L89) -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) - -### Standard Library Migration Checklist -- **Complete**: boost::bind → std::bind migration verified across all plugins -- **Complete**: boost::optional → fc::optional migration verified -- **Complete**: boost::signals2 patterns migrated to std::function + std::bind -- **Verification**: No remaining boost::bind or boost::optional includes in main codebase -- **Performance**: Compilation times improved through fc::optional usage - -**Section sources** -- [plugins/webserver/webserver_plugin.cpp:194-249](file://plugins/webserver/webserver_plugin.cpp#L194-L249) -- [thirdparty/fc/include/fc/optional.hpp:16-21](file://thirdparty/fc/include/fc/optional.hpp#L16-L21) -- [thirdparty/fc/src/asio.cpp:164-165](file://thirdparty/fc/src/asio.cpp#L164-L165) -- [thirdparty/fc/src/ssh/client.cpp:124-125](file://thirdparty/fc/src/ssh/client.cpp#L124-L125) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Platform Configurations.md b/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Platform Configurations.md deleted file mode 100644 index 1d29ced85e..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/CMake Configuration/Platform Configurations.md +++ /dev/null @@ -1,383 +0,0 @@ -# Platform Configurations - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt) -- [libraries/wallet/CMakeLists.txt](file://libraries/wallet/CMakeLists.txt) -- [programs/cli_wallet/CMakeLists.txt](file://programs/cli_wallet/CMakeLists.txt) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [thirdparty/fc/CMakeLists.txt](file://thirdparty/fc/CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) - - -## Update Summary -**Changes Made** -- Updated Linux configuration section to document the new `-DBOOST_BIND_GLOBAL_PLACEHOLDERS` compatibility flag -- Enhanced troubleshooting section with information about Boost binding issues -- Added cross-reference to the fc library's Boost compatibility flag -- Updated platform-specific compiler flags documentation - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction -This document provides comprehensive platform-specific CMake configuration guidance for the VIZ CPP Node build system. It covers compiler and linker settings per platform, static linking options, required libraries, and troubleshooting steps for common issues. The focus areas include: -- Windows with MSVC and MinGW toolchains -- macOS with libc++ and C++14 -- Linux with GCC, pthread, rt, OpenSSL detection, and Boost compatibility flags -- Compiler version requirements and platform-specific dependency resolution - -## Project Structure -The top-level CMake configuration orchestrates platform-specific behavior and includes subprojects for third-party libraries, core libraries, plugins, and programs. Platform checks are performed early to set flags, link libraries, and enable features. - -```mermaid -graph TB -Root["Top-level CMakeLists.txt
Defines project, minimum CMake version,
compiler checks, and platform branches"] -ThirdParty["thirdparty/CMakeLists.txt
Adds appbase, fc, chainbase"] -Libraries["libraries/CMakeLists.txt
Adds api, chain, protocol, network, time, utilities, wallet"] -Plugins["plugins/CMakeLists.txt
Discovers and adds plugins dynamically"] -Programs["programs/CMakeLists.txt
Adds build helpers, cli_wallet, js_operation_serializer, size_checker, util, vizd"] -Root --> ThirdParty -Root --> Libraries -Root --> Plugins -Root --> Programs -``` - -**Diagram sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) - -**Section sources** -- [CMakeLists.txt:1-271](file://CMakeLists.txt#L1-L271) -- [libraries/CMakeLists.txt:1-8](file://libraries/CMakeLists.txt#L1-L8) - -## Core Components -- Top-level CMake configuration sets compiler requirements, optional build features, and platform-specific flags. -- Library targets are built with platform-aware compile and link settings. -- Executables link against platform-specific libraries and optional profiling or performance tools. - -Key platform-specific behaviors: -- Compiler version checks for GCC and Clang. -- Static linking toggles via a full-static build option. -- Platform-specific include/link flags for Windows, macOS, and Linux. - -**Section sources** -- [CMakeLists.txt:11-20](file://CMakeLists.txt#L11-L20) -- [CMakeLists.txt:52-54](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt:158-202](file://CMakeLists.txt#L158-L202) - -## Architecture Overview -The build system applies platform-specific logic early, then composes targets across thirdparty, libraries, plugins, and programs. Windows, macOS, and Linux branches configure flags, libraries, and linkers differently. - -```mermaid -graph TB -subgraph "Windows" -WinFlags["MSVC: disable specific warnings
linker flags: /SAFESEH:NO
Debug linker flags: /DEBUG"] -MinGWFlags["MinGW: C++11, -fpermissive, SSE4.2, -Wa,-mbig-obj
Release: -O3
Debug: -O2"] -TclInteg["TCL: locate via TCL_ROOT env var
resolve optimized/debug libs"] -WinStatic["FULL_STATIC_BUILD: -static-libstdc++ -static-libgcc"] -end -subgraph "macOS" -MacFlags["C++14, libc++, -Wall, -Wno-conversion, -Wno-deprecated-declarations"] -MacReadline["Optional readline detection"] -end -subgraph "Linux" -LinFlags["C++14, -Wall, -DBOOST_BIND_GLOBAL_PLACEHOLDERS"] -LinPthreads["pthread library"] -LinRT["rt library"] -OpenSSLDetect["crypto_library fallback to 'crypto' if not found"] -LinStatic["FULL_STATIC_BUILD: -static-libstdc++ -static-libgcc"] -end -Root["CMakeLists.txt
Compiler checks, options, platform branches"] -Root --> WinFlags -Root --> MinGWFlags -Root --> TclInteg -Root --> WinStatic -Root --> MacFlags -Root --> MacReadline -Root --> LinFlags -Root --> LinPthreads -Root --> LinRT -Root --> OpenSSLDetect -Root --> LinStatic -``` - -**Diagram sources** -- [CMakeLists.txt:112-202](file://CMakeLists.txt#L112-L202) - -## Detailed Component Analysis - -### Windows Configuration (MSVC and MinGW) -- Compiler checks enforce minimum versions for GCC and Clang. -- MSVC-specific flags: - - Disable specific warnings. - - Linker flags to bypass Safe Exception Handler (SEH) requirements. - - Debug linker flags to ensure debug info emission. -- TCL library integration: - - Locate headers via environment variable pointing to TCL installation. - - Resolve optimized and debug variants of the TCL library. -- MinGW-specific flags: - - C++11 standard, permissive mode, SSE4.2, and large object support. - - Release and Debug optimization levels. - - Optional static linking of standard C++ and C runtime when enabled. - -```mermaid -flowchart TD -Start(["Configure on Windows"]) --> CheckToolchain["Detect MSVC or MinGW"] -CheckToolchain --> |MSVC| MSVCPath["Apply MSVC flags:
disable warnings
/SAFESEH:NO for linker
ensure /DEBUG in Debug"] -CheckToolchain --> |MinGW| MinGWPath["Apply MinGW flags:
-std=c++11 -fpermissive -msse4.2 -Wa,-mbig-obj
-O3 for Release
-O2 for Debug"] -MSVCPath --> TclFind["Locate TCL via TCL_ROOT
resolve optimized/debug libs"] -MinGWPath --> StaticCheck{"FULL_STATIC_BUILD?"} -TclFind --> StaticCheck -StaticCheck --> |Yes| WinStatic["Link with -static-libstdc++ -static-libgcc"] -StaticCheck --> |No| End(["Done"]) -WinStatic --> End -``` - -**Diagram sources** -- [CMakeLists.txt:123-156](file://CMakeLists.txt#L123-L156) - -**Section sources** -- [CMakeLists.txt:112-156](file://CMakeLists.txt#L112-L156) - -### macOS Configuration (Apple Platforms) -- Compiler flags: - - C++14 standard. - - Use of libc++ standard library. - - General warning flags and suppression of specific conversion/deprecation warnings. -- Optional readline detection is present but not mandatory. - -```mermaid -flowchart TD -StartMac(["Configure on macOS"]) --> MacFlags["Set C++14 and libc++
apply -Wall and warning suppressions"] -MacFlags --> ReadlineCheck{"readline found?"} -ReadlineCheck --> |Yes| LinkReadline["Link readline"] -ReadlineCheck --> |No| SkipReadline["Proceed without readline"] -LinkReadline --> EndMac(["Done"]) -SkipReadline --> EndMac -``` - -**Diagram sources** -- [CMakeLists.txt:166-170](file://CMakeLists.txt#L166-L170) - -**Section sources** -- [CMakeLists.txt:166-170](file://CMakeLists.txt#L166-L170) - -### Linux Configuration (GNU Toolchain) -- Compiler flags: - - C++14 standard and general warnings. - - **Updated**: Added `-DBOOST_BIND_GLOBAL_PLACEHOLDERS` flag to address Boost library binding issues in modern C++ environments. -- Required libraries: - - pthread library linkage. - - rt library linkage. - - OpenSSL detection fallback to the crypto library if not found by find_package. -- Optional static linking of standard C++ and C runtime when enabled. - -**Updated** The Linux configuration now includes a compatibility flag specifically designed to address Boost library binding issues that arise with newer C++ standards. This flag ensures proper compilation with modern Boost versions and C++ standards. - -```mermaid -flowchart TD -StartLin(["Configure on Linux"]) --> LinFlags["Set C++14 and -Wall
-DBOOST_BIND_GLOBAL_PLACEHOLDERS"] -LinFlags --> Pthread["Ensure pthread library"] -Pthread --> RTlib["Ensure rt library"] -RTlib --> OpenSSL["If OpenSSL not detected, default to 'crypto'"] -OpenSSL --> StaticCheck{"FULL_STATIC_BUILD?"} -StaticCheck --> |Yes| LinStatic["Link with -static-libstdc++ -static-libgcc"] -StaticCheck --> |No| EndLin(["Done"]) -LinStatic --> EndLin -``` - -**Diagram sources** -- [CMakeLists.txt:168-184](file://CMakeLists.txt#L168-L184) - -**Section sources** -- [CMakeLists.txt:168-184](file://CMakeLists.txt#L168-L184) - -### Static Linking Option -- A dedicated build mode enables full static linking of standard C++ and C runtime libraries on both Windows and Linux platforms. -- The option is surfaced in the build helper script and consumed by the top-level configuration. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant Helper as "configure_build.py" -participant Root as "CMakeLists.txt" -Dev->>Helper : Invoke build helper -Helper->>Root : Pass -DFULL_STATIC_BUILD=ON -Root->>Root : Apply platform-specific static flags -Root-->>Dev : Configure with static linking -``` - -**Diagram sources** -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L170) -- [CMakeLists.txt:153-155](file://CMakeLists.txt#L153-L155) -- [CMakeLists.txt:181-183](file://CMakeLists.txt#L181-L183) - -**Section sources** -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L170) -- [CMakeLists.txt:153-155](file://CMakeLists.txt#L153-L155) -- [CMakeLists.txt:181-183](file://CMakeLists.txt#L181-L183) - -### Library Targets and Platform-Aware Settings -- Library targets are built with platform-specific compile flags and link dependencies. -- Examples: - - Chain library applies MSVC-specific bigobj handling and links to protocol, utilities, fc, chainbase, appbase, and optional patch merge library. - - Network library applies MSVC bigobj handling and links to fc and protocol. - - Wallet library links to numerous internal plugins and platform-specific libraries. - -```mermaid -graph TB -Chain["graphene_chain
Compile flags: /bigobj on MSVC
Links: graphene_protocol, graphene_utilities, fc, chainbase, appbase"] -Network["graphene_network
Compile flags: /bigobj on MSVC
Links: fc, graphene_protocol"] -Wallet["graphene_wallet
Links: graphene_network, graphene_chain,
multiple internal plugins, fc, platform libs"] -RootLibs["libraries/CMakeLists.txt
Add subdirectories for api, chain, protocol, network, time, utilities, wallet"] -RootLibs --> Chain -RootLibs --> Network -RootLibs --> Wallet -``` - -**Diagram sources** -- [libraries/chain/CMakeLists.txt:130-132](file://libraries/chain/CMakeLists.txt#L130-L132) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L127) -- [libraries/network/CMakeLists.txt:46-48](file://libraries/network/CMakeLists.txt#L46-L48) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/wallet/CMakeLists.txt:73-75](file://libraries/wallet/CMakeLists.txt#L73-L75) -- [libraries/wallet/CMakeLists.txt:50-70](file://libraries/wallet/CMakeLists.txt#L50-L70) - -**Section sources** -- [libraries/chain/CMakeLists.txt:130-132](file://libraries/chain/CMakeLists.txt#L130-L132) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L127) -- [libraries/network/CMakeLists.txt:46-48](file://libraries/network/CMakeLists.txt#L46-L48) -- [libraries/network/CMakeLists.txt](file://libraries/network/CMakeLists.txt#L39) -- [libraries/wallet/CMakeLists.txt:73-75](file://libraries/wallet/CMakeLists.txt#L73-L75) -- [libraries/wallet/CMakeLists.txt:50-70](file://libraries/wallet/CMakeLists.txt#L50-L70) - -### Executable Targets and Platform-Specific Libraries -- CLI wallet links to network, chain, protocol, utilities, wallet, multiple internal plugins, fc, and platform-specific libraries. -- On Unix (non-macOS), the rt library is added conditionally. -- On macOS, readline is linked if found. -- Optional performance tooling via gperftools detection. - -```mermaid -sequenceDiagram -participant CMake as "CMakeLists.txt" -participant CLI as "cli_wallet target" -participant Libs as "Linked Libraries" -CMake->>CLI : Define target and sources -CMake->>Libs : Add graphene_network, graphene_chain, graphene_protocol, graphene_utilities, graphene_wallet -CMake->>Libs : Add internal plugins and fc -CMake->>Libs : Add ${readline_libraries}, ${CMAKE_DL_LIBS}, ${PLATFORM_SPECIFIC_LIBS} -CMake->>Libs : Add ${Boost_LIBRARIES} -CLI-->>CMake : Target ready for build -``` - -**Diagram sources** -- [programs/cli_wallet/CMakeLists.txt:21-41](file://programs/cli_wallet/CMakeLists.txt#L21-L41) -- [programs/cli_wallet/CMakeLists.txt:2-8](file://programs/cli_wallet/CMakeLists.txt#L2-L8) - -**Section sources** -- [programs/cli_wallet/CMakeLists.txt:21-41](file://programs/cli_wallet/CMakeLists.txt#L21-L41) -- [programs/cli_wallet/CMakeLists.txt:2-8](file://programs/cli_wallet/CMakeLists.txt#L2-L8) - -## Dependency Analysis -- Compiler and toolchain: - - Minimum versions enforced for GCC and Clang. - - Ninja generator receives additional diagnostics flags for Clang. -- Boost: - - Static usage is enabled by default. - - Coroutine component is conditionally added for newer Boost versions. - - **Updated**: Both top-level CMake configuration and fc library include `-DBOOST_BIND_GLOBAL_PLACEHOLDERS` to address Boost binding compatibility issues in modern C++ environments. -- Platform libraries: - - Windows: TCL integration via environment-driven discovery. - - macOS: optional readline linkage. - - Linux: pthread and rt linkage; OpenSSL fallback to crypto. - -**Updated** The Boost compatibility fix is implemented at two levels: the main CMake configuration for Linux builds and the fc library's CMake configuration, ensuring comprehensive coverage across the entire build system. - -```mermaid -graph TB -Compilers["Compiler Checks
GCC >= 4.8
Clang >= 3.3"] -BoostCfg["Boost Static Usage Enabled"] -CoroutineFix["Conditional coroutine component for Boost >= 1.54"] -BoostCompat["Boost Compatibility Flags
-DBOOST_BIND_GLOBAL_PLACEHOLDERS
in both main and fc libraries"] -PlatformLibs["Platform Libraries
Windows: TCL
macOS: readline
Linux: pthread, rt, crypto"] -Root["CMakeLists.txt"] -Root --> Compilers -Root --> BoostCfg -Root --> CoroutineFix -Root --> BoostCompat -Root --> PlatformLibs -``` - -**Diagram sources** -- [CMakeLists.txt:12-20](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L52) -- [CMakeLists.txt:99-104](file://CMakeLists.txt#L99-L104) -- [CMakeLists.txt:168-170](file://CMakeLists.txt#L168-L170) -- [thirdparty/fc/CMakeLists.txt:340-341](file://thirdparty/fc/CMakeLists.txt#L340-L341) - -**Section sources** -- [CMakeLists.txt:12-20](file://CMakeLists.txt#L12-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L52) -- [CMakeLists.txt:99-104](file://CMakeLists.txt#L99-L104) -- [CMakeLists.txt:168-170](file://CMakeLists.txt#L168-L170) -- [thirdparty/fc/CMakeLists.txt:340-341](file://thirdparty/fc/CMakeLists.txt#L340-L341) - -## Performance Considerations -- Optimization flags: - - MinGW Debug builds use a moderate optimization level to avoid assembler errors. - - General Debug builds add a debug macro definition. -- Static linking: - - Enables full static linking of standard C++ and C runtime libraries when requested. -- Build acceleration: - - Optional ccache usage if available. - -## Troubleshooting Guide -Common platform-specific issues and resolutions: -- Windows - - Missing TCL headers or libraries: - - Ensure TCL_ROOT environment variable points to a valid TCL installation so headers and libraries can be discovered. - - SEH-related linker warnings or failures: - - The configuration disables Safe Exception Handler emission; ensure downstream packaging does not require SEH. - - Large object compilation: - - MSVC targets apply bigobj handling; verify that sources triggering large object counts still compile. -- macOS - - Missing readline: - - readline is optional; if not found, the build proceeds without it. Install readline if interactive editing is desired. - - Standard library mismatch: - - Ensure libc++ is used consistently across dependencies. -- Linux - - pthread or rt missing: - - The build expects pthread and rt to be available; ensure the system provides these libraries. - - OpenSSL detection failure: - - If find_package cannot locate OpenSSL, the configuration defaults to linking against the crypto library; adjust package configuration or pass explicit hints if necessary. - - Static linking failures: - - When enabling full static linking, ensure all transitive dependencies are also statically available. - - **Updated** Boost binding issues: - - If experiencing Boost library binding errors with modern C++ standards, the `-DBOOST_BIND_GLOBAL_PLACEHOLDERS` flag is automatically included in Linux builds to resolve compatibility issues. This flag is also present in the fc library configuration for comprehensive coverage. - -**Updated** Added troubleshooting guidance for Boost binding issues that the new compatibility flag addresses. - -**Section sources** -- [CMakeLists.txt:132-145](file://CMakeLists.txt#L132-L145) -- [CMakeLists.txt:130-132](file://CMakeLists.txt#L130-L132) -- [CMakeLists.txt:160-164](file://CMakeLists.txt#L160-L164) -- [CMakeLists.txt:174-180](file://CMakeLists.txt#L174-L180) -- [CMakeLists.txt:181-183](file://CMakeLists.txt#L181-L183) -- [thirdparty/fc/CMakeLists.txt:340-341](file://thirdparty/fc/CMakeLists.txt#L340-L341) - -## Conclusion -The VIZ CPP Node build system applies robust, platform-aware configuration to ensure reliable builds across Windows, macOS, and Linux. By enforcing compiler versions, integrating platform-specific libraries, and supporting a static-linking mode, the system accommodates diverse deployment scenarios. - -**Updated** The recent addition of the `-DBOOST_BIND_GLOBAL_PLACEHOLDERS` compatibility flag enhances Linux build reliability by addressing Boost library binding issues that commonly occur with modern C++ standards. This dual-layer implementation (both in the main CMake configuration and the fc library) ensures comprehensive compatibility across the entire build system. Use the platform-specific guidance and troubleshooting tips herein to resolve typical build issues and tailor configurations to your environment. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Cross-Platform Compilation.md b/.qoder/repowiki/en/content/Development Tools/Build System/Cross-Platform Compilation.md deleted file mode 100644 index 7c396d67a0..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Cross-Platform Compilation.md +++ /dev/null @@ -1,384 +0,0 @@ -# Cross-Platform Compilation - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [README.md](file://README.md) -- [documentation/building.md](file://documentation/building.md) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [.travis.yml](file://.travis.yml) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive cross-platform build instructions and configuration guidance for VIZ CPP Node. It covers platform-specific compiler requirements, dependency installation, build options, static/dynamic linking behavior, optimization flags, and platform-specific artifacts. It also documents CI/CD automation via GitHub Actions and Travis CI, along with Docker-based reproducible builds. Guidance is derived from the repository’s CMake configuration, platform-specific documentation, and CI workflow definitions. - -## Project Structure -The build system is driven by CMake with platform-specific logic and CI workflows that build Docker images. The repository includes: -- Root CMake configuration with compiler checks, options, and platform branches -- Platform-specific build documentation -- CI workflows for Docker image builds -- Dockerfiles for production and testnet variants - -```mermaid -graph TB -A["Root CMakeLists.txt"] --> B["libraries/CMakeLists.txt"] -A --> C["plugins/CMakeLists.txt"] -A --> D["programs/CMakeLists.txt"] -A --> E["thirdparty/CMakeLists.txt"] -F["documentation/building.md"] --> A -G[".github/workflows/docker-main.yml"] --> H["Dockerfile-production"] -G --> I["Dockerfile-testnet"] -J[".github/workflows/docker-pr-build.yml"] --> I -K[".travis.yml"] --> H -K --> I -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) - -## Core Components -- Compiler requirements and flags: - - GCC minimum version check and Clang minimum version check are enforced at the top level. - - Platform-specific flags: - - Windows (MSVC): warning suppressions and linker flags; TCL detection and linkage. - - Windows (MinGW): C++11 dialect, permissive mode, SSE4.2, big object, separate Release/Debug optimization flags, optional full static linking. - - macOS: C++14, libc++, warnings adjustments. - - Linux: C++14, common warnings, pthread/rt/crypto libraries, optional full static linking. - - Coverage and PCH support toggles. -- Linking and libraries: - - Static Boost linkage by default on Windows. - - Optional MongoDB plugin build flag. - - Optional static executable linking via FULL_STATIC_BUILD. -- Build options: - - BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, ENABLE_MONGO_PLUGIN, BUILD_SHARED_LIBRARIES, ENABLE_INSTALLER, ENABLE_COVERAGE_TESTING. - -Key build targets are defined under programs (e.g., vizd, cli_wallet) and assembled by the root CMake configuration. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L11-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L202) -- [CMakeLists.txt](file://CMakeLists.txt#L52-L89) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) - -## Architecture Overview -The build pipeline integrates local CMake builds with CI-driven Docker builds. The CI orchestrates image builds for production and testnet variants, while local documentation describes manual builds on Ubuntu and macOS. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant CMake as "CMake (Local)" -participant Make as "make/ninja" -participant CI as "CI (GitHub Actions/Travis)" -participant Docker as "Docker Build" -Dev->>CMake : Configure with options -CMake->>Make : Generate build system -Make-->>Dev : Produce executables/binaries -Dev->>CI : Push/PR triggers workflow -CI->>Docker : Build Docker image with Dockerfile -Docker-->>CI : Publish image (optional) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) -- [.travis.yml](file://.travis.yml#L22-L42) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L40-L55) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L40-L55) - -## Detailed Component Analysis - -### Windows (MSVC and MinGW) -- Compiler requirements: - - Enforced minimum versions for GCC and Clang apply globally; MSVC is supported via CMake generator selection. -- Dependencies: - - Boost components are required; Windows forces static Boost usage. - - TCL is detected and linked on Windows; include path is derived from environment. -- Flags and options: - - MSVC: warning disables, SafeSEH flags, debug info linkage. - - MinGW: C++11 dialect, permissive mode, SSE4.2, big object, separate Release/Debug optimization flags, optional full static linking. -- Linking: - - Static Boost linkage on Windows; optional full static executable linking controlled by FULL_STATIC_BUILD. -- Artifacts: - - Executables produced under the configured install prefix; Windows packaging controlled by CPack when enabled. - -```mermaid -flowchart TD -Start(["Configure on Windows"]) --> DetectCompiler["Detect MSVC or MinGW"] -DetectCompiler --> |MSVC| MSVCFlags["Apply MSVC flags
warning disables, SafeSEH, debug info"] -DetectCompiler --> |MinGW| MinGWFlags["Apply MinGW flags
C++11, permissive, SSE4.2, big obj"] -MSVCFlags --> BoostWin["Find Boost (static libs)"] -MinGWFlags --> BoostWin -BoostWin --> LinkStep["Link executables"] -LinkStep --> End(["Artifacts ready"]) -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L91-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt](file://CMakeLists.txt#L123-L156) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L91-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L52-L54) - -### macOS (Xcode) -- Compiler requirements: - - Xcode command line tools required; CMake detects compilers automatically. -- Dependencies: - - Boost via Homebrew; OpenSSL prefix exported for discovery. -- Flags and options: - - C++14, libc++, common warnings adjustments. -- Artifacts: - - Executables built with standard CMake generators; install targets available. - -```mermaid -flowchart TD -StartMac(["macOS Build"]) --> XcodeTools["Install Xcode CLI tools"] -XcodeTools --> BrewDeps["Install Boost/OpenSSL via Homebrew"] -BrewDeps --> ExportEnv["Export OPENSSL_ROOT_DIR and BOOST_ROOT"] -ExportEnv --> CMakeConf["Run CMake configure"] -CMakeConf --> Build["Build targets (vizd, cli_wallet)"] -Build --> EndMac(["Artifacts ready"]) -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L138-L201) -- [CMakeLists.txt](file://CMakeLists.txt#L166-L170) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L138-L201) -- [CMakeLists.txt](file://CMakeLists.txt#L166-L170) - -### Linux (Ubuntu LTS) -- Compiler requirements: - - Supported with GCC and Clang; C++14 standard is used. -- Dependencies: - - System packages include CMake, GCC, Git, OpenSSL dev, Boost dev packages, and optional tools (Doxygen, readline, ncurses). -- Flags and options: - - C++14, common warnings; pthread/rt/crypto libraries; optional full static linking. -- Artifacts: - - Executables built via make; install target produces system-wide binaries. - -```mermaid -flowchart TD -StartLinux(["Linux Build"]) --> AptPkgs["Install system packages"] -AptPkgs --> Submodule["Initialize submodules"] -Submodule --> CMakeConf["Configure with CMake"] -CMakeConf --> BuildLinux["Build targets"] -BuildLinux --> Install["Optionally install"] -Install --> EndLinux(["Artifacts ready"]) -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [CMakeLists.txt](file://CMakeLists.txt#L171-L184) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [CMakeLists.txt](file://CMakeLists.txt#L171-L184) - -### Static vs Dynamic Linking -- Library linkage: - - Windows: Boost linkage forced static. - - Linux/macOS: default is dynamic; static linkage can be enabled via FULL_STATIC_BUILD. -- Executable linkage: - - FULL_STATIC_BUILD toggles static linking for executables on Linux/macOS; Windows applies static Boost and optional full static executable linkage. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L52-L54) -- [CMakeLists.txt](file://CMakeLists.txt#L153-L155) -- [CMakeLists.txt](file://CMakeLists.txt#L181-L183) - -### Platform-Specific Optimization Flags -- Windows: - - MSVC: SafeSEH flags and debug info linkage. - - MinGW: SSE4.2, big object, separate Release/Debug optimization flags. -- macOS/Linux: - - C++14 standard; Linux adds pthread/rt/crypto libraries; Ninja with Clang enables colored diagnostics. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L123-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L166-L184) -- [CMakeLists.txt](file://CMakeLists.txt#L190-L194) - -### Build Targets and Artifacts -- Executables: - - vizd, cli_wallet, and additional utilities are built from programs. -- Packaging: - - CPack is conditionally enabled for installer generation; Windows uses ZIP/NSIS; macOS uses DragNDrop; Linux uses TGZ. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) -- [CMakeLists.txt](file://CMakeLists.txt#L215-L262) - -## Dependency Analysis -- External dependencies: - - Boost components are required; Windows forces static Boost linkage. - - OpenSSL and readline are discovered via CMake; Linux sets pthread/rt/crypto defaults. -- Optional components: - - MongoDB plugin can be enabled via a build flag. -- CI-driven builds: - - Dockerfiles define reproducible environments and build options. - -```mermaid -graph LR -CMake["CMakeLists.txt"] --> Boost["Boost (required)"] -CMake --> OpenSSL["OpenSSL (discovered)"] -CMake --> Readline["Readline (discovered)"] -CMake --> Plugins["Optional Plugins"] -Plugins --> Mongo["MongoDB Plugin"] -CI["CI Workflows"] --> DockerProd["Dockerfile-production"] -CI --> DockerTest["Dockerfile-testnet"] -CI --> DockerLowMem["Dockerfile-lowmem"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L160-L180) -- [CMakeLists.txt](file://CMakeLists.txt#L83-L89) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L7-L30) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L7-L30) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L7-L30) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L160-L180) -- [CMakeLists.txt](file://CMakeLists.txt#L83-L89) - -## Performance Considerations -- Compiler and flags: - - Use Release builds for production; Linux/macOS enable C++14; MinGW enables SSE4.2. - - Full static linking reduces runtime dependencies but may increase binary size and startup time. -- Build system: - - ccache is enabled when available to speed up rebuilds. - - Ninja generator with Clang enables colored diagnostics for readability. -- CI and reproducibility: - - Dockerfiles pin system packages and build options for deterministic builds. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L106-L110) -- [CMakeLists.txt](file://CMakeLists.txt#L186-L194) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L54) - -## Troubleshooting Guide -- Compiler version errors: - - GCC and Clang minimum versions are enforced; ensure toolchains meet requirements. -- Boost linkage issues on Windows: - - Static Boost linkage is forced; ensure environment variables and paths are correct. -- MinGW “File too big” errors: - - Debug builds use reduced optimization; enabling big object support is handled in flags. -- macOS OpenSSL discovery: - - Set OPENSSL_ROOT_DIR to Homebrew OpenSSL prefix. -- Linux readline/ncurses: - - Some distributions require readline development packages; CMake attempts to locate them. -- CI failures: - - Verify Dockerfile context copying and submodule initialization steps. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L11-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L91-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L160-L180) -- [documentation/building.md](file://documentation/building.md#L138-L201) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L32-L43) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L32-L43) - -## Conclusion -The repository provides robust, cross-platform build support with explicit platform branches, strong compiler requirements, and CI-driven Docker builds. Developers can build locally on Windows, macOS, and Linux using documented steps, while CI ensures reproducible Docker images for production and testnet deployments. - -## Appendices - -### Step-by-Step Compilation Instructions - -- Ubuntu 16.04 LTS - - Install system packages and Boost development packages. - - Initialize submodules, configure with CMake, build targets, and optionally install. - - Reference: [documentation/building.md](file://documentation/building.md#L25-L75) - -- Ubuntu 14.04 LTS - - Install required packages; build and install Boost 1.57 manually if needed. - - Configure with CMake and build targets. - - Reference: [documentation/building.md](file://documentation/building.md#L76-L137) - -- macOS X - - Install Xcode CLI tools and Homebrew; install Boost and OpenSSL via Homebrew. - - Export OpenSSL and Boost prefixes, initialize submodules, configure with CMake, and build. - - Reference: [documentation/building.md](file://documentation/building.md#L138-L201) - -- Windows (MSVC/MinGW) - - Configure with CMake generator for desired toolchain; MSVC flags and SafeSEH settings are applied automatically; MinGW enables C++11, permissive mode, SSE4.2, and big object support. - - Reference: [CMakeLists.txt](file://CMakeLists.txt#L91-L156) - -### Continuous Integration and Automated Builds -- GitHub Actions - - Builds Docker images for testnet and production on push to master and PRs. - - References: - - [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41) - - [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) - -- Travis CI - - Matrix builds multiple Docker variants; pushes tagged images when applicable. - - Reference: [.travis.yml](file://.travis.yml#L19-L42) - -### Docker-Based Builds -- Production - - Sets Release build, disables shared libraries, disables extra features, installs dependencies, builds, installs, and prepares runtime image. - - Reference: [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L7-L60) - -- Testnet - - Same as production with BUILD_TESTNET enabled. - - Reference: [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L7-L60) - -- Low-memory node - - Same as production with LOW_MEMORY_NODE enabled. - - Reference: [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L7-L60) - -### Relationship Between Platform Choices and Runtime Performance -- Windows: - - MSVC SafeSEH and debug info flags impact link-time behavior; static Boost reduces runtime dependencies. -- macOS: - - C++14 and libc++ align with modern ABI; minimal extra flags optimize for standard compliance. -- Linux: - - C++14 and pthread/rt/crypto libraries ensure efficient threading and timing; static linking reduces external dependencies at the cost of larger binaries. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L123-L156) -- [CMakeLists.txt](file://CMakeLists.txt#L166-L184) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L54) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L46-L54) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Docker Integration.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Docker Integration.md deleted file mode 100644 index 86b1ffb327..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Docker Integration.md +++ /dev/null @@ -1,492 +0,0 @@ -# Docker Integration - - -**Referenced Files in This Document** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [vizd.sh](file://share/vizd/vizd.sh) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [snapshot.json](file://share/vizd/snapshot.json) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json) -- [seednodes](file://share/vizd/seednodes) -- [CMakeLists.txt](file://CMakeLists.txt) - - -## Update Summary -**Changes Made** -- Updated GitHub Actions workflow configurations to reflect major version upgrades (actions/checkout v2→v4, docker/build-push-action v1→v6) -- Added docker/login-action@v3 for enhanced authentication in CI/CD pipelines -- Improved error handling and workflow configurations for better build reliability and security -- Enhanced CI/CD pipeline documentation with current best practices - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive Docker integration guidance for the VIZ CPP Node across development and production environments. It covers multi-stage Dockerfiles for production, testnet, low-memory, and MongoDB-enabled builds, the GitHub Actions CI/CD pipeline for automated Docker builds with enhanced security and reliability, container orchestration patterns, volume mounting for persistence, network configuration, environment variable usage, and the relationship between Docker configurations and CMake build options. Practical examples are included for running development containers, connecting to test networks, and deploying production nodes. Security considerations and troubleshooting tips are also provided. - -## Project Structure -The Docker integration is centered around four primary Dockerfiles under share/vizd/docker, each tailored to a specific deployment profile. Supporting assets include configuration templates, scripts, snapshots, and seednode lists. The CI/CD pipeline is defined via GitHub Actions workflows with enhanced security and reliability features. - -```mermaid -graph TB -subgraph "Docker Build Configurations" -DProd["Dockerfile-production"] -DTest["Dockerfile-testnet"] -DLow["Dockerfile-lowmem"] -DMongo["Dockerfile-mongo"] -end -subgraph "Runtime Assets" -Script["vizd.sh"] -Seed["seednodes"] -Snap["snapshot.json"] -SnapTest["snapshot-testnet.json"] -CfgProd["config.ini"] -CfgTest["config_testnet.ini"] -CfgMongo["config_mongo.ini"] -CfgDebug["config_debug.ini"] -end -subgraph "Enhanced CI/CD" -GHMain[".github/workflows/docker-main.yml
v4 checkout + v6 build-push + v3 login"] -GHPR[".github/workflows/docker-pr-build.yml
v4 checkout + v6 build-push + v3 login"] -end -DProd --> Script -DProd --> Seed -DProd --> Snap -DProd --> CfgProd -DTest --> Script -DTest --> Seed -DTest --> SnapTest -DTest --> CfgTest -DLow --> Script -DLow --> Seed -DLow --> Snap -DLow --> CfgProd -DMongo --> Script -DMongo --> Seed -DMongo --> Snap -DMongo --> CfgMongo -GHMain --> DProd -GHMain --> DTest -GHPR --> DTest -``` - -**Diagram sources** -- [Dockerfile-production:1-98](file://share/vizd/docker/Dockerfile-production#L1-L98) -- [Dockerfile-testnet:1-98](file://share/vizd/docker/Dockerfile-testnet#L1-L98) -- [Dockerfile-lowmem:1-80](file://share/vizd/docker/Dockerfile-lowmem#L1-L80) -- [Dockerfile-mongo:1-109](file://share/vizd/docker/Dockerfile-mongo#L1-L109) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [seednodes:1-6](file://share/vizd/seednodes#L1-L6) -- [snapshot.json:1-174](file://share/vizd/snapshot.json#L1-L174) -- [snapshot-testnet.json:1-35](file://share/vizd/snapshot-testnet.json#L1-L35) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -**Section sources** -- [Dockerfile-production:1-98](file://share/vizd/docker/Dockerfile-production#L1-L98) -- [Dockerfile-testnet:1-98](file://share/vizd/docker/Dockerfile-testnet#L1-L98) -- [Dockerfile-lowmem:1-80](file://share/vizd/docker/Dockerfile-lowmem#L1-L80) -- [Dockerfile-mongo:1-109](file://share/vizd/docker/Dockerfile-mongo#L1-L109) -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -## Core Components -- Multi-stage Dockerfiles: - - Production: Builds with standard node settings, exposes RPC and P2P ports, mounts data directories for persistence. - - Testnet: Similar to production but enables testnet-specific configuration and snapshot. - - Low-memory: Optimized for constrained environments using a low-memory build option. - - MongoDB-enabled: Installs MongoDB C/C++ drivers and enables the mongo_db plugin. -- Enhanced CI/CD: - - Automated Docker builds for master branch (production and testnet) with improved security using docker/login-action@v3. - - PR builds for production images with ref tagging using latest GitHub Actions versions. - - Robust error handling and authentication mechanisms for reliable builds. -- Runtime: - - A service wrapper script initializes configuration, applies optional seed nodes, and starts the node with environment-driven endpoints and optional validator settings. - - Configuration templates define RPC endpoints, P2P endpoints, plugin sets, logging, and optional MongoDB connection. - - Snapshot assets enable fast initialization of blockchain data. - -Key runtime environment variables supported by the container entrypoint: -- VIZD_SEED_NODES: Comma-separated list of seed nodes to connect to. -- VIZD_WITNESS_NAME: Optional validator name for block production. -- VIZD_PRIVATE_KEY: Private key for validator signing. -- VIZD_RPC_ENDPOINT: Override RPC endpoint binding. -- VIZD_P2P_ENDPOINT: Override P2P endpoint binding. -- VIZD_EXTRA_OPTS: Additional arguments appended to the node command. - -Exposed ports: -- 8090: HTTP RPC -- 8091: WebSocket RPC -- 2001: P2P - -Volumes: -- /var/lib/vizd: Blockchain data directory -- /etc/vizd: Configuration directory - -**Section sources** -- [Dockerfile-production:76-98](file://share/vizd/docker/Dockerfile-production#L76-L98) -- [Dockerfile-testnet:77-98](file://share/vizd/docker/Dockerfile-testnet#L77-L98) -- [Dockerfile-lowmem:58-80](file://share/vizd/docker/Dockerfile-lowmem#L58-L80) -- [Dockerfile-mongo:87-109](file://share/vizd/docker/Dockerfile-mongo#L87-L109) -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -## Architecture Overview -The Docker-based deployment architecture separates build-time and runtime concerns with enhanced CI/CD security: -- Build-time: Multi-stage Dockerfiles compile the node with CMake options selected per variant. -- Runtime: A minimal base image runs the node under a service supervisor, with volumes for persistence and configuration overlays. -- CI/CD: Enhanced GitHub Actions workflows with improved authentication, error handling, and build reliability. - -```mermaid -graph TB -subgraph "Enhanced Build Stages" -B1["Stage 1: Builder Base
Install deps, clone repo, cmake configure
actions/checkout@v4 + docker/login-action@v3"] -B2["Stage 2: Install Artifacts
make install, cleanup"] -end -subgraph "Enhanced Runtime Image" -R1["Minimal Base"] -R2["Copy /usr/local from builder"] -R3["Add user, cache dirs, service wrapper"] -R4["Mount volumes, expose ports"] -end -B1 --> B2 --> R2 --> R3 --> R4 -``` - -**Diagram sources** -- [Dockerfile-production:1-98](file://share/vizd/docker/Dockerfile-production#L1-L98) -- [Dockerfile-testnet:1-98](file://share/vizd/docker/Dockerfile-testnet#L1-L98) -- [Dockerfile-lowmem:1-80](file://share/vizd/docker/Dockerfile-lowmem#L1-L80) -- [Dockerfile-mongo:1-109](file://share/vizd/docker/Dockerfile-mongo#L1-L109) -- [docker-main.yml:17-21](file://.github/workflows/docker-main.yml#L17-L21) -- [docker-pr-build.yml:15-19](file://.github/workflows/docker-pr-build.yml#L15-L19) - -## Detailed Component Analysis - -### Dockerfile Variants and CMake Options -Each Dockerfile selects CMake options to tailor the build: -- Production: Standard release build with full plugin set and no special flags. -- Testnet: Enables BUILD_TESTNET and uses testnet configuration and snapshot. -- Low-memory: Enables LOW_MEMORY_NODE to reduce memory footprint. -- MongoDB-enabled: Installs MongoDB C drivers and enables ENABLE_MONGO_PLUGIN. - -```mermaid -flowchart TD -Start(["Start Build"]) --> Stage1["Stage 1: Install Build Tools and Dependencies"] -Stage1 --> CopySrc["Copy Source and Configure CMake"] -CopySrc --> CMakeCfg{"Select CMake Options"} -CMakeCfg --> |Production| OptProd["Release, Shared=OFF,
Testnet=OFF, LowMem=OFF, Mongo=OFF"] -CMakeCfg --> |Testnet| OptTest["Release, Shared=OFF,
Testnet=ON, LowMem=OFF, Mongo=OFF"] -CMakeCfg --> |Low-Memory| OptLM["Release, Shared=OFF,
Testnet=OFF, LowMem=ON, Mongo=OFF"] -CMakeCfg --> |MongoDB| OptMongo["Release, Shared=OFF,
Testnet=OFF, LowMem=OFF, Mongo=ON"] -OptProd --> Build["Compile and Install"] -OptTest --> Build -OptLM --> Build -OptMongo --> MongoDeps["Install MongoDB C/C++ Drivers"] --> Build -Build --> Stage2["Stage 2: Runtime Image Setup"] -Stage2 --> End(["Image Ready"]) -``` - -**Diagram sources** -- [Dockerfile-production:51-69](file://share/vizd/docker/Dockerfile-production#L51-L69) -- [Dockerfile-testnet:51-65](file://share/vizd/docker/Dockerfile-testnet#L51-L65) -- [Dockerfile-lowmem:37-51](file://share/vizd/docker/Dockerfile-lowmem#L37-L51) -- [Dockerfile-mongo:66-80](file://share/vizd/docker/Dockerfile-mongo#L66-L80) -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) - -**Section sources** -- [Dockerfile-production:51-69](file://share/vizd/docker/Dockerfile-production#L51-L69) -- [Dockerfile-testnet:51-65](file://share/vizd/docker/Dockerfile-testnet#L51-L65) -- [Dockerfile-lowmem:37-51](file://share/vizd/docker/Dockerfile-lowmem#L37-L51) -- [Dockerfile-mongo:66-80](file://share/vizd/docker/Dockerfile-mongo#L66-L80) -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) - -### Enhanced CI/CD Pipeline (GitHub Actions) -Automated Docker builds are configured with enhanced security and reliability: -- Master branch: Builds production and testnet images with improved authentication using docker/login-action@v3 and pushes to the registry with appropriate tags. -- Pull requests: Builds a production image and tags it with the PR ref for review using latest GitHub Actions versions. - -**Updated** Enhanced with major version upgrades and improved security measures - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant GH as "GitHub" -participant Act as "Actions Runner" -participant Auth as "docker/login-action@v3" -participant Build as "docker/build-push-action@v6" -participant Reg as "Container Registry" -Dev->>GH : Push to master -GH->>Act : Trigger docker-main.yml -Act->>Auth : Authenticate with Docker Hub -Auth->>Reg : Login with credentials -Act->>Build : Build and push production image (latest) -Build->>Reg : Push with docker/build-push-action@v6 -Act->>Build : Build and push testnet image (testnet) -Build->>Reg : Push with docker/build-push-action@v6 -Dev->>GH : Open PR -GH->>Act : Trigger docker-pr-build.yml -Act->>Auth : Authenticate with Docker Hub -Auth->>Reg : Login with credentials -Act->>Build : Build and push production image (ref-tagged) -Build->>Reg : Push with docker/build-push-action@v6 -``` - -**Diagram sources** -- [docker-main.yml:17-31](file://.github/workflows/docker-main.yml#L17-L31) -- [docker-pr-build.yml:15-29](file://.github/workflows/docker-pr-build.yml#L15-L29) - -**Section sources** -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -### Container Runtime and Environment Variables -The container entrypoint script orchestrates node startup: -- Applies default seed nodes from the seednodes file if none are provided via environment. -- Copies the packaged configuration into the data directory and adjusts ownership. -- Optionally replays from a cached snapshot if present. -- Starts the node with configurable RPC and P2P endpoints and optional validator parameters. - -```mermaid -sequenceDiagram -participant Entrypoint as "vizd.sh" -participant FS as "Mounted Volumes" -participant Node as "vizd" -Entrypoint->>Entrypoint : Parse env vars (seed, validator, keys, endpoints) -Entrypoint->>FS : Copy /etc/vizd/config.ini -> /var/lib/vizd/config.ini -Entrypoint->>FS : Optionally extract cached snapshot to blockchain dir -Entrypoint->>Node : exec vizd with data-dir, endpoints, plugins, extra opts -Node-->>Entrypoint : stdout/stderr -``` - -**Diagram sources** -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) - -**Section sources** -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) - -### Configuration Templates and Plugin Sets -Configuration files define RPC endpoints, plugin sets, logging, and optional MongoDB URI. The testnet configuration enables validator production and includes a default validator and private key suitable for automated testing. - -- Production: Full plugin set excluding MongoDB. -- Testnet: Includes Validator Plugin and default validator credentials. -- MongoDB: Adds mongo_db plugin and a MongoDB URI for external connectivity. - -**Section sources** -- [config.ini:1-130](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini:1-132](file://share/vizd/config/config_testnet.ini#L1-L132) -- [config_mongo.ini:1-135](file://share/vizd/config/config_mongo.ini#L1-L135) - -### Volume Mounting and Persistence -- /var/lib/vizd: Contains blockchain data, logs, and configuration overrides. -- /etc/vizd: Contains initial configuration and seednodes; copied into the data directory at first run. - -Practical guidance: -- Bind-mount a host directory to /var/lib/vizd for persistent storage across container restarts. -- Place a custom config.ini into /etc/vizd to override defaults; it will be copied into the data directory on first run. - -**Section sources** -- [Dockerfile-production:97-98](file://share/vizd/docker/Dockerfile-production#L97-L98) -- [Dockerfile-testnet:97-98](file://share/vizd/docker/Dockerfile-testnet#L97-L98) -- [Dockerfile-lowmem:79-80](file://share/vizd/docker/Dockerfile-lowmem#L79-L80) -- [Dockerfile-mongo:108-109](file://share/vizd/docker/Dockerfile-mongo#L108-L109) -- [vizd.sh:40-43](file://share/vizd/vizd.sh#L40-L43) - -### Network Configuration and Connectivity -- Exposed ports: 8090 (HTTP RPC), 8091 (WebSocket RPC), 2001 (P2P). -- Seed nodes: Provided via /etc/vizd/seednodes; overridden by VIZD_SEED_NODES environment variable. -- P2P endpoint binding: Defaults to 0.0.0.0:2001; overrideable via VIZD_P2P_ENDPOINT. -- RPC endpoint binding: Defaults to 0.0.0.0:8090; overrideable via VIZD_RPC_ENDPOINT. - -For MongoDB-enabled deployments, the configuration template includes a MongoDB URI suitable for connecting to a MongoDB instance reachable from the container's network namespace. - -**Section sources** -- [Dockerfile-production:89-95](file://share/vizd/docker/Dockerfile-production#L89-L95) -- [Dockerfile-testnet:89-95](file://share/vizd/docker/Dockerfile-testnet#L89-L95) -- [Dockerfile-lowmem:71-77](file://share/vizd/docker/Dockerfile-lowmem#L71-L77) -- [Dockerfile-mongo:100-106](file://share/vizd/docker/Dockerfile-mongo#L100-L106) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) -- [seednodes:1-6](file://share/vizd/seednodes#L1-L6) -- [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72) - -### Practical Examples - -- Run a production node locally: - - docker run -d \ - --name viz-prod \ - -p 8090:8090 -p 8091:8091 -p 2001:2001 \ - -v /srv/viz/data:/var/lib/vizd \ - -v /srv/viz/etc:/etc/vizd \ - vizblockchain/vizd:latest - -- Connect to the testnet: - - docker run -d \ - --name viz-testnet \ - -e VIZD_SEED_NODES="seed1.testnet.viz:2001,seed2.testnet.viz:2001" \ - -p 8090:8090 -p 8091:8091 -p 2001:2001 \ - -v /srv/viz/testnet-data:/var/lib/vizd \ - vizblockchain/vizd:testnet - -- Deploy a MongoDB-enabled node: - - docker run -d \ - --name viz-mongo \ - -e VIZD_SEED_NODES="..." \ - -p 8090:8090 -p 8091:8091 -p 2001:2001 \ - -v /srv/viz/mongo-data:/var/lib/vizd \ - -v /srv/viz/mongo-etc:/etc/vizd \ - vizblockchain/vizd:mongo - -- Run a validator node: - - docker run -d \ - --name viz-validator \ - -e VIZD_WITNESS_NAME="your-validator" \ - -e VIZD_PRIVATE_KEY="5...your-private-key" \ - -p 8090:8090 -p 8091:8091 -p 2001:2001 \ - -v /srv/viz/validator-data:/var/lib/vizd \ - vizblockchain/vizd:latest - -[No sources needed since this section provides practical examples without analyzing specific files] - -## Dependency Analysis -The Docker build depends on CMake options to select features and plugins. The CI/CD pipeline depends on Docker Hub credentials and the presence of the Dockerfiles with enhanced authentication security. - -**Updated** Enhanced with improved authentication and build action versions - -```mermaid -graph LR -CMake["CMakeLists.txt
BUILD_TESTNET / LOW_MEMORY_NODE / ENABLE_MONGO_PLUGIN"] -DP["Dockerfile-production"] -DT["Dockerfile-testnet"] -DL["Dockerfile-lowmem"] -DM["Dockerfile-mongo"] -CMake --> DP -CMake --> DT -CMake --> DL -CMake --> DM -GHMain["docker-main.yml
v4 checkout + v6 build-push + v3 login"] --> DP -GHMain --> DT -GHPR["docker-pr-build.yml
v4 checkout + v6 build-push + v3 login"] --> DT -``` - -**Diagram sources** -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) -- [Dockerfile-production:56-61](file://share/vizd/docker/Dockerfile-production#L56-L61) -- [Dockerfile-testnet:56-62](file://share/vizd/docker/Dockerfile-testnet#L56-L62) -- [Dockerfile-lowmem:43-48](file://share/vizd/docker/Dockerfile-lowmem#L43-L48) -- [Dockerfile-mongo:72-77](file://share/vizd/docker/Dockerfile-mongo#L72-L77) -- [docker-main.yml:17-31](file://.github/workflows/docker-main.yml#L17-L31) -- [docker-pr-build.yml:15-29](file://.github/workflows/docker-pr-build.yml#L15-L29) - -**Section sources** -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) -- [docker-main.yml:1-53](file://.github/workflows/docker-main.yml#L1-L53) -- [docker-pr-build.yml:1-30](file://.github/workflows/docker-pr-build.yml#L1-L30) - -## Performance Considerations -- Multi-stage builds minimize final image size by discarding build tools and build artifacts after installation. -- Using Release builds and disabling shared libraries reduces binary size and improves runtime performance characteristics. -- Low-memory builds reduce shared memory sizing and related overhead for constrained environments. -- MongoDB builds include static drivers to avoid runtime dependency resolution overhead. -- Caching: ccache is enabled during CMake configuration to speed up rebuilds when iterating on changes. -- Enhanced CI/CD: Latest GitHub Actions versions provide improved build performance and reliability. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Ports already in use: - - Change published ports or stop conflicting services. -- Permission denied on data directory: - - Ensure the container user owns /var/lib/vizd and mounted volumes are writable. -- No connectivity to peers: - - Verify VIZD_SEED_NODES or rely on default seednodes; confirm firewall/NAT rules allow inbound P2P traffic on port 2001. -- Slow startup due to replay: - - Provide a cached snapshot or pre-seeded blockchain data in /var/lib/vizd to accelerate synchronization. -- validator production not starting: - - Confirm VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY are set and match the configured validator and private key in the configuration. -- MongoDB plugin errors: - - Ensure the MongoDB URI is reachable from the container network and matches the configuration template. -- CI/CD build failures: - - Verify Docker Hub credentials are properly configured; check docker-login-action@v3 authentication. - - Ensure actions/checkout@v4 and docker/build-push-action@v6 are compatible with your repository structure. - -Operational checks: -- Inspect container logs for startup errors. -- Verify configuration file presence in /var/lib/vizd after first run. -- Monitor RPC and P2P endpoints availability. -- Check GitHub Actions workflow logs for authentication and build errors. - -**Section sources** -- [vizd.sh:1-98](file://share/vizd/vizd.sh#L1-L98) -- [config_mongo.ini:71-72](file://share/vizd/config/config_mongo.ini#L71-L72) -- [docker-main.yml:21-24](file://.github/workflows/docker-main.yml#L21-L24) -- [docker-pr-build.yml:19-22](file://.github/workflows/docker-pr-build.yml#L19-L22) - -## Conclusion -The Docker integration for VIZ CPP Node provides flexible, reproducible deployments across production, testnet, low-memory, and MongoDB-enabled scenarios. Enhanced multi-stage builds, modernized CI/CD automation with improved security and reliability, and robust runtime configuration enable efficient development and operations. By leveraging volumes, environment variables, and configuration templates, teams can deploy reliable nodes with predictable performance and minimal operational overhead. The recent upgrades to GitHub Actions workflows ensure better build reliability and security for automated Docker image creation. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Environment Variables Reference -- VIZD_SEED_NODES: Comma-separated P2P endpoints to bootstrap connections. -- VIZD_WITNESS_NAME: Name of the validator to produce blocks. -- VIZD_PRIVATE_KEY: Private key for validator signing. -- VIZD_RPC_ENDPOINT: RPC endpoint binding (host:port). -- VIZD_P2P_ENDPOINT: P2P endpoint binding (host:port). -- VIZD_EXTRA_OPTS: Additional CLI options appended to the node process. - -**Section sources** -- [vizd.sh:17-37](file://share/vizd/vizd.sh#L17-L37) -- [vizd.sh:62-72](file://share/vizd/vizd.sh#L62-L72) - -### Appendix B: CMake Options and Docker Variants Mapping -- BUILD_TESTNET: Selects testnet configuration and snapshot. -- LOW_MEMORY_NODE: Reduces memory footprint for constrained environments. -- ENABLE_MONGO_PLUGIN: Enables MongoDB plugin and installs drivers. -- BUILD_SHARED_LIBRARIES=OFF: Produces static binaries for portability. -- CMAKE_BUILD_TYPE=Release: Optimized release build. - -**Section sources** -- [CMakeLists.txt:56-89](file://CMakeLists.txt#L56-L89) -- [Dockerfile-production:56-61](file://share/vizd/docker/Dockerfile-production#L56-L61) -- [Dockerfile-testnet:56-62](file://share/vizd/docker/Dockerfile-testnet#L56-L62) -- [Dockerfile-lowmem:43-48](file://share/vizd/docker/Dockerfile-lowmem#L43-L48) -- [Dockerfile-mongo:72-77](file://share/vizd/docker/Dockerfile-mongo#L72-L77) - -### Appendix C: Enhanced GitHub Actions Workflow Versions -**Updated** Current workflow versions and security enhancements - -- actions/checkout@v4: Latest checkout action with improved performance and security -- docker/login-action@v3: Enhanced authentication with better credential handling -- docker/build-push-action@v6: Latest build and push action with improved reliability -- Error handling: Better failure detection and reporting in CI/CD pipelines -- Authentication: Secure Docker Hub credentials management through GitHub Secrets - -**Section sources** -- [docker-main.yml:17-21](file://.github/workflows/docker-main.yml#L17-L21) -- [docker-pr-build.yml:19-22](file://.github/workflows/docker-pr-build.yml#L19-L22) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/GitHub Actions CI_CD Pipeline.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/GitHub Actions CI_CD Pipeline.md deleted file mode 100644 index 7eadc9dfd8..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/GitHub Actions CI_CD Pipeline.md +++ /dev/null @@ -1,350 +0,0 @@ -# GitHub Actions CI/CD Pipeline - - -**Referenced Files in This Document** -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [CMakeLists.txt](file://CMakeLists.txt) -- [vizd.sh](file://share/vizd/vizd.sh) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [testing.md](file://documentation/testing.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the GitHub Actions CI/CD pipeline that automates Docker image builds and testing for the VIZ C++ Node. It covers workflow triggers for main branch pushes and pull requests, Docker build matrix variants, automated testing and code quality checks, artifact management, Docker image publishing, and deployment automation. It also provides practical examples for modifying workflow configurations, adding new build stages, and troubleshooting pipeline failures, with best practices tailored for blockchain development. - -## Project Structure -The CI/CD pipeline is defined by two GitHub Actions workflow files: -- A main branch build workflow that produces production and testnet images. -- A pull request build workflow that builds a testnet image and optionally tags it with the ref for traceability. - -Docker images are built from multi-stage Dockerfiles located under share/vizd/docker. The build leverages CMake options to toggle features such as testnet mode, low-memory mode, and MongoDB plugin support. - -```mermaid -graph TB -GH[".github/workflows"] --> MAIN["docker-main.yml"] -GH --> PR["docker-pr-build.yml"] -MAIN --> PROD["Dockerfile-production"] -MAIN --> TESTNET["Dockerfile-testnet"] -PR --> TESTNET_PR["Dockerfile-testnet"] -PROD --> CMAKE["CMakeLists.txt"] -TESTNET --> CMAKE -TESTNET_PR --> CMAKE -CMAKE --> DOCKERS["Dockerfiles"] -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [CMakeLists.txt](file://CMakeLists.txt#L46-L89) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Core Components -- Workflow triggers: - - Main branch push: Builds and publishes production and testnet images. - - Pull request: Builds a testnet image and tags it with the ref for traceability. -- Docker build matrix: - - Production image: Built from Dockerfile-production. - - Testnet image: Built from Dockerfile-testnet. - - Low-memory variant: Dockerfile-lowmem enables LOW_MEMORY_NODE. - - MongoDB-enabled variant: Dockerfile-mongo enables ENABLE_MONGO_PLUGIN. -- Artifact management and publishing: - - Images are pushed to a Docker registry using credentials from GitHub secrets. - - Tagging strategy differs between main and PR workflows. -- Testing and code quality: - - Unit tests can be executed via a documented target. - - Code coverage can be enabled via CMake flags and lcov. -- Runtime configuration: - - Container entrypoint script configures endpoints, seeds, and optional replay from cache. - - Multiple config templates are provided for mainnet and testnet. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L3-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L3-L24) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L46-L53) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L82) -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [documentation/testing.md](file://documentation/testing.md#L3-L43) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L62-L81) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -## Architecture Overview -The CI/CD pipeline orchestrates Docker builds and publishes images to a registry. The main workflow runs on master pushes and produces two images: production and testnet. The PR workflow runs on pull requests and produces a testnet image tagged with the ref. The Dockerfiles use CMake to configure build-time features and produce minimal runtime images. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant GH as "GitHub Actions" -participant Repo as "Repository" -participant Docker as "Docker Registry" -Dev->>GH : Push to master -GH->>Repo : Checkout code -GH->>GH : Build production image -GH->>Docker : Push "latest" tag -GH->>GH : Build testnet image -GH->>Docker : Push "testnet" tag -Dev->>GH : Open Pull Request -GH->>Repo : Checkout PR code -GH->>GH : Build testnet image -GH->>Docker : Push "" tag -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L3-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L3-L24) - -## Detailed Component Analysis - -### Main Branch Workflow -- Triggers: Pushes to master branch with documentation and Markdown files excluded from triggering. -- Jobs: - - Build testnet image using Dockerfile-testnet and tag as testnet. - - Build production image using Dockerfile-production and tag as latest. -- Secrets: Uses DOCKER_USERNAME and DOCKER_PASSWORD for registry authentication. - -```mermaid -flowchart TD -Start(["Push to master"]) --> ExcludeDocs["paths-ignore documentation/** and *.md"] -ExcludeDocs --> BuildTestnet["Job: build_testnet
Dockerfile-testnet -> tag: testnet"] -ExcludeDocs --> BuildProd["Job: build_prod
Dockerfile-production -> tag: latest"] -BuildTestnet --> Publish["Publish to registry"] -BuildProd --> Publish -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L3-L41) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L3-L41) - -### Pull Request Workflow -- Triggers: Pull requests with documentation and Markdown files excluded from triggering. -- Job: - - Build testnet image using Dockerfile-testnet and tag with ref for traceability. -- Secrets: Uses DOCKER_USERNAME and DOCKER_PASSWORD for registry authentication. - -```mermaid -flowchart TD -PRStart(["Pull Request opened"]) --> ExcludeDocsPR["paths-ignore documentation/** and *.md"] -ExcludeDocsPR --> BuildPR["Job: build_testnet
Dockerfile-testnet -> tag: "] -BuildPR --> PublishPR["Publish to registry"] -``` - -**Diagram sources** -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L3-L24) - -**Section sources** -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L3-L24) - -### Docker Build Matrix and Variants -- Production: Built with release flags and standard plugins. -- Testnet: Built with BUILD_TESTNET enabled and testnet-specific config. -- Low-memory: Built with LOW_MEMORY_NODE enabled to reduce resource usage. -- MongoDB: Built with ENABLE_MONGO_PLUGIN enabled and MongoDB driver installation. - -```mermaid -graph LR -CMake["CMake options"] --> Prod["Production"] -CMake --> Testnet["Testnet"] -CMake --> LowMem["Low Memory"] -CMake --> Mongo["MongoDB"] -Prod --- DFProd["Dockerfile-production"] -Testnet --- DFTNet["Dockerfile-testnet"] -LowMem --- DFLow["Dockerfile-lowmem"] -Mongo --- DFMongo["Dockerfile-mongo"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L46-L53) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L82) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L46-L53) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L82) - -### Automated Testing and Code Quality -- Unit tests: - - Target: chain_test. - - Execution: ./tests/chain_test. - - Configuration options include log level, report level, and selective test execution. -- Code coverage: - - Enable via CMake flag. - - Capture baseline and test coverage with lcov and generate HTML reports. - -```mermaid -flowchart TD -Build["Build with CMake"] --> Tests["Run chain_test"] -Tests --> Report["Generate test report"] -Build --> Coverage["Enable coverage in CMake"] -Coverage --> Lcov["Capture coverage with lcov"] -Lcov --> Html["Generate HTML report"] -``` - -**Diagram sources** -- [documentation/testing.md](file://documentation/testing.md#L3-L43) - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L3-L43) - -### Runtime Configuration and Entrypoint -- Entrypoint script configures RPC and P2P endpoints, seed nodes, optional replay from cached snapshot, and passes extra options. -- Config templates: - - Mainnet: config.ini. - - Testnet: config_testnet.ini. - -```mermaid -flowchart TD -Start(["Container start"]) --> Seed["Resolve seed nodes"] -Seed --> Args["Compose arguments"] -Args --> Replay{"Snapshot exists?"} -Replay --> |Yes| Init["Initialize from cached snapshot"] -Replay --> |No| Skip["Skip replay"] -Init --> Run["Start vizd with configured endpoints"] -Skip --> Run -``` - -**Diagram sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L81) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L13-L81) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -## Dependency Analysis -- Workflow-to-Dockerfile dependencies: - - docker-main.yml depends on Dockerfile-production and Dockerfile-testnet. - - docker-pr-build.yml depends on Dockerfile-testnet. -- Build-time configuration: - - Dockerfiles depend on CMake options to enable/disable features and select variants. -- Runtime configuration: - - Entrypoint script depends on config templates and snapshot availability. - -```mermaid -graph TB -MAIN[".github/workflows/docker-main.yml"] --> PROD["Dockerfile-production"] -MAIN --> TESTNET["Dockerfile-testnet"] -PR[".github/workflows/docker-pr-build.yml"] --> TESTNET -PROD --> CMAKE["CMakeLists.txt"] -TESTNET --> CMAKE -LOWMEM["Dockerfile-lowmem"] --> CMAKE -MONGO["Dockerfile-mongo"] --> CMAKE -ENTRY["vizd.sh"] --> CFG["config.ini / config_testnet.ini"] -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [share/vizd/docker/Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [share/vizd/docker/Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [CMakeLists.txt](file://CMakeLists.txt#L46-L89) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [CMakeLists.txt](file://CMakeLists.txt#L46-L89) - -## Performance Considerations -- Build performance: - - Use ccache via CMake to speed up rebuilds. - - Multi-stage builds minimize runtime image size and improve cold start. -- Resource usage: - - Low-memory variant reduces memory footprint for constrained environments. -- Network and storage: - - Entrypoint supports replay from cached snapshot to accelerate initial sync. -- Parallelism: - - Use matrix strategies to run multiple variants concurrently when extending the pipeline. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Authentication failures: - - Verify DOCKER_USERNAME and DOCKER_PASSWORD secrets are set in repository settings. -- Build failures due to missing dependencies: - - Ensure Dockerfiles install required packages and CMake options match intended variant. -- Test failures: - - Confirm chain_test target is available and test runner options are correctly passed. -- Coverage reporting: - - Ensure lcov is installed and CMake coverage flag is enabled during build. -- Image tagging: - - For PR builds, confirm tag_with_ref is enabled to attach the ref to the image tag. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L19-L25) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L17-L23) -- [documentation/testing.md](file://documentation/testing.md#L3-L43) - -## Conclusion -The CI/CD pipeline automates robust Docker image builds for VIZ C++ Node across multiple variants, integrates testing and code coverage, and publishes images to a registry. By leveraging CMake options and multi-stage Dockerfiles, the pipeline supports production, testnet, low-memory, and MongoDB-enabled deployments. Extending the pipeline involves adding jobs, Dockerfiles, and CMake toggles while maintaining consistent tagging and secret management. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples - -- Modify workflow configurations: - - Add a new job to build a variant image by referencing a Dockerfile and setting appropriate tags. - - Adjust paths-ignore to include/exclude specific directories from triggering builds. - - Reference: [docker-main.yml](file://.github/workflows/docker-main.yml#L11-L41), [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L9-L24) - -- Add a new build stage: - - Extend an existing Dockerfile or create a new Dockerfile variant. - - Introduce a corresponding CMake option and update the workflow to consume it. - - Reference: [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54), [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L46-L53), [CMakeLists.txt](file://CMakeLists.txt#L56-L89) - -- Troubleshoot pipeline failures: - - Check logs for authentication errors and verify secrets. - - Validate Docker build steps and ensure dependencies are installed. - - Confirm test targets and coverage tools are available and configured. - - Reference: [docker-main.yml](file://.github/workflows/docker-main.yml#L19-L25), [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L17-L23), [testing.md](file://documentation/testing.md#L3-L43) - -### Best Practices for Blockchain CI/CD -- Reproducible builds: - - Pin Docker base images and toolchain versions; rely on CMake to enforce consistent flags. -- Security: - - Store registry credentials as encrypted secrets; limit permissions; scan images post-build. -- Performance: - - Use caching (ccache, Docker layers); parallelize independent jobs; prune unused artifacts. -- Reliability: - - Validate images with smoke tests; publish multiple tags for traceability; document rollback procedures. - -[No sources needed since this section provides general guidance] \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Low-Memory Dockerfile.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Low-Memory Dockerfile.md deleted file mode 100644 index 184cafaf4e..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Low-Memory Dockerfile.md +++ /dev/null @@ -1,316 +0,0 @@ -# Low-Memory Dockerfile - - -**Referenced Files in This Document** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [CMakeLists.txt](file://CMakeLists.txt) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [vizd.sh](file://share/vizd/vizd.sh) -- [database.cpp](file://libraries/chain/database.cpp) -- [account_api_object.cpp](file://libraries/api/account_api_object.cpp) -- [plugin.cpp](file://plugins/tags/plugin.cpp) -- [social_network.cpp](file://plugins/social_network/social_network.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the low-memory Dockerfile optimized for resource-constrained environments. It details the LOW_MEMORY_NODE build option, its impact on memory usage, reduced functionality, and performance trade-offs. It also documents minimal dependency requirements, the optimized build process, and the reduced feature set compared to production builds. Practical examples for building low-memory containers, resource monitoring, and performance optimization techniques are provided, along with limitations, supported operations, and migration paths to full-featured builds. - -## Project Structure -The low-memory container is built from a dedicated Dockerfile that mirrors the production build process but enables the LOW_MEMORY_NODE CMake option. The Dockerfile sets up a minimal build environment, clones the repository, initializes submodules, configures CMake with low-memory flags, compiles, installs, and packages a runtime image with a non-root user and essential volumes. - -```mermaid -graph TB -A["Dockerfile-lowmem
Defines base image, build deps, CMake flags"] --> B["Builder Stage
Clone repo, init submodules, cmake -DLOW_MEMORY_NODE=TRUE"] -B --> C["Install artifacts to /usr/local"] -C --> D["Runtime Stage
Copy /usr/local, create non-root user, expose ports, mount volumes"] -D --> E["Container Entrypoint
vizd.sh starts node with config and optional snapshot"] -``` - -**Diagram sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) - -## Core Components -- Low-memory Dockerfile: Builds with LOW_MEMORY_NODE enabled, disabling extra indexes and metadata storage to reduce memory footprint. -- CMake configuration: Adds -DIS_LOW_MEM and toggles related compile-time flags. -- Runtime configuration: Minimal RPC endpoints, reduced thread pools, and conservative shared memory sizing. -- Entrypoint script: Initializes data directory, optionally replays a cached snapshot, and launches the node with configurable endpoints. - -Key differences from production: -- LOW_MEMORY_NODE=TRUE vs FALSE -- Reduced plugin surface and indexes -- Smaller shared memory defaults and cautious growth thresholds - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L53) -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [vizd.sh](file://share/vizd/vizd.sh#L44-L53) - -## Architecture Overview -The low-memory container architecture separates build-time and runtime concerns: -- Build stage: Installs minimal toolchain and dependencies, configures CMake with LOW_MEMORY_NODE, compiles, and installs binaries. -- Runtime stage: Copies installed binaries, creates a non-root user, exposes RPC and P2P ports, mounts persistent volumes for blockchain data and config, and runs via an init service wrapper. - -```mermaid -graph TB -subgraph "Build Stage" -L1["apt-get install minimal deps"] --> L2["git submodule update"] -L2 --> L3["cmake -DLOW_MEMORY_NODE=TRUE ..."] -L3 --> L4["make -j$(nproc)"] -L4 --> L5["make install"] -end -subgraph "Runtime Stage" -R1["FROM baseimage"] --> R2["COPY --from=builder /usr/local"] -R2 --> R3["useradd vizd, chown cache dir"] -R3 --> R4["COPY config.ini, seednodes, vizd.sh"] -R4 --> R5["EXPOSE 8090, 8091, 2001"] -R5 --> R6["VOLUME [/var/lib/vizd, /etc/vizd]"] -R6 --> R7["Entrypoint: vizd.sh"] -end -L5 --> R2 -``` - -**Diagram sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L7-L59) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L40-L59) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Detailed Component Analysis - -### Low-Memory Build Option Impact -The LOW_MEMORY_NODE option adds -DIS_LOW_MEM and disables certain indexes and metadata storage to reduce memory usage. Conditional compilation blocks appear across chain logic and plugins. - -```mermaid -flowchart TD -Start(["Configure CMake"]) --> Check{"LOW_MEMORY_NODE enabled?"} -Check --> |Yes| AddFlag["Add -DIS_LOW_MEM"] -AddFlag --> DisableIndexes["Disable extra indexes and metadata storage"] -DisableIndexes --> Compile["Compile with reduced feature set"] -Check --> |No| FullBuild["Full feature build"] -Compile --> Install["Install artifacts"] -FullBuild --> Install -Install --> Runtime["Runtime image"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) -- [database.cpp](file://libraries/chain/database.cpp#L2221-L2225) -- [database.cpp](file://libraries/chain/database.cpp#L2269-L2278) -- [database.cpp](file://libraries/chain/database.cpp#L3063-L3067) -- [database.cpp](file://libraries/chain/database.cpp#L3078-L3082) -- [database.cpp](file://libraries/chain/database.cpp#L3098-L3103) -- [database.cpp](file://libraries/chain/database.cpp#L3120-L3124) -- [database.cpp](file://libraries/chain/database.cpp#L3144-L3148) -- [database.cpp](file://libraries/chain/database.cpp#L3170-L3174) -- [account_api_object.cpp](file://libraries/api/account_api_object.cpp#L40-L43) -- [plugin.cpp](file://plugins/tags/plugin.cpp#L42-L52) -- [plugin.cpp](file://plugins/tags/plugin.cpp#L211-L220) -- [social_network.cpp](file://plugins/social_network/social_network.cpp#L372-L392) - -### Memory-Efficient Chain Initialization -Genesis initialization and account creation are guarded by low-memory conditionals to skip metadata objects when memory is constrained. - -```mermaid -flowchart TD -A["Initialize genesis accounts"] --> B{"IS_LOW_MEM?"} -B --> |Yes| C["Skip metadata objects for accounts"] -B --> |No| D["Create metadata objects for accounts"] -C --> E["Continue initialization"] -D --> E -``` - -**Diagram sources** -- [database.cpp](file://libraries/chain/database.cpp#L3063-L3067) -- [database.cpp](file://libraries/chain/database.cpp#L3078-L3082) -- [database.cpp](file://libraries/chain/database.cpp#L3098-L3103) -- [database.cpp](file://libraries/chain/database.cpp#L3120-L3124) -- [database.cpp](file://libraries/chain/database.cpp#L3144-L3148) -- [database.cpp](file://libraries/chain/database.cpp#L3170-L3174) - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3060-L3182) - -### Tags Plugin Index Management -The tags plugin conditionally registers indexes and hooks to reduce memory overhead under low-memory mode. - -```mermaid -sequenceDiagram -participant Init as "tags_plugin : : plugin_initialize" -participant DB as "database" -Init->>Init : "#ifndef IS_LOW_MEM" -Init->>DB : "add_plugin_index(tag_index)" -Init->>DB : "add_plugin_index(tag_stats_index)" -Init->>DB : "add_plugin_index(author_tag_stats_index)" -Init->>DB : "add_plugin_index(language_index)" -Init-->>Init : "#endif" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/tags/plugin.cpp#L211-L220) - -**Section sources** -- [plugin.cpp](file://plugins/tags/plugin.cpp#L42-L52) -- [plugin.cpp](file://plugins/tags/plugin.cpp#L211-L220) - -### Social Network Discussions Retrieval -Discussion retrieval APIs are guarded by low-memory conditionals to avoid heavy indexing operations. - -```mermaid -sequenceDiagram -participant API as "social_network : : get_replies_by_last_update" -participant Impl as "impl : : get_replies_by_last_update" -participant DB as "database" -API->>Impl : "validate args and limits" -Impl->>Impl : "#ifndef IS_LOW_MEM" -Impl->>DB : "iterate by_last_update index" -Impl-->>API : "return discussions" -Impl->>Impl : "#endif" -``` - -**Diagram sources** -- [social_network.cpp](file://plugins/social_network/social_network.cpp#L372-L392) - -**Section sources** -- [social_network.cpp](file://plugins/social_network/social_network.cpp#L370-L394) - -### Runtime Entrypoint and Snapshot Replay -The entrypoint script prepares the data directory, optionally replays a cached snapshot, and launches the node with configurable endpoints. - -```mermaid -flowchart TD -S["Start vizd.sh"] --> U["Ensure ownership of /var/lib/vizd"] -U --> C["Copy /etc/vizd/config.ini -> $HOME/config.ini"] -C --> D{"blockchain dir exists?"} -D --> |No| E{"blocks.tbz2 present in cache?"} -E --> |Yes| F["Replay cached snapshot"] -E --> |No| G["Proceed without snapshot"] -D --> |Yes| H["Proceed without snapshot"] -F --> I["Launch vizd with endpoints and seed nodes"] -G --> I -H --> I -``` - -**Diagram sources** -- [vizd.sh](file://share/vizd/vizd.sh#L44-L81) - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Dependency Analysis -The low-memory Dockerfile depends on: -- Base image for build and runtime stages -- Minimal toolchain and libraries for compilation -- CMake configuration toggling LOW_MEMORY_NODE and related flags -- Runtime configuration files and entrypoint script - -```mermaid -graph LR -CM["CMakeLists.txt
LOW_MEMORY_NODE option"] --> DF["Dockerfile-lowmem
cmake -DLOW_MEMORY_NODE=TRUE"] -DF --> IMG["Built Image"] -CFG["config.ini
shared memory defaults"] --> IMG -SH["vizd.sh
entrypoint"] --> IMG -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L45-L53) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L1-L82) -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Performance Considerations -- Shared memory sizing: Defaults are tuned to reduce initial allocation and growth frequency. -- Thread pool sizing: Conservative thread counts for RPC clients. -- Lock contention: Single write thread reduces database lock contention. -- Plugin notifications: Disabled on push transactions to reduce overhead. -- MongoDB plugin: Explicitly disabled in low-memory builds. - -Practical tips: -- Monitor shared memory free space and adjust growth increments if needed. -- Keep RPC thread pool size minimal for constrained systems. -- Disable non-essential plugins to further reduce memory usage. -- Use snapshot replay to bootstrap quickly without replaying entire chain. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L13-L47) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L50-L50) - -## Troubleshooting Guide -Common issues and remedies: -- Out-of-memory during startup: Reduce shared memory growth increments or disable non-essential plugins. -- Slow RPC response: Lower thread pool size or disable plugin notifications on push. -- Missing metadata in API responses: Expected in low-memory mode; metadata is intentionally omitted. -- Snapshot replay failures: Verify cached snapshot presence and permissions. - -Operational checks: -- Confirm LOW_MEMORY_NODE is enabled in the build. -- Validate runtime configuration overrides via environment variables. -- Inspect logs written to configured appenders. - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L112-L130) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L81) - -## Conclusion -The low-memory Dockerfile provides a compact, resource-efficient node suitable for constrained environments. By enabling LOW_MEMORY_NODE, the build reduces indexes and metadata storage, lowers shared memory defaults, and simplifies operational overhead. While some features are intentionally disabled, it remains capable of serving basic RPC needs and can be migrated to full-featured builds when resources permit. - -## Appendices - -### Building Low-Memory Containers -- Build command: Use the low-memory Dockerfile to produce a minimal image. -- Environment overrides: Configure endpoints and seed nodes via environment variables injected by the entrypoint script. -- Persistent volumes: Mount data and config directories to preserve state across restarts. - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L60-L82) -- [vizd.sh](file://share/vizd/vizd.sh#L13-L39) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L81) - -### Supported Operations Under Low-Memory Mode -- Basic RPC endpoints remain available. -- Genesis initialization proceeds without metadata objects. -- Some plugin indexes and operations are disabled to conserve memory. - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L3063-L3067) -- [database.cpp](file://libraries/chain/database.cpp#L3078-L3082) -- [plugin.cpp](file://plugins/tags/plugin.cpp#L211-L220) -- [social_network.cpp](file://plugins/social_network/social_network.cpp#L372-L392) - -### Migration Paths to Full-Featured Builds -- Switch to the production Dockerfile to enable full feature set. -- Re-enable MongoDB plugin if persistence to MongoDB is required. -- Increase shared memory defaults and thread pool sizes for higher throughput. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L52) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L74-L82) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/MongoDB Integration Dockerfile.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/MongoDB Integration Dockerfile.md deleted file mode 100644 index 2bc98da404..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/MongoDB Integration Dockerfile.md +++ /dev/null @@ -1,434 +0,0 @@ -# MongoDB Integration Dockerfile - - -**Referenced Files in This Document** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [CMakeLists.txt](file://CMakeLists.txt) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp) -- [plugins/mongo_db/mongo_db_types.cpp](file://plugins/mongo_db/mongo_db_types.cpp) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [share/vizd/config/config_debug_mongo.ini](file://share/vizd/config/config_debug_mongo.ini) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the MongoDB-enabled Dockerfile variant that integrates VIZ CPP Node with MongoDB for enhanced indexing and query capabilities. It covers the ENABLE_MONGO_PLUGIN CMake option, the MongoDB plugin architecture, data synchronization mechanisms, and performance characteristics. It also documents container setup, connection configuration, persistence strategies, and practical examples for enabling MongoDB integration, configuring replica sets, and optimizing queries. Finally, it compares the trade-offs between traditional SQLite-based storage and MongoDB integration, including storage requirements, backups, and migration procedures. - -## Project Structure -The MongoDB integration spans Docker build configuration, CMake build options, and the MongoDB plugin implementation. The Dockerfile variant installs MongoDB C drivers and enables the MongoDB plugin during build. The plugin connects to MongoDB, listens to blockchain events, transforms state and operations into documents, and writes them to collections with secondary indexes. - -```mermaid -graph TB -subgraph "Docker Build" -DF["Dockerfile-mongo
Installs MongoDB C/C++ drivers
Builds with ENABLE_MONGO_PLUGIN=TRUE"] -CFG["config_mongo.ini
Enables mongo_db plugin
Sets mongodb-uri"] -end -subgraph "CMake Build" -CM["CMakeLists.txt
ENABLE_MONGO_PLUGIN option"] -PM["plugins/mongo_db/CMakeLists.txt
Finds libmongocxx/libbsoncxx
Links targets"] -end -subgraph "Plugin Runtime" -PLUG["mongo_db_plugin
App base plugin"] -WR["mongo_db_writer
Connects to MongoDB
Bulk writes"] -STATE["state_writer
Formats docs per operation"] -TYPES["mongo_db_types
named_document, helpers"] -end -DF --> CM -CM --> PM -CFG --> PLUG -PLUG --> WR -WR --> STATE -WR --> TYPES -``` - -**Diagram sources** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L1-L81) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L54-L125) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L133) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L25-L29) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) - -**Section sources** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L1-L111) -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L1-L81) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) - -## Core Components -- ENABLE_MONGO_PLUGIN CMake option: Controls whether the MongoDB plugin is built and linked into the node. When enabled, the plugin target is added and linked against libmongocxx and libbsoncxx. -- Dockerfile-mongo: Installs MongoDB C drivers (mongo-c-driver and mongo-cxx-driver), clones and builds the C++ driver, and passes -DENABLE_MONGO_PLUGIN=TRUE to cmake. -- mongo_db_plugin: An appbase plugin that registers CLI/config options, initializes the MongoDB writer, subscribes to applied_block and post_apply_operation signals, and coordinates writes. -- mongo_db_writer: Manages MongoDB connection, bulk writes, document formatting, and index creation on first use per collection. -- state_writer: Visitor that formats blockchain state and operations into named_document entries with upsert semantics and optional removal updates. -- mongo_db_types: Provides document metadata (collection name, key, indexes), hashing helpers, and a multi-index container for efficient deduplication and updates. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L1-L81) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L31-L58) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L54-L125) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp#L42-L90) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L133) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp#L19-L77) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L25-L29) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) - -## Architecture Overview -The MongoDB integration is layered: -- Build-time: ENABLE_MONGO_PLUGIN toggles inclusion of the mongo_db target and links MongoDB C++ drivers. -- Runtime: The plugin initializes a MongoDB client, subscribes to chain events, formats documents via state_writer, and performs bulk writes with upserts and selective index creation. - -```mermaid -sequenceDiagram -participant Node as "vizd node" -participant Plugin as "mongo_db_plugin" -participant Writer as "mongo_db_writer" -participant DB as "MongoDB" -Node->>Plugin : Initialize plugin with options -Plugin->>Writer : initialize(uri, write_raw, ops) -Writer->>DB : Connect via URI -Note over Writer,DB : Connection established -Node->>Plugin : applied_block(block) -Plugin->>Writer : on_block(block) -Writer->>Writer : Buffer blocks until LRB -Writer->>Writer : Format docs via state_writer -Writer->>DB : Bulk insert/update per collection -DB-->>Writer : Acknowledged write -Node->>Plugin : post_apply_operation(op) -Plugin->>Writer : on_operation(op) -Writer->>Writer : Track virtual ops for rollback -``` - -**Diagram sources** -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L71-L113) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L68-L133) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L272-L294) - -## Detailed Component Analysis - -### ENABLE_MONGO_PLUGIN CMake Option -- Purpose: Enables MongoDB plugin compilation and links against libmongocxx and libbsoncxx. -- Behavior: - - When TRUE: Adds the mongo_db target, finds libmongocxx and libbsoncxx, links them, and exports the target. - - When FALSE: Skips plugin build and linking. -- Impact on dependencies: Requires MongoDB C drivers to be installed in the build environment for successful linking. - -```mermaid -flowchart TD -Start(["Configure CMake"]) --> CheckOpt["ENABLE_MONGO_PLUGIN = TRUE?"] -CheckOpt --> |Yes| FindDrivers["Find libmongocxx and libbsoncxx"] -FindDrivers --> AddTarget["Add mongo_db target
Link drivers and deps"] -AddTarget --> Export["Export graphene::mongo_db"] -CheckOpt --> |No| Skip["Skip mongo_db build"] -Export --> End(["Build Complete"]) -Skip --> End -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L15-L67) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L1-L81) - -### Dockerfile-mongo: MongoDB Driver Installation and Build -- Installs mongo-c-driver and mongo-cxx-driver from source. -- Configures and builds the C++ driver with a static prefix. -- Builds the project with -DENABLE_MONGO_PLUGIN=TRUE and installs artifacts. - -```mermaid -flowchart TD -DStart(["Dockerfile-mongo build"]) --> InstallC["Install mongo-c-driver"] -InstallC --> InstallCpp["Clone mongo-cxx-driver
Build and install"] -InstallCpp --> CopySrc["Copy repo sources"] -CopySrc --> Configure["cmake -DENABLE_MONGO_PLUGIN=TRUE .."] -Configure --> Make["make -j$(nproc)"] -Make --> Install["make install"] -Install --> DEnd(["Image ready"]) -``` - -**Diagram sources** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L31-L87) - -**Section sources** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L31-L87) - -### mongo_db_plugin: Lifecycle and Event Subscription -- Registers CLI options for mongodb-uri, mongodb-write-raw-blocks, and mongodb-write-operations. -- Initializes the writer with parsed options and subscribes to: - - applied_block: triggers block processing. - - post_apply_operation: tracks virtual operations for rollback safety. - -```mermaid -classDiagram -class mongo_db_plugin { -+set_program_options(cli, cfg) -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() --pimpl_ : mongo_db_plugin_impl -} -class mongo_db_plugin_impl { -+initialize(uri, write_raw, ops) bool -+on_block(block) -+on_operation(notification) --writer : mongo_db_writer --database() : database& -} -mongo_db_plugin --> mongo_db_plugin_impl : "owns" -``` - -**Diagram sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L54-L125) - -**Section sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L54-L125) - -### mongo_db_writer: Connection, Buffering, and Bulk Writes -- Establishes connection from URI, selects database, configures unordered bulk operations. -- Buffers blocks until last irreversible block advances, formats documents, and writes via bulk operations. -- Creates secondary indexes on first use per collection and supports removal updates. - -```mermaid -flowchart TD -Init(["initialize(uri, write_raw, ops)"]) --> Conn["Connect to MongoDB"] -Conn --> Loop["on_block(block)"] -Loop --> Buffer["Buffer by block_num"] -Buffer --> LRB{"Block <= LRB?"} -LRB --> |Yes| Format["Format docs via state_writer"] -Format --> Upsert["Upsert or Insert per doc"] -Upsert --> MaybeIndex{"Index created?"} -MaybeIndex --> |No| CreateIdx["Create indexes"] -MaybeIndex --> |Yes| Next["Next block"] -LRB --> |No| Wait["Wait for LRB advance"] -CreateIdx --> Flush["write_data() bulk write"] -Next --> Flush -Flush --> Done(["Processed"]) -``` - -**Diagram sources** -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L133) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L206-L233) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L272-L294) - -**Section sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_writer.hpp#L42-L90) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L133) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L206-L233) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L272-L294) - -### state_writer: Operation-to-Document Formatting -- Implements visitor operators for various operations (e.g., vote, content, author_reward, curation_reward, content_reward, content_benefactor_reward). -- Produces named_document entries with: - - collection_name: target MongoDB collection. - - key/keyval: composite key for deduplication/upsert. - - indexes_to_create: secondary index specs (e.g., content root content, content votes). - - $set body: fields to update. -- Supports removal documents for soft-deletion semantics. - -```mermaid -classDiagram -class state_writer { -+operator()(vote_operation) -+operator()(content_operation) -+operator()(author_reward_operation) -+operator()(curation_reward_operation) -+operator()(content_reward_operation) -+operator()(content_benefactor_reward_operation) --create_document(name, key, keyval) named_document --create_removal_document(name, key, keyval) named_document --db_ : database& --state_block : signed_block --all_docs : db_map -} -class named_document { -+string collection_name -+document doc -+bool is_removal -+vector indexes_to_create -+string key -+string keyval -} -state_writer --> named_document : "produces" -``` - -**Diagram sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp#L19-L77) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L31-L49) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) - -**Section sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_state.hpp#L19-L77) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L203-L248) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L411-L473) -- [plugins/mongo_db/mongo_db_state.cpp](file://plugins/mongo_db/mongo_db_state.cpp#L501-L530) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) - -### mongo_db_types: Data Structures and Helpers -- named_document: carries collection metadata, BSON document payload, keying, and index specs. -- db_map: multi_index container with random access and hashed unique index for efficient deduplication and replacement. -- Hashing and formatting helpers: SHA1-based OID generation and typed field formatters for BSON. - -```mermaid -classDiagram -class named_document { -+string collection_name -+document doc -+bool is_removal -+vector indexes_to_create -+string key -+string keyval -} -class db_map { -<> -+random_access -+hashed_unique(composite_key) -} -class helpers { -+hash_oid(value) string -+format_oid(doc, name, value) -+format_value(doc, name, value) -} -db_map --> named_document : "stores" -``` - -**Diagram sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) -- [plugins/mongo_db/mongo_db_types.cpp](file://plugins/mongo_db/mongo_db_types.cpp#L7-L14) - -**Section sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp#L40-L85) -- [plugins/mongo_db/mongo_db_types.cpp](file://plugins/mongo_db/mongo_db_types.cpp#L7-L14) - -## Dependency Analysis -- Build dependencies: - - Dockerfile-mongo installs mongo-c-driver and mongo-cxx-driver and passes -DENABLE_MONGO_PLUGIN=TRUE. - - plugins/mongo_db/CMakeLists.txt requires libmongocxx and libbsoncxx to be found and links them to the mongo_db target. - - Root CMakeLists.txt defines ENABLE_MONGO_PLUGIN and conditionally sets compiler flags and library linkage. -- Runtime dependencies: - - mongo_db_plugin depends on chain plugin and JSON RPC plugin. - - mongo_db_writer depends on mongocxx client and BSON builders. - -```mermaid -graph LR -RootCMake["Root CMakeLists.txt
ENABLE_MONGO_PLUGIN"] --> PluginCMake["plugins/mongo_db/CMakeLists.txt"] -PluginCMake --> Drivers["libmongocxx / libbsoncxx"] -Docker["Dockerfile-mongo"] --> Drivers -PluginCMake --> Target["graphene::mongo_db target"] -Target --> AppBase["appbase / fc / graphene libs"] -Plugin["mongo_db_plugin"] --> Chain["chain plugin"] -Plugin --> Writer["mongo_db_writer"] -Writer --> Mongo["MongoDB server"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L15-L67) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L31-L58) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L17-L19) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L66) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L82-L89) -- [plugins/mongo_db/CMakeLists.txt](file://plugins/mongo_db/CMakeLists.txt#L15-L67) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L31-L58) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L17-L19) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L66) - -## Performance Considerations -- Bulk writes: Unordered bulk operations reduce latency by batching inserts/updates per collection. -- Index creation: Indexes are created on first use per collection to avoid repeated overhead. -- Last irreversible block (LRB) buffering: Ensures writes occur only after blocks become irreversible, preventing rollback costs. -- Optional raw block writes: Can be disabled to reduce storage and improve performance when only state/operation indexing is needed. -- Virtual operations: Only virtual operations are written to plugins, reducing unnecessary processing for non-virtual ops. -- Shared memory sizing and thread pool tuning: Configuration options in the MongoDB config help balance concurrency and lock contention. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- MongoDB plugin disabled: - - Cause: mongodb-uri not provided or initialization fails. - - Action: Verify config_mongo.ini has a valid mongodb-uri and plugin list includes mongo_db. -- Driver installation failures: - - Cause: Missing system packages or incompatible driver versions. - - Action: Ensure Dockerfile-mongo installs mongo-c-driver and mongo-cxx-driver; confirm cmake can find libmongocxx and libbsoncxx. -- Connection errors: - - Cause: Incorrect URI, unreachable host, or authentication issues. - - Action: Validate URI in config_mongo.ini; check container networking and firewall rules. -- Bulk write failures: - - Cause: Temporary server issues or malformed documents. - - Action: Review logs around write_data(); ensure indexes are compatible with document shapes. -- Index creation errors: - - Cause: Conflicting index definitions or server-side constraints. - - Action: Inspect index specs generated by state_writer and adjust as needed. - -**Section sources** -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L84-L109) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L39-L66) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L272-L294) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) - -## Conclusion -The MongoDB-enabled Dockerfile variant integrates VIZ CPP Node with MongoDB through a dedicated plugin that listens to blockchain events, formats documents, and performs efficient bulk writes with secondary indexing. The ENABLE_MONGO_PLUGIN CMake option controls build inclusion and links required drivers. Container setup ensures drivers are present and the node is configured to enable the plugin and connect to MongoDB. While MongoDB adds query flexibility and indexing capabilities, it introduces operational overhead and storage considerations compared to native storage. Proper configuration, index planning, and monitoring are essential for reliable performance. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples - -- Enabling MongoDB integration in Docker: - - Use the MongoDB Dockerfile to build an image with drivers and ENABLE_MONGO_PLUGIN=TRUE. - - Mount persistent volumes for /var/lib/vizd and /etc/vizd. - - Expose ports 8090 (HTTP), 8091 (WebSocket), and 2001 (P2P) as defined in the Dockerfile. - -- Connecting to MongoDB: - - Set mongodb-uri in config_mongo.ini to point to your MongoDB instance or replica set. - - Example: mongodb://host:port/dbname or mongodb://user:pass@host:port/dbname with appropriate credentials. - -- Configuring replica sets: - - Deploy MongoDB with replica set configuration. - - Update mongodb-uri to include replica set hosts and set appropriate read/write concerns in the MongoDB client options if needed. - -- Optimizing query performance: - - Leverage secondary indexes created per collection by state_writer (e.g., content root content, content votes). - - Limit tracked operations via mongodb-write-operations to reduce write volume. - - Disable raw block writes if only state/operation indexing is required. - -- Trade-offs and migration: - - Storage requirements: MongoDB documents can be larger than native storage depending on normalization; monitor disk usage. - - Backup strategies: Use MongoDB-native backup tools (e.g., logical dumps or snapshot-based backups) alongside chain snapshots. - - Migration: To switch from native storage to MongoDB, deploy the MongoDB-enabled node, allow indexing to complete, and validate queries. Back up MongoDB collections before major upgrades. - -**Section sources** -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L97-L111) -- [share/vizd/config/config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) -- [plugins/mongo_db/mongo_db_writer.cpp](file://plugins/mongo_db/mongo_db_writer.cpp#L227-L232) -- [plugins/mongo_db/mongo_db_plugin.cpp](file://plugins/mongo_db/mongo_db_plugin.cpp#L58-L67) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Production Dockerfile.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Production Dockerfile.md deleted file mode 100644 index 7843edceee..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Production Dockerfile.md +++ /dev/null @@ -1,347 +0,0 @@ -# Production Dockerfile - - -**Referenced Files in This Document** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [vizd.sh](file://share/vizd/vizd.sh) -- [config.ini](file://share/vizd/config/config.ini) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini) -- [README.md](file://README.md) -- [building.md](file://documentation/building.md) -- [docker-main.yml](file://.github/workflows/docker-main.yml) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the production Dockerfile configuration used to deploy the VIZ C++ node. It covers the multi-stage build process, base image selection, build environment setup, CMake configuration options, dependency installation, build optimization techniques, runtime image construction, user and volumes, and exposed ports. Practical examples for building and running the production container are included, along with guidance for persistent data and network configuration. - -## Project Structure -The production Dockerfile resides under the share/vizd/docker directory and is complemented by runtime scripts and configuration files. The CI/CD pipeline automates building and publishing the production image. - -```mermaid -graph TB -A["Dockerfile-production
Multi-stage build"] --> B["Builder stage
Ubuntu-based build env"] -A --> C["Runtime stage
Production image"] -D["vizd.sh
Entry script"] --> E["Runtime configuration
config.ini"] -F["CI/CD Workflow
docker-main.yml"] --> A -G["Low-memory variant
Dockerfile-lowmem"] --> C -H["MongoDB variant
Dockerfile-mongo"] --> C -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) - -## Core Components -- Multi-stage build: Separates build dependencies from the runtime image for smaller footprint and improved security. -- Base image: Uses phusion/baseimage:bionic-1.0.0 for both stages, ensuring a consistent, minimal Linux environment. -- Build environment: Installs essential build tools, Boost, OpenSSL, Python, and ccache. -- CMake configuration: Sets production defaults for shared libraries, memory profile, locking checks, and plugin enablement. -- Runtime setup: Creates a dedicated user, prepares cache and data directories, installs entry script and configuration, exposes ports, and defines volumes. -- CI/CD automation: Builds and pushes the production image tagged as latest. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [building.md](file://documentation/building.md#L3-L16) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L27-L41) - -## Architecture Overview -The production Dockerfile implements a two-stage build: -- Builder stage: Installs build dependencies, clones the repository, initializes submodules, configures CMake with production flags, compiles with parallel jobs, and installs artifacts. -- Runtime stage: Copies installed artifacts from the builder, creates a non-root user, sets up directories, installs the entry script and configuration, exposes ports, and declares volumes. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant CI as "CI/CD Pipeline" -participant Builder as "Builder Stage" -participant Runtime as "Runtime Stage" -participant Container as "Container Runtime" -Dev->>CI : Trigger build (master branch) -CI->>Builder : Build image with Dockerfile-production -Builder->>Builder : Install deps, clone repo, init submodules -Builder->>Builder : CMake configure (production flags) -Builder->>Builder : make -j$(nproc) -Builder->>Builder : make install -Builder-->>CI : Built artifact layer -CI->>Runtime : Build runtime image -Runtime->>Runtime : Copy artifacts, create user, setup dirs -Runtime->>Runtime : Install entry script & config -Runtime-->>CI : Push image to registry (tag : latest) -CI-->>Container : Pull latest image -Container->>Runtime : Start container -Runtime->>Container : Run entry script (vizd.sh) -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L27-L41) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Detailed Component Analysis - -### Multi-Stage Build Process -- Builder stage: - - Sets environment variables for locale, application directory, and home. - - Installs build tools, Boost, OpenSSL, Python, ccache, and auxiliary utilities. - - Copies only necessary source files to minimize rebuild triggers. - - Initializes Git submodules and configures CMake with production flags. - - Compiles with parallel jobs and installs artifacts. - - Cleans package cache to reduce image size. -- Runtime stage: - - Copies installed artifacts from the builder. - - Creates a non-root user and prepares cache/data directories. - - Installs the entry script and copies configuration files. - - Exposes ports and declares volumes for persistence. - -```mermaid -flowchart TD -Start(["Build Start"]) --> Env["Set ENV vars"] -Env --> InstallDeps["Install build deps
Boost, OpenSSL, Python, ccache"] -InstallDeps --> CopySrc["Copy minimal source tree"] -CopySrc --> Submodule["Init Git submodules"] -Submodule --> Configure["CMake configure
Production flags"] -Configure --> Build["make -j$(nproc)"] -Build --> Install["make install"] -Install --> Clean["Clean package cache"] -Clean --> Runtime["Runtime stage"] -Runtime --> CreateUser["Create non-root user"] -CreateUser --> SetupDirs["Setup cache/data dirs"] -SetupDirs --> InstallScript["Install entry script & config"] -InstallScript --> ExposePorts["Expose ports"] -ExposePorts --> Volumes["Declare volumes"] -Volumes --> End(["Image Ready"]) -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -### Base Image Selection -- phusion/baseimage:bionic-1.0.0 is used for both stages to ensure a stable, minimal Ubuntu 18.04-based environment with a service supervisor suitable for long-running containers. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -### Build Environment Setup -- Essential tools: autoconf, automake, autotools-dev, binutils, bsdmainutils, build-essential, cmake, doxygen, git, libtool, ncurses-dev, pbzip2, pkg-config. -- Libraries: libboost-all-dev, libreadline-dev, libssl-dev. -- Python: python3, python3-dev, python3-pip; gcovr installed via pip. -- ccache enabled for faster incremental builds. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L7-L30) - -### CMake Configuration Options -The production Dockerfile configures CMake with the following flags: -- CMAKE_BUILD_TYPE=Release -- BUILD_SHARED_LIBRARIES=FALSE -- LOW_MEMORY_NODE=FALSE -- CHAINBASE_CHECK_LOCKING=FALSE -- ENABLE_MONGO_PLUGIN=FALSE - -These choices optimize for a production node that: -- Builds optimized binaries. -- Links statically to reduce runtime dependencies. -- Does not enable low-memory mode. -- Disables extra locking checks. -- Disables the MongoDB plugin. - -```mermaid -flowchart TD -A["CMake Configure"] --> B["CMAKE_BUILD_TYPE=Release"] -A --> C["BUILD_SHARED_LIBRARIES=FALSE"] -A --> D["LOW_MEMORY_NODE=FALSE"] -A --> E["CHAINBASE_CHECK_LOCKING=FALSE"] -A --> F["ENABLE_MONGO_PLUGIN=FALSE"] -B --> G["Optimized binary"] -C --> H["Static linking"] -D --> I["Full-feature node"] -E --> J["Reduced overhead"] -F --> K["No MongoDB plugin"] -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L52) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L52) -- [building.md](file://documentation/building.md#L3-L16) - -### Dependency Installation Process -- Boost: Installed via libboost-all-dev to satisfy library requirements. -- OpenSSL: Installed via libssl-dev for cryptographic operations. -- Python: Installed via python3, python3-dev, python3-pip; gcovr installed for coverage reporting. -- Development tools: cmake, git, build-essential, doxygen, autotools, etc. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L19-L30) - -### Build Optimization Techniques -- ccache: Enabled during build to accelerate incremental builds. -- Parallel compilation: make -j$(nproc) uses all CPU cores for faster builds. -- Static linking: BUILD_SHARED_LIBRARIES=FALSE reduces runtime dependencies. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L19-L30) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L54-L54) - -### Runtime Image Construction -- Artifact copy: Copies /usr/local from the builder to the runtime image. -- User creation: Creates a non-root user with a home directory under /var/lib/vizd. -- Cache/data directories: Prepares /var/cache/vizd and sets ownership. -- Entry script: Installs /etc/service/vizd/run to launch the node. -- Configuration: Copies config.ini to /etc/vizd/config.ini and seednodes to /etc/vizd/seednodes. -- Ports: Exposes 8090 (HTTP), 8091 (WebSocket), 2001 (P2P). -- Volumes: Declares persistent volumes for /var/lib/vizd and /etc/vizd. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -### Volume Mounting Configuration -- /var/lib/vizd: Contains blockchain data, configuration overrides, and logs. -- /etc/vizd: Contains initial configuration and seednode lists. -- The entry script ensures proper ownership and can initialize from a cached snapshot if present. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L87-L87) -- [vizd.sh](file://share/vizd/vizd.sh#L7-L53) - -### Exposed Ports -- 8090: HTTP RPC endpoint. -- 8091: WebSocket RPC endpoint. -- 2001: P2P endpoint. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L79-L85) -- [config.ini](file://share/vizd/config/config.ini#L16-L20) - -### Practical Examples - -#### Building the Production Container -- Build locally: - - docker build -t viz:latest -f share/vizd/docker/Dockerfile-production . -- Build with CI/CD: - - The workflow builds and pushes the image tagged as latest. - -**Section sources** -- [README.md](file://README.md#L40-L52) -- [docker-main.yml](file://.github/workflows/docker-main.yml#L27-L41) - -#### Running the Production Container -- Basic run: - - docker run -d -p 2001:2001 -p 8090:8090 -p 8091:8091 --name vizd vizblockchain/vizd:latest -- Attach logs: - - docker logs -f vizd -- Override RPC/P2P endpoints: - - Set VIZD_RPC_ENDPOINT and VIZD_P2P_ENDPOINT environment variables. -- Provide custom seed nodes: - - Set VIZD_SEED_NODES to a whitespace-delimited list of seed nodes. -- Enable validator mode: - - Set VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY environment variables. - -**Section sources** -- [README.md](file://README.md#L21-L29) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L72) - -#### Volume Management for Persistent Blockchain Data -- Mount /var/lib/vizd to persist blockchain data and logs across container restarts. -- Mount /etc/vizd to override configuration and seednodes. -- The entry script initializes from a cached snapshot if present and sets proper ownership. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L87-L87) -- [vizd.sh](file://share/vizd/vizd.sh#L44-L53) - -#### Network Configuration for Node Connectivity -- Publish host ports 2001 (P2P), 8090 (HTTP), and 8091 (WebSocket) to allow external clients and peers to connect. -- Seed nodes are loaded from /etc/vizd/seednodes by default; override via VIZD_SEED_NODES. -- The entry script allows overriding RPC and P2P endpoints via environment variables. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L79-L85) -- [vizd.sh](file://share/vizd/vizd.sh#L11-L29) - -## Dependency Analysis -The production Dockerfile depends on: -- phusion/baseimage:bionic-1.0.0 for both stages. -- Build dependencies installed in the builder stage. -- CMake configuration flags controlling node behavior. -- Runtime configuration files and entry script. - -```mermaid -graph LR -DF["Dockerfile-production"] --> IMG["phusion/baseimage:bionic-1.0.0"] -DF --> DEPS["Build deps
Boost, OpenSSL, Python, ccache"] -DF --> CMAKE["CMake flags
Production defaults"] -DF --> RUNTIME["Runtime setup
User, dirs, script, config"] -RUNTIME --> CFG["config.ini"] -RUNTIME --> SCRIPT["vizd.sh"] -``` - -**Diagram sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -## Performance Considerations -- Static linking reduces runtime dependencies and improves portability. -- Parallel compilation accelerates builds using all available CPU cores. -- ccache speeds up incremental builds by caching compiled objects. -- Production defaults disable extra locking checks and MongoDB plugin to reduce overhead. - -**Section sources** -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) -- [building.md](file://documentation/building.md#L3-L16) - -## Troubleshooting Guide -- Port conflicts: Ensure host ports 2001, 8090, and 8091 are free when running the container. -- Permission issues: The entry script sets ownership for /var/lib/vizd; ensure mounted volumes have correct permissions. -- Configuration overrides: Place a custom config.ini in /etc/vizd to override defaults. -- Seed nodes: Provide VIZD_SEED_NODES to override the default seednodes list. -- validator mode: Set VIZD_WITNESS_NAME and VIZD_PRIVATE_KEY to enable validator participation. - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L7-L53) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -## Conclusion -The production Dockerfile provides a robust, secure, and efficient way to deploy the VIZ C++ node. Its multi-stage build minimizes attack surface and image size, while CMake flags tailor the node for production. The runtime setup ensures non-root execution, persistent storage, and straightforward networking. The CI/CD pipeline automates building and publishing the latest image, and the entry script simplifies customization via environment variables. - -## Appendices - -### Additional Variants -- Low-memory variant: Enables LOW_MEMORY_NODE=TRUE for resource-constrained environments. -- MongoDB variant: Installs MongoDB drivers and enables ENABLE_MONGO_PLUGIN=TRUE with a dedicated configuration. - -**Section sources** -- [Dockerfile-lowmem](file://share/vizd/docker/Dockerfile-lowmem#L47-L50) -- [Dockerfile-mongo](file://share/vizd/docker/Dockerfile-mongo#L78-L79) -- [config_mongo.ini](file://share/vizd/config/config_mongo.ini#L69-L72) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Testnet Dockerfile.md b/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Testnet Dockerfile.md deleted file mode 100644 index 1d38025472..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Build System/Docker Integration/Testnet Dockerfile.md +++ /dev/null @@ -1,369 +0,0 @@ -# Testnet Dockerfile - - -**Referenced Files in This Document** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [config.ini](file://share/vizd/config/config.ini) -- [vizd.sh](file://share/vizd/vizd.sh) -- [seednodes](file://share/vizd/seednodes) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json) -- [CMakeLists.txt](file://CMakeLists.txt) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp) -- [get_config.cpp](file://libraries/protocol/get_config.cpp) -- [testnet.md](file://documentation/testnet.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the testnet Dockerfile variant designed for deploying VIZ test network nodes. It highlights differences from the production configuration, focusing on testnet-specific CMake options, configuration files, bootstrap behavior, seed node setup, and RPC endpoints. It also covers automated snapshot loading, genesis-like initialization, and practical operational guidance for running and connecting to testnet networks. - -## Project Structure -The testnet Dockerfile variant resides under share/vizd/docker and integrates with testnet-specific configuration and scripts: -- Dockerfile-testnet builds the node with BUILD_TESTNET enabled and packages testnet-specific assets. -- config_testnet.ini sets testnet RPC endpoints, P2P ports, logging, and plugin selection. -- vizd.sh orchestrates container startup, seed node resolution, optional replay, and runtime arguments. -- snapshot-testnet.json provides pre-defined test accounts for quick testing. -- seednodes lists known testnet seed nodes for initial connectivity. - -```mermaid -graph TB -subgraph "Docker Build" -DF["Dockerfile-testnet"] -CMake["CMakeLists.txt
BUILD_TESTNET=TRUE"] -CFG["config_testnet.ini"] -SH["vizd.sh"] -SNAP["snapshot-testnet.json"] -SEED["seednodes"] -end -DF --> CMake -DF --> CFG -DF --> SH -DF --> SNAP -DF --> SEED -``` - -**Diagram sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [CMakeLists.txt](file://CMakeLists.txt#L55-L64) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L88) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -## Core Components -- Testnet Dockerfile: Builds with BUILD_TESTNET enabled, installs testnet config, snapshot, and seed nodes, exposes testnet RPC and P2P ports, and declares persistent volumes for data and config. -- Testnet configuration: Defines RPC endpoints, P2P settings, plugin list, and validator production parameters tuned for testnet. -- Startup script: Resolves seed nodes, applies environment overrides, optionally replays from cached blockchain, and launches the node with proper data directory ownership. -- Snapshot: Pre-populates test accounts for immediate testing without manual account creation. -- Seed nodes: Provides initial peers for testnet connectivity. - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L9-L29) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -## Architecture Overview -The testnet container architecture centers on the testnet Dockerfile’s build-time and runtime behavior, testnet configuration, and startup orchestration. - -```mermaid -graph TB -subgraph "Container Runtime" -RUN["vizd.sh"] -VIZD["vizd binary"] -CFG["/etc/vizd/config.ini"] -DATA["/var/lib/vizd"] -SNAP["/var/lib/vizd/snapshot.json"] -SEED["/etc/vizd/seednodes"] -end -subgraph "Build-time" -DFT["Dockerfile-testnet"] -CMAKE["CMake BUILD_TESTNET=TRUE"] -CTI["config_testnet.ini"] -VSH["vizd.sh"] -SST["snapshot-testnet.json"] -SDN["seednodes"] -end -DFT --> CMAKE -DFT --> CTI -DFT --> VSH -DFT --> SST -DFT --> SDN -RUN --> CFG -RUN --> DATA -RUN --> SNAP -RUN --> SEED -RUN --> VIZD -``` - -**Diagram sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -## Detailed Component Analysis - -### Testnet Dockerfile Differences from Production -- Build option: Enables BUILD_TESTNET during CMake configuration. -- Assets: Copies testnet-specific config, snapshot, and seed nodes. -- Ports: Exposes testnet RPC endpoints (HTTP and WS) and P2P port. -- Volumes: Declares persistent volumes for data and config directories. - -```mermaid -flowchart TD -Start(["Build Start"]) --> CopyFiles["Copy Source & Config"] -CopyFiles --> Submodules["Initialize Git Submodules"] -Submodules --> Configure["cmake -DBUILD_TESTNET=TRUE ..."] -Configure --> Make["make -j$(nproc)"] -Make --> Install["make install"] -Install --> FinalStage["Final Stage Image"] -FinalStage --> CopyAssets["Copy testnet config, snapshot, seednodes"] -CopyAssets --> ExposePorts["Expose RPC and P2P"] -ExposePorts --> VolumeDecl["Declare /var/lib/vizd and /etc/vizd volumes"] -VolumeDecl --> End(["Ready"]) -``` - -**Diagram sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L32-L65) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L75-L87) - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L75-L87) -- [Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L46-L54) - -### Testnet CMake Configuration and Build Flags -- BUILD_TESTNET: When enabled, adds a preprocessor definition and includes testnet-specific protocol constants and configuration. -- Impact: Selects testnet chain parameters, address prefix, block interval, and other consensus settings. - -```mermaid -flowchart TD -A["CMakeLists.txt
BUILD_TESTNET option"] --> B{"Enabled?"} -B --> |Yes| C["Add -DBUILD_TESTNET to compiler flags"] -C --> D["Include config_testnet.hpp in protocol"] -D --> E["Use testnet chain parameters"] -B --> |No| F["Default production config"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L55-L64) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L2-L6) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L55-L64) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L2-L6) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -### Testnet Configuration and RPC Endpoints -- P2P endpoint: Listens on a testnet-specific port. -- RPC endpoints: HTTP and WebSocket endpoints configured for testnet. -- Plugins: Includes chain, p2p, json_rpc, webserver, and other plugins suitable for testnet development and testing. -- validator production: Enabled with configurable participation thresholds and validator name/key for testnet block production. - -```mermaid -flowchart TD -CFG["config_testnet.ini"] --> P2P["p2p-endpoint"] -CFG --> RPC["webserver-http-endpoint
webserver-ws-endpoint"] -CFG --> PLUGINS["plugin list"] -CFG --> validator["validator and private-key"] -``` - -**Diagram sources** -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -**Section sources** -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) - -### Testnet Bootstrap and Snapshot Loading -- Snapshot availability: The startup script checks for a cached blockchain archive and, if present, replays it to initialize the chain quickly. -- Snapshot content: Testnet snapshot includes predefined accounts with initial balances, enabling immediate testing without manual account creation. -- Seed nodes: The script reads seednodes and passes them to the node as seed peers. - -```mermaid -sequenceDiagram -participant Script as "vizd.sh" -participant FS as "Filesystem" -participant Node as "vizd" -participant Seed as "Seed Nodes" -Script->>FS : Check /var/cache/vizd/blocks.tbz2 -alt Found -Script->>Script : Append --replay-blockchain -Script->>FS : Extract blocks.tbz2 to /var/lib/vizd/blockchain -else Not Found -Script->>Script : Proceed without replay -end -Script->>FS : Read /etc/vizd/seednodes -Script->>Seed : Resolve seed nodes -Script->>Node : exec vizd with args and env overrides -``` - -**Diagram sources** -- [vizd.sh](file://share/vizd/vizd.sh#L44-L53) -- [vizd.sh](file://share/vizd/vizd.sh#L17-L29) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L44-L53) -- [vizd.sh](file://share/vizd/vizd.sh#L17-L29) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) - -### Testnet RPC Endpoint Setup and Environment Overrides -- RPC endpoint override: The script allows overriding the RPC endpoint via an environment variable. -- P2P endpoint override: Similarly supports overriding the P2P endpoint. -- validator customization: Allows setting the validator name and private key via environment variables. - -```mermaid -flowchart TD -ENV["Environment Variables"] --> RPC["VIZD_RPC_ENDPOINT"] -ENV --> P2P["VIZD_P2P_ENDPOINT"] -ENV --> WIT["VIZD_WITNESS_NAME"] -ENV --> KEY["VIZD_PRIVATE_KEY"] -RPC --> ARG["--rpc-endpoint"] -P2P --> ARG -WIT --> ARG -KEY --> ARG -``` - -**Diagram sources** -- [vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [vizd.sh](file://share/vizd/vizd.sh#L31-L37) - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [vizd.sh](file://share/vizd/vizd.sh#L31-L37) - -### Testnet Volume Mounts and Persistence -- Data directory: Persistent storage for blockchain data and runtime state. -- Config directory: Persistent storage for configuration overrides and logs. - -```mermaid -graph LR -Host["Host Machine"] --> Vol1["/var/lib/vizd"] -Host --> Vol2["/etc/vizd"] -Vol1 --> Container["Container Data Dir"] -Vol2 --> Container["Container Config Dir"] -``` - -**Diagram sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L87-L87) - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L87-L87) - -### Practical Examples: Running Testnet Containers -- Build the testnet image from the repository. -- Run a container and tail logs to observe bootstrapping and synchronization progress. -- Use the pre-built image from the registry. - -Refer to the documentation for exact commands and additional users available in the testnet snapshot. - -**Section sources** -- [testnet.md](file://documentation/testnet.md#L21-L37) - -## Dependency Analysis -The testnet Dockerfile depends on: -- CMake configuration enabling BUILD_TESTNET to select testnet protocol constants. -- Testnet configuration file for RPC and plugin settings. -- Startup script for seed node resolution and runtime argument assembly. -- Snapshot and seed nodes for bootstrap convenience. - -```mermaid -graph TB -DFT["Dockerfile-testnet"] --> CMake["CMakeLists.txt
BUILD_TESTNET"] -DFT --> CTI["config_testnet.ini"] -DFT --> VSH["vizd.sh"] -DFT --> SST["snapshot-testnet.json"] -DFT --> SDN["seednodes"] -CMake --> Proto["config_testnet.hpp"] -CTI --> NodeCfg["Node Runtime Config"] -VSH --> Node["vizd Binary"] -``` - -**Diagram sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [CMakeLists.txt](file://CMakeLists.txt#L55-L64) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L46-L55) -- [CMakeLists.txt](file://CMakeLists.txt#L55-L64) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [seednodes](file://share/vizd/seednodes#L1-L6) -- [config_testnet.hpp](file://libraries/protocol/include/graphene/protocol/config_testnet.hpp#L1-L170) - -## Performance Considerations -- Testnet block interval is shorter than production, accelerating iteration cycles for developers. -- Shared memory sizing and growth parameters are tuned for testnet throughput and stability. -- Single write thread and reduced plugin notifications on push transactions can improve performance under load. -- Logging levels are set to aid debugging during testnet runs. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- No seed nodes provided: The startup script automatically loads seed nodes from the built-in seed list if none are supplied via environment variables. -- RPC endpoint conflicts: Override the RPC endpoint using the environment variable to avoid port conflicts. -- P2P endpoint conflicts: Override the P2P endpoint similarly. -- validator production: Ensure the validator name and private key match the testnet configuration when attempting to produce blocks. -- Snapshot not applied: Verify the presence of the snapshot file and that the node has permission to read it. -- Connectivity delays: Allow time for the node to discover peers and synchronize; monitor logs for peer connection and block sync progress. - -**Section sources** -- [vizd.sh](file://share/vizd/vizd.sh#L17-L29) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L72) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L105-L112) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) - -## Conclusion -The testnet Dockerfile variant streamlines deployment of VIZ test network nodes by enabling BUILD_TESTNET, packaging testnet-specific configuration, snapshot, and seed nodes, and exposing appropriate RPC and P2P endpoints. The startup script automates seed node resolution, optional replay, and runtime customization, making it straightforward to run and connect to the testnet for development and testing. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Testnet RPC and P2P Port Exposure -- HTTP RPC: Exposed on the testnet port. -- WebSocket RPC: Exposed on the testnet port. -- P2P: Exposed on the testnet port. - -**Section sources** -- [Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L79-L85) - -### Appendix B: Testnet Genesis and Snapshot Accounts -- Snapshot includes predefined accounts with initial balances for immediate testing. -- Additional users are available for testing without manual account creation. - -**Section sources** -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L35) -- [testnet.md](file://documentation/testnet.md#L39-L54) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debug Node Plugin.md b/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debug Node Plugin.md deleted file mode 100644 index 86e170874b..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debug Node Plugin.md +++ /dev/null @@ -1,348 +0,0 @@ -# Debug Node Plugin - - -**Referenced Files in This Document** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [1.hf](file://libraries/chain/hardfork.d/1.hf) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -The debug node plugin is a development and debugging tool designed to manipulate blockchain state locally for testing, reproducibility, and experimentation. It enables: -- Generating blocks programmatically for rapid scenario testing -- Importing existing blockchain data via binary block logs or JSON arrays -- Inspecting and modifying validator scheduling and hardfork state -- Applying targeted database edits during block application - -It integrates with the chain plugin for database access and the JSON-RPC plugin for API exposure, allowing controlled manipulation of chain state without affecting consensus on public networks. - -## Project Structure -The debug node plugin resides under plugins/debug_node and exposes a set of APIs registered via the JSON-RPC plugin. It depends on the chain plugin for database operations and uses the JSON-RPC plugin to serve API methods. - -```mermaid -graph TB -subgraph "Plugins" -DN["debug_node plugin
plugin.cpp"] -CH["chain plugin
plugin.cpp"] -JR["json_rpc plugin
plugin.cpp"] -end -subgraph "Libraries" -DBH["database.hpp
database interface"] -HF["hardfork.d/*.hf
hardfork definitions"] -end -DN --> CH -DN --> JR -DN --> DBH -CH --> DBH -CH --> HF -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L1-L668) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L1-L200) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L1-L200) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L1-L668) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L1-L200) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L1-L200) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) - -## Core Components -- Plugin lifecycle and registration - - Initializes program options, connects to chain plugin database signals, and registers JSON-RPC APIs. -- Public APIs exposed - - Block generation: debug_generate_blocks, debug_generate_blocks_until - - Block import: debug_push_blocks, debug_push_json_blocks - - State inspection: debug_pop_block, debug_get_witness_schedule - - Hardfork control: debug_set_hardfork, debug_has_hardfork -- Internal mechanisms - - Uses database flags to skip validations for faster import - - Applies targeted database edits per block head to simulate state changes - - Logs and conditionally modifies validator signing keys to enable block production - -Key API definitions and declarations are declared in the plugin header and implemented in the plugin source. - -**Section sources** -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L25-L108) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L31-L60) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L475-L556) - -## Architecture Overview -The debug node plugin orchestrates block generation and import through the chain plugin’s database interface and serves methods via the JSON-RPC plugin. It listens to applied-block events to apply debug updates against the current head block. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant RPC as "JSON-RPC Plugin" -participant DBG as "debug_node plugin" -participant CH as "chain plugin" -participant DB as "database" -Client->>RPC : "call , , " -RPC->>DBG : "dispatch to debug_* API" -DBG->>CH : "access database()" -CH->>DB : "execute operation (generate/push/pop/schedule/hardfork)" -DB-->>CH : "result or exception" -CH-->>DBG : "result or exception" -DBG-->>RPC : "result" -RPC-->>Client : "JSON-RPC response" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L117-L136) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L479-L555) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L180-L200) - -## Detailed Component Analysis - -### API Surface and Responsibilities -- debug_push_blocks - - Imports blocks from a binary block log starting after the current head block. - - Returns the number of blocks successfully imported. -- debug_push_json_blocks - - Imports blocks from a JSON file containing an array of signed blocks. - - Supports skip flags to bypass validations for faster import. -- debug_generate_blocks - - Generates a given number of blocks by scheduling the current head time and modifying validator signing keys if needed. - - Accepts skip flags and optional key editing to align validator keys with the provided private key. -- debug_generate_blocks_until - - Generates blocks until the chain head reaches a specified absolute time, optionally skipping intermediate slots. -- debug_pop_block - - Returns the last block without popping it from the chain (useful for inspection). -- debug_get_witness_schedule - - Retrieves the current validator schedule object for inspection. -- debug_set_hardfork - - Sets the active hardfork to a given ID (no-op if beyond supported range). -- debug_has_hardfork - - Checks whether the chain has reached or exceeded a given hardfork ID. - -```mermaid -flowchart TD -Start(["Call debug_push_json_blocks"]) --> CheckCount["count == 0?"] -CheckCount --> |Yes| ReturnZero["Return 0"] -CheckCount --> |No| ValidateFile["Validate JSON file exists and is readable"] -ValidateFile --> |Fail| LogError["Log error and return 0"] -ValidateFile --> |Success| LoadArray["Load array of signed blocks"] -LoadArray --> Iterate["Iterate up to 'count' blocks"] -Iterate --> PushBlock["Push each block with skip_flags"] -PushBlock --> NextOrDone{"More blocks?"} -NextOrDone --> |Yes| Iterate -NextOrDone --> |No| Done(["Return total pushed"]) -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L374-L420) - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L31-L60) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L321-L420) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L479-L555) - -### Block Generation Workflow -The block generation process selects the scheduled validator for the next slot, compares its signing key with the provided debug key, optionally edits the validator object to match, and generates a block signed by the debug key. - -```mermaid -flowchart TD -Enter(["debug_generate_blocks"]) --> ZeroCheck{"count == 0?"} -ZeroCheck --> |Yes| Exit0["Return 0"] -ZeroCheck --> |No| ParseKey["Parse WIF private key"] -ParseKey --> ValidKey{"Valid key?"} -ValidKey --> |No| Exit0 -ValidKey --> |Yes| Loop["While produced < count"] -Loop --> SlotCalc["Compute slot and scheduled validator"] -SlotCalc --> CompareKey{"Scheduled key == debug key?"} -CompareKey --> |No| EditNeeded{"edit_if_needed?"} -EditNeeded --> |No| ExitLoop["Break loop"] -EditNeeded --> |Yes| ApplyEdit["Apply debug_update to modify validator signing key"] -ApplyEdit --> Loop -CompareKey --> |Yes| GenBlock["Generate block at scheduled time"] -GenBlock --> Inc["Increment produced and slot"] -Inc --> Loop -Loop --> ExitLoop -ExitLoop --> Return(["Return produced count"]) -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L222-L288) - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L222-L288) - -### validator Schedule Inspection -Retrieves the current validator schedule object from the database for inspection and debugging. - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L427-L430) - -### Hardfork Management -- debug_set_hardfork - - Sets the active hardfork ID if within supported range. -- debug_has_hardfork - - Checks if the stored hardfork property indicates the chain has reached or exceeded the given hardfork ID. - -These methods rely on the database’s hardfork property object and internal hardfork arrays. - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L441-L454) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L429-L524) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) - -### Integration with Chain and JSON-RPC Plugins -- Chain plugin - - Provides the database instance and handles block acceptance/validation. - - Offers skip flags to bypass expensive checks during import. -- JSON-RPC plugin - - Registers the debug_node API methods and dispatches requests to the plugin. - - Manages request parsing, argument validation, and response formatting. - -```mermaid -classDiagram -class DebugNodePlugin { -+set_program_options(cli, cfg) -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+debug_push_blocks(src, count) -+debug_push_json_blocks(file, count, skip) -+debug_generate_blocks(key, count, skip, miss, edit) -+debug_generate_blocks_until(key, time, sparse, skip) -+debug_pop_block() -+debug_get_witness_schedule() -+debug_set_hardfork(id) -+debug_has_hardfork(id) -} -class ChainPlugin { -+db() database& -+accept_block(block, currently_syncing, skip) -+accept_transaction(trx) -} -class JsonRpcPlugin { -+add_api_method(api_name, method_name, api) -+find_api_method(api, method) -+process_params(...) -} -DebugNodePlugin --> ChainPlugin : "uses database()" -DebugNodePlugin --> JsonRpcPlugin : "registers APIs" -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L104-L136) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L159-L178) - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L104-L136) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L169-L182) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp#L159-L178) - -## Dependency Analysis -- Internal dependencies - - debug_node plugin requires chain plugin for database access and signals. - - Uses fc utilities for filesystem, JSON parsing, and logging. -- External dependencies - - JSON-RPC plugin for API registration and request handling. - - Hardfork definitions under hardfork.d for version/time constants. - -```mermaid -graph LR -DN["debug_node plugin"] --> CH["chain plugin"] -DN --> JR["json_rpc plugin"] -CH --> HF["hardfork.d/*.hf"] -DN --> FC["fc utilities"] -``` - -**Diagram sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L1-L20) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L1-L20) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L1-L20) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L1-L20) -- [1.hf](file://libraries/chain/hardfork.d/1.hf#L1-L7) - -## Performance Considerations -- Skip flags - - Use skip flags (e.g., skip_witness_signature, skip_authority_check, skip_witness_schedule_check) when importing blocks to avoid heavy validations. -- Batch operations - - Prefer debug_push_blocks or debug_push_json_blocks with reasonable counts to minimize repeated I/O. -- Logging overhead - - Disable logging in performance-sensitive scenarios to reduce I/O and CPU overhead. -- Block generation - - Limit the number of generated blocks and avoid unnecessary key edits to reduce database modifications. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Empty or invalid JSON file - - Ensure the JSON file contains an array of signed blocks and is readable. -- Block log not found or incomplete - - Verify the block log path and index exist and contain sufficient blocks. -- Validation failures during import - - Use appropriate skip flags to bypass checks; confirm compatibility with mainnet/testnet block formats. -- validator key mismatch - - Provide a valid WIF private key and allow key editing if needed; otherwise, block generation will halt. -- Hardfork ID out of range - - Set hardfork ID within supported bounds; exceeding the maximum has no effect. - -Operational tips: -- Bind RPC and P2P endpoints to localhost for development. -- Restrict public API exposure when debug_node_api is enabled. -- Use sparse generation for large time jumps to reduce intermediate blocks. - -**Section sources** -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L374-L420) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L321-L372) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L222-L288) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L441-L454) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) - -## Conclusion -The debug node plugin provides powerful tools for blockchain state manipulation in development environments. It supports rapid block generation, efficient import of existing data, validator schedule inspection, and hardfork control. Proper use of skip flags, careful key management, and restricted API exposure ensures safe and effective debugging without compromising production integrity. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Debugging Workflows -- Creating a test environment from live chain data - - Export blocks from a live node, start a new node with debug_node enabled, and import blocks via debug_push_blocks or debug_push_json_blocks. -- Reproducing edge cases - - Generate blocks until a specific time, adjust hardfork state, and simulate validator key changes to reproduce timing-sensitive issues. -- Validating state changes - - Inspect validator schedules and hardfork properties, then generate blocks to observe behavioral differences. - -**Section sources** -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) - -### Security Considerations -- Development vs production - - Enable debug_node only in isolated development environments; restrict RPC access to localhost and avoid exposing debug_node_api publicly. -- Database edits - - Treat debug updates as ephemeral and local; they do not affect consensus and are not propagated to other nodes. -- Private key handling - - Use disposable keys for debugging; never deploy debug keys in production configurations. - -**Section sources** -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L18-L71) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debugging Tools.md b/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debugging Tools.md deleted file mode 100644 index 439138bc26..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Debugging Tools.md +++ /dev/null @@ -1,523 +0,0 @@ -# Debugging Tools - - -**Referenced Files in This Document** -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [api_helper.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [node.cpp](file://libraries/network/node.cpp) - - -## Update Summary -**Changes Made** -- Enhanced P2P plugin logging section to document ANSI color code improvements -- Added detailed explanation of color-coded logging for different network event types -- Updated network debugging section with specific color coding examples -- Added console readability and debugging efficiency benefits -- Updated troubleshooting guide with color-based log analysis techniques - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the debugging tooling available in the VIZ C++ Node, focusing on: -- The debug node plugin for state inspection, transaction tracing, and blockchain state visualization -- Transaction serialization utilities for diagnosing signing issues -- Network debugging and peer connection monitoring with enhanced ANSI color-coded logging -- Performance profiling and memory analysis utilities -- Practical debugging workflows for unit testing to production troubleshooting - -The goal is to provide a practical guide for developers and operators to diagnose and resolve issues efficiently, with references to concrete source files and configuration examples. - -**Updated** Enhanced P2P plugin logging now provides visual distinction through ANSI color codes for different types of network events, significantly improving console readability and debugging efficiency. - -## Project Structure -The debugging tooling spans several areas: -- The debug node plugin that enables "what-if" experiments and block generation/state manipulation -- Utilities for signing transactions and digests to validate signing logic -- P2P and network components that surface peer connection and message handling details with enhanced color-coded logging -- Configuration templates optimized for debugging and performance tuning - -```mermaid -graph TB -subgraph "Debug Node Plugin" -DNP["plugin.hpp"] -DNPImpl["plugin.cpp"] -AH["api_helper.hpp"] -end -subgraph "Utilities" -ST["sign_transaction.cpp"] -SD["sign_digest.cpp"] -end -subgraph "Network" -P2P["p2p_plugin.cpp"] -NETNode["node.hpp"] -PeerConn["peer_connection.hpp"] -end -CFG["config_debug.ini"] -DNP --> DNPImpl -DNPImpl --> AH -ST --> DNPImpl -SD --> DNPImpl -P2P --> NETNode -P2P --> PeerConn -CFG --> DNPImpl -CFG --> P2P -``` - -**Diagram sources** -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) -- [plugin.cpp:25-94](file://plugins/debug_node/plugin.cpp#L25-L94) -- [api_helper.hpp:1-108](file://plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp#L1-L108) -- [sign_transaction.cpp:12-26](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_digest.cpp:12-24](file://programs/util/sign_digest.cpp#L12-L24) -- [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) -- [node.hpp:190-200](file://libraries/network/include/graphene/network/node.hpp#L190-L200) -- [peer_connection.hpp:79-200](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L200) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) - -**Section sources** -- [plugin.hpp:1-111](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L1-L111) -- [plugin.cpp:1-668](file://plugins/debug_node/plugin.cpp#L1-L668) -- [api_helper.hpp:1-108](file://plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp#L1-L108) -- [sign_transaction.cpp:1-54](file://programs/util/sign_transaction.cpp#L1-L54) -- [sign_digest.cpp:1-49](file://programs/util/sign_digest.cpp#L1-L49) -- [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) -- [node.hpp:1-200](file://libraries/network/include/graphene/network/node.hpp#L1-L200) -- [peer_connection.hpp:1-200](file://libraries/network/include/graphene/network/peer_connection.hpp#L1-L200) -- [config_debug.ini:1-126](file://share/vizd/config/config_debug.ini#L1-L126) - -## Core Components -- Debug node plugin - - Provides APIs to push blocks from disk or JSON, generate blocks locally, pop blocks, inspect validator schedule, and control hardfork state - - Supports applying database updates at specific block heights and logging decisions - - Exposes program options for initial database edit scripts -- Transaction signing utilities - - Standalone CLI tools to compute transaction digests, signature digests, and signatures given WIF keys -- Network debugging with enhanced visual distinction - - P2P plugin logs block acceptance and transaction ingestion with ANSI color codes - - Network node and peer connection abstractions expose peer status and message propagation metadata - - Color-coded logging improves console readability and debugging efficiency - -Key capabilities: -- State inspection via database access and validator schedule retrieval -- Transaction tracing by generating blocks and observing accepted transactions -- Blockchain state visualization by replaying blocks from logs or JSON -- Signing diagnostics using deterministic signing utilities -- Enhanced network debugging through visual color coding - -**Updated** Enhanced P2P plugin logging now uses ANSI color codes to provide visual distinction for different types of network events, including block processing messages in white color, peer statistics in cyan color, and detailed debugging information in gray color. - -**Section sources** -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) -- [plugin.cpp:25-94](file://plugins/debug_node/plugin.cpp#L25-L94) -- [plugin.cpp:222-288](file://plugins/debug_node/plugin.cpp#L222-L288) -- [plugin.cpp:321-420](file://plugins/debug_node/plugin.cpp#L321-L420) -- [plugin.cpp:489-555](file://plugins/debug_node/plugin.cpp#L489-L555) -- [sign_transaction.cpp:12-26](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_digest.cpp:12-24](file://programs/util/sign_digest.cpp#L12-L24) -- [p2p_plugin.cpp:118-170](file://plugins/p2p/p2p_plugin.cpp#L118-L170) -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) - -## Architecture Overview -The debug node plugin integrates with the chain plugin and JSON-RPC to expose a set of debugging APIs. It manipulates the database to simulate conditions and replay blocks from external sources. Network debugging leverages the P2P plugin's enhanced logging hooks with ANSI color codes and the network node's peer management. - -```mermaid -sequenceDiagram -participant Client as "RPC Client" -participant JSONRPC as "JSON-RPC Layer" -participant DNP as "debug_node plugin" -participant DB as "Chain Database" -participant P2P as "P2P Plugin" -Client->>JSONRPC : "call debug_push_blocks(src,count)" -JSONRPC->>DNP : "debug_push_blocks(...)" -DNP->>DB : "push_block(block, skip_flags)" -DB-->>DNP : "accepted or exception" -DNP-->>JSONRPC : "count of blocks pushed" -JSONRPC-->>Client : "result" -Note over Client,P2P : "Enhanced P2P plugin logs with ANSI color codes for improved readability" -``` - -**Diagram sources** -- [plugin.cpp:489-511](file://plugins/debug_node/plugin.cpp#L489-L511) -- [plugin.cpp:321-372](file://plugins/debug_node/plugin.cpp#L321-L372) -- [p2p_plugin.cpp:118-170](file://plugins/p2p/p2p_plugin.cpp#L118-L170) - -## Detailed Component Analysis - -### Debug Node Plugin -The debug node plugin offers: -- Block replay from block log and JSON arrays -- Local block generation with configurable validator key and skipping of validations -- Database update hooks applied at specific block heights -- Hardfork state control and validator schedule inspection - -```mermaid -classDiagram -class plugin { -+set_program_options(cli, cfg) -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+DECLARE_API(...) -+debug_update(callback, skip) -+set_logging(islogging) -} -class plugin_impl { -+debug_push_blocks(src, count) uint32_t -+debug_push_json_blocks(file, count, skip) uint32_t -+debug_generate_blocks(key, count, skip, miss, edit) uint32_t -+debug_generate_blocks_until(key, time, sparse, skip) uint32_t -+debug_pop_block() optional -+debug_get_witness_schedule() witness_schedule_object -+debug_set_hardfork(id) void -+debug_has_hardfork(id) bool -+apply_debug_updates() void -+on_applied_block(b) void -} -plugin --> plugin_impl : "owns" -``` - -**Diagram sources** -- [plugin.hpp:38-108](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) -- [plugin.cpp:25-94](file://plugins/debug_node/plugin.cpp#L25-L94) -- [plugin.cpp:222-555](file://plugins/debug_node/plugin.cpp#L222-L555) - -Key behaviors: -- Block replay honors skip flags to bypass expensive validations when needed -- Local block generation modifies validator signing keys to accept self-signed blocks -- Hardfork state can be set programmatically for testing activation logic -- Logging toggles help reduce noise during automated tests - -Practical usage patterns: -- Replay historical blocks from a block log to reproduce state -- Generate blocks deterministically for consensus timing tests -- Inspect validator schedule and hardfork state during debugging sessions - -**Section sources** -- [plugin.cpp:321-420](file://plugins/debug_node/plugin.cpp#L321-L420) -- [plugin.cpp:222-288](file://plugins/debug_node/plugin.cpp#L222-L288) -- [plugin.cpp:441-454](file://plugins/debug_node/plugin.cpp#L441-L454) -- [plugin.cpp:422-430](file://plugins/debug_node/plugin.cpp#L422-L430) -- [plugin.cpp:117-136](file://plugins/debug_node/plugin.cpp#L117-L136) - -### Transaction Serialization Utilities -Two standalone utilities support signing diagnostics: -- sign_transaction: computes digest and signature digest, signs a transaction, and prints results -- sign_digest: signs a raw digest with a WIF key and prints the signature - -```mermaid -flowchart TD -Start(["Read JSON line"]) --> Parse["Parse JSON to signing request"] -Parse --> Compute["Compute tx.digest() and tx.sig_digest(CHAIN_ID)"] -Compute --> LoadKey["Load private key from WIF"] -LoadKey --> Sign["Sign sig_digest to produce signature"] -Sign --> Emit["Emit JSON result with digest, sig_digest, key, signature"] -Emit --> End(["Next line"]) -``` - -**Diagram sources** -- [sign_transaction.cpp:28-53](file://programs/util/sign_transaction.cpp#L28-L53) -- [sign_digest.cpp:26-48](file://programs/util/sign_digest.cpp#L26-L48) - -Common debugging scenarios: -- Verifying transaction signing failures by comparing computed sig_digest against wallet-produced signatures -- Confirming chain ID correctness by ensuring sig_digest matches expected chain ID -- Isolating signature malleability or encoding issues by printing compact signatures - -**Section sources** -- [sign_transaction.cpp:12-26](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_transaction.cpp:28-53](file://programs/util/sign_transaction.cpp#L28-L53) -- [sign_digest.cpp:12-24](file://programs/util/sign_digest.cpp#L12-L24) -- [sign_digest.cpp:26-48](file://programs/util/sign_digest.cpp#L26-L48) - -### Network Debugging and Peer Monitoring with Enhanced Visual Distinction - -**Updated** The P2P plugin now provides enhanced logging with ANSI color codes for improved console readability and debugging efficiency. - -The P2P plugin logs block acceptance and transaction ingestion with ANSI color codes, and the network node/peer connection abstractions expose peer status and message propagation metadata. The enhanced logging system uses color codes to visually distinguish different types of network events: - -- **White color (CLOG_WHITE)**: Block processing messages including transaction counts and latency information -- **Cyan color (CLOG_CYAN)**: Peer statistics and connection status information -- **Gray color (CLOG_GRAY)**: Detailed debugging information and operational context -- **Orange color (CLOG_ORANGE)**: Connection-related warnings and termination notices -- **Red color (CLOG_RED)**: Critical connection termination events - -```mermaid -sequenceDiagram -participant Peer as "Remote Peer" -participant P2P as "p2p_plugin" -participant Chain as "Chain DB" -participant Log as "Color-Coded Logs" -Peer->>P2P : "block_message" -P2P->>Log : "WHITE : Block processing with transaction count" -P2P->>Chain : "accept_block(..., skip_flags)" -Chain-->>P2P : "result" -P2P-->>Peer : "acknowledge or error" -Peer->>P2P : "trx_message" -P2P->>Chain : "accept_transaction(trx)" -Chain-->>P2P : "accepted or rejected" -Note over Log : "CYAN : Peer statistics and connection status" -Note over Log : "GRAY : Detailed debugging context" -``` - -**Diagram sources** -- [p2p_plugin.cpp:118-170](file://plugins/p2p/p2p_plugin.cpp#L118-L170) -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:169-172](file://plugins/p2p/p2p_plugin.cpp#L169-L172) -- [p2p_plugin.cpp:605-652](file://plugins/p2p/p2p_plugin.cpp#L605-L652) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) -- [node.cpp:5091-5108](file://libraries/network/node.cpp#L5091-L5108) - -Operational insights with enhanced visual distinction: -- **White logs**: Immediately highlight block processing activity with transaction counts and latency measurements -- **Cyan logs**: Provide clear peer statistics including connection counts, latency, and bandwidth metrics -- **Gray logs**: Offer detailed debugging context for DLT mode operations and synchronization status -- **Orange/red logs**: Clearly indicate connection warnings, terminations, and critical network events -- Logs indicate block ingestion latency and transaction counts per block -- Sync vs normal mode logs differentiate between catching-up and live operation -- Peer connection states and metrics (round-trip delay, clock offset) aid in diagnosing connectivity issues - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:169-172](file://plugins/p2p/p2p_plugin.cpp#L169-L172) -- [p2p_plugin.cpp:298-365](file://plugins/p2p/p2p_plugin.cpp#L298-L365) -- [p2p_plugin.cpp:521-530](file://plugins/p2p/p2p_plugin.cpp#L521-L530) -- [p2p_plugin.cpp:605-686](file://plugins/p2p/p2p_plugin.cpp#L605-L686) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) -- [node.cpp:5091-5108](file://libraries/network/node.cpp#L5091-L5108) - -## Dependency Analysis -The debug node plugin depends on the chain plugin and JSON-RPC infrastructure. It interacts with the database to push blocks, modify validator keys, and manage hardfork state. The P2P plugin depends on the chain plugin for validation and delegates block/trx handling to it. The enhanced logging system relies on ANSI color code definitions and the underlying logging framework. - -```mermaid -graph LR -DNP["debug_node plugin"] --> Chain["chain plugin"] -DNP --> JSONRPC["json_rpc plugin"] -P2P["p2p_plugin"] --> Chain -P2P --> NetNode["network::node"] -NetNode --> PeerConn["peer_connection"] -P2P --> ColorCodes["ANSI Color Codes"] -ColorCodes --> Console["Console Output"] -``` - -**Diagram sources** -- [plugin.hpp:40-41](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L40-L41) -- [plugin.cpp:117-136](file://plugins/debug_node/plugin.cpp#L117-L136) -- [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) -- [node.hpp:190-200](file://libraries/network/include/graphene/network/node.hpp#L190-L200) -- [peer_connection.hpp:79-200](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L200) -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) - -**Section sources** -- [plugin.hpp:40-41](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L40-L41) -- [plugin.cpp:117-136](file://plugins/debug_node/plugin.cpp#L117-L136) -- [p2p_plugin.cpp:1-200](file://plugins/p2p/p2p_plugin.cpp#L1-L200) - -## Performance Considerations -- Shared memory sizing and growth thresholds impact replay performance and stability -- Single write thread and reduced plugin notifications can improve throughput during bulk operations -- Read/write lock contention affects RPC responsiveness under load -- **Updated** Enhanced logging with color codes provides better visual scanning efficiency without impacting performance significantly - -Recommendations: -- Increase shared memory size and thresholds for long replays -- Enable single write thread for deterministic block generation -- Tune read/write wait retries to avoid transient lock errors -- **Updated** Leverage color-coded logs for faster identification of network events and debugging scenarios - -**Section sources** -- [config_debug.ini:36-47](file://share/vizd/config/config_debug.ini#L36-L47) -- [config_debug.ini:49-67](file://share/vizd/config/config_debug.ini#L49-L67) - -## Troubleshooting Guide - -### Transaction Validation Failures -Symptoms: -- Transactions rejected with signature or authority errors -- Mismatch between expected and computed digests - -Workflow: -- Use sign_transaction to compute digest and sig_digest for the transaction -- Compare sig_digest with the transaction's sig_digest(CHAIN_ID) -- Verify WIF corresponds to the claimed signing key -- Reproduce by pushing blocks that include the transaction and observe logs - -```mermaid -flowchart TD -A["Transaction rejected"] --> B["Run sign_transaction on JSON input"] -B --> C{"sig_digest matches?"} -C --> |No| D["Fix chain ID or transaction fields"] -C --> |Yes| E["Verify WIF and key derivation"] -E --> F["Replay blocks with skip flags to isolate issue"] -``` - -**Diagram sources** -- [sign_transaction.cpp:28-53](file://programs/util/sign_transaction.cpp#L28-L53) -- [plugin.cpp:321-372](file://plugins/debug_node/plugin.cpp#L321-L372) - -**Section sources** -- [sign_transaction.cpp:12-26](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_transaction.cpp:28-53](file://programs/util/sign_transaction.cpp#L28-L53) -- [plugin.cpp:321-372](file://plugins/debug_node/plugin.cpp#L321-L372) - -### Consensus Issues -Symptoms: -- Blocks not accepted or chain stalls -- validator participation thresholds not met - -Workflow: -- Use debug_generate_blocks to advance the chain deterministically -- Temporarily modify validator signing keys to accept self-signed blocks -- Inspect validator schedule and hardfork state via debug APIs - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant DNP as "debug_node" -participant DB as "Database" -Dev->>DNP : "debug_generate_blocks(key,count,skip)" -DNP->>DB : "modify validator signing_key if needed" -DNP->>DB : "generate_block(slot,validator,priv_key,skip)" -DB-->>DNP : "new head block" -``` - -**Diagram sources** -- [plugin.cpp:222-288](file://plugins/debug_node/plugin.cpp#L222-L288) -- [plugin.cpp:489-511](file://plugins/debug_node/plugin.cpp#L489-L511) - -**Section sources** -- [plugin.cpp:222-288](file://plugins/debug_node/plugin.cpp#L222-L288) -- [plugin.cpp:489-511](file://plugins/debug_node/plugin.cpp#L489-L511) - -### Network Connectivity Problems with Enhanced Visual Analysis - -**Updated** Network connectivity problems can now be diagnosed more efficiently using the enhanced color-coded logging system. - -Symptoms: -- Peers disconnect frequently -- No blocks received or delayed propagation -- Sudden connection drops or reconnections - -Workflow with color-coded analysis: -- **Monitor CYAN logs**: Check peer statistics and connection status for immediate issues -- **Review WHITE logs**: Analyze block processing latency and transaction counts -- **Examine GRAY logs**: Investigate DLT mode operations and synchronization context -- **Watch ORANGE/RED logs**: Identify connection warnings and critical termination events -- Adjust seed nodes and connection limits in configuration - -Enhanced diagnostic approach: -- **Cyan peer statistics**: Look for sudden spikes in bytes_in or latency changes -- **White block processing**: Monitor transaction counts per block for network congestion -- **Gray debugging info**: Check DLT mode operations during snapshot sync failures -- **Orange/red warnings**: Identify connection health issues and peer blocking status - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:605-686](file://plugins/p2p/p2p_plugin.cpp#L605-L686) -- [p2p_plugin.cpp:169-172](file://plugins/p2p/p2p_plugin.cpp#L169-L172) -- [p2p_plugin.cpp:298-365](file://plugins/p2p/p2p_plugin.cpp#L298-L365) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) -- [node.cpp:5091-5108](file://libraries/network/node.cpp#L5091-L5108) - -### Log Analysis Techniques with Color-Coded System - -**Updated** Enhanced log analysis techniques leveraging ANSI color codes for improved debugging efficiency. - -- **White logs**: Quickly identify block processing activity and transaction volume -- **Cyan logs**: Monitor peer statistics and connection health in real-time -- **Gray logs**: Access detailed debugging context for complex operations -- **Orange/red logs**: Immediately spot critical connection issues and warnings -- Use the debug node plugin's logging toggle to reduce noise during scripted runs -- Inspect P2P logs for sync vs live modes and block ingestion latency -- Correlate error backtraces from block push operations with the specific block number and ID - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:605-686](file://plugins/p2p/p2p_plugin.cpp#L605-L686) -- [p2p_plugin.cpp:169-172](file://plugins/p2p/p2p_plugin.cpp#L169-L172) -- [plugin.cpp:244-248](file://plugins/debug_node/plugin.cpp#L244-L248) -- [plugin.cpp:363-366](file://plugins/debug_node/plugin.cpp#L363-L366) -- [p2p_plugin.cpp:124-133](file://plugins/p2p/p2p_plugin.cpp#L124-L133) - -### Integration with External Tools and IDEs -- Build and run the signing utilities from the programs/util directory to pipe transaction JSON into them -- Use the debug node plugin's JSON-RPC API from IDE REST clients or scripts -- Configure logging appenders and endpoints in the debug configuration template -- **Updated** Leverage color-coded console output for better integration with terminal-based debugging tools - -**Section sources** -- [sign_transaction.cpp:1-54](file://programs/util/sign_transaction.cpp#L1-L54) -- [sign_digest.cpp:1-49](file://programs/util/sign_digest.cpp#L1-L49) -- [config_debug.ini:107-126](file://share/vizd/config/config_debug.ini#L107-L126) - -### Debugging Workflows Across Development Phases -- Unit testing: Use sign_transaction and sign_digest to validate signing logic in isolation -- Integration testing: Replay blocks from JSON logs with skip flags to accelerate tests -- Staging: Enable debug node plugin with restricted RPC access and targeted edit scripts -- Production troubleshooting: Temporarily enable debug APIs on loopback, replay problematic blocks, and inspect validator schedule and hardfork state -- **Updated** Utilize enhanced color-coded logging for rapid identification of network issues in production environments - -**Section sources** -- [plugin.cpp:489-511](file://plugins/debug_node/plugin.cpp#L489-L511) -- [plugin.cpp:374-420](file://plugins/debug_node/plugin.cpp#L374-L420) -- [debug_node_plugin.md:50-134](file://documentation/debug_node_plugin.md#L50-L134) - -## Conclusion -The VIZ C++ Node provides robust debugging tooling centered around the debug node plugin, transaction signing utilities, and network introspection with enhanced ANSI color-coded logging. By combining deterministic block generation, replay capabilities, structured logging with visual distinction, and the enhanced P2P plugin logging system, teams can systematically diagnose transaction validation failures, consensus issues, and network connectivity problems more efficiently. The color-coded console output significantly improves debugging speed and accuracy, especially for complex network debugging scenarios. Proper configuration and disciplined workflows ensure efficient troubleshooting from development to production. - -**Updated** The enhanced P2P plugin logging with ANSI color codes provides substantial improvements in console readability and debugging efficiency, allowing developers and operators to quickly identify and resolve network issues through visual distinction of different event types. - -## Appendices - -### API Reference Summary -- debug_push_blocks: Load blocks from a block log -- debug_push_json_blocks: Load blocks from a JSON array -- debug_generate_blocks: Produce blocks with a specified key -- debug_generate_blocks_until: Advance time-based to a target head block time -- debug_pop_block: Remove the head block -- debug_get_witness_schedule: Retrieve validator schedule object -- debug_set_hardfork / debug_has_hardfork: Control and query hardfork state - -**Section sources** -- [plugin.hpp:62-90](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L62-L90) -- [plugin.cpp:489-555](file://plugins/debug_node/plugin.cpp#L489-L555) - -### Enhanced P2P Logging Color Codes Reference - -**Updated** Color-coded logging system for improved network debugging: - -- **CLOG_WHITE** ("\033[97m"): Block processing messages including transaction counts and latency -- **CLOG_CYAN** ("\033[96m"): Peer statistics and connection status information -- **CLOG_GRAY** ("\033[90m"): Detailed debugging information and operational context -- **CLOG_RESET** ("\033[0m"): Reset color formatting to default - -Common usage patterns: -- White logs for immediate block processing visibility -- Cyan logs for peer monitoring and connection health -- Gray logs for detailed operational context during complex operations -- Automatic reset ensures proper console formatting - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:169-172](file://plugins/p2p/p2p_plugin.cpp#L169-L172) -- [p2p_plugin.cpp:605-686](file://plugins/p2p/p2p_plugin.cpp#L605-L686) -- [p2p_plugin.cpp:298-365](file://plugins/p2p/p2p_plugin.cpp#L298-L365) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) -- [node.cpp:5091-5108](file://libraries/network/node.cpp#L5091-L5108) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Network Debugging Capabilities.md b/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Network Debugging Capabilities.md deleted file mode 100644 index b823e7e20a..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Network Debugging Capabilities.md +++ /dev/null @@ -1,490 +0,0 @@ -# Network Debugging Capabilities - - -**Referenced Files in This Document** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [peer_database.cpp](file://libraries/network/peer_database.cpp) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [config_debug.ini](file://share/vizd/config/config_debug.ini) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document explains the network debugging capabilities in VIZ CPP Node with a focus on: -- Peer connection monitoring and debugging (establishment, handshake, and protocol issues) -- Message propagation debugging for blocks and transactions -- Network performance monitoring and latency analysis -- Peer database inspection for topology and connection quality diagnostics -- Practical scenarios: peer discovery failures, block propagation delays, and network partitions -- Logging configuration for network debugging, connection state monitoring, and traffic analysis -- Troubleshooting connectivity and optimizing performance - -## Project Structure -The network stack is implemented in the network library and integrated via the P2P plugin. Debugging and logging are configured via the debug configuration file and the debug_node plugin. - -```mermaid -graph TB -subgraph "Network Library" -N["node.hpp
node.cpp"] -PC["peer_connection.hpp
peer_connection.cpp"] -PD["peer_database.hpp
peer_database.cpp"] -MOC["message_oriented_connection.hpp"] -end -subgraph "Plugins" -P2P["p2p_plugin.hpp
p2p_plugin.cpp"] -DNP["debug_node plugin.hpp
debug_node plugin.cpp"] -end -subgraph "Config" -CFG["config_debug.ini"] -end -P2P --> N -N --> PC -N --> PD -PC --> MOC -DNP -. "debugging utilities" .- N -CFG -. "logging config" .- N -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [node.cpp](file://libraries/network/node.cpp#L106-L176) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L68-L162) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L186) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L41-L103) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L38-L108) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L104-L156) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -## Core Components -- Node: Manages P2P connections, broadcasting, syncing, and propagation metrics. Provides APIs to inspect peers, bandwidth limits, and usage statistics. -- PeerConnection: Encapsulates per-peer state, negotiation status, inventory tracking, and timing metrics. -- PeerDatabase: Persistent storage of potential peers, connection attempts, and outcomes. -- MessageOrientedConnection: Low-level transport abstraction for message streams. -- P2P Plugin: Integrates the node with the chain plugin, handles blocks/transactions, and exposes broadcast APIs. -- Debug Node Plugin: Adds debugging hooks and APIs for “what-if” experiments and logging controls. -- Logging Config: Routes logs to console and file appenders, including a dedicated p2p logger. - -Key debugging APIs and structures: -- Propagation data tracking for blocks and transactions -- Peer status and connection counts -- Bandwidth limiting and usage stats -- Peer database inspection and clearing -- Firewall and negotiation state visibility - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L276-L278) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L292-L294) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L296-L296) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L288-L288) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L175-L198) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L200-L225) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L227-L268) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L40-L46) -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L101-L101) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -## Architecture Overview -The P2P subsystem is layered: -- Application layer (P2P plugin) delegates to Node for networking. -- Node manages PeerConnections and PeerDatabase. -- PeerConnection composes MessageOrientedConnection for transport. -- Debug Node plugin augments runtime behavior for diagnostics. - -```mermaid -classDiagram -class Node { -+broadcast(message) -+sync_from(item_id, forks) -+get_connected_peers() -+get_connection_count() -+get_transaction_propagation_data(id) -+get_block_propagation_data(id) -+clear_peer_database() -+network_get_info() -+network_get_usage_stats() -+get_potential_peers() -} -class PeerConnection { -+accept_connection() -+connect_to(endpoint) -+send_message(msg) -+close_connection() -+get_total_bytes_sent() -+get_total_bytes_received() -+get_last_message_sent_time() -+get_last_message_received_time() -+busy()/idle() -} -class PeerDatabase { -+open(path) -+update_entry(record) -+lookup_or_create_entry_for_endpoint(ep) -+begin()/end() -+size() -} -class MessageOrientedConnection { -+accept() -+bind(endpoint) -+connect_to(remote) -+send_message(msg) -+get_total_bytes_sent() -+get_total_bytes_received() -} -class P2PPlugin { -+broadcast_block(signed_block) -+broadcast_transaction(signed_transaction) -} -Node --> PeerConnection : "manages" -Node --> PeerDatabase : "uses" -PeerConnection --> MessageOrientedConnection : "uses" -P2PPlugin --> Node : "delegates" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) - -## Detailed Component Analysis - -### Node: Peer Monitoring and Propagation Metrics -- Propagation tracking: message_propagation_data captures received and validated timestamps and originating peer for blocks and transactions. -- Peer inspection: get_connected_peers returns peer_status with version, endpoint, and variant info. -- Stats and limits: network_get_info and network_get_usage_stats expose bandwidth and call statistics; set_total_bandwidth_limit caps throughput. -- Peer DB operations: clear_peer_database resets persistent peer records to aid in diagnosing discovery/connectivity issues. -- Sync and broadcast: sync_from initiates sync; broadcast dispatches messages to peers. - -```mermaid -sequenceDiagram -participant App as "Application" -participant P2P as "P2P Plugin" -participant Node as "Node" -participant Peer as "PeerConnection" -App->>P2P : broadcast_block / broadcast_transaction -P2P->>Node : broadcast(message) -Node->>Peer : send_message(message) per connected peer -Peer-->>Node : bytes counters updated -Node-->>App : stats via network_get_usage_stats() -``` - -**Diagram sources** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L40-L46) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L258-L258) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L305-L305) - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L249-L253) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L276-L278) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L292-L294) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L296-L296) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L288-L288) - -### PeerConnection: Negotiation States and Timing -- Negotiation lifecycle: connection_negotiation_status enumerates states from connecting to accepted and hello exchange. -- Per-peer metrics: bytes sent/received, last message times, busy/idle detection, and inhibition flags for fetching. -- Inventory tracking: maintains sets of advertised items, requested items, and sync queues. -- Transport: wraps MessageOrientedConnection for accept/bind/connect and send operations. - -```mermaid -stateDiagram-v2 -[*] --> disconnected -disconnected --> connecting : "initiate outbound" -disconnected --> accepting : "accept inbound" -connecting --> hello_sent : "exchange hello" -accepting --> accepted : "exchange hello" -hello_sent --> negotiation_complete : "ready" -accepted --> negotiation_complete : "ready" -negotiation_complete --> closing : "graceful close" -closing --> closed : "destroy" -``` - -**Diagram sources** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L94-L106) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L169-L200) - -**Section sources** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L175-L198) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L227-L268) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L169-L200) - -### PeerDatabase: Diagnosing Topology and Quality -- Records: endpoint, last seen, disposition of last connection (success/failure/rejected/handshake failed), attempt counts, and last error. -- Iteration: begin/end iterators traverse entries sorted by last_seen_time. -- Persistence: open loads from JSON; close saves to JSON; clear removes all entries. - -```mermaid -flowchart TD -Start(["Open PeerDB"]) --> Load["Load JSON file if exists"] -Load --> Prune{"Size > max?"} -Prune --> |Yes| Trim["Trim to maximum size"] -Prune --> |No| Ready["Ready"] -Ready --> Update["update_entry()"] -Update --> Lookup["lookup_or_create_entry_for_endpoint()"] -Lookup --> Iterate["begin()/end() iteration"] -Iterate --> Save["close(): save to JSON"] -Save --> End(["Close"]) -``` - -**Diagram sources** -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L151-L174) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L176-L182) - -**Section sources** -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L151-L174) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L176-L182) - -### MessageOrientedConnection: Transport Abstraction -- Accepts inbound connections, binds local endpoints, connects to remotes, sends messages, and tracks bytes and last message times. -- Used by PeerConnection to encapsulate transport concerns. - -**Section sources** -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) - -### P2P Plugin: Integration and Broadcast -- Implements node_delegate to integrate with the chain plugin. -- Exposes broadcast_block and broadcast_transaction for application-level propagation. -- Handles block and transaction ingestion and logs sync latencies. - -**Section sources** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L40-L46) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L106-L170) - -### Debug Node Plugin: Logging Controls and Debug Utilities -- Provides APIs to generate or push blocks and to control logging behavior. -- Useful for isolating network behavior under controlled conditions. - -**Section sources** -- [plugin.hpp](file://plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#L101-L101) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L104-L156) - -## Dependency Analysis -- P2P plugin depends on Node for networking and on Chain plugin for blockchain operations. -- Node depends on PeerConnection and PeerDatabase for peer lifecycle and topology persistence. -- PeerConnection depends on MessageOrientedConnection for transport. -- Logging configuration routes network events to the p2p logger. - -```mermaid -graph LR -P2P["p2p_plugin.cpp"] --> NodeHdr["node.hpp"] -NodeCpp["node.cpp"] --> PeerConnHdr["peer_connection.hpp"] -NodeCpp --> PeerDBHdr["peer_database.hpp"] -PeerConnHdr --> MOC["message_oriented_connection.hpp"] -CFG["config_debug.ini"] --> NodeHdr -DNP["debug_node plugin.cpp"] -. "logging control" .- NodeHdr -``` - -**Diagram sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L41-L103) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [node.cpp](file://libraries/network/node.cpp#L106-L176) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L351) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) -- [plugin.cpp](file://plugins/debug_node/plugin.cpp#L104-L156) - -**Section sources** -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L41-L103) -- [node.cpp](file://libraries/network/node.cpp#L106-L176) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L68-L162) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L100-L138) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -## Performance Considerations -- Bandwidth limiting: set_total_bandwidth_limit can throttle upload/download to stabilize resource-constrained environments. -- Usage stats: network_get_usage_stats provides byte counters and call statistics to identify hotspots. -- Queueing and throttling: PeerConnection busy()/idle() and transaction_fetching_inhibited_until help prevent overload during floods. -- Latency measurement: P2P plugin logs sync latency for blocks, aiding diagnosis of propagation bottlenecks. - -Practical tips: -- Monitor bytes sent/received per peer to detect misbehaving nodes. -- Temporarily lower bandwidth limits to stabilize a congested network. -- Use clear_peer_database to remove stale peers and improve discovery. - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L290-L290) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L294-L294) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L327-L329) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp#L144-L148) - -## Troubleshooting Guide - -### Peer Discovery Failures -Symptoms: -- Low connection count despite configured seeds. -- Repeated failed connection attempts. - -Actions: -- Inspect potential peers: use get_potential_peers to enumerate endpoints and last_connection_disposition. -- Clear peer database: call clear_peer_database to reset persistent records and retry discovery. -- Review logs: ensure p2p logger is enabled and review handshake/connection rejection reasons. - -Evidence in code: -- Potential peer disposition includes handshaking failure and rejected outcomes. -- Peer DB persists last error and attempt counts. - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L296-L296) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L288-L288) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L39-L45) -- [peer_database.cpp](file://libraries/network/peer_database.cpp#L151-L174) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -### Handshake and Protocol Issues -Symptoms: -- Peers connect then close quickly. -- Negotiation remains stuck at hello_sent or accepted. - -Actions: -- Check negotiation status: monitor connection_negotiation_status transitions. -- Verify chain_id compatibility and user agent/version fields exchanged during hello. -- Inspect firewall and NAT traversal: is_firewalled and endpoint fields capture relevant state. - -Evidence in code: -- Negotiation states and connection times are tracked in PeerConnection. -- Hello fields include node identifiers and capabilities. - -**Section sources** -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L94-L106) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L175-L198) -- [peer_connection.cpp](file://libraries/network/peer_connection.cpp#L169-L200) - -### Block Propagation Delays -Symptoms: -- Blocks arrive late or out of order. -- Sync stalls with peers. - -Actions: -- Measure propagation: use get_block_propagation_data to retrieve received/validated timestamps and originating peer. -- Inspect peer inventory: review advertised and requested sets to detect missing items. -- Reduce bandwidth pressure: temporarily lower limits to improve responsiveness. - -Evidence in code: -- message_propagation_data stores propagation timestamps and origin. -- Peer inventory tracking and sync queues are maintained in PeerConnection. - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L54) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L278-L278) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp#L227-L268) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L290-L290) - -### Network Partition Detection -Symptoms: -- Partial connectivity with isolated subset of peers. -- No progress on sync despite multiple peers. - -Actions: -- Compare get_connected_peers and get_potential_peers to identify partitions. -- Clear peer database to force re-discovery and rebuild topology. -- Increase verbosity of p2p logger to capture partition events. - -Evidence in code: -- Peer status includes endpoint and variant info for diagnostics. -- Peer DB records last seen and disposition to infer partition health. - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L249-L253) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L47-L71) -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -### Logging Configuration for Network Debugging -- Configure loggers: default and p2p loggers route to console and file appenders. -- File appender writes to logs/p2p/p2p.log. -- Adjust levels to capture detailed P2P events. - -Evidence in code: -- Logger and appender configuration in debug config. - -**Section sources** -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) - -### Practical Scenarios and Examples -- Peer discovery failures: Clear peer database and observe reconnection behavior; inspect potential peers for repeated handshaking failures. -- Block propagation delays: Retrieve propagation data for recent blocks and compare timestamps across peers to locate slow links. -- Network partitions: Use get_connected_peers and get_potential_peers to map connectivity; clear peer database to recover. - -Evidence in code: -- APIs for propagation data, peer inspection, and peer DB enumeration. - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L276-L278) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L249-L253) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L296-L296) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L288-L288) - -## Conclusion -The VIZ CPP Node provides robust primitives for network debugging: -- Node exposes propagation metrics, peer inspection, and usage stats. -- PeerConnection tracks negotiation and per-peer timing. -- PeerDatabase persists topology and outcomes for diagnosis. -- P2P plugin integrates with the chain and broadcasts messages. -- Logging and debug_node plugin support controlled experiments and logging control. - -These capabilities enable systematic diagnosis of connection issues, propagation bottlenecks, and topology problems, along with actionable performance tuning. - -## Appendices - -### Appendix A: Key APIs and Where They Are Defined -- Propagation data retrieval: get_block_propagation_data, get_transaction_propagation_data -- Peer inspection: get_connected_peers, get_potential_peers -- Peer DB operations: clear_peer_database, update_entry, lookup_or_create_entry_for_endpoint -- Bandwidth and stats: set_total_bandwidth_limit, network_get_info, network_get_usage_stats -- Transport: MessageOrientedConnection methods for accept/bind/connect/send -- P2P broadcast: broadcast_block, broadcast_transaction - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L249-L253) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L276-L278) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L288-L288) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L292-L294) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L296-L296) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp#L104-L134) -- [message_oriented_connection.hpp](file://libraries/network/include/graphene/network/message_oriented_connection.hpp#L45-L79) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L40-L46) - -### Appendix B: Logging Configuration Reference -- Console and file appenders for default and p2p loggers -- Log file location: logs/p2p/p2p.log - -**Section sources** -- [config_debug.ini](file://share/vizd/config/config_debug.ini#L107-L126) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Performance Profiling Utilities.md b/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Performance Profiling Utilities.md deleted file mode 100644 index 96553f475b..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Performance Profiling Utilities.md +++ /dev/null @@ -1,495 +0,0 @@ -# Performance Profiling Utilities - - -**Referenced Files in This Document** -- [inflation_plot.py](file://programs/util/inflation_plot.py) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp) -- [main.cpp](file://programs/size_checker/main.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [testing.md](file://documentation/testing.md) -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes performance profiling and analysis utilities available in the VIZ CPP Node. It focuses on: -- The inflation_plot.py script for analyzing blockchain economic metrics and inflation patterns -- The size_checker utility for examining memory usage and object sizing within the blockchain database -- Test utilities test_block_log and test_shared_mem for performance benchmarking and memory testing -- Practical performance analysis workflows for identifying memory bottlenecks, measuring transaction processing throughput, and analyzing database performance -- Profiling techniques for blockchain processing, network operations, and database performance -- Guidance on interpreting performance metrics and identifying optimization opportunities -- Integration with external profiling tools and system monitoring approaches - -## Project Structure -The performance-related utilities are located under programs/util and programs/size_checker. They complement the core blockchain libraries under libraries/chain and libraries/network, and are integrated into the node via plugins. - -```mermaid -graph TB -subgraph "Utilities" -U1["programs/util/inflation_plot.py"] -U2["programs/util/test_block_log.cpp"] -U3["programs/util/test_shared_mem.cpp"] -U4["programs/size_checker/main.cpp"] -end -subgraph "Core Libraries" -L1["libraries/chain/include/graphene/chain/database.hpp"] -L2["libraries/chain/include/graphene/chain/block_log.hpp"] -L3["libraries/network/include/graphene/network/node.hpp"] -end -subgraph "Plugins" -P1["plugins/chain/plugin.cpp"] -end -U1 --> L1 -U2 --> L2 -U3 --> L1 -U4 --> L1 -P1 --> L1 -P1 --> L2 -``` - -**Diagram sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L200) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L23-L322) - -**Section sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L200) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L23-L322) - -## Core Components -- inflation_plot.py: Reads per-block JSON metrics and plots monetary supply projections with inflection points for economic parameters. -- size_checker: Computes memory and wire sizes for protocol types and blocks, aiding memory footprint analysis. -- test_block_log: Exercises block_log append/read operations for I/O and serialization performance checks. -- test_shared_mem: Validates shared memory container behavior and object sizing for chainbase/shared memory usage. -- Chain database and block_log APIs: Provide the foundational interfaces for performance-sensitive operations. -- Network node interface: Exposes hooks for message propagation timing and peer statistics relevant to network performance. - -**Section sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L200) - -## Architecture Overview -The performance utilities operate at different layers: -- Economic metrics plotting relies on external JSON input and visualization -- Memory sizing operates on protocol types and block structures -- Block log tests exercise the block storage layer -- Shared memory tests validate chainbase/shared memory behavior -- Plugins integrate these capabilities into the node lifecycle - -```mermaid -graph TB -A["inflation_plot.py
Economic metrics plotting"] --> B["External JSON metrics"] -C["size_checker
Memory sizing"] --> D["Protocol types and blocks"] -E["test_block_log
Block I/O tests"] --> F["block_log API"] -G["test_shared_mem
Shared memory tests"] --> H["Chainbase/shared memory"] -I["plugins/chain/plugin.cpp
Node integration"] --> J["database.hpp"] -I --> K["block_log.hpp"] -J --> L["Core blockchain processing"] -K --> M["Block storage and retrieval"] -``` - -**Diagram sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L23-L322) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) - -## Detailed Component Analysis - -### inflation_plot.py -Purpose: -- Parse per-block JSON records containing block number, supply, and revenue vector -- Plot cumulative supply growth and mark inflection points for economic parameters - -Key behaviors: -- Reads a JSON stream line-by-line -- Filters blocks at regular intervals (every 10,000 blocks) -- Converts block numbers to years using a constant blocks-per-year value -- Plots supply on a logarithmic scale with custom tick labels -- Identifies inflection points by detecting changes in revenue vector components - -```mermaid -flowchart TD -Start(["Start"]) --> ReadFile["Open JSON input file"] -ReadFile --> Loop["Iterate lines"] -Loop --> Parse["Parse JSON line"] -Parse --> Filter{"Block divisible by 10000?"} -Filter --> |No| Loop -Filter --> |Yes| Compute["Compute x=block/BLOCKS_PER_YEAR, y=supply/1000"] -Compute --> Store["Append to x,y series"] -Store --> Inflection{"First non-zero revenue component change?"} -Inflection --> |No| Loop -Inflection --> |Yes| Mark["Mark inflection point with color and shape"] -Mark --> Loop -Loop --> DonePlot["Plot curve and markers"] -DonePlot --> Save["Save figure to 'myfig.png'"] -Save --> End(["End"]) -``` - -**Diagram sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) - -Interpretation tips: -- Peaks in the supply curve indicate policy changes or hardforks -- Inflection markers highlight shifts in revenue distribution among curators, content creators, producers, liquidity, and proof-of-work -- Logarithmic scale helps visualize long-term trends - -Practical usage: -- Generate per-block metrics JSON from node logs or debug outputs -- Run the script to produce a supply projection chart - -**Section sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) - -### size_checker -Purpose: -- Measure memory footprint and serialized size of protocol types and blocks -- Aid in optimizing data structures and reducing serialization overhead - -Key behaviors: -- Iterates through operation types and computes in-memory and packed sizes -- Sorts types by memory size to highlight heavy-weight structures -- Prints JSON array of type metadata for further analysis -- Reports block header and signed block sizes - -```mermaid -flowchart TD -Start(["Start"]) --> Init["Initialize operation type iterator"] -Init --> Visit["Visit each operation type"] -Visit --> Measure["Measure sizeof(Type) and pack_size(Type)"] -Measure --> Record["Record name, mem_size, wire_size"] -Record --> Next{"More types?"} -Next --> |Yes| Visit -Next --> |No| Sort["Sort by mem_size descending"] -Sort --> Print["Print JSON array"] -Print --> Sizes["Report block_header and signed_block sizes"] -Sizes --> End(["End"]) -``` - -**Diagram sources** -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) - -Interpretation tips: -- Types with large memory or wire sizes are candidates for optimization -- Compare mem_size vs wire_size to identify over-allocation or inefficient packing -- Use reported block sizes to estimate transaction and block overhead - -Practical usage: -- Build and run the utility to generate a size report -- Review sorted types to prioritize refactoring efforts - -**Section sources** -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) - -### test_block_log -Purpose: -- Exercise block_log append and read operations to evaluate I/O and serialization performance -- Validate block storage behavior under controlled conditions - -Key behaviors: -- Opens a temporary block log -- Appends two test blocks, flushes, and verifies head updates -- Reads back stored blocks and compares packed sizes -- Demonstrates typical block_log usage patterns - -```mermaid -sequenceDiagram -participant T as "test_block_log.cpp" -participant BL as "block_log" -participant FS as "Filesystem" -T->>BL : open(temp_path) -T->>BL : append(b1) -BL->>FS : write block + index -T->>BL : flush() -T->>BL : append(b2) -BL->>FS : write block + index -T->>BL : flush() -T->>BL : read_block(0) -BL->>FS : seek + read -T->>BL : read_block(offset) -BL->>FS : seek + read -T->>BL : read_head() -BL->>FS : read head pointer -``` - -**Diagram sources** -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) - -Interpretation tips: -- Monitor flush frequency and block sizes to tune I/O performance -- Use read timings to estimate storage latency and throughput -- Validate that offsets and indices are correctly maintained - -Practical usage: -- Run the test to verify block_log operations -- Extend with timing measurements for performance profiling - -**Section sources** -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) - -### test_shared_mem -Purpose: -- Validate shared memory container behavior and object sizing for chainbase/shared memory usage -- Aid in diagnosing memory allocation and fragmentation issues - -Key behaviors: -- Creates or opens a managed mapped file segment -- Constructs a multi-index container of shared_string-backed book objects -- Emplaces entries and manipulates a deque within shared memory -- Uses named mutex for synchronization - -```mermaid -flowchart TD -Start(["Start"]) --> Open["Open or create managed segment './book_container.db'"] -Open --> Construct["Construct book_container and book deque"] -Construct --> Iterate["Iterate container contents"] -Iterate --> Emplace["Emplace new book entry"] -Emplace --> DequeOp["Operate on shared deque"] -DequeOp --> Sync["Named mutex usage"] -Sync --> End(["End"]) -``` - -**Diagram sources** -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) - -Interpretation tips: -- Verify that shared memory limits are respected and allocations succeed -- Monitor container growth and memory usage patterns -- Ensure proper synchronization with named mutexes - -Practical usage: -- Run the test to validate shared memory setup -- Extend with memory profiling and allocation tracing - -**Section sources** -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) - -### Blockchain Processing and Database Performance Hooks -The chain database exposes several performance-relevant controls and flags: -- Validation step flags for selective validation to reduce overhead during reindex or specialized operations -- Shared memory management functions to monitor and adjust free memory thresholds -- Methods to open/reindex databases with configurable shared memory sizes - -```mermaid -classDiagram -class database { -+open(data_dir, shared_mem_dir, initial_supply, shared_file_size, chainbase_flags) -+reindex(data_dir, shared_mem_dir, from_block_num, shared_file_size) -+set_min_free_shared_memory_size(size_t) -+set_inc_shared_memory_size(size_t) -+set_block_num_check_free_size(uint32_t) -+check_free_memory(skip_print, current_block_num) -+wipe(data_dir, shared_mem_dir, include_blocks) -+close(rewind) -+push_block(b, skip) -+push_transaction(trx, skip) -+validate_block(b, skip) -} -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [database.cpp](file://libraries/chain/database.cpp#L351-L413) - -Interpretation tips: -- Use validation step flags to disable expensive checks during benchmarking -- Tune shared memory parameters to avoid frequent resizing and improve cache locality -- Monitor free memory checks to detect potential bottlenecks - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L56-L108) -- [database.cpp](file://libraries/chain/database.cpp#L351-L413) - -### Network Operations Performance Hooks -The network node interface supports message propagation timing and peer statistics: -- Message propagation data structure captures received and validated timestamps -- Peer status provides endpoint and variant information for diagnostics -- Node delegate callbacks for block and transaction handling expose timing-sensitive entry points - -```mermaid -classDiagram -class node { -+set_node_delegate(del) -+load_configuration(path) -+close() -} -class node_delegate { -+has_item(id) bool -+handle_block(blk_msg, sync_mode, contained_transaction_message_ids) bool -+handle_transaction(trx_msg) void -+handle_message(message) void -+get_block_ids(synopsis, remaining_item_count, limit) std : : vector -+get_item(id) message -+get_blockchain_synopsis(reference_point, number_of_blocks_after_reference_point) std : : vector -+sync_status(item_type, item_count) void -+connection_count_changed(c) void -+get_block_number(block_id) uint32_t -+get_block_time(block_id) fc : : time_point_sec -+get_blockchain_now() fc : : time_point_sec -+get_head_block_id() item_hash_t -+estimate_last_known_fork_from_git_revision_timestamp(unix_timestamp) uint32_t -+error_encountered(message, error) void -} -node --> node_delegate : "uses" -``` - -**Diagram sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L1-L200) - -Interpretation tips: -- Track message propagation delays to identify network bottlenecks -- Monitor peer counts and sync status to assess network health -- Use delegate callbacks to instrument timing around block and transaction processing - -**Section sources** -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L166) - -## Dependency Analysis -The performance utilities depend on core library APIs and are integrated via plugins: -- inflation_plot.py depends on external JSON metrics and matplotlib -- size_checker depends on protocol type definitions and fc serialization -- test_block_log depends on block_log API -- test_shared_mem depends on chainbase and boost interprocess -- Plugins initialize and configure database and block log behavior - -```mermaid -graph LR -IP["inflation_plot.py"] --> METRICS["Per-block metrics JSON"] -SC["size_checker"] --> PROT["Protocol types"] -TBL["test_block_log"] --> BLAPI["block_log.hpp"] -TSM["test_shared_mem"] --> CB["chainbase/shared memory"] -PLG["plugins/chain/plugin.cpp"] --> DBH["database.hpp"] -PLG --> BLH["block_log.hpp"] -``` - -**Diagram sources** -- [inflation_plot.py](file://programs/util/inflation_plot.py#L1-L74) -- [main.cpp](file://programs/size_checker/main.cpp#L1-L85) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [plugin.cpp](file://plugins/chain/plugin.cpp#L23-L322) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) - -**Section sources** -- [plugin.cpp](file://plugins/chain/plugin.cpp#L23-L322) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) -- [block_log.hpp](file://libraries/chain/include/graphene/chain/block_log.hpp#L1-L75) - -## Performance Considerations -- Memory footprint - - Use size_checker to identify large protocol types and blocks - - Optimize data structures and reduce unnecessary fields - - Monitor shared memory growth and tune increment sizes -- Storage I/O - - Profile block_log append/read operations with test_block_log - - Adjust flush policies and block sizes to balance durability and throughput -- Network latency - - Instrument message propagation timing via node delegate callbacks - - Monitor peer counts and sync status to detect network congestion -- Validation overhead - - Apply validation step flags selectively during benchmarks - - Disable non-essential checks for synthetic workloads - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Memory pressure during reindex - - Increase shared memory size and adjust minimum free memory thresholds - - Use validation step flags to reduce overhead -- Slow block log operations - - Verify flush policies and filesystem performance - - Benchmark with test_block_log to isolate bottlenecks -- Shared memory allocation failures - - Validate segment creation and capacity - - Use test_shared_mem to confirm container behavior -- Network performance anomalies - - Inspect message propagation delays and peer status - - Use node delegate hooks to capture timing data - -**Section sources** -- [database.cpp](file://libraries/chain/database.cpp#L351-L413) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [test_shared_mem.cpp](file://programs/util/test_shared_mem.cpp#L1-L169) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L166) - -## Conclusion -The VIZ CPP Node provides focused utilities for performance profiling across economic metrics, memory sizing, block storage, and shared memory behavior. Combined with plugin-driven configuration and core library APIs, these tools enable targeted analysis and optimization of blockchain processing, network operations, and database performance. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Workflows - -- Identifying memory bottlenecks - - Run size_checker to obtain type size reports - - Focus on top-heavy types and reduce field sizes or packing overhead - - Monitor shared memory usage and adjust thresholds via database configuration - -- Measuring transaction processing throughput - - Use debug_node plugin to generate synthetic blocks and transactions - - Instrument node delegate callbacks to capture timing around block and transaction handling - - Compare metrics across different validation step configurations - -- Analyzing database performance - - Use test_block_log to profile append/read latencies - - Evaluate block sizes and flush frequencies - - Monitor free memory checks and shared memory growth during extended runs - -**Section sources** -- [debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp#L48-L166) -- [test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [database.cpp](file://libraries/chain/database.cpp#L351-L413) - -### Integration with External Tools and Monitoring -- Code coverage and profiling - - Use lcov-based workflow for coverage capture and reporting - - Combine with unit test targets for comprehensive coverage analysis - -- System monitoring - - Track CPU, memory, and I/O metrics during utility runs - - Correlate metrics with block log and shared memory operations - -**Section sources** -- [testing.md](file://documentation/testing.md#L26-L43) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Transaction Debugging Tools.md b/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Transaction Debugging Tools.md deleted file mode 100644 index d6c5438bfc..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Debugging Tools/Transaction Debugging Tools.md +++ /dev/null @@ -1,366 +0,0 @@ -# Transaction Debugging Tools - - -**Referenced Files in This Document** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp) -- [main.cpp](file://programs/js_operation_serializer/main.cpp) -- [transaction.cpp](file://libraries/protocol/transaction.cpp) -- [sign_state.hpp](file://libraries/protocol/sign_state.hpp) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [get_config.cpp](file://libraries/protocol/get_config.cpp) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive documentation for transaction debugging utilities in the VIZ C++ Node. It focuses on three primary tools: -- sign_transaction: a command-line utility to debug transaction signing issues by computing digests and generating signatures from WIF keys. -- sign_digest: a command-line utility to debug cryptographic operations and signature verification processes by signing arbitrary SHA256 digests. -- JavaScript operation serializer: a utility to convert between JSON and binary operation formats for inspection and debugging. - -It also covers transaction validation, authority verification, and common error scenarios encountered during transaction construction, signing, and network transmission. - -## Project Structure -The transaction debugging tools reside under the programs/util directory and the programs/js_operation_serializer directory. Supporting protocol and chain logic is located under libraries/protocol and libraries/chain. - -```mermaid -graph TB -subgraph "Utilities" -ST["programs/util/sign_transaction.cpp"] -SD["programs/util/sign_digest.cpp"] -JS["programs/js_operation_serializer/main.cpp"] -end -subgraph "Protocol Layer" -TXCPP["libraries/protocol/transaction.cpp"] -SIGSTATE["libraries/protocol/sign_state.hpp"] -EXC["libraries/protocol/exceptions.hpp"] -CFG["libraries/protocol/config.hpp"] -GCFG["libraries/protocol/get_config.cpp"] -end -subgraph "Chain Layer" -TXOBJ["libraries/chain/transaction_object.hpp"] -end -ST --> TXCPP -SD --> TXCPP -JS --> TXCPP -TXCPP --> SIGSTATE -TXCPP --> EXC -TXCPP --> CFG -GCFG --> CFG -TXOBJ --> TXCPP -``` - -**Diagram sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L1-L54) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L1-L49) -- [main.cpp](file://programs/js_operation_serializer/main.cpp#L1-L531) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [sign_state.hpp](file://libraries/protocol/sign_state.hpp#L1-L45) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L1-L116) -- [config.hpp](file://libraries/protocol/config.hpp#L1-L169) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L1-L78) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp#L1-L56) - -**Section sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L1-L54) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L1-L49) -- [main.cpp](file://programs/js_operation_serializer/main.cpp#L1-L531) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L361) -- [sign_state.hpp](file://libraries/protocol/sign_state.hpp#L1-L45) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L1-L116) -- [config.hpp](file://libraries/protocol/config.hpp#L1-L169) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L1-L78) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp#L1-L56) - -## Core Components -- sign_transaction: Reads transaction and WIF key from stdin, computes transaction digest and signature digest bound to the chain ID, signs with the private key, and prints a JSON result containing the original transaction, computed digests, public key, and signature. -- sign_digest: Reads a SHA256 digest and WIF key from stdin, signs the digest with the private key, and prints a JSON result containing the digest, public key, and signature. -- JavaScript operation serializer: Generates JavaScript serializers for operations and chain properties, enabling inspection of binary-to-JSON conversion behavior. - -Key input/output formats: -- Both utilities consume one JSON object per line via stdin and emit one JSON object per line to stdout. -- sign_transaction expects an object with a transaction field and a WIF key string; it emits an object with transaction, digest, sig_digest, key, and sig. -- sign_digest expects an object with a hex SHA256 digest string and a WIF key string; it emits an object with the digest, key, and sig. - -Common error scenarios: -- Malformed JSON input lines. -- Invalid WIF key or mismatched chain ID. -- Transaction validation failures (e.g., missing operations, invalid authority combinations). -- Duplicate or irrelevant signatures during authority verification. - -**Section sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L12-L24) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L54-L115) - -## Architecture Overview -The signing utilities integrate with the protocol layer to compute digests and signatures, and leverage the chain layer for transaction storage and duplicate detection. - -```mermaid -sequenceDiagram -participant User as "User" -participant ST as "sign_transaction" -participant TX as "transaction.cpp" -participant KEYS as "key_conversion.hpp" -participant OUT as "stdout" -User->>ST : "stdin line with {tx, wif}" -ST->>TX : "tx.digest()" -ST->>TX : "tx.sig_digest(CHAIN_ID)" -ST->>KEYS : "wif_to_key(wif)" -KEYS-->>ST : "private_key" -ST->>ST : "sign_compact(sig_digest)" -ST-->>OUT : "JSON {tx, digest, sig_digest, key, sig}" -``` - -**Diagram sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L28-L51) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L17-L28) -- [config.hpp](file://libraries/protocol/config.hpp#L9-L9) - -```mermaid -sequenceDiagram -participant User as "User" -participant SD as "sign_digest" -participant KEYS as "key_conversion.hpp" -participant OUT as "stdout" -User->>SD : "stdin line with {dig, wif}" -SD->>KEYS : "wif_to_key(wif)" -KEYS-->>SD : "private_key" -SD->>SD : "sign_compact(dig)" -SD-->>OUT : "JSON {dig, key, sig}" -``` - -**Diagram sources** -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L26-L46) - -## Detailed Component Analysis - -### sign_transaction Tool -Purpose: -- Debug transaction signing by computing digests and verifying signatures against a given chain ID. - -Command-line usage: -- Standard input: newline-separated JSON objects with fields: - - tx: a transaction object - - wif: a WIF-encoded private key string -- Standard output: newline-separated JSON objects with fields: - - tx: the original transaction - - digest: transaction digest - - sig_digest: signature digest bound to chain ID - - key: public key derived from WIF - - sig: compact signature - -Processing logic: -- Parse each input line as JSON. -- Convert WIF to a private key. -- Compute transaction digest and signature digest bound to the chain ID. -- Sign the signature digest with the private key. -- Emit the result as JSON. - -```mermaid -flowchart TD -Start(["Read stdin line"]) --> Parse["Parse JSON variant"] -Parse --> Valid{"Valid JSON?"} -Valid --> |No| Error["Skip/Log error"] -Valid --> |Yes| WIF["Convert WIF to private key"] -WIF --> Digests["Compute tx.digest()
and tx.sig_digest(CHAIN_ID)"] -Digests --> Sign["Sign sig_digest with private key"] -Sign --> PubKey["Derive public key"] -PubKey --> Emit["Emit JSON {tx, digest, sig_digest, key, sig}"] -Emit --> End(["Exit loop"]) -Error --> End -``` - -**Diagram sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L28-L51) - -**Section sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L12-L26) -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L28-L51) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L17-L28) -- [config.hpp](file://libraries/protocol/config.hpp#L9-L9) - -### sign_digest Tool -Purpose: -- Debug cryptographic operations and signature verification by signing arbitrary SHA256 digests. - -Command-line usage: -- Standard input: newline-separated JSON objects with fields: - - dig: a hex-encoded SHA256 digest string - - wif: a WIF-encoded private key string -- Standard output: newline-separated JSON objects with fields: - - dig: the input digest - - key: public key derived from WIF - - sig: compact signature - -Processing logic: -- Parse each input line as JSON. -- Convert WIF to a private key. -- Sign the digest with the private key. -- Emit the result as JSON. - -```mermaid -flowchart TD -Start(["Read stdin line"]) --> Parse["Parse JSON variant"] -Parse --> Valid{"Valid JSON?"} -Valid --> |No| Error["Skip/Log error"] -Valid --> |Yes| WIF["Convert WIF to private key"] -WIF --> Sign["Sign digest with private key"] -Sign --> PubKey["Derive public key"] -PubKey --> Emit["Emit JSON {dig, key, sig}"] -Emit --> End(["Exit loop"]) -Error --> End -``` - -**Diagram sources** -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L26-L46) - -**Section sources** -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L12-L24) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L26-L46) - -### JavaScript Operation Serializer -Purpose: -- Generate JavaScript serializers for operations and chain properties to inspect binary-to-JSON conversion behavior. - -Command-line usage: -- No command-line options; runs and prints generated JavaScript serializer definitions to stdout. - -Processing logic: -- Iterates through operation types and chain properties. -- Generates serializer definitions for each type, printing them to stdout. - -```mermaid -flowchart TD -Start(["Run main"]) --> Ops["Iterate operation types"] -Ops --> Props["Iterate chain properties"] -Props --> Init["Initialize serializers"] -Init --> Print["Print serializer definitions"] -Print --> End(["Exit"]) -``` - -**Diagram sources** -- [main.cpp](file://programs/js_operation_serializer/main.cpp#L495-L531) - -**Section sources** -- [main.cpp](file://programs/js_operation_serializer/main.cpp#L495-L531) - -### Transaction Validation and Authority Verification -Validation: -- Transactions must contain at least one operation. -- Each operation undergoes validation checks. - -Authority verification: -- The verify_authority function computes required authorities and validates provided signatures and approvals. -- It distinguishes between regular, active, and master authorities and enforces mutual exclusivity rules. -- It reports missing authorities and unused signatures/approvals. - -```mermaid -flowchart TD -Start(["verify_authority(ops, sigs, getters)"]) --> Required["Collect required authorities"] -Required --> Branch{"Regular authority present?"} -Branch --> |Yes| Reg["Check regular authority
and approvals"] -Branch --> |No| ActMaster["Check active/master authorities"] -Reg --> Unused["Assert no unused signatures/approvals"] -ActMaster --> Unused -Unused --> End(["Success"]) -``` - -**Diagram sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L94-L222) -- [sign_state.hpp](file://libraries/protocol/sign_state.hpp#L10-L42) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L58-L115) - -## Dependency Analysis -The signing utilities depend on the protocol layer for digest computation and signature generation. The chain layer provides transaction storage and duplicate detection mechanisms. - -```mermaid -graph LR -ST["sign_transaction.cpp"] --> TXCPP["transaction.cpp"] -SD["sign_digest.cpp"] --> TXCPP -TXCPP --> SIGSTATE["sign_state.hpp"] -TXCPP --> EXC["exceptions.hpp"] -TXCPP --> CFG["config.hpp"] -GCFG["get_config.cpp"] --> CFG -TXOBJ["transaction_object.hpp"] --> TXCPP -``` - -**Diagram sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L10-L10) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L10-L10) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L3) -- [sign_state.hpp](file://libraries/protocol/sign_state.hpp#L1-L45) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L1-L116) -- [config.hpp](file://libraries/protocol/config.hpp#L1-L169) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L1-L78) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp#L1-L56) - -**Section sources** -- [sign_transaction.cpp](file://programs/util/sign_transaction.cpp#L10-L10) -- [sign_digest.cpp](file://programs/util/sign_digest.cpp#L10-L10) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L1-L3) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp#L1-L56) - -## Performance Considerations -- Both utilities process input line-by-line, suitable for streaming large sets of transactions or digests. -- Digest computations and ECDSA signatures are CPU-bound; batching multiple inputs per invocation reduces overhead. -- For large-scale debugging, consider precomputing digests and reusing WIF keys to minimize repeated conversions. - -## Troubleshooting Guide -Common transaction validation failures: -- Missing operations: Ensure the transaction contains at least one operation. -- Invalid authority combinations: Regular authority cannot be mixed with active/master authority in the same transaction. - -Signature verification problems: -- Duplicate signatures: Detected during signature key extraction; remove duplicates. -- Irrelevant signatures: Unused signatures cause verification failure; remove before submission. -- Missing required authorities: Add signatures from required authorities or adjust approvals. - -Serialization issues: -- Use the JavaScript operation serializer to inspect operation and chain property serializers and confirm binary-to-JSON mapping. - -Network transmission issues: -- Verify the chain ID matches the target network; mismatches prevent successful broadcast. -- Confirm transaction size does not exceed limits and expiration is set appropriately. - -Practical examples: -- Transaction construction errors: Validate operations individually and ensure correct field types/values. -- Authority verification failures: Use sign_transaction to generate expected signatures and compare with provided ones. -- Serialization issues: Compare JSON vs. binary representation using the JavaScript operation serializer. - -**Section sources** -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L30-L36) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L225-L237) -- [transaction.cpp](file://libraries/protocol/transaction.cpp#L76-L92) -- [exceptions.hpp](file://libraries/protocol/exceptions.hpp#L58-L115) -- [config.hpp](file://libraries/protocol/config.hpp#L9-L9) -- [get_config.cpp](file://libraries/protocol/get_config.cpp#L28-L28) - -## Conclusion -The transaction debugging utilities provide focused capabilities to validate signing, cryptographic operations, and serialization. By leveraging the protocol and chain layers, developers can isolate issues in transaction construction, authority verification, and network compatibility. Use the troubleshooting guide to systematically address common problems and improve reliability in production environments. - -## Appendices -- Chain ID: The chain ID is derived from the chain name and is used to bind signatures to the correct network. -- Transaction storage: Duplicate detection relies on storing packed transactions with expiration timestamps. - -**Section sources** -- [config.hpp](file://libraries/protocol/config.hpp#L9-L9) -- [transaction_object.hpp](file://libraries/chain/transaction_object.hpp#L19-L35) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Development Tools.md b/.qoder/repowiki/en/content/Development Tools/Development Tools.md deleted file mode 100644 index 55d91c8010..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Development Tools.md +++ /dev/null @@ -1,346 +0,0 @@ -# Development Tools - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [CMakeLists.txt](file://CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testing.md](file://documentation/testing.md) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md) -- [documentation/plugin.md](file://documentation/plugin.md) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) -- [programs/util/newplugin.py](file://programs/util/newplugin.py) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp) -- [programs/util/pretty_schema.py](file://programs/util/pretty_schema.py) -- [programs/js_operation_serializer/main.cpp](file://programs/js_operation_serializer/main.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the complete development toolkit for VIZ CPP Node, focusing on the CMake build system, cross-platform compilation, Docker-based development environments, testing frameworks, debugging tools, and development workflow. It also covers code generation utilities, schema validation helpers, and practical examples for common development tasks such as building custom plugins, running tests, and profiling performance. The goal is to make the development toolchain accessible to contributors while providing sufficient technical depth for advanced tasks. - -## Project Structure -The repository is organized around a layered structure: -- Top-level CMake configuration orchestrates thirdparty, libraries, plugins, and programs. -- Libraries implement core blockchain logic (chain, protocol, network, utilities, wallet). -- Plugins provide modular features (e.g., chain, debug_node, p2p, webserver). -- Programs include the node daemon, CLI wallet, utilities, and build helpers. -- Documentation provides build, testing, plugin, and debugging guides. -- Dockerfiles and CI workflows support reproducible builds and automated testing. - -```mermaid -graph TB -Root["Top-level CMakeLists.txt"] -ThirdParty["thirdparty/"] -Libs["libraries/"] -Plugins["plugins/"] -Programs["programs/"] -Docs["documentation/"] -Docker["share/vizd/docker/"] -Root --> ThirdParty -Root --> Libs -Root --> Plugins -Root --> Programs -Root --> Docs -Root --> Docker -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L214) -- [README.md](file://README.md#L1-L53) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L277) -- [README.md](file://README.md#L1-L53) - -## Core Components -- Build system: CMake with platform-specific flags, coverage, and optional components (e.g., MongoDB plugin). -- Cross-compilation helper: configure_build.py supports Windows cross-compilation and custom Boost/OpenSSL roots. -- Plugin system: automatic discovery of internal plugins and support for external plugins. -- Testing: unit tests via chain_test with configurable runtime options and coverage reporting. -- Debugging: debug_node plugin for state simulation and API experimentation. -- Utilities: schema inspection, pretty-printing JSON schema, JS operation serializer, and plugin scaffolding. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L52-L89) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L143-L196) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L1-L57) -- [programs/util/pretty_schema.py](file://programs/util/pretty_schema.py#L1-L28) -- [programs/js_operation_serializer/main.cpp](file://programs/js_operation_serializer/main.cpp#L1-L531) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) - -## Architecture Overview -The development architecture integrates build orchestration, modular plugins, and reproducible environments: -- CMake discovers libraries, plugins, and programs, enabling conditional compilation and platform-specific flags. -- Dockerfiles encapsulate build environments for production and testnet scenarios. -- CI workflows automate Docker image builds for main and PR contexts. -- Utilities and scripts streamline plugin creation, reflection checks, and schema validation. - -```mermaid -graph TB -subgraph "Build Orchestration" -CMake["CMakeLists.txt"] -ConfigPy["configure_build.py"] -end -subgraph "Runtime Modules" -Libs["libraries/"] -Plugins["plugins/"] -Programs["programs/"] -end -subgraph "Dev Tools" -NewPlugin["newplugin.py"] -SchemaTest["schema_test.cpp"] -PrettySchema["pretty_schema.py"] -ReflectCheck["check_reflect.py"] -end -subgraph "Reproducibility" -DockerProd["Dockerfile-production"] -GHMain[".github/workflows/docker-main.yml"] -GHPR[".github/workflows/docker-pr-build.yml"] -end -CMake --> Libs -CMake --> Plugins -CMake --> Programs -ConfigPy --> CMake -NewPlugin --> Plugins -SchemaTest --> Libs -PrettySchema --> Plugins -ReflectCheck --> Libs -DockerProd --> Programs -GHMain --> DockerProd -GHPR --> DockerProd -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L214) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L143-L196) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L225-L247) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L44-L56) -- [programs/util/pretty_schema.py](file://programs/util/pretty_schema.py#L9-L27) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L160) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) - -## Detailed Component Analysis - -### CMake Build System -Key characteristics: -- Enforces minimum compiler versions for GCC and Clang. -- Supports compile-time options such as BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, and ENABLE_MONGO_PLUGIN. -- Enables ccache globally when available. -- Adds subdirectories for thirdparty, libraries, plugins, and programs. -- Provides coverage flags via ENABLE_COVERAGE_TESTING. - -Common build options and flags: -- CMAKE_BUILD_TYPE: Release or Debug. -- LOW_MEMORY_NODE: Build a consensus-only node. -- BUILD_TESTNET: Configure for test network. -- CHAINBASE_CHECK_LOCKING: Enable lock checking in chainbase. -- ENABLE_MONGO_PLUGIN: Include MongoDB plugin. -- ENABLE_COVERAGE_TESTING: Enable coverage instrumentation. - -Cross-platform flags: -- Windows (MSVC/Mingw): Compiler and linker flags, static linking options, and MSVC-specific settings. -- macOS/Linux: Standard C++14 flags, platform-specific libraries, and Ninja diagnostics. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L11-L20) -- [CMakeLists.txt](file://CMakeLists.txt#L56-L89) -- [CMakeLists.txt](file://CMakeLists.txt#L106-L110) -- [CMakeLists.txt](file://CMakeLists.txt#L112-L202) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [CMakeLists.txt](file://CMakeLists.txt#L210-L214) - -### Cross-Platform Compilation and Docker Environments -- Platform-specific instructions and dependencies are documented for Ubuntu, macOS, and Windows (where applicable). -- Dockerfiles define reproducible builds for production and testnet, including dependency installation, submodule initialization, and staged builds. - -Practical steps: -- Use configure_build.py to simplify cross-compilation and environment setup. -- Build Docker images for production or testnet using provided Dockerfiles. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L143-L196) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) - -### Testing Framework -- Unit tests are built via chain_test and executed to validate basic, block, operation, serialization, and time-dependent functionality. -- Runtime configuration supports log levels, report levels, and selective test execution. -- Coverage testing is supported with lcov integration. - -Recommended workflow: -- Build chain_test with CMake. -- Run tests with desired runtime options. -- Capture coverage data and generate HTML reports. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -### Debugging Tools -- debug_node plugin enables “what-if” simulations by editing chain state locally, generating blocks, and manipulating accounts for testing. -- Provides RPC methods for loading blocks, generating blocks, and updating objects. -- Use with caution: changes are local and do not affect the live network. - -Typical usage: -- Configure RPC and plugin exposure carefully. -- Load historical blocks and simulate conditions. -- Experiment with account keys and transactions. - -**Section sources** -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L1-L134) - -### Plugin Development Toolkit -- Internal plugins are discovered automatically; external plugins can be added to a dedicated directory and built seamlessly. -- newplugin.py generates boilerplate for custom plugins with API registration and factory registration. - -Workflow: -- Run newplugin.py to scaffold a plugin. -- Implement plugin lifecycle hooks and API methods. -- Register APIs and connect to chain events. - -**Section sources** -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L225-L247) - -### Transaction Serialization Utilities -- js_operation_serializer produces JavaScript-friendly serializers for operations and chain objects. -- Useful for front-end tooling and schema validation. - -Usage: -- Build and run the utility to emit serializers for operations and chain properties. - -**Section sources** -- [programs/js_operation_serializer/main.cpp](file://programs/js_operation_serializer/main.cpp#L495-L531) - -### Schema Validation and Reflection Checks -- schema_test.cpp inspects and prints schema metadata for chain objects. -- pretty_schema.py fetches and prettifies JSON schema from a running node’s debug_node API. -- check_reflect.py validates FC_REFLECT declarations against Doxygen class member lists. - -Integration: -- Use schema_test.cpp to inspect object schemas during development. -- Use pretty_schema.py to obtain human-readable schema definitions. -- Use check_reflect.py to ensure reflection and documentation remain synchronized. - -**Section sources** -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L44-L56) -- [programs/util/pretty_schema.py](file://programs/util/pretty_schema.py#L9-L27) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L160) - -### Development Workflow and CI -- Git branching follows a model with master and develop, with strict policies for pull requests, reviews, and tagging. -- CI workflows build Docker images for main and PR contexts to ensure reproducibility. - -Best practices: -- Branch from develop, keep commits focused, and ensure tests pass. -- Use PRs for code review and automated checks. -- Leverage Docker images for consistent environments. - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) - -## Dependency Analysis -The build system composes the project from multiple subprojects. The top-level CMake adds subdirectories for thirdparty, libraries, plugins, and programs. Conditional options influence which components are compiled and linked. - -```mermaid -graph TB -Root["CMakeLists.txt"] -TP["thirdparty"] -LIB["libraries"] -PLG["plugins"] -PRG["programs"] -Root --> TP -Root --> LIB -Root --> PLG -Root --> PRG -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L214) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L214) - -## Performance Considerations -- Use Release builds for performance-sensitive tasks. -- Enable coverage only when profiling or auditing code coverage. -- Consider LOW_MEMORY_NODE for resource-constrained environments (e.g., validators). -- Use Docker images to standardize environments and avoid performance regressions caused by local toolchain differences. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -Common issues and resolutions: -- Compiler version mismatch: Ensure GCC >= 4.8 or Clang >= 3.3 as enforced by CMake. -- Boost version: Use compatible Boost versions; configure_build.py helps locate custom Boost roots. -- Missing dependencies: Follow platform-specific installation steps in the building guide. -- Reflection mismatches: Run check_reflect.py to compare Doxygen-derived members with FC_REFLECT declarations. -- Docker build failures: Verify submodule initialization and environment variables; use provided Dockerfiles for reproducibility. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L11-L20) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L122-L140) -- [documentation/building.md](file://documentation/building.md#L25-L137) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py#L107-L160) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L32-L54) - -## Conclusion -The VIZ CPP Node development toolkit combines a robust CMake build system, cross-platform support, Docker-based reproducibility, comprehensive testing, and powerful debugging utilities. Together with plugin scaffolding and schema validation tools, it enables efficient and reliable development across platforms. Following the documented workflow and leveraging the provided utilities ensures consistent progress and high-quality contributions. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples - -- Build a Release binary on Linux/macOS: - - Configure with CMake and build targets as described in the building guide. - - Example targets include the node daemon and CLI wallet. - -- Build a Windows cross-compiled binary: - - Use configure_build.py with the Windows cross-compilation option and appropriate toolchain. - -- Run unit tests: - - Build chain_test and execute with desired runtime options. - -- Generate a custom plugin: - - Run newplugin.py to scaffold a plugin under libraries/plugins/. - - Implement plugin lifecycle and API methods, then rebuild. - -- Inspect chain object schemas: - - Build and run schema_test.cpp to print schema metadata. - - Use pretty_schema.py to fetch and format JSON schema from a node. - -- Profile performance: - - Build with coverage enabled and capture lcov data as described in the testing guide. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L190-L201) -- [programs/build_helpers/configure_build.py](file://programs/build_helpers/configure_build.py#L168-L179) -- [documentation/testing.md](file://documentation/testing.md#L30-L42) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L225-L247) -- [programs/util/schema_test.cpp](file://programs/util/schema_test.cpp#L44-L56) -- [programs/util/pretty_schema.py](file://programs/util/pretty_schema.py#L9-L27) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Development Workflow.md b/.qoder/repowiki/en/content/Development Tools/Development Workflow.md deleted file mode 100644 index ad630bc910..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Development Workflow.md +++ /dev/null @@ -1,394 +0,0 @@ -# Development Workflow - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md) -- [documentation/plugin.md](file://documentation/plugin.md) -- [programs/util/newplugin.py](file://programs/util/newplugin.py) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testing.md](file://documentation/testing.md) -- [.travis.yml](file://.travis.yml) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the complete development lifecycle for VIZ CPP Node contributors. It covers code style expectations, commit and branch conventions, pull request processes, plugin development workflow using the newplugin.py template, continuous integration pipelines (GitHub Actions and legacy CI), testing requirements, code review and merge criteria, collaboration and issue tracking, and how development practices tie into quality assurance. - -## Project Structure -The repository is organized around a CMake-based build system, with libraries, plugins, programs, and documentation. Key areas for contributors: -- Libraries: core blockchain logic and APIs -- Plugins: modular features enabling APIs and services -- Programs: utilities and executables (vizd, cli_wallet, helpers) -- Documentation: build, plugin, testing, and Git guidelines -- CI: GitHub Actions for Docker builds and PR validation - -```mermaid -graph TB -A["Root"] --> B["libraries"] -A --> C["plugins"] -A --> D["programs"] -A --> E["documentation"] -A --> F[".github/workflows"] -A --> G[".travis.yml"] -B --> B1["chain"] -B --> B2["api"] -B --> B3["network"] -B --> B4["protocol"] -B --> B5["utilities"] -B --> B6["wallet"] -C --> C1["chain"] -C --> C2["account_history"] -C --> C3["debug_node"] -C --> C4["json_rpc"] -C --> C5["mongo_db"] -C --> C6["tags"] -C --> C7["webserver"] -C --> C8["witness_api"] -C --> C9["... others"] -D --> D1["util"] -D --> D2["build_helpers"] -D --> D3["cli_wallet"] -D --> D4["vizd"] -D --> D5["js_operation_serializer"] -D --> D6["size_checker"] -D --> D7["util/*"] -E --> E1["building.md"] -E --> E2["plugin.md"] -E --> E3["testing.md"] -E --> E4["git_guildelines.md"] -E --> E5["testnet.md"] -E --> E6["debug_node_plugin.md"] -E --> E7["api_notes.md"] -E --> E8["doxygen/*"] -F --> F1["docker-main.yml"] -F --> F2["docker-pr-build.yml"] -``` - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [documentation/building.md](file://documentation/building.md#L1-L212) - -## Core Components -- Git and branching model: defines branches, PR process, and policies for master and develop. -- Plugin system: how plugins are registered, configured, and enabled. -- CI pipelines: automated Docker builds for PRs and releases. -- Testing: unit tests, coverage, and configuration options. -- Build system: CMake options and platform-specific instructions. - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L1-L111) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/building.md](file://documentation/building.md#L1-L212) - -## Architecture Overview -The development workflow integrates local development, automated CI, and release automation. The diagram below maps the primary components and their interactions during development and release. - -```mermaid -graph TB -Dev["Developer"] --> Repo["Repository"] -Repo --> GH["GitHub Actions
docker-main.yml"] -Repo --> PR["Pull Request Validation
docker-pr-build.yml"] -GH --> DockerHub["Docker Hub Images"] -PR --> DockerHub -Repo --> Travis["Legacy CI
.travis.yml"] -Travis --> DockerHub -Repo --> Docs["Documentation
building.md, testing.md, plugin.md"] -Repo --> Plugins["Plugin System
newplugin.py"] -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) - -## Detailed Component Analysis - -### Git and Pull Request Workflow -- Branches: - - master: release branch; PRs validated by CI before merge. - - develop: active development branch; PRs validated by CI. -- Branch naming: - - Issue-driven patches: issue-number-short-description. - - Non-issue patches: YYYYMMDD-shortname. -- Pull Requests: - - All changes to develop and master are submitted via PRs. - - Automated testing is mandatory; manual code review required. - - Merge conflicts must be resolved by rebasing against origin/develop. -- Policies: - - Force-push policy: master and develop are protected; patch branches may be force-pushed at discretion. - - Tagging policy: releases tagged as vMajor.Hardfork.Release on master. - -```mermaid -flowchart TD -Start(["Start Feature/Hotfix"]) --> Branch["Create Branch from develop
Issue-driven or YYYYMMDD naming"] -Branch --> Develop["Implement Changes
Follow style and tests"] -Develop --> Commit["Commit Conventions
Clear messages, single focus"] -Commit --> Push["Push Branch"] -Push --> PR["Open Pull Request to develop"] -PR --> CI["Automated Testing"] -CI --> |Pass| Review["Code Review by 2 Developers"] -CI --> |Fail| Fix["Fix Issues and Update PR"] -Review --> |Approved| Merge["Merge to develop or master per policy"] -Review --> |Changes Requested| Fix -Merge --> End(["Complete"]) -``` - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L8-L111) - -### Plugin Development Workflow Using newplugin.py -The newplugin.py script generates a complete plugin skeleton with boilerplate for headers, implementation files, and CMake configuration. After generation, contributors register signals, add API methods, and integrate with the application’s API factory. - -```mermaid -flowchart TD -A["Run newplugin.py provider name"] --> B["Generate files:
CMakeLists.txt,
*_plugin.hpp/cpp,
*_api.hpp/cpp"] -B --> C["Add plugin to CMake environment variable CHAIN_INTERNAL_PLUGINS"] -C --> D["Enable plugin via config: enable-plugin=name"] -D --> E["Register API factory in plugin_startup()
register_api_factory_api>"] -E --> F["Reflect API methods in FC_API declaration"] -F --> G["Optionally enable public API via config:
public-api, api-user"] -G --> H["Replay chain if enabling a DB-affecting plugin"] -``` - -**Diagram sources** -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) -- [documentation/plugin.md](file://documentation/plugin.md#L21-L28) - -**Section sources** -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) -- [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) - -### Continuous Integration Pipelines -- GitHub Actions: - - docker-main.yml: builds and pushes Docker images for master (testnet/latest). - - docker-pr-build.yml: builds a testnet image for PRs with ref tagging. -- Legacy CI (.travis.yml): - - Matrix builds multiple Dockerfiles (standard, test, testnet, lowmem, mongo). - - On master or tag, pushes images to Docker Hub. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant GH as "GitHub Actions" -participant Hub as "Docker Hub" -Dev->>GH : Push to master or open PR -GH->>GH : Run docker-main.yml or docker-pr-build.yml -GH->>Hub : Build and push image (latest/testnet/ref) -Hub-->>Dev : Image available for deployment -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) - -### Testing Requirements and Coverage -- Unit tests: - - Target: make chain_test - - Categories include basic_tests, block_tests, operation_tests, serialization_tests, etc. -- Runtime configuration: - - log_level, report_level, run_test flags for controlling verbosity and selection. -- Code coverage: - - Enable coverage in CMake, run initial capture, run tests, combine lcov traces, and generate HTML report. - -```mermaid -flowchart TD -A["Configure CMake
CMAKE_BUILD_TYPE, coverage flags"] --> B["Build"] -B --> C["Run initial lcov capture"] -C --> D["Execute tests/chain_test"] -D --> E["Run lcov capture"] -E --> F["Combine base.info + test.info -> total.info"] -F --> G["Filter out tests/* -> interesting.info"] -G --> H["Generate HTML report in lcov/"] -``` - -**Diagram sources** -- [documentation/testing.md](file://documentation/testing.md#L26-L43) - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -### Build System and Platform Notes -- CMake options: - - CMAKE_BUILD_TYPE=[Release/Debug] - - LOW_MEMORY_NODE=[FALSE/TRUE] for consensus-only nodes -- Platform-specific instructions: - - Ubuntu 16.04, 14.04, macOS X with specific package lists and caveats. -- Docker builds: - - Prebuilt images available; manual builds supported via Dockerfiles in share/vizd/docker. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [README.md](file://README.md#L1-L53) - -### Code Review and Merge Criteria -- Review policy: - - Two developers must review every release before merging into master. - - Two developers must review consensus-breaking changes before merging into develop. - - Patches should be reviewed by at least one developer other than the author. -- Quality checks: - - Automated tests must pass. - - Style and correctness must be verified (no trailing whitespace, single focus per patch, no mixing unrelated changes). -- Collaboration: - - External contributions should be reviewed by two internal developers. - - PRs should reference related issues to maintain traceability. - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L93-L111) - -### Issue Tracking and Collaboration -- Branches: - - master and develop define the cadence for releases and development. -- Branch creation: - - From develop; name according to issue number or date-based naming. -- PRs: - - Always reference related issues. - - Resolve merge conflicts by rebasing against origin/develop. - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L8-L76) - -### Relationship Between Development Workflow and QA -- CI ensures builds and Docker images are produced consistently for PRs and releases. -- Automated tests validate core functionality; coverage analysis helps identify gaps. -- Plugin scaffolding and reflection checks support API completeness and correctness. -- Release tagging and protected branches enforce stability gates for merges. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) - -## Dependency Analysis -The development workflow depends on: -- CI systems for automated validation and image publishing -- CMake and platform toolchains for building -- Plugin scaffolding for consistent API development -- Test suites for regression prevention - -```mermaid -graph LR -CI["CI Pipelines"] --> Build["Build & Test"] -Build --> Docker["Docker Images"] -Build --> Tests["Unit Tests & Coverage"] -Plugins["Plugin Scaffolding"] --> Build -Docs["Documentation"] --> Dev["Developer Workflow"] -Dev --> CI -Dev --> Plugins -Dev --> Tests -``` - -**Diagram sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [documentation/plugin.md](file://documentation/plugin.md#L1-L28) - -## Performance Considerations -- Build type: prefer Release for production; Debug with coverage for development and analysis. -- Low-memory nodes: use LOW_MEMORY_NODE for validator and seed-node deployments to reduce resource usage. -- Docker builds: leverage prebuilt images for faster iteration; build locally when debugging CI issues. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- CI failures: - - Verify Dockerfile selection and credentials for GitHub Actions. - - For Travis, confirm matrix variables and Docker Hub credentials. -- Build issues: - - Follow platform-specific dependency lists and version requirements. - - Use CMAKE_BUILD_TYPE=Release for production builds. -- Test failures: - - Use run_test and report_level to narrow down failing categories. - - Re-run with increased verbosity to locate failing test cases. -- Reflection mismatches: - - Use check_reflect.py to compare Doxygen XML and FC_REFLECT declarations. - -**Section sources** -- [.github/workflows/docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [.github/workflows/docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) -- [.travis.yml](file://.travis.yml#L1-L46) -- [documentation/building.md](file://documentation/building.md#L1-L212) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [programs/build_helpers/check_reflect.py](file://programs/build_helpers/check_reflect.py#L1-L160) - -## Conclusion -This workflow ensures reliable development, robust CI validation, and consistent releases. Contributors should follow branch naming, PR procedures, and review criteria; use the plugin scaffolding for API development; adhere to testing and coverage practices; and rely on CI pipelines for automated Docker builds and validations. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Practical Examples - -- Implementing a new plugin - - Use newplugin.py to generate boilerplate. - - Register API factory in plugin_startup(). - - Reflect API methods in FC_API declaration. - - Enable via config and optionally expose via public-api. - - **Section sources** - - [programs/util/newplugin.py](file://programs/util/newplugin.py#L1-L251) - - [documentation/plugin.md](file://documentation/plugin.md#L21-L28) - -- Fixing a bug - - Create a branch from develop with a descriptive name. - - Write targeted tests; run make chain_test and adjust flags as needed. - - Open a PR; address reviewer feedback; re-run CI. - - **Section sources** - - [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L25-L76) - - [documentation/testing.md](file://documentation/testing.md#L1-L43) - -- Contributing to an existing plugin - - Identify the plugin directory under plugins/. - - Follow the same scaffolding and reflection rules if adding new API methods. - - Ensure compatibility with DB state if applicable and document replay requirements. - - **Section sources** - - [documentation/plugin.md](file://documentation/plugin.md#L11-L20) - -### Code Style and Commit Conventions -- Keep commits focused and atomic. -- Use clear, descriptive commit messages. -- Avoid mixing unrelated changes in a single commit. -- Reference related issues in PR descriptions. - -**Section sources** -- [documentation/git_guildelines.md](file://documentation/git_guildelines.md#L62-L76) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Code Coverage Analysis.md b/.qoder/repowiki/en/content/Development Tools/Testing Framework/Code Coverage Analysis.md deleted file mode 100644 index a8569b22ee..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Code Coverage Analysis.md +++ /dev/null @@ -1,265 +0,0 @@ -# Code Coverage Analysis - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [testing.md](file://documentation/testing.md) -- [docker-main.yml](file://.github/workflows/docker-main.yml) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides a comprehensive guide to code coverage analysis for the VIZ CPP Node testing framework. It documents the complete lcov integration workflow, including prerequisites, debug build configuration, and the multi-step coverage capture process. It also explains cmake configuration options for enabling coverage testing in Debug builds, details lcov command-line options, and offers practical examples for generating coverage reports, interpreting metrics, and integrating coverage analysis into CI/CD pipelines. - -## Project Structure -The repository organizes the build and testing infrastructure around a top-level cmake configuration and documentation that describes the coverage workflow. The testing documentation outlines the lcov commands and the chain_test target used to exercise the test suite. The main cmake file defines the option to enable coverage testing and injects compiler flags accordingly. - -```mermaid -graph TB -Root["Repository Root"] -Docs["documentation/testing.md"] -CMakeRoot["CMakeLists.txt"] -Workflows["GitHub Workflows"] -Root --> Docs -Root --> CMakeRoot -Root --> Workflows -``` - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L26-L42) - -## Core Components -- Coverage build configuration via cmake option ENABLE_COVERAGE_TESTING -- Debug build requirement for coverage instrumentation -- lcov capture workflow with base.info, test execution, test.info, total.info, and filtered interesting.info -- HTML report generation with genhtml - -Key implementation points: -- The cmake option ENABLE_COVERAGE_TESTING controls whether coverage instrumentation flags are added to the build. -- The lcov workflow documented in testing.md shows the step-by-step process for capturing and combining tracefiles and generating HTML reports. -- The chain_test target is used to execute the test suite during coverage capture. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L26-L42) - -## Architecture Overview -The coverage workflow integrates cmake, lcov, and the test runner to produce an HTML coverage report. The diagram below maps the documented steps to actual files and targets. - -```mermaid -sequenceDiagram -participant Dev as "Developer" -participant CMake as "CMake (ENABLE_COVERAGE_TESTING)" -participant Lcov as "lcov" -participant Test as "chain_test" -participant GenHTML as "genhtml" -Dev->>CMake : Configure with -D ENABLE_COVERAGE_TESTING=true -D CMAKE_BUILD_TYPE=Debug -CMake-->>Dev : Compiler flags include --coverage -Dev->>Lcov : lcov --capture --initial --directory . --output-file base.info --no-external -Dev->>Test : Run tests/chain_test -Dev->>Lcov : lcov --capture --directory . --output-file test.info --no-external -Dev->>Lcov : lcov --add-tracefile base.info --add-tracefile test.info --output-file total.info -Dev->>Lcov : lcov -o interesting.info -r total.info tests/* -Dev->>GenHTML : genhtml interesting.info --output-directory lcov --prefix pwd -GenHTML-->>Dev : Open lcov/index.html in a browser -``` - -**Diagram sources** -- [testing.md](file://documentation/testing.md#L26-L42) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) - -## Detailed Component Analysis - -### cmake Coverage Configuration -- Option definition: ENABLE_COVERAGE_TESTING is defined as a cmake option with a cache type of BOOL. -- Conditional instrumentation: When enabled, the --coverage flag is prepended to CMAKE_CXX_FLAGS. -- Build type requirement: The documented workflow requires CMAKE_BUILD_TYPE=Debug. - -Practical implications: -- Enabling coverage adds instrumentation to all targets built under the project. -- The Debug build type ensures debug symbols are present for accurate line-level coverage. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) - -### lcov Workflow Steps -The documented workflow consists of the following stages: - -1. Initial capture with base.info - - Purpose: Initialize the coverage recorder with baseline counts. - - Command: lcov --capture --initial --directory . --output-file base.info --no-external - -2. Test execution with chain_test - - Purpose: Run the test suite to collect coverage data. - - Target: tests/chain_test - -3. Secondary capture with test.info - - Purpose: Capture coverage after running tests. - - Command: lcov --capture --directory . --output-file test.info --no-external - -4. Tracefile combination with total.info - - Purpose: Merge base and test tracefiles into a single total.info. - - Command: lcov --add-tracefile base.info --add-tracefile test.info --output-file total.info - -5. Filtering of test directories with interesting.info - - Purpose: Remove entries from tests/* to focus on library and plugin code. - - Command: lcov -o interesting.info -r total.info tests/* - -6. HTML report generation with genhtml - - Purpose: Produce an HTML report from the filtered tracefile. - - Command: genhtml interesting.info --output-directory lcov --prefix `pwd` - -7. Viewing the report - - Purpose: Inspect coverage metrics in a browser. - - Path: lcov/index.html - -**Section sources** -- [testing.md](file://documentation/testing.md#L26-L42) - -### lcov Command-Line Options -The workflow uses the following lcov options: -- --capture: Collects execution counts from the current working directory. -- --initial: Initializes the recorder for a clean baseline. -- --directory: Specifies the root directory for coverage data collection. -- --output-file: Sets the output filename for tracefiles. -- --no-external: Filters out coverage contributions from external sources. -- --add-tracefile: Combines multiple tracefiles into one. -- -r (remove): Removes matched patterns from the tracefile (used to exclude tests/*). - -These options are applied as documented in the testing guide. - -**Section sources** -- [testing.md](file://documentation/testing.md#L30-L42) - -### CI/CD Integration -While the repository does not include a dedicated coverage job in the GitHub Actions workflows, the existing Docker build workflows demonstrate how to integrate build and packaging steps in CI. To add coverage reporting to CI: - -- Add a job that configures the project with ENABLE_COVERAGE_TESTING and CMAKE_BUILD_TYPE=Debug. -- Run the lcov capture and report generation steps as documented. -- Publish artifacts (lcov/) for review. - -The Docker workflows show the general pattern of building images on pushes and pull requests, which can be extended to include coverage jobs. - -**Section sources** -- [docker-main.yml](file://.github/workflows/docker-main.yml#L1-L41) -- [docker-pr-build.yml](file://.github/workflows/docker-pr-build.yml#L1-L24) - -## Dependency Analysis -Coverage depends on: -- Cmake option ENABLE_COVERAGE_TESTING to inject --coverage flags. -- Debug build type for debug symbols. -- lcov tool availability (installed via brew on macOS as documented). -- The chain_test target to exercise the test suite. - -```mermaid -graph TB -CMakeOpt["ENABLE_COVERAGE_TESTING"] -Flags["--coverage in CMAKE_CXX_FLAGS"] -BuildType["CMAKE_BUILD_TYPE=Debug"] -LcovTool["lcov"] -ChainTest["tests/chain_test"] -TraceBase["base.info"] -TraceTest["test.info"] -TraceTotal["total.info"] -TraceFiltered["interesting.info"] -HtmlReport["lcov/index.html"] -CMakeOpt --> Flags -BuildType --> Flags -Flags --> ChainTest -LcovTool --> TraceBase -ChainTest --> TraceTest -TraceBase --> TraceTotal -TraceTest --> TraceTotal -TraceTotal --> TraceFiltered -TraceFiltered --> HtmlReport -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L26-L42) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L26-L42) - -## Performance Considerations -- Coverage instrumentation adds overhead; expect slower test execution and larger binary sizes. -- Using --no-external reduces noise from external dependencies, focusing on project code. -- Filtering tests/* with -r improves report readability by excluding test harness code. -- Keep the build in Debug to ensure accurate line-level coverage. - -## Troubleshooting Guide -Common issues and resolutions: -- Missing lcov tool - - Symptom: Commands fail with "command not found". - - Resolution: Install lcov using the documented package manager command. - -- No coverage data captured - - Symptom: Empty or minimal coverage in HTML report. - - Causes: - - ENABLE_COVERAGE_TESTING not enabled during configuration. - - CMAKE_BUILD_TYPE not set to Debug. - - Tests not executed or failing before coverage capture. - - Resolutions: - - Reconfigure with -D ENABLE_COVERAGE_TESTING=true -D CMAKE_BUILD_TYPE=Debug. - - Ensure tests/chain_test runs successfully. - - Verify --directory points to the build root and includes compiled sources. - -- Incorrect or missing debug symbols - - Symptom: Lines not attributed to source files. - - Resolution: Confirm Debug build and that --coverage flags are applied. - -- HTML report shows external paths - - Symptom: Coverage includes third-party or system libraries. - - Resolution: Use --no-external during capture and -r to remove unwanted patterns. - -- Tracefile combination errors - - Symptom: lcov fails to merge tracefiles. - - Resolution: Ensure base.info and test.info exist and are valid; confirm correct filenames and paths. - -- genhtml output location - - Symptom: Report not found or paths incorrect. - - Resolution: Use --output-directory lcov and --prefix `pwd` as documented. - -**Section sources** -- [testing.md](file://documentation/testing.md#L26-L42) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) - -## Conclusion -The VIZ CPP Node testing framework supports code coverage analysis through a straightforward cmake option and a well-defined lcov workflow. By enabling coverage instrumentation in Debug builds, capturing baseline and test tracefiles, combining and filtering them, and generating an HTML report, teams can gain actionable insights into test coverage. Integrating these steps into CI/CD pipelines enables continuous monitoring of coverage trends and helps maintain high-quality test suites. - -## Appendices - -### Practical Examples -- Enabling coverage and building: - - Configure with cmake -D ENABLE_COVERAGE_TESTING=true -D CMAKE_BUILD_TYPE=Debug . -- Capturing baseline coverage: - - Run lcov --capture --initial --directory . --output-file base.info --no-external -- Executing tests: - - Run tests/chain_test -- Capturing test coverage: - - Run lcov --capture --directory . --output-file test.info --no-external -- Combining tracefiles: - - Run lcov --add-tracefile base.info --add-tracefile test.info --output-file total.info -- Filtering test directories: - - Run lcov -o interesting.info -r total.info tests/* -- Generating HTML report: - - Run genhtml interesting.info --output-directory lcov --prefix `pwd` -- Viewing results: - - Open lcov/index.html in a browser - -**Section sources** -- [testing.md](file://documentation/testing.md#L26-L42) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Testing Framework.md b/.qoder/repowiki/en/content/Development Tools/Testing Framework/Testing Framework.md deleted file mode 100644 index 711bee8e2d..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Testing Framework.md +++ /dev/null @@ -1,336 +0,0 @@ -# Testing Framework - - -**Referenced Files in This Document** -- [testing.md](file://documentation/testing.md) -- [.travis.yml](file://.travis.yml) -- [CMakeLists.txt](file://CMakeLists.txt) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) -- [share/vizd/snapshot-testnet.json](file://share/vizd/snapshot-testnet.json) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the testing framework for VIZ CPP Node, focusing on unit tests, integration tests, and performance benchmarks. It explains the test categories, Boost.Test configuration, execution commands, reporting options, code coverage with lcov, and CI workflows. It also covers test data management, mock objects, environment setup, and practical examples for writing and running tests. - -## Project Structure -The testing infrastructure spans documentation, CMake build configuration, utility executables, and a dedicated test API plugin. The primary unit test target is generated via CMake and executed as an executable that runs all unit tests. Test categories are organized under a single test binary and filtered at runtime. - -```mermaid -graph TB -A["Root CMakeLists.txt"] --> B["libraries/CMakeLists.txt"] -B --> C["libraries/chain/CMakeLists.txt"] -A --> D["programs/util/CMakeLists.txt"] -D --> E["programs/util/test_block_log.cpp"] -A --> F["plugins/test_api/test_api_plugin.cpp"] -G["programs/vizd/main.cpp"] --> F -H["documentation/testing.md"] --> I["Unit test target and categories"] -J[".travis.yml"] --> K["CI container builds"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L200) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L1-L142) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [.travis.yml](file://.travis.yml#L1-L46) - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) -- [CMakeLists.txt](file://CMakeLists.txt#L1-L200) -- [libraries/CMakeLists.txt](file://libraries/CMakeLists.txt#L1-L8) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L1-L142) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) -- [.travis.yml](file://.travis.yml#L1-L46) - -## Core Components -- Unit test target and categories: - - The unit test target is built via CMake and produces an executable that runs all unit tests. - - Test categories include basic_tests, block_tests, live_tests, operation_tests, operation_time_tests, and serialization_tests. -- Boost.Test configuration: - - Runtime configuration supports log_level, report_level, and run_test filters. - - Refer to Boost.Test documentation for advanced options. -- Code coverage: - - lcov integration is supported with a dedicated CMake option to enable coverage in Debug builds. - - The documented workflow captures baseline and test tracefiles, merges them, removes test artifacts, and generates HTML reports. - -Practical usage examples: -- Run all unit tests: execute the built test binary. -- Filter by category or test case: use the run_test runtime option. -- Enable coverage: configure with the coverage flag and follow the lcov capture and HTML generation steps. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L1-L43) - -## Architecture Overview -The test architecture centers on a single test executable that aggregates multiple test suites. The test API plugin exposes JSON-RPC endpoints useful for integration-style tests. Utility programs exercise subsystems like block logging and signing. - -```mermaid -graph TB -subgraph "Test Executable" -T1["Unit tests
basic_tests, block_tests,
live_tests, operation_tests,
operation_time_tests, serialization_tests"] -end -subgraph "Test API Plugin" -P1["JSON-RPC APIs"] -P2["test_api_a"] -P2a["test_api_b"] -end -subgraph "Utilities" -U1["test_block_log"] -U2["sign_transaction"] -U3["sign_digest"] -end -T1 --> P1 -P1 --> P2 -P1 --> P2a -T1 --> U1 -T1 --> U2 -T1 --> U3 -``` - -**Diagram sources** -- [documentation/testing.md](file://documentation/testing.md#L6-L14) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L6-L14) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) - -## Detailed Component Analysis - -### Test Categories -- basic_tests: Validates “basic” functionality. -- block_tests: Validates blockchain-specific logic. -- live_tests: Validates against live chain data (e.g., past hardfork scenarios). -- operation_tests: Validates operations. -- operation_time_tests: Validates time-dependent operations (e.g., vesting withdrawals). -- serialization_tests: Validates serialization logic. - -Filtering and execution: -- Use the run_test runtime option to select specific suites or test cases. -- Configure log_level and report_level for verbosity and detail. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L6-L23) - -### Boost.Test Configuration and Execution -- Log level options include all, success, test_suite, message, warning, error, cpp_exception, system_error, fatal_error, nothing. -- Report level options include no, confirm, short, detailed. -- run_test supports selecting specific suites or test cases. - -Execution command: -- Build the test target and run the resulting executable to execute all tests. -- Use runtime options to filter and tune output. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L16-L23) - -### Code Coverage with lcov -- Enable coverage in Debug builds via a CMake option. -- Workflow: - - Capture initial tracefile. - - Run the test executable. - - Capture test tracefile. - - Merge and post-process tracefiles. - - Generate HTML report and open it in a browser. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L26-L43) - -### Test Data Management and Environment Setup -- Testnet configuration: - - A dedicated testnet configuration file exists for isolated testing environments. - - A Dockerfile is provided for building a testnet image. - - A snapshot file is available for quick testnet initialization. -- Test API plugin: - - The plugin registers JSON-RPC APIs and is loaded by the node process. - -```mermaid -sequenceDiagram -participant Node as "Node Process" -participant Main as "programs/vizd/main.cpp" -participant Plugin as "plugins/test_api/test_api_plugin.cpp" -Node->>Main : "Initialize application" -Main->>Plugin : "register_plugin()" -Plugin-->>Main : "plugin_initialize(options)" -Main-->>Node : "Startup complete" -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) - -**Section sources** -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L200) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L1-L200) -- [share/vizd/snapshot-testnet.json](file://share/vizd/snapshot-testnet.json#L1-L200) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) - -### Continuous Integration Testing Workflows -- CI builds Docker images for multiple variants (standard, test, testnet, low memory, mongo). -- The matrix defines environment variables and Dockerfile selection. -- Builds are triggered per branch and tag, enabling automated artifact publishing. - -```mermaid -flowchart TD -Start(["CI Trigger"]) --> SetEnv["Set DOCKERFILE and DOCKERNAME"] -SetEnv --> Build["docker build -t viz-world/viz-world: -f "] -Build --> Success{"Build Success?"} -Success --> |Yes| Push["Push to registry if credentials present"] -Success --> |No| Fail["Report failure"] -Push --> Deploy{"Master + latest?"} -Deploy --> |Yes| Release["Run deployment script"] -Deploy --> |No| End(["Done"]) -Release --> End -Fail --> End -``` - -**Diagram sources** -- [.travis.yml](file://.travis.yml#L1-L46) - -**Section sources** -- [.travis.yml](file://.travis.yml#L1-L46) - -### Practical Examples -- Writing a new test suite: - - Add tests to the existing test target using Boost.Test macros. - - Group tests into categories (basic_tests, block_tests, etc.) as appropriate. -- Running a specific suite: - - Use the run_test runtime option to execute a named suite or specific test case. -- Interpreting results: - - Adjust report_level to control output detail. - - Use log_level to focus on successes, warnings, errors, or disable logs. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L16-L23) - -### Integration Test Utilities -- Block log utility: - - Demonstrates opening a block log, appending signed blocks, flushing, and reading blocks. - - Useful for validating block storage and retrieval logic. -- Signing utilities: - - Provide helpers for signing digests and transactions, useful for integration tests requiring cryptographic operations. - -```mermaid -sequenceDiagram -participant App as "test_block_log" -participant Log as "block_log" -participant FS as "Filesystem" -App->>Log : "open(temp_dir)" -App->>Log : "append(signed_block)" -Log->>FS : "write" -App->>Log : "flush()" -App->>Log : "read_block(index)" -Log->>FS : "read" -Log-->>App : "block data" -``` - -**Diagram sources** -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) - -**Section sources** -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L58-L69) - -## Dependency Analysis -The test framework relies on: -- CMake configuration to build the test target and link required libraries. -- The test API plugin for JSON-RPC-based integration tests. -- Utility programs for exercising subsystems like block logging and signing. - -```mermaid -graph LR -CMake["CMakeLists.txt"] --> ChainLib["libraries/chain/CMakeLists.txt"] -CMake --> UtilCMake["programs/util/CMakeLists.txt"] -CMake --> TestAPI["plugins/test_api/test_api_plugin.cpp"] -UtilCMake --> TestBlockLog["programs/util/test_block_log.cpp"] -TestAPI --> NodeMain["programs/vizd/main.cpp"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L200) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L1-L142) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L1-L200) -- [libraries/chain/CMakeLists.txt](file://libraries/chain/CMakeLists.txt#L1-L142) -- [programs/util/CMakeLists.txt](file://programs/util/CMakeLists.txt#L1-L69) -- [programs/util/test_block_log.cpp](file://programs/util/test_block_log.cpp#L1-L54) -- [plugins/test_api/test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L1-L40) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L1-L120) - -## Performance Considerations -- Performance benchmarks are not explicitly defined in the repository’s testing documentation. -- Recommended approach: - - Use the existing test categories to isolate performance-sensitive areas (e.g., operation_time_tests). - - Integrate timing measurements around critical operations within unit tests. - - Use external benchmarking tools if needed, ensuring they integrate with the test runner and produce machine-readable results for CI. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- Coverage report generation fails: - - Ensure lcov is installed and the CMake coverage option is enabled in Debug builds. - - Verify tracefile capture steps and that the test executable path is correct. -- Test filtering does not work: - - Confirm the run_test runtime option syntax and that the selected suite or test case names match the registered tests. -- CI build failures: - - Review Docker build logs and environment variable assignments in the CI configuration. - - Validate that required credentials are configured for pushing images. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L26-L43) -- [.travis.yml](file://.travis.yml#L1-L46) - -## Conclusion -The VIZ CPP Node testing framework leverages a unified test executable with categorized suites, Boost.Test runtime configuration, and lcov-based coverage reporting. Integration tests benefit from the test API plugin and utility programs. CI automation builds multiple Docker variants to support diverse testing scenarios. Extending the framework involves adding tests to existing suites, configuring runtime options, and integrating coverage and CI pipelines. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices -- Example runtime options: - - log_level: set to desired verbosity level. - - report_level: set to control detail. - - run_test: filter suites or specific test cases. -- Coverage workflow summary: - - Enable coverage in Debug builds. - - Capture baseline and test tracefiles. - - Merge and post-process tracefiles. - - Generate and open HTML report. - -**Section sources** -- [documentation/testing.md](file://documentation/testing.md#L16-L43) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Unit Testing Infrastructure.md b/.qoder/repowiki/en/content/Development Tools/Testing Framework/Unit Testing Infrastructure.md deleted file mode 100644 index 7ed9151701..0000000000 --- a/.qoder/repowiki/en/content/Development Tools/Testing Framework/Unit Testing Infrastructure.md +++ /dev/null @@ -1,261 +0,0 @@ -# Unit Testing Infrastructure - - -**Referenced Files in This Document** -- [CMakeLists.txt](file://CMakeLists.txt) -- [testing.md](file://documentation/testing.md) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp) -- [main.cpp](file://programs/vizd/main.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document describes the unit testing infrastructure for VIZ CPP Node with a focus on the Boost.Test framework setup and configuration used across the testing suite. It explains the test categories, execution mechanisms via the chain_test target, runtime configuration options, and best practices for test development, data management, mocking, and environment isolation. - -## Project Structure -The testing infrastructure is primarily driven by the top-level build configuration and a dedicated test API plugin that supports test harnesses. The key elements are: -- Top-level CMake configuration enabling Boost unit_test_framework and defining the chain_test target -- Test category documentation and runtime configuration options -- A minimal test API plugin used by the node to support test scenarios - -```mermaid -graph TB -Root["Top-level CMakeLists.txt
Defines chain_test target and Boost unit_test_framework"] --> Tests["Generated chain_test executable"] -Tests --> Categories["Test Categories:
basic_tests, block_tests, live_tests,
operation_tests, operation_time_tests, serialization_tests"] -Tests --> RuntimeCfg["Runtime Config:
log_level, report_level, run_test"] -Tests --> Coverage["Coverage Testing:
ENABLE_COVERAGE_TESTING option"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L3-L23) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L3-L23) - -## Core Components -- Boost.Test framework integration: - - Boost unit_test_framework is included as a required component for building the test target. - - The chain_test target is produced by the build system and runs all unit tests. -- Test categories: - - basic_tests: Fundamental functionality tests - - block_tests: Blockchain operation tests - - live_tests: Live chain data validation (historical/past hardfork testing) - - operation_tests: Individual operation validation - - operation_time_tests: Time-dependent operations (e.g., vesting withdrawals) - - serialization_tests: Data encoding/decoding tests -- Runtime configuration: - - log_level: Controls logging verbosity (all, success, test_suite, message, warning, error, cpp_exception, system_error, fatal_error, nothing) - - report_level: Controls reporting detail (no, confirm, short, detailed) - - run_test: Filters which test units to execute (supports selecting suites and individual test cases) -- Code coverage: - - ENABLE_COVERAGE_TESTING option enables coverage flags during Debug builds - -Practical execution: -- Build and run: make chain_test followed by ./tests/chain_test -- Selective execution: pass --run_test= to filter tests -- Reporting customization: pass --report_level= and --log-level= - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [testing.md](file://documentation/testing.md#L3-L23) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) - -## Architecture Overview -The testing architecture centers on the Boost.Test framework integrated through CMake. The chain_test executable aggregates all registered tests across categories and executes them according to runtime configuration. The test API plugin is part of the node’s plugin ecosystem and can be leveraged by tests requiring RPC-like interactions. - -```mermaid -graph TB -subgraph "Build System" -CMake["CMakeLists.txt
unit_test_framework, chain_test target"] -end -subgraph "Test Harness" -ChainTest["chain_test executable"] -Categories["Test Suites
basic/block/live/operation/operation_time/serialization"] -Runtime["Boost.Test Runtime Args
log-level, report_level, run_test"] -end -subgraph "Node Plugin Ecosystem" -TestAPI["test_api_plugin
JSON_RPC_REGISTER_API"] -Main["vizd main.cpp
registers test_api_plugin"] -end -CMake --> ChainTest -ChainTest --> Categories -ChainTest --> Runtime -Main --> TestAPI -TestAPI -. "RPC-like test support" .-> ChainTest -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [testing.md](file://documentation/testing.md#L3-L23) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L16) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L52) -- [main.cpp](file://programs/vizd/main.cpp#L11-L71) - -## Detailed Component Analysis - -### Boost.Test Integration and chain_test Target -- The build configuration includes Boost unit_test_framework as a required component, ensuring the test framework is available. -- The chain_test target produces an executable that runs all unit tests. -- Optional coverage instrumentation is enabled via ENABLE_COVERAGE_TESTING, which injects coverage flags in Debug builds. - -```mermaid -flowchart TD -Start(["Configure with CMake"]) --> FindBoost["Find Boost with unit_test_framework"] -FindBoost --> DefineTarget["Define chain_test target"] -DefineTarget --> Build["Build chain_test"] -Build --> Run["Run ./tests/chain_test"] -Run --> Filter["Apply --run_test filter"] -Run --> Report["Apply --report_level and --log-level"] -Report --> Results["Output test results"] -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L3-L23) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [testing.md](file://documentation/testing.md#L3-L23) - -### Test Categories -The testing suite organizes tests into six categories: -- basic_tests: Validates basic functionality -- block_tests: Validates blockchain operations -- live_tests: Validates against live chain data (historical hardfork checks) -- operation_tests: Validates individual operations -- operation_time_tests: Validates time-dependent operations -- serialization_tests: Validates data encoding/decoding - -These categories are executed by the chain_test target and can be filtered using the run_test runtime argument. - -**Section sources** -- [testing.md](file://documentation/testing.md#L6-L14) - -### Runtime Configuration Options -- log_level: Controls logging verbosity. Values include all, success, test_suite, message, warning, error, cpp_exception, system_error, fatal_error, nothing. -- report_level: Controls reporting detail. Values include no, confirm, short, detailed. -- run_test: Selectively executes test suites or individual test cases. Examples: - - Run a whole suite: --run_test=operation_tests - - Run a specific case: --run_test=operation_tests/delegation - -These options are passed to the chain_test executable and align with Boost.Test’s documented runtime configuration. - -**Section sources** -- [testing.md](file://documentation/testing.md#L16-L23) - -### Test Data Management, Mock Objects, and Environment Isolation -- Test data management: - - Use temporary directories and isolated databases per test case to prevent cross-contamination. - - For blockchain-related tests, initialize a clean database state and reset forks as needed. -- Mock objects: - - Utilize lightweight mocks for external dependencies (e.g., network, storage) to isolate unit under test. - - Prefer dependency injection to swap real implementations with test doubles. -- Environment isolation: - - Run tests in separate processes or containers when necessary. - - Avoid global mutable state; prefer per-test fixtures and deterministic initialization. - -[No sources needed since this section provides general guidance] - -### Adding New Test Cases -- Create a new test suite or add to existing ones (e.g., operation_tests) using Boost.Test macros. -- Register test cases with meaningful names and organize them by category. -- Use run_test to selectively execute new cases during development. -- Keep tests deterministic and fast; avoid heavy I/O or external dependencies. - -[No sources needed since this section provides general guidance] - -## Dependency Analysis -The testing infrastructure depends on: -- Boost.Test framework (unit_test_framework) for test discovery and execution -- CMake configuration to produce the chain_test target -- Optional coverage flags controlled by ENABLE_COVERAGE_TESTING -- The test API plugin for RPC-like interactions within tests - -```mermaid -graph LR -Boost["Boost unit_test_framework"] --> CMake["CMakeLists.txt"] -CMake --> ChainTest["chain_test target"] -ChainTest --> Tests["All Test Suites"] -Coverage["ENABLE_COVERAGE_TESTING"] --> CMake -TestAPI["test_api_plugin"] --> ChainTest -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L16) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L52) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [CMakeLists.txt](file://CMakeLists.txt#L204-L208) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L16) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L52) - -## Performance Considerations -- Keep tests fast and deterministic; avoid unnecessary I/O or network calls. -- Use small, focused test cases and minimize fixture setup/teardown overhead. -- Leverage run_test to execute only relevant suites during development. -- Enable coverage only when needed to reduce build and runtime overhead. - -[No sources needed since this section provides general guidance] - -## Troubleshooting Guide -- If chain_test does not appear after building, verify the chain_test target exists and that Boost unit_test_framework is properly linked. -- If tests fail due to missing runtime configuration, ensure you pass --log-level, --report_level, and/or --run_test as needed. -- For coverage issues, confirm ENABLE_COVERAGE_TESTING is enabled and that lcov steps are executed correctly. - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L38-L50) -- [testing.md](file://documentation/testing.md#L26-L42) - -## Conclusion -The VIZ CPP Node testing infrastructure leverages Boost.Test through a well-defined CMake configuration that produces the chain_test executable. Tests are categorized for clarity and can be selectively executed using runtime arguments. The test API plugin integrates with the node to support RPC-like interactions in tests. By following best practices for test data management, mocking, and environment isolation, developers can maintain a robust and reliable testing suite. - -[No sources needed since this section summarizes without analyzing specific files] - -## Appendices - -### Appendix A: Test API Plugin Integration -The test_api_plugin registers a JSON-RPC API surface and is initialized by the node. While primarily intended for runtime node operations, it can also serve as a controlled interface for tests that require deterministic RPC-like behavior. - -```mermaid -sequenceDiagram -participant Node as "vizd main.cpp" -participant TestAPI as "test_api_plugin" -participant ChainTest as "chain_test" -Node->>TestAPI : register_plugin() -TestAPI->>TestAPI : plugin_initialize(options) -ChainTest->>TestAPI : invoke test_api_a/test_api_b (via RPC) -TestAPI-->>ChainTest : return values -``` - -**Diagram sources** -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L16) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L25-L35) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L52) -- [main.cpp](file://programs/vizd/main.cpp#L11-L71) - -**Section sources** -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L15-L16) -- [test_api_plugin.cpp](file://plugins/test_api/test_api_plugin.cpp#L25-L35) -- [test_api_plugin.hpp](file://plugins/test_api/include/graphene/plugins/test_api/test_api_plugin.hpp#L35-L52) -- [main.cpp](file://programs/vizd/main.cpp#L11-L71) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Getting Started.md b/.qoder/repowiki/en/content/Getting Started.md deleted file mode 100644 index b5342c6936..0000000000 --- a/.qoder/repowiki/en/content/Getting Started.md +++ /dev/null @@ -1,376 +0,0 @@ -# Getting Started - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [CMakeLists.txt](file://CMakeLists.txt) -- [documentation/building.md](file://documentation/building.md) -- [documentation/testnet.md](file://documentation/testnet.md) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini) -- [share/vizd/seednodes](file://share/vizd/seednodes) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This guide helps you install, configure, and run a VIZ node quickly. It covers: -- Prerequisites and environment setup -- Multiple installation approaches: Docker, manual compilation, and package installation -- First-time setup, configuration, and initial synchronization -- Practical scenarios: full node, testnet node, and validator node -- Security considerations, monitoring, and troubleshooting - -## Project Structure -At a high level, the repository provides: -- A production-ready node binary (vizd) -- Configuration templates for mainnet and testnet -- Dockerfiles for containerized deployment -- Build scripts and documentation for manual compilation - -```mermaid -graph TB -A["Root"] --> B["programs/vizd"] -A --> C["share/vizd"] -A --> D["documentation"] -A --> E["libraries"] -A --> F["plugins"] -C --> C1["config/*.ini"] -C --> C2["seednodes"] -C --> C3["docker/*.Dockerfile"] -C --> C4["vizd.sh"] -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -**Section sources** -- [README.md](file://README.md#L1-L53) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L158) - -## Core Components -- Node binary: vizd, the core blockchain node -- Configuration: config.ini for mainnet, config_testnet.ini for testnet, config_witness.ini for validator-only setups -- Seed nodes: curated list to bootstrap P2P connectivity -- Docker images: prebuilt or self-built images for quick deployment - -Key runtime entry point and plugin registration are defined in the node’s main program. - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L69-L73) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L73) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L86) -- [share/vizd/seednodes](file://share/vizd/seednodes#L1-L6) - -## Architecture Overview -The node exposes: -- P2P endpoint for peer-to-peer communication -- JSON-RPC HTTP and WebSocket endpoints for API access -- Optional validator production controls - -```mermaid -graph TB -subgraph "Node Runtime" -N["vizd"] -P["P2P Plugin"] -W["Webserver Plugin"] -C["Chain Plugin"] -NA["Network Broadcast API"] -WA["validator API"] -end -subgraph "External" -S["Seed Nodes"] -U["Users/Apps"] -end -N --> P -N --> W -N --> C -N --> NA -N --> WA -S --> P -U --> W -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L90) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L20) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L20) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L20) - -## Detailed Component Analysis - -### Prerequisites and Environment Setup -Supported platforms: -- Linux Ubuntu LTS -- macOS -- Windows (compilation notes are provided; official CI focuses on Linux/macOS) - -Dependencies: -- Boost 1.57+ -- OpenSSL -- CMake -- Compiler toolchains (GCC/Clang) - -Build-time options: -- Release vs Debug -- Low-memory node mode -- Testnet vs mainnet builds -- MongoDB plugin toggle - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [CMakeLists.txt](file://CMakeLists.txt#L56-L64) -- [CMakeLists.txt](file://CMakeLists.txt#L66-L74) -- [CMakeLists.txt](file://CMakeLists.txt#L83-L89) -- [documentation/building.md](file://documentation/building.md#L3-L16) -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L138-L189) - -### Installation Approaches - -#### Option A: Docker Deployment (Recommended for beginners) -- Use prebuilt images or build locally -- Exposed ports: P2P (2001), HTTP RPC (8090), WebSocket RPC (8091) -- Volume mounts for persistent data and config - -```mermaid -sequenceDiagram -participant User as "Operator" -participant Docker as "Docker Engine" -participant Image as "vizd Image" -participant Script as "vizd.sh" -participant Node as "vizd" -User->>Docker : Run container with env vars and volumes -Docker->>Image : Start entrypoint -Image->>Script : Execute vizd.sh -Script->>Node : Launch vizd with args and config -Node-->>User : Logs and RPC endpoints ready -``` - -**Diagram sources** -- [README.md](file://README.md#L12-L29) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L66-L88) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L74-L81) - -Practical steps: -- Pull or build the production image -- Run with mapped ports and volumes -- Optionally set seed nodes via environment variables -- Inspect logs and verify RPC availability - -**Section sources** -- [README.md](file://README.md#L12-L29) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L1-L88) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -#### Option B: Manual Compilation from Source -- Ubuntu LTS: install required packages, then build with CMake and make -- macOS: install dependencies via Homebrew, set environment variables for OpenSSL and Boost, then build -- Build targets include vizd and cli_wallet - -```mermaid -flowchart TD -Start(["Start"]) --> Deps["Install Boost 1.57+, OpenSSL, CMake, Compiler"] -Deps --> Clone["Clone repo and init submodules"] -Clone --> Configure["Configure with CMake"] -Configure --> Build["Build vizd and optional cli_wallet"] -Build --> Install["Optionally install to system"] -Install --> End(["Done"]) -``` - -**Diagram sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L138-L189) - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L138-L189) - -#### Option C: Package Installation -- Not documented in this repository; Docker and manual builds are the supported paths -- If packaging is desired, use the build artifacts produced by the CMake pipeline - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L210-L213) - -### First-Time Setup and Configuration - -#### Initial Configuration Files -- Mainnet: config.ini -- Testnet: config_testnet.ini -- validator-only: config_witness.ini - -Key areas to review: -- P2P endpoint and seed nodes -- RPC endpoints (HTTP and WebSocket) -- Shared memory sizing and growth thresholds -- Plugin selection and enablement -- Logging configuration - -```mermaid -flowchart TD -A["Copy template config"] --> B["Set p2p-endpoint and webserver-* endpoints"] -B --> C["Add p2p-seed-node entries"] -C --> D["Adjust shared-file-size and growth params"] -D --> E["Enable required plugins"] -E --> F["Review logging config"] -F --> G["Save and start node"] -``` - -**Diagram sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L20) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L69-L73) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L111-L130) - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L1-L107) -- [share/vizd/seednodes](file://share/vizd/seednodes#L1-L6) - -#### Initial Synchronization -- The node connects to seed nodes and downloads blocks -- Docker images may preload a snapshot to accelerate first sync -- Monitor logs to confirm peers and block progress - -**Section sources** -- [README.md](file://README.md#L31-L38) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L44-L53) - -### Practical Scenarios - -#### Full Node (Mainnet) -- Use config.ini -- Expose P2P and RPC ports -- Optionally set custom seed nodes via environment variables - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L20) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L17-L29) - -#### Testnet Node -- Use config_testnet.ini or the testnet Docker image -- Preloaded snapshot accelerates sync -- Additional test users and keys are documented - -**Section sources** -- [share/vizd/config/config_testnet.ini](file://share/vizd/config/config_testnet.ini#L1-L132) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L75-L77) -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) - -#### validator Node -- Use config_witness.ini -- Enable validator and witness_api plugins -- Configure validator name and private key - -**Section sources** -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L68-L86) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L106-L111) - -## Dependency Analysis -- Build-time dependencies: Boost, OpenSSL, CMake, compiler toolchain -- Runtime dependencies: shared libraries linked at build time -- Docker images encapsulate dependencies and expose ports - -```mermaid -graph LR -A["CMakeLists.txt"] --> B["Boost 1.57+"] -A --> C["OpenSSL"] -A --> D["Compiler Toolchain"] -E["Dockerfile-production"] --> B -E --> C -E --> D -F["Dockerfile-testnet"] --> B -F --> C -F --> D -``` - -**Diagram sources** -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L9-L30) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L9-L30) - -**Section sources** -- [CMakeLists.txt](file://CMakeLists.txt#L97-L104) -- [share/vizd/docker/Dockerfile-production](file://share/vizd/docker/Dockerfile-production#L9-L30) -- [share/vizd/docker/Dockerfile-testnet](file://share/vizd/docker/Dockerfile-testnet#L9-L30) - -## Performance Considerations -- Shared memory sizing and growth thresholds impact stability during high load -- Single write thread reduces lock contention for write-heavy workloads -- Plugin notification toggles can reduce overhead on push_transaction -- Thread pool sizing for RPC clients should match CPU cores - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L36-L47) - -## Troubleshooting Guide - -Common issues and resolutions: -- Network connectivity - - Verify P2P endpoint and firewall rules - - Confirm seed nodes are reachable - - Override seed nodes via environment variables in Docker - -- Configuration errors - - Validate config.ini sections and plugin lists - - Ensure endpoints are not conflicting with other services - -- Docker-specific - - Check container logs for initialization errors - - Confirm volume mounts for persistent data and config - - Rebuild images if dependencies change - -- validator setup - - Ensure validator name and private key are configured - - Adjust participation thresholds for testnet if needed - -**Section sources** -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L17-L29) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L20) -- [share/vizd/config/config_witness.ini](file://share/vizd/config/config_witness.ini#L82-L86) -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) - -## Conclusion -You now have multiple paths to run a VIZ node: -- Docker for quick start -- Manual build for customization -- validator configuration for block production - -Follow the configuration and troubleshooting sections to ensure a smooth setup and ongoing operation. - -## Appendices - -### Security Considerations -- Limit RPC exposure to trusted networks or use reverse proxies -- Use strong private keys for validator nodes -- Regularly update the node and monitor logs for anomalies - -### Monitoring Node Health -- Observe logs for peer connections and block progress -- Verify RPC endpoints are reachable -- Track shared memory usage and growth thresholds - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L111-L130) -- [share/vizd/vizd.sh](file://share/vizd/vizd.sh#L74-L81) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Logging System.md b/.qoder/repowiki/en/content/Logging System.md deleted file mode 100644 index fc6afff9fb..0000000000 --- a/.qoder/repowiki/en/content/Logging System.md +++ /dev/null @@ -1,490 +0,0 @@ -# Logging System - - -**Referenced Files in This Document** -- [logger.hpp](file://thirdparty/fc/include/fc/log/logger.hpp) -- [logger.cpp](file://thirdparty/fc/src/log/logger.cpp) -- [appender.hpp](file://thirdparty/fc/include/fc/log/appender.hpp) -- [appender.cpp](file://thirdparty/fc/src/log/appender.cpp) -- [logger_config.hpp](file://thirdparty/fc/include/fc/log/logger_config.hpp) -- [logger_config.cpp](file://thirdparty/fc/src/log/logger_config.cpp) -- [log_message.hpp](file://thirdparty/fc/include/fc/log/log_message.hpp) -- [console_appender.hpp](file://thirdparty/fc/include/fc/log/console_appender.hpp) -- [console_appender.cpp](file://thirdparty/fc/src/log/console_appender.cpp) -- [file_appender.hpp](file://thirdparty/fc/include/fc/log/file_appender.hpp) -- [file_appender.cpp](file://thirdparty/fc/src/log/file_appender.cpp) -- [gelf_appender.hpp](file://thirdparty/fc/include/fc/log/gelf_appender.hpp) -- [gelf_appender.cpp](file://thirdparty/fc/src/log/gelf_appender.cpp) -- [json_console_appender.hpp](file://thirdparty/fc/include/fc/log/json_console_appender.hpp) -- [json_console_appender.cpp](file://thirdparty/fc/src/log/json_console_appender.cpp) -- [main.cpp](file://programs/vizd/main.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Configuration System](#configuration-system) -7. [Log Levels and Filtering](#log-levels-and-filtering) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction - -The VIZ logging system is built on the fc (Fast Crypto) library's logging framework, providing a flexible and extensible architecture for capturing application events, errors, and informational messages. This system supports multiple output destinations through appenders, hierarchical logger organization, and configurable log levels with filtering capabilities. - -The logging system follows a layered architecture where loggers represent named logging channels, appenders handle the actual output formatting and destination, and log messages carry contextual information about the source and content of each log event. - -## Project Structure - -The logging system is organized across several key directories and files: - -```mermaid -graph TB -subgraph "Logging Core" -A[logger.hpp] --> B[logger.cpp] -C[appender.hpp] --> D[appender.cpp] -E[log_message.hpp] -F[logger_config.hpp] --> G[logger_config.cpp] -end -subgraph "Appenders" -H[console_appender.hpp] --> I[console_appender.cpp] -J[file_appender.hpp] --> K[file_appender.cpp] -L[gelf_appender.hpp] --> M[gelf_appender.cpp] -N[json_console_appender.hpp] --> O[json_console_appender.cpp] -end -subgraph "Application Integration" -P[main.cpp] -end -A --> H -A --> J -A --> L -A --> N -F --> H -F --> J -F --> L -F --> N -``` - -**Diagram sources** -- [logger.hpp:1-195](file://thirdparty/fc/include/fc/log/logger.hpp#L1-L195) -- [appender.hpp:1-51](file://thirdparty/fc/include/fc/log/appender.hpp#L1-L51) -- [logger_config.hpp:1-53](file://thirdparty/fc/include/fc/log/logger_config.hpp#L1-L53) - -**Section sources** -- [logger.hpp:1-195](file://thirdparty/fc/include/fc/log/logger.hpp#L1-L195) -- [appender.hpp:1-51](file://thirdparty/fc/include/fc/log/appender.hpp#L1-L51) -- [logger_config.hpp:1-53](file://thirdparty/fc/include/fc/log/logger_config.hpp#L1-L53) - -## Core Components - -### Logger Hierarchy - -The logging system centers around the `logger` class, which provides named logging channels with hierarchical inheritance: - -```mermaid -classDiagram -class Logger { --string _name --Logger _parent --bool _enabled --bool _additivity --LogLevel _level --vector~AppenderPtr~ _appenders -+get(name) Logger -+set_log_level(level) Logger& -+set_parent(parent) Logger& -+add_appender(appender) void -+log(message) void -+is_enabled(level) bool -} -class LogLevel { -+values all, debug, info, warn, error, off -+operator int() int -} -class LogMessage { -+LogContext context -+string format -+VariantObject data -+get_message() string -+get_context() LogContext -} -Logger --> LogLevel : "uses" -Logger --> LogMessage : "receives" -Logger --> Logger : "parent-child relationship" -``` - -**Diagram sources** -- [logger.hpp:22-72](file://thirdparty/fc/include/fc/log/logger.hpp#L22-L72) -- [log_message.hpp:116-141](file://thirdparty/fc/include/fc/log/log_message.hpp#L116-L141) - -### Appender Architecture - -The appender system provides pluggable output mechanisms through a factory pattern: - -```mermaid -classDiagram -class Appender { -<> -+create(name, type, args) AppenderPtr -+get(name) AppenderPtr -+register_appender(type, factory) bool -+log(message) void -} -class AppenderFactory { -<> -+create(args) AppenderPtr -} -class ConsoleAppender { --Config cfg --Color[] level_colors -+log(message) void -+configure(config) void -+print(text, color) void -} -class FileAppender { --Config cfg --ofstream out --Mutex slock -+log(message) void --rotate_files() void -} -class GelfAppender { --Config cfg --Endpoint gelf_endpoint --UdpSocket gelf_socket -+log(message) void -} -class JsonConsoleAppender { -+log(message) void -} -Appender <|-- ConsoleAppender -Appender <|-- FileAppender -Appender <|-- GelfAppender -Appender <|-- JsonConsoleAppender -Appender --> AppenderFactory : "factory pattern" -``` - -**Diagram sources** -- [appender.hpp:33-49](file://thirdparty/fc/include/fc/log/appender.hpp#L33-L49) -- [console_appender.hpp:8-65](file://thirdparty/fc/include/fc/log/console_appender.hpp#L8-L65) -- [file_appender.hpp:10-33](file://thirdparty/fc/include/fc/log/file_appender.hpp#L10-L33) -- [gelf_appender.hpp:10-27](file://thirdparty/fc/include/fc/log/gelf_appender.hpp#L10-L27) - -**Section sources** -- [logger.hpp:22-72](file://thirdparty/fc/include/fc/log/logger.hpp#L22-L72) -- [appender.hpp:33-49](file://thirdparty/fc/include/fc/log/appender.hpp#L33-L49) -- [log_message.hpp:116-141](file://thirdparty/fc/include/fc/log/log_message.hpp#L116-L141) - -## Architecture Overview - -The logging system implements a publish-subscribe pattern where loggers act as publishers and appenders as subscribers to log events: - -```mermaid -sequenceDiagram -participant Application as "Application Code" -participant Logger as "Logger" -participant Message as "LogMessage" -participant Appender1 as "ConsoleAppender" -participant Appender2 as "FileAppender" -participant Appender3 as "GelfAppender" -Application->>Logger : fc_ilog(logger, format, args) -Logger->>Logger : is_enabled(level) -alt Level enabled -Logger->>Message : create log_message -Logger->>Appender1 : log(message) -Logger->>Appender2 : log(message) -Logger->>Appender3 : log(message) -Appender1->>Appender1 : format to console -Appender2->>Appender2 : write to file -Appender3->>Appender3 : send via UDP -else Level disabled -Logger->>Application : return immediately -end -``` - -**Diagram sources** -- [logger.cpp:72-82](file://thirdparty/fc/src/log/logger.cpp#L72-L82) -- [console_appender.cpp:90-130](file://thirdparty/fc/src/log/console_appender.cpp#L90-L130) -- [file_appender.cpp:161-197](file://thirdparty/fc/src/log/file_appender.cpp#L161-L197) -- [gelf_appender.cpp:73-182](file://thirdparty/fc/src/log/gelf_appender.cpp#L73-L182) - -The architecture supports multiple output destinations simultaneously, with each appender handling its own formatting and output mechanism independently. - -## Detailed Component Analysis - -### Logger Implementation - -The logger implementation provides thread-safe access to named logging channels with hierarchical inheritance: - -```mermaid -flowchart TD -A[Logger Request] --> B{Logger Exists?} -B --> |No| C[Create New Logger] -B --> |Yes| D[Get Existing Logger] -C --> E[Initialize Logger Properties] -D --> E -E --> F[Set Parent Relationship] -F --> G[Apply Log Level] -G --> H[Add Appenders] -H --> I[Return Logger Instance] -J[Log Message] --> K[Check Level Enabled] -K --> |No| L[Skip Message] -K --> |Yes| M[Format Context] -M --> N[Distribute to Appenders] -N --> O[Parent Propagation] -``` - -**Diagram sources** -- [logger.cpp:102-106](file://thirdparty/fc/src/log/logger.cpp#L102-L106) -- [logger.cpp:126-135](file://thirdparty/fc/src/log/logger.cpp#L126-L135) - -Key features include: -- Thread-safe logger registry using spin locks -- Hierarchical parent-child relationships for log level inheritance -- Additivity property for propagating messages to parent loggers -- Configurable log levels with filtering - -**Section sources** -- [logger.cpp:14-26](file://thirdparty/fc/src/log/logger.cpp#L14-L26) -- [logger.cpp:102-141](file://thirdparty/fc/src/log/logger.cpp#L102-L141) - -### Console Appender - -The console appender provides formatted output to standard error and standard out with color support: - -```mermaid -flowchart TD -A[Log Message] --> B[Extract Context Info] -B --> C[Format Timestamp] -C --> D[Format Thread Name] -D --> E[Format File:Line] -E --> F[Format Method] -F --> G[Format Message Content] -G --> H[Apply Color Based on Level] -H --> I[Write to Console Stream] -I --> J[Optional Flush] -K[Configuration] --> L[Stream Selection] -L --> M[Level Color Mapping] -M --> N[Format Template] -N --> O[Flush Setting] -``` - -**Diagram sources** -- [console_appender.cpp:90-130](file://thirdparty/fc/src/log/console_appender.cpp#L90-L130) -- [console_appender.hpp:30-39](file://thirdparty/fc/include/fc/log/console_appender.hpp#L30-L39) - -**Section sources** -- [console_appender.cpp:21-64](file://thirdparty/fc/src/log/console_appender.cpp#L21-L64) -- [console_appender.cpp:90-162](file://thirdparty/fc/src/log/console_appender.cpp#L90-L162) - -### File Appender - -The file appender handles persistent log storage with rotation capabilities: - -```mermaid -flowchart TD -A[Log Message] --> B[Format Complete Message] -B --> C[Acquire Write Lock] -C --> D[Write to File] -D --> E[Check Rotation Needed] -E --> |Yes| F[Rotate Files] -E --> |No| G[Release Lock] -F --> H[Close Current File] -F --> I[Create New Timestamped File] -F --> J[Create Hard Link] -F --> K[Schedule Next Rotation] -K --> G -G --> L[Flush if Enabled] -L --> M[Complete Write] -N[Rotation Configuration] --> O[Interval Settings] -O --> P[Limit Settings] -P --> Q[Auto-Rotation Task] -``` - -**Diagram sources** -- [file_appender.cpp:60-131](file://thirdparty/fc/src/log/file_appender.cpp#L60-L131) -- [file_appender.cpp:161-197](file://thirdparty/fc/src/log/file_appender.cpp#L161-L197) - -**Section sources** -- [file_appender.cpp:16-58](file://thirdparty/fc/src/log/file_appender.cpp#L16-L58) -- [file_appender.cpp:161-197](file://thirdparty/fc/src/log/file_appender.cpp#L161-L197) - -### GELF Appender - -The Graylog Extended Log Format (GELF) appender enables integration with centralized logging systems: - -```mermaid -sequenceDiagram -participant Logger as "Logger" -participant GelfAppender as "GELF Appender" -participant Socket as "UDP Socket" -participant Graylog as "Graylog Server" -Logger->>GelfAppender : log(message) -GelfAppender->>GelfAppender : Extract Context Data -GelfAppender->>GelfAppender : Build GELF JSON -GelfAppender->>GelfAppender : Compress with ZLIB -alt Message Within Payload Limit -GelfAppender->>Socket : send_to(endpoint) -else Message Exceeds Limit -GelfAppender->>GelfAppender : Split into Chunks -loop For Each Chunk -GelfAppender->>Socket : send_chunk() -end -end -Socket->>Graylog : Deliver Log Message -``` - -**Diagram sources** -- [gelf_appender.cpp:73-182](file://thirdparty/fc/src/log/gelf_appender.cpp#L73-L182) - -**Section sources** -- [gelf_appender.cpp:22-33](file://thirdparty/fc/src/log/gelf_appender.cpp#L22-L33) -- [gelf_appender.cpp:73-182](file://thirdparty/fc/src/log/gelf_appender.cpp#L73-L182) - -## Configuration System - -The logging system supports dynamic configuration through structured configuration files: - -```mermaid -flowchart TD -A[Configuration File] --> B[Parse JSON] -B --> C[Load Appenders] -C --> D[Register Appenders] -D --> E[Load Loggers] -E --> F[Configure Logger Hierarchy] -F --> G[Set Log Levels] -G --> H[Attach Append to Loggers] -H --> I[Enable Logging System] -J[Default Configuration] --> K[Console Appenders] -K --> L[Default Logger] -L --> M[Standard Error/Out Streams] -N[Runtime Configuration] --> O[Command Line Options] -O --> P[Log Console Appender Options] -P --> Q[File Appender Options] -Q --> R[Logger Routing Options] -``` - -**Diagram sources** -- [logger_config.cpp:29-67](file://thirdparty/fc/src/log/logger_config.cpp#L29-L67) -- [logger_config.cpp:69-89](file://thirdparty/fc/src/log/logger_config.cpp#L69-L89) - -The configuration system supports: -- JSON-based configuration files -- Runtime configuration updates -- Hierarchical logger relationships -- Multiple appender types with custom parameters - -**Section sources** -- [logger_config.hpp:35-46](file://thirdparty/fc/include/fc/log/logger_config.hpp#L35-L46) -- [logger_config.cpp:25-67](file://thirdparty/fc/src/log/logger_config.cpp#L25-L67) - -## Log Levels and Filtering - -The logging system implements a hierarchical level-based filtering mechanism: - -```mermaid -flowchart TD -A[Log Level Request] --> B{Compare with Logger Level} -B --> |Request >= Logger Level| C[Message Enabled] -B --> |Request < Logger Level| D[Message Disabled] -C --> E[Check Parent Propagation] -E --> |Additivity Enabled| F[Forward to Parent] -E --> |Additivity Disabled| G[Complete] -F --> H[Parent Decision] -H --> |Enabled| I[Propagate Message] -H --> |Disabled| G -D --> J[Skip Processing] -K[Level Hierarchy] --> L[all < debug < info < warn < error < off] -L --> M[Each Level Includes Higher Levels] -``` - -**Diagram sources** -- [logger.cpp:68-70](file://thirdparty/fc/src/log/logger.cpp#L68-L70) -- [log_message.hpp:29-31](file://thirdparty/fc/include/fc/log/log_message.hpp#L29-L31) - -Supported log levels include: -- `all`: Capture all messages (lowest level) -- `debug`: Debug information and development messages -- `info`: General operational information -- `warn`: Warning conditions requiring attention -- `error`: Error conditions affecting functionality -- `off`: Disable all logging (highest level) - -**Section sources** -- [log_message.hpp:21-44](file://thirdparty/fc/include/fc/log/log_message.hpp#L21-L44) -- [logger.cpp:68-70](file://thirdparty/fc/src/log/logger.cpp#L68-L70) - -## Performance Considerations - -The logging system incorporates several performance optimization strategies: - -### Thread Safety and Concurrency -- Spin locks for logger registry access -- Mutex protection for console output streams -- Separate mutexes for different appenders to minimize contention -- Asynchronous file rotation tasks - -### Memory Management -- Smart pointer usage for automatic resource cleanup -- RAII-based file handle management -- Efficient string formatting with pre-allocated buffers - -### I/O Optimization -- Optional flushing to reduce disk writes -- Buffered file operations -- Asynchronous rotation to avoid blocking log operations - -### Network Efficiency -- UDP-based transmission for GELF appender -- Message compression to reduce bandwidth -- Chunked transmission for large messages - -**Section sources** -- [logger.cpp:102-106](file://thirdparty/fc/src/log/logger.cpp#L102-L106) -- [console_appender.cpp:123-125](file://thirdparty/fc/src/log/console_appender.cpp#L123-L125) -- [file_appender.cpp:191-196](file://thirdparty/fc/src/log/file_appender.cpp#L191-L196) - -## Troubleshooting Guide - -### Common Issues and Solutions - -**Log Messages Not Appearing** -- Verify log level configuration matches intended verbosity -- Check logger hierarchy for proper parent-child relationships -- Ensure appenders are properly attached to target loggers - -**File Appender Issues** -- Confirm file path permissions and directory existence -- Verify rotation configuration parameters are valid -- Check for file locking issues on Windows systems - -**Network Appender Problems** -- Validate GELF endpoint connectivity and port accessibility -- Verify DNS resolution for hostname-based endpoints -- Check firewall settings for UDP traffic - -**Performance Degradation** -- Review log level settings to reduce message volume -- Consider disabling unnecessary appenders -- Evaluate flush frequency settings for file appenders - -**Section sources** -- [file_appender.cpp:144-155](file://thirdparty/fc/src/log/file_appender.cpp#L144-L155) -- [gelf_appender.cpp:65-67](file://thirdparty/fc/src/log/gelf_appender.cpp#L65-L67) - -## Conclusion - -The VIZ logging system provides a robust, extensible foundation for application monitoring and debugging. Its modular architecture supports multiple output destinations, hierarchical organization, and flexible configuration options. The system balances performance with functionality through careful concurrency management and efficient I/O operations. - -Key strengths include: -- Pluggable appender architecture supporting diverse output formats -- Hierarchical logger organization with intelligent level propagation -- Comprehensive configuration system supporting runtime modifications -- Performance optimizations for production environments -- Integration capabilities with external logging systems - -The system serves as a solid foundation for both development debugging and production monitoring, with clear extension points for custom logging requirements. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/P2p Plugin.md b/.qoder/repowiki/en/content/P2p Plugin.md deleted file mode 100644 index 8a10541c59..0000000000 --- a/.qoder/repowiki/en/content/P2p Plugin.md +++ /dev/null @@ -1,2215 +0,0 @@ -# P2P Plugin - - -**Referenced Files in This Document** -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [peer_connection.hpp](file://libraries/network/include/graphene/network/peer_connection.hpp) -- [peer_database.hpp](file://libraries/network/include/graphene/network/peer_database.hpp) -- [core_messages.hpp](file://libraries/network/include/graphene/network/core_messages.hpp) -- [message.hpp](file://libraries/network/include/graphene/network/message.hpp) -- [config.hpp](file://libraries/network/include/graphene/network/config.hpp) -- [node.cpp](file://libraries/network/node.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [chainbase.hpp](file://thirdparty/chainbase/include/chainbase/chainbase.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [CMakeLists.txt](file://plugins/p2p/CMakeLists.txt) -- [config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced peer information logging with comprehensive metrics including bytes sent, connection direction, user agent strings, fork revision information, head block numbers and timestamps, firewall status indicators, and connection timing information -- Added cross-referencing capabilities with peer database entries to show failed/rejected peers and their current connection status -- Implemented comprehensive gap detection with automatic peer soft-banning for sync spam -- Enhanced DLT mode support with integrity verification, coverage gap monitoring, and Windows compatibility enhancements -- Integrated ANSI color coding system (white, cyan, gray, orange, red) throughout the logging system for improved console readability -- Added enhanced peer ahead-of-us detection mechanism with sophisticated DLT mode logic -- Implemented comprehensive startup block storage diagnostics with gap detection -- Enhanced minority fork recovery with improved peer interaction handling -- Replaced bool block-processing flags with `std::atomic` to allow thread-safe pause/resume from any thread -- Fixed atomic flag ordering in resume: `_catchup_after_pause` is set before clearing `snapshot_in_progress` to prevent stale-head fork -- Refactored resume_block_processing() into two-phase design: flags set immediately (Phase 1), drain posted async without wait (Phase 2) to eliminate a fiber deadlock -- Handle `shared_memory_corruption_exception` in block acceptance path: triggers auto-recovery instead of peer soft-ban -- Clear `_dlt_syncing` flag on SYNC→FORWARD transition to unblock validator production after sync completes -- Added node uptime field (`uptime=Xh Ym Zs`) to DLT Status and DLT P2P Stats log lines - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Enhanced Peer Information Logging](#enhanced-peer-information-logging) -7. [Comprehensive Gap Detection System](#comprehensive-gap-detection-system) -8. [Enhanced DLT Mode Block Range Management](#enhanced-dlt-mode-block-range-management) -9. [Improved Gap Detection and Recovery](#improved-gap-detection-and-recovery) -10. [Sophisticated Clamping Logic](#sophisticated-clamping-logic) -11. [Enhanced Peer Interaction Handling](#enhanced-peer-interaction-handling) -12. [Comprehensive Logging Throughout Sync Process](#comprehensive-logging-throughout-sync-process) -13. [ANSI Color Code Implementation](#ansi-color-code-implementation) -14. [Enhanced DLT Mode Debug Logging](#enhanced-dlt-mode-debug-logging) -15. [Improved Console Readability](#improved-console-readability) -16. [Conditional Block Processing Latency Logging](#conditional-block-processing-latency-logging) -17. [Graceful Degradation Capabilities](#graceful-degradation-capabilities) -18. [Minority Fork Recovery](#minority-fork-recovery) -19. [Enhanced Block Validation](#enhanced-block-validation) -20. [Concurrent Access Safety](#concurrent-access-safety) -21. [Logging Level Consistency](#logging-level-consistency) -22. [Dependency Analysis](#dependency-analysis) -23. [Performance Considerations](#performance-considerations) -24. [Troubleshooting Guide](#troubleshooting-guide) -25. [Conclusion](#conclusion) - -## Introduction - -The P2P (Peer-to-Peer) Plugin is a critical component of the VIZ blockchain node that enables decentralized communication between nodes in the network. This plugin provides the foundation for blockchain synchronization, transaction propagation, and peer discovery mechanisms that keep the entire network synchronized and functional. - -The plugin implements a sophisticated networking layer built on top of the Graphene network library, providing features such as automatic peer discovery, blockchain synchronization protocols, transaction broadcasting, and advanced peer management capabilities including soft-ban mechanisms and connection monitoring. - -**Updated** The plugin now includes enhanced monitoring capabilities with comprehensive ANSI color codes for improved console readability. DLT mode debug messages are displayed in gray color, while peer statistics and other informational messages use cyan and white color codes. The conditional block processing latency logging ensures that latency information is only displayed for successful block processing in non-sync mode, reducing log volume while maintaining operational visibility. These enhancements provide better visual distinction between different types of log messages and improve troubleshooting capabilities during network operations. - -## Project Structure - -The P2P plugin follows a modular architecture with clear separation of concerns: - -```mermaid -graph TB -subgraph "P2P Plugin Layer" -P2P[p2p_plugin.hpp/cpp] -Impl[p2p_plugin_impl] -DLT[DLT Mode Integration] -Stats[P2P Stats Task] -Stale[Stale Sync Detection] -Resync[resync_from_lib method] -Guard[operation_guard integration] -Colors[ANSI Color Codes] -Latency[Conditional Latency Logging] -Visibility[Enhanced Block Processing Visibility] -PeerDB[Enhanced Peer Database Logging] -StorageDiag[Block Storage Diagnostics] -DLTIntegrity[DLT Integrity Verification] -GapDetection[Comprehensive Gap Detection] -AheadOfUs[Enhanced Peer Ahead Detection] -StartupDiag[Startup Block Storage Diagnostics] -WindowsCompat[Windows Compatibility Enhancements] -``` - -**Diagram sources** -- [p2p_plugin.hpp:18-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L55) -- [p2p_plugin.cpp:910-979](file://plugins/p2p/p2p_plugin.cpp#L910-L979) -- [node.hpp:190-320](file://libraries/network/include/graphene/network/node.hpp#L190-L320) - -**Section sources** -- [p2p_plugin.hpp:1-57](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L1-L57) -- [CMakeLists.txt:1-49](file://plugins/p2p/CMakeLists.txt#L1-L49) - -## Core Components - -### P2P Plugin Interface - -The main plugin class provides a clean interface for managing P2P networking functionality: - -```mermaid -classDiagram -class p2p_plugin { -+set_program_options(cli, cfg) -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+broadcast_block(block) -+broadcast_block_post_validation(block_id, witness_account, signature) -+broadcast_transaction(tx) -+set_block_production(producing_blocks) -+resync_from_lib() --my : p2p_plugin_impl -} -class p2p_plugin_impl { -+has_item(id) -+handle_block(blk_msg, sync_mode, contained_tx_ids) -+handle_transaction(trx_msg) -+handle_message(message) -+get_block_ids(synopsis, remaining_count, limit) -+get_item(id) -+get_blockchain_synopsis(reference_point, num_blocks) -+sync_status(item_type, item_count) -+connection_count_changed(count) -+get_block_number(block_id) -+get_block_time(block_id) -+get_head_block_id() -+get_chain_id() -+error_encountered(message, error) -+get_blockchain_now() -+p2p_stats_task() -+stale_sync_check_task() -+is_included_block(block_id) -+ANSI Color Codes -+Conditional Latency Logging -+Enhanced Block Processing Visibility -+DLT Mode Debug Logging -+Enhanced Peer Stats -+Enhanced Peer Database Logging -+Block Storage Diagnostics -+DLT Integrity Verification -+Automatic Peer Soft-Banning -+Enhanced Gap Detection -+Comprehensive Gap Reporting -+Periodic DLT Integrity Scans -+Gap-Aware Recovery Mechanisms -+DLT Coverage Gap Monitoring -+Orange Color Coding for Warnings -+Red Color Coding for Critical Alerts -+Enhanced Peer Ahead-of-Us Detection -+Startup Block Storage Diagnostics -+Windows Compatibility Enhancements -``` - -**Diagram sources** -- [p2p_plugin.hpp:18-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L55) -- [p2p_plugin.cpp:49-126](file://plugins/p2p/p2p_plugin.cpp#L49-L126) - -### Network Node Architecture - -The plugin integrates with the underlying network infrastructure through a sophisticated node abstraction: - -```mermaid -classDiagram -class node { -+listen_to_p2p_network() -+connect_to_p2p_network() -+add_node(endpoint) -+connect_to_endpoint(endpoint) -+listen_on_endpoint(endpoint, wait) -+broadcast(message) -+sync_from(item_id, hard_fork_nums) -+resync() -+set_advanced_node_parameters(params) -+set_trusted_peer_endpoints(endpoints) -+get_connected_peers() -+get_connection_count() -+clear_peer_database() -+set_allowed_peers(allowed_peers) -+get_potential_peers() -} -class node_delegate { -<> -+has_item(id) -+handle_block(blk_msg, sync_mode, contained_tx_ids) -+handle_transaction(trx_msg) -+handle_message(message) -+get_block_ids(synopsis, remaining_count, limit) -+get_item(id) -+get_blockchain_synopsis(reference_point, num_blocks) -+sync_status(item_type, item_count) -+connection_count_changed(count) -+get_block_number(block_id) -+get_block_time(block_id) -+get_head_block_id() -+get_chain_id() -+error_encountered(message, error) -+get_blockchain_now() -} -class peer_connection { -+send_message(message) -+send_item(item_id) -+close_connection() -+destroy_connection() -+get_remote_endpoint() -+get_total_bytes_sent() -+get_total_bytes_received() -+busy() -+idle() -} -node ..|> node_delegate : "implements" -node --> peer_connection : "manages" -``` - -**Diagram sources** -- [node.hpp:190-320](file://libraries/network/include/graphene/network/node.hpp#L190-L320) -- [node.hpp:60-167](file://libraries/network/include/graphene/network/node.hpp#L60-L167) -- [peer_connection.hpp:79-354](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L354) - -**Section sources** -- [p2p_plugin.hpp:18-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L55) -- [node.hpp:190-320](file://libraries/network/include/graphene/network/node.hpp#L190-L320) - -## Architecture Overview - -The P2P plugin architecture implements a layered approach to blockchain networking: - -```mermaid -sequenceDiagram -participant App as Application -participant P2P as P2P Plugin -participant Node as Network Node -participant Peer as Remote Peer -participant Chain as Chain Database -App->>P2P : Initialize plugin -P2P->>Node : Create node instance -P2P->>Node : Load configuration -P2P->>Node : Set delegate (p2p_plugin_impl) -P2P->>Node : Listen on endpoint -P2P->>Node : Connect to seed nodes -Note over P2P,Node : Network initialization complete -Peer->>Node : Connect request -Node->>P2P : handle_message(hello) -P2P->>Node : Accept/reject connection -Node->>Peer : Connection accepted -Peer->>Node : Request blockchain synopsis -Node->>P2P : get_blockchain_synopsis() -P2P->>Chain : Query chain state -P2P->>Node : Return synopsis -Node->>Peer : Send synopsis -Peer->>Node : Request blocks/transactions -Node->>P2P : handle_message(fetch_items) -P2P->>Chain : Fetch items -P2P->>Node : Return items -Node->>Peer : Send items -Note over P2P,Chain : Enhanced DLT Mode with Gap Detection -P2P->>Chain : Check DLT availability -Chain-->>P2P : Earliest available block -P2P->>Node : Clamp block range with gap detection -P2P->>Node : Advertise only available blocks -Peer->>Node : New block/transaction -Node->>P2P : handle_block()/handle_transaction() -P2P->>Chain : Accept/validate block -P2P->>Node : Broadcast to peers -Note over P2P : Enhanced logging with ANSI color codes -P2P->>Node : Log DLT mode operations in gray -P2P->>Node : Log peer stats in cyan -P2P->>Node : Log latency in white only on successful processing -P2P->>Node : Log storage diagnostics with gap detection -P2P->>Node : Log DLT integrity verification -P2P->>Node : Log DLT coverage gaps in orange -P2P->>Node : Log critical errors in red -Note over P2P : Enhanced peer ahead-of-us detection -P2P->>Node : Detect peers ahead of us in DLT mode -P2P->>Node : Return empty response for ahead peers -Note over P2P : Startup block storage diagnostics -P2P->>Node : Log comprehensive storage diagnostics -P2P->>Node : Detect gaps and integrity issues -``` - -**Diagram sources** -- [p2p_plugin.cpp:758-823](file://plugins/p2p/p2p_plugin.cpp#L758-L823) -- [node.cpp:1-200](file://libraries/network/node.cpp#L1-L200) - -The architecture provides several key capabilities: - -1. **Automatic Peer Discovery**: The plugin automatically discovers and connects to seed nodes specified in configuration -2. **Blockchain Synchronization**: Implements efficient blockchain synchronization using selective block fetching with DLT mode awareness and gap detection -3. **Transaction Propagation**: Broadcasts transactions to connected peers with intelligent caching -4. **Peer Management**: Manages peer connections with soft-ban mechanisms and connection limits -5. **Monitoring and Statistics**: Provides comprehensive peer statistics and network health monitoring with colored console output -6. **Minority Fork Recovery**: Specialized recovery mechanism for handling minority fork scenarios -7. **Concurrent Access Safety**: Enhanced protection against concurrent access conflicts during block processing -8. **DLT Mode Support**: Intelligent block range management for snapshot-based nodes with sophisticated gap detection -9. **Graceful Degradation**: Handles peer unavailability with fallback mechanisms and automatic recovery -10. **Enhanced Logging**: Comprehensive logging system with ANSI color codes for improved console readability and conditional latency reporting -11. **DLT Storage Diagnostics**: Comprehensive block storage monitoring with gap detection and coverage analysis -12. **Peer Database Analytics**: Detailed peer interaction tracking with enhanced visibility into connection failures -13. **Automatic Peer Soft-Banning**: Intelligent peer management with automatic soft-banning for sync spam -14. **DLT Integrity Verification**: Periodic verification of DLT block log integrity with gap detection and continuity scanning -15. **Comprehensive Gap Detection**: Advanced gap detection reporting with detailed coverage gap monitoring -16. **Enhanced Peer Ahead-of-Us Detection**: Sophisticated detection of peers that are ahead of the local node in DLT mode -17. **Startup Block Storage Diagnostics**: Comprehensive diagnostics system that runs before synchronization begins -18. **Windows Compatibility Enhancements**: Enhanced compatibility with Windows operating systems for DLT block log operations - -## Detailed Component Analysis - -### Block Validation Protocol - -The P2P plugin implements a sophisticated block validation mechanism that enhances security and prevents malicious attacks: - -```mermaid -flowchart TD -Start([Block Received]) --> ValidateType{"Is block_post_validation_message?"} -ValidateType --> |No| StandardValidation["Standard block validation
via chain.accept_block()"] -ValidateType --> |Yes| ExtractParams["Extract block_id,
witness_account,
signature"] -ExtractParams --> VerifyWitness{"Verify validator exists?"} -VerifyWitness --> |No| RejectBlock["Reject block
(invalid validator)"] -VerifyWitness --> |Yes| VerifySignature["Verify signature
matches validator key"] -VerifySignature --> SignatureValid{"Signature valid?"} -SignatureValid --> |No| RejectBlock -SignatureValid --> |Yes| ApplyValidation["Apply block post-validation
chain.db().apply_block_post_validation()"] -ApplyValidation --> BroadcastBlock["Broadcast block to peers"] -StandardValidation --> BroadcastBlock -RejectBlock --> End([End]) -BroadcastBlock --> End -style RejectBlock fill:#ffcccc -style BroadcastBlock fill:#ccffcc -``` - -**Diagram sources** -- [p2p_plugin.cpp:216-245](file://plugins/p2p/p2p_plugin.cpp#L216-L245) -- [p2p_plugin.cpp:855-865](file://plugins/p2p/p2p_plugin.cpp#L855-L865) - -**Updated** The block validation protocol now includes enhanced concurrent access safety through operation guard protection and conditional latency logging: - -The block validation process incorporates operation guards to prevent concurrent access conflicts during validator key validation and block post-validation processing. This ensures thread-safe access to shared blockchain state during high-load conditions. - -The enhanced validation includes: - -1. **validator Signature Verification**: Validates that the block signature matches the claimed validator's public key -2. **Chain ID Consistency**: Ensures blocks belong to the correct blockchain instance -3. **Hard Fork Protection**: Handles different validation requirements across blockchain hard forks -4. **Post-Validation Processing**: Applies additional validation steps after initial acceptance -5. **Concurrent Access Protection**: Uses operation guards to prevent race conditions during validation -6. **Error Handling**: Comprehensive error handling for various failure scenarios -7. **Conditional Latency Reporting**: Only displays latency information for successful block processing in non-sync mode - -### Peer Connection Management - -The plugin manages peer connections through a sophisticated state machine: - -```mermaid -stateDiagram-v2 -[*] --> Disconnected -Disconnected --> Connecting : initiate_connection() -Connecting --> Connected : handshake_success -Connecting --> Disconnected : handshake_failed -Connected --> Negotiating : exchange_hello() -Negotiating --> Operating : negotiation_complete -Negotiating --> Rejected : negotiation_failed -Rejected --> Disconnected : close_connection() -Operating --> Syncing : start_sync() -Syncing --> Operating : sync_complete -Operating --> Closing : close_requested -Closing --> Disconnected : connection_closed -state Operating { -[*] --> NormalOperation -NormalOperation --> Broadcasting : broadcast_message -Broadcasting --> NormalOperation : broadcast_complete -NormalOperation --> Fetching : fetch_item -Fetching --> NormalOperation : item_fetched -} -``` - -**Diagram sources** -- [peer_connection.hpp:82-106](file://libraries/network/include/graphene/network/peer_connection.hpp#L82-L106) - -### Blockchain Synchronization Protocol - -The synchronization protocol efficiently handles blockchain state reconciliation with enhanced gap detection: - -```mermaid -sequenceDiagram -participant Local as Local Node -participant Remote as Remote Peer -participant Chain as Local Chain -Remote->>Local : hello_message -Local->>Remote : connection_accepted_message -Remote->>Local : fetch_blockchain_item_ids_message -Local->>Chain : get_blockchain_synopsis(reference_point, num_blocks) -Chain-->>Local : blockchain synopsis -Local->>Remote : blockchain_item_ids_inventory_message -Remote->>Local : fetch_items_message -Local->>Chain : get_item(item_id) -Chain-->>Local : item data -Note over Local,Chain : Enhanced DLT Mode with Gap Detection -Chain->>Local : earliest_available_block_num() -Local->>Remote : item_message (only available blocks) -Note over Local,Remote : Enhanced peer ahead-of-us detection -Local->>Remote : Empty response for peers ahead of us -Note over Local,Remote : Continue until synchronized with gap awareness -``` - -**Diagram sources** -- [core_messages.hpp:188-218](file://libraries/network/include/graphene/network/core_messages.hpp#L188-L218) -- [p2p_plugin.cpp:247-301](file://plugins/p2p/p2p_plugin.cpp#L247-L301) - -**Section sources** -- [p2p_plugin.cpp:129-208](file://plugins/p2p/p2p_plugin.cpp#L129-L208) -- [p2p_plugin.cpp:247-301](file://plugins/p2p/p2p_plugin.cpp#L247-L301) -- [peer_connection.hpp:79-354](file://libraries/network/include/graphene/network/peer_connection.hpp#L79-L354) - -## Enhanced Peer Information Logging - -**New** The P2P plugin now includes comprehensive peer information logging with detailed metrics for enhanced monitoring and troubleshooting capabilities. - -### Comprehensive Peer Metrics Collection - -The enhanced peer statistics system collects extensive information from connected peers: - -```mermaid -flowchart TD -PeerStats[Peer Statistics Collection] --> BasicInfo[Basic Connection Info] -BasicInfo --> IPInfo[IP Address and Port] -BasicInfo --> Direction[Connection Direction] -BasicInfo --> Latency[Latency Measurement] -BasicInfo --> Bytes[Bytes Sent/Received] -PeerStats --> ExtendedInfo[Extended Peer Info] -ExtendedInfo --> UA[User Agent String] -ExtendedInfo --> FW[Firewall Status] -ExtendedInfo --> HeadBlock[Head Block Info] -ExtendedInfo --> Timestamps[Timestamps] -PeerStats --> StatusInfo[Status Information] -StatusInfo --> Blocked[Blocked Status] -StatusInfo --> Reason[Block Reason] -StatusInfo --> ConnTime[Connection Time] -StatusInfo --> LastActivity[Last Activity Times] -PeerStats --> DLTInfo[DLT Mode Information] -DLTInfo --> DLTMode[DLT Mode Status] -DLTInfo --> DLTRev[DLT Revision Info] -DLTInfo --> EarliestAvail[Earliest Available Block] -``` - -**Diagram sources** -- [p2p_plugin.cpp:653-770](file://plugins/p2p/p2p_plugin.cpp#L653-L770) - -### Enhanced Peer Database Cross-Referencing - -The plugin provides comprehensive peer database logging with cross-referencing capabilities: - -```mermaid -flowchart TD -PeerDBDump[Peer Database Dump] --> PotentialPeers[Collect Potential Peers] -PotentialPeers --> FilterFailed[Filter Failed/Rejected Peers] -FilterFailed --> ExtractInfo[Extract Peer Info] -ExtractInfo --> Status[Extract Status] -ExtractInfo --> Attempts[Extract Attempt Counts] -ExtractInfo --> Error[Extract Error Info] -PeerDBDump --> CrossRef[Cross-Reference with Connected Peers] -CrossRef --> CheckConnected[Check Current Connection Status] -CheckConnected --> MarkConnected[Mark as Currently Connected] -CrossRef --> MarkDisconnected[Mark as Disconnected] -PeerDBDump --> LogResults[Log Results with Color Coding] -LogResults --> Cyan[Cyan for Peer Info] -LogResults --> Orange[Orange for Failed Peers] -LogResults --> Gray[Gray for Peer Database Info] -``` - -**Diagram sources** -- [p2p_plugin.cpp:773-813](file://plugins/p2p/p2p_plugin.cpp#L773-L813) - -### Detailed Peer Information Logging - -The enhanced peer logging system provides comprehensive information for each connected peer: - -```mermaid -sequenceDiagram -participant Logger as Logger -participant P2P as P2P Plugin -participant Peer as Peer Connection -Logger->>P2P : Collect peer info -P2P->>Peer : Extract connection metrics -Peer-->>P2P : Return metrics -P2P->>P2P : Format peer information -P2P->>Logger : Log peer stats with color coding -Note over P2P,Logger : Colored output :
- Cyan : Peer statistics
- Gray : Peer database info
- White : Transaction notifications -``` - -**Diagram sources** -- [p2p_plugin.cpp:760-768](file://plugins/p2p/p2p_plugin.cpp#L760-L768) - -### Peer Database Analytics - -The plugin provides detailed analytics on peer database entries with enhanced visibility: - -```mermaid -flowchart TD -PeerDBAnalytics[Peer Database Analytics] --> FailedCount[Failed Peer Count] -FailedCount --> StatusDist[Status Distribution] -StatusDist --> ErrorAnalysis[Error Pattern Analysis] -ErrorAnalysis --> RecoveryEffectiveness[Recovery Effectiveness] -PeerDBAnalytics --> CrossRefAnalysis[Cross-Reference Analysis] -CrossRefAnalysis --> ConnectedVsFailed[Connected vs Failed Analysis] -CrossRefAnalysis --> StatusTrends[Status Trends] -PeerDBAnalytics --> GapImpact[Gap Detection Impact] -GapImpact --> PeerSelection[Peer Selection Impact] -GapImpact --> RecoveryStrategies[Recovery Strategy Effectiveness] -``` - -**Diagram sources** -- [p2p_plugin.cpp:773-813](file://plugins/p2p/p2p_plugin.cpp#L773-L813) - -**Section sources** -- [p2p_plugin.cpp:653-770](file://plugins/p2p/p2p_plugin.cpp#L653-L770) -- [p2p_plugin.cpp:773-813](file://plugins/p2p/p2p_plugin.cpp#L773-L813) - -## Comprehensive Gap Detection System - -**New** The P2P plugin now includes a comprehensive gap detection system that monitors storage boundaries and provides automatic recovery mechanisms to prevent peer disconnections due to unavailable blocks. - -### Multi-Layer Gap Detection Architecture - -The enhanced gap detection system implements multiple layers of monitoring: - -```mermaid -flowchart TD -GapDetection[Gap Detection System] --> DLTMode{DLT Mode Active?} -DLTMode --> |No| NormalProcessing[Normal Processing] -DLTMode --> |Yes| DLTGapDetection[DLT Gap Detection] -DLTGapDetection --> StartBoundary[Check Start Boundary] -StartBoundary --> EarliestCheck{start_num < earliest?} -EarliestCheck --> |Yes| ClampEarliest[Clamp to Earliest] -EarliestCheck --> |No| StorageBoundary[Check Storage Boundary] -StorageBoundary --> StorageEnd[Calculate Storage End] -StorageEnd --> BeyondStorage{start_num > storage_end?} -BeyondStorage --> |Yes| ForkDBCheck[Check Fork DB] -BeyondStorage --> |No| ForkDBGap[Check Fork DB Gap] -ForkDBCheck --> ForkDBAvailable{Fork DB Available?} -ForkDBAvailable --> |Yes| UseForkDB[Use Fork DB Block] -ForkDBAvailable --> |No| GapDetected[Gap Detected] -ForkDBGap --> GapExists{Gap Exists?} -GapExists --> |Yes| ClampForkDB[Clamp to Fork DB] -GapExists --> |No| ContiguityCheck[Check Contiguity] -ClampEarliest --> LogClamp[Log Clamping] -ClampForkDB --> LogGap[Log Gap] -UseForkDB --> LogForkDB[Log Fork DB Usage] -GapDetected --> LogGap -LogClamp --> BuildRange[Build Range] -LogGap --> BuildRange -LogForkDB --> BuildRange -NormalProcessing --> End([End]) -BuildRange --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -### Automatic Peer Soft-Banning System - -**New** The plugin implements an automatic peer soft-banning system that responds to gap-related errors and sync spam: - -```mermaid -flowchart TD -PeerSoftBan[Peer Soft-Ban System] --> ErrorDetection[Error Detection] -ErrorDetection --> GapError{Gap Related Error?} -GapError --> |Yes| IncreasePenalty[Increase Penalty] -GapError --> |No| OtherError{Other Error Type?} -OtherError --> |Sync Spam| IncreasePenalty -OtherError --> |Linkable Block| ModeratePenalty -OtherError --> |Other| MaintainPenalty -IncreasePenalty --> CheckThreshold{Penalty Threshold?} -CheckThreshold --> |Exceeded| RemovePeer[Remove Peer] -CheckThreshold --> |Not Exceeded| Continue[Continue] -ModeratePenalty --> CheckTrusted{Trusted Peer?} -CheckTrusted --> |Yes| ReducedBan[Reduced Ban Duration] -CheckTrusted --> |No| Continue -RemovePeer --> FindAlternative[Find Alternative Peer] -ReducedBan --> FindAlternative -Continue --> End([End]) -FindAlternative --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -### Gap Detection Logging and Reporting - -The gap detection system provides comprehensive logging for troubleshooting: - -```mermaid -flowchart TD -GapLogging[Gap Detection Logging] --> GapTypes[Gap Type Classification] -GapTypes --> BelowEarliest[Below Earliest] -GapTypes --> BeyondStorage[Beyond Storage] -GapTypes --> ForkDBGap[Fork DB Gap] -GapTypes --> MissingBlock[Missing Block] -GapLogging --> ContextInfo[Context Information] -ContextInfo --> BlockNumbers[Block Numbers] -ContextInfo --> StorageBoundaries[Storage Boundaries] -ContextInfo --> ErrorContext[Error Context] -GapLogging --> RecoveryActions[Recovery Actions] -RecoveryActions --> RangeClamping[Range Clamping] -RecoveryActions --> PeerSwitching[Peer Switching] -RecoveryActions --> ParameterAdjustment[Parameter Adjustment] -GapLogging --> ImpactAssessment[Impact Assessment] -ImpactAssessment --> PeerDisconnectionRisk[Peer Disconnection Risk] -ImpactAssessment --> SyncDelay[Sync Delay] -ImpactAssessment --> DataAvailability[Data Availability] -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -**Section sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -## Enhanced DLT Mode Block Range Management - -**New** The P2P plugin now includes enhanced DLT (Data Ledger Technology) mode block range management that provides intelligent block serving capabilities for snapshot-based nodes with sophisticated gap detection and automatic recovery mechanisms. - -### Sophisticated Clamping Logic in get_block_ids() - -The `get_block_ids()` method has been enhanced with sophisticated clamping logic to prevent advertising blocks not available in node storage: - -```mermaid -flowchart TD -Start([get_block_ids Called]) --> CheckSynopsis{"Empty synopsis?"} -CheckSynopsis --> |Yes| UseZero["Use block 000000000"] -CheckSynopsis --> |No| IterateSyn["Iterate synopsis reverse"] -IterateSyn --> CheckKnown{"Known block AND included?"} -CheckKnown --> |Yes| FoundBlock["Set last_known_block_id"] -CheckKnown --> |No| ContinueLoop["Continue iteration"] -ContinueLoop --> CheckKnown -FoundBlock --> CalcStart["Calculate start_num from last_known_block_id"] -CalcStart --> CheckDLT{"In DLT mode?"} -CheckDLT --> |No| BuildRange["Build block range normally"] -CheckDLT --> |Yes| ClampStart["Clamp start to earliest_available_block_num"] -ClampStart --> LogClamp["Log DLT mode clamp operation
in gray ANSI color"] -ClampStart --> CheckStorageGaps["Check for storage gaps"] -CheckStorageGaps --> |Gap Detected| ClampEnd["Clamp end to storage boundary"] -CheckStorageGaps --> |No Gap| CheckUpperBound["Check upper bound gaps"] -CheckUpperBound --> |Gap Detected| ClampEnd -CheckUpperBound --> |No Gap| BuildRange -ClampEnd --> LogGap["Log gap detection and clamping
in gray ANSI color"] -LogGap --> BuildRange -BuildRange --> CheckLimit["Check block limit"] -CheckLimit --> |Exceeded| ReturnResult["Return partial result"] -CheckLimit --> |Within limit| ContinueBuild["Continue building range"] -ContinueBuild --> ReturnResult -ReturnResult --> End([End]) -LogClamp --> BuildRange -LogGap --> BuildRange -``` - -**Diagram sources** -- [p2p_plugin.cpp:290-364](file://plugins/p2p/p2p_plugin.cpp#L290-L364) - -### Enhanced Gap Detection and Recovery - -The plugin now includes comprehensive gap detection and automatic recovery mechanisms: - -```mermaid -flowchart TD -Start([Block Range Request]) --> CheckDLT{"DLT Mode Active?"} -CheckDLT --> |No| NormalRange["Build normal block range"] -CheckDLT --> |Yes| CheckStartGap["Check start_num vs earliest_available"] -CheckStartGap --> |Below Earliest| ClampToEarliest["Clamp start to earliest_available"] -CheckStartGap --> |Within Range| CheckStorageBoundary["Check storage boundaries"] -CheckStorageBoundary --> |Gap Found| ClampToBoundary["Clamp to storage boundary"] -CheckStorageBoundary --> |No Gap| CheckForkDBGap["Check fork_db gap"] -CheckForkDBGap --> |Gap Found| ClampToForkDB["Clamp to fork_db boundary"] -CheckForkDBGap --> |No Gap| BuildRange -ClampToEarliest --> LogClamp["Log clamping action
in gray ANSI color"] -ClampToBoundary --> LogGap["Log gap detection
in gray ANSI color"] -ClampToForkDB --> LogGap -LogClamp --> BuildRange -LogGap --> BuildRange -BuildRange --> CheckLimit["Check against block limit"] -CheckLimit --> |Exceeded| ReturnPartial["Return partial range"] -CheckLimit --> |Within Limit| ReturnFull["Return full range"] -ReturnPartial --> End([End]) -ReturnFull --> End -NormalRange --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -### Enhanced get_item() Method with Gap Awareness - -The `get_item()` method now provides comprehensive DLT mode error handling with gap detection: - -```mermaid -flowchart TD -Start([get_item Called]) --> CheckItemType{"Item type == block?"} -CheckItemType --> |No| FetchTx["Fetch transaction from chain"] -CheckItemType --> |Yes| CheckDLT{"In DLT mode?"} -CheckDLT --> |No| FetchBlock["Fetch block normally"] -CheckDLT --> |Yes| CheckAvailability["Check block availability"] -CheckAvailability --> |Available| FetchBlock -CheckAvailability --> |Not Available| CheckGap["Check if in DLT gap"] -CheckGap --> |In Gap| LogGapError["Log DLT gap error:
- Block number
- Available range
- DLT log bounds
in gray ANSI color"] -CheckGap --> |Not In Gap| LogMissingError["Log missing block error:
- Block not found anywhere
in gray ANSI color"] -LogGapError --> ThrowGapException["Throw key_not_found_exception"] -LogMissingError --> ThrowMissingException["Throw key_not_found_exception"] -FetchTx --> End([End]) -FetchBlock --> ReturnBlock["Return block_message"] -ReturnBlock --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) - -### Enhanced Peer Ahead-of-Us Detection - -**New** The plugin now includes sophisticated peer ahead-of-us detection mechanism that identifies peers who are ahead of the local node in DLT mode: - -```mermaid -flowchart TD -Start([Peer Synopsis Analysis]) --> CheckDLT{"DLT Mode Active?"} -CheckDLT --> |No| NormalForkCheck["Normal fork detection"] -CheckDLT --> |Yes| CheckAllAboveHead["Check if all synopsis entries > head"] -CheckAllAboveHead --> |All Above| LogAhead["Log peer ahead detection:
- All entries above head
- Peer is ahead, not on fork
in orange ANSI color"] -CheckAllAboveHead --> |Mixed| NormalForkCheck -LogAhead --> ReturnEmpty["Return empty block list"] -NormalForkCheck --> End([End]) -ReturnEmpty --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:307-327](file://plugins/p2p/p2p_plugin.cpp#L307-L327) - -### Startup Block Storage Diagnostics - -**New** The plugin provides comprehensive startup diagnostics that run before synchronization begins: - -```mermaid -flowchart TD -Start([Plugin Startup]) --> LogStart["Log startup diagnostics begin"] -LogStart --> GatherInfo["Gather storage information:
- Head block
- LIB
- Earliest available
- DLT log range
- Block log end
- Fork DB stats"] -GatherInfo --> CheckGaps["Check for gaps:
- DLT coverage gaps
- Integrity issues"] -CheckGaps --> |Gaps Found| LogGaps["Log gaps:
- Gap locations
- Missing blocks
in orange ANSI color"] -CheckGaps --> |No Gaps| LogOK["Log integrity OK"] -LogGaps --> LogEnd["Log startup diagnostics complete"] -LogOK --> LogEnd -LogEnd --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:1042-1113](file://plugins/p2p/p2p_plugin.cpp#L1042-L1113) - -### Windows Compatibility Enhancements - -**New** The plugin includes Windows compatibility enhancements for DLT block log operations: - -```mermaid -flowchart TD -Start([DLT Block Log Operation]) --> CheckPlatform{"Windows Platform?"} -CheckPlatform --> |No| NormalOperation["Normal operation"] -CheckPlatform --> |Yes| CheckMapping["Check mapping consistency"] -CheckMapping --> |Stale Mapping| HealMapping["Heal stale mapping:
- Close and reopen files
- Sync logical sizes
- Track resize count"] -CheckMapping --> |Valid Mapping| NormalOperation -HealMapping --> LogHeal["Log healing action:
- Stale mapping detected
- Healing performed
in gray ANSI color"] -LogHeal --> NormalOperation -NormalOperation --> End([End]) -``` - -**Diagram sources** -- [dlt_block_log.cpp:545-574](file://libraries/chain/dlt_block_log.cpp#L545-L574) - -### DLT Mode Integration Points - -The enhanced DLT mode integration affects multiple plugin methods with sophisticated gap detection: - -1. **Block ID Generation**: `get_block_ids()` clamps starting block numbers to available DLT range and detects storage gaps -2. **Item Serving**: `get_item()` provides detailed logging for unavailable DLT blocks and gap detection -3. **Synopsis Generation**: `get_blockchain_synopsis()` includes DLT availability context with gap awareness -4. **Earliest Block Calculation**: Database provides `earliest_available_block_num()` for DLT mode with gap detection -5. **Storage Boundary Detection**: Enhanced logic to detect gaps between dlt_block_log and fork_db -6. **Peer Ahead Detection**: Sophisticated detection of peers ahead of the local node in DLT mode -7. **Startup Diagnostics**: Comprehensive diagnostics system that runs before sync begins -8. **Windows Compatibility**: Enhanced compatibility with Windows operating systems for DLT operations - -### Database Integration - -The database provides DLT-specific functionality with gap detection: - -```mermaid -classDiagram -class database { -+bool _dlt_mode -+dlt_block_log _dlt_block_log -+uint32_t earliest_available_block_num() -+void set_dlt_mode(enabled) -+const dlt_block_log& get_dlt_block_log() -+uint32_t head_block_num() -+uint32_t last_non_undoable_block_num() -+optional fetch_block_by_number(num) -} -class dlt_block_log { -+uint32_t start_block_num() -+uint32_t head_block_num() -+uint32_t num_blocks() -+optional read_block_by_num(block_num) -+bool verify_mapping() -+std : : vector verify_continuity() -+uint64_t resize_count() -} -database --> dlt_block_log : "contains" -``` - -**Diagram sources** -- [database.hpp:57-78](file://libraries/chain/include/graphene/chain/database.hpp#L57-L78) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) - -**Section sources** -- [p2p_plugin.cpp:290-405](file://plugins/p2p/p2p_plugin.cpp#L290-L405) -- [p2p_plugin.cpp:307-327](file://plugins/p2p/p2p_plugin.cpp#L307-L327) -- [p2p_plugin.cpp:1042-1113](file://plugins/p2p/p2p_plugin.cpp#L1042-L1113) -- [database.hpp:57-78](file://libraries/chain/include/graphene/chain/database.hpp#L57-L78) -- [dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) - -## Improved Gap Detection and Recovery - -**New** The P2P plugin now includes sophisticated gap detection and automatic recovery mechanisms that prevent peer disconnections due to item_not_available responses. - -### Comprehensive Gap Detection Logic - -The enhanced gap detection system monitors multiple storage boundaries: - -```mermaid -flowchart TD -Start([Gap Detection]) --> CheckDLTMode{"DLT Mode Active?"} -CheckDLTMode --> |No| NormalProcessing["Normal processing"] -CheckDLTMode --> |Yes| CheckStartBoundary["Check start_num boundary"] -CheckStartBoundary --> GetEarliest["Get earliest_available_block_num()"] -GetEarliest --> CheckBelowEarliest{"start_num < earliest?"} -CheckBelowEarliest --> |Yes| ClampToEarliest["Clamp start to earliest"] -CheckBelowEarliest --> |No| CheckStorageBoundary["Check storage boundary"] -CheckStorageBoundary --> GetDLTEnd["Get dlt_block_log.head_block_num()"] -GetDLTEnd --> GetBlogEnd["Get block_log.head_block_num()"] -GetBlogEnd --> GetStorageEnd["storage_end = max(dlt_end, blog_end)"] -GetStorageEnd --> CheckBeyondStorage{"start_num > storage_end?"} -CheckBeyondStorage --> |Yes| CheckForkDB["Check fork_db availability"] -CheckBeyondStorage --> |No| CheckForkDBGap["Check fork_db gap"] -CheckForkDB --> |Available| UseForkDB["Use fork_db block"] -CheckForkDB --> |Not Available| LogGap["Log gap detected
in gray ANSI color"] -CheckForkDBGap --> |Gap Exists| ClampToForkDB["Clamp to fork_db boundary"] -CheckForkDBGap --> |No Gap| CheckContiguous["Check contiguity"] -ClampToEarliest --> LogClamp["Log clamping action
in gray ANSI color"] -ClampToForkDB --> LogGap -UseForkDB --> LogForkDB["Log fork_db usage
in gray ANSI color"] -LogClamp --> BuildRange["Build clamped range"] -LogGap --> BuildRange -LogForkDB --> BuildRange -BuildRange --> CheckLimit["Check against block limit"] -CheckLimit --> |Exceeded| ReturnPartial["Return partial range"] -CheckLimit --> |Within Limit| ReturnFull["Return full range"] -ReturnPartial --> End([End]) -ReturnFull --> End -NormalProcessing --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -### Automatic Recovery Mechanisms - -The plugin implements automatic recovery from gap-related synchronization issues: - -```mermaid -flowchart TD -Start([Gap Recovery Triggered]) --> DetectGap["Detect gap in block range"] -DetectGap --> LogGapInfo["Log gap information:
- Gap start/end
- Available ranges
- Storage boundaries
in gray ANSI color"] -LogGapInfo --> CheckPeerResponse["Check peer response type"] -CheckPeerResponse --> |item_not_available| LogPeerIssue["Log peer disconnection issue
in gray ANSI color"] -CheckPeerResponse --> |other_error| LogOtherError["Log other error
in gray ANSI color"] -LogPeerIssue --> SoftBanPeer["Soft-ban peer appropriately"] -LogOtherError --> SoftBanPeer -SoftBanPeer --> CheckRecoveryOptions["Check recovery options:
- Alternative peers
- Different sync strategy"] -CheckRecoveryOptions --> SwitchPeer["Switch to alternative peer"] -CheckRecoveryOptions --> AdjustSync["Adjust sync parameters"] -CheckRecoveryOptions --> WaitAndRetry["Wait and retry later"] -SwitchPeer --> ContinueSync["Continue synchronization"] -AdjustSync --> ContinueSync -WaitAndRetry --> ContinueSync -ContinueSync --> End([Recovery Complete]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) - -### Enhanced Error Handling and Logging - -The gap detection system provides comprehensive logging for troubleshooting: - -```mermaid -flowchart TD -Start([Gap Error]) --> ClassifyError["Classify gap type:
- Below earliest
- Beyond storage
- Fork_db gap
- Missing block"] -ClassifyError --> LogDetailedInfo["Log detailed gap info:
- Block numbers
- Available ranges
- Storage locations
- Error context
in gray ANSI color"] -LogDetailedInfo --> DetermineImpact["Determine impact:
- Peer disconnection risk
- Sync delay
- Data availability"] -DetermineImpact --> ApplyRecovery["Apply recovery:
- Range clamping
- Peer switching
- Parameter adjustment"] -ApplyRecovery --> LogRecovery["Log recovery actions:
- Actions taken
- Results
- Next steps
in gray ANSI color"] -LogRecovery --> ContinueSync["Continue sync process"] -ContinueSync --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -**Section sources** -- [p2p_plugin.cpp:295-405](file://plugins/p2p/p2p_plugin.cpp#L295-L405) - -## Sophisticated Clamping Logic - -**New** The P2P plugin now includes sophisticated clamping logic in the get_block_ids() method to prevent advertising blocks that aren't available in node storage, avoiding peer disconnections due to item_not_available responses. - -### Advanced Clamping Algorithm - -The enhanced clamping logic implements multiple layers of block availability validation: - -```mermaid -flowchart TD -Start([Block Range Request]) --> GetStartNum["Get calculated start_num"] -GetStartNum --> CheckDLTMode{"DLT Mode Active?"} -CheckDLTMode --> |No| BuildNormalRange["Build normal range"] -CheckDLTMode --> |Yes| CheckEarliest["Check against earliest_available"] -CheckEarliest --> GetEarliest["Get earliest_available_block_num()"] -GetEarliest --> CompareEarliest{"start_num < earliest?"} -CompareEarliest --> |Yes| ClampToEarliest["Clamp start_num = earliest"] -CompareEarliest --> |No| CheckStorageBoundary["Check storage boundary"] -CheckStorageBoundary --> GetStorageEnd["Get storage_end = max(dlt_end, blog_end)"] -GetStorageEnd --> CompareStorage{"start_num > storage_end?"} -CompareStorage --> |Yes| CheckForkDB["Check fork_db availability"] -CompareStorage --> |No| CheckForkDBGap["Check fork_db gap"] -CheckForkDB --> |Available| UseForkDB["Use fork_db block"] -CheckForkDB --> |Not Available| CheckForkDBGap -CheckForkDBGap --> |Gap Exists| ClampToForkDB["Clamp to fork_db boundary"] -CheckForkDBGap --> |No Gap| CheckContiguous["Check contiguity"] -ClampToEarliest --> LogClamp["Log clamping to earliest
in gray ANSI color"] -ClampToForkDB --> LogClamp -UseForkDB --> LogForkDB["Log fork_db usage
in gray ANSI color"] -LogClamp --> BuildClampedRange["Build clamped range"] -LogForkDB --> BuildClampedRange -CheckContiguous --> CheckGap["Check for gap between storage_end+1 and fork_db"] -CheckGap --> |Gap| ClampToStorageEnd["Clamp to storage_end"] -CheckGap --> |No Gap| BuildClampedRange -ClampToStorageEnd --> LogGap["Log gap detection
in gray ANSI color"] -LogGap --> BuildClampedRange -BuildNormalRange --> End([End]) -BuildClampedRange --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -### Storage Boundary Detection - -The clamping logic includes sophisticated storage boundary detection: - -```mermaid -flowchart TD -Start([Storage Boundary Check]) --> GetDLTInfo["Get DLT block log info:
- start_block_num()
- head_block_num()"] -GetDLTInfo --> GetBlogInfo["Get block log info:
- head_block_num()"] -GetBlogInfo --> CalcStorageEnd["Calculate storage_end:
storage_end = max(dlt_end, blog_end)"] -CalcStorageEnd --> CheckStartBeyond["Check: start_num > storage_end"] -CheckStartBeyond --> |Yes| CheckForkDBRange["Check fork_db range:
fetch_block_by_number(storage_end+1)"] -CheckStartBeyond --> |No| CheckForkDBGap["Check fork_db gap:
between storage_end and fork_db"] -CheckForkDBRange --> |Block Found| UseForkDB["Use fork_db block"] -CheckForkDBRange --> |No Block| LogNoBlock["Log no block found
in gray ANSI color"] -CheckForkDBGap --> |Gap Exists| ClampToStorage["Clamp to storage_end"] -CheckForkDBGap --> |No Gap| CheckContiguity["Check contiguity"] -UseForkDB --> LogForkDB["Log fork_db usage
in gray ANSI color"] -LogNoBlock --> LogError["Log error: block not found
in gray ANSI color"] -ClampToStorage --> LogClamp["Log clamping to storage boundary
in gray ANSI color"] -LogForkDB --> BuildRange["Build range up to boundary"] -LogError --> BuildEmpty["Build empty range"] -LogClamp --> BuildRange -CheckContiguity --> BuildRange -BuildEmpty --> End([End]) -BuildRange --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:308-340](file://plugins/p2p/p2p_plugin.cpp#L308-L340) - -### Enhanced Logging for Clamping Operations - -The clamping logic provides comprehensive logging for troubleshooting and monitoring: - -```mermaid -flowchart TD -Start([Clamping Operation]) --> LogClampStart["Log clamping start:
- Original start_num
- Reason for clamping
in gray ANSI color"] -LogClampStart --> PerformClamp["Perform clamping:
- Clamp to earliest
- Clamp to storage_end
- Clamp to fork_db"] -PerformClamp --> LogClampResult["Log clamping result:
- New start_num
- Effective head
- Range size
in gray ANSI color"] -LogClampResult --> LogContext["Log context:
- DLT mode active
- Earliest available
- Storage boundaries
in gray ANSI color"] -LogContext --> LogDecision["Log decision:
- Why clamping was needed
- Impact on sync
- Peer compatibility
in gray ANSI color"] -LogDecision --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:298-302](file://plugins/p2p/p2p_plugin.cpp#L298-L302) -- [p2p_plugin.cpp:335-338](file://plugins/p2p/p2p_plugin.cpp#L335-L338) - -**Section sources** -- [p2p_plugin.cpp:295-340](file://plugins/p2p/p2p_plugin.cpp#L295-L340) - -## Enhanced Peer Interaction Handling - -**New** The P2P plugin now includes enhanced peer interaction handling with improved error management, graceful degradation capabilities, and sophisticated gap-aware block serving to avoid item_not_available responses. - -### Comprehensive Peer Database Logging - -The plugin provides detailed peer database logging for troubleshooting with gap detection awareness: - -```mermaid -flowchart TD -Start([Peer Stats Task]) --> CheckPeers{"Any connected peers?"} -CheckPeers --> |No| LogNoPeers["Log 'no connected peers'
in cyan ANSI color"] -CheckPeers --> |Yes| IteratePeers["Iterate connected peers"] -IteratePeers --> ExtractInfo["Extract peer info:
- IP/port
- Latency
- Bytes received
- Blocked status"] -ExtractInfo --> LogPeer["Log individual peer stats
in cyan ANSI color"] -LogPeer --> CheckPotential["Check potential peers"] -CheckPotential --> IteratePotential["Iterate potential peers"] -IteratePotential --> CheckStatus{"Failed/rejected status?"} -CheckStatus --> |No| NextPeer["Next potential peer"] -CheckStatus --> |Yes| LogPotential["Log failed/rejected peer:
- Endpoint
- Last attempt time
- Failed attempts
- Error details
- Gap-related errors
in cyan ANSI color"] -LogPotential --> NextPeer -NextPeer --> CheckMore{"More potential peers?"} -CheckMore --> |Yes| IteratePotential -CheckMore --> |No| LogSummary["Log summary of failed peers
including gap detection results
in cyan ANSI color"] -LogSummary --> End([End]) -LogNoPeers --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -### Graceful Degradation on Peer Failure with Gap Awareness - -The plugin implements graceful degradation when peers cannot serve requested items with sophisticated gap detection: - -```mermaid -flowchart TD -Start([Peer Request Failed]) --> CheckError{"Error type?"} -CheckError --> |DLT Mode Error| CheckGapError["Check if gap-related error:
- item_not_available
- block not in dlt_block_log
- missing from storage"] -CheckGapError --> |Gap Error| LogDLTError["Log DLT availability error:
- Block number
- Available range
- DLT log bounds
- Gap detection results
in gray ANSI color"] -CheckGapError --> |Other Error| LogGenericError["Log generic error:
- Error details
- Peer endpoint
- Error context
in gray ANSI color"] -CheckError --> |Other Error Type| LogOtherError["Log other error type:
- Error classification
- Peer status
- Recovery actions
in gray ANSI color"] -LogDLTError --> CheckRecovery{"Check recovery options:
- Peer switching
- Range adjustment
- Wait and retry"} -LogGenericError --> CheckRecovery -LogOtherError --> CheckRecovery -CheckRecovery --> |Peer Switching| SwitchPeer["Switch to alternative peer"] -CheckRecovery --> |Range Adjustment| AdjustRange["Adjust block range
with gap detection"] -CheckRecovery --> |Wait and Retry| WaitRetry["Wait and retry later"] -SwitchPeer --> ResetTimer["Reset stale sync timer"] -AdjustRange --> ResetTimer -WaitRetry --> ResetTimer -ResetTimer --> ContinueSync["Continue synchronization"] -ContinueSync --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) - -### Enhanced Stale Sync Detection with Gap Awareness - -The stale sync detection has been enhanced with better peer interaction and gap detection: - -```mermaid -sequenceDiagram -participant Timer as Stale Sync Timer -participant Node as Network Node -participant Chain as Chain Database -participant Peers as Connected Peers -Timer->>Node : Check last_block_received_time -Node->>Chain : Get head_block_num and LIB -Chain-->>Node : Return chain state -Node->>Node : Compare elapsed time with timeout -alt Stale sync detected -Node->>Node : sync_from(LIB, []) -Node->>Node : resync() -Node->>Node : add_node(seed) for each seed -Node->>Node : connect_to_endpoint(seed) for each seed -Note over Node : Enhanced with gap detection -Node->>Chain : Check DLT gaps during recovery -Chain-->>Node : Return gap information -Node->>Node : Adjust sync parameters based on gaps -Node->>Timer : Reset _last_block_received_time -end -``` - -**Diagram sources** -- [p2p_plugin.cpp:701-765](file://plugins/p2p/p2p_plugin.cpp#L701-L765) - -**Section sources** -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) -- [p2p_plugin.cpp:701-765](file://plugins/p2p/p2p_plugin.cpp#L701-L765) - -## Comprehensive Logging Throughout Sync Process - -**New** The P2P plugin now includes comprehensive logging throughout the sync process, providing detailed visibility into DLT mode operations, gap detection, and peer interactions with sophisticated gap-aware logging. - -### DLT Mode Logging Enhancements with Gap Detection - -The plugin provides detailed logging for DLT mode operations with gap detection awareness: - -```mermaid -flowchart TD -Start([DLT Mode Operation]) --> LogClamp["Log DLT clamp:
- Old start number
- New start number
- Earliest available
- Head block
- Gap detection results
in gray ANSI color"] -LogClamp --> LogIDs["Log get_block_ids result:
- Number of IDs
- Start block
- Head block
- Earliest available
- Gap information
in gray ANSI color"] -LogIDs --> LogSynopsis["Log get_blockchain_synopsis:
- Entry count
- Low/high blocks
- Head/LIB
- Earliest available
- Gap boundaries
in gray ANSI color"] -LogSynopsis --> LogAvailability["Log DLT availability:
- Block number
- Available range
- DLT log bounds
- Storage boundaries
in gray ANSI color"] -LogAvailability --> LogGap["Log gap detection:
- Gap location
- Gap size
- Available alternatives
- Recovery actions
in gray ANSI color"] -LogGap --> LogAhead["Log peer ahead detection:
- All entries above head
- Peer is ahead
- Empty response
in orange ANSI color"] -LogAhead --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:298-302](file://plugins/p2p/p2p_plugin.cpp#L298-L302) -- [p2p_plugin.cpp:355-364](file://plugins/p2p/p2p_plugin.cpp#L355-L364) -- [p2p_plugin.cpp:520-528](file://plugins/p2p/p2p_plugin.cpp#L520-L528) -- [p2p_plugin.cpp:321-327](file://plugins/p2p/p2p_plugin.cpp#L321-L327) - -### Enhanced Block Processing Logs with Gap Awareness - -**Updated** The block processing logging has been enhanced with conditional latency reporting and improved visibility: - -```mermaid -flowchart TD -Start([Handle Block]) --> LogGap["Log block gap:
- Block number
- Head block
- Gap size
- Gap detection context
in gray ANSI color"] -LogGap --> CheckSyncMode{"Sync mode?"} -CheckSyncMode --> |Yes| LogSync["Log sync block:
- Block number
- Head
- Gap
- Clamping info
in gray ANSI color"] -CheckSyncMode --> |No| LogNormal["Log normal block:
- Block number
- Transactions
- validator
- Gap context
in gray ANSI color"] -LogSync --> AcceptBlock["Accept block via chain.accept_block()"] -LogNormal --> AcceptBlock -AcceptBlock --> CheckResult{"Result successful?"} -CheckResult --> |No| End([End]) -CheckResult --> |Yes| CheckSyncMode2{"Sync mode?"} -CheckSyncMode2 --> |Yes| End -CheckSyncMode2 --> |No| LogLatency["Log latency:
- Transaction count
- Block number
- validator
- Latency in milliseconds
in white ANSI color"] -LogLatency --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:151-208](file://plugins/p2p/p2p_plugin.cpp#L151-L208) - -### Peer Interaction Logging with Gap Detection - -The plugin provides comprehensive peer interaction logging with gap detection awareness: - -```mermaid -flowchart TD -Start([Peer Interaction]) --> LogPeerStats["Log peer stats:
- IP/port
- Latency
- Bytes received
- Blocked status
- Reason
- Gap-related interactions
in cyan ANSI color"] -LogPeerStats --> LogPotential["Log potential peers:
- Endpoint
- Status
- Last attempt
- Failed attempts
- Error
- Gap detection results
in cyan ANSI color"] -LogPotential --> LogFailed["Log failed peers:
- Count
- Total peers
- Status distribution
- Gap-related failures
in cyan ANSI color"] -LogFailed --> LogRecovery["Log recovery actions:
- Peer switching
- Range adjustments
- Gap handling
- Success rates
in gray ANSI color"] -LogRecovery --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -### Block Storage Diagnostics with Gap Detection - -**New** The plugin provides comprehensive block storage diagnostics with gap detection and coverage monitoring: - -```mermaid -flowchart TD -Start([Storage Diagnostics]) --> LogStorage["Log block storage:
- Head block
- LIB
- Earliest available
- DLT log range
- Block log end
- Fork DB stats
- DLT mode status
- DLT resize count
in cyan ANSI color"] -LogStorage --> CheckGap["Check for DLT coverage gap:
- DLT end vs Fork DB start
- Gap detection
- Availability impact
in orange ANSI color"] -CheckGap --> LogGapWarning["Log DLT coverage gap:
- Gap start/end
- Blocks unavailable
- Impact on serving
in orange ANSI color"] -LogGapWarning --> LogIntegrity["Log DLT integrity:
- Gap count
- Missing blocks
- Gap locations
in orange ANSI color"] -LogIntegrity --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:722-771](file://plugins/p2p/p2p_plugin.cpp#L722-L771) -- [p2p_plugin.cpp:783-791](file://plugins/p2p/p2p_plugin.cpp#L783-L791) -- [p2p_plugin.cpp:812-816](file://plugins/p2p/p2p_plugin.cpp#L812-L816) - -### DLT Integrity Verification with Continuity Scanning - -**New** The plugin implements comprehensive DLT integrity verification with periodic continuity scanning: - -```mermaid -flowchart TD -Start([DLT Integrity Scan]) --> CheckDLTMode{"DLT Mode Active?"} -CheckDLTMode --> |No| End([End]) -CheckDLTMode --> |Yes| VerifyMapping["Call verify_mapping()
- Detect stale mapping
- Heal if needed
in gray ANSI color"] -VerifyMapping --> CheckContinuity["Call verify_continuity()
- Walk all blocks
- Report gaps
- Log missing blocks
in gray ANSI color"] -CheckContinuity --> CheckGaps{"Any gaps found?"} -CheckGaps --> |No| End -CheckGaps --> |Yes| LogGaps["Log DLT integrity warning:
- Gap count
- Missing blocks
- Gap locations
in orange ANSI color"] -LogGaps --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:773-795](file://plugins/p2p/p2p_plugin.cpp#L773-L795) - -### Startup Block Storage Diagnostics - -**New** The plugin provides comprehensive startup diagnostics that run before synchronization begins: - -```mermaid -flowchart TD -Start([Startup Diagnostics]) --> LogStart["Log startup diagnostics begin
in cyan ANSI color"] -LogStart --> GatherInfo["Gather storage information:
- Head block
- LIB
- Earliest available
- DLT log range
- Block log end
- Fork DB stats
- DLT mode status
- DLT resize count
in cyan ANSI color"] -GatherInfo --> CheckStartupGaps["Check for startup gaps:
- DLT coverage gaps
- Integrity issues
- Gap locations
in orange ANSI color"] -CheckStartupGaps --> LogGaps["Log startup gaps:
- Gap start/end
- Missing blocks
- Impact on serving
in orange ANSI color"] -LogGaps --> LogIntegrity["Log integrity status:
- Gap count
- Missing blocks
- OK status
in cyan ANSI color"] -LogIntegrity --> LogEnd["Log startup diagnostics complete
in cyan ANSI color"] -LogEnd --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:1042-1113](file://plugins/p2p/p2p_plugin.cpp#L1042-L1113) - -**Section sources** -- [p2p_plugin.cpp:298-302](file://plugins/p2p/p2p_plugin.cpp#L298-L302) -- [p2p_plugin.cpp:355-364](file://plugins/p2p/p2p_plugin.cpp#L355-L364) -- [p2p_plugin.cpp:520-528](file://plugins/p2p/p2p_plugin.cpp#L520-L528) -- [p2p_plugin.cpp:151-208](file://plugins/p2p/p2p_plugin.cpp#L151-L208) -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) -- [p2p_plugin.cpp:722-771](file://plugins/p2p/p2p_plugin.cpp#L722-L771) -- [p2p_plugin.cpp:773-795](file://plugins/p2p/p2p_plugin.cpp#L773-L795) -- [p2p_plugin.cpp:1042-1113](file://plugins/p2p/p2p_plugin.cpp#L1042-L1113) - -## ANSI Color Code Implementation - -**New** The P2P plugin now includes comprehensive ANSI color code implementation for enhanced console readability and visual distinction between different types of log messages. - -### ANSI Color Code Definitions - -The plugin defines ANSI color codes for consistent color usage throughout the logging system: - -```mermaid -flowchart TD -ColorCodes["ANSI Color Code Definitions"] --> Gray["CLOG_GRAY
\\033[90m
Gray color for DLT mode debug messages"] -ColorCodes --> Cyan["CLOG_CYAN
\\033[96m
Cyan color for peer statistics and informational messages"] -ColorCodes --> White["CLOG_WHITE
\\033[97m
White color for important transaction notifications and latency information"] -ColorCodes --> Reset["CLOG_RESET
\\033[0m
Reset color to default"] -ColorCodes --> Orange["CLOG_ORANGE
\\033[33m
Orange color for network-related warnings and peer connection status"] -ColorCodes --> Red["CLOG_RED
\\033[91m
Red color for critical errors and severe warnings"] -Gray --> DLTLogging["DLT Mode Debug Logging
in gray color"] -Cyan --> PeerStats["Peer Statistics Logging
in cyan color"] -White --> TransactionLogs["Transaction Notifications and Latency
in white color"] -Orange --> NetworkWarnings["Network Warnings and Peer Status
in orange color"] -Red --> CriticalErrors["Critical Errors
in red color"] -``` - -**Diagram sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) - -### Color Code Usage Patterns - -The ANSI color codes are applied consistently across different logging scenarios: - -1. **DLT Mode Debug Messages**: Gray color for detailed DLT mode operations, gap detection, and block range management -2. **Peer Statistics**: Cyan color for peer connection statistics, connection status, and peer database information -3. **Transaction Notifications**: White color for important transaction-related information and block processing notifications -4. **Network Warnings**: Orange color for peer connection warnings, network issues, and peer status changes -5. **Critical Errors**: Red color for severe errors, critical failures, and system emergencies -6. **Error and Warning Messages**: Default color scheme for error conditions and warnings (unchanged) - -### Implementation Examples - -The color codes are integrated throughout the plugin implementation: - -```mermaid -sequenceDiagram -participant Logger as Logger -participant P2P as P2P Plugin -participant Console as Console Output -Logger->>P2P : Log message with color code -P2P->>Console : Output colored text
CLOG_GRAY + message + CLOG_RESET -Console-->>P2P : Colored output displayed -Note over P2P,Console : Consistent color coding
throughout all logging operations -``` - -**Diagram sources** -- [p2p_plugin.cpp:169-171](file://plugins/p2p/p2p_plugin.cpp#L169-L171) -- [p2p_plugin.cpp:299-301](file://plugins/p2p/p2p_plugin.cpp#L299-L301) -- [p2p_plugin.cpp:522-528](file://plugins/p2p/p2p_plugin.cpp#L522-L528) - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:169-171](file://plugins/p2p/p2p_plugin.cpp#L169-L171) -- [p2p_plugin.cpp:299-301](file://plugins/p2p/p2p_plugin.cpp#L299-L301) -- [p2p_plugin.cpp:522-528](file://plugins/p2p/p2p_plugin.cpp#L522-L528) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) - -## Enhanced DLT Mode Debug Logging - -**New** The P2P plugin now includes enhanced DLT (Data Ledger Technology) mode debug logging with comprehensive gap detection and block range management information displayed in gray ANSI color for improved troubleshooting capabilities. - -### Comprehensive DLT Mode Logging - -The enhanced DLT mode logging provides detailed information about block availability, gap detection, and synchronization operations: - -```mermaid -flowchart TD -DLTLogging["DLT Mode Debug Logging"] --> ClampStart["Clamp Start Logging
- Original start number
- New clamped start
- Earliest available block
- Head block information
in gray ANSI color"] -DLTLogging --> GapDetection["Gap Detection Logging
- Gap location identification
- Gap size calculation
- Storage boundary detection
- Fork database gap analysis
in gray ANSI color"] -DLTLogging --> BlockRange["Block Range Logging
- Number of blocks returned
- Start and end block numbers
- Effective head block
- Earliest available block
- DLT log end position
in gray ANSI color"] -DLTLogging --> Availability["Availability Logging
- Block number being served
- Available block range
- DLT log bounds
- Storage boundaries
in gray ANSI color"] -DLTLogging --> AheadDetection["Peer Ahead Detection Logging
- All synopsis entries above head
- Peer is ahead of us
- Empty response returned
in orange ANSI color"] -ClampStart --> DLTLogging -GapDetection --> DLTLogging -BlockRange --> DLTLogging -Availability --> DLTLogging -AheadDetection --> DLTLogging -``` - -**Diagram sources** -- [p2p_plugin.cpp:299-301](file://plugins/p2p/p2p_plugin.cpp#L299-L301) -- [p2p_plugin.cpp:321-327](file://plugins/p2p/p2p_plugin.cpp#L321-L327) -- [p2p_plugin.cpp:336-338](file://plugins/p2p/p2p_plugin.cpp#L336-L338) -- [p2p_plugin.cpp:357-364](file://plugins/p2p/p2p_plugin.cpp#L357-L364) -- [p2p_plugin.cpp:321-327](file://plugins/p2p/p2p_plugin.cpp#L321-L327) - -### DLT Mode Operation Logging - -The plugin provides comprehensive logging for all DLT mode operations: - -1. **get_block_ids() Operations**: Detailed logging of block ID generation with gap detection and clamping information -2. **get_blockchain_synopsis() Operations**: Logging of blockchain synopsis generation with DLT availability context -3. **get_item() Operations**: Logging of item serving operations with DLT mode error handling -4. **Gap Detection Operations**: Comprehensive logging of gap detection and recovery mechanisms -5. **Peer Ahead Detection**: Sophisticated logging of peer ahead-of-us detection in DLT mode -6. **Startup Diagnostics**: Comprehensive logging of startup block storage diagnostics -7. **Windows Compatibility**: Logging of Windows compatibility enhancements for DLT operations - -### Logging Context Information - -Each DLT mode log entry includes comprehensive context information: - -- **Block Numbers**: Current block, head block, earliest available block, and DLT log boundaries -- **Storage Information**: DLT log start and end positions, block log boundaries -- **Gap Information**: Gap locations, sizes, and detection results -- **Synchronization Context**: Effective head block, remaining item counts, and synchronization status -- **Peer Status**: Information about peers ahead of the local node in DLT mode - -**Section sources** -- [p2p_plugin.cpp:299-301](file://plugins/p2p/p2p_plugin.cpp#L299-L301) -- [p2p_plugin.cpp:321-327](file://plugins/p2p/p2p_plugin.cpp#L321-L327) -- [p2p_plugin.cpp:336-338](file://plugins/p2p/p2p_plugin.cpp#L336-L338) -- [p2p_plugin.cpp:357-364](file://plugins/p2p/p2p_plugin.cpp#L357-L364) -- [p2p_plugin.cpp:522-528](file://plugins/p2p/p2p_plugin.cpp#L522-L528) - -## Improved Console Readability - -**New** The P2P plugin now provides significantly improved console readability through the strategic use of ANSI color codes, allowing operators to quickly distinguish between different types of log messages and troubleshoot network operations more effectively. - -### Visual Distinction Between Log Types - -The color-coded logging system provides clear visual distinction between different categories of log messages: - -```mermaid -graph TB -subgraph "Console Readability Enhancement" -GrayLogs["Gray Logs
DLT Mode Debug
Gap Detection
Block Range Info
Windows Compatibility"] -CyanLogs["Cyan Logs
Peer Statistics
Connection Status
Peer Database Info
Startup Diagnostics"] -WhiteLogs["White Logs
Transaction Notifications
Block Processing
Latency Information"] -OrangeLogs["Orange Logs
Network Warnings
Peer Status
Connection Issues
Gap Warnings"] -RedLogs["Red Logs
Critical Errors
Severe Warnings
System Failures"] -DefaultLogs["Default Color
General Information
Debug Messages
Non-Critical Events"] -end -subgraph "Visual Benefits" -Benefit1["Quick Pattern Recognition"] -Benefit2["Faster Troubleshooting"] -Benefit3["Reduced Console Scrolling"] -Benefit4["Enhanced Multi-Tasking"] -end -GrayLogs --> Benefit1 -CyanLogs --> Benefit1 -WhiteLogs --> Benefit1 -OrangeLogs --> Benefit1 -RedLogs --> Benefit1 -DefaultLogs --> Benefit1 -``` - -**Diagram sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) - -### Operator Experience Improvements - -The enhanced console readability provides several operational benefits: - -1. **Quick Pattern Recognition**: Operators can instantly identify DLT mode operations (gray), peer statistics (cyan), transaction notifications (white), network warnings (orange), and critical errors (red) -2. **Faster Troubleshooting**: Color coding helps operators quickly locate relevant log entries during debugging sessions -3. **Reduced Console Scrolling**: Visual distinction makes it easier to scan through large amounts of log output -4. **Enhanced Multi-Tasking**: Operators can monitor multiple log streams simultaneously with color-based differentiation - -### Color Coding Strategy - -The color coding strategy is designed for optimal operator experience: - -- **Gray**: DLT mode debug information, gap detection details, block range management, and Windows compatibility enhancements -- **Cyan**: Peer statistics, connection status, peer database information, and startup diagnostics -- **White**: Important transaction notifications, block processing information, and latency details -- **Orange**: Network warnings, peer status changes, connection issues, and gap-related warnings -- **Red**: Critical errors, severe warnings, and system failures -- **Default**: General information, debug messages, and non-critical events (unchanged) - -**Section sources** -- [p2p_plugin.cpp:16-21](file://plugins/p2p/p2p_plugin.cpp#L16-L21) -- [p2p_plugin.cpp:169-171](file://plugins/p2p/p2p_plugin.cpp#L169-L171) -- [p2p_plugin.cpp:299-301](file://plugins/p2p/p2p_plugin.cpp#L299-L301) -- [p2p_plugin.cpp:522-528](file://plugins/p2p/p2p_plugin.cpp#L522-L528) -- [node.cpp:79-83](file://libraries/network/node.cpp#L79-L83) - -## Conditional Block Processing Latency Logging - -**New** The P2P plugin now implements conditional block processing latency logging that only executes when blocks are successfully processed in non-sync mode, significantly reducing log volume while maintaining operational visibility. - -### Conditional Latency Logging Implementation - -The enhanced block processing includes sophisticated conditional logging logic: - -```mermaid -flowchart TD -Start([Block Processing]) --> AcceptBlock["chain.accept_block()"] -AcceptBlock --> CheckResult{"Result successful?"} -CheckResult --> |No| End([End - No Latency Logging]) -CheckResult --> |Yes| CheckSyncMode{"Sync mode?"} -CheckSyncMode --> |Yes| End([End - No Latency Logging]) -CheckSyncMode --> |No| CalculateLatency["Calculate latency:
fc::time_point::now() - blk_msg.block.timestamp"] -CalculateLatency --> LogLatency["Log latency:
- Transaction count
- Block number
- validator
- Latency in milliseconds
in white ANSI color"] -LogLatency --> End([End - Latency Logged]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:159-175](file://plugins/p2p/p2p_plugin.cpp#L159-L175) - -### Benefits of Conditional Latency Logging - -The conditional approach provides several operational advantages: - -1. **Reduced Log Volume**: Latency information is only logged for successful block processing, significantly reducing log output during sync operations -2. **Maintained Visibility**: Critical latency information for successful normal operations is preserved for troubleshooting and performance monitoring -3. **Performance Impact**: Minimizes CPU overhead during high-volume sync operations while preserving diagnostic information -4. **Resource Efficiency**: Reduces I/O overhead and memory usage associated with excessive logging -5. **Operational Focus**: Ensures logs focus on meaningful operational events rather than routine sync activities - -### Implementation Details - -The conditional latency logging is implemented in the block processing method: - -```cpp -bool result = chain.accept_block(blk_msg.block, sync_mode, ...); - -if (!sync_mode && result) { - fc::microseconds latency = fc::time_point::now() - blk_msg.block.timestamp; - ilog(CLOG_WHITE "Got ${t} transactions on block ${b} by ${w} -- latency: ${l} ms" CLOG_RESET, - ("t", blk_msg.block.transactions.size())("b", blk_msg.block.block_num())("w", blk_msg.block.validator)("l", latency.count() / 1000)); -} -``` - -**Section sources** -- [p2p_plugin.cpp:159-175](file://plugins/p2p/p2p_plugin.cpp#L159-L175) - -## Graceful Degradation Capabilities - -**New** The P2P plugin now includes comprehensive graceful degradation capabilities when peers cannot serve requested items, ensuring network resilience and continued operation with sophisticated gap detection and automatic recovery. - -### DLT Mode Graceful Degradation with Gap Detection - -When peers cannot serve DLT-mode blocks, the plugin implements graceful degradation with comprehensive gap detection: - -```mermaid -flowchart TD -Start([DLT Block Request]) --> CheckAvailability["Check block availability:
- Block number
- Earliest available
- DLT log range
- Gap detection"] -CheckAvailability --> |Available| ServeBlock["Serve block normally"] -CheckAvailability --> |Not Available| CheckGap["Check if gap-related:
- Below earliest
- Beyond storage
- Fork_db gap"] -CheckGap --> |Gap Error| LogUnavailable["Log gap-related unavailability:
- Block number
- Available range
- DLT bounds
- Gap location
in gray ANSI color"] -CheckGap --> |Other Error| LogGenericUnavailable["Log generic unavailability:
- Error details
- Peer endpoint
- Context
in gray ANSI color"] -LogUnavailable --> CheckRecovery["Check recovery options:
- Peer switching
- Range adjustment
- Wait and retry"] -LogGenericUnavailable --> CheckRecovery -CheckRecovery --> |Peer Switching| SwitchPeer["Switch to alternative peer"] -CheckRecovery --> |Range Adjustment| AdjustRange["Adjust block range
with gap detection"] -CheckRecovery --> |Wait and Retry| WaitRetry["Wait and retry later"] -SwitchPeer --> LogRecovery["Log recovery actions:
- Peer switched
- Reason
- Success
in gray ANSI color"] -AdjustRange --> LogRecovery -WaitRetry --> LogRecovery -LogRecovery --> ContinueSync["Continue sync with available peers"] -ContinueSync --> End([End]) -ServeBlock --> End -``` - -**Diagram sources** -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) - -### Error Handling and Recovery with Gap Awareness - -The plugin implements comprehensive error handling and recovery mechanisms with gap detection: - -```mermaid -flowchart TD -Start([Error Occurred]) --> ClassifyError["Classify error:
- block_too_old_exception
- deferred_resize_exception
- unlinkable_block_exception
- network exceptions
- gap-related errors"] -ClassifyError --> HandleBlockTooOld["Handle block too old:
- Log warning
- Convert to network exception
- Soft-ban peer"] -ClassifyError --> HandleDeferredResize["Handle deferred resize:
- Log info
- Convert to network exception
- No peer penalty"] -ClassifyError --> HandleUnlinkable["Handle unlinkable block:
- Log warning
- Convert to network exception
- Peer soft-ban or resync"] -ClassifyError --> HandleGapError["Handle gap error:
- Log gap detection
- Adjust sync parameters
- Peer switching
in gray ANSI color"] -HandleBlockTooOld --> ContinueSync["Continue synchronization"] -HandleDeferredResize --> ContinueSync -HandleUnlinkable --> ContinueSync -HandleGapError --> CheckRecovery["Check recovery:
- Peer switching
- Range adjustment
- Wait and retry"] -CheckRecovery --> ContinueSync -ContinueSync --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:173-204](file://plugins/p2p/p2p_plugin.cpp#L173-L204) - -### Peer Soft-Ban Management with Gap Detection - -**New** The plugin manages peer soft-bans based on error severity with gap detection awareness and improved peer interaction: - -```mermaid -flowchart TD -Start([Peer Action]) --> CheckAction{"Action type?"} -CheckAction --> |Successful| DecreasePenalty["Decrease peer penalty"] -CheckAction --> |Minor Error| MaintainPenalty["Maintain current penalty"] -CheckAction --> |Major Error| IncreasePenalty["Increase penalty:
- Hard fork error
- Gap-related error
- Invalid block
- Sync spam detection
in gray ANSI color"] -CheckAction --> |Peer Disconnect| ResetPenalty["Reset penalty:
- Peer disconnected
- Handshake failed
- Rejected"] -IncreasePenalty --> CheckThreshold{"Penalty threshold exceeded?"} -CheckThreshold --> |No| Continue["Continue with current peer"] -CheckThreshold --> |Yes| CheckTrusted["Check if trusted peer:
- Trusted snapshot peer
- Reduced soft-ban duration"] -CheckTrusted --> |Trusted| ApplyReducedBan["Apply reduced soft-ban:
- 5 min instead of 1 hour
- For trusted peers only
in orange ANSI color"] -CheckTrusted --> |Not Trusted| RemovePeer["Remove peer:
- Add to banned list
- Clear from potential peers
- Log removal
- Gap detection context
in gray ANSI color"] -ApplyReducedBan --> FindAlternative["Find alternative peer:
- Check potential peers
- Consider gap compatibility
- Attempt reconnection
in gray ANSI color"] -RemovePeer --> FindAlternative -FindAlternative --> Continue -DecreasePenalty --> Continue -MaintainPenalty --> Continue -ResetPenalty --> Continue -Continue --> End([End]) -``` - -**Diagram sources** -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -**Section sources** -- [p2p_plugin.cpp:371-405](file://plugins/p2p/p2p_plugin.cpp#L371-L405) -- [p2p_plugin.cpp:173-204](file://plugins/p2p/p2p_plugin.cpp#L173-L204) -- [p2p_plugin.cpp:614-650](file://plugins/p2p/p2p_plugin.cpp#L614-L650) - -## Minority Fork Recovery - -**Updated** The minority fork recovery mechanism has been enhanced with improved peer interaction handling, comprehensive logging, and sophisticated gap detection throughout the recovery process. - -### Enhanced resync_from_lib() Method with Gap Detection - -The `resync_from_lib()` method now includes comprehensive logging, improved peer interaction, and gap detection: - -```mermaid -flowchart TD -Start([Minority Fork Detected]) --> CheckState{"Check LIB vs Head:
- LIB == 0?
- Head <= LIB?"} -CheckState --> |LIB == 0 or Head <= LIB| NoAction["No recovery needed:
- Already at/after LIB
- Log info message
in gray ANSI color"] -CheckState --> |Head > LIB| PopBlocks["Pop reversible blocks:
- While head > LIB
- db.pop_block()
- Clear pending
- Reset fork_db
- Log gap detection context
in gray ANSI color"] -PopBlocks --> RebuildForkDB["Re-seed fork DB:
- Fetch LIB block
- start_block(LIB_block)
- Log recovery step
- Check gap boundaries
in gray ANSI color"] -RebuildForkDB --> TriggerSync["Trigger P2P sync:
- sync_from(LIB_block_id)
- resync()
- Log sync initiation
- Include gap detection info
in gray ANSI color"] -TriggerSync --> ReconnectPeers["Reconnect to seed peers:
- add_node(seed)
- connect_to_endpoint(seed)
- Log peer switching
- Consider gap compatibility
in gray ANSI color"] -ReconnectPeers --> ResetTimer["Reset stale sync timer:
- _last_block_received_time = now
- Log timer reset
- Gap detection monitoring
in gray ANSI color"] -ResetTimer --> Complete([Recovery Complete]) -NoAction --> Complete -``` - -**Diagram sources** -- [p2p_plugin.cpp:992-1061](file://plugins/p2p/p2p_plugin.cpp#L992-L1061) - -### Enhanced Recovery Process Implementation with Gap Awareness - -The minority fork recovery process now includes several critical enhancements with gap detection: - -1. **State Analysis**: Improved comparison logic with comprehensive logging including gap detection context -2. **Block Popping**: Enhanced loop with proper error handling, logging, and gap boundary awareness -3. **Fork Database Reset**: Better error handling, state validation, and gap boundary detection -4. **Network Resynchronization**: Improved sync triggering with logging and gap-aware parameters -5. **Peer Reconnection**: Enhanced peer management with error handling and gap compatibility checking -6. **Timer Reset**: Proper timing management to prevent immediate re-trigger with gap monitoring - -### Integration with Validator Plugin and Gap Detection - -The minority fork recovery is triggered automatically by the Validator Plugin with enhanced logging and gap detection: - -```mermaid -sequenceDiagram -participant validator as Validator Plugin -participant P2P as P2P Plugin -participant Chain as Chain Database -participant Network as Network Layer -validator->>Chain : Check recent blocks -Chain-->>validator : Block validation results -validator->>validator : Analyze fork scenario
with gap detection -alt Minority fork detected -validator->>P2P : resync_from_lib() -Note over P2P : Enhanced logging with gap context
in gray ANSI color -P2P->>Chain : Pop blocks to LIB
with gap boundary awareness -P2P->>Chain : Reset fork database
including gap detection -P2P->>Network : Trigger sync from LIB
with gap-aware parameters -P2P->>Network : Reconnect to peers
considering gap compatibility -Note over P2P : Comprehensive recovery logging
with gap detection results
in gray ANSI color -end -``` - -**Diagram sources** -- [validator.cpp:540-552](file://plugins/validator/validator.cpp#L540-L552) -- [p2p_plugin.cpp:992-1061](file://plugins/p2p/p2p_plugin.cpp#L992-L1061) - -**Section sources** -- [p2p_plugin.cpp:992-1061](file://plugins/p2p/p2p_plugin.cpp#L992-L1061) -- [validator.cpp:540-552](file://plugins/validator/validator.cpp#L540-L552) - -## Enhanced Block Validation - -**Updated** The block validation process has been enhanced with operation guard protection to ensure concurrent access safety during critical validation operations with improved gap detection awareness. - -### Operation Guard Integration - -The enhanced block validation incorporates operation guards to prevent race conditions and ensure thread-safe access to shared blockchain state: - -```mermaid -flowchart TD -BlockReceived([Block Received]) --> ExtractWitness["Extract validator information"] -ExtractWitness --> AcquireGuard["Acquire operation guard"] -AcquireGuard --> VerifyWitness["Verify validator exists"] -VerifyWitness --> VerifySignature["Verify signature matches validator key"] -VerifySignature --> ReleaseGuard["Release operation guard"] -ReleaseGuard --> ApplyValidation["Apply block post-validation"] -ApplyValidation --> BroadcastBlock["Broadcast block to peers"] -``` - -**Diagram sources** -- [p2p_plugin.cpp:216-245](file://plugins/p2p/p2p_plugin.cpp#L216-L245) - -### Concurrent Access Protection with Gap Detection - -The operation guard system provides several layers of protection with gap detection awareness: - -1. **Resize Barrier Participation**: Operation guards participate in the shared memory resize barrier -2. **Lock Acquisition**: Automatically waits for resize operations to complete -3. **Thread Safety**: Prevents concurrent access conflicts during validator key validation -4. **Resource Management**: Ensures proper cleanup and release of resources -5. **Gap Detection Integration**: Operation guards work with gap detection mechanisms - -### Database Integration - -The enhanced validation leverages the chainbase database's operation guard functionality: - -```mermaid -classDiagram -class operation_guard { -+operation_guard(database& db) -+~operation_guard() -+release() -- database& _db -- bool _active -} -class database { -+make_operation_guard() operation_guard -+enter_operation() -+exit_operation() -} -operation_guard --> database : "guards access to" -``` - -**Diagram sources** -- [chainbase.hpp:1078-1115](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1115) - -**Section sources** -- [p2p_plugin.cpp:216-245](file://plugins/p2p/p2p_plugin.cpp#L216-L245) -- [chainbase.hpp:1078-1115](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1078-L1115) - -## Concurrent Access Safety - -**New** The P2P plugin now includes comprehensive concurrent access safety mechanisms to prevent data corruption and ensure thread-safe operations during high-load conditions with gap detection integration. - -### Operation Guard Implementation - -The operation guard system provides automatic protection against concurrent access conflicts: - -```mermaid -flowchart TD -Start([Operation Begins]) --> EnterOperation["Enter operation barrier"] -EnterOperation --> AcquireLock["Acquire database lock"] -AcquireLock --> PerformOperation["Perform database operation"] -PerformOperation --> ReleaseLock["Release database lock"] -ReleaseLock --> ExitOperation["Exit operation barrier"] -ExitOperation --> End([Operation Complete]) -``` - -**Diagram sources** -- [chainbase.hpp:1130-1137](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1130-L1137) - -### Thread Safety Enhancements with Gap Detection - -The concurrent access safety includes several key features with gap detection integration: - -1. **Automatic Lock Management**: Operation guards automatically manage database locks -2. **Resize Barrier Integration**: Participates in shared memory resize barriers -3. **Timeout Handling**: Implements timeout mechanisms for lock acquisition -4. **Resource Cleanup**: Ensures proper cleanup of resources on completion -5. **Gap Detection Integration**: Operation guards work seamlessly with gap detection mechanisms - -### Error Handling Improvements - -Enhanced error handling protects against various failure scenarios with gap detection: - -1. **Concurrent Resize Exceptions**: Proper handling of shared memory resize operations -2. **Deadlock Prevention**: Timeout mechanisms prevent indefinite blocking -3. **Graceful Degradation**: Fallback mechanisms for critical operations -4. **Diagnostic Information**: Comprehensive logging for debugging concurrent issues -5. **Gap Detection Logging**: Enhanced logging for concurrent gap detection scenarios - -**Section sources** -- [chainbase.hpp:1130-1137](file://thirdparty/chainbase/include/chainbase/chainbase.hpp#L1130-L1137) -- [p2p_plugin.cpp:173-208](file://plugins/p2p/p2p_plugin.cpp#L173-L208) - -## Logging Level Consistency - -**Updated** The P2P plugin has implemented improved logging level consistency to reduce verbosity during normal operation while maintaining appropriate log levels for different operational contexts with enhanced gap detection logging. - -### Sync Mode Logging Improvements - -**Updated** The plugin has undergone significant improvements in logging level management, particularly for synchronization operations with gap detection awareness: - -- **Sync Mode Downgrade**: Sync mode block processing logs were downgraded from info level to debug level -- **Normal Mode Preservation**: Normal block processing continues to use info level logging for visibility -- **Reduced Verbosity**: This change significantly reduces log volume during routine blockchain synchronization -- **Contextual Appropriateness**: Debug level logging is more appropriate for frequent sync operations while preserving info level for exceptional events -- **Gap Detection Logging**: Enhanced gap detection logs use appropriate levels for troubleshooting - -### Conditional Latency Logging Implementation - -**New** The conditional latency logging ensures that latency information is only displayed for successful block processing in non-sync mode: - -```cpp -if (!sync_mode && result) { - fc::microseconds latency = fc::time_point::now() - blk_msg.block.timestamp; - ilog(CLOG_WHITE "Got ${t} transactions on block ${b} by ${w} -- latency: ${l} ms" CLOG_RESET, - ("t", blk_msg.block.transactions.size())("b", blk_msg.block.block_num())("w", blk_msg.block.validator)("l", latency.count() / 1000)); -} -``` - -**Key Benefits:** -- **Reduced Log Volume**: Sync operations (which occur frequently during blockchain synchronization) now use debug level logging -- **Maintained Visibility**: Normal operations continue to use info level logging for operational visibility -- **Consistent Behavior**: Both sync and normal modes now consistently use debug level logging, improving overall logging consistency -- **Performance Impact**: Lower logging overhead during normal operation while preserving diagnostic information -- **Gap Detection Visibility**: Gap detection logs provide appropriate visibility for troubleshooting - -### Network Layer Integration - -The network layer maintains mixed logging levels for different operational contexts with gap detection awareness: - -- **Info Level**: Used for significant operational events and peer management actions -- **Debug Level**: Used for routine synchronization and connection maintenance -- **Warning/Error Levels**: Used for error conditions and exceptional circumstances -- **Gap Detection Levels**: Specialized logging for gap-related operations and recovery - -**Section sources** -- [p2p_plugin.cpp:151-156](file://plugins/p2p/p2p_plugin.cpp#L151-L156) -- [p2p_plugin.cpp:168-172](file://plugins/p2p/p2p_plugin.cpp#L168-L172) - -## Atomic Block Processing Flags and Two-Phase Resume - -Block processing pause/resume is now fully thread-safe using `std::atomic` flags in `dlt_p2p_node`, allowing the snapshot plugin to call `resume_block_processing()` from any thread without dispatching to the P2P thread. - -### Atomic Flag Design - -Three relevant flags are now atomic: -- `_block_processing_paused` — set by the P2P thread during a snapshot-triggered pause. -- `snapshot_in_progress` (conceptually cleared by the caller via a guard) — controls whether new blocks are accepted. -- `_catchup_after_pause` — tells the production gate that we just resumed and are catching up. - -**Critical ordering**: `_catchup_after_pause` must be set to `true` **before** `snapshot_in_progress` is cleared. If the order were reversed, the Validator Plugin could observe the snapshot complete but the catchup flag unset, mis-classify the head as a stale fork, and refuse to produce. - -This ordering is enforced in `p2p_plugin::resume_block_processing()` via `dlt_p2p_node::set_resume_flags()` (sets both atomics) followed by an async post for the P2P-thread-only drain. - -**Section sources** -- [p2p_plugin.cpp:692-723](file://plugins/p2p/p2p_plugin.cpp#L692-L723) -- [dlt_p2p_node.cpp](file://libraries/network/dlt_p2p_node.cpp) - -### Two-Phase Resume Implementation - -`resume_block_processing()` is split into two phases to avoid a deadlock that existed when calling `async().wait()` while holding a read lock: - -1. **Phase 1 (immediate, any thread)**: `set_resume_flags()` atomically sets `_catchup_after_pause = true` and clears `_block_processing_paused`. Because both are `std::atomic`, no P2P thread dispatch is required. -2. **Phase 2 (async, P2P thread)**: An async post to the P2P thread calls `run_resume_on_p2p_thread()` which logs the resume and drains the `_paused_block_queue`. No `.wait()` is used; the caller proceeds immediately after Phase 1. - -**Prior deadlock**: The old implementation dispatched Phase 1 via `async().wait()` while a read lock on the database was held. A second P2P fiber that had already passed the `_block_processing_paused` check would call `push_block()`, which blocked on the write lock (waiting for our read lock). The OS thread froze, the posted fiber never ran — deadlock. - -**Section sources** -- [p2p_plugin.cpp:708-722](file://plugins/p2p/p2p_plugin.cpp#L708-L722) - -### Shared Memory Corruption in Block Acceptance - -When `dlt_p2p_node` receives a block from the network and calls `push_block()`, it now catches `shared_memory_corruption_exception` separately from other exceptions. On this exception class the node triggers the same auto-recovery path as the chain plugin (reopen with replay), rather than simply soft-banning the peer that delivered the block. - -**Section sources** -- [p2p_plugin.cpp:692-706](file://plugins/p2p/p2p_plugin.cpp#L692-L706) -- [dlt_p2p_node.cpp](file://libraries/network/dlt_p2p_node.cpp) - -### Clear Syncing Flag on SYNC→FORWARD Transition - -`dlt_p2p_node` now explicitly clears the `_dlt_syncing` flag when transitioning from SYNC state to FORWARD state. Previously the flag could remain set after the sync completed, causing the Validator Plugin to see `chain().is_syncing() == true` indefinitely and refuse to produce blocks. - -**Section sources** -- [dlt_p2p_node.cpp](file://libraries/network/dlt_p2p_node.cpp) - -## DLT Status Log Uptime Field - -The periodic DLT Status log line now includes a node uptime field so operators can immediately see how long the node has been running without checking separate tooling. - -**Format**: `uptime=${uh}h${um}m${us}s` appended after the peer counts field. - -**Example**: `DLT Status | FORWARD | head=#1234567 lib=#1234500 | dlt_range=1000000-1234567 | peers=8active/10conn | uptime=2h15m43s | ...` - -**Implementation**: `_node_start_time` is recorded in the `dlt_p2p_node` constructor. Both the regular status log and the detailed stats log compute elapsed time as `(fc::time_point::now() - _node_start_time).count() / 1000000` seconds. - -**Section sources** -- [dlt_p2p_node.cpp:3126-3133](file://libraries/network/dlt_p2p_node.cpp#L3126-L3133) -- [dlt_p2p_node.cpp:3163-3169](file://libraries/network/dlt_p2p_node.cpp#L3163-L3169) - -## Dependency Analysis - -The P2P plugin has well-defined dependencies that enable modularity and maintainability with enhanced gap detection integration: - -```mermaid -graph TB -subgraph "Plugin Dependencies" -P2P[p2p_plugin] -Chain[chain::plugin] -AppBase[appbase] -Snapshot[snapshot_plugin] -validator[witness_plugin] -end -subgraph "Network Dependencies" -Node[node.hpp] -PeerConn[peer_connection.hpp] -Messages[core_messages.hpp] -PeerDB[peer_database.hpp] -Config[config.hpp] -end -subgraph "Protocol Dependencies" -Block[block.hpp] -Transaction[transaction.hpp] -Types[types.hpp] -end -subgraph "Database Dependencies" -Database[database.hpp] -Chainbase[chainbase.hpp] -OperationGuard[operation_guard] -DLTLog[dlt_block_log] -end -P2P --> Chain -P2P --> Node -P2P --> AppBase -P2P --> Snapshot -P2P --> validator -Node --> PeerConn -Node --> Messages -Node --> PeerDB -Node --> Config -Messages --> Block -Messages --> Transaction -Messages --> Types -Chain --> Database -Chain --> Chainbase -Chain --> OperationGuard -Chain --> DLTLog -Database --> OperationGuard -Database --> DLTLog -``` - -**Diagram sources** -- [CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [p2p_plugin.cpp:1-13](file://plugins/p2p/p2p_plugin.cpp#L1-L13) - -Key dependency relationships: - -1. **Chain Integration**: Direct dependency on the chain plugin for blockchain state access with gap detection -2. **Network Foundation**: Relies on the network library for peer communication with gap-aware protocols -3. **Application Framework**: Uses appbase for plugin lifecycle management -4. **Snapshot Coordination**: Integrates with snapshot plugin for trusted peer management with gap detection -5. **validator Integration**: Works closely with Validator Plugin for fork detection and gap monitoring -6. **Database Protection**: Leverages chainbase operation guards for concurrent access safety with gap detection -7. **DLT Mode Support**: Integrates with dlt_block_log for snapshot-based block serving with sophisticated gap detection -8. **Gap Detection**: Enhanced integration with gap detection mechanisms throughout the plugin stack -9. **Windows Compatibility**: Integration with DLT block log operations for Windows platform support - -**Section sources** -- [CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [p2p_plugin.cpp:1-13](file://plugins/p2p/p2p_plugin.cpp#L1-L13) - -## Performance Considerations - -The P2P plugin implements several performance optimization strategies with enhanced gap detection efficiency: - -### Connection Management -- **Connection Limits**: Configurable maximum connections to prevent resource exhaustion -- **Soft-Ban Mechanisms**: Automatic peer banning for misbehaving nodes with gap detection awareness -- **Trusted Peer System**: Reduced soft-ban duration for snapshot-provided trusted peers - -### Network Efficiency -- **Selective Synchronization**: Only fetches missing blockchain data with gap-aware range limiting -- **Message Caching**: Prevents redundant message propagation -- **Bandwidth Throttling**: Configurable upload/download limits - -### Monitoring and Diagnostics -- **Periodic Statistics**: Configurable logging intervals for peer statistics with gap detection -- **Stale Sync Detection**: Automatic recovery from stalled synchronization with gap monitoring -- **Connection Health Monitoring**: Real-time peer connection quality metrics with gap awareness - -### DLT Mode Performance with Gap Detection -**New** The DLT mode introduces several performance optimizations with gap detection: - -- **Intelligent Block Range Clamping**: Prevents requesting unavailable blocks with sophisticated gap detection -- **Early Availability Checking**: Reduces network requests for unavailable items with gap awareness -- **Optimized Peer Selection**: Better handling of DLT-capable peers with gap compatibility -- **Reduced Error Handling Overhead**: Graceful degradation minimizes performance impact with gap detection -- **Gap-Aware Recovery**: Automatic recovery mechanisms minimize performance impact during gap scenarios -- **Enhanced Peer Ahead Detection**: Sophisticated detection reduces unnecessary sync attempts -- **Startup Diagnostics Efficiency**: Optimized startup diagnostics minimize sync delay -- **Windows Compatibility Optimization**: Enhanced compatibility reduces performance impact - -### Logging Performance Impact -**Updated** The improved logging level consistency and conditional latency logging provide additional performance benefits: - -- **Reduced I/O Overhead**: Debug level logging produces less output than info level logging -- **Lower Memory Usage**: Reduced log buffer consumption during sync operations -- **Improved Throughput**: Less frequent logging reduces CPU overhead during normal operation -- **Better Resource Utilization**: More efficient use of system resources during routine operations -- **Conditional Latency Reporting**: Latency logging only occurs for successful operations, reducing unnecessary processing -- **Gap Detection Efficiency**: Optimized logging for gap detection scenarios - -### Concurrent Access Optimization -**New** The operation guard system provides performance benefits through gap detection integration: - -- **Reduced Contention**: Automatic lock management reduces thread contention -- **Efficient Resource Usage**: Operation guards minimize overhead during validation -- **Scalable Design**: Thread-safe operations scale better under load with gap detection -- **Graceful Degradation**: Timeout mechanisms prevent performance degradation -- **Gap Detection Optimization**: Integrated gap detection reduces unnecessary operations - -### DLT Storage Diagnostics Performance -**New** The enhanced DLT storage diagnostics provide performance monitoring with minimal overhead: - -- **Periodic Execution**: Diagnostics run at configurable intervals to balance accuracy and performance -- **Efficient Gap Detection**: Optimized algorithms for detecting DLT coverage gaps -- **Minimal I/O Impact**: Storage diagnostics use efficient queries to minimize disk access -- **Background Processing**: Diagnostics run in background threads to avoid blocking main operations -- **Startup Diagnostics Optimization**: Efficient startup diagnostics minimize sync delay - -### DLT Integrity Scanning Performance -**New** The periodic DLT integrity scanning provides comprehensive monitoring with performance considerations: - -- **Selective Scanning**: Continuity verification runs only when DLT mode is active -- **Efficient Gap Detection**: verify_continuity() algorithm optimized for performance -- **Limited Scope**: Scans only when gaps are detected, minimizing overhead -- **Background Execution**: Integrity scans run in background without impacting main operations -- **Windows Compatibility Optimization**: Enhanced compatibility reduces performance impact - -### Windows Compatibility Performance -**New** The Windows compatibility enhancements provide performance benefits: - -- **Stale Mapping Detection**: Efficient detection and healing of stale mappings -- **Logical Size Tracking**: Optimized tracking of file sizes to avoid performance issues -- **Memory-Mapped File Optimization**: Efficient handling of memory-mapped files on Windows -- **Resize Count Monitoring**: Minimal overhead for tracking resize operations - -**Section sources** -- [p2p_plugin.cpp:701-765](file://plugins/p2p/p2p_plugin.cpp#L701-L765) -- [p2p_plugin.cpp:596-699](file://plugins/p2p/p2p_plugin.cpp#L596-L699) -- [dlt_block_log.cpp:576-602](file://libraries/chain/dlt_block_log.cpp#L576-L602) - -## Troubleshooting Guide - -### Common Issues and Solutions - -#### Connection Problems -- **Symptom**: Unable to connect to seed nodes -- **Solution**: Verify network connectivity and check firewall settings -- **Configuration**: Review `p2p-seed-node` entries in configuration file - -#### Synchronization Delays -- **Symptom**: Slow blockchain synchronization -- **Solution**: Increase `p2p-max-connections` setting -- **Monitoring**: Enable P2P statistics to identify slow peers with gap detection awareness - -#### Peer Quality Issues -- **Symptom**: Frequent peer disconnections -- **Solution**: Check network stability and bandwidth limitations -- **Diagnostics**: Monitor peer statistics for connection patterns with gap-related errors - -### DLT Mode Troubleshooting with Gap Detection - -**New** For DLT mode-specific issues with gap detection: - -1. **Block Availability Errors**: Check `earliest_available_block_num()` and DLT log bounds with gap detection -2. **Peer Compatibility**: Verify peers support DLT mode block serving with gap awareness -3. **Recovery Actions**: Monitor graceful degradation logs for peer soft-bans with gap detection -4. **Sync Performance**: Use DLT-specific logging to identify block range issues with gap information -5. **Gap Detection**: Monitor gap detection logs for storage boundary issues -6. **Peer Ahead Detection**: Verify peer ahead detection is working correctly in DLT mode -7. **Startup Diagnostics**: Review startup diagnostics for gap and integrity issues - -### Minor Fork Recovery Procedures - -**Updated** For minority fork scenarios with gap detection: - -1. **Detection**: Monitor Validator Plugin logs for minority fork warnings with gap context -2. **Automatic Recovery**: The system automatically triggers `resync_from_lib()` with gap detection -3. **Manual Intervention**: Use RPC commands to trigger recovery if automatic detection fails -4. **Verification**: Monitor logs to confirm successful recovery and synchronization with gap awareness - -### Enhanced Peer Database Analysis - -**New** Use the enhanced peer database logging for troubleshooting with gap detection: - -1. **Failed Peer Analysis**: Review logs for failed/rejected peer status with gap-related errors -2. **Connection Attempts**: Monitor last connection attempt times and reasons with gap context -3. **Error Patterns**: Identify recurring error patterns across multiple peers with gap detection -4. **Recovery Effectiveness**: Track peer reconnection success rates with gap-aware metrics - -### Gap Detection Troubleshooting - -**New** Specific gap detection troubleshooting procedures: - -1. **Gap Detection Logs**: Review gap detection logs for storage boundary issues -2. **Clamping Operations**: Monitor clamping operations for proper gap handling -3. **Peer Compatibility**: Check peer compatibility with gap detection mechanisms -4. **Recovery Actions**: Verify automatic recovery actions for gap-related issues -5. **Peer Ahead Detection**: Verify peer ahead detection is working correctly - -### Conditional Latency Logging Troubleshooting - -**New** For conditional latency logging issues: - -1. **Latency Not Displayed**: Verify that blocks are being processed successfully in non-sync mode -2. **Log Volume**: Check that sync mode operations are not generating excessive latency logs -3. **Performance Impact**: Monitor system performance to ensure conditional logging is not causing overhead -4. **Color Coding**: Verify that latency logs are displayed in white color with proper ANSI formatting - -### ANSI Color Code Troubleshooting - -**New** For ANSI color code-related issues: - -1. **Console Compatibility**: Ensure terminal supports ANSI color codes -2. **Color Output Testing**: Test color output in different terminal environments -3. **Log Filtering**: Use log filtering to isolate specific color-coded log categories -4. **Operator Training**: Train operators to recognize different color-coded log categories - -### DLT Storage Diagnostics Troubleshooting - -**New** For DLT storage diagnostics issues: - -1. **Coverage Gaps**: Monitor DLT coverage gap warnings and investigate storage boundaries -2. **Integrity Verification**: Review DLT integrity warnings and investigate block log continuity -3. **Mapping Consistency**: Check DLT mapping verification results and address stale mappings -4. **Storage Performance**: Monitor storage diagnostics for optimal performance tuning -5. **Startup Diagnostics**: Review startup diagnostics for gap and integrity issues - -### Automatic Peer Soft-Banning Troubleshooting - -**New** For automatic peer soft-banning issues: - -1. **Soft-Ban Duration**: Verify soft-ban duration for trusted vs non-trusted peers -2. **Penalty Threshold**: Check penalty threshold calculations and enforcement -3. **Peer Recovery**: Monitor peer recovery mechanisms and automatic unbanning -4. **Sync Spam Detection**: Investigate sync spam detection and peer behavior analysis -5. **Gap Detection Impact**: Verify gap detection is not affecting soft-ban decisions - -### DLT Integrity Scanning Troubleshooting - -**New** For DLT integrity scanning issues: - -1. **Integrity Warnings**: Review DLT integrity warnings for gap detection and recovery -2. **Mapping Issues**: Investigate stale mapping detection and healing -3. **Performance Impact**: Monitor integrity scanning performance and adjust frequency -4. **Gap Reporting**: Verify gap reporting accuracy and completeness -5. **Windows Compatibility**: Verify Windows compatibility enhancements are working correctly - -### Enhanced Peer Ahead Detection Troubleshooting - -**New** For peer ahead detection issues: - -1. **Detection Accuracy**: Verify peer ahead detection is working correctly in DLT mode -2. **Empty Response**: Check that empty responses are returned for ahead peers -3. **Sync Performance**: Monitor sync performance with peer ahead detection enabled -4. **Logging**: Verify peer ahead detection logging is working correctly - -### Startup Diagnostics Troubleshooting - -**New** For startup diagnostics issues: - -1. **Diagnostics Timing**: Verify startup diagnostics run before synchronization begins -2. **Gap Detection**: Check startup gap detection and logging -3. **Integrity Scanning**: Verify startup integrity scanning is working correctly -4. **Performance Impact**: Monitor startup diagnostics performance impact - -### Windows Compatibility Troubleshooting - -**New** For Windows compatibility issues: - -1. **Stale Mapping Detection**: Verify stale mapping detection and healing are working -2. **File Operations**: Check Windows-specific file operations are working correctly -3. **Memory-Mapped Files**: Verify memory-mapped file operations on Windows -4. **Performance Impact**: Monitor Windows compatibility performance impact - -### Configuration Reference - -The P2P plugin supports extensive configuration options: - -| Configuration Option | Description | Default Value | -|---------------------|-------------|---------------| -| `p2p-endpoint` | Local IP address and port for incoming connections | 127.0.0.1:9876 | -| `p2p-max-connections` | Maximum incoming connections | 0 (unlimited) | -| `p2p-seed-node` | Seed node endpoints | None | -| `p2p-stats-enabled` | Enable peer statistics logging | true | -| `p2p-stats-interval` | Statistics logging interval (seconds) | 300 | -| `p2p-stale-sync-detection` | Enable stale sync detection | false | -| `p2p-stale-sync-timeout-seconds` | Stale sync timeout | 120 | - -### Concurrent Access Issues - -**New** For concurrent access problems with gap detection: - -1. **Monitor Operation Guards**: Check for operation guard timeouts in logs with gap context -2. **Check Shared Memory**: Verify shared memory resize operations are completing -3. **Adjust Timeouts**: Increase operation guard timeout values if needed -4. **Resource Monitoring**: Monitor system resources during high-load periods with gap detection -5. **Gap Detection Monitoring**: Monitor gap detection operations for performance impact - -### Color Coding Issues - -**New** For color coding problems: - -1. **Terminal Compatibility**: Ensure terminal supports ANSI color codes -2. **Color Output Verification**: Test color output in different environments -3. **Log Filtering**: Use log filtering to examine color-coded categories -4. **Operator Training**: Train staff to interpret color-coded log messages - -**Section sources** -- [p2p_plugin.cpp:701-765](file://plugins/p2p/p2p_plugin.cpp#L701-L765) -- [p2p_plugin.cpp:992-1061](file://plugins/p2p/p2p_plugin.cpp#L992-L1061) -- [config.ini:1-143](file://share/vizd/config/config.ini#L1-L143) - -## Conclusion - -The P2P Plugin represents a sophisticated implementation of blockchain networking infrastructure that provides essential functionality for distributed consensus systems. Its modular architecture, comprehensive peer management, and robust synchronization protocols make it a cornerstone component of the VIZ blockchain ecosystem. - -**Updated** Key enhancements include: - -1. **Security Focus**: Advanced block validation and validator verification mechanisms with gap detection -2. **Performance Optimization**: Efficient synchronization and connection management with gap-aware optimizations -3. **Operational Excellence**: Comprehensive monitoring and diagnostic capabilities with gap detection -4. **Extensibility**: Clean interfaces that support future enhancements with gap detection integration -5. **Enhanced Logging**: Improved logging level consistency with reduced verbosity while maintaining operational visibility -6. **Minority Fork Recovery**: Specialized recovery mechanism for handling fork scenarios with gap awareness -7. **Concurrent Access Safety**: Enhanced protection against race conditions and data corruption with gap detection -8. **Integration Capabilities**: Seamless coordination with validator and snapshot plugins with gap detection -9. **DLT Mode Support**: Intelligent block range management for snapshot-based nodes with sophisticated gap detection -10. **Graceful Degradation**: Robust error handling and peer interaction management with gap-aware recovery -11. **Enhanced Diagnostics**: Comprehensive logging throughout the sync process with gap detection -12. **Peer Database Analytics**: Detailed peer interaction tracking and troubleshooting with gap awareness -13. **ANSI Color Code Implementation**: Strategic use of color codes (white, cyan, gray, orange, red) for improved console readability and visual distinction -14. **Conditional Latency Logging**: Smart latency reporting that only displays successful block processing information in non-sync mode -15. **Enhanced Block Processing Visibility**: Improved visibility into block processing with detailed transaction and validator information -16. **DLT Storage Diagnostics**: Comprehensive block storage monitoring with gap detection and coverage analysis -17. **Automatic Peer Soft-Banning**: Intelligent peer management with automatic soft-banning for sync spam and improved peer interaction -18. **DLT Integrity Verification**: Periodic verification of DLT block log integrity with gap detection and continuity scanning -19. **Comprehensive Gap Detection**: Advanced gap detection reporting with detailed coverage gap monitoring -20. **Enhanced Peer Ahead-of-Us Detection**: Sophisticated detection of peers ahead of the local node in DLT mode -21. **Startup Block Storage Diagnostics**: Comprehensive diagnostics system that runs before synchronization begins -22. **Windows Compatibility Enhancements**: Enhanced compatibility with Windows operating systems for DLT block log operations - -The recent additions demonstrate ongoing attention to operational efficiency and user experience. The new DLT mode block range management with sophisticated gap detection provides intelligent support for snapshot-based nodes, while the enhanced peer interaction handling improves network resilience. The comprehensive logging throughout the sync process provides unprecedented visibility into network operations, and the graceful degradation capabilities ensure reliable operation even when peers cannot serve requested items. - -The plugin's design demonstrates best practices in distributed systems engineering, balancing security, performance, and maintainability while providing the foundation for scalable blockchain networks. The integration of DLT mode support, graceful degradation mechanisms, enhanced diagnostic capabilities, and sophisticated gap detection positions the P2P plugin to handle increasingly complex blockchain networking requirements with improved reliability and operability. - -The implementation of comprehensive ANSI color codes (white, cyan, gray, orange, red) further enhances the plugin's operational capabilities by providing visual distinction between different types of log messages, enabling operators to quickly identify and respond to different operational scenarios. The strategic use of color codes creates a clear visual hierarchy that improves troubleshooting efficiency and reduces operator workload during complex network operations. - -The conditional block processing latency logging ensures that operators receive timely feedback on successful block processing without being overwhelmed by log volume during sync operations. This balanced approach to logging provides the right amount of information at the right time, improving both operational efficiency and system performance. - -The enhanced peer database logging and DLT storage diagnostics provide unprecedented visibility into peer interactions and storage capabilities, enabling operators to quickly identify and resolve network issues. The automatic peer soft-banning system with gap detection awareness improves network resilience by intelligently managing problematic peers while maintaining service quality for legitimate users. - -The DLT integrity verification system provides continuous monitoring of data integrity, ensuring that snapshot-based nodes maintain reliable and consistent block storage. This comprehensive approach to diagnostics and monitoring positions the P2P plugin as a critical component in maintaining the health and reliability of the VIZ blockchain network. - -The enhanced peer ahead-of-us detection mechanism provides sophisticated peer management capabilities, preventing unnecessary sync attempts and improving overall network efficiency. The comprehensive startup diagnostics system ensures that potential issues are identified and resolved before synchronization begins, improving the reliability of new node deployments. - -The Windows compatibility enhancements ensure that the plugin operates reliably across different platforms, with special attention to DLT block log operations on Windows systems. This cross-platform compatibility is essential for the widespread deployment of VIZ blockchain nodes. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Plugin System/Plugin System.md b/.qoder/repowiki/en/content/Plugin System/Plugin System.md deleted file mode 100644 index 4bfc47dd4b..0000000000 --- a/.qoder/repowiki/en/content/Plugin System/Plugin System.md +++ /dev/null @@ -1,1152 +0,0 @@ -# Plugin System - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/plugin.md](file://documentation/plugin.md) -- [documentation/snapshot-plugin.md](file://documentation/snapshot-plugin.md) -- [plugins/CMakeLists.txt](file://plugins/CMakeLists.txt) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp) -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [plugins/p2p/CMakeLists.txt](file://plugins/p2p/CMakeLists.txt) -- [plugins/p2p/p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp) -- [plugins/snapshot/CMakeLists.txt](file://plugins/snapshot/CMakeLists.txt) -- [plugins/snapshot/plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [plugins/debug_node/plugin.cpp](file://plugins/debug_node/plugin.cpp) -- [libraries/protocol/include/graphene/protocol/operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [libraries/chain/chain_evaluator.cpp](file://libraries/chain/chain_evaluator.cpp) -- [libraries/chain/database.cpp](file://libraries/chain/database.cpp) -- [libraries/chain/dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [libraries/chain/include/graphene/chain/dlt_block_log.hpp](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp) -- [libraries/network/node.cpp](file://libraries/network/node.cpp) -- [libraries/network/peer_connection.hpp](file://libraries/network/peer_connection.hpp) -- [libraries/network/core_messages.hpp](file://libraries/network/core_messages.hpp) -- [thirdparty/fc/include/fc/network/ip.hpp](file://thirdparty/fc/include/fc/network/ip.hpp) -- [thirdparty/fc/src/network/ip.cpp](file://thirdparty/fc/src/network/ip.cpp) -- [programs/util/newplugin.py](file://programs/util/newplugin.py) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced P2P plugin integration with snapshot plugin through CMake linking and cross-plugin functionality -- Added automatic trusted peer endpoint registration from snapshot plugin to P2P layer -- Updated P2P plugin to utilize snapshot plugin's trusted peer management for reduced soft-ban duration -- Improved cross-plugin communication patterns between P2P and snapshot plugins - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [DLT Mode and Snapshot Integration](#dlt-mode-and-snapshot-integration) -7. [Enhanced P2P Plugin Integration with DLT Mode Awareness](#enhanced-p2p-plugin-integration-with-dlt-mode-awareness) -8. [Cross-Plugin Integration: P2P and Snapshot](#cross-plugin-integration-p2p-and-snapshot) -9. [Type Safety Improvements in IP Address Handling](#type-safety-improvements-in-ip-address-handling) -10. [Dependency Analysis](#dependency-analysis) -11. [Plugin Deprecation Status and Maintenance Practices](#plugin-deprecation-status-and-maintenance-practices) -12. [Performance Considerations](#performance-considerations) -13. [Troubleshooting Guide](#troubleshooting-guide) -14. [Conclusion](#conclusion) -15. [Appendices](#appendices) - -## Introduction -This document explains the VIZ C++ Node plugin system architecture, focusing on how the appbase-based framework enables modular functionality, the plugin lifecycle from registration to shutdown, and inter-plugin communication patterns. It documents the built-in plugin ecosystem (40+ plugins) ranging from core blockchain functions to specialized APIs and integrations, including the enhanced snapshot plugin capabilities for DLT (Distributed Ledger Technology) mode operations and integration with rolling block log features. - -**Updated** Enhanced with comprehensive DLT mode documentation covering snapshot-based node bootstrap, rolling block log integration, and P2P layer compatibility for distributed ledger deployments. The P2P plugin now includes sophisticated DLT mode awareness with improved error handling and logging capabilities for DLT mode block serving operations, featuring enhanced sync block processing visibility and better synchronization progress monitoring. Recent improvements include enhanced type safety in IP address handling to prevent implicit type conversion issues in peer management code. **Cross-plugin integration** now enables the P2P plugin to automatically register trusted peer endpoints from the snapshot plugin, improving peer trust management and reducing soft-ban durations for verified snapshot sources. - -## Project Structure -The plugin system is organized around the appbase application framework and a dedicated plugins directory. Each plugin is a self-contained module that registers APIs, subscribes to chain events, and optionally depends on other plugins. The top-level plugins build script enumerates subdirectories and exposes a runtime-accessible list of available plugins. Built-in plugins are located under libraries/plugins/, while external plugins can be added similarly. - -```mermaid -graph TB -A["AppBase Application
appbase::application"] --> B["JSON-RPC Plugin
json_rpc::plugin"] -B --> C["Chain Plugin
chain::plugin"] -B --> D["Webserver Plugin
webserver::plugin"] -B --> E["Database API Plugin
database_api::plugin"] -B --> F["Account History Plugin
account_history::plugin"] -B --> G["P2P Plugin
p2p::plugin"] -B --> H["MongoDB Plugin
mongo_db::plugin"] -B --> I["Snapshot Plugin
snapshot::plugin"] -C --> J["Chain Database
chainbase::database"] -I --> K["DLT Block Log
dlt_block_log"] -G --> L["DLT Mode Integration
P2P Layer"] -G --> M["Type Safety Enhancements
IP Address Handling"] -G --> N["Cross-Plugin Integration
Snapshot Trust Management"] -I --> O["Trusted Peer Management
Automatic Endpoint Registration"] -``` - -**Diagram sources** -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:84-118](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-57](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-403](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:59-97](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L97) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-52](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) -- [libraries/chain/include/graphene/chain/dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) -- [plugins/p2p/p2p_plugin.cpp:203-257](file://plugins/p2p/p2p_plugin.cpp#L203-L257) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -**Section sources** -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [documentation/plugin.md:1-28](file://documentation/plugin.md#L1-L28) - -## Core Components -- JSON-RPC Plugin: Central dispatcher for API method routing and request handling. It maintains a registry of API names and methods and delegates calls to registered APIs. -- Chain Plugin: Provides blockchain database access, block acceptance, transaction acceptance, and synchronization signals for other plugins. -- Webserver Plugin: Starts an HTTP/WebSocket server and dispatches JSON-RPC queries to registered handlers on the app's io_service thread. -- Database API Plugin: Exposes read-only database queries via JSON-RPC, including blocks, accounts, balances, and chain metadata. -- Account History Plugin: Tracks per-account operation histories and exposes retrieval APIs. -- P2P Plugin: Manages peer-to-peer networking, broadcasting blocks/transactions, and block production controls. **Enhanced** with DLT mode awareness, improved error handling, sophisticated logging for sync block processing, and **improved type safety** in IP address handling. **Enhanced** with cross-plugin integration for trusted peer management from the snapshot plugin. -- Mongo DB Plugin: Integrates with MongoDB for indexing and archival of chain data. -- **Snapshot Plugin**: Enables DLT (Distributed Ledger Technology) mode operations including snapshot creation, loading, P2P snapshot synchronization, and integration with rolling block logs. **Enhanced** with trusted peer endpoint management for cross-plugin integration. - -**Section sources** -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:84-118](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-57](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-403](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:59-97](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L97) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-52](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) - -## Architecture Overview -The plugin architecture follows appbase conventions: -- Plugins derive from appbase::plugin and declare dependencies via APPBASE_PLUGIN_REQUIRES. -- Plugins register APIs during startup and expose methods via JSON-RPC. -- Inter-plugin communication occurs through: - - Shared application services (e.g., chain database). - - Signals/slots (Boost.Signals2) for event-driven coordination. - - Explicit API calls across plugin boundaries. - - **Enhanced cross-plugin integration** through direct plugin access and shared configuration. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant WS as "Webserver Plugin" -participant RPC as "JSON-RPC Plugin" -participant DBAPI as "Database API Plugin" -participant CHAIN as "Chain Plugin" -participant SNAP as "Snapshot Plugin" -participant P2P as "P2P Plugin" -Client->>WS : "HTTP/WS JSON-RPC request" -WS->>RPC : "Dispatch body" -RPC->>DBAPI : "Resolve API name and method" -DBAPI->>CHAIN : "Read chain state" -CHAIN-->>DBAPI : "Database objects" -DBAPI-->>RPC : "Response variant" -RPC-->>WS : "Formatted JSON-RPC response" -WS-->>Client : "HTTP/WS response" -Note over SNAP,P2P : "Cross-plugin integration :
P2P registers trusted peers
from snapshot plugin" -Note over P2P,CHAIN : "DLT mode : Snapshot plugin manages state
and integrates with rolling block logs" -``` - -**Diagram sources** -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-57](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:109-113](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L109-L113) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-403](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:88-91](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:60-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L60-L76) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -## Detailed Component Analysis - -### JSON-RPC Plugin -- Role: Registers API method bindings and routes incoming JSON-RPC requests to the appropriate plugin API. -- Key behaviors: - - Maintains a registry of API names and methods. - - Dispatches calls using a visitor pattern that binds method pointers to variants. - - Supports error codes standardized for JSON-RPC. - -```mermaid -classDiagram -class JsonRpcPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+add_api_method(api_name, method_name, api) -+call(body, response_handler) -} -``` - -**Diagram sources** -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:84-118](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) - -**Section sources** -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:38-55](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L38-L55) -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:109-113](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L109-L113) - -### Chain Plugin -- Role: Core blockchain engine exposing database accessors, block/transaction acceptance, and synchronization signals. -- Lifecycle hooks: initialize, startup, shutdown. -- Public API surface includes helpers for indices and objects, plus a synchronization signal for dependent plugins. - -```mermaid -classDiagram -class ChainPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+accept_block(block, currently_syncing, skip) -+accept_transaction(trx) -+db() Database -+on_sync signal -} -``` - -**Diagram sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-96](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L96) - -**Section sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:36-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L36-L42) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:88-91](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) - -### Webserver Plugin -- Role: Starts an HTTP/WebSocket server and dispatches JSON-RPC queries to registered handlers on the application io_service thread. -- Dependencies: Requires JSON-RPC plugin. - -```mermaid -classDiagram -class WebserverPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -} -``` - -**Diagram sources** -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-57](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) - -**Section sources** -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:19-31](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L19-L31) - -### Database API Plugin -- Role: Exposes read-only database queries via JSON-RPC, including blocks, accounts, balances, and chain metadata. -- Dependencies: Requires JSON-RPC and Chain plugins. -- API coverage includes block retrieval, dynamic/global properties, account queries, and more. - -```mermaid -classDiagram -class DatabaseApiPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+DECLARE_API(...) -} -``` - -**Diagram sources** -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-403](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) - -**Section sources** -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:188-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:227-398](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L227-L398) - -### Account History Plugin -- Role: Tracks per-account operation histories and exposes retrieval APIs. -- Dependencies: Requires JSON-RPC, Chain, and Operation History plugins. - -```mermaid -classDiagram -class AccountHistoryPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+DECLARE_API(get_account_history) -} -``` - -**Diagram sources** -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:59-97](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L97) - -**Section sources** -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:61-65](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L61-L65) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:83-92](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L83-L92) - -### P2P Plugin -- Role: Manages peer-to-peer networking, broadcasting blocks/transactions, and block production controls. -- Dependencies: Requires Chain plugin. -- **Maintenance Note**: Uses deprecated configuration options with warnings for migration. -- **DLT Integration**: Automatically falls back to DLT block log when serving blocks not found in main block log. -- **Enhanced Error Handling**: Improved logging and error handling specifically for DLT mode scenarios with sophisticated debug logging capabilities. -- **Type Safety Improvements**: Enhanced IP address handling with explicit type conversion using static_cast() to prevent implicit type conversion issues in peer management code. -- **Cross-Plugin Integration**: **Enhanced** with automatic trusted peer endpoint registration from the snapshot plugin for improved peer trust management. - -```mermaid -classDiagram -class P2PPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+broadcast_block(block) -+broadcast_transaction(trx) -+set_block_production(flag) -+get_item(item_id) -+get_block_ids(synopsis, remaining, limit) -+register_trusted_snapshot_peers() -} -``` - -**Diagram sources** -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-52](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L52) -- [plugins/p2p/p2p_plugin.cpp:259-277](file://plugins/p2p/p2p_plugin.cpp#L259-L277) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -**Section sources** -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:20-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:40-49](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L40-L49) -- [plugins/p2p/p2p_plugin.cpp:259-277](file://plugins/p2p/p2p_plugin.cpp#L259-L277) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -### Mongo DB Plugin -- Role: Integrates with MongoDB for indexing and archival of chain data. -- Dependencies: Requires Chain plugin. - -```mermaid -classDiagram -class MongoDbPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -} -``` - -**Diagram sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:14-47](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L47) - -**Section sources** -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:17-19](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) - -### Snapshot Plugin -- Role: Enables DLT (Distributed Ledger Technology) mode operations including snapshot creation, loading, P2P snapshot synchronization, and integration with rolling block logs. -- Dependencies: Requires Chain plugin. -- Key capabilities: - - Creates compressed state snapshots at specific blocks or periodically - - Loads state from snapshot files for fast node bootstrap - - Serves snapshots to other nodes via TCP protocol - - Manages automatic snapshot cleanup and rotation - - Integrates with DLT mode for distributed ledger deployments - - **Enhanced** with trusted peer endpoint management for cross-plugin integration - - **Enhanced** with trusted snapshot peer configuration for P2P integration - -```mermaid -classDiagram -class SnapshotPlugin { -+plugin_initialize(options) -+plugin_startup() -+plugin_shutdown() -+get_snapshot_path() string -+load_snapshot_from(path) -+create_snapshot_at(path) -+start_server() -+download_snapshot_from_peers() -+get_trusted_snapshot_peers() vector -} -``` - -**Diagram sources** -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -**Section sources** -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:46-87](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L46-L87) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -### Plugin Registration and Lifecycle -- Registration: Plugins are enumerated by the build system and registered with the application. Built-in plugins are discovered via the plugins directory traversal. -- Startup: Plugins initialize dependencies, set up program options, and register APIs with the JSON-RPC dispatcher. -- Shutdown: Plugins clean up resources and disconnect signals. - -```mermaid -flowchart TD -Start(["Application Start"]) --> Discover["Discover Plugins
CMake discovers subdirectories"] -Discover --> Init["Initialize Plugins
plugin_initialize()"] -Init --> Deps["Resolve Dependencies
APPBASE_PLUGIN_REQUIRES"] -Deps --> Startup["Startup Phase
plugin_startup()"] -Startup --> CrossPlugin["Cross-Plugin Integration
P2P registers trusted peers"] -CrossPlugin --> Run["Runtime
Serve APIs, handle events"] -Run --> DLTMode["DLT Mode Detection
Snapshot-based state"] -DLTMode --> Run -Run --> Shutdown["Shutdown Phase
plugin_shutdown()"] -Shutdown --> End(["Exit"]) -``` - -**Diagram sources** -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:84-118](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:36-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L36-L42) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:60-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L60-L76) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -**Section sources** -- [documentation/plugin.md:11-20](file://documentation/plugin.md#L11-L20) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) - -### Inter-Plugin Communication Patterns -- Shared Database Access: Plugins like Database API and Account History rely on Chain plugin's database interface. -- Event Synchronization: Plugins can subscribe to Chain plugin signals (e.g., on_sync) to coordinate startup behavior. -- Explicit API Calls: Plugins can call APIs exposed by other plugins via the JSON-RPC registry. -- **DLT Mode Coordination**: Snapshot plugin coordinates with Chain plugin for state management and with P2P plugin for snapshot distribution. -- **Enhanced Cross-Plugin Integration**: P2P plugin can directly access snapshot plugin to retrieve trusted peer endpoints for improved peer trust management. - -```mermaid -sequenceDiagram -participant CHAIN as "Chain Plugin" -participant AHIST as "Account History Plugin" -participant DBAPI as "Database API Plugin" -participant SNAP as "Snapshot Plugin" -participant P2P as "P2P Plugin" -CHAIN-->>AHIST : "on_sync signal" -AHIST->>CHAIN : "Subscribe to applied_block" -CHAIN-->>DBAPI : "Expose database via APIs" -CHAIN-->>SNAP : "State management for DLT mode" -SNAP->>CHAIN : "Load snapshot state" -P2P->>SNAP : "get_trusted_snapshot_peers()" -SNAP-->>P2P : "Vector of trusted peer endpoints" -P2P->>P2P : "set_trusted_peer_endpoints()" -``` - -**Diagram sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:88-91](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:77-77](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L77-L77) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-403](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L403) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:60-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L60-L76) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) - -**Section sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:88-91](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L88-L91) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:77-77](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L77-L77) - -### Built-in Plugins Catalog (Overview) -The following plugins are part of the built-in set. Each plugin exposes specific APIs and integrates with the appbase framework and JSON-RPC dispatcher. Consult individual plugin headers for API declarations and lifecycle hooks. - -- chain: Core blockchain database access and block/transaction acceptance. -- webserver: HTTP/WebSocket server for JSON-RPC. -- database_api: Read-only chain state queries. -- account_history: Per-account operation history. -- p2p: Peer-to-peer networking and broadcasting. -- mongo_db: MongoDB integration for archival/indexing. -- json_rpc: JSON-RPC dispatcher and method registry. -- **snapshot**: DLT mode snapshot management and P2P synchronization. -- Additional plugins include: account_by_key, auth_util, block_info, committee_api, custom_protocol_api, debug_node, follow, invite_api, network_broadcast_api, operation_history, paid_subscription_api, private_message, raw_block, social_network, tags, test_api, validator, witness_api. - -**Section sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L42) -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-43](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L43) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:179-186](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L179-L186) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:59-70](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L59-L70) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:18-32](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L18-L32) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:14-41](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L14-L41) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:42-54](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L54) - -### Plugin Development Workflow -- Template-based Creation Tool: Use the provided Python script to generate a plugin skeleton with CMake targets, API headers, and implementation stubs. -- Steps: - - Run the generator with provider and plugin name to scaffold files. - - Implement plugin lifecycle methods and register API factory in startup. - - Declare API methods and integrate with JSON-RPC. - - Build and enable the plugin via configuration. - -```mermaid -flowchart TD -A["Run newplugin.py
generator"] --> B["Generate files
plugin.hpp/cpp, api.hpp/cpp"] -B --> C["Implement plugin methods
initialize/startup/shutdown"] -C --> D["Register API factory
register_api_factory"] -D --> E["Enable plugin in config
enable-plugin"] -E --> F["Build and run node"] -``` - -**Diagram sources** -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) -- [programs/util/newplugin.py:168-173](file://programs/util/newplugin.py#L168-L173) - -**Section sources** -- [documentation/plugin.md:21-28](file://documentation/plugin.md#L21-L28) -- [programs/util/newplugin.py:225-246](file://programs/util/newplugin.py#L225-L246) - -## DLT Mode and Snapshot Integration - -### DLT Mode Overview -DLT (Distributed Ledger Technology) mode enables snapshot-based node deployments where the main block log is empty and state is managed through snapshots. This approach significantly reduces bootstrap time and storage requirements for distributed ledger applications. - -### Snapshot-Based State Management -The snapshot plugin manages DLT mode operations including: -- **State Loading**: Loads complete blockchain state from snapshot files -- **Periodic Snapshots**: Automatic snapshot creation at specified intervals -- **Snapshot Distribution**: TCP-based P2P synchronization for node bootstrap -- **State Validation**: Integrity checking and verification during snapshot operations - -```mermaid -flowchart TD -A["DLT Mode Detection"] --> B["Open Database for Snapshot Import"] -B --> C["Wipe Shared Memory"] -C --> D["Initialize Schema and Indexes"] -D --> E["Open Block Logs
Main: block_log (empty)
DLT: dlt_block_log (rolling)"] -E --> F["Load Snapshot State"] -F --> G["Ready for P2P Operations"] -``` - -**Diagram sources** -- [libraries/chain/database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [libraries/chain/database.cpp:292-292](file://libraries/chain/database.cpp#L292-L292) -- [libraries/chain/database.cpp:313-317](file://libraries/chain/database.cpp#L313-L317) - -**Section sources** -- [libraries/chain/database.cpp:281-324](file://libraries/chain/database.cpp#L281-L324) -- [libraries/chain/database.cpp:292-292](file://libraries/chain/database.cpp#L292-L292) -- [libraries/chain/database.cpp:313-317](file://libraries/chain/database.cpp#L313-L317) - -### DLT Rolling Block Log -In DLT mode, a separate rolling block log (`dlt_block_log`) serves as the primary storage for recent irreversible blocks: - -**Key Features:** -- **Offset-Aware Index**: 8-byte header storing first block number -- **Rolling Window**: Configurable size (default: 100,000 blocks) -- **Amortized Cost**: Truncation when window exceeds 2x limit -- **Fallback Mechanism**: P2P layer automatically falls back to DLT log - -**Implementation Details:** -- Same binary format as regular block_log -- Memory-mapped file access for performance -- Automatic reconstruction of corrupted indexes -- Temporary file swapping for efficient truncation - -```mermaid -classDiagram -class DLTBlockLog { -+open(file) -+append(block) -+read_block_by_num(block_num) optional -+truncate_before(new_start) -+start_block_num() uint32 -+head_block_num() uint32 -+num_blocks() uint32 -} -``` - -**Diagram sources** -- [libraries/chain/include/graphene/chain/dlt_block_log.hpp:35-72](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L72) - -**Section sources** -- [libraries/chain/include/graphene/chain/dlt_block_log.hpp:13-33](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L13-L33) -- [libraries/chain/dlt_block_log.cpp:1-200](file://libraries/chain/dlt_block_log.cpp#L1-L200) -- [libraries/chain/dlt_block_log.cpp:356-382](file://libraries/chain/dlt_block_log.cpp#L356-L382) - -### P2P Integration with DLT Mode -The P2P plugin seamlessly integrates with DLT mode through automatic fallback mechanisms: - -**Block Retrieval Flow:** -1. Check main block_log for requested block -2. If not found, check DLT block_log fallback -3. If still not found, check fork database -4. Return appropriate error if block unavailable - -**Configuration Options:** -- `dlt-block-log-max-blocks`: Rolling window size (default: 100,000) -- Automatic truncation when exceeding 2x limit -- Amortized cost distribution across block writes - -```mermaid -sequenceDiagram -participant P2P as "P2P Plugin" -participant DB as "Database" -participant BL as "Block Log" -participant DLT as "DLT Block Log" -P2P->>DB : "get_block_id_for_num(block_num)" -DB->>BL : "read_block_by_num(block_num)" -alt Block found in main log -BL-->>DB : "block_id" -DB-->>P2P : "block_id" -else Block not in main log -DB->>DLT : "read_block_by_num(block_num)" -alt Block found in DLT log -DLT-->>DB : "block_id" -DB-->>P2P : "block_id" -else Block not found anywhere -DB-->>P2P : "empty result" -end -end -``` - -**Diagram sources** -- [plugins/p2p/p2p_plugin.cpp:259-277](file://plugins/p2p/p2p_plugin.cpp#L259-L277) -- [libraries/chain/database.cpp:558-567](file://libraries/chain/database.cpp#L558-L567) -- [libraries/chain/database.cpp:596-600](file://libraries/chain/database.cpp#L596-L600) - -**Section sources** -- [libraries/chain/database.cpp:558-567](file://libraries/chain/database.cpp#L558-L567) -- [libraries/chain/database.cpp:596-600](file://libraries/chain/database.cpp#L596-L600) -- [libraries/chain/database.cpp:618-622](file://libraries/chain/database.cpp#L618-L622) - -### Snapshot P2P Synchronization -The snapshot plugin provides TCP-based synchronization for distributed deployments: - -**Protocol Features:** -- Binary request-response protocol over TCP -- Anti-spam protection (1 connection/IP, 3 connections/hour) -- Chunked transfer with progress reporting -- Integrity verification via checksums - -**Trust Model:** -- Public serving: Any IP can download snapshots -- Trusted-only serving: Only IPs from trusted list can download -- Client-side trust: Connects only to specified trusted peers - -**Section sources** -- [documentation/snapshot-plugin.md:104-164](file://documentation/snapshot-plugin.md#L104-L164) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:15-41](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L15-L41) - -## Enhanced P2P Plugin Integration with DLT Mode Awareness - -### Improved Error Handling and Logging -The P2P plugin now includes sophisticated DLT mode awareness with enhanced error handling and logging capabilities: - -**DLT Mode Detection Logic:** -- When serving blocks in DLT mode, the P2P plugin detects when block data is not available for blocks outside the DLT log range -- Instead of logging generic errors, it provides specific DLT mode context information using debug logging -- Uses debug logging (`dlog`) for DLT mode scenarios to avoid flooding error logs with expected behavior -- Maintains backward compatibility with error logging for non-DLT mode scenarios - -**Enhanced Block Serving Flow:** -1. Attempt to fetch block from main chain database -2. If block not found and DLT mode is active: - - Log specific DLT mode information using debug logging (`dlog`) - - Provide context about expected block unavailability in DLT mode - - Throw appropriate exception to indicate block unavailability -3. If not in DLT mode, log detailed error information with block ID correlation using error logging (`elog`) - -**Logging Improvements:** -- **Debug Logging**: `dlog` statements provide DLT mode context without polluting error logs -- **Error Logging**: `elog` statements provide detailed error information with block ID correlation -- **Context Information**: Both debug and error logs include block ID and expected block number context -- **Sync Block Processing**: Enhanced logging for sync block processing with better visibility into synchronization progress - -```mermaid -flowchart TD -A["Block Request Received"] --> B{"Is DLT Mode Active?"} -B --> |Yes| C["Check Main Block Log"] -B --> |No| D["Check Main Block Log"] -C --> E{"Block Found?"} -E --> |Yes| F["Return Block"] -E --> |No| G["Log DLT Context Info
dlog: 'Block ${id} not available in DLT mode'
Throw key_not_found_exception"] -D --> H{"Block Found?"} -H --> |Yes| F -H --> |No| I["Log Detailed Error
elog: 'Couldn't find block ${id}'
Include block ID correlation"] -``` - -**Diagram sources** -- [plugins/p2p/p2p_plugin.cpp:265-276](file://plugins/p2p/p2p_plugin.cpp#L265-L276) - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:265-276](file://plugins/p2p/p2p_plugin.cpp#L265-L276) - -### Enhanced Sync Block Processing Logging -The P2P plugin now provides improved logging for sync block processing with better visibility into synchronization progress: - -**Sync Block Logging Enhancements:** -- **Sync Mode Detection**: Distinguishes between sync mode and regular block processing -- **Head Block Context**: Logs current head block number alongside block processing -- **Progress Tracking**: Provides clear indication of synchronization progress -- **Performance Metrics**: Includes transaction count and validator information for non-sync blocks - -**Logging Categories:** -- **Sync Mode**: Uses `fc_ilog` with "sync" logger for synchronization operations -- **Regular Mode**: Uses standard `ilog` for normal block processing -- **Error Context**: Maintains detailed error logging with head block context - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:118-165](file://plugins/p2p/p2p_plugin.cpp#L118-L165) - -### DLT Mode Block Serving Operations -The P2P plugin now provides enhanced error handling specifically for DLT mode block serving operations: - -**Expected Behavior in DLT Mode:** -- Blocks outside the DLT log range are intentionally not available -- This is expected behavior and should not be logged as errors -- The P2P layer handles this gracefully by falling back to other peers -- Debug logging provides context without flooding error logs - -**Error Handling Strategy:** -- **DLT Mode**: Use debug logging with `dlog` to indicate expected unavailability -- **Non-DLT Mode**: Use error logging with `elog` to report unexpected failures -- **Exception Handling**: Throw appropriate exceptions to signal block unavailability -- **Context Preservation**: Maintain block ID and expected block number context in logs - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:265-276](file://plugins/p2p/p2p_plugin.cpp#L265-L276) - -### Database Integration Enhancements -The database layer provides comprehensive fallback mechanisms for DLT mode: - -**Multi-Level Block Retrieval:** -1. **TAPoS Buffer**: Fastest check for reversible blocks -2. **Main Block Log**: Irreversible blocks -3. **DLT Block Log**: Recent blocks in DLT mode -4. **Fork Database**: Alternative chain blocks - -**DLT Mode Fallback Logic:** -- Main block log fallback for DLT mode scenarios -- Automatic detection of DLT mode availability -- Graceful degradation when DLT log is empty or unavailable -- Enhanced logging for DLT mode block serving operations - -**Section sources** -- [libraries/chain/database.cpp:558-580](file://libraries/chain/database.cpp#L558-L580) -- [libraries/chain/database.cpp:599-620](file://libraries/chain/database.cpp#L599-L620) -- [libraries/chain/database.cpp:623-640](file://libraries/chain/database.cpp#L623-L640) - -## Cross-Plugin Integration: P2P and Snapshot - -### Enhanced P2P Plugin Integration with Snapshot Plugin -The P2P plugin now features enhanced integration with the snapshot plugin through automatic trusted peer endpoint registration and cross-plugin communication. - -**Integration Architecture:** -- **CMake Linking**: P2P plugin now links against the snapshot library (`graphene::snapshot`) -- **Direct Plugin Access**: P2P plugin can directly access snapshot plugin instance -- **Automatic Configuration**: P2P plugin automatically retrieves trusted peer endpoints from snapshot plugin -- **Reduced Soft-Ban Duration**: Trusted snapshot peers receive reduced soft-ban duration (5 minutes vs 1 hour) - -**Implementation Details:** -- P2P plugin searches for snapshot plugin instance during startup -- Retrieves trusted snapshot peer endpoints using `get_trusted_snapshot_peers()` API -- Registers endpoints with P2P node using `set_trusted_peer_endpoints()` -- Applies reduced soft-ban duration for registered trusted peers - -```mermaid -sequenceDiagram -participant SNAP as "Snapshot Plugin" -participant P2P as "P2P Plugin" -participant NODE as "Network Node" -SNAP->>SNAP : "parse trusted-snapshot-peer config" -SNAP->>SNAP : "store trusted endpoints" -P2P->>P2P : "plugin_startup()" -P2P->>SNAP : "find_plugin()" -SNAP-->>P2P : "snapshot plugin instance" -P2P->>SNAP : "get_trusted_snapshot_peers()" -SNAP-->>P2P : "vector trusted endpoints" -P2P->>NODE : "set_trusted_peer_endpoints(endpoints)" -NODE-->>P2P : "trusted peer endpoints registered" -P2P->>P2P : "apply reduced soft-ban (5 min)" -``` - -**Diagram sources** -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) -- [libraries/network/node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [plugins/snapshot/plugin.cpp:3039-3045](file://plugins/snapshot/plugin.cpp#L3039-L3045) -- [libraries/network/node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) - -### CMake Integration and Build System Changes -The P2P plugin's CMake configuration has been updated to enable cross-plugin functionality: - -**P2P Plugin CMake Changes:** -- Added `graphene::snapshot` to target_link_libraries -- Enables direct access to snapshot plugin APIs -- Facilitates automatic trusted peer endpoint registration -- Supports enhanced peer trust management - -**Snapshot Plugin CMake (unchanged):** -- Maintains standalone library configuration -- Provides trusted peer management functionality -- Exposes `get_trusted_snapshot_peers()` API for cross-plugin access - -**Build System Benefits:** -- Direct plugin-to-plugin communication without intermediate layers -- Reduced runtime overhead for trusted peer management -- Improved configuration consistency across plugins -- Enhanced maintainability through explicit dependencies - -**Section sources** -- [plugins/p2p/CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [plugins/snapshot/CMakeLists.txt:27-38](file://plugins/snapshot/CMakeLists.txt#L27-L38) - -### Trusted Peer Management Enhancement -The cross-plugin integration enables sophisticated trusted peer management: - -**Configuration Integration:** -- P2P plugin reads `trusted-snapshot-peer` configuration from snapshot plugin -- Automatic endpoint registration eliminates manual configuration duplication -- Consistent trust model across both plugins -- Dynamic trust management based on snapshot plugin configuration - -**Trust Enforcement Benefits:** -- Reduced soft-ban duration for verified snapshot sources (5 minutes vs 1 hour) -- Improved peer reputation management -- Enhanced security through verified snapshot peer sources -- Better resource allocation for trusted snapshot sources - -**Operational Improvements:** -- Automatic discovery of trusted snapshot peers -- Dynamic adjustment of trust levels based on peer behavior -- Enhanced monitoring and logging for trusted peer activities -- Improved network topology optimization - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) -- [libraries/network/node.cpp:5254-5274](file://libraries/network/node.cpp#L5254-L5274) - -### Type Safety Improvements in IP Address Handling - -### Enhanced Type Safety in Peer Statistics -Recent improvements to the P2P plugin include enhanced type safety in IP address handling to prevent implicit type conversion issues in peer management code. - -**The Issue**: The P2P plugin's peer statistics logging previously relied on implicit type conversions when extracting IP addresses from peer_info.host.get_address(). This could lead to unexpected behavior and type conversion errors in certain scenarios. - -**The Solution**: Implemented explicit type conversion using static_cast() to ensure reliable IP address extraction and formatting. - -**Key Changes**: -- Line 504: `ip = static_cast(peer_info.host.get_address());` -- This ensures explicit conversion from fc::ip::address to std::string -- Prevents potential implicit conversion issues and compiler warnings -- Provides consistent string formatting for IP addresses in logs - -**Impact**: -- Eliminates type conversion ambiguity in peer statistics logging -- Improves code reliability and prevents runtime errors -- Maintains backward compatibility while enhancing type safety -- Reduces potential security vulnerabilities from implicit conversions - -```mermaid -flowchart TD -A["Peer Connection Established"] --> B["Extract Peer Information"] -B --> C["Get IP Address from peer_info.host.get_address()"] -C --> D{"Type Conversion Required?"} -D --> |Yes| E["Apply static_cast()"] -D --> |No| F["Direct String Conversion"] -E --> G["Format IP Address for Logging"] -F --> G -G --> H["Output Peer Statistics"] -``` - -**Diagram sources** -- [plugins/p2p/p2p_plugin.cpp:500-508](file://plugins/p2p/p2p_plugin.cpp#L500-L508) - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:500-508](file://plugins/p2p/p2p_plugin.cpp#L500-L508) -- [thirdparty/fc/include/fc/network/ip.hpp:69-71](file://thirdparty/fc/include/fc/network/ip.hpp#L69-L71) -- [thirdparty/fc/src/network/ip.cpp:35-39](file://thirdparty/fc/src/network/ip.cpp#L35-L39) - -### IP Address Type System -The underlying fc::ip::address and fc::ip::endpoint classes provide a robust type system for network address handling: - -**Address Class Features**: -- Implicit conversion operators for different types -- String conversion via operator std::string() -- Numeric conversion via operator uint32_t() -- Range checking for private/public/multicast addresses - -**Endpoint Class Features**: -- Composite address and port management -- String parsing from "IP:PORT" format -- Comparison operators for sorting and matching -- Port extraction and manipulation - -**Type Safety Benefits**: -- Compile-time type checking prevents misuse -- Clear separation between address and endpoint types -- Safe conversion between string and numeric representations -- Consistent behavior across different network operations - -**Section sources** -- [thirdparty/fc/include/fc/network/ip.hpp:12-87](file://thirdparty/fc/include/fc/network/ip.hpp#L12-L87) -- [thirdparty/fc/src/network/ip.cpp:14-87](file://thirdparty/fc/src/network/ip.cpp#L14-L87) - -### Network Integration Points -The enhanced type safety extends throughout the network layer: - -**Peer Connection Integration**: -- Peer connections store fc::ip::endpoint for remote addresses -- Node implementation extracts endpoints for statistics reporting -- Message handling maintains type-safe address information -- Firewall and NAT detection uses proper endpoint types - -**Message Protocol Integration**: -- Hello messages exchange endpoint information -- Address broadcasting maintains type safety -- Connection establishment preserves endpoint integrity -- Peer discovery protocols use consistent address formats - -**Section sources** -- [libraries/network/peer_connection.hpp:109-110](file://libraries/network/peer_connection.hpp#L109-L110) -- [libraries/network/node.cpp:4900-4903](file://libraries/network/node.cpp#L4900-L4903) -- [libraries/network/core_messages.hpp:333-345](file://libraries/network/core_messages.hpp#L333-L345) - -## Dependency Analysis -Plugins declare explicit dependencies using APPBASE_PLUGIN_REQUIRES. The JSON-RPC plugin is a central dependency for most plugins that expose APIs. The Chain plugin is often required by stateful plugins. **Enhanced** with cross-plugin integration patterns. - -```mermaid -graph LR -JSON["json_rpc::plugin"] --> CHAIN["chain::plugin"] -JSON --> WEB["webserver::plugin"] -JSON --> DBAPI["database_api::plugin"] -JSON --> AHIST["account_history::plugin"] -CHAIN --> P2P["p2p::plugin"] -CHAIN --> MONGO["mongo_db::plugin"] -CHAIN --> SNAP["snapshot::plugin"] -P2P --> DLT["dlt_block_log"] -SNAP --> DLT -P2P --> TYPESAFE["Type Safety Enhancements"] -P2P --> CROSSPLUGIN["Cross-Plugin Integration
Snapshot Trust Management"] -SNAP --> TRUSTEDPEERS["Trusted Peer Management
Automatic Endpoint Registration"] -``` - -**Diagram sources** -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:84-118](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L84-L118) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-24](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp:32-38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L38) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:188-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:61-65](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L61-L65) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:20-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:17-19](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:44-44](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L44-L44) -- [libraries/chain/include/graphene/chain/dlt_block_log.hpp:35-35](file://libraries/chain/include/graphene/chain/dlt_block_log.hpp#L35-L35) -- [plugins/p2p/CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -**Section sources** -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:21-24](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L21-L24) -- [plugins/database_api/include/graphene/plugins/database_api/plugin.hpp:188-191](file://plugins/database_api/include/graphene/plugins/database_api/plugin.hpp#L188-L191) -- [plugins/account_history/include/graphene/plugins/account_history/plugin.hpp:61-65](file://plugins/account_history/include/graphene/plugins/account_history/plugin.hpp#L61-L65) -- [plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp:20-20](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L20-L20) -- [plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp:17-19](file://plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_plugin.hpp#L17-L19) -- [plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp:44-44](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L44-L44) -- [plugins/p2p/CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) - -## Plugin Deprecation Status and Maintenance Practices - -### Deprecation Overview -The VIZ blockchain platform maintains strict deprecation policies for operations and plugins that are no longer supported. Understanding deprecation status is crucial for maintaining compatibility and avoiding runtime errors. - -### Deprecated Operations -Several blockchain operations have been deprecated as part of hardfork implementations: - -#### Hardfork 4 Deprecations -- **vote_operation**: Voting operations are deprecated as of Hardfork 4 -- **content_operation**: Content creation/update operations are deprecated as of Hardfork 4 -- **delete_content_operation**: Content deletion operations are deprecated as of Hardfork 4 - -These operations are explicitly marked as deprecated in the operations header and validated in chain evaluators with hardfork checks. - -**Section sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp:14-27](file://libraries/protocol/include/graphene/protocol/operations.hpp#L14-L27) -- [libraries/chain/chain_evaluator.cpp:216-216](file://libraries/chain/chain_evaluator.cpp#L216-L216) -- [libraries/chain/chain_evaluator.cpp:551-551](file://libraries/chain/chain_evaluator.cpp#L551-L551) -- [libraries/chain/chain_evaluator.cpp:1296-1296](file://libraries/chain/chain_evaluator.cpp#L1296-L1296) - -### Plugin Configuration Deprecations -Several plugin configuration options have been deprecated in favor of newer alternatives: - -#### P2P Plugin Deprecations -- **seed-node**: Deprecated in favor of `p2p-seed-node` -- **force-validate**: Deprecated in favor of `p2p-force-validate` - -Both deprecations emit warnings during plugin initialization and support graceful migration by accepting both old and new option formats. - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:499-528](file://plugins/p2p/p2p_plugin.cpp#L499-L528) - -#### Debug Node Plugin Deprecations -- **edit-script**: Deprecated in favor of `debug-node-edit-script` - -The debug node plugin maintains backward compatibility by logging warnings and merging deprecated options with their modern equivalents. - -**Section sources** -- [plugins/debug_node/plugin.cpp:124-128](file://plugins/debug_node/plugin.cpp#L124-L128) - -### Maintenance Best Practices - -#### Migration Strategies -1. **Configuration Migration**: Replace deprecated configuration options with their modern equivalents -2. **Operation Updates**: Update client applications to use supported alternatives -3. **Plugin Updates**: Monitor plugin deprecation notices and migrate to maintained alternatives -4. **DLT Mode Adoption**: Consider migrating to DLT mode for improved performance and reduced storage requirements -5. **Type Safety Updates**: Ensure all IP address handling uses explicit type conversion for reliability -6. **Cross-Plugin Integration**: Leverage enhanced P2P-snapshot integration for improved peer trust management - -#### Monitoring Deprecation Warnings -Plugins emit warnings when deprecated features are detected: -- P2P plugin logs warnings for deprecated seed-node and force-validate options -- Debug node plugin logs warnings for deprecated edit-script option -- Chain evaluators enforce hardfork-based operation deprecations - -#### Testing and Validation -- Test with deprecated operations to identify compatibility issues -- Monitor warning logs for deprecated feature usage -- Validate migration paths before hardfork activation -- Test DLT mode configurations for proper snapshot and block log operation -- Verify type safety improvements in IP address handling -- **Test cross-plugin integration**: Validate P2P-snapshot integration for trusted peer management -- **Verify CMake linking**: Ensure P2P plugin can access snapshot plugin APIs - -### Practical Examples - -#### Handling Deprecated P2P Configuration -```ini -# Deprecated (will show warning) -seed-node = 192.168.0.1:4243 - -# Recommended approach -p2p-seed-node = 192.168.0.1:4243 -``` - -#### Managing Deprecated Operations -When encountering deprecation errors: -1. Check current hardfork status using chain operations -2. Update client applications to use supported alternatives -3. Monitor deprecation warnings in plugin logs - -#### DLT Mode Configuration Example -```ini -# Enable DLT mode with snapshot support -plugin = snapshot -snapshot-every-n-blocks = 100000 -snapshot-dir = /var/lib/vizd/snapshots -dlt-block-log-max-blocks = 100000 - -# Configure P2P for DLT mode -plugin = p2p - -# Configure trusted snapshot peers for enhanced integration -trusted-snapshot-peer = 192.168.1.100:8093 -trusted-snapshot-peer = 192.168.1.101:8093 -``` - -**Section sources** -- [plugins/p2p/p2p_plugin.cpp:499-528](file://plugins/p2p/p2p_plugin.cpp#L499-L528) -- [plugins/debug_node/plugin.cpp:124-128](file://plugins/debug_node/plugin.cpp#L124-L128) -- [libraries/chain/chain_evaluator.cpp:216-216](file://libraries/chain/chain_evaluator.cpp#L216-L216) - -## Performance Considerations -- JSON-RPC Overhead: Each request incurs serialization/deserialization and method dispatch overhead. Batch requests and minimize unnecessary API calls. -- Database Access: Heavy queries against the chain database should be cached or paginated to avoid latency spikes. -- Threading Model: Webserver runs on its own io_service thread to isolate HTTP processing from other plugins. -- Signal Usage: Prefer signals for lightweight coordination; avoid heavy computation inside connected slots. -- Storage Backends: Plugins like mongo_db introduce additional write amplification; tune indexing and batching strategies. -- **DLT Mode Benefits**: Snapshot-based nodes eliminate block log storage requirements and enable instant bootstrap times. -- **DLT Mode Overhead**: Rolling block log requires additional disk I/O for recent block storage and truncation operations. -- **Enhanced Error Handling**: Improved logging reduces error noise while providing better context information for debugging. -- **Maintenance Impact**: Deprecated plugins may have reduced performance due to compatibility layers and should be migrated to supported alternatives. -- **Sync Block Processing**: Enhanced logging provides better visibility into synchronization progress without impacting performance. -- **Type Safety Improvements**: Explicit type conversion adds minimal overhead while preventing runtime errors and improving reliability. -- **Cross-Plugin Integration**: **Enhanced** with minimal overhead for trusted peer management through direct plugin access. -- **CMake Integration**: Linking against snapshot library enables efficient cross-plugin communication without runtime overhead. - -## Troubleshooting Guide -- Plugin Not Found: - - Ensure the plugin directory exists and contains a CMakeLists.txt; the build system enumerates subdirectories. -- API Not Available: - - Verify the plugin is enabled and public-api is configured if exposing public endpoints. - - Confirm the plugin registered its API factory during startup. -- Replay Required: - - Some plugins maintain persistent records; disabling/enabling them may require a replay. -- Authentication: - - Use api-user to protect sensitive APIs. -- **DLT Mode Issues**: - - Verify snapshot files exist and are accessible - - Check DLT block log configuration and permissions - - Monitor rolling window truncation logs - - Validate P2P fallback to DLT block log - - **Enhanced Error Handling**: Check debug logs for DLT mode context information - - **DLT Mode Logging**: Look for specific DLT mode debug messages indicating expected block unavailability - - **Sync Block Processing**: Monitor sync mode logging for better visibility into synchronization progress -- **Deprecation Issues**: - - Check for deprecation warnings in plugin logs - - Review deprecated operations and migrate to supported alternatives - - Update configuration options to use non-deprecated values - - Monitor hardfork compliance for operation usage -- **Type Safety Issues**: - - Verify IP address handling uses explicit type conversion - - Check for compilation errors related to implicit type conversions - - Ensure peer statistics logging displays correct IP addresses - - Validate network connectivity and address resolution -- **Cross-Plugin Integration Issues**: - - **P2P-Snapshot Integration**: Verify snapshot plugin is loaded before P2P plugin - - **Trusted Peer Registration**: Check that `trusted-snapshot-peer` configuration is properly parsed - - **CMake Linking**: Ensure P2P plugin links against snapshot library - - **Plugin Access**: Verify direct plugin access functionality works correctly - - **Soft-Ban Duration**: Confirm trusted peers receive reduced soft-ban duration - -**Section sources** -- [documentation/plugin.md:11-20](file://documentation/plugin.md#L11-L20) -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [plugins/p2p/p2p_plugin.cpp:499-528](file://plugins/p2p/p2p_plugin.cpp#L499-L528) -- [plugins/debug_node/plugin.cpp:124-128](file://plugins/debug_node/plugin.cpp#L124-L128) -- [libraries/chain/database.cpp:292-292](file://libraries/chain/database.cpp#L292-L292) -- [plugins/p2p/CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -## Conclusion -The VIZ C++ Node plugin system leverages appbase to deliver a modular, extensible architecture. Plugins integrate seamlessly through JSON-RPC, share the chain database, and coordinate via signals. The template-based development tool accelerates custom plugin creation, while configuration options govern exposure and security. With 40+ built-in plugins spanning core blockchain functionality to specialized integrations, the system supports diverse use cases from public APIs to archival pipelines. - -**Updated** The system now includes comprehensive DLT mode support with snapshot-based state management, rolling block log integration, and P2P layer compatibility. The enhanced P2P plugin integration with DLT mode awareness provides improved error handling and logging capabilities for DLT mode block serving operations, featuring sophisticated debug logging for DLT mode scenarios, enhanced sync block processing visibility, and better synchronization progress monitoring. Recent improvements include enhanced type safety in IP address handling using explicit type conversion to prevent implicit type conversion issues in peer management code, further improving the reliability and maintainability of the plugin system. **Cross-plugin integration** has been significantly enhanced with the P2P plugin's ability to automatically register trusted peer endpoints from the snapshot plugin, improving peer trust management and reducing soft-ban durations for verified snapshot sources through direct plugin access and CMake-based linking. - -## Appendices - -### Appendix A: Plugin Lifecycle Reference -- Discovery: Build system scans plugins directory and sets available plugin list. -- Initialization: plugin_initialize parses options and prepares state. -- Startup: plugin_startup registers APIs and connects to chain/database signals. -- Shutdown: plugin_shutdown tears down connections and cleans up. - -**Section sources** -- [plugins/CMakeLists.txt:1-12](file://plugins/CMakeLists.txt#L1-L12) -- [plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp:103-107](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp#L103-L107) -- [plugins/chain/include/graphene/plugins/chain/plugin.hpp:36-42](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp#L36-L42) - -### Appendix B: Configuration Options -- enable-plugin: Comma-separated list of plugin names to activate. -- public-api: Comma-separated list of public API names to expose. -- api-user: Username/password protection for APIs. -- **DLT Mode Options**: - - `dlt-block-log-max-blocks`: Rolling window size for DLT block log (default: 100,000) - - `snapshot-at-block`: Create snapshot at specific block number - - `snapshot-every-n-blocks`: Create periodic snapshots (0 = disabled) - - `snapshot-dir`: Directory for auto-generated snapshots -- **Deprecated Options**: seed-node (use p2p-seed-node), force-validate (use p2p-force-validate), edit-script (use debug-node-edit-script). -- **Type Safety Options**: Enhanced IP address handling with explicit type conversion for reliable peer management. -- **Cross-Plugin Integration Options**: - - `trusted-snapshot-peer`: IP:port pairs of trusted snapshot sources for P2P integration - - Enables automatic trusted peer endpoint registration and reduced soft-ban duration - -**Section sources** -- [documentation/plugin.md:11-20](file://documentation/plugin.md#L11-L20) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [plugins/p2p/p2p_plugin.cpp:499-528](file://plugins/p2p/p2p_plugin.cpp#L499-L528) -- [plugins/debug_node/plugin.cpp:124-128](file://plugins/debug_node/plugin.cpp#L124-L128) -- [documentation/snapshot-plugin.md:142-164](file://documentation/snapshot-plugin.md#L142-L164) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) - -### Appendix C: Deprecation Timeline -- Hardfork 4: vote_operation, content_operation, delete_content_operation deprecated -- Future Hardforks: Monitor operation deprecation notices and prepare migration plans -- Plugin Deprecations: Regular review and replacement of deprecated plugin functionality -- **DLT Mode Introduction**: Snapshot-based DLT mode with rolling block log support -- **Enhanced P2P Integration**: Improved DLT mode awareness with sophisticated error handling and logging -- **Sync Block Processing**: Enhanced logging for better synchronization progress visibility -- **Type Safety Improvements**: Enhanced IP address handling with explicit type conversion for reliability -- **Cross-Plugin Integration**: **Enhanced** with P2P plugin linking against snapshot library and automatic trusted peer registration - -**Section sources** -- [libraries/protocol/include/graphene/protocol/operations.hpp:14-27](file://libraries/protocol/include/graphene/protocol/operations.hpp#L14-L27) -- [libraries/chain/chain_evaluator.cpp:216-216](file://libraries/chain/chain_evaluator.cpp#L216-L216) -- [libraries/chain/chain_evaluator.cpp:551-551](file://libraries/chain/chain_evaluator.cpp#L551-L551) -- [libraries/chain/chain_evaluator.cpp:1296-1296](file://libraries/chain/chain_evaluator.cpp#L1296-L1296) -- [libraries/chain/database.cpp:292-292](file://libraries/chain/database.cpp#L292-L292) -- [plugins/p2p/CMakeLists.txt:27-34](file://plugins/p2p/CMakeLists.txt#L27-L34) -- [plugins/p2p/p2p_plugin.cpp:688-697](file://plugins/p2p/p2p_plugin.cpp#L688-L697) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Plugin System/Snapshot Plugin System.md b/.qoder/repowiki/en/content/Plugin System/Snapshot Plugin System.md deleted file mode 100644 index 06cad90dd7..0000000000 --- a/.qoder/repowiki/en/content/Plugin System/Snapshot Plugin System.md +++ /dev/null @@ -1,1602 +0,0 @@ -# Snapshot Plugin System - - -**Referenced Files in This Document** -- [plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [plugin.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp) -- [snapshot_types.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp) -- [snapshot_serializer.hpp](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp) -- [CMakeLists.txt](file://plugins/snapshot/CMakeLists.txt) -- [snapshot.json](file://share/vizd/snapshot.json) -- [snapshot-testnet.json](file://share/vizd/snapshot-testnet.json) -- [snapshot-plugin.md](file://documentation/snapshot-plugin.md) -- [plugin.cpp](file://plugins/chain/plugin.cpp) -- [plugin.hpp](file://plugins/chain/include/graphene/plugins/chain/plugin.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [dlt_block_log.cpp](file://libraries/chain/dlt_block_log.cpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [file_mutex.cpp](file://thirdparty/fc/src/interprocess/file_mutex.cpp) -- [config.ini](file://share/vizd/config/config.ini) -- [node.cpp](file://libraries/network/node.cpp) -- [node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [p2p_plugin.cpp](file://plugins/p2p/p2p_plugin.cpp) -- [logger_config.cpp](file://thirdparty/fc/src/log/logger_config.cpp) -- [console_appender.cpp](file://thirdparty/fc/src/log/console_appender.cpp) -- [chainbase.cpp](file://thirdparty/chainbase/src/chainbase.cpp) - - -## Update Summary -**Changes Made** -- Added comprehensive stale snapshot detection feature that automatically identifies snapshots older than DLT block log start -- Implemented urgent fresh snapshot creation to prevent sync gaps when downloading nodes would have missing blocks -- Enhanced DLT mode recovery capabilities with intelligent gap detection and automatic snapshot regeneration -- Improved snapshot validation logic to prevent serving broken snapshots with gaps -- Fixed snapshot path propagation: snapshot path is now passed correctly into the async load callback (was empty before) -- Fixed initialization order in snapshot plugin startup to avoid accessing uninitialized state -- Fixed P2P resume after async snapshot task: `_block_processing_paused` flag and P2P catchup flag are now reliably reset even when the async task completes on a non-P2P thread - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Asynchronous Snapshot Creation](#asynchronous-snapshot-creation) -7. [validator-Aware Deferral Mechanism](#validator-aware-deferral-mechanism) -8. [Enhanced Error Handling](#enhanced-error-handling) -9. [Automatic Snapshot Discovery](#automatic-snapshot-discovery) -10. [Integrated Recovery Workflow](#integrated-recovery-workflow) -11. [DLT Replay Integration](#dlt-replay-integration) -12. [Signal-Based DLT Block Log Reset Handling](#signal-based-dlt-block-log-reset-handling) -13. [Peer-to-Peer Snapshot Synchronization](#peer-to-peer-snapshot-synchronization) -14. [Enhanced P2P Integration with Trusted Peers](#enhanced-p2p-integration-with-trusted-peers) -15. [Watchdog and Stalled Sync Detection](#watchdog-and-stalled-sync-detection) -16. [P2P Stale Sync Detection](#p2p-stale-sync-detection) -17. [Emergency Consensus Handling](#emergency-consensus-handling) -18. [Enhanced Anti-Spam Protection](#enhanced-anti-spam-protection) -19. [Access Control and Security Mechanisms](#access-control-and-security-mechanisms) -20. [Integration with Chain Plugin](#integration-with-chain-plugin) -21. [Dependency Analysis](#dependency-analysis) -22. [Performance Considerations](#performance-considerations) -23. [Troubleshooting Guide](#troubleshooting-guide) -24. [Conclusion](#conclusion) - -## Introduction - -The Snapshot Plugin System is a comprehensive solution for VIZ blockchain nodes that enables efficient state synchronization through distributed ledger technology (DLT). This system provides mechanisms for creating, loading, serving, and downloading blockchain state snapshots, significantly reducing bootstrap times and enabling rapid node initialization. - -**Updated** The system has been enhanced with comprehensive snapshot plugin configuration supporting multiple trusted snapshot peers, snapshot scheduling parameters, serving options, watchdog monitoring, automatic snapshot discovery, integrated recovery workflow, enhanced anti-spam protection, **signal-based DLT block log reset handling**, **enhanced P2P integration with trusted peers**, **enhanced error handling for snapshot download operations**, **improved undo stack management during snapshot loading**, and **stale snapshot detection**. These enhancements provide robust error handling for recovery scenarios, automatic peer-to-peer snapshot synchronization for empty state nodes, **automatic registration of trusted peer endpoints with the P2P layer**, **advanced watchdog mechanisms for DLT mode operation**, **automatic snapshot creation during DLT block log reset scenarios**, and **intelligent gap detection to prevent sync gaps when serving snapshots**. - -The plugin addresses the fundamental challenge of blockchain bootstrapping by allowing nodes to jump directly to a recent state rather than replaying thousands of blocks. This is particularly crucial for VIZ's social media and content platform characteristics, where rapid deployment and scaling are essential. - -## Project Structure - -The snapshot plugin is organized within the VIZ C++ node codebase following a modular architecture: - -```mermaid -graph TB -subgraph "Plugin Structure" -A[snapshot/] --> B[include/] -A --> C[source/] -B --> D[plugin.hpp] -B --> E[snapshot_types.hpp] -B --> F[snapshot_serializer.hpp] -C --> G[plugin.cpp] -end -subgraph "Configuration" -H[share/vizd/] --> I[snapshot.json] -H --> J[snapshot-testnet.json] -H --> K[config.ini] -L[documentation/] --> M[snapshot-plugin.md] -end -subgraph "Build System" -N[CMakeLists.txt] --> O[Target: graphene_snapshot] -O --> P[Dependencies] -P --> Q[graphene_chain] -P --> R[appbase] -P --> S[chainbase] -P --> T[fc] -end -D --> G -E --> G -F --> G -``` - -**Diagram sources** -- [plugin.cpp:1-50](file://plugins/snapshot/plugin.cpp#L1-L50) -- [plugin.hpp:1-88](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L1-L88) -- [snapshot_types.hpp:1-52](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp#L1-L52) -- [CMakeLists.txt:1-52](file://plugins/snapshot/CMakeLists.txt#L1-L52) - -**Section sources** -- [plugin.cpp:1-50](file://plugins/snapshot/plugin.cpp#L1-L50) -- [CMakeLists.txt:1-52](file://plugins/snapshot/CMakeLists.txt#L1-L52) - -## Core Components - -The snapshot plugin consists of several interconnected components that work together to provide comprehensive state synchronization capabilities: - -### Modular Layer Architecture -The plugin has been refactored into distinct functional layers: - -#### Interface Layer -The main plugin class provides the primary interface for external systems to interact with the snapshot functionality. It implements the appbase plugin interface and exposes methods for loading and creating snapshots programmatically. - -#### Serialization Engine Layer -A sophisticated serialization system handles the conversion of blockchain state objects to/from compressed JSON format. This engine manages different object types with varying memory layouts and special data structures. - -#### Network Protocol Layer -The plugin implements a custom TCP protocol for peer-to-peer snapshot distribution, including message framing, authentication, and transfer optimization. Enhanced with comprehensive access control mechanisms and denial reasons. - -#### Database Integration Layer -Deep integration with the VIZ blockchain database ensures seamless state transitions and maintains consistency during snapshot operations. - -#### Recovery Workflow Layer -**New** Comprehensive recovery workflow integration with DLT replay capabilities, automatic snapshot discovery, and enhanced error handling for recovery scenarios. - -#### Asynchronous Execution Layer -**New** Dedicated thread-based asynchronous execution system that prevents snapshot creation from blocking main thread operations and causing read-lock timeouts. - -#### Watchdog Monitoring Layer -**New** Comprehensive watchdog system that monitors server health and automatically restarts dead accept loops to ensure continuous operation. - -#### **Signal-Based DLT Block Log Reset Handling Layer** -**New** Advanced integration with DLT block log reset events that automatically schedules fresh snapshot creation for other DLT nodes to bootstrap from, providing seamless network recovery and state synchronization. - -#### **Enhanced P2P Integration Layer** -**New** Advanced integration with the P2P layer that automatically registers trusted peer endpoints for reduced soft-ban duration, enabling trusted peers to receive 5-minute bans instead of the default 1-hour duration. - -#### **Enhanced Logging Layer** -**New** Comprehensive logging system with ANSI color codes for improved visibility and debugging capabilities across different log levels. - -#### **P2P Stale Sync Detection Layer** -**New** Lightweight recovery mechanism that automatically detects and recovers from network stalls without requiring snapshot downloads, resetting sync from LIB and reconnecting peers. - -#### **Dedicated Threading for Stalled Sync Detection** -**New** Dedicated fc::thread instance for stalled sync detection operations, preventing fc fibers from stalling on main thread blocked in io_serv->run(). - -#### **Automatic Gap Detection for DLT Block Log Initialization** -**New** Intelligent gap detection and automatic reset logic that prevents index position mismatch assertions during DLT block log initialization after snapshot imports, ensuring seamless state synchronization. - -#### **Enhanced Error Handling for Snapshot Download Operations** -**New** Comprehensive error handling around snapshot download operations within the check_stalled_sync_loop method, ensuring stalled sync monitoring continues running even when snapshot loading fails. - -#### **Improved Undo Stack Management** -**New** Enhanced undo stack management in load_snapshot method by adding proper undo stack management with db.undo_all() call before set_revision operations, ensuring proper database state cleanup. - -#### **Enhanced Exception Handling** -**New** Enhanced exception handling for both fc::exception and std::exception types during snapshot download attempts, providing robust error recovery mechanisms. - -#### **Stale Snapshot Detection Layer** -**New** Intelligent stale snapshot detection system that automatically identifies snapshots older than DLT block log start and schedules urgent fresh snapshot creation to prevent sync gaps when downloading nodes would encounter missing blocks. - -**Updated** The modular architecture provides enhanced extensibility and maintainability through clear separation of concerns between interface, serialization, network, database, recovery, asynchronous execution, watchdog, **signal-based DLT block log reset handling**, **enhanced P2P integration**, **enhanced error handling**, **improved undo stack management**, and **stale snapshot detection** components. The recent additions include asynchronous snapshot creation, validator-aware deferral, watchdog mechanisms, automatic snapshot discovery, integrated recovery workflow, comprehensive error handling, **signal-based DLT block log reset handling**, **enhanced P2P integration with trusted peer support**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **automatic gap detection for DLT block log initialization**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **enhanced exception handling**, and **stale snapshot detection**. - -**Section sources** -- [plugin.hpp:42-76](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L42-L76) -- [snapshot_types.hpp:16-52](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp#L16-L52) -- [snapshot_serializer.hpp:30-158](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp#L30-L158) - -## Architecture Overview - -The snapshot plugin follows a layered architecture designed for modularity and extensibility: - -```mermaid -graph TB -subgraph "Application Layer" -A[CLI Commands] --> B[Plugin Interface] -C[Configuration] --> B -D[Recovery Mode] --> B -end -subgraph "Plugin Core" -B --> E[Serialization Engine] -B --> F[Network Protocol] -B --> G[Database Manager] -B --> H[Recovery Workflow] -B --> I[Async Execution Engine] -B --> J[Watchdog Monitor] -B --> K[P2P Integration Layer] -B --> L[Enhanced Logging System] -B --> M[P2P Stale Sync Detection] -B --> N[Signal-Based DLT Reset Handler] -B --> O[Dedicated Threading for Stalled Sync] -B --> P[Automatic Gap Detection for DLT] -B --> Q[Enhanced Error Handling] -B --> R[Improved Undo Stack Management] -B --> S[Stale Snapshot Detection] -end -subgraph "Security Layer" -F --> T[Access Control] -T --> U[Trust Enforcement] -T --> V[Anti-Spam Protection] -end -subgraph "Serialization Layer" -E --> W[Object Exporter] -E --> X[Object Importer] -W --> Y[JSON Serializer] -X --> Z[Object Constructor] -end -subgraph "Network Layer" -F --> AA[TCP Server] -F --> AB[TCP Client] -AA --> AC[Connection Management] -AB --> AD[Peer Discovery] -end -subgraph "Database Layer" -G --> AE[Chainbase Integration] -G --> AF[Fork Database] -AE --> AG[Object Indexes] -AF --> AH[Block Validation] -end -subgraph "Storage Layer" -Y --> AI[File System] -Z --> AI -AI --> AJ[Snapshot Files] -end -subgraph "Recovery Layer" -H --> AK[DLT Replay Engine] -H --> AL[Automatic Discovery] -H --> AM[Error Handling] -AK --> AN[Block Log Integration] -AL --> AO[Peer Synchronization] -AM --> AP[Diagnostic Tools] -end -subgraph "Reliability Layer" -AA --> AQ[Watchdog Mechanism] -AQ --> AR[Dedicated Server Thread] -AQ --> AS[Stalled Sync Detection] -I --> AT[Dedicated Snapshot Thread] -I --> AU[Async Snapshot Guard] -O --> AV[Dedicated Stalled Sync Thread] -O --> AW[Stalled Sync Operations] -K --> AX[Trusted Peer Registration] -K --> AY[Soft-Ban Duration Management] -L --> AZ[ANSI Color Codes] -L --> BA[Level-Based Coloring] -M --> BB[LIB Reset Mechanism] -M --> BC[Peer Reconnection] -M --> BD[Seed Node Management] -N --> BE[DLT Reset Signal Handling] -N --> BF[Automatic Snapshot Scheduling] -P --> BG[Index Position Mismatch Prevention] -P --> BH[Gap Detection Logic] -Q --> BI[Enhanced Exception Handling] -R --> BJ[Undo Stack Management] -S --> BK[Gap Detection Logic] -S --> BL[Urgent Fresh Snapshot Creation] -``` - -**Updated** The architecture emphasizes separation of concerns with clear boundaries between serialization, networking, database operations, security controls, recovery workflows, asynchronous execution, watchdog monitoring, **signal-based DLT block log reset handling**, **enhanced P2P integration**, **enhanced error handling**, **improved undo stack management**, and **stale snapshot detection**. The modular design enables independent development and testing of each component while maintaining system coherence. Recent enhancements include integrated recovery workflow, DLT replay integration, automatic snapshot discovery, comprehensive watchdog mechanisms, asynchronous execution system, enhanced error handling, **signal-based DLT block log reset handling**, **enhanced P2P integration with trusted peer support**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **automatic gap detection for DLT block log initialization**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **enhanced exception handling**, and **stale snapshot detection**. - -**Diagram sources** -- [plugin.cpp:675-780](file://plugins/snapshot/plugin.cpp#L675-L780) -- [snapshot_serializer.hpp:37-107](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp#L37-L107) - -**Section sources** -- [plugin.cpp:675-780](file://plugins/snapshot/plugin.cpp#L675-L780) -- [snapshot_serializer.hpp:37-107](file://plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp#L37-L107) - -## Detailed Component Analysis - -### Snapshot Creation and Management - -The snapshot creation process involves comprehensive state serialization with careful handling of different object types: - -```mermaid -sequenceDiagram -participant CLI as CLI Interface -participant Plugin as Snapshot Plugin -participant DB as Database -participant Serializer as Serializer -participant FileSys as File System -CLI->>Plugin : create_snapshot(path) -Plugin->>Plugin : schedule_async_snapshot() -Plugin->>Plugin : snapshot_thread->async() -Plugin->>DB : with_strong_read_lock() -DB-->>Plugin : locked_access -Plugin->>Serializer : serialize_state() -loop For each object type -Serializer->>DB : get_index(type) -DB-->>Serializer : object_iterator -Serializer->>Serializer : to_variant() -end -Serializer-->>Plugin : state_json -Plugin->>Plugin : compute_checksum() -Plugin->>FileSys : write_compressed_file() -FileSys-->>Plugin : success -Plugin-->>CLI : completion_status -``` - -**Updated** The creation process handles over 30 different object types, from critical singleton objects to optional metadata. Each object type receives specialized treatment based on its memory layout and data structure complexity, demonstrating the modular architecture's flexibility. The recent enhancements include validator-aware deferral to prevent missed block production slots, improved anti-spam protection, integrated recovery workflow capabilities, asynchronous execution system that prevents read-lock timeouts for API and P2P threads, **signal-based DLT block log reset handling**, **dedicated threading for stalled sync detection**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, and **enhanced P2P integration with automatic trusted peer endpoint registration**. - -**Diagram sources** -- [plugin.cpp:885-987](file://plugins/snapshot/plugin.cpp#L885-L987) -- [plugin.cpp:789-883](file://plugins/snapshot/plugin.cpp#L789-L883) -- [plugin.cpp:1400-1484](file://plugins/snapshot/plugin.cpp#L1400-L1484) - -### Snapshot Loading and Validation - -Snapshot loading implements rigorous validation and reconstruction procedures with enhanced memory management and improved error handling: - -```mermaid -flowchart TD -Start([Load Snapshot]) --> ReadFile["Read Compressed File"] -ReadFile --> Decompress["Decompress Zlib"] -Decompress --> ParseJSON["Parse JSON Header"] -ParseJSON --> ValidateVersion["Validate Format Version"] -ValidateVersion --> CheckChainID["Verify Chain ID"] -CheckChainID --> ChecksumVerify["Verify Payload Checksum"] -ChecksumVerify --> ClearGenesis["Clear Genesis Objects"] -ClearGenesis --> ImportSingletons["Import Singleton Objects"] -ImportSingletons --> ImportCritical["Import Critical Objects"] -ImportCritical --> ImportImportant["Import Important Objects"] -ImportImportant --> ImportOptional["Import Optional Objects"] -ImportOptional --> UndoAll["db.undo_all() - Clear Undo Stack"] -UndoAll --> SetRevision["Set Database Revision"] -SetRevision --> SeedForkDB["Seed Fork Database"] -SeedForkDB --> PromoteLIB["Promote LIB to Head Block"] -PromoteLIB --> Complete([Load Complete]) -``` - -**Updated** The loading process includes extensive validation steps to ensure data integrity and compatibility with the current node configuration, showcasing the robustness of the modular design. Recent improvements include enhanced LIB promotion for DLT mode, improved fork database seeding for reliable P2P synchronization, integrated recovery workflow integration, comprehensive error handling for unlinkable_block_exception scenarios, comprehensive object clearing for hot-reload scenarios, **improved undo stack management with proper cleanup before set_revision operations**, **enhanced error handling for snapshot download operations**, **enhanced exception handling for both fc::exception and std::exception types**, **stale snapshot detection with gap prevention**, and **enhanced P2P integration with automatic trusted peer endpoint registration**. - -**Diagram sources** -- [plugin.cpp:1046-1288](file://plugins/snapshot/plugin.cpp#L1046-L1288) - -### Network Protocol Implementation - -The snapshot protocol provides efficient peer-to-peer distribution with robust error handling and comprehensive access control: - -```mermaid -sequenceDiagram -participant Client as Client Node -participant Server as Server Node -participant AntiSpam as Anti-Spam -participant Security as Security Layer -Client->>Server : SNAPSHOT_INFO_REQUEST -Server->>Security : Check Trust Status -Security-->>Server : Trusted/Untrusted -alt Untrusted IP -Server->>Client : SNAPSHOT_ACCESS_DENIED (untrusted) -else Trusted IP -Server->>AntiSpam : Check Rate Limits -AntiSpam-->>Server : Allow/Deny -alt Rate Limit Exceeded -Server->>Client : SNAPSHOT_ACCESS_DENIED (rate_limited) -else Within Limits -Server->>Server : Check Session Limits -alt Too Many Active Sessions -Server->>Client : SNAPSHOT_ACCESS_DENIED (session_limit) -else Within Session Limits -Server->>Server : Check Concurrent Connections -alt Max Connections Reached -Server->>Client : SNAPSHOT_ACCESS_DENIED (max_connections) -else Within Connection Limits -Server->>Server : Find Latest Snapshot -Server-->>Client : SNAPSHOT_INFO_REPLY -Client->>Server : SNAPSHOT_DATA_REQUEST(offset, size) -loop Until Complete -Server->>Server : Read Chunk -Server-->>Client : SNAPSHOT_DATA_REPLY -Client->>Server : Next Request -end -end -end -end -Note over Client,Server : Connection Closed -``` - -**Updated** The protocol includes sophisticated anti-spam protection mechanisms, trust enforcement, and detailed denial reasons. The security layer provides comprehensive access control with specific reason codes for different violation types. Recent enhancements include watchdog mechanisms for server reliability, improved peer selection algorithms, integrated recovery workflow support, enhanced error handling for connection timeouts and failures, **dual-tier soft-ban system with automatic trusted peer endpoint registration**, **signal-based DLT block log reset handling**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **enhanced error handling for snapshot download operations**, **stale snapshot detection**, and **enhanced exception handling**. - -**Diagram sources** -- [plugin.cpp:1902-2038](file://plugins/snapshot/plugin.cpp#L1902-L2038) -- [plugin.cpp:1470-1599](file://plugins/snapshot/plugin.cpp#L1470-L1599) - -### Configuration and Options - -The plugin supports extensive configuration through both command-line arguments and configuration files: - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `snapshot-at-block` | uint32 | 0 | Create snapshot at specific block number | -| `snapshot-every-n-blocks` | uint32 | 0 | Create periodic snapshots | -| `snapshot-dir` | string | "" | Directory for auto-generated snapshots | -| `snapshot-max-age-days` | uint32 | 0 | Delete snapshots older than N days (0 = disabled) | -| `snapshot-auto-latest` | bool | false | Auto-discover latest snapshot in snapshot-dir | -| `allow-snapshot-serving` | bool | false | Enable TCP snapshot serving | -| `allow-snapshot-serving-only-trusted` | bool | false | Restrict serving to trusted peers | -| `snapshot-serve-endpoint` | string | "0.0.0.0:8092" | TCP listen endpoint | -| `trusted-snapshot-peer` | string[] | [] | Trusted peer endpoints | -| `sync-snapshot-from-trusted-peer` | bool | false | Download snapshot on empty state | -| `enable-stalled-sync-detection` | bool | false | Auto-detect stalled sync | -| `stalled-sync-timeout-minutes` | uint32 | 5 | Timeout for stalled sync | -| `test-trusted-seeds` | bool | false | Test trusted peers connectivity | -| `dlt-block-log-max-blocks` | uint32 | 100000 | Rolling DLT block log window | -| `disable-snapshot-anti-spam` | bool | false | Disable anti-spam checks | -| `snapshot-serve-allow-ip` | string[] | [] | Allowed client IPs for serving | -| **`dlt-block-log-reset-snapshots`** | **bool** | **true** | Enable automatic snapshots on DLT reset | -| **`p2p-stale-sync-detection`** | **bool** | **false** | **Enable P2P stale sync detection** | -| **`p2p-stale-sync-timeout-seconds`** | **uint32** | **120** | **Timeout for P2P stale sync detection** | -| **`needs_fresh_snapshot`** | **bool** | **false** | **Internal flag for stale snapshot detection** | - -**Updated** The configuration system now includes new options for enhanced anti-spam protection, automatic snapshot discovery, integrated recovery workflow, watchdog monitoring, **signal-based DLT block log reset handling**, **enhanced P2P integration with trusted peer support**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, and **enhanced exception handling**. The `snapshot-auto-latest` option enables automatic discovery of the latest snapshot in the specified directory, while `replay-from-snapshot` provides comprehensive recovery mode functionality, and `trusted-snapshot-peer` enables **automatic registration of trusted peer endpoints with the P2P layer**. **The new DLT block log reset snapshots option enables automatic snapshot creation when DLT block logs are reset, the new P2P stale sync detection options provide lightweight recovery from network stalls without requiring snapshot downloads, and the needs_fresh_snapshot internal flag enables stale snapshot detection and urgent fresh snapshot creation**. - -**Section sources** -- [plugin.cpp:2473-2510](file://plugins/snapshot/plugin.cpp#L2473-L2510) -- [snapshot-plugin.md:247-273](file://documentation/snapshot-plugin.md#L247-L273) - -## Asynchronous Snapshot Creation - -**New** The snapshot plugin now implements a comprehensive asynchronous non-blocking snapshot creation system that prevents read-lock timeouts for API and P2P threads while maintaining snapshot quality and consistency. - -### Asynchronous Execution Architecture - -The asynchronous snapshot creation system provides non-blocking snapshot generation through dedicated thread management: - -```mermaid -sequenceDiagram -participant MainThread as Main Thread -participant SnapshotThread as Snapshot Thread -participant Database as Database -participant Serializer as Serializer -participant FileSystem as File System -MainThread->>MainThread : schedule_async_snapshot() -MainThread->>MainThread : snapshot_in_progress.exchange(true) -alt First Snapshot -MainThread->>MainThread : snapshot_thread = std : : make_unique() -end -MainThread->>SnapshotThread : snapshot_thread->async([=](){}) -SnapshotThread->>Database : with_strong_read_lock() -Database-->>SnapshotThread : locked_access -SnapshotThread->>Serializer : serialize_state() -Serializer-->>SnapshotThread : state_json -SnapshotThread->>FileSystem : write_compressed_file() -FileSystem-->>SnapshotThread : success -SnapshotThread->>MainThread : snapshot_in_progress = false -``` - -### Key Asynchronous Features - -The asynchronous execution system includes several critical improvements: - -#### Dedicated Snapshot Thread -- **Thread Isolation**: Uses dedicated `fc::thread` for snapshot I/O operations -- **Fiber Scheduler Independence**: Mirrors P2P plugin's approach with dedicated worker thread -- **Background Processing**: Prevents snapshot creation from blocking main thread operations - -#### Atomic Progress Tracking -- **Progress Guard**: Uses `std::atomic` to prevent concurrent snapshot creation -- **RAII Cleanup**: Automatic cleanup through destructor-based guard pattern -- **Exception Safety**: Comprehensive error handling with proper cleanup guarantees - -#### Read Lock Optimization -- **Lock Scope Minimization**: Database read operations occur within tight lock scope -- **Background Processing**: Compression and file I/O occur outside database lock -- **Performance Enhancement**: Reduces main thread blocking time from 3+ seconds - -#### Enhanced Error Handling -- **Comprehensive Exception Catching**: Catches fc::exception, std::exception, and unknown exceptions -- **Graceful Degradation**: Logs errors and continues normal operation -- **Resource Cleanup**: Ensures proper cleanup even on failure - -**Section sources** -- [plugin.cpp:1400-1484](file://plugins/snapshot/plugin.cpp#L1400-L1484) -- [plugin.cpp:1418-1436](file://plugins/snapshot/plugin.cpp#L1418-L1436) -- [plugin.cpp:737-743](file://plugins/snapshot/plugin.cpp#L737-L743) - -## validator-Aware Deferral Mechanism - -**New** The snapshot plugin now includes a sophisticated validator-aware deferral mechanism that prevents snapshot creation from interrupting validator block production, ensuring network stability and consensus participation. - -### validator Detection and Deferral Logic - -The validator-aware deferral system provides intelligent scheduling based on validator production status: - -```mermaid -flowchart TD -Start([Snapshot Creation Request]) --> CheckSync{"is_syncing?"} -CheckSync --> |Yes| Skip["Skip Snapshot Creation"] -CheckSync --> |No| CheckWitness["is_witness_producing_soon()?"] -CheckWitness --> |No| CreateNow["Create Snapshot Immediately"] -CheckWitness --> |Yes| CheckPending{"snapshot_pending?"} -CheckWitness --> |Yes| CheckDeferred["Handle Deferred Snapshot"] -CheckPending --> |No| SetPending["Set snapshot_pending = true"] -SetPending --> StorePath["Store pending_snapshot_path"] -CheckPending --> |Yes| Skip -CreateNow --> ScheduleAsync["schedule_async_snapshot()"] -ScheduleAsync --> Complete([Creation Scheduled]) -StorePath --> Complete -CheckDeferred --> CreateDeferred["Create Deferred Snapshot"] -CreateDeferred --> Complete -Skip --> Complete -``` - -### validator Integration Features - -The validator-aware deferral system includes several key components: - -#### validator Production Detection -- **Plugin Integration**: Queries Validator Plugin for production schedule information -- **State Validation**: Checks if Validator Plugin is properly initialized and started -- **Graceful Degradation**: Falls back to conservative behavior if Validator Plugin unavailable - -#### One-Time Deferral Limit -- **Single Deferral Policy**: Allows only one deferral per validator production cycle -- **Infinite Loop Prevention**: Prevents infinite deferral loops with validator-aware checks -- **Production Priority**: Ensures validator block production takes precedence over snapshot creation - -#### Deferred Snapshot Management -- **State Persistence**: Stores snapshot path for later execution -- **Cleanup Mechanism**: Clears pending state after successful execution -- **Atomic Operations**: Uses atomic flags for thread-safe state management - -#### Integration with Block Processing -- **Applied Block Handler**: Monitors block application for deferral timing -- **Sync Detection**: Skips snapshot creation during P2P synchronization -- **Live Block Priority**: Only creates snapshots for live, synchronized blocks - -**Section sources** -- [plugin.cpp:1390-1484](file://plugins/snapshot/plugin.cpp#L1390-L1484) -- [plugin.cpp:1440-1449](file://plugins/snapshot/plugin.cpp#L1440-L1449) -- [validator.cpp:335-551](file://plugins/validator/validator.cpp#L335-L551) - -## Enhanced Error Handling - -**New** The snapshot plugin now includes comprehensive enhanced error handling capabilities specifically designed for recovery scenarios, providing robust fault tolerance and diagnostic information for unlinkable_block_exception and related errors. - -### Enhanced Error Handling Architecture - -The enhanced error handling system provides comprehensive fault tolerance and recovery mechanisms: - -```mermaid -flowchart TD -Start([Operation Request]) --> TryOperation["Attempt Operation"] -TryOperation --> Success{"Operation Success?"} -Success --> |Yes| LogSuccess["Log Success"] -Success --> |No| CheckErrorType{"Check Error Type"} -CheckErrorType --> IsRecoverable{"Is Recoverable?"} -IsRecoverable --> |Yes| AttemptRecovery["Attempt Recovery"] -IsRecoverable --> |No| LogFatal["Log Fatal Error"] -AttemptRecovery --> RecoverySuccess{"Recovery Success?"} -RecoverySuccess --> |Yes| RetryOperation["Retry Original Operation"] -RecoverySuccess --> |No| LogFatal -RetryOperation --> Success -LogSuccess --> Complete([Operation Complete]) -LogFatal --> Complete -``` - -### Enhanced Error Handling Features - -The enhanced error handling system includes several key improvements: - -#### Unlinkable Block Exception Prevention -- **LIB Promotion Strategy**: Promotes LIB to head block during snapshot import to prevent unlinkable_block_exception -- **Fork Database Seeding**: Seeds fork database with head block to ensure proper linking -- **Safe Transition**: Ensures snapshot import doesn't create orphaned blocks that cause synchronization issues - -#### Comprehensive Exception Coverage -- **Multiple Exception Types**: Catches fc::exception, std::exception, and unknown exceptions -- **Detailed Logging**: Provides comprehensive error context and diagnostic information -- **Graceful Degradation**: Continues normal operation even when snapshot creation fails - -#### Resource Management and Cleanup -- **Atomic State Management**: Uses atomic flags for thread-safe error handling -- **RAII Pattern**: Ensures proper cleanup through destructor-based resource management -- **Memory Safety**: Prevents memory leaks and resource corruption during error scenarios - -#### Integration with Watchdog System -- **Server Health Monitoring**: Integrates with watchdog to detect and recover from server failures -- **Connection Timeout Handling**: Manages connection timeouts and socket errors gracefully -- **Thread Safety**: Ensures error handling doesn't interfere with other system components - -#### **Enhanced Error Handling for Snapshot Download Operations** -- **Stalled Sync Monitoring Continuity**: Ensures stalled sync monitoring continues running even when snapshot loading fails -- **Graceful Recovery**: Restarts stalled sync detection after failed snapshot download attempts -- **Improved Exception Handling**: Enhanced exception handling for both fc::exception and std::exception types during snapshot download attempts - -#### **Improved Undo Stack Management** -- **Proper Cleanup**: Adds proper undo stack management with db.undo_all() call before set_revision operations -- **Database State Consistency**: Ensures proper cleanup of database state during snapshot loading -- **Hot-Reload Safety**: Prevents undo stack corruption during hot-reload scenarios - -**Section sources** -- [plugin.cpp:1326-1376](file://plugins/snapshot/plugin.cpp#L1326-L1376) -- [plugin.cpp:1426-1435](file://plugins/snapshot/plugin.cpp#L1426-L1435) -- [plugin.cpp:745-750](file://plugins/snapshot/plugin.cpp#L745-L750) - -## Automatic Snapshot Discovery - -**New** The snapshot plugin now includes comprehensive automatic snapshot discovery functionality through the --snapshot-auto-latest option, enabling nodes to automatically locate and use the most recent snapshot in a specified directory. - -### Enhanced Path Validation Logic - -**Updated** The automatic snapshot discovery process now includes robust path validation and defensive programming checks: - -```mermaid -flowchart TD -Start([Auto-Discovery Request]) --> CheckOption{"--snapshot-auto-latest Enabled?"} -CheckOption --> |No| End([Skip Discovery]) -CheckOption --> |Yes| CheckPath{"--snapshot Path Provided?"} -CheckPath --> |Yes| LogIgnored["Log: Ignored (manual path provided)"] -CheckPath --> |No| CheckDir{"--snapshot-dir Configured?"} -CheckDir --> |No| LogNoDir["Log: No directory configured"] -CheckDir --> |Yes| ValidateDir["Validate Directory Path"] -ValidateDir --> DirExists{"Directory Exists?"} -DirExists --> |No| LogInvalidDir["Log: Invalid directory path"] -DirExists --> |Yes| ReadDir["Read Directory Contents"] -ReadDir --> FilterFiles["Filter .vizjson/.json Files"] -FilterFiles --> ParseName["Parse 'snapshot-block-N' Names"] -ParseName --> CheckNonEmpty["Check Non-Empty String Representations"] -CheckNonEmpty --> FindBest["Find Highest Block Number"] -FindBest --> Found{"Snapshot Found?"} -Found --> |Yes| SetPath["Set snapshot_path to best snapshot"] -Found --> |No| LogNotFound["Log: No snapshots found"] -SetPath --> Complete([Discovery Complete]) -LogIgnored --> Complete -LogNoDir --> Complete -LogInvalidDir --> Complete -LogNotFound --> Complete -End -``` - -### Enhanced Discovery Features - -The automatic snapshot discovery system includes several key improvements: - -#### Robust Directory Validation -- **Path Existence Verification**: Validates directory existence before processing -- **Directory Type Checking**: Ensures the path points to a valid directory -- **Defensive Path Handling**: Handles edge cases and invalid path representations - -#### Improved File Processing -- **Enhanced String Validation**: Checks for non-empty string representations of file paths -- **Robust Filename Parsing**: Gracefully handles malformed filenames with defensive checks -- **Comprehensive Error Handling**: Provides detailed logging for debugging and monitoring - -#### Integration with Recovery Workflow -- **Recovery Mode Compatibility**: Works seamlessly with --replay-from-snapshot flag -- **Fallback Support**: Provides graceful degradation when no snapshots found -- **Manual Override Priority**: Respects manually specified snapshot paths - -**Section sources** -- [plugin.cpp:697-700](file://plugins/snapshot/plugin.cpp#L697-L700) -- [plugin.cpp:2831-2845](file://plugins/snapshot/plugin.cpp#L2831-L2845) -- [plugin.cpp:1719-1748](file://plugins/snapshot/plugin.cpp#L1719-L1748) -- [plugin.cpp:1706-1748](file://plugins/snapshot/plugin.cpp#L1706-L1748) - -## Integrated Recovery Workflow - -**New** The snapshot plugin now provides comprehensive integrated recovery workflow through the --replay-from-snapshot flag, enabling nodes to recover from corrupted states using snapshot-based restoration and DLT block log replay. - -### Recovery Mode Startup Sequence - -The integrated recovery workflow provides a complete recovery process: - -```mermaid -sequenceDiagram -participant User as User Command -participant Chain as Chain Plugin -participant Snap as Snapshot Plugin -participant DB as Database -User->>Chain : Start with --replay-from-snapshot -Chain->>Chain : Validate Snapshot Path -Chain->>DB : open_from_snapshot() -DB-->>Chain : Database Ready -Chain->>Snap : Execute snapshot_load_callback() -Snap->>DB : load_snapshot_from_snapshot_file() -DB-->>Snap : State Restored -Snap->>DB : initialize_hardforks() -DB-->>Snap : Hardforks Initialized -Snap->>DB : promote LIB to head block -Snap->>DB : seed fork database -DB-->>Snap : Recovery Complete -Snap-->>Chain : Success -Chain->>DB : initialize_hardforks() -Chain->>DB : reindex_from_dlt() -DB-->>Chain : DLT Replay Complete -Chain->>Chain : on_sync() Complete -``` - -### Enhanced Recovery Workflow Features - -The integrated recovery workflow includes several key components: - -#### Snapshot-Based State Restoration -- **Complete State Import**: Full snapshot loading with validation and checksum verification -- **Hardfork Initialization**: Proper hardfork state initialization after snapshot import -- **LIB Promotion**: Automatic promotion of last irreversible block to snapshot head - -#### DLT Block Log Integration -- **Post-Recovery Replay**: Automatic replay of DLT block log blocks after snapshot import -- **Gap Resolution**: Seamless filling of gaps between snapshot and current blockchain state -- **Mode Detection**: Intelligent detection and handling of DLT mode operation - -#### Enhanced Error Recovery and Diagnostics -- **Graceful Degradation**: Fallback to normal operation if recovery fails -- **Comprehensive Logging**: Detailed logging for recovery process monitoring -- **Diagnostic Information**: Extensive error reporting and recovery status information - -**Section sources** -- [plugin.cpp:490-560](file://plugins/chain/plugin.cpp#L490-L560) -- [plugin.cpp:2945-2959](file://plugins/snapshot/plugin.cpp#L2945-L2959) -- [database.cpp:441-5201](file://libraries/chain/database.cpp#L441-L5201) - -## DLT Replay Integration - -**New** The snapshot plugin now includes comprehensive DLT (Distributed Ledger Technology) replay integration, enabling enhanced error handling and recovery scenarios through seamless integration with the DLT block log system. - -### DLT Replay Architecture - -The DLT replay integration provides robust block log management: - -```mermaid -flowchart TD -Start([DLT Replay Request]) --> CheckHead{"DLT Head Available?"} -CheckHead --> |No| LogEmpty["Log: No blocks in dlt_block_log"] -CheckHead --> |Yes| ValidateRange["Validate Replay Range"] -ValidateRange --> AdjustFrom["Adjust from_block if needed"] -AdjustFrom --> ReadBlocks["Read Blocks from DLT Log"] -ReadBlocks --> ProcessBlocks["Process Each Block"] -ProcessBlocks --> ApplyBlock["Apply Block to Database"] -ApplyBlock --> UpdateDatabases["Update DLT and Fork DB"] -UpdateDatabases --> CheckComplete{"More Blocks?"} -CheckComplete --> |Yes| ReadBlocks -CheckComplete --> |No| Complete([Replay Complete]) -LogEmpty --> Complete -``` - -### Enhanced DLT Replay Features - -The DLT replay integration includes several key improvements: - -#### Intelligent Block Log Management -- **Dynamic Range Adjustment**: Automatic adjustment of replay range based on DLT log availability -- **Gap Detection and Handling**: Detection and handling of gaps between snapshot and current state -- **Efficient Memory Usage**: Streaming processing of blocks to minimize memory footprint - -#### Seamless Integration -- **Database State Synchronization**: Automatic synchronization between DLT block log and database state -- **Fork Database Seeding**: Proper seeding of fork database for P2P synchronization -- **Hardfork State Preservation**: Maintenance of hardfork state during replay process - -#### Enhanced Error Resilience -- **Graceful Error Handling**: Comprehensive error handling with fallback to normal operation -- **Progress Reporting**: Real-time progress reporting and status updates -- **Resource Management**: Efficient resource management during long-running replay operations - -**Section sources** -- [database.cpp:441-5201](file://libraries/chain/database.cpp#L441-L5201) -- [plugin.cpp:542-559](file://plugins/chain/plugin.cpp#L542-L559) - -## Signal-Based DLT Block Log Reset Handling - -**New** The snapshot plugin now includes comprehensive signal-based DLT block log reset handling that automatically creates fresh snapshots when DLT block logs are reset, enabling other DLT nodes to bootstrap from the current state. - -### DLT Block Log Reset Architecture - -The signal-based DLT block log reset handling provides automatic snapshot creation: - -```mermaid -sequenceDiagram -participant DLT as DLT Block Log -participant DB as Database -participant Snap as Snapshot Plugin -participant FS as File System -DLT->>DB : reset() or truncate_before() -DB->>DB : emit dlt_block_log_was_reset() -DB->>Snap : dlt_block_log_was_reset signal -Snap->>Snap : Check DLT mode and snapshot_dir -Snap->>Snap : schedule_async_snapshot() -Snap->>Snap : snapshot_thread->async() -Snap->>FS : create_snapshot(output_path) -FS-->>Snap : snapshot_created -Snap->>Snap : cleanup_old_snapshots() -Snap-->>DB : automatic snapshot ready -``` - -### DLT Reset Handling Features - -The signal-based DLT block log reset handling includes several key improvements: - -#### Signal-Based Event Handling -- **Automatic Connection**: The snapshot plugin connects to `dlt_block_log_was_reset` signal during initialization -- **Conditional Activation**: Only activates when DLT mode is enabled and snapshot directory is configured -- **Event-Driven Creation**: Creates snapshots automatically when DLT block logs are reset - -#### Automatic Snapshot Generation -- **Fresh State Creation**: Generates snapshots at the current head block number after reset -- **Directory Management**: Places snapshots in the configured snapshot directory with proper naming -- **Async Execution**: Uses the existing asynchronous snapshot creation system to prevent blocking - -#### Integration with Existing Systems -- **Consistent Naming**: Uses the same naming convention as manual snapshots (`snapshot-block-.vizjson`) -- **Cache Updates**: Automatically updates the snapshot cache after creation -- **Cleanup Integration**: Integrates with existing snapshot cleanup mechanisms - -#### Enhanced Error Handling -- **Exception Safety**: Comprehensive error handling with proper logging -- **Guard Mechanisms**: Uses atomic flags to prevent concurrent snapshot creation -- **Thread Management**: Reuses existing dedicated snapshot thread infrastructure - -**Section sources** -- [plugin.cpp:3252-3290](file://plugins/snapshot/plugin.cpp#L3252-L3290) -- [database.cpp:4945-4947](file://libraries/chain/database.cpp#L4945-L4947) -- [database.cpp:5139-5140](file://libraries/chain/database.cpp#L5139-L5140) -- [database.hpp:337-338](file://libraries/chain/include/graphene/chain/database.hpp#L337-L338) - -## Peer-to-Peer Snapshot Synchronization - -**New** The snapshot plugin now includes comprehensive peer-to-peer snapshot synchronization capabilities for nodes with empty state, enabling automatic discovery and download of snapshots from trusted peers. - -### Enhanced P2P Synchronization Workflow - -The peer-to-peer synchronization provides automated snapshot acquisition with improved robustness: - -```mermaid -sequenceDiagram -participant Node as Empty State Node -participant Peer as Trusted Peer -participant Snap as Snapshot Plugin -Node->>Snap : Trigger P2P Sync -Snap->>Peer : Connect to Trusted Peers -Peer-->>Snap : SNAPSHOT_INFO_REPLY -Snap->>Snap : Validate Snapshot Info -Snap->>Peer : SNAPSHOT_DATA_REQUEST -loop Until Complete -Peer-->>Snap : SNAPSHOT_DATA_REPLY -Snap->>Snap : Append to Temp File -end -Snap->>Snap : Verify Checksum -Snap->>Snap : Rename to Final Path -Snap->>Snap : Load Snapshot -Snap->>Node : Sync Complete -``` - -### Enhanced P2P Synchronization Features - -The peer-to-peer synchronization system includes several key improvements: - -#### Automated Peer Discovery -- **Trusted Peer Configuration**: Support for multiple trusted peer endpoints -- **Connection Management**: Robust connection management with retry logic -- **Peer Selection Algorithms**: Intelligent peer selection and load balancing - -#### Secure and Reliable Transfer -- **Checksum Verification**: Comprehensive checksum verification for data integrity -- **Chunked Transfer**: Efficient chunked transfer with configurable chunk sizes -- **Connection Timeouts**: Proper timeout handling for network reliability - -#### Enhanced Integration with Recovery Workflow -- **Pre-Sync State Management**: Proper state management before snapshot import -- **Post-Sync Validation**: Comprehensive validation after successful transfer -- **Fallback Mechanisms**: Multiple retry attempts with progressive failure handling - -**Section sources** -- [plugin.cpp:2976-3009](file://plugins/snapshot/plugin.cpp#L2976-L3009) -- [plugin.cpp:2468-2570](file://plugins/snapshot/plugin.cpp#L2468-L2570) - -## Enhanced P2P Integration with Trusted Peers - -**New** The snapshot plugin now provides **enhanced P2P integration with trusted peer support** through automatic registration of trusted peer endpoints with the P2P layer, enabling **dual-tier soft-ban system** where trusted peers receive 5-minute bans instead of the default 1-hour duration. - -### Automatic Trusted Peer Endpoint Registration - -The enhanced P2P integration provides seamless trusted peer endpoint registration: - -```mermaid -sequenceDiagram -participant SnapPlug as Snapshot Plugin -participant P2PPlug as P2P Plugin -participant NetNode as Network Node -participant Peer as Trusted Peer -SnapPlug->>P2PPlug : get_trusted_snapshot_peers() -P2PPlug->>SnapPlug : trusted_eps (IP : port list) -P2PPlug->>NetNode : set_trusted_peer_endpoints(trusted_eps) -NetNode->>NetNode : Parse IP addresses from endpoints -NetNode->>NetNode : Store as uint32_t raw IPs -NetNode->>Peer : Soft-ban Duration Check -Peer-->>NetNode : is_trusted_peer(peer)? -alt Trusted Peer -NetNode->>Peer : 5-minute soft-ban (TRUSTED_SOFT_BAN_DURATION_SEC) -else Untrusted Peer -NetNode->>Peer : 1-hour soft-ban (SOFT_BAN_DURATION_SEC) -end -``` - -### Dual-Tier Soft-Ban System - -The enhanced P2P integration implements a comprehensive dual-tier soft-ban system: - -#### Soft-Ban Duration Constants -- **Default Soft-Ban Duration**: 3600 seconds (1 hour) for untrusted peers -- **Trusted Peer Soft-Ban Duration**: 300 seconds (5 minutes) for trusted peers -- **Automatic Application**: Soft-ban duration determined by peer trust status - -#### Trusted Peer Detection -- **Endpoint Parsing**: Extracts IP addresses from "host:port" endpoint strings -- **Raw IP Storage**: Stores trusted peer IPs as 32-bit integers for O(1) lookup -- **Dynamic Updates**: Supports runtime updates to trusted peer lists - -#### Enhanced P2P Integration Features - -#### Automatic Registration Process -- **Plugin Discovery**: P2P plugin automatically discovers snapshot plugin -- **Endpoint Retrieval**: Retrieves trusted snapshot peer endpoints -- **Registration Automation**: Registers endpoints with network node automatically - -#### Reduced Soft-Ban Duration Benefits -- **Faster Recovery**: Trusted peers recover from soft-bans in 5 minutes instead of 1 hour -- **Improved Reliability**: Better handling of legitimate snapshot requests from trusted peers -- **Network Efficiency**: Reduced downtime for trusted peers during snapshot operations - -#### Enhanced Trust Enforcement -- **Consistent Application**: Soft-ban duration applies consistently across all P2P operations -- **Performance Optimization**: O(1) trust lookup using raw IP addresses -- **Scalability**: Efficient handling of large numbers of trusted peers - -**Section sources** -- [p2p_plugin.cpp:689-697](file://plugins/p2p/p2p_plugin.cpp#L689-L697) -- [node.cpp:5241-5274](file://libraries/network/node.cpp#L5241-L5274) -- [node.hpp:284-290](file://libraries/network/include/graphene/network/node.hpp#L284-L290) -- [plugin.hpp:86-88](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L86-L88) - -## Watchdog and Stalled Sync Detection - -**Updated** The snapshot plugin now includes comprehensive watchdog mechanisms and stalled sync detection for DLT mode, ensuring server reliability and continuous operation through automatic monitoring and recovery. - -### Enhanced Watchdog Architecture - -The watchdog system provides continuous monitoring and automatic recovery: - -```mermaid -sequenceDiagram -participant Watchdog as Watchdog Thread -participant Server as Snapshot Server -participant AcceptLoop as Accept Loop -Watchdog->>Watchdog : Start monitoring loop -loop Every 30 Seconds -Watchdog->>Server : Check last_accept_activity -Server-->>Watchdog : Last activity timestamp -Watchdog->>Watchdog : Calculate idle time -alt Accept Loop Dead -Watchdog->>Server : Restart accept loop -Server->>Server : Clean up old state -Server->>Server : Create new server socket -Server->>Server : Reset anti-spam state -Server->>Server : Start fresh accept loop -else Accept Loop Alive -Watchdog->>Watchdog : Continue monitoring -end -end -``` - -### Enhanced Stalled Sync Detection for DLT Mode - -The stalled sync detection provides DLT mode monitoring with improved reliability: - -```mermaid -sequenceDiagram -participant Monitor as Stalled Sync Monitor -participant Chain as Chain Plugin -participant DB as Database -Monitor->>Monitor : Start monitoring loop -loop Every Check Interval -Monitor->>DB : Check last_block_received_time -DB-->>Monitor : Last block reception time -Monitor->>Monitor : Calculate idle duration -alt Sync Stalled -Monitor->>Chain : Trigger Recovery Actions -Chain->>Chain : Initiate P2P Sync -Chain->>Chain : Attempt Snapshot Download -else Sync Active -Monitor->>Monitor : Continue monitoring -end -end -``` - -### Enhanced Watchdog and Stalled Sync Features - -The watchdog and stalled sync detection include several key improvements: - -#### Dead Accept Loop Detection -- **Monitoring Interval**: Checks every 30 seconds -- **Activity Tracking**: Monitors last accept loop activity timestamp -- **Automatic Restart**: Restarts dead accept loops with full cleanup - -#### Enhanced Stalled Sync Detection for DLT Mode -- **Idle Time Monitoring**: Monitors time since last block reception -- **Timeout Configuration**: Configurable timeout periods for stall detection -- **Recovery Action Triggering**: Automatic triggering of recovery actions when stalls detected - -#### Improved Graceful Recovery -- **State Cleanup**: Resets all anti-spam state to prevent corruption -- **Socket Recreation**: Creates fresh server sockets for new connections -- **Thread Safety**: Properly shuts down dedicated server thread before restart - -#### **Dedicated Threading for Stalled Sync Detection** -- **Thread Isolation**: Uses dedicated `fc::thread` for stalled sync operations -- **Fiber Scheduler Independence**: Prevents fc fibers from stalling on main thread blocked in io_serv->run() -- **Background Processing**: Runs stalled sync detection in background without affecting main thread - -#### **Enhanced Error Handling for Snapshot Download Operations** -- **Continuity Guarantee**: Ensures stalled sync monitoring continues running even when snapshot loading fails -- **Graceful Recovery**: Restarts stalled sync detection after failed snapshot download attempts -- **Improved Exception Handling**: Enhanced exception handling for both fc::exception and std::exception types during snapshot download attempts - -**Section sources** -- [plugin.cpp:735-740](file://plugins/snapshot/plugin.cpp#L735-L740) -- [plugin.cpp:1814-1862](file://plugins/snapshot/plugin.cpp#L1814-L1862) -- [plugin.cpp:772-785](file://plugins/snapshot/plugin.cpp#L772-L785) -- [plugin.cpp:1595-1624](file://plugins/snapshot/plugin.cpp#L1595-L1624) - -## P2P Stale Sync Detection - -**New** The P2P plugin provides a lightweight recovery mechanism that automatically detects and recovers from network stalls without requiring snapshot downloads. This complements the snapshot plugin's stalled sync detection by providing immediate recovery for temporary network issues. - -### How It Works - -When enabled, the P2P plugin tracks the last time a block was received via the network. A background task checks every 30 seconds whether the elapsed time exceeds the configured timeout. If a stall is detected, the node performs three recovery actions in sequence: - -1. **Reset sync from LIB** — The P2P layer's sync start point is reset to the last irreversible block (LIB). This ensures the node resumes from a safe, fork-proof position instead of potentially chasing a dead fork. -2. **Resync with connected peers** — The node explicitly restarts synchronization with all currently connected peers by sending fresh `fetch_blockchain_item_ids_message` requests. -3. **Reconnect seed peers** — All seed nodes from `p2p-seed-node` config are re-added to the connection queue and reconnection is attempted for any that were disconnected. - -This is complementary to the snapshot plugin's stalled sync detection (which downloads a new snapshot). The P2P stale recovery is faster and less disruptive — it only adjusts sync state and reconnects peers, without requiring any state reload. - -### Configuration - -```ini -# Enable P2P stale sync detection (default: false) -p2p-stale-sync-detection = true - -# Timeout in seconds before recovery triggers (default: 120 = 2 minutes) -p2p-stale-sync-timeout-seconds = 120 -``` - -### Use Cases - -- **Temporary network partition**: When peers become unreachable for short periods, the node automatically recovers without manual intervention. -- **Peer disconnections**: If connected peers disconnect unexpectedly, the node can quickly reconnect and resume synchronization. -- **Initial sync delays**: During heavy network traffic or node startup, the node can recover from temporary stalls. - -### Comparison with Snapshot Stalled Sync Detection - -| Feature | P2P Stale Sync | Snapshot Stalled Sync | -|---------|---------------|----------------------| -| Plugin | P2P | Snapshot | -| Trigger | No blocks received for timeout | No blocks received for timeout | -| Recovery action | Reset sync + reconnect peers | Download newer snapshot + reload state | -| Timeout default | 120 seconds | 5 minutes | -| Use case | Temporary network partition, peer disconnections | Node far behind, peers lack old blocks | -| DLT mode | Works for all nodes | Designed for DLT mode | - -Both can be enabled independently. For DLT nodes, the snapshot detection provides deeper recovery (fresh state), while P2P detection handles transient connectivity issues without state reload. - -**Section sources** -- [snapshot-plugin.md:339-374](file://documentation/snapshot-plugin.md#L339-L374) -- [p2p_plugin.cpp:585-649](file://plugins/p2p/p2p_plugin.cpp#L585-L649) -- [p2p_plugin.cpp:673-677](file://plugins/p2p/p2p_plugin.cpp#L673-L677) -- [p2p_plugin.cpp:744-755](file://plugins/p2p/p2p_plugin.cpp#L744-L755) - -## Emergency Consensus Handling - -**Updated** The snapshot plugin now includes comprehensive emergency consensus handling with forward-compatible fields for emergency consensus activation. - -### Enhanced Emergency Consensus Fields - -The dynamic global property object now includes enhanced emergency consensus fields for improved network resilience: - -```mermaid -flowchart TD -Start([Dynamic Global Property Import]) --> CheckFields["Check for Emergency Consensus Fields"] -CheckFields --> HasFields{"Emergency Consensus Fields Present?"} -HasFields --> |Yes| ImportFields["Import emergency_consensus_active
and emergency_consensus_start_block"] -HasFields --> |No| SetDefaults["Set defaults:
emergency_consensus_active = false
emergency_consensus_start_block = 0"] -ImportFields --> ContinueProcessing["Continue with Normal Processing"] -SetDefaults --> ContinueProcessing -ContinueProcessing --> Complete([Import Complete]) -``` - -### Enhanced Forward-Compatible Design - -The emergency consensus handling implements a forward-compatible approach: - -- **Backward Compatibility**: Nodes without emergency consensus fields gracefully handle snapshots from newer nodes -- **Default Values**: Missing fields are assigned sensible defaults -- **Runtime Activation**: Emergency consensus can be activated dynamically without requiring snapshot regeneration - -**Section sources** -- [plugin.cpp:165-176](file://plugins/snapshot/plugin.cpp#L165-L176) - -## Enhanced Anti-Spam Protection - -**Updated** The snapshot plugin now includes comprehensive anti-spam protection with new configuration options and improved trust enforcement mechanisms. - -### Enhanced Anti-Spam Architecture - -The anti-spam system provides multiple layers of protection against abuse: - -```mermaid -flowchart TD -Start([Incoming Connection]) --> CheckAntiSpam{"Anti-Spam Enabled?"} -CheckAntiSpam --> |No| CheckTrust{"Allow Only Trusted?"} -CheckAntiSpam --> |Yes| CheckConcurrent{"Concurrent Connections < 5?"} -CheckTrust --> |Yes| ValidateTrust{"IP in Trusted List?"} -CheckTrust --> |No| CheckSession{"Active Sessions < 3/IP?"} -CheckConcurrent --> |No| DenyMaxConnections["Send DENY_MAX_CONNECTIONS"] -CheckConcurrent --> |Yes| CheckSession -CheckSession --> |No| DenySessionLimit["Send DENY_SESSION_LIMIT"] -CheckSession --> |Yes| CheckRate{"Connections < 10/Hour/IP?"} -CheckRate --> |No| DenyRateLimited["Send DENY_RATE_LIMITED"] -CheckRate --> |Yes| Accept["Accept Connection"] -ValidateTrust --> |No| DenyUntrusted["Send DENY_UNTRUSTED"] -ValidateTrust --> |Yes| Accept -Accept --> Process["Process Snapshot Request"] -``` - -**Updated** The anti-spam system has been enhanced with increased limits to improve service accessibility while maintaining security controls. The new configuration values are: - -- **Maximum sessions per IP**: Increased from 2 to 3 sessions per IP -- **Maximum connections per hour**: Increased from 6 to 10 connections per hour per IP - -These changes provide better support for legitimate users while maintaining effective protection against abuse. - -### Enhanced New Configuration Options - -The anti-spam system introduces several new configuration options: - -#### disable-snapshot-anti-spam -- **Purpose**: Disable all anti-spam checks for snapshot serving -- **Use Case**: Trusted networks where anti-spam protection is not needed -- **Security Implications**: Removes all rate limiting and session management - -#### snapshot-serve-allow-ip -- **Purpose**: Specify which client IPs are allowed to connect for snapshot serving -- **Use Case**: Private networks with controlled access -- **Implementation**: Maintains whitelist of approved client IP addresses - -### Enhanced Trust Enforcement - -The trust enforcement system now operates independently of anti-spam protection: - -- **Separate Logic**: Trust validation occurs before anti-spam checks -- **Whitelist Management**: Dynamic updates to trusted IP lists -- **Consistent Enforcement**: Anti-spam rules apply uniformly regardless of trust status - -**Section sources** -- [plugin.cpp:1587-1596](file://plugins/snapshot/plugin.cpp#L1587-L1596) -- [plugin.cpp:1610-1620](file://plugins/snapshot/plugin.cpp#L1610-L1620) -- [plugin.cpp:1812-1877](file://plugins/snapshot/plugin.cpp#L1812-L1877) - -## Access Control and Security Mechanisms - -**Updated** The snapshot plugin now includes comprehensive access control mechanisms with detailed denial reasons for enhanced security and resource management. - -### Enhanced Access Control Architecture - -The access control system provides multiple layers of security enforcement: - -```mermaid -flowchart TD -Start([Incoming Connection]) --> CheckTrust{"Allow Only Trusted?"} -CheckTrust --> |Yes| ValidateTrust{"IP in Trusted List?"} -CheckTrust --> |No| CheckConcurrent{"Concurrent Connections < 5?"} -ValidateTrust --> |No| DenyUntrusted["Send DENY_UNTRUSTED"] -ValidateTrust --> |Yes| CheckConcurrent -CheckConcurrent --> |No| DenyMaxConnections["Send DENY_MAX_CONNECTIONS"] -CheckConcurrent --> |Yes| CheckSession{"Active Sessions < 3/IP?"} -CheckSession --> |No| DenySessionLimit["Send DENY_SESSION_LIMIT"] -CheckSession --> |Yes| CheckRate{"Connections < 10/Hour/IP?"} -CheckRate --> |No| DenyRateLimited["Send DENY_RATE_LIMITED"] -CheckRate --> |Yes| Accept["Accept Connection"] -DenyUntrusted --> Close["Close Connection"] -DenyMaxConnections --> Close -DenySessionLimit --> Close -DenyRateLimited --> Close -Accept --> Process["Process Snapshot Request"] -``` - -**Updated** The access control system now enforces the enhanced anti-spam limits with improved session management and rate limiting: - -- **Maximum concurrent connections**: 5 simultaneous connections -- **Per-IP session limit**: 3 active sessions per IP (increased from 2) -- **Rate limit**: 10 connections per hour per IP (increased from 6) - -These enhanced limits provide better support for legitimate users while maintaining effective protection against abuse. - -### Enhanced Denial Reason Codes - -The system provides specific denial reasons for different violation types: - -| Reason Code | Enum Value | Description | -|-------------|------------|-------------| -| `deny_untrusted` | 1 | IP address not in trusted list | -| `deny_max_connections` | 2 | Server has reached maximum concurrent connections (5) | -| `deny_session_limit` | 3 | Too many active sessions from this IP (3 per IP limit) | -| `deny_rate_limited` | 4 | Too many connections per hour from this IP (10 per hour limit) | - -### Enhanced Anti-Spam Protection Features - -The access control system implements multiple enhanced anti-spam mechanisms: - -#### Connection Throttling -- **Maximum Concurrent Connections**: 5 simultaneous connections -- **Per-IP Session Limit**: 3 active sessions per IP (increased from 2) -- **Rate Limiting**: 10 connections per hour per IP (increased from 6) - -#### Enhanced Session Management -- **Active Session Tracking**: Monitors concurrent sessions per IP -- **Connection History**: Tracks connection timestamps for rate limiting -- **RAII Session Guards**: Ensures proper cleanup of session resources - -#### Enhanced Trust Enforcement -- **Trusted IP Validation**: Maintains whitelist of approved IP addresses -- **Dynamic Trust Updates**: Supports runtime updates to trusted peer lists -- **Consistent Enforcement**: Anti-spam rules apply uniformly to all connections - -**Section sources** -- [plugin.hpp:24-34](file://plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#L24-L34) -- [plugin.cpp:1587-1596](file://plugins/snapshot/plugin.cpp#L1587-L1596) -- [plugin.cpp:1610-1620](file://plugins/snapshot/plugin.cpp#L1610-L1620) -- [plugin.cpp:1812-1877](file://plugins/snapshot/plugin.cpp#L1812-L1877) - -## Integration with Chain Plugin - -**Updated** The snapshot plugin has been integrated with the chain plugin through a sophisticated callback system that enables programmatic state restoration, enhanced P2P synchronization, and comprehensive recovery workflow integration. - -The integration works through three key callback mechanisms registered during plugin initialization: - -### Enhanced Snapshot Loading Callback -```mermaid -sequenceDiagram -participant Chain as Chain Plugin -participant Snapshot as Snapshot Plugin -participant DB as Database -Chain->>Chain : Detect --snapshot option -Chain->>Snapshot : Register snapshot_load_callback() -Snapshot->>Chain : Callback registered -Chain->>Chain : During startup, check for callback -Chain->>Snapshot : Execute snapshot_load_callback() -Snapshot->>DB : load_snapshot_from_snapshot_file() -DB-->>Snapshot : State restored -Snapshot-->>Chain : Success -Chain->>Chain : Continue normal startup -``` - -### Enhanced Snapshot Creation Callback -The snapshot plugin registers a callback that executes during chain plugin startup to create snapshots after full database load, ensuring proper state capture. - -### Enhanced P2P Snapshot Sync Callback -For nodes with empty state, the snapshot plugin registers a callback that downloads and loads snapshots from trusted peers before normal P2P synchronization begins. Enhanced with automatic retry logic, improved peer selection algorithms, comprehensive error handling, **automatic trusted peer endpoint registration with the P2P layer**, **signal-based DLT block log reset handling**, **dedicated threading for stalled sync detection**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, and **stale snapshot detection**. - -### Enhanced Recovery Workflow Integration -**New** The chain plugin now includes comprehensive recovery workflow integration that coordinates with the snapshot plugin for automatic recovery from corrupted states using snapshot-based restoration and DLT block log replay. - -**Section sources** -- [plugin.cpp:2598-2680](file://plugins/snapshot/plugin.cpp#L2598-L2680) -- [plugin.cpp:364-432](file://plugins/chain/plugin.cpp#L364-L432) - -## Dependency Analysis - -The snapshot plugin has carefully managed dependencies to ensure modularity and maintainability: - -```mermaid -graph LR -subgraph "Core Dependencies" -A[graphene_chain] --> D[snapshot_plugin] -B[appbase] --> D -C[chainbase] --> D -E[fc] --> D -end -subgraph "Blockchain Dependencies" -F[graphene_protocol] --> D -G[graphene_witness] --> D -H[graphene_json_rpc] --> D -I[graphene_time] --> D -end -subgraph "External Libraries" -J[Boost.Filesystem] --> D -K[zlib] --> D -L[OpenSSL] --> D -end -subgraph "Build System" -M[CMake] --> N[Target: graphene_snapshot] -N --> O[Static Library] -N --> P[Shared Library] -end -``` - -**Updated** The dependency graph reveals a clean separation between core blockchain functionality and plugin-specific features. The plugin relies on established VIZ infrastructure while maintaining independence from external systems, demonstrating the benefits of the modular architecture. Recent enhancements include watchdog dependencies, **signal-based DLT block log reset handling**, enhanced P2P integration, automatic snapshot discovery, comprehensive recovery workflow integration, asynchronous execution system dependencies, **enhanced P2P integration with trusted peer support**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, and **enhanced exception handling**. - -**Diagram sources** -- [CMakeLists.txt:27-38](file://plugins/snapshot/CMakeLists.txt#L27-L38) - -**Section sources** -- [CMakeLists.txt:27-38](file://plugins/snapshot/CMakeLists.txt#L27-L38) - -## Performance Considerations - -The snapshot plugin implements several performance optimization strategies through its modular architecture: - -### Asynchronous Execution Performance -- **Thread Isolation**: Dedicated snapshot thread prevents main thread blocking -- **Atomic Operations**: Minimal synchronization overhead with atomic flags -- **Background Processing**: Long-running operations occur outside critical sections - -### Compression and Storage Efficiency -- Uses zlib compression to reduce snapshot file sizes by approximately 70-80% -- Implements streaming compression/decompression to minimize memory usage -- Supports automatic snapshot rotation to manage storage requirements - -### Network Transfer Optimization -- Chunked transfer protocol with configurable chunk sizes (up to 1MB) -- Connection pooling and reuse for efficient peer communication -- Anti-spam measures prevent resource exhaustion during transfers - -### Database Operation Optimization -- Uses strong read locks during snapshot creation to ensure consistency -- Implements validator-aware deferral to prevent missed block production slots -- Optimized object serialization minimizes CPU overhead - -### Enhanced Memory Management -- Streaming JSON parsing prevents loading entire snapshots into memory -- Efficient object copying mechanisms handle complex data structures -- Automatic cleanup of temporary files and resources - -### **Signal-Based DLT Block Log Reset Performance** -- **Event-Driven Creation**: Automatic snapshot creation only when DLT block logs are reset -- **Async Execution**: Reuses existing asynchronous snapshot creation infrastructure -- **Minimal Overhead**: Single atomic flag check during DLT reset events -- **Thread Safety**: Dedicated snapshot thread prevents blocking during reset events - -### **Enhanced P2P Integration Performance** -- **Automatic Registration**: Eliminates manual configuration overhead -- **Efficient Lookup**: O(1) trust validation using raw IP addresses -- **Reduced Soft-Ban Impact**: Faster recovery for trusted peers reduces network downtime -- **Optimized Communication**: Streamlined trusted peer endpoint management - -### **Enhanced Logging Performance** -- **ANSI Color Codes**: Provides visual distinction between log levels without performance overhead -- **Level-Based Coloring**: Green for success, orange for warnings, yellow for informational messages -- **Minimal Processing Overhead**: Color code injection occurs only when terminal supports color output - -### **P2P Stale Sync Detection Performance** -- **Lightweight Monitoring**: Minimal CPU overhead through efficient background task scheduling -- **LIB Reset Optimization**: Fast sync reset using pre-computed block IDs -- **Selective Peer Reconnection**: Only reconnects seed nodes that were previously connected -- **30-second Check Interval**: Balances responsiveness with minimal resource usage - -### **Dedicated Threading for Stalled Sync Detection Performance** -- **Thread Isolation**: Dedicated fc::thread prevents main thread blocking -- **Fiber Scheduler Independence**: Prevents fc fibers from stalling on main thread blocked in io_serv->run() -- **Background Processing**: Runs stalled sync detection in background without affecting main thread -- **Minimal Overhead**: Single dedicated thread for all stalled sync operations - -### **Automatic Gap Detection for DLT Block Log Initialization Performance** -- **Intelligent Gap Detection**: Prevents index position mismatch assertions through early detection -- **Automatic Reset Mechanism**: Seamlessly resets DLT block log when gaps are detected -- **Minimal Performance Impact**: Gap detection adds negligible overhead during snapshot import -- **Thread-Safe Operations**: Uses atomic operations to prevent race conditions during gap detection - -### **Enhanced Error Handling Performance** -- **Exception Safety**: Comprehensive error handling prevents cascading failures -- **Graceful Degradation**: Continues normal operation even when snapshot download fails -- **Minimal Overhead**: Enhanced exception handling adds negligible performance impact -- **Improved Resource Management**: Proper cleanup prevents resource leaks during error scenarios - -### **Improved Undo Stack Management Performance** -- **Efficient Cleanup**: db.undo_all() call prevents undo stack corruption -- **Minimal Performance Impact**: Undo stack management adds negligible overhead -- **Thread Safety**: Atomic operations ensure safe undo stack manipulation -- **Hot-Reload Optimization**: Prevents undo stack issues during state reload scenarios - -### **Enhanced Anti-Spam Configuration Performance** -- **Optimized Limits**: Enhanced limits provide better user experience with minimal overhead -- **Efficient Rate Limiting**: Sliding window algorithm minimizes memory usage -- **Thread-Safe Operations**: Atomic counters prevent race conditions -- **Minimal Processing Overhead**: Anti-spam checks add negligible CPU overhead - -### **Stale Snapshot Detection Performance** -- **Intelligent Gap Detection**: Prevents serving broken snapshots with gaps through early detection -- **Automatic Fresh Snapshot Creation**: Urgent snapshot creation eliminates sync gaps without manual intervention -- **Minimal Performance Impact**: Stale detection adds negligible overhead during plugin initialization -- **Thread-Safe Operations**: Uses atomic flags to prevent race conditions during detection - -**Updated** The modular architecture enhances performance by enabling independent optimization of each layer while maintaining system coherence. The watchdog mechanism, **signal-based DLT block log reset handling**, enhanced anti-spam protections, automatic snapshot discovery, integrated recovery workflow, asynchronous execution system, comprehensive error handling, **enhanced P2P integration with trusted peer support**, **dedicated threading for stalled sync detection**, **P2P stale sync detection**, **automatic gap detection for DLT block log initialization**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **enhanced anti-spam configuration**, **stale snapshot detection**, and **enhanced exception handling** are designed to minimize performance impact while providing comprehensive functionality. Recent improvements include dedicated server thread optimizations, DLT replay efficiency, enhanced error handling performance, validator-aware deferral optimization, **efficient dual-tier soft-ban system implementation**, **signal-based DLT block log reset handling**, **optimized P2P stale sync detection with minimal overhead**, **dedicated threading for stalled sync detection with thread isolation**, **intelligent gap detection preventing index position mismatch assertions**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection with urgent fresh snapshot creation**, and **enhanced exception handling**. - -### Enhanced Security Performance Considerations -- Access control checks are performed efficiently using hash maps for IP lookups -- Session tracking uses atomic counters for thread-safe operations -- Rate limiting maintains minimal memory overhead through sliding window algorithm -- Watchdog mechanism operates with minimal CPU overhead through efficient monitoring -- Recovery workflow includes performance-optimized snapshot validation and checksum verification -- Asynchronous execution system minimizes main thread blocking time -- **Signal-based DLT block log reset handling provides efficient event-driven snapshot creation** -- **Enhanced P2P integration provides efficient trust validation with O(1) lookup performance** -- **Enhanced logging system provides efficient colored output with minimal performance impact** -- **P2P stale sync detection operates with minimal overhead through optimized background tasks** -- **Dedicated threading for stalled sync detection prevents main thread blocking and fiber stalling** -- **Automatic gap detection prevents index position mismatch assertions with minimal performance impact** -- **Enhanced error handling for snapshot download operations ensures continuous monitoring** -- **Improved undo stack management prevents database state corruption** -- **Stale snapshot detection prevents serving broken snapshots with gaps** -- **Enhanced exception handling provides robust error recovery mechanisms** - -## Troubleshooting Guide - -### Enhanced Common Issues and Solutions - -**Snapshot Creation Failures** -- **Symptom**: Snapshot creation fails with database lock errors -- **Cause**: validator production conflicts with snapshot creation -- **Solution**: Configure validator-aware deferral or schedule snapshots during maintenance windows - -**Enhanced Asynchronous Execution Issues** -- **Symptom**: Snapshot creation appears stuck or slow -- **Cause**: Main thread blocked by synchronous operations -- **Solution**: Verify dedicated snapshot thread is running and atomic flags are properly managed - -**Enhanced Network Transfer Problems** -- **Symptom**: Peers fail to respond to snapshot requests -- **Cause**: Firewall restrictions or anti-spam protection -- **Solution**: Verify port accessibility and adjust anti-spam thresholds - -**Memory Issues During Loading** -- **Symptom**: Loading fails due to insufficient memory -- **Cause**: Large snapshot files exceeding available RAM -- **Solution**: Use streaming loading or increase system resources - -**Checksum Validation Errors** -- **Symptom**: Snapshot loading fails with checksum mismatch -- **Cause**: Corrupted snapshot file or tampering -- **Solution**: Recreate snapshot from source or download from trusted peer - -**Enhanced Automatic Snapshot Discovery Failures** -- **Symptom**: --snapshot-auto-latest option fails to find snapshots -- **Cause**: Incorrect snapshot directory configuration or malformed filenames -- **Solution**: Verify snapshot directory path and filename naming conventions - -**Enhanced Recovery Mode Issues** -- **Symptom**: --replay-from-snapshot fails to recover from corrupted state -- **Cause**: Missing snapshot file or incompatible snapshot format -- **Solution**: Verify snapshot file existence and compatibility, check DLT block log availability - -**Enhanced DLT Replay Failures** -- **Symptom**: DLT replay fails during recovery process -- **Cause**: Corrupted DLT block log or insufficient disk space -- **Solution**: Check DLT block log integrity, verify sufficient disk space, review error logs - -**Enhanced Watchdog and Server Issues** -- **Symptom**: Server appears to stop accepting connections -- **Cause**: Accept loop fiber died or became unresponsive -- **Solution**: Watchdog automatically restarts accept loop with full cleanup - -**Enhanced Error Handling Issues** -- **Symptom**: Unlinkable block exceptions during snapshot import -- **Cause**: Improper LIB promotion or fork database state -- **Solution**: Verify LIB promotion to head block and fork database seeding - -**Enhanced P2P Integration Issues** -- **Symptom**: Trusted peers still receiving 1-hour soft-bans instead of 5-minute soft-bans -- **Cause**: P2P plugin not properly registering trusted peer endpoints -- **Solution**: Add client IP to trusted list or disable trust enforcement - -**Enhanced Trusted Peer Registration Issues** -- **Symptom**: P2P plugin fails to register trusted peer endpoints -- **Cause**: Snapshot plugin not providing trusted peer list or P2P plugin startup order issues -- **Solution**: Check snapshot plugin configuration and verify P2P plugin initialization sequence - -**Enhanced Snapshot Directory Creation Issues** -- **Symptom**: Snapshot creation fails with directory not found errors -- **Cause**: Automatic directory creation not working or permission issues -- **Solution**: Verify snapshot directory permissions and manual creation if needed - -**Enhanced Logging Color Issues** -- **Symptom**: Log messages appear without color codes -- **Cause**: Terminal not supporting ANSI color codes or color output disabled -- **Solution**: Check terminal capabilities or disable color output in configuration - -**Enhanced P2P Stale Sync Detection Issues** -- **Symptom**: P2P stale sync detection not triggering recovery actions -- **Cause**: Timeout too low or P2P plugin not properly tracking last block received time -- **Solution**: Increase `p2p-stale-sync-timeout-seconds`, verify P2P plugin initialization - -**Enhanced DLT Block Log Reset Handling Issues** -- **Symptom**: Automatic snapshots not created after DLT block log reset -- **Cause**: DLT mode not enabled or snapshot directory not configured -- **Solution**: Verify DLT mode configuration and snapshot directory settings - -**Enhanced Anti-Spam Configuration Issues** -- **Symptom**: Users experiencing connection denials despite legitimate usage -- **Cause**: Anti-spam limits too restrictive with new values (3 sessions/IP, 10 connections/hour/IP) -- **Solution**: Review anti-spam configuration, consider increasing limits for legitimate use cases, monitor connection patterns - -**Enhanced Stalled Sync Detection Issues** -- **Symptom**: Stalled sync detection not functioning properly -- **Cause**: Main thread blocked in io_serv->run() preventing fc fiber execution -- **Solution**: Verify dedicated stalled sync thread is running and properly configured - -**Enhanced Automatic Gap Detection Issues** -- **Symptom**: Index position mismatch assertions during DLT block log initialization -- **Cause**: Gap between DLT block log head and snapshot head not properly detected -- **Solution**: Verify DLT block log gap detection logic and automatic reset mechanism - -**Enhanced Error Handling for Snapshot Download Operations Issues** -- **Symptom**: Stalled sync monitoring stops when snapshot download fails -- **Cause**: Missing exception handling for snapshot download attempts -- **Solution**: Verify enhanced error handling is properly catching fc::exception and std::exception types - -**Enhanced Undo Stack Management Issues** -- **Symptom**: Database state corruption during snapshot loading -- **Cause**: Missing db.undo_all() call before set_revision operations -- **Solution**: Verify proper undo stack management with db.undo_all() before set_revision - -**Enhanced Exception Handling Issues** -- **Symptom**: Snapshot download failures not properly handled -- **Cause**: Missing comprehensive exception handling for both fc::exception and std::exception types -- **Solution**: Verify enhanced exception handling covers all error scenarios during snapshot download attempts - -**Enhanced Hot-Reload Scenario Issues** -- **Symptom**: Stalled sync detection fails during hot-reload scenarios -- **Cause**: Undo stack not properly cleared before import operations -- **Solution**: Verify db.undo_all() is called before import operations during hot-reload scenarios - -**Enhanced Database State Cleanup Issues** -- **Symptom**: Database state inconsistency after snapshot loading -- **Cause**: Missing proper cleanup of multi-instance objects during hot-reload -- **Solution**: Verify comprehensive object clearing for hot-reload scenarios before import operations - -**Enhanced Stale Snapshot Detection Issues** -- **Symptom**: Stale snapshot detection not working properly -- **Cause**: needs_fresh_snapshot flag not being set or applied_block signal not connecting -- **Solution**: Verify stale snapshot detection logic, check DLT block log start block detection, and ensure urgent fresh snapshot creation is triggered - -**Enhanced Urgent Fresh Snapshot Creation Issues** -- **Symptom**: Urgent fresh snapshots not being created when stale snapshot detected -- **Cause**: needs_fresh_snapshot flag not reset or validator-aware deferral interfering -- **Solution**: Verify needs_fresh_snapshot flag management, check validator-aware deferral logic, and ensure proper snapshot creation scheduling - -**Enhanced Diagnostic Tools** - -The plugin includes comprehensive enhanced diagnostic capabilities: - -- **Trusted Seeds Test**: Validates connectivity and performance of configured peers -- **Stalled Sync Detection**: Automatically recovers from network partitions -- **Watchdog Monitoring**: Real-time server health and accept loop status -- **Access Control Logging**: Detailed logs for denial reasons and security events -- **Emergency Consensus Monitoring**: Tracks emergency consensus activation status -- **Recovery Workflow Diagnostics**: Comprehensive logging for recovery process monitoring -- **DLT Replay Status**: Real-time monitoring of DLT replay progress and status -- **Asynchronous Execution Monitoring**: Tracks snapshot creation progress and thread health -- **Signal-Based DLT Reset Handling**: Monitors DLT block log reset events and automatic snapshot creation -- **Enhanced P2P Integration Diagnostics**: Monitors trusted peer endpoint registration and soft-ban duration application -- **Snapshot Directory Management**: Monitors automatic directory creation and cleanup processes -- **Enhanced Logging Diagnostics**: Monitors ANSI color code application and terminal compatibility -- **P2P Stale Sync Detection Diagnostics**: Monitors LIB reset, peer reconnection, and seed node management -- **Enhanced Anti-Spam Configuration Diagnostics**: Monitors session limits, rate limiting, and connection patterns -- **Dedicated Threading Diagnostics**: Monitors stalled sync thread health and operation status -- **Automatic Gap Detection Diagnostics**: Monitors DLT block log gap detection and automatic reset operations -- **Enhanced Error Handling Diagnostics**: Monitors exception handling for snapshot download operations -- **Undo Stack Management Diagnostics**: Monitors database state cleanup and undo stack operations -- **Enhanced Exception Handling Diagnostics**: Monitors comprehensive exception handling coverage -- **Stale Snapshot Detection Diagnostics**: Monitors gap detection logic and urgent fresh snapshot creation -- **Urgent Fresh Snapshot Creation Diagnostics**: Monitors needs_fresh_snapshot flag management and snapshot creation scheduling - -**Updated** The modular architecture provides enhanced diagnostic capabilities through separate layers for serialization, networking, database operations, security controls, recovery workflows, asynchronous execution, watchdog monitoring, **signal-based DLT block log reset handling**, **enhanced P2P integration**, **enhanced error handling**, **improved undo stack management**, **stale snapshot detection**, and **enhanced exception handling**. Recent improvements include watchdog monitoring, **signal-based DLT block log reset handling diagnostics**, enhanced P2P fallback diagnostics, emergency consensus status tracking, comprehensive recovery workflow diagnostics, DLT replay status monitoring, asynchronous execution health monitoring, **P2P stale sync detection diagnostics**, **dedicated threading diagnostics**, **automatic gap detection diagnostics**, **enhanced error handling diagnostics**, **undo stack management diagnostics**, **stale snapshot detection diagnostics**, **urgent fresh snapshot creation diagnostics**, and **enhanced exception handling diagnostics**. - -**Section sources** -- [plugin.cpp:2294-2464](file://plugins/snapshot/plugin.cpp#L2294-L2464) -- [plugin.cpp:1378-1464](file://plugins/snapshot/plugin.cpp#L1378-L1464) - -## Conclusion - -The Snapshot Plugin System represents a sophisticated solution for blockchain state synchronization that significantly improves the VIZ node bootstrapping experience. Through careful architectural design, comprehensive feature coverage, and robust error handling, it enables efficient deployment and scaling of VIZ-based applications. - -**Updated** The recent enhancements with comprehensive snapshot plugin configuration supporting multiple trusted snapshot peers, snapshot scheduling parameters, serving options, watchdog monitoring, automatic snapshot discovery, integrated recovery workflow, enhanced anti-spam protection, **signal-based DLT block log reset handling**, **enhanced P2P integration with trusted peer support**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, and **enhanced exception handling** have significantly strengthened the security, reliability, and resource management capabilities of the snapshot distribution services. - -Key strengths of the system include its modular architecture, extensive configuration options, built-in performance optimizations, comprehensive security features, automatic snapshot discovery, integrated recovery workflow, DLT replay integration, watchdog monitoring, asynchronous execution system, comprehensive diagnostic capabilities, **signal-based DLT block log reset handling**, **P2P stale sync detection**, **dedicated threading for stalled sync detection**, **automatic gap detection for DLT block log initialization**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, **automatic P2P integration with trusted peer support**, and **enhanced exception handling**. The plugin seamlessly integrates with existing VIZ infrastructure while providing powerful new capabilities for state management, peer-to-peer synchronization, automatic recovery from corrupted states, intelligent validator-aware scheduling, **efficient P2P integration with trusted peer support**, **lightweight P2P stale sync detection**, **intelligent gap detection preventing index position mismatch assertions**, **robust error handling for snapshot download operations**, **proper undo stack management during snapshot loading**, **stale snapshot detection with urgent fresh snapshot creation**, and **comprehensive exception handling mechanisms**. - -The implementation demonstrates best practices in blockchain plugin development, including proper resource management, error handling, user experience considerations, security through layered access control, comprehensive monitoring and recovery capabilities, asynchronous execution for improved performance, **signal-based DLT block log reset handling**, **dedicated threading for stalled sync detection**, **automatic gap detection for DLT block log initialization**, **enhanced error handling for snapshot download operations**, **improved undo stack management**, **stale snapshot detection**, and **enhanced exception handling**. The modular design enables independent development and testing of each component while maintaining system coherence, representing a significant advancement in extensibility and maintainability. - -Future enhancements could focus on additional compression algorithms, enhanced security features, expanded monitoring capabilities, more sophisticated access control policies, improved recovery workflow automation, enhanced DLT replay performance optimization, advanced validator-aware scheduling algorithms, **optimized signal-based DLT block log reset handling**, **further optimization of the dual-tier soft-ban system**, **enhanced P2P stale sync detection**, **improved dedicated threading for stalled sync detection**, **intelligent gap detection preventing index position mismatch assertions**, **comprehensive error handling for all snapshot operations**, **advanced undo stack management techniques**, **stale snapshot detection optimization**, **enhanced exception handling mechanisms**, and **stale snapshot detection with urgent fresh snapshot creation**. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Plugin System/Witness Guard Plugin.md b/.qoder/repowiki/en/content/Plugin System/Witness Guard Plugin.md deleted file mode 100644 index d7fbbe97c7..0000000000 --- a/.qoder/repowiki/en/content/Plugin System/Witness Guard Plugin.md +++ /dev/null @@ -1,416 +0,0 @@ -# validator Guard Plugin - - -**Referenced Files in This Document** -- [witness_guard.hpp](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp) -- [witness_guard.cpp](file://plugins/witness_guard/witness_guard.cpp) -- [CMakeLists.txt](file://plugins/witness_guard/CMakeLists.txt) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [account_object.hpp](file://libraries/chain/include/graphene/chain/account_object.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [config.ini](file://share/vizd/config/config.ini) -- [plugin.md](file://documentation/plugin.md) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) - -## Introduction - -The validator Guard Plugin is a specialized plugin for the VIZ blockchain node that automatically monitors and maintains validator signing keys to prevent downtime in block production. This plugin serves as a critical safety mechanism for validator operators who want to ensure their validators remain productive even when encountering issues with their signing keys. - -The plugin operates by continuously monitoring configured validators and automatically restoring their on-chain signing keys when they become null or invalid. It also includes intelligent auto-disable functionality to prevent excessive block production by a single validator, protecting the network from potential centralization risks. - -## Project Structure - -The validator Guard Plugin follows the standard VIZ plugin architecture pattern with a clear separation between interface and implementation: - -```mermaid -graph TB -subgraph "Plugin Structure" -A[witness_guard.hpp
Header Definition] --> B[witness_guard.cpp
Implementation] -C[CMakeLists.txt
Build Configuration] --> B -end -subgraph "Dependencies" -D[chain_plugin] --> B -E[p2p_plugin] --> B -F[protocol] --> B -G[utilities] --> B -H[time] --> B -I[appbase] --> B -end -subgraph "Chain Objects" -J[witness_objects.hpp] --> B -K[account_object.hpp] --> B -L[database.hpp] --> B -end -``` - -**Diagram sources** -- [witness_guard.hpp:1-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L1-L48) -- [witness_guard.cpp:1-559](file://plugins/witness_guard/witness_guard.cpp#L1-L559) -- [CMakeLists.txt:1-44](file://plugins/witness_guard/CMakeLists.txt#L1-L44) - -**Section sources** -- [witness_guard.hpp:1-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L1-L48) -- [witness_guard.cpp:1-559](file://plugins/witness_guard/witness_guard.cpp#L1-L559) -- [CMakeLists.txt:1-44](file://plugins/witness_guard/CMakeLists.txt#L1-L44) - -## Core Components - -The validator Guard Plugin consists of several key components that work together to provide comprehensive validator monitoring and protection: - -### Main Plugin Class -The primary plugin class implements the appbase plugin interface and manages the plugin lifecycle. It requires both the chain plugin and p2p plugin to function properly. - -### Internal Implementation (impl) -The internal implementation class contains all the core logic for: -- Configuration management and validation -- Periodic monitoring and restoration processes -- Auto-disable functionality for excessive block production -- Transaction broadcasting and confirmation tracking - -### Data Structures -The plugin maintains several critical data structures: -- **validator Configuration Map**: Stores validator names with their associated key pairs -- **Consecutive Block Counters**: Tracks blocks produced by each validator -- **Pending Restoration Tracking**: Manages in-flight transactions -- **Auto-Disabled validators**: Prevents automatic restoration of problematic validators - -**Section sources** -- [witness_guard.hpp:11-44](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L11-L44) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) - -## Architecture Overview - -The validator Guard Plugin integrates deeply with the VIZ blockchain's core infrastructure through a sophisticated event-driven architecture: - -```mermaid -sequenceDiagram -participant Node as "VIZ Node" -participant Chain as "Chain Plugin" -participant Guard as "validator Guard Plugin" -participant DB as "Database" -participant P2P as "P2P Network" -participant validator as "validator Node" -Note over Node,validator : Startup Phase -Node->>Guard : plugin_initialize() -Guard->>Guard : Parse Configuration -Guard->>DB : Verify Authority Keys -Guard->>Guard : Setup Monitoring -Note over Node,validator : Runtime Monitoring -Chain->>Guard : applied_block Signal -Guard->>Guard : Check Consecutive Blocks -Guard->>DB : Query validator Status -Guard->>Guard : Auto-Disable Check -alt Null Signing Key Detected -Guard->>DB : Fetch validator Object -Guard->>Guard : Build Restore Transaction -Guard->>P2P : Broadcast Transaction -Guard->>Guard : Track Confirmation -end -Note over Node,validator : Periodic Checks -Chain->>Guard : Block Applied -Guard->>Guard : Check Restoration Status -Guard->>DB : Confirm Transaction Inclusion -``` - -**Diagram sources** -- [witness_guard.cpp:410-548](file://plugins/witness_guard/witness_guard.cpp#L410-L548) -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) - -The architecture follows a reactive pattern where the plugin listens for blockchain events and responds appropriately. The plugin subscribes to the `applied_block` signal from the chain database, enabling it to monitor block production in real-time. - -**Section sources** -- [witness_guard.cpp:455-544](file://plugins/witness_guard/witness_guard.cpp#L455-L544) -- [database.hpp:1-200](file://libraries/chain/include/graphene/chain/database.hpp#L1-L200) - -## Detailed Component Analysis - -### Configuration Management - -The plugin supports extensive configuration options that allow fine-tuned control over its behavior: - -#### Core Configuration Options -- **validator-guard-enabled**: Enables or disables the entire plugin functionality -- **validator-guard-validator**: Configures individual validators with their key pairs -- **validator-guard-interval**: Sets the frequency of periodic checks in blocks -- **validator-guard-disable**: Controls auto-disable threshold for excessive block production - -#### validator Configuration Format -Each validator configuration requires three components: -1. **validator Name**: The account name of the validator -2. **Signing WIF**: Private key for signing blocks -3. **Active WIF**: Private key for transaction authorization - -The plugin validates all configurations during initialization and performs authority verification against the blockchain state. - -**Section sources** -- [witness_guard.cpp:301-408](file://plugins/witness_guard/witness_guard.cpp#L301-L408) - -### Monitoring and Restoration Logic - -The core monitoring functionality operates through a sophisticated state machine that tracks validator health and automatically restores compromised keys: - -```mermaid -flowchart TD -Start([Block Applied]) --> CheckStale["Check Stale Production Mode"] -CheckStale --> StaleEnabled{"Stale Production Enabled?"} -StaleEnabled --> |Yes| CheckHealth["Check Network Health (≥33%)"] -CheckHealth --> Healthy{"Network Healthy?"} -Healthy --> |No| SkipRestore["Skip Auto-Restore"] -Healthy --> |Yes| Proceed["Proceed with Check"] -StaleEnabled --> |No| Proceed -Proceed --> CheckSync["Check Node Sync Status"] -CheckSync --> SyncOK{"Node in Sync?"} -SyncOK --> |No| SkipRestore -SyncOK --> |Yes| CheckLIB["Check LIB Age"] -CheckLIB --> LIBOK{"LIB Recent?"} -LIBOK --> |No| SkipRestore -LIBOK --> |Yes| CheckWitnesses["Iterate Configured validators"] -CheckWitnesses --> NullKey{"Null Signing Key?"} -NullKey --> |No| ClearState["Clear Pending State"] -NullKey --> |Yes| CheckAutoDisabled{"Auto-Disabled?"} -CheckAutoDisabled --> |Yes| SkipRestore -CheckAutoDisabled --> |No| CheckPending{"Restore Pending?"} -CheckPending --> |Yes| CheckExpire{"Expired?"} -CheckExpire --> |Yes| RetryRestore["Retry Restore"] -CheckExpire --> |No| SkipRestore -CheckPending --> |No| InitiateRestore["Initiate Restore"] -RetryRestore --> InitiateRestore -InitiateRestore --> BroadcastTx["Broadcast Restore Transaction"] -BroadcastTx --> TrackConfirm["Track Confirmation"] -ClearState --> End([Complete]) -TrackConfirm --> End -SkipRestore --> End -``` - -**Diagram sources** -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) - -The restoration process includes comprehensive error handling and retry mechanisms to ensure reliable key restoration even in challenging network conditions. - -**Section sources** -- [witness_guard.cpp:197-246](file://plugins/witness_guard/witness_guard.cpp#L197-L246) -- [witness_guard.cpp:252-294](file://plugins/witness_guard/witness_guard.cpp#L252-L294) - -### Auto-Disable Mechanism - -The plugin includes an intelligent auto-disable feature designed to prevent excessive block production by a single validator: - -#### Consecutive Block Detection -The system tracks blocks produced by each validator and increments counters when the same validator produces consecutive blocks. When the counter reaches the configured threshold, the system automatically disables the validator by broadcasting a transaction that sets the signing key to null. - -#### Prevention of Excessive Centralization -This mechanism serves as a safeguard against: -- Single-validator dominance in block production -- Potential malicious behavior by a single validator -- Network instability caused by excessive block production - -#### Operator Intervention Required -When a validator is auto-disabled, the plugin prevents automatic restoration to ensure operators investigate and address underlying issues. Manual intervention is required to re-enable the validator. - -**Section sources** -- [witness_guard.cpp:459-495](file://plugins/witness_guard/witness_guard.cpp#L459-L495) -- [witness_guard.cpp:467-484](file://plugins/witness_guard/witness_guard.cpp#L467-L484) - -### Transaction Broadcasting and Confirmation - -The plugin implements robust transaction management for both restoration and disabling operations: - -#### Transaction Construction -Each operation constructs a properly formatted `witness_update` transaction with: -- Correct validator owner identification -- Appropriate URL preservation -- Proper key updates (restore or disable) -- Transaction expiration handling - -#### Broadcasting Strategy -Transactions are broadcast through the P2P network with careful consideration of: -- Transaction fee optimization -- Network congestion handling -- Confirmation tracking mechanisms - -#### Confirmation Tracking -The plugin maintains detailed tracking of all broadcast transactions: -- Transaction ID correlation -- Expiration time management -- Confirmation verification in subsequent blocks -- Automatic retry for failed transactions - -**Section sources** -- [witness_guard.cpp:197-246](file://plugins/witness_guard/witness_guard.cpp#L197-L246) -- [witness_guard.cpp:252-294](file://plugins/witness_guard/witness_guard.cpp#L252-L294) - -## Dependency Analysis - -The validator Guard Plugin has carefully managed dependencies that enable it to function effectively within the VIZ ecosystem: - -```mermaid -graph LR -subgraph "Plugin Dependencies" -A[witness_guard_plugin] --> B[chain_plugin] -A --> C[p2p_plugin] -A --> D[protocol] -A --> E[utilities] -A --> F[time] -A --> G[appbase] -end -subgraph "Chain Dependencies" -B --> H[database] -H --> I[witness_objects] -H --> J[account_authority_object] -H --> K[global_property_object] -end -subgraph "External Dependencies" -L[fc::signals] --> M[Boost Signals] -N[fc::variant] --> O[JSON Processing] -P[fc::ecc] --> Q[Crypto Operations] -end -A --> L -A --> N -A --> P -``` - -**Diagram sources** -- [CMakeLists.txt:26-34](file://plugins/witness_guard/CMakeLists.txt#L26-L34) -- [witness_guard.cpp:3-18](file://plugins/witness_guard/witness_guard.cpp#L3-L18) - -### Core Dependencies - -#### Chain Plugin Integration -The plugin requires the chain plugin for: -- Database access and manipulation -- Block production scheduling -- validator object management -- Authority verification - -#### P2P Plugin Integration -The plugin requires the p2p plugin for: -- Transaction broadcasting -- Network connectivity -- Peer communication -- Transaction propagation - -#### Protocol Dependencies -The plugin relies on protocol definitions for: -- Operation structures -- Authority formats -- Transaction construction -- Cryptographic operations - -**Section sources** -- [CMakeLists.txt:26-34](file://plugins/witness_guard/CMakeLists.txt#L26-L34) -- [witness_guard.hpp:3-6](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L3-L6) - -## Performance Considerations - -The validator Guard Plugin is designed with performance optimization in mind to minimize impact on node operations: - -### Efficient Monitoring Strategy -- **Event-Driven Architecture**: Uses blockchain event signals rather than polling -- **Intelligent Scheduling**: Adjusts check frequency based on network conditions -- **Selective Processing**: Only processes blocks that affect monitored validators -- **Memory Management**: Implements efficient data structures for tracking state - -### Resource Optimization -- **Minimal Memory Footprint**: Uses compact data structures for tracking -- **Efficient Key Storage**: Optimizes storage of validator configurations -- **Connection Management**: Properly manages database connections -- **Signal Handling**: Efficient signal connection and disconnection - -### Network Efficiency -- **Transaction Batching**: Minimizes unnecessary transaction broadcasts -- **Confirmation Optimization**: Reduces redundant processing of confirmed transactions -- **Network Awareness**: Adapts behavior based on network conditions -- **Timeout Management**: Implements appropriate timeouts for various operations - -## Troubleshooting Guide - -### Common Issues and Solutions - -#### Plugin Not Starting -**Symptoms**: Plugin fails to initialize or appears disabled -**Causes**: -- Missing configuration options -- Invalid validator configurations -- Missing required plugins (chain, p2p) -- Authority verification failures - -**Solutions**: -- Verify all configuration options are properly set -- Check validator configuration format and validity -- Ensure required plugins are enabled in config.ini -- Validate validator authority keys against blockchain state - -#### validator Restoration Failures -**Symptoms**: validator keys not being restored despite null signing keys -**Causes**: -- Active authority key mismatch -- Insufficient network synchronization -- Stale production mode interference -- Transaction broadcast failures - -**Solutions**: -- Verify active authority key matches on-chain authority -- Ensure node is fully synchronized with network -- Check stale production mode configuration -- Monitor P2P network connectivity and transaction propagation - -#### Auto-Disable Issues -**Symptoms**: validators being auto-disabled unexpectedly or not being disabled -**Causes**: -- Incorrect disable threshold configuration -- Network timing issues -- validator scheduling conflicts -- Database access problems - -**Solutions**: -- Review and adjust disable threshold settings -- Monitor validator production patterns -- Check network stability and block times -- Verify database connectivity and performance - -### Configuration Validation - -The plugin performs extensive validation during initialization: - -#### Configuration Validation Steps -1. **Option Parsing**: Validates all command-line and config file options -2. **validator Entry Validation**: Verifies each validator configuration triplet -3. **Authority Verification**: Confirms active keys have proper authority -4. **Network Health Assessment**: Evaluates current network conditions -5. **Stale Production Detection**: Identifies stale production mode activation - -#### Error Handling and Logging -The plugin implements comprehensive logging for troubleshooting: -- **Debug Information**: Detailed operational information -- **Warning Messages**: Potential issues and recommendations -- **Error Reporting**: Critical failures and resolution steps -- **Success Confirmations**: Successful operations and outcomes - -**Section sources** -- [witness_guard.cpp:330-408](file://plugins/witness_guard/witness_guard.cpp#L330-L408) -- [witness_guard.cpp:410-548](file://plugins/witness_guard/witness_guard.cpp#L410-L548) - -## Conclusion - -The validator Guard Plugin represents a sophisticated solution for maintaining validator reliability in the VIZ blockchain ecosystem. Its comprehensive monitoring capabilities, intelligent auto-disable mechanisms, and robust restoration processes provide essential protection against validator downtime while preventing excessive centralization risks. - -The plugin's architecture demonstrates best practices in blockchain plugin development, including proper separation of concerns, efficient resource management, and comprehensive error handling. Its integration with the VIZ blockchain's event-driven architecture enables real-time monitoring and response to network conditions. - -Key benefits of the validator Guard Plugin include: -- **Automated Reliability**: Continuous monitoring reduces manual intervention requirements -- **Network Protection**: Prevents excessive validator dominance and centralization -- **Operational Efficiency**: Intelligent scheduling minimizes performance impact -- **Security Enhancement**: Comprehensive validation protects against unauthorized operations - -For optimal deployment, operators should carefully configure the plugin according to their specific needs, monitor its performance regularly, and maintain awareness of network conditions that may affect its operation. The plugin's comprehensive logging and error reporting capabilities provide excellent visibility into its operations and help ensure reliable validator protection. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Project Overview.md b/.qoder/repowiki/en/content/Project Overview.md deleted file mode 100644 index 2435b923a3..0000000000 --- a/.qoder/repowiki/en/content/Project Overview.md +++ /dev/null @@ -1,388 +0,0 @@ -# Project Overview - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [building.md](file://documentation/building.md) -- [plugin.md](file://documentation/plugin.md) -- [main.cpp](file://programs/vizd/main.cpp) -- [config.ini](file://share/vizd/config/config.ini) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini) -- [vizd.sh](file://share/vizd/vizd.sh) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [social_network.hpp](file://plugins/social_network/include/graphene/plugins/social_network/social_network.hpp) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -VIZ is a Graphene-based blockchain implementing Fair-DPOS consensus, designed as a full consensus node for the VIZ World platform. It provides a robust, extensible foundation for decentralized applications, social networks, and financial systems with a focus on fairness, transparency, and efficient governance. The project emphasizes: -- Fair-DPOS consensus ensuring equitable validator participation and penalties for missed blocks -- Rich social and content features integrated into the blockchain state -- A modular plugin architecture enabling flexible node configurations for different roles (full node, validator, indexer, etc.) -- Strong developer tooling and operational scripts for building, running, and maintaining nodes - -Target audiences: -- Node operators: Run full nodes, seed nodes, and validator nodes with configurable plugins and performance tuning -- Application developers: Build decentralized apps leveraging JSON-RPC APIs and plugin-specific endpoints -- Wallet developers: Integrate with database and chain APIs for account, transaction, and content queries - -Key differentiators: -- Fair-DPOS with explicit participation checks and penalties for inactive validators -- Integrated social features (content, voting, rewards, invites, subscriptions) in the core chain -- Extensive plugin ecosystem for APIs, indexing, and specialized node roles -- Operational readiness with Docker images, seed nodes, and shell scripts - -**Section sources** -- [README.md](file://README.md#L5-L10) -- [building.md](file://documentation/building.md#L1-L20) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) - -## Project Structure -At a high level, the repository is organized into: -- Core libraries: Protocol definitions, chain logic, network messaging, utilities, and wallet support -- Plugins: Modular extensions exposing APIs and specialized functionality (e.g., validator, social_network, database_api) -- Programs: Executables (vizd, cli_wallet) and utilities -- Documentation: Build instructions, plugin usage, testnet setup, and API notes -- Share assets: Configurations, Dockerfiles, seed nodes, and shell scripts for deployment - -```mermaid -graph TB -subgraph "Programs" -VIZD["vizd (full node)"] -CLI["cli_wallet"] -end -subgraph "Libraries" -LChain["libraries/chain"] -LProto["libraries/protocol"] -LNet["libraries/network"] -LUtil["libraries/utilities"] -LWallet["libraries/wallet"] -end -subgraph "Plugins" -PChain["plugins/chain"] -PWitness["plugins/validator"] -PDB["plugins/database_api"] -PSocial["plugins/social_network"] -PJSON["plugins/json_rpc"] -PWeb["plugins/webserver"] -PComm["plugins/committee_api"] -PInv["plugins/invite_api"] -PPaid["plugins/paid_subscription_api"] -end -VIZD --> PChain -VIZD --> PWitness -VIZD --> PDB -VIZD --> PSocial -VIZD --> PJSON -VIZD --> PWeb -VIZD --> PComm -VIZD --> PInv -VIZD --> PPaid -PChain --> LChain -PDB --> LChain -PSocial --> LChain -PWitness --> LChain -PJSON --> LNet -PWeb --> LNet -LChain --> LProto -LChain --> LUtil -LWallet --> LProto -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) - -## Core Components -- Chain database and consensus engine: Manages blockchain state, fork resolution, block validation, validator scheduling, and reward/cashout mechanics -- Protocol definitions: Enumerates operations (transfers, content, governance, social features) and virtual operations for rewards and payouts -- Plugin architecture: Enables modular APIs (database, social_network, committee, invite, paid_subscription, witness_api) and transport (JSON-RPC, WebServer) -- Validator Plugin: Produces blocks according to Fair-DPOS participation thresholds and schedule -- Social network plugin: Exposes content, votes, replies, and governance APIs tailored for VIZ World’s social features -- Configuration and deployment: Comprehensive config files, Docker images, and shell scripts for production and testnet - -Practical examples: -- Run a full node: Use the provided Docker image or build from source, configure endpoints and plugins, and start the node -- Develop applications: Consume JSON-RPC endpoints exposed by database_api and social_network plugins -- Operate a validator: Enable the Validator Plugin, set validator name and private key, and monitor participation metrics - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L194-L227) -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L65) -- [social_network.hpp](file://plugins/social_network/include/graphene/plugins/social_network/social_network.hpp#L36-L76) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L111) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Architecture Overview -The node initializes plugins, opens the chain database, and starts P2P networking and webserver services. The chain plugin coordinates block production and validation, while Validator Plugin enforces Fair-DPOS participation. Social and governance plugins expose APIs for content, voting, and committee operations. - -```mermaid -graph TB -Main["vizd main()
initializes plugins"] --> Chain["chain plugin
blockchain state"] -Main --> P2P["p2p plugin
peer connections"] -Main --> Web["webserver plugin
HTTP/WebSocket"] -Main --> JSON["json_rpc plugin
RPC transport"] -Main --> DBAPI["database_api plugin
chain queries"] -Main --> validator["Validator Plugin
block production"] -Main --> Social["social_network plugin
content & votes"] -Main --> Others["other plugins
committee, invite, paid_subscription"] -Chain --> DB["database
blocks, txns, objects"] -DBAPI --> DB -Social --> DB -validator --> DB -P2P --> Net["network core"] -Web --> JSON -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L140) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L106-L140) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) - -## Detailed Component Analysis - -### Fair-DPOS Consensus and validator Production -Fair-DPOS ensures that only participating validators produce blocks, with penalties for missed slots. The chain tracks participation and schedules validators accordingly. Operators can configure participation thresholds and enable stale production for resilience. - -```mermaid -flowchart TD -Start(["Block production cycle"]) --> CheckSync["Check sync with network"] -CheckSync --> SyncOK{"Synced?"} -SyncOK --> |No| WaitSync["Wait for peers"] -SyncOK --> |Yes| CheckTurn["Is it my turn?"] -CheckTurn --> MyTurn{"validator slot active?"} -MyTurn --> |No| SleepSlot["Sleep until next slot"] -MyTurn --> |Yes| CheckParticipation["Check participation threshold"] -CheckParticipation --> PartOK{"Participation >= required?"} -PartOK --> |No| SkipBlock["Skip block production"] -PartOK --> |Yes| Produce["Generate and sign block"] -Produce --> Broadcast["Broadcast block to peers"] -SleepSlot --> CheckSync -WaitSync --> CheckSync -SkipBlock --> CheckSync -Broadcast --> CheckSync -``` - -**Diagram sources** -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L99-L103) - -**Section sources** -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L20-L32) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L99-L103) - -### Database and State Management -The database manages blocks, transactions, and domain objects (accounts, content, proposals, validators). It supports validation, push operations, fork resolution, and periodic processing (cashouts, inflation, committee actions). - -```mermaid -classDiagram -class Database { -+open(data_dir, shared_mem_dir, ...) -+reindex(data_dir, shared_mem_dir, from_block_num, ...) -+push_block(signed_block, skip_flags) -+push_transaction(signed_transaction, skip_flags) -+generate_block(when, witness_owner, priv_key, skip) -+get_account(name) -+get_content(author, permlink) -+get_witness_schedule_object() -+applied_block signal -+on_applied_transaction signal -} -class DynamicGlobalPropertyObject { -+head_block_number -+current_witness -+current_supply -+total_vesting_fund -+total_reward_fund -+average_block_size -+maximum_block_size -+current_aslot -+recent_slots_filled -+participation_count -+last_irreversible_block_num -+max_virtual_bandwidth -+current_reserve_ratio -} -Database --> DynamicGlobalPropertyObject : "manages" -``` - -**Diagram sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L287) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L133) - -**Section sources** -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L287) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L24-L133) - -### Protocol Operations and Social Features -The protocol defines operations covering transfers, vesting, governance proposals, and social features such as content creation, voting, rewards, invites, and paid subscriptions. These operations drive the state managed by the chain database. - -```mermaid -classDiagram -class Operation { -<> -+transfer_operation -+transfer_to_vesting_operation -+withdraw_vesting_operation -+account_update_operation -+witness_update_operation -+account_witness_vote_operation -+account_witness_proxy_operation -+proposal_create/update/delete_operation -+chain_properties_update_operation -+content_operation -+delete_content_operation -+vote_operation -+custom_operation -+author_reward_operation -+curation_reward_operation -+content_reward_operation -+witness_reward_operation -+create_invite_operation -+claim_invite_balance_operation -+invite_registration_operation -+set_paid_subscription_operation -+paid_subscribe_operation -+award_operation -+receive_award_operation -+benefactor_award_operation -} -``` - -**Diagram sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -**Section sources** -- [operations.hpp](file://libraries/protocol/include/graphene/protocol/operations.hpp#L13-L102) - -### Plugin APIs and Deployment -The node enables a wide array of plugins for APIs and transport. Configuration files define endpoints, plugin lists, and validator credentials. Shell scripts and Docker images streamline deployment and seeding. - -```mermaid -sequenceDiagram -participant Operator as "Operator" -participant Script as "vizd.sh" -participant VIZD as "vizd" -participant P2P as "p2p plugin" -participant Web as "webserver plugin" -participant JSON as "json_rpc plugin" -Operator->>Script : "Run with env vars" -Script->>VIZD : "Start with args (RPC/P2P/data)" -VIZD->>P2P : "Initialize P2P" -VIZD->>Web : "Start HTTP/WS" -VIZD->>JSON : "Expose RPC endpoints" -VIZD-->>Operator : "Logs and metrics" -``` - -**Diagram sources** -- [vizd.sh](file://share/vizd/vizd.sh#L74-L81) -- [config.ini](file://share/vizd/config/config.ini#L1-L130) - -**Section sources** -- [plugin.md](file://documentation/plugin.md#L11-L28) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) - -## Dependency Analysis -The node composes multiple subsystems: -- Program entry point registers and starts plugins -- Plugins depend on chain library for state and protocol definitions -- Network and transport plugins depend on network core -- Social and governance plugins depend on chain objects and protocol operations - -```mermaid -graph LR -Entry["programs/vizd/main.cpp"] --> Reg["register_plugins()"] -Reg --> PChain["plugins/chain"] -Reg --> PWitness["plugins/validator"] -Reg --> PDB["plugins/database_api"] -Reg --> PSocial["plugins/social_network"] -Reg --> PJSON["plugins/json_rpc"] -Reg --> PWeb["plugins/webserver"] -PChain --> LChain["libraries/chain"] -PDB --> LChain -PSocial --> LChain -PWitness --> LChain -PJSON --> LNet["libraries/network"] -PWeb --> LNet -LChain --> LProto["libraries/protocol"] -``` - -**Diagram sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) - -**Section sources** -- [main.cpp](file://programs/vizd/main.cpp#L62-L91) - -## Performance Considerations -- Single write thread: Dedicates all write operations to a single thread to reduce lock contention and improve stability under load -- Lock wait tuning: Configurable read/write wait timeouts and retries to balance responsiveness and throughput -- Shared memory sizing: Adjustable initial size, minimum free space, and increment steps to manage storage growth efficiently -- Plugin notifications: Option to disable plugin notifications on push_transaction to reduce overhead -- Participation thresholds: Tuning participation requirements impacts block production frequency and network liveness - -Operational tips: -- Use LOW_MEMORY_NODE build option for consensus-only nodes (validators/seed nodes) -- Monitor shared memory free space and tune increments based on workload -- Adjust thread pool size for RPC clients to match CPU cores - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L36-L47) -- [config.ini](file://share/vizd/config/config.ini#L49-L67) -- [building.md](file://documentation/building.md#L11-L15) - -## Troubleshooting Guide -Common operational scenarios: -- Node not syncing: Verify P2P endpoints and seed nodes; check logs for connection errors -- RPC lock errors: Increase read/write wait retries or tune single-write-thread behavior -- Memory pressure: Reduce plugin overhead, enable virtual ops skipping, and adjust shared memory parameters -- validator production issues: Confirm participation thresholds, validator name, and private key configuration - -Useful references: -- Logging configuration via config sections for console and file appenders -- Testnet configuration enabling stale production and default validator credentials for development -- Shell script arguments for RPC/P2P endpoints and validator overrides - -**Section sources** -- [config.ini](file://share/vizd/config/config.ini#L112-L130) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L99-L111) -- [vizd.sh](file://share/vizd/vizd.sh#L62-L73) - -## Conclusion -VIZ delivers a Graphene-based blockchain optimized for fairness and social features, with a modular plugin architecture and strong operational tooling. Its Fair-DPOS consensus, integrated content and governance primitives, and extensive APIs make it suitable for diverse use cases—from full node operations and validator roles to application and wallet development. The combination of comprehensive documentation, Docker images, and shell scripts lowers the barrier to entry while offering deep customization for advanced users. - -## Appendices -- Practical examples: - - Full node: Use Docker image or build from source; configure endpoints and plugins; start with default or testnet config - - Application development: Consume database_api and social_network endpoints over HTTP/WebSocket - - validator operation: Enable Validator Plugin, set validator name and private key, monitor participation and block production - -**Section sources** -- [README.md](file://README.md#L12-L29) -- [building.md](file://documentation/building.md#L1-L20) -- [config.ini](file://share/vizd/config/config.ini#L69-L74) -- [config_testnet.ini](file://share/vizd/config/config_testnet.ini#L69-L111) -- [vizd.sh](file://share/vizd/vizd.sh#L1-L82) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Troubleshooting and FAQ.md b/.qoder/repowiki/en/content/Troubleshooting and FAQ.md deleted file mode 100644 index 1b69f800ff..0000000000 --- a/.qoder/repowiki/en/content/Troubleshooting and FAQ.md +++ /dev/null @@ -1,434 +0,0 @@ -# Troubleshooting and FAQ - - -**Referenced Files in This Document** -- [README.md](file://README.md) -- [documentation/building.md](file://documentation/building.md) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md) -- [documentation/api_notes.md](file://documentation/api_notes.md) -- [documentation/testnet.md](file://documentation/testnet.md) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini) -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp) -- [libraries/network/node.cpp](file://libraries/network/node.cpp) -- [libraries/network/include/graphene/network/exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [libraries/chain/include/graphene/chain/database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp) -- [plugins/debug_node/plugin.cpp](file://plugins/debug_node/plugin.cpp) - - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Troubleshooting Guide](#troubleshooting-guide) -9. [Conclusion](#conclusion) -10. [Appendices](#appendices) - -## Introduction -This document provides comprehensive troubleshooting and FAQ guidance for the VIZ CPP Node. It focuses on: -- Build issues and dependency problems -- Network connectivity failures and sync issues -- Performance tuning for memory, CPU, and disk I/O -- Interpretation of error messages and diagnostic procedures -- Frequently asked questions about node operation, API usage, plugin development, and integration -- Systematic debugging with the debug_node plugin, log analysis, and diagnostic tools -- Recovery procedures for common failure scenarios - -## Project Structure -The VIZ node is organized into libraries (chain, protocol, network, utilities, wallet), plugins (core and optional), and the main application entry point. Configuration is primarily managed via INI files, with logging configured through dedicated sections. - -```mermaid -graph TB -subgraph "Application" -MAIN["programs/vizd/main.cpp"] -end -subgraph "Libraries" -NET["libraries/network"] -CHAIN["libraries/chain"] -UTIL["libraries/utilities"] -WALLET["libraries/wallet"] -API["libraries/api"] -end -subgraph "Plugins" -P2P["plugins/p2p"] -CHAINPLUG["plugins/chain"] -WEB["plugins/webserver"] -DEBUG["plugins/debug_node"] -others["..."] -end -subgraph "Config" -CFG["share/vizd/config/config.ini"] -CFGD["share/vizd/config/config_debug.ini"] -end -MAIN --> NET -MAIN --> CHAIN -MAIN --> P2P -MAIN --> WEB -MAIN --> DEBUG -MAIN --> others -CFG -. loads .-> MAIN -CFGD -. loads .-> MAIN -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L69-L73) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini#L69) - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L69-L73) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini#L69) - -## Core Components -- Application entry and plugin registration: The main executable registers and initializes core plugins including chain, p2p, webserver, and optional plugins. -- Network layer: Provides peer-to-peer connectivity, message propagation, sync orchestration, and bandwidth monitoring. -- Chain database: Manages blockchain state, block and transaction validation, fork handling, and shared memory sizing. -- Configuration: Centralized via INI files controlling endpoints, RPC/TLS, plugin activation, and performance knobs. -- Logging: Configurable console and file appenders with logger sections. - -Key configuration areas: -- P2P endpoints, seed nodes, and connection limits -- RPC endpoints, thread pools, and lock timeouts -- Shared memory sizing and growth thresholds -- Plugin selection and API exposure -- Loggers and appenders - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L83-L107) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) -- [share/vizd/config/config_debug.ini](file://share/vizd/config/config_debug.ini#L1-L126) - -## Architecture Overview -High-level runtime flow: -- The application initializes plugins, loads configuration, and starts the P2P and webserver components. -- The P2P node connects to peers, discovers candidates, and synchronizes blocks and transactions. -- The chain database validates and applies blocks and transactions, emitting signals for plugins. -- The webserver exposes JSON-RPC APIs and WebSocket endpoints for clients. - -```mermaid -sequenceDiagram -participant App as "vizd main" -participant P2P as "P2P Node" -participant Net as "Network Layer" -participant DB as "Chain Database" -participant WS as "Webserver" -App->>P2P : Initialize and connect -P2P->>Net : Listen/connect to peers -Net-->>P2P : Peer inventory and messages -P2P->>DB : Push blocks/transactions -DB-->>P2P : Validation results and signals -App->>WS : Expose RPC/WebSocket APIs -WS-->>App : Requests processed via plugins -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L106-L142) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L776-L788) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L194-L206) - -## Detailed Component Analysis - -### Build and Dependency Troubleshooting -Common issues and resolutions: -- Missing system dependencies (Linux): Ensure required packages are installed as documented for your distribution. -- Boost version conflicts (especially on older distributions): Use the documented Boost versions and installation steps. -- Compiler compatibility: GCC and Clang are supported; avoid compilers not used by maintainers unless you can resolve warnings. -- Docker builds: Use provided Dockerfiles for reproducible environments. - -Recommended steps: -- Verify all documented dependencies are present. -- Clean build tree and rerun CMake with Release configuration. -- For Docker, use the provided Dockerfiles and tags. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L76-L137) -- [documentation/building.md](file://documentation/building.md#L138-L189) -- [documentation/building.md](file://documentation/building.md#L202-L212) - -### Network Connectivity and Sync Issues -Symptoms and diagnostics: -- No peers or slow peer discovery: - - Confirm P2P endpoint and seed nodes are configured. - - Clear peer database if stuck due to stale entries. -- Sync stalls or fork errors: - - Review network exceptions for unlinkable blocks or peers on unreachable forks. - - Consider checkpoints and shared memory sizing. -- Firewall/NAT: - - The node can detect firewall status and may require explicit public endpoint configuration. - -Actions: -- Adjust p2p-endpoint, p2p-max-connections, and p2p-seed-node. -- Increase read/write lock wait retries and microsecond timeouts if RPC contention is observed. -- Use the debug_node plugin to simulate and validate behavior in isolation. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L27) -- [libraries/network/include/graphene/network/exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L46) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L788-L796) - -### API Access Control and Security -- Bind RPC to localhost for trusted environments. -- Use TLS endpoints for remote access with proper certificates. -- Username/password authentication for specific API sets. - -Best practices: -- Keep public-api minimal and ordered. -- Use login_api as the second API for string identifier compatibility. -- Protect sensitive APIs with credentials and TLS. - -**Section sources** -- [documentation/api_notes.md](file://documentation/api_notes.md#L56-L121) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L16-L20) - -### Performance Tuning -Key levers: -- Single write thread: Reduces lock contention for write-heavy workloads. -- Plugin notifications on push_transaction: Disable to reduce overhead. -- Shared memory sizing: Tune initial size, minimum free space, and increment step. -- RPC thread pool size: Match to CPU cores minus one. -- Skip virtual operations: Reduce memory footprint for non-consensus nodes. - -Operational tips: -- Monitor average network read/write speeds exposed by the network layer. -- Adjust block-number-based free-space checks to balance safety and performance. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L36-L47) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L13-L14) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L632-L634) - -### Error Message Interpretation and Diagnostics -- Network exceptions: - - send_queue_overflow, insufficient_relay_fee, already_connected_to_requested_peer, block_older_than_undo_history, peer_is_on_an_unreachable_fork, unlinkable_block_exception. -- Chain exceptions: - - database_query_exception, block_validate_exception, transaction_exception, operation_validate_exception, operation_evaluate_exception, unlinkable_block_exception, unknown_hardfork_exception, plugin_exception, block_log_exception. - -Diagnostic procedure: -- Capture full exception backtraces from logs. -- Correlate timestamps with network and chain events. -- Use debug_node to reproduce and narrow issues in isolation. - -**Section sources** -- [libraries/network/include/graphene/network/exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L46) -- [libraries/chain/include/graphene/chain/database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L67-L117) - -### Debugging with the debug_node Plugin -Capabilities: -- Load blocks from a block log or JSON array. -- Generate blocks deterministically for testing. -- Edit chain state for “what-if” experiments. -- Replay and inspect applied operations. - -Usage highlights: -- Configure RPC to localhost for security. -- Enable debug_node and required APIs. -- Use curl or WebSocket clients to call debug APIs. - -Recovery and isolation: -- Use debug_node to validate assumptions and isolate bugs without affecting live networks. - -**Section sources** -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) -- [plugins/debug_node/plugin.cpp](file://plugins/debug_node/plugin.cpp#L475-L556) - -### Recovery Procedures -- Database corruption or replay issues: - - Use database reindex/replay capabilities with appropriate skip flags. - - Adjust shared memory sizing and free-space thresholds. -- Sync desynchronization: - - Clear peer database and restart sync. - - Verify checkpoints and hardfork handling. -- Configuration errors: - - Validate INI sections and logger configurations. - - Use minimal config to confirm correctness, then re-add options incrementally. - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L91-L92) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L94-L97) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L288) - -### Frequently Asked Questions -- How do I run a testnet? - - Use the provided Docker images or build locally with the testnet Dockerfile. -- How do I expose APIs securely? - - Bind RPC to localhost, or use TLS endpoints with certificates. -- How do I limit API access? - - Use username/password authentication and restrict allowed_apis. -- How do I troubleshoot missing peers? - - Check p2p-endpoint, p2p-seed-node, and firewall/NAT status. -- How do I improve performance? - - Tune shared memory sizing, single write thread, plugin notifications, and RPC thread pool. - -**Section sources** -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) -- [documentation/api_notes.md](file://documentation/api_notes.md#L56-L121) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L27) - -## Dependency Analysis -The application depends on a layered architecture: -- Application layer registers and orchestrates plugins. -- Network layer handles peer management and synchronization. -- Chain layer validates and applies state transitions. -- Utilities and wallet provide supporting functionality. - -```mermaid -graph LR -APP["vizd main"] --> P2P["p2p_plugin"] -APP --> CHAIN["chain_plugin"] -APP --> WEB["webserver_plugin"] -APP --> DEBUG["debug_node_plugin"] -P2P --> NETLIB["network library"] -CHAIN --> CHAINLIB["chain library"] -WEB --> APILIB["api library"] -``` - -**Diagram sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) -- [libraries/network/include/graphene/network/node.hpp](file://libraries/network/include/graphene/network/node.hpp#L190-L304) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L36-L561) - -**Section sources** -- [programs/vizd/main.cpp](file://programs/vizd/main.cpp#L62-L91) - -## Performance Considerations -- Memory: - - Tune shared memory initial size, minimum free space, and increment step. - - Consider skip-virtual-ops for reduced memory usage. -- CPU: - - Use single-write-thread to reduce lock contention. - - Disable plugin notifications on push_transaction for lower overhead. -- Disk I/O: - - Monitor average network read/write speeds. - - Adjust block-number-based free-space checks to balance safety and throughput. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L632-L634) - -## Troubleshooting Guide - -### Build Issues -- Symptoms: CMake fails or compiler errors. -- Checks: - - Dependencies installed per platform-specific instructions. - - Boost version matches documented requirements. - - Compiler is GCC or Clang. -- Actions: - - Clean build, rerun CMake with Release. - - Use Docker images for reproducibility. - -**Section sources** -- [documentation/building.md](file://documentation/building.md#L25-L75) -- [documentation/building.md](file://documentation/building.md#L76-L137) -- [documentation/building.md](file://documentation/building.md#L138-L189) - -### Network Connectivity Problems -- Symptoms: No peers, slow sync, or fork errors. -- Checks: - - P2P endpoint and seed nodes configured. - - Firewall/NAT status and public endpoint visibility. -- Actions: - - Clear peer database if stuck. - - Increase connection and timeout parameters. - - Use debug_node to validate behavior. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L27) -- [libraries/network/include/graphene/network/exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L46) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L788-L796) - -### API Access and Security -- Symptoms: Unauthorized access or TLS handshake failures. -- Checks: - - RPC endpoint binding and TLS configuration. - - Username/password policies and allowed_apis. -- Actions: - - Bind RPC to localhost for trusted environments. - - Configure TLS with matching certificate and client trust. - -**Section sources** -- [documentation/api_notes.md](file://documentation/api_notes.md#L56-L121) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L16-L20) - -### Performance Bottlenecks -- Symptoms: High lock wait errors, slow RPC, or memory pressure. -- Checks: - - Read/write lock wait retries and microsecond timeouts. - - Shared memory sizing and free-space thresholds. -- Actions: - - Enable single-write-thread and disable plugin notifications on push_transaction. - - Increase shared memory increments and adjust free-space checks. - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L22-L47) -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L49-L67) - -### Error Interpretation and Logs -- Use network and chain exception categories to classify issues. -- Capture full backtraces and correlate with timestamps. -- Employ debug_node to reproduce and validate fixes. - -**Section sources** -- [libraries/network/include/graphene/network/exceptions.hpp](file://libraries/network/include/graphene/network/exceptions.hpp#L33-L46) -- [libraries/chain/include/graphene/chain/database_exceptions.hpp](file://libraries/chain/include/graphene/chain/database_exceptions.hpp#L67-L117) -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) - -### Recovery Procedures -- Database issues: - - Reindex with appropriate skip flags. - - Resize shared memory and adjust free-space thresholds. -- Sync issues: - - Clear peer database and restart sync. - - Verify checkpoints and hardfork handling. -- Configuration errors: - - Validate INI sections and logger configurations. - - Gradually reintroduce options. - -**Section sources** -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L91-L92) -- [libraries/chain/include/graphene/chain/database.hpp](file://libraries/chain/include/graphene/chain/database.hpp#L94-L97) -- [libraries/network/node.cpp](file://libraries/network/node.cpp#L288) - -### Systematic Debugging with debug_node -- Isolate issues by loading historical blocks and generating deterministic blocks. -- Edit chain state for “what-if” experiments. -- Use localhost RPC and minimal API exposure for security. - -**Section sources** -- [documentation/debug_node_plugin.md](file://documentation/debug_node_plugin.md#L50-L134) -- [plugins/debug_node/plugin.cpp](file://plugins/debug_node/plugin.cpp#L475-L556) - -## Conclusion -This guide consolidates practical troubleshooting steps, performance tuning, and debugging techniques for the VIZ CPP Node. By aligning configuration with operational needs, leveraging the debug_node plugin, and interpreting structured error messages, most issues can be diagnosed and resolved efficiently. - -## Appendices - -### Quick Reference: Key Configuration Areas -- P2P: p2p-endpoint, p2p-max-connections, p2p-seed-node, checkpoint -- RPC: webserver-thread-pool-size, webserver-http-endpoint, webserver-ws-endpoint -- Locks: read-wait-micro, max-read-wait-retries, write-wait-micro, max-write-wait-retries -- Write path: single-write-thread -- Plugins: plugin list and public-api ordering -- Shared memory: shared-file-size, min-free-shared-file-size, inc-shared-file-size, block-num-check-free-size -- Logging: log.console_appender, log.file_appender, logger sections - -**Section sources** -- [share/vizd/config/config.ini](file://share/vizd/config/config.ini#L1-L130) - -### Testnet Launch -- Use Docker images or build locally with the testnet Dockerfile. -- Inspect snapshot behavior and initial users. - -**Section sources** -- [documentation/testnet.md](file://documentation/testnet.md#L21-L37) \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Validator.md b/.qoder/repowiki/en/content/Validator.md deleted file mode 100644 index fc79bf5889..0000000000 --- a/.qoder/repowiki/en/content/Validator.md +++ /dev/null @@ -1,1435 +0,0 @@ -# validator - - -**Referenced Files in This Document** -- [validator.hpp](file://plugins/validator/include/graphene/plugins/validator/validator.hpp) -- [validator.cpp](file://plugins/validator/validator.cpp) -- [witness_api_plugin.hpp](file://plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp) -- [witness_api_plugin.cpp](file://plugins/witness_api/plugin.cpp) -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) -- [chain_objects.hpp](file://libraries/chain/include/graphene/chain/chain_objects.hpp) -- [database.hpp](file://libraries/chain/include/graphene/chain/database.hpp) -- [database.cpp](file://libraries/chain/database.cpp) -- [fork_database.hpp](file://libraries/chain/include/graphene/chain/fork_database.hpp) -- [fork_database.cpp](file://libraries/chain/fork_database.cpp) -- [time.hpp](file://libraries/time/time.hpp) -- [time.cpp](file://libraries/time/time.cpp) -- [ntp.cpp](file://thirdparty/fc/src/network/ntp.cpp) -- [main.cpp](file://programs/vizd/main.cpp) -- [snapshot_plugin.cpp](file://plugins/snapshot/plugin.cpp) -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) -- [config.ini](file://share/vizd/config/config.ini) -- [config_witness.ini](file://share/vizd/config/config_witness.ini) -- [p2p_plugin.hpp](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp) -- [witness_guard.hpp](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp) -- [witness_guard.cpp](file://plugins/witness_guard/witness_guard.cpp) -- [global_property_object.hpp](file://libraries/chain/include/graphene/chain/global_property_object.hpp) - - -## Update Summary -**Changes Made** -- HF13: Implemented validator reward sharing — stakeholder reward distribution, `set_reward_sharing_operation`, `distribution_epoch_length` consensus parameter, `process_validator_epoch_distribution()`, new virtual op `stakeholder_reward_operation`; rewards accumulate as TOKEN and convert to SHARES at epoch end -- Added comprehensive validator protection and monitoring capabilities with new witness_guard plugin -- Enhanced emergency recovery mechanisms with auto-disable thresholds and improved network connectivity features -- Integrated validator key auto-restore functionality with emergency consensus mode support -- Implemented consecutive block auto-disable protection to prevent validator abuse -- Added enhanced minority fork detection with automatic recovery mechanisms -- Integrated emergency consensus detection and recovery procedures -- Enhanced network connectivity features with improved peer synchronization -- Isolated production timer on dedicated io_service/thread, preventing P2P I/O from delaying slot callbacks -- Fixed lag tight loop: tracks missed slot time and skips ahead to avoid rechecking the same slot every 250ms -- Added production watchdog: fires at 60s (emergency master) or 180s (regular validator) of no block produced -- Added slot hijack detection: counts consecutive slots where emergency master fills slots assigned to our validator -- Fixed false-positive hijack: own-validator blocks no longer trigger hijack counter -- Fixed slot index calculation (current_aslot % num_scheduled_witnesses) for correct schedule position -- Added not_my_turn streak detection: warns at 500 consecutive iterations (~125s) of schedule misalignment -- Added on_block_applied missed-slot diagnostic: dumps full plugin state when incoming block reveals our missed slots -- Refined slot=0 stall detection: only counts real NTP stalls (now ≤ head_block_time), not normal between-slot waits - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Configuration Parameters](#configuration-parameters) -6. [Detailed Component Analysis](#detailed-component-analysis) -7. [Dependency Analysis](#dependency-analysis) -8. [Performance Considerations](#performance-considerations) -9. [Troubleshooting Guide](#troubleshooting-guide) -10. [Conclusion](#conclusion) - -## Introduction -This document explains the validator subsystem of the VIZ node implementation. It covers how validators are scheduled, how blocks are produced, how validator participation is monitored, and how the validator-related APIs expose information to clients. The focus is on the Validator Plugin (block production), the validator API plugin (read-only queries), the validator guard plugin (protection and monitoring), and the underlying chain database that maintains validator state and schedules. - -**Updated** Enhanced with comprehensive validator protection and monitoring capabilities, emergency recovery mechanisms, auto-disable thresholds, improved network connectivity features, validator key auto-restore functionality, consecutive block protection, enhanced minority fork detection, emergency consensus integration, and automatic recovery procedures. - -## Project Structure -The validator functionality spans four primary areas: -- Validator Plugin: Produces blocks and validates blocks posted by other validators with optimized timing. -- validator Guard plugin: Provides protection and monitoring for validator keys with auto-restore and auto-disable capabilities. -- validator API plugin: Exposes validator-related read-only queries via JSON-RPC. -- Chain database: Maintains validator objects, voting, scheduling, and participation metrics. - -```mermaid -graph TB -subgraph "Node Binary" -VIZD["vizd main
registers plugins"] -end -subgraph "Plugins" -validator["Validator Plugin
optimized block production
fork collision timeout: 21 blocks
minority fork detection
DEBUG logging: enabled"] -WGUARD["validator Guard Plugin
key auto-restore
auto-disable protection
emergency consensus support"] -WAPI["validator API Plugin
JSON-RPC queries"] -SNAPSHOT["Snapshot Plugin
coordinated operations"] -P2P["P2P Plugin
broadcast
resync_from_lib()"] -CHAIN["Chain Plugin
database access"] -end -subgraph "Chain Database" -DB["database.hpp/.cpp
compare_fork_branches()
DEBUG logging: enabled
emergency_consensus_active"] -WITNESS_OBJ["witness_objects.hpp"] -BPV_OBJ["chain_objects.hpp
block_post_validation_object"] -FORK_DB["fork_database.hpp/.cpp
enhanced fork collision detection
automatic stale pruning"] -end -subgraph "Time Synchronization" -TIME["Time Service
NTP synchronization with 250ms ticks"] -END -VIZD --> validator -VIZD --> WGUARD -VIZD --> WAPI -VIZD --> SNAPSHOT -VIZD --> P2P -VIZD --> CHAIN -validator --> P2P -validator --> CHAIN -validator --> TIME -WGUARD --> CHAIN -WGUARD --> P2P -CHAIN --> DB -DB --> WITNESS_OBJ -DB --> BPV_OBJ -DB --> FORK_DB -WAPI --> CHAIN -CHAIN --> DB -SNAPSHOT --> validator -``` - -**Diagram sources** -- [main.cpp:63-92](file://programs/vizd/main.cpp#L63-L92) -- [validator.hpp:34-68](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L68) -- [validator.cpp:59-118](file://plugins/validator/validator.cpp#L59-L118) -- [witness_guard.hpp:11-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L11-L48) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) -- [witness_api_plugin.hpp:56-98](file://plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp#L56-L98) -- [witness_api_plugin.cpp:13-28](file://plugins/witness_api/plugin.cpp#L13-L28) -- [database.hpp:37-83](file://libraries/chain/include/graphene/chain/database.hpp#L37-L83) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [chain_objects.hpp:174-201](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L174-L201) -- [fork_database.hpp:53-81](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L81) -- [time.cpp:13-53](file://libraries/time/time.cpp#L13-L53) -- [snapshot_plugin.cpp:1267-1276](file://plugins/snapshot/plugin.cpp#L1267-1276) -- [p2p_plugin.hpp:50-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L50-L55) - -**Section sources** -- [main.cpp:63-92](file://programs/vizd/main.cpp#L63-L92) - -## Core Components -- Validator Plugin - - Provides optimized block production loop synchronized to 250ms intervals for deterministic slot time alignment. - - Validates whether it is time to produce a block, checks participation thresholds, and signs blocks with configured private keys. - - Broadcasts blocks and block post validations via the P2P plugin. - - **Enhanced**: Implements forced NTP synchronization when timing issues are detected during block production attempts. - - **Enhanced**: Implements comprehensive fork collision detection to prevent competing blocks at the same height. - - **Enhanced**: **NEW**: Implements comprehensive minority fork detection system to identify when all recent blocks were produced by local validators only. - - **Enhanced**: **NEW**: Provides automatic recovery through resync_from_lib() when minority fork is detected. - - **Enhanced**: **NEW**: Integrates with skip_undo_history_check flag to control production during recovery scenarios. - - **Enhanced**: **NEW**: Implements comprehensive debug logging with verbose traces for block production and chain internals. - - **New**: Provides `is_witness_scheduled_soon()` method to check if any locally-controlled validators are scheduled to produce blocks in the upcoming 4 slots. - - **New**: Implements two-level fork collision resolution system with configurable timeout blocks parameter (--fork-collision-timeout-blocks). - - **New**: Integrates with enhanced fork database for automatic stale fork pruning after successful block application. - - **New**: Runs production timer on a dedicated `boost::asio::io_service` and thread, isolated from P2P network I/O. - - **New**: Prevents lag tight loop: records missed slot time and skips ahead to avoid rechecking the same slot every 250ms. - - **New**: Production watchdog alerts when no block is produced for 60s (emergency master) or 180s (regular validator); auto-enables verbose debug logging on first fire. - - **New**: Slot hijack detection counts consecutive emergency-master-filled slots assigned to our validator in the shuffled schedule. - - **New**: not_my_turn streak detection warns after 500 consecutive iterations (~125s) of another validator holding all slots. - - **New**: Missed-slot diagnostics via `on_block_applied` signal: detects gaps and dumps full plugin state when our validator missed a slot. -- validator Guard Plugin - - **NEW**: Provides comprehensive validator protection and monitoring capabilities. - - **NEW**: Implements validator key auto-restore functionality to automatically restore null signing keys. - - **NEW**: Provides consecutive block auto-disable protection to prevent validator abuse by disabling validators after N consecutive blocks. - - **NEW**: Supports emergency consensus mode with automatic key restoration and recovery procedures. - - **NEW**: Monitors validator signing keys and automatically restores them when detected as null on-chain. - - **NEW**: Integrates with P2P plugin to broadcast witness_update transactions for key restoration and disabling. - - **NEW**: Implements safety checks including network health monitoring and long fork detection. - - **NEW**: Provides configurable check intervals and disable thresholds for flexible protection strategies. -- validator API Plugin - - Exposes read-only queries for active validators, schedule, individual validators, and counts. - - Returns API-friendly objects derived from chain validator data. -- Chain Database - - Stores validator objects, schedules, participation metrics, and supports validator scheduling and participation computations. - - Manages block post validation objects and updates last irreversible block computation based on validator confirmations. - - **Enhanced**: Provides enhanced fork database access with comprehensive querying capabilities for fork collision detection. - - **Enhanced**: Implements comprehensive validator reward creation with find_account() validation to prevent crashes from missing account objects. - - **Enhanced**: **NEW**: Integrates with skip_undo_history_check flag for controlled production during recovery scenarios. - - **Enhanced**: **NEW**: Implements comprehensive debug logging system enabling verbose traces for chain internals and block processing. - - **New**: Implements compare_fork_branches() function for intelligent fork weight comparison with +10% longer-chain bonus. - - **New**: Provides automatic stale fork pruning mechanism to remove competing blocks from dead forks. - - **New**: **Enhanced**: Supports emergency_consensus_active field for emergency consensus mode detection. - -**Updated** Added comprehensive error handling and validation for validator reward creation, including find_account() checks before creating vesting rewards, crash prevention mechanisms, clear recovery procedures for database corruption scenarios, new fork collision timeout configuration, two-level fork resolution system with vote-weighted comparison and stuck-head timeout, enhanced fork database querying capabilities, automatic stale fork pruning after successful block application, **NEW**: comprehensive minority fork detection system with automatic recovery mechanisms, **NEW**: enhanced emergency consensus mode integration, **NEW**: skip_undo_history_check flag for controlled production during recovery scenarios, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms with automatic key restoration, **NEW**: consecutive block protection to prevent validator abuse, **NEW**: enhanced network connectivity with improved peer synchronization. - -**Section sources** -- [validator.hpp:34-68](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L68) -- [validator.cpp:59-118](file://plugins/validator/validator.cpp#L59-L118) -- [validator.cpp:206-249](file://plugins/validator/validator.cpp#L206-L249) -- [witness_guard.hpp:11-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L11-L48) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) -- [witness_guard.cpp:360-369](file://plugins/witness_guard/witness_guard.cpp#L360-L369) -- [witness_api_plugin.hpp:56-98](file://plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp#L56-L98) -- [witness_api_plugin.cpp:13-28](file://plugins/witness_api/plugin.cpp#L13-L28) -- [database.hpp:37-83](file://libraries/chain/include/graphene/chain/database.hpp#L37-L83) - -## Architecture Overview -The validator subsystem integrates tightly with the chain database and P2P layer. The Validator Plugin periodically evaluates conditions to produce a block using optimized 250ms interval scheduling, consults the database for validator scheduling and participation, and broadcasts the resulting block. The validator guard plugin provides continuous monitoring and protection for validator keys, automatically restoring null signing keys and preventing validator abuse through auto-disable mechanisms. The validator API plugin reads from the database to serve JSON-RPC queries. **New**: Other plugins can now coordinate with validator scheduling using the `is_witness_scheduled_soon()` method to avoid conflicts during critical operations. - -**Enhanced** The architecture now includes robust NTP time synchronization with automatic fallback mechanisms, crash-safe shutdown procedures, plugin coordination capabilities through the new scheduling method, comprehensive fork collision detection system with two-level resolution, enhanced fork database querying capabilities, automatic stale fork pruning, enhanced validator reward creation with comprehensive validation and error handling, **NEW**: comprehensive minority fork detection system with automatic recovery mechanisms, **NEW**: enhanced emergency consensus mode integration, **NEW**: skip_undo_history_check flag for controlled production during recovery scenarios, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms with automatic key restoration, **NEW**: consecutive block protection to prevent validator abuse, **NEW**: enhanced network connectivity with improved peer synchronization. - -```mermaid -sequenceDiagram -participant Timer as "validator Impl
schedule_production_loop (250ms ticks)" -participant Guard as "validator Guard
auto-restore & protection" -participant NTP as "NTP Service
time synchronization" -participant DB as "Chain Database
DEBUG logging : enabled
emergency_consensus_active" -participant ForkDB as "Fork Database
collision detection
stale pruning" -participant P2P as "P2P Plugin" -participant Net as "Network" -participant Snapshot as "Snapshot Plugin
coordination" -Guard->>DB : check_and_restore_internal() -DB-->>Guard : network health & key status -alt network healthy & key null -Guard->>P2P : broadcast witness_update -P2P-->>Guard : transaction broadcast -Guard->>DB : track pending confirmation -else network unhealthy -Guard->>Guard : skip auto-restore -end -Timer->>NTP : check_time_sync() -NTP-->>Timer : synchronized status -alt timing issues detected -Timer->>NTP : force_sync() -NTP-->>Timer : updated time -end -Timer->>Timer : compute next 250ms boundary -Timer->>DB : get_slot_at_time(now + 250ms) -DB-->>Timer : slot -alt slot available -Timer->>DB : get_scheduled_witness(slot) -Timer->>DB : get_slot_time(slot) -Timer->>DB : witness_participation_rate() -alt conditions met -alt fork collision check -Timer->>ForkDB : fetch_block_by_number(head_block_num + 1) -ForkDB-->>Timer : existing blocks at height -alt competing blocks exist -alt LEVEL 1 : Vote-weighted comparison -Timer->>DB : compare_fork_branches(competing_id, head_id) -DB-->>Timer : weight comparison result -alt comparison possible -alt competing fork heavier -Timer->>NTP : force_sync() on fork collision -Timer->>Timer : log fork collision and defer -else our fork heavier -Timer->>ForkDB : remove(competing_id) -Timer->>Timer : reset defer count -else tied/comparison impossible -alt LEVEL 2 : Stuck-head timeout -Timer->>Timer : fork_collision_defer_count++ -alt timeout exceeded (21 blocks) -Timer->>ForkDB : remove_blocks_by_number(head_block_num + 1) -Timer->>Timer : reset defer count -Timer->>Timer : fall through to produce -else timeout not exceeded -Timer->>NTP : force_sync() on fork collision -Timer->>Timer : log fork collision and defer -end -else no competing blocks -alt minority fork detection -Timer->>ForkDB : check last CHAIN_MAX_WITNESSES blocks -alt all from our validators -alt emergency consensus active -Timer->>Timer : skip minority fork detection -else enable-stale-production enabled -Timer->>Timer : continue production -else enable-stale-production disabled -Timer->>P2P : resync_from_lib() -Timer->>Timer : production disabled -Timer->>Timer : return minority_fork -else not a minority fork -alt validator reward creation -Timer->>DB : get_witness(current_witness) -Timer->>DB : find_account(validator.owner) -alt account exists -Timer->>DB : create_vesting(account, reward) -Timer->>DB : push_virtual_operation(witness_reward) -else account missing -Timer->>DB : log critical error -Timer->>DB : FC_ASSERT restart required -end -Timer->>P2P : broadcast_block(block) -P2P->>Net : transmit block -end -else conditions not met -Timer->>NTP : update_ntp_time() on lag -Timer->>Timer : log reason (sync, participation, key, lag) -end -else no slot -Timer->>Timer : wait until next 250ms tick -end -Timer->>Timer : reschedule for next 250ms tick -Note over Snapshot : Check if validator scheduled soon
to coordinate operations -Snapshot->>Timer : is_witness_scheduled_soon() -Timer-->>Snapshot : true/false -``` - -**Diagram sources** -- [validator.cpp:206-276](file://plugins/validator/validator.cpp#L206-L276) -- [validator.cpp:278-423](file://plugins/validator/validator.cpp#L278-L423) -- [validator.cpp:447-471](file://plugins/validator/validator.cpp#L447-L471) -- [validator.cpp:590-695](file://plugins/validator/validator.cpp#L590-L695) -- [validator.cpp:263-266](file://plugins/validator/validator.cpp#L263-L266) -- [validator.cpp:206-249](file://plugins/validator/validator.cpp#L206-L249) -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) -- [witness_guard.cpp:455-544](file://plugins/witness_guard/witness_guard.cpp#L455-L544) -- [database.cpp:4317-4332](file://libraries/chain/database.cpp#L4317-L4332) -- [time.cpp:74-76](file://libraries/time/time.cpp#L74-L76) -- [snapshot_plugin.cpp:1267-1276](file://plugins/snapshot/plugin.cpp#L1267-1276) -- [database.cpp:2824-2839](file://libraries/chain/database.cpp#L2824-L2839) -- [database.cpp:2871-2886](file://libraries/chain/database.cpp#L2871-2886) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [p2p_plugin.hpp:50-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L50-L55) - -## Configuration Parameters - -### Parameter Types and Scaling - -The Validator Plugin configuration parameters have been updated with improved type safety and scaling: - -- **enable-stale-production**: Boolean parameter controlling whether block production continues when the chain is stale - - Type: `bool` (previously `int`) - - Default: `false` (changed from `true`) - - Purpose: Allows production even when the node is behind the chain head - - Command line: `--enable-stale-production` - - Config file: `enable-stale-production` - -- **required-participation**: Integer parameter specifying minimum validator participation percentage - - Type: `uint32_t` (changed from `int`) - - Scale: Multiplied by `CHAIN_1_PERCENT` (100 units = 1%) - - Range: 0-99% (0-9900 units) - - Default: 33% (3300 units) - - Command line: `--required-participation` - - Config file: `required-participation` - -- **fork-collision-timeout-blocks**: New parameter controlling fork collision timeout behavior - - Type: `uint32_t` - - Default: 21 blocks (one full validator round, 63 seconds) - - Purpose: Number of consecutive fork-collision deferrals before forcing production - - Command line: `--fork-collision-timeout-blocks` - - Config file: `fork-collision-timeout-blocks` - -- **debug-block-production**: **NEW** Boolean parameter enabling verbose debug logging for block production and chain internals - - Type: `bool` - - Default: `false` - - Purpose: Enables comprehensive logging with detailed traces of validator participation checks, emergency mode enforcement, block post-validation processes, and minority fork detection - - Command line: `--debug-block-production` - - Config file: `debug-block-production` - -### validator Guard Plugin Configuration - -**NEW** The validator guard plugin introduces several new configuration parameters: - -- **validator-guard-enabled**: Boolean parameter enabling/disabling the validator protection and monitoring system - - Type: `bool` - - Default: `true` - - Purpose: Controls whether the validator guard plugin is active - - Command line: `--validator-guard-enabled` - - Config file: `validator-guard-enabled` - -- **validator-guard-disable**: Integer parameter controlling consecutive block auto-disable threshold - - Type: `uint32_t` - - Default: 5 blocks - - Purpose: Number of consecutive blocks produced by the same validator before automatic disabling - - Command line: `--validator-guard-disable` - - Config file: `validator-guard-disable` - -- **validator-guard-interval**: Integer parameter controlling check frequency - - Type: `uint32_t` - - Default: 20 blocks (approximately 60 seconds) - - Purpose: How often to check validator signing keys in block intervals - - Command line: `--validator-guard-interval` - - Config file: `validator-guard-interval` - -- **validator-guard-validator**: Array parameter defining validators to monitor - - Type: `std::vector` - - Format: JSON triplet `["name", "signing_wif", "active_wif"]` - - Purpose: Specifies which validators to monitor and their key pairs - - Command line: `--validator-guard-validator` - - Config file: `validator-guard-validator` - -### Configuration Defaults - -**Updated** The default values have been corrected for production stability: - -- **enable-stale-production**: Now defaults to `false` to improve network stability and prevent minority fork propagation -- **required-participation**: Defaults to 33% participation threshold for balanced security/performance -- **fork-collision-timeout-blocks**: Defaults to 21 blocks to match one full validator schedule round -- **debug-block-production**: Defaults to `false` to maintain production performance while providing debugging capability when needed -- **validator-guard-enabled**: Defaults to `true` to provide comprehensive validator protection by default -- **validator-guard-disable**: Defaults to 5 consecutive blocks to prevent validator abuse while allowing normal operation -- **validator-guard-interval**: Defaults to 20 blocks for balanced monitoring frequency -- **validator-guard-validator**: Defaults to empty (no validators monitored) requiring explicit configuration - -### Configuration Processing - -The configuration parameters are processed during plugin initialization: - -```mermaid -flowchart TD -Config["Configuration File"] --> Parser["Parameter Parser"] -Parser --> TypeCheck{"Type Validation"} -TypeCheck --> |enable-stale-production| BoolConvert["Convert to bool
Default: false"] -TypeCheck --> |required-participation| IntConvert["Convert to uint32_t
Scale by CHAIN_1_PERCENT"] -TypeCheck --> |fork-collision-timeout-blocks| TimeoutConvert["Convert to uint32_t
Default: 21 blocks"] -TypeCheck --> |debug-block-production| DebugConvert["Convert to bool
Default: false"] -TypeCheck --> |validator-guard-enabled| GuardEnabled["Convert to bool
Default: true"] -TypeCheck --> |validator-guard-disable| DisableConvert["Convert to uint32_t
Default: 5"] -TypeCheck --> |validator-guard-interval| IntervalConvert["Convert to uint32_t
Default: 20"] -TypeCheck --> |validator-guard-validator| WitnessArray["Parse JSON triplets
Format: [name, signing_wif, active_wif]"] -BoolConvert --> Storage["Store in plugin state"] -IntConvert --> Storage -TimeoutConvert --> Storage -DebugConvert --> Storage -GuardEnabled --> Storage -DisableConvert --> Storage -IntervalConvert --> Storage -WitnessArray --> Storage -Storage --> Runtime["Runtime Usage"] -``` - -**Diagram sources** -- [validator.cpp:125-133](file://plugins/validator/validator.cpp#L125-L133) -- [validator.cpp:149-155](file://plugins/validator/validator.cpp#L149-L155) -- [validator.cpp:222-224](file://plugins/validator/validator.cpp#L222-L224) -- [validator.cpp:228-233](file://plugins/validator/validator.cpp#L228-L233) -- [witness_guard.cpp:301-328](file://plugins/witness_guard/witness_guard.cpp#L301-L328) -- [witness_guard.cpp:330-408](file://plugins/witness_guard/witness_guard.cpp#L330-L408) -- [config.hpp:57-58](file://libraries/protocol/include/graphene/protocol/config.hpp#L57-L58) - -**Section sources** -- [validator.cpp:125-133](file://plugins/validator/validator.cpp#L125-L133) -- [validator.cpp:149-155](file://plugins/validator/validator.cpp#L149-L155) -- [validator.cpp:222-224](file://plugins/validator/validator.cpp#L222-L224) -- [validator.cpp:228-233](file://plugins/validator/validator.cpp#L228-L233) -- [witness_guard.cpp:301-328](file://plugins/witness_guard/witness_guard.cpp#L301-L328) -- [witness_guard.cpp:330-408](file://plugins/witness_guard/witness_guard.cpp#L330-L408) -- [config.hpp:57-58](file://libraries/protocol/include/graphene/protocol/config.hpp#L57-L58) -- [config.ini:99-103](file://share/vizd/config/config.ini#L99-L103) -- [config_witness.ini:76-80](file://share/vizd/config/config_witness.ini#L76-L80) -- [config_witness.ini:128-141](file://share/vizd/config/config_witness.ini#L128-L141) - -## Detailed Component Analysis - -### Validator Plugin -Responsibilities: -- Parse configuration for validator names and private keys. -- Initialize NTP time synchronization with 250ms interval optimization. -- Run a production loop that: - - Waits until synchronized to the next 250ms boundary for deterministic slot alignment. - - Checks participation thresholds and scheduling eligibility. - - **Enhanced**: Performs comprehensive fork collision detection before block generation. - - **Enhanced**: **NEW**: Implements comprehensive minority fork detection to identify when all recent blocks were produced by local validators only. - - **Enhanced**: **NEW**: Provides automatic recovery through resync_from_lib() when minority fork is detected. - - **Enhanced**: **NEW**: Integrates with skip_undo_history_check flag for controlled production during recovery scenarios. - - **Enhanced**: **NEW**: Implements comprehensive debug logging with verbose traces for block production and chain internals. - - **New**: Implements two-level fork collision resolution system with configurable timeout. - - Generates and broadcasts blocks when eligible. - - Signs and broadcasts block post validations when available. - - **Enhanced**: Forces NTP synchronization when timing issues or fork collisions are detected during production attempts. - - **New**: Provides `is_witness_scheduled_soon()` method for external coordination. - -Key behaviors: -- Participation threshold enforcement via validator participation rate. -- Graceful handling of missing private keys, low participation, and timing lags. -- Optional allowance for stale production during initial sync. -- **Enhanced**: Automatic NTP synchronization on lag detection and fork collision to prevent timing-related production failures. -- **Enhanced**: Comprehensive fork collision detection prevents competing blocks at the same height. -- **Enhanced**: **NEW**: Minority fork detection identifies when all recent blocks were produced by local validators only. -- **Enhanced**: **NEW**: Automatic recovery through P2P resynchronization when minority fork is detected. -- **Enhanced**: **NEW**: Controlled production during recovery scenarios using skip_undo_history_check flag. -- **Enhanced**: **NEW**: Comprehensive debug logging system with verbose traces for detailed visibility into block production pipeline. -- **New**: Efficient slot checking across 4 upcoming slots to detect validator scheduling conflicts. -- **New**: Two-level fork collision resolution with vote-weighted comparison and stuck-head timeout mechanism. -- **New**: Configurable fork collision timeout blocks parameter for fine-tuning fork resolution behavior. - -```mermaid -flowchart TD -Start(["Startup"]) --> InitKeys["Load validator names and private keys"] -InitKeys --> InitNTP["Initialize NTP time service with 250ms ticks"] -InitNTP --> InitTimeout["Initialize fork-collision-timeout-blocks (21)"] -InitTimeout --> InitSkipFlag["Initialize skip_undo_history_check (false)"] -InitSkipFlag --> InitDebug["Initialize debug-block-production (false)"] -InitDebug --> SyncCheck["Wait until synchronized to 250ms boundary"] -SyncCheck --> SlotCheck{"Slot available?"} -SlotCheck --> |No| WaitNext["Sleep until next 250ms tick"] --> SyncCheck -SlotCheck --> |Yes| Scheduled["Get scheduled validator and slot time"] -Scheduled --> Participation{"Participation >= threshold?"} -Participation --> |No| LogLowParticipation["Log low participation"] --> Resched["Reschedule"] --> SyncCheck -Participation --> |Yes| TimeCheck{"Within 500ms window?"} -TimeCheck --> |No| LogLag["Log lag"] --> ForceSync["Force NTP sync"] --> Resched -TimeCheck --> |Yes| ForkCollision{"Fork collision check"} -ForkCollision --> |Competing blocks| Level1["LEVEL 1: Vote-weighted comparison"] -Level1 --> |Comparison possible| WeightCheck{"Weight comparison"} -WeightCheck --> |Our fork heavier| RemoveComp["Remove competing block"] --> ResetCount["Reset defer count"] --> SignCheck -WeightCheck --> |Competing fork heavier| LogCollision["Log fork collision"] --> ForceSync --> Resched -WeightCheck --> |Tied/Impossible| Level2["LEVEL 2: Stuck-head timeout"] -Level2 --> TimeoutCheck{"Defer count > timeout (21)?"} -TimeoutCheck --> |Yes| PruneFork["Prune stale competing blocks"] --> ResetCount -TimeoutCheck --> |No| LogCollision2["Log fork collision"] --> ForceSync --> Resched -ForkCollision --> |No competing blocks| MinorityFork{"Minority fork detection"} -MinorityFork --> |All recent blocks from us| EmergencyCheck{"Emergency consensus active?"} -EmergencyCheck --> |Yes| SkipMinority["Skip minority fork detection"] --> SignCheck -EmergencyCheck --> |No| StaleProdCheck{"enable-stale-production enabled?"} -StaleProdCheck --> |Yes| ContinueProd["Continue production"] --> SignCheck -StaleProdCheck --> |No| Resync["P2P resync_from_lib()"] --> DisableProd["Disable production"] --> ReturnMinority["Return minority_fork"] -MinorityFork --> |Not a minority fork| SignCheck{"Private key available?"} -SignCheck --> |No| LogNoKey["Log missing key"] --> Resched -SignCheck --> |Yes| RewardValidation{"Validate validator account"} -RewardValidation --> |Account exists| Produce["Generate block and broadcast"] -RewardValidation --> |Account missing| CriticalError["Log critical error
Request node restart"] -Produce --> Resched -``` - -**Diagram sources** -- [validator.cpp:206-276](file://plugins/validator/validator.cpp#L206-L276) -- [validator.cpp:278-423](file://plugins/validator/validator.cpp#L278-L423) -- [validator.cpp:447-471](file://plugins/validator/validator.cpp#L447-L471) -- [validator.cpp:590-695](file://plugins/validator/validator.cpp#L590-L695) -- [validator.cpp:263-266](file://plugins/validator/validator.cpp#L263-L266) -- [validator.cpp:509-555](file://plugins/validator/validator.cpp#L509-L555) -- [p2p_plugin.hpp:50-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L50-L55) - -**Section sources** -- [validator.hpp:34-68](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L68) -- [validator.cpp:120-169](file://plugins/validator/validator.cpp#L120-L169) -- [validator.cpp:171-192](file://plugins/validator/validator.cpp#L171-L192) -- [validator.cpp:206-276](file://plugins/validator/validator.cpp#L206-L276) -- [validator.cpp:278-423](file://plugins/validator/validator.cpp#L278-L423) -- [validator.cpp:447-471](file://plugins/validator/validator.cpp#L447-L471) -- [validator.cpp:590-695](file://plugins/validator/validator.cpp#L590-L695) -- [validator.cpp:206-249](file://plugins/validator/validator.cpp#L206-L249) -- [validator.cpp:509-555](file://plugins/validator/validator.cpp#L509-L555) - -### New: Enhanced Minoriy Fork Detection System -The Validator Plugin now implements a comprehensive minority fork detection system to identify when all recent blocks were produced by local validators only, indicating a potential minority fork scenario. - -**Detection Logic**: -- Checks the last CHAIN_MAX_WITNESSES (21) blocks in the fork database -- Verifies that all blocks were produced by configured local validators -- Skips detection during emergency consensus mode to prevent false positives -- Integrates with skip_undo_history_check flag for controlled production during recovery - -**Recovery Mechanisms**: -- **Automatic Recovery**: Calls P2P resync_from_lib() to reset sync from last irreversible block -- **Production Control**: Disables production temporarily during recovery -- **Flag Management**: Uses skip_undo_history_check to control production flags during recovery -- **Emergency Mode Protection**: Skips detection when emergency consensus is active - -**Implementation Details**: -- Uses `db.get_fork_db().head()` to access the fork database head -- Iterates backwards through CHAIN_MAX_WITNESSES blocks to verify validator ownership -- Checks `_witnesses.find(current->data.validator) == _witnesses.end()` to detect foreign validators -- Calls `p2p().resync_from_lib()` for automatic recovery -- Returns `block_production_condition::minority_fork` to signal recovery state -- Integrates with emergency consensus detection via `dgp.emergency_consensus_active` - -**Section sources** -- [validator.cpp:509-555](file://plugins/validator/validator.cpp#L509-L555) -- [validator.hpp:31](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L31) -- [database.hpp:88](file://libraries/chain/include/graphene/chain/database.hpp#L88) - -### New: Enhanced Fork Collision Detection System -The Validator Plugin now implements a comprehensive fork collision detection system to prevent competing blocks at the same height. - -**Detection Logic**: -- Queries the fork database for all blocks at the next height level (head_block_num + 1) -- Identifies competing blocks produced by different validators with different parent blocks -- Prevents block production when fork collision is detected -- Automatically triggers NTP synchronization to resolve timing issues - -**Two-Level Resolution System**: -- **LEVEL 1: Vote-weighted comparison** (HF12+) - - Uses compare_fork_branches() function to calculate vote weights for both forks - - Applies +10% bonus to longer chain for fairness - - Removes losing fork or defers production based on weight comparison -- **LEVEL 2: Stuck-head timeout** (All versions) - - Tracks consecutive deferral count for fork collisions - - Forces production after timeout exceeds configured blocks (default: 21) - - Removes all competing blocks at the target height after timeout - -**Implementation Details**: -- Uses `db.get_fork_db().fetch_block_by_number(db.head_block_num() + 1)` to query all blocks at the target height -- Analyzes each existing block to determine if it was produced by a different validator with a different parent -- Captures detailed information including height and scheduled validator for logging -- Returns `block_production_condition::fork_collision` to defer production -- Integrates with compare_fork_branches() function for intelligent fork switching decisions - -**Section sources** -- [validator.cpp:447-471](file://plugins/validator/validator.cpp#L447-L471) -- [validator.cpp:590-695](file://plugins/validator/validator.cpp#L590-L695) -- [fork_database.hpp:73](file://libraries/chain/include/graphene/chain/fork_database.hpp#L73) -- [fork_database.cpp:151-166](file://libraries/chain/fork_database.cpp#L151-166) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) - -### New: Enhanced Fork Database Integration with Automatic Stale Pruning -The fork database now includes automatic stale fork pruning capabilities to maintain database efficiency and prevent memory bloat. - -**Automatic Stale Pruning Mechanism**: -- Executes after successful block application in _push_block() method -- Identifies competing blocks at the same height that are no longer part of the active chain -- Removes blocks whose parent is no longer in fork_db (indicating dead fork) -- Prevents accumulation of stale competing blocks in the fork database - -**Pruning Logic**: -- Called after new block is successfully applied -- Fetches all competing blocks at new_block.block_num() -- Checks if competing block has unknown parent (not in fork_db) -- Removes stale competing blocks with log messages for debugging -- Preserves legitimate fork switching scenarios by only removing truly dead forks - -**Integration Points**: -- Triggered in database::_push_block() after successful block application -- Works in conjunction with fork collision detection system -- Supports both HF12+ vote-weighted comparisons and pre-HF12 longest-chain rules -- Maintains fork database integrity and performance - -**Section sources** -- [database.cpp:1456-1471](file://libraries/chain/database.cpp#L1456-L1471) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) - -### New: Enhanced compare_fork_branches() Function -The database now includes a sophisticated compare_fork_branches() function that intelligently evaluates fork weight and chain length for decision-making. - -**Function Capabilities**: -- Calculates total vote weight for each fork branch using validator objects -- Excludes emergency validator account from weight calculations -- Applies +10% bonus to longer chain to encourage network support -- Handles tied scenarios and comparison impossibility gracefully -- Returns 1 (branch_a heavier), -1 (branch_b heavier), or 0 (tied/impossible) - -**Weight Calculation Algorithm**: -- Iterates through branch items to accumulate validator vote weights -- Uses flat_set to avoid counting the same validator multiple times -- Skips emergency validator account for fairness -- Handles exceptions during validator lookup gracefully -- Returns 0 when comparison cannot be performed - -**Integration with Fork Resolution**: -- Used by Validator Plugin for vote-weighted fork comparisons -- Supports HF12+ consensus rules with longer-chain bonus -- Provides fallback for pre-HF12 longest-chain scenarios -- Enables intelligent fork switching decisions - -**Section sources** -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) - -### New: is_witness_scheduled_soon() Method -The `is_witness_scheduled_soon()` method provides a crucial coordination mechanism for other plugins to avoid conflicts during critical operations. - -**Method Signature**: `bool is_witness_scheduled_soon() const` - -**Purpose**: Checks if any locally-controlled validators are scheduled to produce blocks in the upcoming 4 slots, enabling other plugins to coordinate and avoid conflicts during critical operations like snapshot creation. - -**Implementation Details**: -- Validates that the Validator Plugin has been initialized with validators and private keys -- Calculates the current slot based on synchronized time plus 250ms buffer for deterministic alignment -- Iterates through slots 0-3 positions ahead to check for scheduled validators -- Verifies that the scheduled validator belongs to the locally-controlled set -- Confirms the validator has a valid signing key (not disabled) -- Ensures the plugin has the corresponding private key for block signing - -**Usage Pattern**: Other plugins can use this method to defer operations when validator production is imminent, particularly useful for snapshot creation which requires exclusive access to the blockchain state. - -**Section sources** -- [validator.cpp:206-249](file://plugins/validator/validator.cpp#L206-L249) - -### Enhanced: validator Reward Creation Process -The validator reward creation process has been significantly enhanced with comprehensive error handling and validation to prevent crashes when validator account objects are missing from the database. - -**Enhanced Reward Creation Logic**: -- **Pre-validation**: Uses `find_account()` to check if the validator account exists before attempting reward creation -- **Crash Prevention**: Implements comprehensive validation to prevent crashes from shared memory corruption -- **Clear Recovery Guidance**: Provides explicit instructions for recovery procedures when accounts are missing -- **Multi-hardfork Support**: Applies validation across all hardfork versions (HF4, HF11, and legacy models) - -**Implementation Details**: -- **HF11 Model**: Validates validator account before creating vesting rewards for new emission model -- **HF4 Model**: Comprehensive validation for consensus inflation model with detailed error logging -- **Legacy Model**: Falls back to `get_account()` with clear error messaging for older models -- **Critical Error Handling**: Logs detailed validator information (signing key, missed blocks, penalties) for debugging - -**Error Handling Features**: -- Detailed logging with validator metadata (signing key, missed blocks, penalties, last confirmed block) -- Clear FC_ASSERT messages directing users to restart with replay -- Account index size reporting for diagnostic purposes -- Prevention of crashes during validator reward distribution - -```mermaid -flowchart TD -ProcessFunds["process_funds()"] --> HardforkCheck{"Hardfork Version?"} -HardforkCheck --> |HF11| HF11Path["New Emission Model"] -HF11Check --> |HF4| HF4Path["Consensus Inflation Model"] -HF11Check --> |Legacy| LegacyPath["Legacy Model"] -HF11Path --> HF11Witness["get_witness(current_witness)"] -HF11Witness --> HF11FindAccount["find_account(owner)"] -HF11FindAccount --> |Exists| HF11CreateVesting["create_vesting(account, reward)"] -HF11FindAccount --> |Missing| HF11CriticalError["elog critical error
FC_ASSERT restart required"] -HF4Path --> HF4Witness["get_witness(current_witness)"] -HF4Witness --> HF4FindAccount["find_account(owner)"] -HF4FindAccount --> |Exists| HF4CreateVesting["create_vesting(account, reward)"] -HF4FindAccount --> |Missing| HF4CriticalError["elog critical error
FC_ASSERT restart required"] -LegacyPath --> LegacyWitness["get_witness(current_witness)"] -LegacyWitness --> LegacyGetAccount["get_account(owner)"] -LegacyGetAccount --> LegacyCreateVesting["create_vesting(account, reward)"] -``` - -**Diagram sources** -- [database.cpp:2807-2839](file://libraries/chain/database.cpp#L2807-L2839) -- [database.cpp:2871-2886](file://libraries/chain/database.cpp#L2871-L2886) -- [database.cpp:2897-2914](file://libraries/chain/database.cpp#L2897-L2914) - -**Section sources** -- [database.cpp:2807-2839](file://libraries/chain/database.cpp#L2807-L2839) -- [database.cpp:2871-2886](file://libraries/chain/database.cpp#L2871-L2886) -- [database.cpp:2897-2914](file://libraries/chain/database.cpp#L2897-L2914) -- [database.cpp:1294-1311](file://libraries/chain/database.cpp#L1294-L1311) - -### New: Comprehensive Debug Logging System -The Validator Plugin now implements a comprehensive debug logging system that provides verbose traces for block production and chain internals with detailed visibility into the entire block production pipeline. - -**Debug Logging Features**: -- **Block Production Loop**: Comprehensive logging of block_production_loop() entry and exit points -- **Maybe Produce Block**: Detailed tracing of maybe_produce_block() execution flow -- **Condition Tracking**: Timestamped logging of block production condition results -- **Emergency Mode**: Enhanced logging for emergency consensus mode enforcement -- **Minority Fork Detection**: Granular visibility into minority fork detection process -- **Fork Collision Resolution**: Detailed traces of fork collision detection and resolution -- **Contextual Information**: Rich contextual data including timestamps, block numbers, and validator information - -**Logging Implementation**: -- Uses `database()._debug_block_production` flag to control debug logging -- Implements comprehensive `ilog()` statements throughout the block production pipeline -- Provides detailed traces for validator participation checks, emergency mode enforcement, block post-validation processes, and minority fork detection -- Includes timestamps and contextual information for better debugging and troubleshooting -- Supports granular visibility into all aspects of block production with minimal performance impact - -**Section sources** -- [validator.cpp:228-233](file://plugins/validator/validator.cpp#L228-L233) -- [validator.cpp:338-407](file://plugins/validator/validator.cpp#L338-L407) -- [validator.cpp:411-419](file://plugins/validator/validator.cpp#L411-L419) -- [database.hpp:60](file://libraries/chain/include/graphene/chain/database.hpp#L60) -- [database.cpp:1890-1892](file://libraries/chain/database.cpp#L1890-L1892) -- [database.cpp:4536-4573](file://libraries/chain/database.cpp#L4536-L4573) -- [database.cpp:5530-5655](file://libraries/chain/database.cpp#L5530-L5655) - -### New: Dedicated Production Timer Thread -The production timer runs on its own `production_io_service_` with a dedicated OS thread, fully isolated from the appbase/P2P shared io_service. This prevents P2P network activity — peer disconnects, TLS handshakes, send-queue drains — from delaying the `async_wait` callback and causing missed-slot lag. - -**Implementation**: -- `production_io_service_` is a private `boost::asio::io_service` declared in `impl`, initialized before `production_timer_`. -- `production_io_work_` keeps the io_service alive while the thread runs. -- `production_io_thread_` (`std::thread`) calls `production_io_service_.run()`. -- Destructor: `production_io_service_.stop()` then `join()` for clean shutdown. -- All timer operations (`expires_from_now`, `async_wait`) use this dedicated service. - -**Benefit**: The 250ms tick fires on its own OS thread with no contention from P2P fiber scheduling. Even under heavy peer churn the production callback is called at the correct wall-clock time. - -**Section sources** -- [validator.cpp:64-83](file://plugins/validator/validator.cpp#L64-L83) -- [validator.cpp:139-144](file://plugins/validator/validator.cpp#L139-L144) -- [validator.cpp:374-378](file://plugins/validator/validator.cpp#L374-L378) -- [validator.cpp:663-685](file://plugins/validator/validator.cpp#L663-L685) - -### New: Lag Tight Loop Prevention -After a `lag` production condition the current slot is already missed. Without a guard the next 250ms tick re-evaluates the same slot and returns `lag` again, spinning in a tight loop until the full 3s slot interval passes. - -**Fix**: `_last_lag_slot_time` records the `scheduled_time` of the missed slot. At the top of `schedule_production_loop()` the elapsed time since the lag is computed; if less than one full slot interval (3 s = `CHAIN_BLOCK_INTERVAL * 1000 ms`) has passed, the timer is set to skip the remainder of that slot before resuming normal 250ms scheduling. - -**State variable**: `fc::time_point_sec _last_lag_slot_time` (zero when no lag is active). - -**Section sources** -- [validator.cpp:182-186](file://plugins/validator/validator.cpp#L182-L186) -- [validator.cpp:911-920](file://plugins/validator/validator.cpp#L911-L920) -- [validator.cpp:945-963](file://plugins/validator/validator.cpp#L945-L963) - -### New: Production Watchdog -The watchdog fires when the node has produced at least one block (`_ever_produced = true`) but has gone silent while production conditions are met. This catches cases where an external factor (e.g., the emergency master blanking our key) silently stops production without returning an explicit error. - -**Thresholds**: -- Emergency master (has `CHAIN_EMERGENCY_WITNESS_ACCOUNT` in `_witnesses`): **60 seconds**. -- Regular validator: **180 seconds**. -- Re-fires every **30 seconds** after the first alert. - -**Actions on first fire**: -1. Sets `_watchdog_debug_enabled = true` and enables `database()._debug_block_production` to capture verbose production loop traces automatically. -2. Logs full diagnostic state: NTP drift, head block, DLT sync status, P2P catchup flag, scheduled validator, how many of our validators appear in the shuffled schedule, and which validators have blanked on-chain keys. - -**Relevant state**: -- `bool _ever_produced` — set to true on first successful production. -- `fc::time_point _last_production_time` — updated on every produced block. -- `int _last_slot_result` — last non-`not_time_yet` result (meaningful failure code for diagnostics). -- `bool _watchdog_debug_enabled` — latching flag; never reset once set. - -**Section sources** -- [validator.cpp:174-191](file://plugins/validator/validator.cpp#L174-L191) -- [validator.cpp:965-1065](file://plugins/validator/validator.cpp#L965-L1065) - -### New: Slot Hijack Detection -In DLT emergency consensus mode the emergency master may blank a regular validator's signing key and produce `committee` blocks in that validator's scheduled slots. The hijack counter makes this pattern visible in watchdog diagnostics. - -**Detection logic** (runs inside `on_block_applied`): -1. Skip if emergency consensus is not active. -2. Compute `slot_idx = dgp.current_aslot % num_scheduled_witnesses`. -3. Look up the expected validator at `slot_idx` in the shuffled schedule. -4. If the actual block producer (`block.validator`) is `committee` (or any non-local validator) AND `slot_idx` maps to one of our validators → hijack detected. -5. If the actual producer IS one of our validators (any of them) → reset counter (false-positive guard). - -**State variables**: -- `uint32_t _slot_hijack_count` — consecutive hijacked slots since last own production. -- `uint32_t _slot_hijack_height` — block number of last detected hijack. - -**Logging**: First 3 hijacks are always logged; thereafter once per minute to avoid log spam. - -**Section sources** -- [validator.cpp:192-207](file://plugins/validator/validator.cpp#L192-L207) -- [validator.cpp:486-562](file://plugins/validator/validator.cpp#L486-L562) - -### New: Missed Block Diagnostic via on_block_applied Signal -The Validator Plugin subscribes to the chain's `applied_block` signal via `on_block_applied()`. When an incoming block reveals that one or more slots were skipped (block number jumped by more than 1 since the last applied block), and any of the missed slots were assigned to one of our validators, the handler dumps the full plugin state for diagnosis. - -**Triggered by**: gaps between `_last_applied_block_num` and the new block number. - -**State variable**: `uint64_t _last_applied_block_num` — updated on every applied block. - -**Section sources** -- [validator.cpp:200-207](file://plugins/validator/validator.cpp#L200-L207) -- [validator.cpp:470-562](file://plugins/validator/validator.cpp#L470-L562) - -### New: not_my_turn Streak Detection -When the production loop repeatedly returns `not_my_turn` (another validator is scheduled) for an extended period while our validators are supposed to be in the schedule, it may indicate schedule misalignment, a forked-off chain, or a configuration error. - -**Threshold**: **500 consecutive** `not_my_turn` results ≈ 125 seconds of other validators producing uninterrupted. - -**On threshold**: Logs a warning with streak count, elapsed time, last scheduled validator name, and our configured validator set. - -**Reset**: On any `produced`, `not_synced`, or other non-`not_my_turn` result. - -**State variables**: -- `uint32_t _not_my_turn_streak` -- `fc::time_point _not_my_turn_streak_start` -- `std::string _last_scheduled_witness` - -**Section sources** -- [validator.cpp:170-173](file://plugins/validator/validator.cpp#L170-L173) -- [validator.cpp:754-780](file://plugins/validator/validator.cpp#L754-L780) - -### New: validator Guard Plugin - Comprehensive Protection and Monitoring -The validator guard plugin provides comprehensive protection and monitoring capabilities for validator keys and operations. - -**Core Responsibilities**: -- **Auto-Key Restoration**: Automatically detects and restores null signing keys on-chain -- **Consecutive Block Protection**: Monitors validator block production and auto-disables validators after N consecutive blocks -- **Emergency Consensus Support**: Continues monitoring and protection during emergency consensus mode -- **Network Health Monitoring**: Ensures node synchronization and network health before performing actions -- **Safety Checks**: Implements comprehensive safety checks to prevent malicious actions - -**Auto-Restore Mechanism**: -- Periodically checks configured validators for null signing keys -- Broadcasts witness_update transactions to restore keys using stored key pairs -- Tracks pending transactions and confirms successful restoration -- Implements retry logic for failed restoration attempts -- Prevents unbounded growth of pending confirmation tracking - -**Auto-Disable Protection**: -- Monitors consecutive block production by configured validators -- Auto-disables validators that exceed the configured threshold -- Prevents validator abuse and ensures fair network participation -- Maintains records of auto-disabled validators to prevent auto-restore -- Broadcasts witness_update transactions with null signing key to disable production - -**Emergency Consensus Integration**: -- Continues monitoring during emergency consensus mode -- Adapts behavior based on emergency_consensus_active flag -- Supports key restoration even when network is unstable -- Coordinates with Validator Plugin for seamless operation - -**Safety and Validation**: -- Verifies on-chain authority for configured active keys -- Implements network health checks before performing actions -- Detects and warns about long fork scenarios -- Prevents auto-restore during stale production override periods -- Provides comprehensive logging for all operations - -**Configuration Options**: -- **validator-guard-enabled**: Enable/disable the protection system -- **validator-guard-disable**: Set consecutive block threshold for auto-disable -- **validator-guard-interval**: Configure check frequency in blocks -- **validator-guard-validator**: Define validators to monitor with key pairs - -**Section sources** -- [witness_guard.hpp:11-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L11-L48) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) -- [witness_guard.cpp:197-246](file://plugins/witness_guard/witness_guard.cpp#L197-L246) -- [witness_guard.cpp:252-294](file://plugins/witness_guard/witness_guard.cpp#L252-L294) -- [witness_guard.cpp:301-408](file://plugins/witness_guard/witness_guard.cpp#L301-L408) -- [witness_guard.cpp:410-555](file://plugins/witness_guard/witness_guard.cpp#L410-L555) - -### validator API Plugin -Responsibilities: -- Expose JSON-RPC endpoints for: - - Active validators in the current schedule. - - Full validator schedule object. - - validators by ID, by account, by votes, by counted votes. - - Count of validators. - - Lookup of validator accounts by name range. - -Implementation highlights: -- Uses weak read locks around database queries. -- Enforces limits on returned sets (e.g., max 100 for vote-based lists). -- Converts chain validator objects to API-friendly structures. - -```mermaid -sequenceDiagram -participant Client as "Client" -participant RPC as "JSON-RPC" -participant WAPI as "validator API Plugin" -participant DB as "Chain Database" -Client->>RPC : get_active_witnesses() -RPC->>WAPI : dispatch -WAPI->>DB : get_witness_schedule_object() -DB-->>WAPI : witness_schedule_object -WAPI-->>RPC : active validator names[] -RPC-->>Client : response -Client->>RPC : get_witness_by_account(account) -RPC->>WAPI : dispatch -WAPI->>DB : find validator by name -DB-->>WAPI : witness_object -WAPI-->>RPC : witness_api_object or null -RPC-->>Client : response -``` - -**Diagram sources** -- [witness_api_plugin.cpp:30-49](file://plugins/witness_api/plugin.cpp#L30-L49) -- [witness_api_plugin.cpp:75-91](file://plugins/witness_api/plugin.cpp#L75-L91) -- [witness_api_plugin.cpp:102-125](file://plugins/witness_api/plugin.cpp#L102-L125) -- [witness_api_plugin.cpp:127-159](file://plugins/witness_api/plugin.cpp#L127-L159) -- [witness_api_plugin.cpp:161-169](file://plugins/witness_api/plugin.cpp#L161-L169) -- [witness_api_plugin.cpp:171-203](file://plugins/witness_api/plugin.cpp#L171-L203) - -**Section sources** -- [witness_api_plugin.hpp:56-98](file://plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp#L56-L98) -- [witness_api_plugin.cpp:13-28](file://plugins/witness_api/plugin.cpp#L13-L28) -- [witness_api_plugin.cpp:30-49](file://plugins/witness_api/plugin.cpp#L30-L49) -- [witness_api_plugin.cpp:75-91](file://plugins/witness_api/plugin.cpp#L75-L91) -- [witness_api_plugin.cpp:102-159](file://plugins/witness_api/plugin.cpp#L102-L159) -- [witness_api_plugin.cpp:161-203](file://plugins/witness_api/plugin.cpp#L161-L203) - -### Chain Database: Enhanced Fork Database Integration -The database maintains: -- validator objects with voting, signing keys, virtual scheduling fields, and participation counters. -- validator schedule object with shuffled validators, current virtual time, and majority version. -- Block post validation objects used to coordinate cross-validator validation. -- **Enhanced**: Direct fork database access through `get_fork_db()` method for comprehensive fork collision detection. -- **Enhanced**: Comprehensive validator reward creation with find_account() validation to prevent crashes from missing account objects. -- **Enhanced**: **NEW**: Integration with skip_undo_history_check flag for controlled production during recovery scenarios. -- **Enhanced**: **NEW**: Comprehensive debug logging system enabling verbose traces for chain internals and block processing. -- **New**: Enhanced fork database with automatic stale fork pruning after successful block application. -- **New**: Sophisticated compare_fork_branches() function for intelligent fork weight comparison. -- **New**: **Enhanced**: Supports emergency_consensus_active field for emergency consensus mode detection. - -Behavior highlights: -- Computes validator participation rate and enforces minimum participation thresholds. -- Updates last irreversible block (LIB) based on validator confirmations and thresholds. -- Recomputes validator schedule and shuffles according to virtual time and votes. -- **Enhanced**: Provides comprehensive fork database querying capabilities for fork collision detection. -- **Enhanced**: Implements comprehensive validation for validator reward creation across all hardfork versions. -- **New**: Automatic stale fork pruning removes competing blocks from dead forks to maintain database efficiency. -- **New**: Intelligent fork comparison with vote-weighted calculations and longer-chain bonuses. -- **New**: **Enhanced**: Supports emergency consensus detection through emergency_consensus_active flag. - -**Enhanced Fork Database Capabilities**: -- `fetch_block_by_number()`: Retrieves all blocks at a specific height (handles multiple forks) -- `fetch_block_on_main_branch_by_number()`: Resolves ambiguity between competing blocks -- `fetch_branch_from()`: Provides branch comparison for fork resolution -- **New**: `remove_blocks_by_number()`: Removes all blocks at a specific height for stale fork pruning -- **New**: `compare_fork_branches()`: Intelligent fork weight comparison with +10% longer-chain bonus - -```mermaid -classDiagram -class witness_object { -+id -+owner -+created -+url -+votes -+penalty_percent -+counted_votes -+virtual_last_update -+virtual_position -+virtual_scheduled_time -+total_missed -+last_aslot -+last_confirmed_block_num -+last_supported_block_num -+signing_key -+props -+last_work -+running_version -+hardfork_version_vote -+hardfork_time_vote -+sharing_rate : uint16_t -+pending_stakeholder_reward : share_type -} -class witness_schedule_object { -+id -+current_virtual_time -+next_shuffle_block_num -+current_shuffled_witnesses[] -+num_scheduled_witnesses -+median_props -+majority_version -} -class block_post_validation_object { -+id -+block_num -+block_id -+current_shuffled_witnesses[] -+current_shuffled_witnesses_validations[] -} -class fork_database { -+MAX_BLOCK_REORDERING : 1024 -+push_block() -+fetch_block_by_number() -+fetch_block_on_main_branch_by_number() -+fetch_branch_from() -+remove_blocks_by_number() -+compare_fork_branches() -} -class dynamic_global_property_object { -+emergency_consensus_active : bool -+emergency_consensus_start_block : uint32_t -} -witness_object --> witness_schedule_object : "referenced by schedule" -block_post_validation_object --> witness_schedule_object : "mentions scheduled validators" -fork_database --> witness_schedule_object : "tracks competing blocks" -dynamic_global_property_object --> fork_database : "emergency consensus state" -``` - -**Diagram sources** -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [witness_objects.hpp:104-171](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L104-L171) -- [chain_objects.hpp:174-201](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L174-L201) -- [fork_database.hpp:53-81](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L81) -- [fork_database.hpp:90-95](file://libraries/chain/include/graphene/chain/fork_database.hpp#L90-L95) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [global_property_object.hpp:139](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L139) - -**Section sources** -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [witness_objects.hpp:104-171](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L104-L171) -- [chain_objects.hpp:174-201](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L174-L201) -- [database.cpp:1626-1805](file://libraries/chain/database.cpp#L1626-L1805) -- [database.cpp:4317-4332](file://libraries/chain/database.cpp#L4317-L4332) -- [database.cpp:4334-4463](file://libraries/chain/database.cpp#L4334-L4463) -- [database.hpp:492-499](file://libraries/chain/include/graphene/chain/database.hpp#L492-L499) -- [fork_database.hpp:73](file://libraries/chain/include/graphene/chain/fork_database.hpp#L73) -- [fork_database.cpp:151-166](file://libraries/chain/fork_database.cpp#L151-166) -- [fork_database.cpp:269-274](file://libraries/chain/fork_database.cpp#L269-L274) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [global_property_object.hpp:139](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L139) - -### Enhanced Time Synchronization Service -**New Section** The validator system now includes robust time synchronization capabilities managed through the time service layer with enhanced logging for fork collision detection and comprehensive error handling for validator reward creation. - -Responsibilities: -- Provide precise wall-clock time synchronization using NTP with 250ms interval optimization. -- Handle crash-safe shutdown procedures for NTP services. -- Monitor and report significant time synchronization changes. -- Enable forced synchronization on timing issues and fork collisions. -- **Enhanced**: Comprehensive delta change monitoring with 100ms threshold detection. -- **Enhanced**: Comprehensive error handling for validator reward creation with find_account() validation. - -Key behaviors: -- Thread-safe NTP service initialization and management with 250ms tick scheduling. -- Automatic fallback mechanisms for NTP server failures. -- Significant delta change detection (100ms threshold) for monitoring. -- Graceful shutdown with proper resource cleanup. -- **Enhanced**: Automatic NTP synchronization triggered by fork collision detection. -- **Enhanced**: Comprehensive validation and error handling for validator reward distribution. - -**Section sources** -- [time.cpp:13-53](file://libraries/time/time.cpp#L13-L53) -- [time.cpp:36-39](file://libraries/time/time.cpp#L36-L39) -- [time.cpp:74-76](file://libraries/time/time.cpp#L74-L76) -- [ntp.cpp:184-201](file://thirdparty/fc/src/network/ntp.cpp#L184-L201) -- [ntp.cpp:236-266](file://thirdparty/fc/src/network/ntp.cpp#L236-L266) - -## HF13: Validator Reward Sharing - -Introduced in Hardfork 13. Validators can redirect a fraction of their block reward to the -accounts that voted for them. Rewards accumulate in **TOKEN (VIZ)** inside the `witness_object` -and are converted to SHARES only at epoch end via `create_vesting()`. - -### New chain parameter: `distribution_epoch_length` - -Added to `chain_properties_hf13` (which becomes the `chain_properties` alias used throughout the -chain library). Validators vote on this parameter via `versioned_chain_properties_update_operation`. - -| Field | Default | Range | Description | -|---|---|---|---| -| `distribution_epoch_length` | 28800 (1 day) | [21, ~10.5M] | Blocks between consecutive distribution epochs | - -The median across all scheduled validators becomes the consensus value. - -### New operation: `set_reward_sharing_operation` - -Active authority of `owner` required. Rejected before HF13. - -| Field | Type | Description | -|---|---|---| -| `owner` | `account_name_type` | Validator account name | -| `sharing_rate` | `uint16_t` | Basis points; 0 = 0%, 10000 = 100% | - -### Block reward split (`process_funds`) - -When `sharing_rate > 0` and HF13 is active: - -``` -stakeholder_token = witness_reward * sharing_rate / CHAIN_100_PERCENT -validator_token = witness_reward - stakeholder_token - -create_vesting(validator_account, validator_token) -→ witness_reward_operation(validator, validator_shares) # only validator's share - -witness_object.pending_stakeholder_reward += stakeholder_token # TOKEN, accumulated -``` - -If `sharing_rate == 0`, the full reward goes to the validator as before. - -### Mid-epoch sharing rate change - -The new rate takes effect **immediately** on the next block. The accumulated -`pending_stakeholder_reward` is not recalculated retroactively. Stakeholders receive a proportional -mix of the old and new rates at epoch end. - -### Epoch distribution (`process_validator_epoch_distribution`) - -Called at the end of `_apply_block` when `head_block_num % distribution_epoch_length == 0`. - -Uses **time-weighted** stakeholder shares. Each `witness_vote_object` records `vote_created_block` — -the block at which the vote was cast. At epoch end: - -``` -epoch_start_block = head_block_num - epoch_length + 1 - -for each stakeholder: - first_block = max(vote_created_block, epoch_start_block) - blocks_in_epoch = head_block_num - first_block + 1 - weighted = stakeholder.witness_vote_weight() * blocks_in_epoch - -stakeholder_token = total_token * weighted[stakeholder] / Σ weighted -if stakeholder_token < CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT (1 atomic = 0.001 VIZ): - skip (dust) -else: - create_vesting(stakeholder_account, stakeholder_token) - → stakeholder_reward_operation(validator, stakeholder, stakeholder_shares) - -dust → create_vesting(validator_account, dust) + witness_reward_operation -witness_object.pending_stakeholder_reward = 0 -``` - -A stakeholder who joined mid-epoch receives a proportionally smaller reward. Pre-HF13 votes -(`vote_created_block == 0`) receive full-epoch weight. - -**Dust handling**: sharing rewards is entirely the validator's voluntary decision. A stakeholder -whose computed share falls below `CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT` has not earned a viable -payout — the responsibility is theirs. Unclaimed dust (rounding remainder + skipped sub-threshold -shares) is therefore **not burned** but returned to the validator via `witness_reward_operation`. - -#### Flash-voter protection - -Time-weighting prevents the flash-vote attack (vote just before epoch end, capture full pool). -A stakeholder who votes in the last block of a 1-day epoch (28800 blocks) receives only `1/28800` -of their stake-proportional share — economically insignificant. - -### New virtual operation: `stakeholder_reward_operation` - -| Field | Type | Description | -|---|---|---| -| `validator` | `account_name_type` | Validator that produced the accumulated rewards | -| `stakeholder` | `account_name_type` | Stakeholder account receiving the reward | -| `shares` | `asset` | SHARES credited to the stakeholder | - -**Section sources** -- [config.hpp](file://libraries/protocol/include/graphene/protocol/config.hpp) — `CHAIN_MIN_STAKEHOLDER_REWARD_PAYOUT`, `CHAIN_DEFAULT_DISTRIBUTION_EPOCH_LENGTH` -- [chain_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_operations.hpp) — `chain_properties_hf13`, `set_reward_sharing_operation` -- [chain_virtual_operations.hpp](file://libraries/protocol/include/graphene/protocol/chain_virtual_operations.hpp) — `stakeholder_reward_operation` -- [witness_objects.hpp](file://libraries/chain/include/graphene/chain/witness_objects.hpp) — `sharing_rate`, `pending_stakeholder_reward` fields -- [database.cpp](file://libraries/chain/database.cpp) — `process_funds` split, `process_validator_epoch_distribution` - ---- - -## Dependency Analysis -- The Validator Plugin depends on: - - Chain plugin for database access and block generation. - - P2P plugin for broadcasting blocks and block post validations. - - **Enhanced**: NTP time service for precise 250ms slot alignment and timing validation. - - **Enhanced**: Fork database for comprehensive fork collision detection and stale pruning. - - **Enhanced**: **NEW**: P2P resync_from_lib() method for automatic recovery from minority forks. - - **Enhanced**: **NEW**: Comprehensive debug logging system for verbose traces of block production and chain internals. - - **New**: External plugins can depend on the `is_witness_scheduled_soon()` method for coordination. - - **New**: Enhanced fork database with compare_fork_branches() function for intelligent fork switching. -- The validator guard plugin depends on: - - Chain plugin for database access and validator monitoring. - - P2P plugin for broadcasting witness_update transactions. - - **New**: Emergency consensus detection through dynamic_global_property_object. - - **New**: Configurable check intervals and auto-disable thresholds. - - **New**: Key pair management for validator protection. -- The validator API plugin depends on: - - Chain plugin for read-only queries. - - JSON-RPC plugin for transport. -- The chain database depends on: - - validator objects and schedule indices. - - Block post validation objects for cross-validator coordination. - - **Enhanced**: Fork database for tracking competing blocks and fork resolution. - - **Enhanced**: Comprehensive validation for validator reward creation with find_account() checks. - - **Enhanced**: **NEW**: skip_undo_history_check flag for controlled production during recovery scenarios. - - **Enhanced**: **NEW**: Comprehensive debug logging system enabling verbose traces for chain internals. - - **New**: Automatic stale fork pruning mechanism for database efficiency. - - **New**: Enhanced fork comparison functions for intelligent chain selection. - - **New**: **Enhanced**: emergency_consensus_active field for emergency consensus detection. - -```mermaid -graph LR -validator["Validator Plugin"] --> CHAIN["Chain Plugin"] -validator --> P2P["P2P Plugin
resync_from_lib()"] -validator --> TIME["Time Service"] -validator --> FORK_DB["Fork Database
enhanced with stale pruning"] -validator --> DEBUG_LOG["Debug Logging
verbose traces"] -WGUARD["validator Guard Plugin"] --> CHAIN -WGUARD --> P2P -WGUARD --> EMERGENCY["Emergency Consensus
emergency_consensus_active"] -WAPI["validator API Plugin"] --> CHAIN -SNAPSHOT["Snapshot Plugin"] --> validator -CHAIN --> DB["database.hpp/.cpp
compare_fork_branches()"] -DB --> WITNESS_OBJ["witness_objects.hpp"] -DB --> BPV_OBJ["chain_objects.hpp"] -DB --> FORK_DB["fork_database.hpp/.cpp"] -DB --> FIND_ACCOUNT["find_account() validation"] -DB --> COMPARE_FORK["compare_fork_branches()"] -DB --> SKIP_UNDO["skip_undo_history_check flag"] -DB --> EMERGENCY["emergency_consensus_active"] -TIME --> NTP["NTP Service"] -``` - -**Diagram sources** -- [validator.hpp:34-68](file://plugins/validator/include/graphene/plugins/validator/validator.hpp#L34-L68) -- [validator.cpp:59-118](file://plugins/validator/validator.cpp#L59-L118) -- [witness_guard.hpp:11-48](file://plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#L11-L48) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) -- [witness_api_plugin.hpp:56-98](file://plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp#L56-L98) -- [database.hpp:37-83](file://libraries/chain/include/graphene/chain/database.hpp#L37-L83) -- [witness_objects.hpp:27-132](file://libraries/chain/include/graphene/chain/witness_objects.hpp#L27-L132) -- [chain_objects.hpp:174-201](file://libraries/chain/include/graphene/chain/chain_objects.hpp#L174-L201) -- [fork_database.hpp:53-81](file://libraries/chain/include/graphene/chain/fork_database.hpp#L53-L81) -- [time.cpp:13-53](file://libraries/time/time.cpp#L13-L53) -- [snapshot_plugin.cpp:1267-1276](file://plugins/snapshot/plugin.cpp#L1267-1276) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [global_property_object.hpp:139](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L139) -- [p2p_plugin.hpp:50-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L50-L55) - -**Section sources** -- [validator.cpp:59-118](file://plugins/validator/validator.cpp#L59-L118) -- [witness_guard.cpp:27-78](file://plugins/witness_guard/witness_guard.cpp#L27-L78) -- [witness_api_plugin.cpp:13-28](file://plugins/witness_api/plugin.cpp#L13-L28) -- [database.hpp:37-83](file://libraries/chain/include/graphene/chain/database.hpp#L37-L83) - -## Performance Considerations -- Production loop alignment: The loop waits until the next 250ms boundary and sleeps for at least 50ms to avoid excessive polling, reducing CPU overhead and providing deterministic slot time alignment. -- Retry on block generation failures: On exceptions during block generation, pending transactions are cleared and the generation is retried once to mitigate transient issues. -- Participation threshold: Ensures sufficient validator participation before producing blocks, preventing premature production on minority forks. -- Virtual scheduling: Uses virtual time and votes to fairly distribute block production slots among validators, avoiding hot-spotting and ensuring proportional representation. -- **Enhanced**: Forced NTP synchronization reduces timing-related production failures and improves system reliability during clock drift scenarios. -- **Enhanced**: Comprehensive fork collision detection adds minimal overhead while preventing costly fork resolution failures. -- **Enhanced**: **NEW**: Minority fork detection adds minimal overhead while preventing network fragmentation and minority fork propagation. -- **Enhanced**: **NEW**: Automatic recovery through P2P resynchronization is efficient and prevents prolonged network instability. -- **Enhanced**: **NEW**: Comprehensive debug logging system provides detailed visibility with minimal performance impact through selective logging. -- **New**: Efficient slot checking in `is_witness_scheduled_soon()` method performs minimal database operations across 4 slots to detect scheduling conflicts quickly. -- **Updated**: Improved configuration parameter processing with type safety and proper scaling for better performance and reliability. -- **Enhanced**: Fork database querying uses efficient multi-index containers for fast block lookup and competition detection. -- **Enhanced**: find_account() validation adds minimal overhead while providing comprehensive protection against database corruption scenarios. -- **Enhanced**: Comprehensive error handling in validator reward creation prevents crashes and ensures graceful degradation during critical failures. -- **New**: 250ms interval optimization provides precise timing alignment for deterministic consensus maintenance. -- **New**: Deterministic slot time calculation ensures consistent block production timing across all validator nodes. -- **New**: Two-level fork collision resolution system provides intelligent fork switching decisions with configurable timeout behavior. -- **New**: Automatic stale fork pruning prevents database bloat and maintains fork database efficiency. -- **New**: Enhanced compare_fork_branches() function provides intelligent fork weight comparison with +10% longer-chain bonus. -- **New**: Configurable fork collision timeout blocks parameter allows fine-tuning of fork resolution behavior for different network conditions. -- **New**: skip_undo_history_check flag provides controlled production during recovery scenarios without disrupting normal operations. -- **Enhanced**: **NEW**: debug-block-production configuration option enables verbose logging for block production and chain internals with detailed traces and granular visibility. -- **Enhanced**: **NEW**: validator guard plugin provides comprehensive protection with minimal performance impact through efficient monitoring and safety checks. -- **Enhanced**: **NEW**: Auto-disable threshold prevents validator abuse while maintaining network stability and fair participation. -- **Enhanced**: **NEW**: Emergency consensus integration ensures continuous protection and recovery during network distress scenarios. -- **Enhanced**: **NEW**: Network health monitoring prevents unsafe operations during stale production override periods. -- **Enhanced**: **NEW**: Pending transaction tracking prevents unbounded memory growth while maintaining reliable restoration mechanisms. - -**Updated** Added performance considerations for the corrected configuration parameter types, fork collision detection system, enhanced fork database querying capabilities, comprehensive validator reward creation validation, 250ms interval optimization, deterministic slot time alignment, new fork collision timeout configuration, two-level fork resolution system with intelligent decision-making, automatic stale fork pruning, enhanced fork comparison functions, configurable timeout parameters for optimal network performance, **NEW**: minority fork detection system with minimal overhead, **NEW**: automatic recovery mechanisms through P2P resynchronization, **NEW**: skip_undo_history_check flag for controlled production during recovery scenarios, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals with detailed visibility, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms with automatic key restoration, **NEW**: consecutive block protection to prevent validator abuse, **NEW**: enhanced network connectivity with improved peer synchronization, **NEW**: validator guard plugin with efficient monitoring and safety checks, **NEW**: auto-disable threshold for preventing validator abuse, **NEW**: emergency consensus integration for continuous protection, **NEW**: network health monitoring for safe operations, **NEW**: pending transaction tracking for reliable restoration. - -## Troubleshooting Guide -Common issues and resolutions: -- No validators configured - - Symptom: Startup logs indicate no validators configured. - - Resolution: Add validator names and private keys to configuration. -- Low participation - - Symptom: Blocks not produced due to insufficient validator participation. - - Resolution: Ensure enough validators are online and participating per configured threshold. -- Missing private key - - Symptom: Logs indicate inability to sign block due to missing private key. - - Resolution: Verify private key is provided in the correct WIF format and matches the validator signing key. -- Timing lag - - Symptom: Blocks not produced due to waking up outside the 500ms window. - - Resolution: Improve system clock accuracy and reduce latency; consider enabling stale production only as a temporary workaround. - - **Enhanced**: System automatically forces NTP synchronization when timing issues are detected. -- Consecutive block production disabled - - Symptom: Blocks not produced because the last block was generated by the same validator. - - Resolution: Investigate connectivity issues; disable consecutive production only as a temporary workaround. -- **New**: Fork collision detection issues - - Symptom: Blocks not produced despite good participation and timing, frequent "deferred block production due to fork collision" messages. - - Resolution: Check network connectivity and validator coordination; verify fork database integrity; monitor NTP synchronization quality. - - **New**: Check fork-collision-timeout-blocks configuration (default: 21 blocks) for appropriate timeout settings. - - **New**: Monitor fork collision deferral count and timeout behavior for proper fork resolution. -- **New**: Two-level fork collision resolution problems - - Symptom: Fork collision handling not working as expected with vote-weighted comparisons. - - Resolution: Verify HF12+ compatibility for vote-weighted comparisons; check compare_fork_branches() function behavior; ensure fork database has both forks for comparison. -- **New**: Stale fork pruning issues - - Symptom: Memory usage growing or fork database becoming bloated with competing blocks. - - Resolution: Verify automatic stale fork pruning is working; check fork database remove_blocks_by_number() function; ensure proper parent-child relationships in fork database. -- **New**: validator scheduling conflicts - - Symptom: Other plugins experience conflicts with validator operations. - - Resolution: Use `is_witness_scheduled_soon()` method to coordinate operations and defer critical tasks until validator production is complete. -- **New**: NTP synchronization issues - - Symptom: Frequent timing-related warnings or blocks not produced despite good participation. - - Resolution: Check NTP server connectivity and system clock accuracy; verify NTP service is running properly; monitor delta change logs. -- **New**: Crash race conditions - - Symptom: Validator Plugin fails to shut down cleanly or leaves NTP service in inconsistent state. - - Resolution: Ensure proper shutdown sequence; the system now handles crash-safe NTP service cleanup. -- **New**: Configuration parameter type errors - - Symptom: Errors indicating incorrect parameter types or values. - - Resolution: Verify configuration parameters use correct types: - - `enable-stale-production`: boolean value (`true`/`false`) - - `required-participation`: integer value scaled by `CHAIN_1_PERCENT` (e.g., 33 for 33%) - - `fork-collision-timeout-blocks`: integer value (default: 21 blocks) - - `debug-block-production`: boolean value (`true`/`false`) - **NEW** - - `validator-guard-enabled`: boolean value (`true`/`false`) - **NEW** - - `validator-guard-disable`: integer value (default: 5) - **NEW** - - `validator-guard-interval`: integer value (default: 20) - **NEW** - - `validator-guard-validator`: JSON triplet format - **NEW** - - Check configuration files for proper syntax and values -- **Enhanced**: Fork collision detection logging - - Symptom: Frequent fork collision warnings with "Collision parents at block" messages. - - Resolution: Monitor fork database for competing blocks; check validator coordination; verify network stability; ensure proper NTP synchronization. - - **New**: Check fork collision deferral count and timeout behavior for proper resolution. -- **New**: Enhanced fork comparison failures - - Symptom: compare_fork_branches() function returning 0 (cannot compare) frequently. - - Resolution: Verify both fork tips are in fork database; check validator objects availability; ensure proper fork database state. -- **New**: Automatic stale pruning not working - - Symptom: Fork database grows with stale competing blocks. - - Resolution: Verify _push_block() method is calling stale pruning; check fork database state; ensure proper parent-child relationships. -- **New**: Database corruption detection - - Symptom: Multiple critical error messages during validator reward processing with account validation failures. - - Resolution: - - Immediate restart with replay to rebuild database from genesis - - Check disk space and file system integrity - - Verify database backup and recovery procedures - - Monitor for hardware issues affecting shared memory - - Review system logs for memory corruption indicators -- **New**: 250ms interval timing issues - - Symptom: Blocks not produced at expected 250ms boundaries or inconsistent timing. - - Resolution: Verify system clock precision; check for high system load causing timing delays; ensure NTP service is functioning properly; review system resources for adequate performance. -- **New**: Configurable timeout parameter issues - - Symptom: Fork collision timeout not triggering as expected or triggering too frequently. - - Resolution: Adjust fork-collision-timeout-blocks parameter based on network conditions; monitor fork collision deferral count; verify timeout logic is working correctly. -- **New**: Minority fork detection false positives - - Symptom: Frequent minority fork detection warnings or unexpected recovery behavior. - - Resolution: Verify emergency consensus mode is not active; check skip_undo_history_check flag state; ensure proper network connectivity; verify validator configuration is correct. -- **New**: Recovery mechanism issues - - Symptom: Automatic recovery not working or taking too long to complete. - - Resolution: Check P2P plugin connectivity; verify resync_from_lib() method is functioning; monitor network synchronization progress; ensure sufficient peer connections. -- **New**: skip_undo_history_check flag problems - - Symptom: Production not behaving as expected during recovery scenarios. - - Resolution: Verify flag state during recovery; check enable-stale-production configuration; ensure proper flag management during minority fork detection and recovery. -- **New**: Debug logging configuration issues - - Symptom: Debug logging not providing expected verbose traces or performance impact concerns. - - Resolution: Verify debug-block-production configuration is set to `true`; check log level settings; ensure proper log file configuration; monitor performance impact; adjust debug logging scope as needed. -- **New**: Comprehensive debug trace analysis - - Symptom: Difficulty interpreting debug log output or missing expected trace information. - - Resolution: Review debug log entries for timestamped traces; verify debug-block-production is enabled; check for granular visibility into validator participation checks, emergency mode enforcement, block post-validation processes, and minority fork detection; ensure proper log rotation and retention policies. -- **New**: validator guard plugin issues - - Symptom: validator key not being restored or auto-disabled unexpectedly. - - Resolution: Check validator-guard-enabled configuration; verify validator-guard-validator entries are properly formatted JSON triplets; ensure active keys have proper authority on-chain; monitor validator guard logs for specific error messages. -- **New**: Auto-disable threshold problems - - Symptom: validators being auto-disabled too frequently or not at all. - - Resolution: Adjust validator-guard-disable parameter based on network conditions; verify validator block production patterns; ensure proper key management and network connectivity. -- **New**: Emergency consensus protection issues - - Symptom: validator protection not working during emergency consensus mode. - - Resolution: Verify emergency_consensus_active flag is detected correctly; check validator guard plugin behavior during emergency mode; ensure proper key restoration procedures. -- **New**: Network health monitoring failures - - Symptom: validator guard performing operations during unhealthy network conditions. - - Resolution: Verify network health checks are working; check LIB age monitoring; ensure proper safety checks are in place; review validator guard logs for health check results. -- **New**: Production watchdog fires unexpectedly - - Symptom: `WATCHDOG:` elog appears even though production seems healthy; verbose `DEBUG_CRASH` logging auto-enabled. - - Resolution: The watchdog fires when no block has been produced for 60s (emergency master) or 180s (regular validator) while production conditions appear met. Check: is our validator in the shuffled schedule (`our_slots_in_schedule > 0`)? Is the on-chain signing key blanked (`blanked_keys` field in watchdog log)? Is P2P still syncing (`dlt_syncing`)? The watchdog log contains all these fields. -- **New**: Lag tight loop / high CPU after missed slot - - Symptom: After a `lag` condition, node CPU spikes and production loop fires many times per second on the same slot. - - Resolution: This was a bug fixed in commit 8fce5f1e. The `_last_lag_slot_time` guard now skips ahead to avoid rechecking the same missed slot. Upgrade to a build that includes this fix. -- **New**: Slot hijack counter increments for own blocks - - Symptom: `hijack #N` messages appear in watchdog diagnostics even when one of our own validators produced the block. - - Resolution: Fixed in commit 7b589b71. The hijack counter now resets when any of our validators (not just the slot-assigned one) produced the block. Upgrade to a build containing this fix. -- **New**: not_my_turn streak warning - - Symptom: `NOT_MY_TURN STREAK: N consecutive slots` warning in logs. - - Resolution: Another validator has held all slots for ~125s. Check: (1) Is our validator still in the shuffled schedule? (2) Is there a chain fork where the other side has a different schedule? (3) Has our validator been replaced/disabled on-chain? The log includes `our validators` and `last scheduled` fields for quick diagnosis. - -**Updated** Added troubleshooting information for fork collision detection, validator scheduling conflicts, the new coordination mechanisms, configuration parameter type issues, comprehensive validator reward creation validation, database corruption scenarios with clear recovery procedures, 250ms interval timing optimization issues, new fork collision timeout configuration, two-level fork resolution system, automatic stale fork pruning, enhanced fork comparison functions, configurable timeout parameters for optimal network behavior, **NEW**: comprehensive minority fork detection system with automatic recovery mechanisms, **NEW**: recovery mechanism issues through P2P resynchronization, **NEW**: skip_undo_history_check flag management during recovery scenarios, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals with detailed visibility, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms through P2P resynchronization, **NEW**: auto-disable threshold management for preventing validator abuse, **NEW**: emergency consensus integration for continuous protection, **NEW**: network health monitoring for safe operations, **NEW**: pending transaction tracking for reliable restoration, **NEW**: validator guard plugin configuration issues, **NEW**: auto-disable threshold problems, **NEW**: emergency consensus protection failures, **NEW**: network health monitoring failures. - -**Section sources** -- [validator.cpp:171-192](file://plugins/validator/validator.cpp#L171-L192) -- [validator.cpp:255-271](file://plugins/validator/validator.cpp#L255-L271) -- [validator.cpp:387-396](file://plugins/validator/validator.cpp#L387-L396) -- [validator.cpp:263-266](file://plugins/validator/validator.cpp#L263-L266) -- [validator.cpp:206-249](file://plugins/validator/validator.cpp#L206-L249) -- [validator.cpp:447-471](file://plugins/validator/validator.cpp#L447-L471) -- [validator.cpp:590-695](file://plugins/validator/validator.cpp#L590-L695) -- [time.cpp:36-39](file://libraries/time/time.cpp#L36-L39) -- [database.cpp:2826-2836](file://libraries/chain/database.cpp#L2826-L2836) -- [database.cpp:2873-2883](file://libraries/chain/database.cpp#L2873-L2883) -- [database.cpp:1456-1471](file://libraries/chain/database.cpp#L1456-L1471) -- [database.cpp:1223-1267](file://libraries/chain/database.cpp#L1223-L1267) -- [validator.cpp:509-555](file://plugins/validator/validator.cpp#L509-L555) -- [witness_guard.cpp:83-191](file://plugins/witness_guard/witness_guard.cpp#L83-L191) -- [witness_guard.cpp:455-544](file://plugins/witness_guard/witness_guard.cpp#L455-L544) -- [global_property_object.hpp:139](file://libraries/chain/include/graphene/chain/global_property_object.hpp#L139) -- [p2p_plugin.hpp:50-55](file://plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#L50-L55) - -## Conclusion -The validator subsystem integrates tightly with the chain database and P2P layer to ensure timely, secure, and fair block production. The Validator Plugin manages production loops, participation thresholds, and broadcasting, while the validator guard plugin provides comprehensive protection and monitoring capabilities. The validator API plugin exposes essential read-only data to clients. - -**Enhanced** The system now includes robust NTP time synchronization with automatic fallback mechanisms, crash-safe shutdown procedures, strengthened timing-related production failure prevention, comprehensive fork collision detection system with two-level resolution, and enhanced fork database querying capabilities. **New** The addition of the `is_witness_scheduled_soon()` method enables sophisticated plugin coordination, allowing other plugins to avoid conflicts during critical operations like snapshot creation. **Updated** The configuration parameter system has been improved with corrected defaults and proper type handling for better reliability and performance. **Enhanced** The validator reward creation process has been significantly strengthened with comprehensive error handling, find_account() validation, crash prevention mechanisms, and clear recovery procedures for database corruption scenarios. **New** The 250ms interval optimization provides precise timing alignment for deterministic consensus maintenance, while the enhanced performance characteristics ensure better system responsiveness and consensus stability. **New** The two-level fork collision resolution system with configurable timeout provides intelligent fork switching decisions, automatic stale fork pruning maintains database efficiency, enhanced fork comparison functions enable sophisticated chain selection, and configurable timeout parameters allow fine-tuning for different network conditions. **NEW** The comprehensive minority fork detection system with automatic recovery mechanisms prevents network fragmentation and ensures proper consensus maintenance, while the enhanced emergency consensus mode integration provides seamless operation during network distress scenarios. **NEW** The skip_undo_history_check flag provides controlled production during recovery scenarios, and the P2P resynchronization mechanism ensures efficient network recovery without disrupting normal operations. **NEW** The comprehensive debug logging system enables verbose traces for block production and chain internals with detailed visibility into validator participation checks, emergency mode enforcement, block post-validation processes, and minority fork detection. **NEW** The validator guard plugin provides comprehensive protection and monitoring capabilities with auto-restore functionality, consecutive block auto-disable protection, emergency consensus support, and safety checks. **NEW** The enhanced network connectivity features include improved peer synchronization and emergency recovery mechanisms. Together, they form a robust foundation for validator operations in the VIZ node, with improved time synchronization, crash handling capabilities, enhanced plugin coordination features, comprehensive fork collision detection, reliable configuration parameter processing, strengthened fork database querying for detecting competing blocks at the same height, comprehensive validator reward creation validation with crash prevention and recovery procedures, 250ms interval optimization for deterministic slot time alignment, enhanced performance characteristics for better consensus maintenance, intelligent fork resolution system, automatic stale fork pruning, configurable timeout parameters for optimal network behavior, **NEW**: comprehensive minority fork detection system with automatic recovery mechanisms, **NEW**: enhanced emergency consensus mode integration, **NEW**: controlled production during recovery scenarios, **NEW**: efficient automatic recovery through P2P resynchronization for network stability, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals with detailed visibility, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms with automatic key restoration, **NEW**: consecutive block protection to prevent validator abuse, **NEW**: enhanced network connectivity with improved peer synchronization, **NEW**: validator guard plugin with comprehensive protection and monitoring, **NEW**: emergency consensus integration for continuous protection, **NEW**: network health monitoring for safe operations, and **NEW**: pending transaction tracking for reliable restoration. These enhancements make the validator system more resilient to various operational challenges while providing better integration points for the broader VIZ ecosystem, comprehensive protection against shared memory corruption, robust validation mechanisms for validator reward distribution across all hardfork versions, optimized timing for improved consensus maintenance, intelligent fork resolution with configurable behavior, automatic database maintenance for optimal performance, **NEW**: comprehensive minority fork detection and recovery mechanisms for network stability, **NEW**: enhanced emergency consensus mode integration for seamless operation during network distress, **NEW**: controlled production during recovery scenarios through skip_undo_history_check flag management, **NEW**: efficient automatic recovery through P2P resynchronization for rapid network stabilization, **NEW**: comprehensive debug logging system enabling verbose traces for block production and chain internals with detailed visibility, **NEW**: validator protection and monitoring capabilities with auto-restore and auto-disable features, **NEW**: emergency recovery mechanisms with automatic key restoration, **NEW**: consecutive block protection to prevent validator abuse, **NEW**: enhanced network connectivity with improved peer synchronization, and **NEW**: validator guard plugin with comprehensive protection and monitoring for enhanced network stability and security. \ No newline at end of file diff --git a/.qoder/repowiki/en/content/Webserver Plugin.md b/.qoder/repowiki/en/content/Webserver Plugin.md deleted file mode 100644 index 09475d7c6a..0000000000 --- a/.qoder/repowiki/en/content/Webserver Plugin.md +++ /dev/null @@ -1,823 +0,0 @@ -# Webserver Plugin - - -**Referenced Files in This Document** -- [webserver_plugin.hpp](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp) -- [webserver_plugin.cpp](file://plugins/webserver/webserver_plugin.cpp) -- [plugin.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/plugin.hpp) -- [plugin.cpp](file://plugins/json_rpc/plugin.cpp) -- [utility.hpp](file://plugins/json_rpc/include/graphene/plugins/json_rpc/utility.hpp) -- [webserver-plugin.md](file://documentation/webserver-plugin.md) -- [config.ini](file://share/vizd/config/config.ini) - - -## Update Summary -**Changes Made** -- Enhanced JSON RPC logging with gray color support for data dumps, improving log readability and debugging capabilities for RPC operations -- Updated diagnostic logging system to use ANSI escape sequences for visual distinction between normal operation and diagnostic information -- Improved developer experience with colored log output for request/response data visualization -- Enhanced timing measurements with precise elapsed time tracking for request processing -- Added comprehensive error tracking with timing context for better debugging - -## Table of Contents -1. [Introduction](#introduction) -2. [Project Structure](#project-structure) -3. [Core Components](#core-components) -4. [Architecture Overview](#architecture-overview) -5. [Detailed Component Analysis](#detailed-component-analysis) -6. [Dependency Analysis](#dependency-analysis) -7. [Performance Considerations](#performance-considerations) -8. [Security Considerations](#security-considerations) -9. [Configuration Guide](#configuration-guide) -10. [Troubleshooting Guide](#troubleshooting-guide) -11. [Logging and Diagnostics](#logging-and-diagnostics) -12. [Conclusion](#conclusion) - -## Introduction -The Webserver Plugin provides HTTP and WebSocket endpoints for JSON-RPC API access to the VIZ blockchain node. It serves as a bridge between external clients and the internal JSON-RPC system, offering both persistent WebSocket connections for real-time updates and standard HTTP endpoints for traditional API calls. The plugin includes an intelligent caching mechanisms that automatically classifies requests as mutating or non-mutating using robust fc::variant-based JSON parsing, optimizing performance for frequently accessed read-only API methods while preventing cache pollution from state-changing operations. - -**Updated** Enhanced with major performance optimizations to the JSON-RPC caching mechanism, including fc::variant-based JSON parsing, id-independent keys, robust request classification, comprehensive cache validation, improved WebSocket/HTTP handler support with proper JSON-RPC 2.0 response ID patching, modernized Boost library usage with std::bind and std::placeholders for better C++11 compatibility, and enhanced diagnostic logging with ANSI gray color support for improved debugging capabilities. - -## Project Structure -The webserver plugin is organized within the plugins/webserver directory structure, following the standard VIZ plugin architecture pattern: - -```mermaid -graph TB -subgraph "Webserver Plugin Structure" -A[webserver_plugin.hpp] --> B[Public Header] -C[webserver_plugin.cpp] --> D[Implementation] -subgraph "Dependencies" -E[json_rpc/plugin.hpp] --> F[JSON-RPC Plugin] -G[appbase/application.hpp] --> H[Application Framework] -I[websocketpp/server.hpp] --> J[WebSocket Library] -K[std::bind/std::placeholders] --> L[C++11 Standard Bindings] -M[fc::json::from_string] --> N[Proper JSON Parsing] -O[fc::variant] --> P[Robust Data Structures] -Q[ANSI Color Logging] --> R[Enhanced Diagnostics] -end -D --> E -D --> G -D --> I -D --> K -D --> M -D --> O -D --> Q -end -``` - -**Diagram sources** -- [webserver_plugin.hpp:1-62](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [webserver_plugin.cpp:1-605](file://plugins/webserver/webserver_plugin.cpp#L1-L605) - -**Section sources** -- [webserver_plugin.hpp:1-62](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L1-L62) -- [webserver_plugin.cpp:1-605](file://plugins/webserver/webserver_plugin.cpp#L1-L605) - -## Core Components -The webserver plugin consists of several key components working together to provide HTTP and WebSocket API services: - -### Main Plugin Class -The primary interface is the `webserver_plugin` class that inherits from appbase's plugin system, providing lifecycle management and configuration options. - -### Implementation Container -The `webserver_plugin_impl` struct contains all the internal state and functionality, including: -- HTTP and WebSocket server instances with separate io_service instances -- Thread pool management for concurrent request processing using appbase scheduler with modernized std::bind bindings -- Intelligent response caching mechanism with request classification and block-based invalidation using fc::variant parsing -- Connection handling for both HTTP and WebSocket protocols with std::bind-based message handlers -- Signal connections for blockchain event monitoring and cache management - -### JSON-RPC Integration -The plugin integrates with the JSON-RPC plugin to handle API method dispatching and response generation, supporting both individual requests and batch processing with comprehensive error handling using fc::json::from_string for proper JSON parsing. - -**Section sources** -- [webserver_plugin.hpp:32-57](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L32-L57) -- [webserver_plugin.cpp:190-234](file://plugins/webserver/webserver_plugin.cpp#L190-L234) - -## Architecture Overview -The webserver plugin follows a sophisticated multi-threaded architecture designed for high concurrency and reliability with intelligent caching control using fc::variant-based JSON parsing and modernized std::bind bindings: - -```mermaid -graph TB -subgraph "Client Layer" -A[HTTP Clients] -B[WebSocket Clients] -end -subgraph "Webserver Plugin" -C[HTTP Server Thread] -D[WebSocket Server Thread] -E[Thread Pool with std::bind] -F[Intelligent Cache System] -G[Request Classifier] -H[fc::variant Parser] -I[Response ID Patcher] -J[Cache Key Generator] -K[Malformed Request Handler] -end -subgraph "JSON-RPC Layer" -L[JSON-RPC Plugin with Enhanced Logging] -M[API Registry] -N[fc::json::from_string] -O[fc::variant Objects] -P[ANSI Color Logging] -Q[Diagnostic Timers] -end -subgraph "Blockchain Layer" -R[Chain Plugin] -S[Database] -T[Block Event Signals] -end -A --> C -B --> D -C --> E -D --> E -E --> G -G --> F -F --> I -F --> H -F --> J -F --> K -H --> N -H --> O -I --> N -J --> N -K --> N -K --> O -F -.-> C -F -.-> D -F -.-> E -G --> L -L --> M -M --> N -N --> R -O --> R -R --> S -R --> T -T --> F -P --> Q -``` - -**Diagram sources** -- [webserver_plugin.cpp:190-234](file://plugins/webserver/webserver_plugin.cpp#L190-L234) -- [webserver_plugin.cpp:236-289](file://plugins/webserver/webserver_plugin.cpp#L236-L289) -- [webserver_plugin.cpp:352-416](file://plugins/webserver/webserver_plugin.cpp#L352-L416) -- [webserver_plugin.cpp:418-495](file://plugins/webserver/webserver_plugin.cpp#L418-L495) -- [plugin.cpp:258-288](file://plugins/json_rpc/plugin.cpp#L258-L288) - -The architecture implements several key design patterns: -- **Separation of Concerns**: HTTP and WebSocket servers run in separate threads with dedicated io_service instances -- **Thread Pool Pattern**: Concurrent request processing with configurable thread count using appbase scheduler and modernized std::bind bindings -- **Intelligent Caching Pattern**: Request classification system with automatic cache control based on API mutability using fc::variant parsing -- **Observer Pattern**: Chain event subscription for automatic cache management on block application -- **Blacklist Pattern**: Mutating API detection and prevention of cache pollution using fc::variant-based method analysis -- **fc::variant Pattern**: Robust JSON parsing and manipulation using fc library variants for optimal performance -- **Error Handling Pattern**: Comprehensive fc::json::from_string-based error handling preventing crashes and improving reliability -- **Enhanced Logging Pattern**: ANSI color-coded diagnostic logging for improved debugging and monitoring - -**Updated** Enhanced with fc::variant-based JSON parsing, response ID patching, comprehensive error handling capabilities, improved cache management using fc::variant objects, modernized std::bind-based thread pool management, and enhanced diagnostic logging with ANSI gray color support. - -## Detailed Component Analysis - -### Modernized Thread Pool Management -The plugin uses the appbase scheduler for request processing with modernized std::bind bindings, providing a dedicated thread pool separate from the main application thread: - -```mermaid -classDiagram -class webserver_plugin_impl { -+thread_pool_size_t thread_pool_size -+asio : : io_service thread_pool_ios -+asio : : io_service : : work thread_pool_work -+vector worker_threads -+start_webserver() -+stop_webserver() -+handle_ws_message() -+handle_http_message() -+is_cacheable_request() -+make_cache_key() -+extract_request_id() -+patch_response_id() -+fc : : variant Parser -} -class ThreadGroup { -+create_thread(std : : bind) -+join_all() -+ioservice scheduler -} -webserver_plugin_impl --> ThreadGroup : "uses modernized std : : bind" -``` - -**Diagram sources** -- [webserver_plugin.cpp:190-197](file://plugins/webserver/webserver_plugin.cpp#L190-L197) - -**Updated** Enhanced with comprehensive fc::variant-based JSON parsing methods, improved cache management capabilities, robust fc::variant object handling, and modernized std::bind-based thread pool management using std::placeholders. - -### Enhanced WebSocket Message Handlers -The plugin implements modernized std::bind-based WebSocket message handlers with proper std::placeholders for parameter binding: - -```mermaid -sequenceDiagram -participant WS as "WebSocket Server" -participant Handler as "std : : bind Handler" -participant Parser as "fc : : json : : from_string Parser" -participant Variant as "fc : : variant Request" -participant Classifier as "Request Classifier" -participant Cache as "Cache System" -participant API as "JSON-RPC API" -WS->>Handler : WebSocket Message -Handler->>Parser : fc : : json : : from_string -Parser-->>Handler : fc : : variant Request -Handler->>Variant : Process request object -Handler->>Classifier : Check Mutating API -Classifier-->>Handler : Cache Decision -alt Cacheable Request -Handler->>Cache : Lookup Cache -Cache-->>Handler : Cache Hit/Miss -alt Cache Hit -Handler->>WS : Return Cached Response -else Cache Miss -Handler->>API : Process Request -API-->>Handler : Response -Handler->>Cache : Store Response -Handler->>WS : Return Response -end -else Non-Cacheable Request -Handler->>API : Process Request -API-->>Handler : Response -Handler->>WS : Return Response -end -``` - -**Diagram sources** -- [webserver_plugin.cpp:236-289](file://plugins/webserver/webserver_plugin.cpp#L236-L289) -- [webserver_plugin.cpp:352-416](file://plugins/webserver/webserver_plugin.cpp#L352-L416) - -**Updated** Enhanced with fc::variant-based JSON parsing, robust error handling, improved cache management, comprehensive fc::variant object processing, and modernized std::bind-based WebSocket message handlers using std::placeholders. - -### Intelligent Request Classification System -The plugin implements an advanced request classification system that automatically determines whether a JSON-RPC request should be cached based on its API mutability using robust fc::variant parsing: - -```mermaid -sequenceDiagram -participant Client as "Client" -participant Server as "Webserver Plugin" -participant Parser as "fc : : json : : from_string Parser" -participant Variant as "fc : : variant Object" -participant Classifier as "Request Classifier" -participant Cache as "Response Cache" -participant JSONRPC as "JSON-RPC Plugin" -Client->>Server : JSON-RPC Request -Server->>Parser : fc : : json : : from_string(request) -Parser-->>Server : fc : : variant object -Server->>Variant : Extract request object -Server->>Classifier : Analyze request method -Classifier->>Variant : Extract method name using fc : : variant -Classifier->>Variant : Check blacklist (network_broadcast_api, debug_node) -Classifier-->>Server : Cacheable/Non-cacheable decision -alt Cacheable request -Server->>Cache : Check cache availability -Cache-->>Server : Cache hit/miss -alt Cache miss -Server->>JSONRPC : Process request -JSONRPC-->>Server : Response -Server->>Cache : Store response -end -else Non-cacheable request -Server->>JSONRPC : Process request (bypass cache) -JSONRPC-->>Server : Response -end -Server-->>Client : Send response -``` - -**Diagram sources** -- [webserver_plugin.cpp:87-113](file://plugins/webserver/webserver_plugin.cpp#L87-L113) -- [webserver_plugin.cpp:352-416](file://plugins/webserver/webserver_plugin.cpp#L352-L416) -- [webserver_plugin.cpp:418-495](file://plugins/webserver/webserver_plugin.cpp#L418-L495) - -**Updated** Enhanced with fc::variant-based JSON parsing and robust request classification logic using fc::variant objects for method extraction and blacklist checking. - -### Response Caching Mechanism -The caching system provides significant performance improvements for frequently accessed API methods with sophisticated block-based invalidation and intelligent request filtering using fc::variant-based JSON parsing: - -```mermaid -flowchart TD -Start([Request Received]) --> Parse[Parse with fc::json::from_string] -Parse --> Valid{Valid JSON?} -Valid --> |No| ProcessDirect["Process Directly (No Cache)"] -Valid --> |Yes| Classify["Classify Request Type"] -Classify --> Mutating{"Mutating API?"} -Mutating --> |Yes| ProcessDirect -Mutating --> |No| Hash["Generate SHA256 Hash"] -Hash --> CacheCheck{"Cache Enabled?"} -CacheCheck --> |No| ProcessDirect -CacheCheck --> |Yes| LookupCache["Lookup Cache Entry"] -LookupCache --> CacheHit{"Cache Hit?"} -CacheHit --> |Yes| BlockCheck{"Block Valid?"} -CacheHit --> |No| ProcessRequest["Process Request"] -BlockCheck --> |Yes| PatchID["Patch Response ID"] -PatchID --> ReturnCached["Return Cached Response"] -BlockCheck --> |No| ProcessRequest -ProcessRequest --> StoreCache["Store in Cache"] -StoreCache --> ReturnResponse["Return Response"] -ProcessDirect --> ReturnResponse -ReturnCached --> End([Complete]) -ReturnResponse --> End -``` - -**Diagram sources** -- [webserver_plugin.cpp:207-234](file://plugins/webserver/webserver_plugin.cpp#L207-L234) -- [webserver_plugin.cpp:87-113](file://plugins/webserver/webserver_plugin.cpp#L87-L113) -- [webserver_plugin.cpp:136-158](file://plugins/webserver/webserver_plugin.cpp#L136-L158) - -**Updated** Enhanced with fc::variant-based JSON parsing, response ID patching, comprehensive cache validation, and improved error handling using fc::variant objects. - -### Enhanced Cache Key Generation -The plugin now implements id-independent cache keys to prevent cache bypass attacks and improve cache efficiency using fc::variant-based request parsing: - -```mermaid -flowchart TD -Request[JSON-RPC Request] --> Parse[fc::json::from_string] -Parse --> Batch{Is Array Request?} -Batch --> |Yes| FullHash[SHA256 Hash Full Array] -Batch --> |No| BuildKey[Build Key Material] -BuildKey --> Method{Has Method?} -Method --> |Yes| AddMethod[Add Method to Key] -Method --> |No| ParamsCheck{Has Params?} -AddMethod --> ParamsCheck -ParamsCheck --> |Yes| AddParams[Add Params to Key] -ParamsCheck --> |No| EmptyKey[Empty Key Material] -AddParams --> HashKey[SHA256 Hash Key Material] -EmptyKey --> HashKey -HashKey --> CacheKey[Unique Cache Key] -FullHash --> CacheKey -CacheKey --> UseKey[Use for Cache Lookup] -``` - -**Diagram sources** -- [webserver_plugin.cpp:136-158](file://plugins/webserver/webserver_plugin.cpp#L136-L158) - -**Updated** Enhanced with fc::variant-based JSON parsing and id-independent cache key generation that prevents cache bypass attacks using fc::variant objects for method and parameter extraction. - -### Enhanced Response ID Handling -The plugin implements proper JSON-RPC 2.0 compliance with response ID patching using fc::json::from_string for accurate ID extraction and replacement: - -```mermaid -flowchart TD -Response[JSON-RPC Response] --> ParseResp[fc::json::from_string] -ParseResp --> HasID{Has ID Field?} -HasID --> |No| ReturnResp[Return Original Response] -HasID --> |Yes| ExtractID[Extract Request ID] -ExtractID --> PatchResp[Replace Response ID] -PatchResp --> Serialize[fc::json::to_string] -Serialize --> ReturnPatched[Return Patched Response] -ReturnResp --> End([Complete]) -ReturnPatched --> End -``` - -**Diagram sources** -- [webserver_plugin.cpp:160-182](file://plugins/webserver/webserver_plugin.cpp#L160-L182) - -**Updated** Enhanced with fc::variant-based JSON parsing for accurate response ID extraction and proper JSON-RPC 2.0 compliance using fc::variant objects. - -### Enhanced Request Processing Pipeline -The plugin now includes improved WebSocket and HTTP handler support with better request processing using fc::variant-based JSON parsing and modernized std::bind bindings: - -```mermaid -sequenceDiagram -participant Client as "Client" -participant Handler as "HTTP/WebSocket Handler" -participant Parser as "fc : : json : : from_string Parser" -participant Variant as "fc : : variant Request" -participant Classifier as "Request Classifier" -participant Cache as "Cache System" -participant API as "JSON-RPC API" -Client->>Handler : Raw Request -Handler->>Parser : fc : : json : : from_string -Parser-->>Handler : fc : : variant Request -Handler->>Variant : Process request object -Handler->>Classifier : Check Mutating API -Classifier-->>Handler : Cache Decision -alt Cacheable Request -Handler->>Cache : Lookup Cache -Cache-->>Handler : Cache Hit/Miss -alt Cache Hit -Handler->>Client : Return Cached Response -else Cache Miss -Handler->>API : Process Request -API-->>Handler : Response -Handler->>Cache : Store Response -Handler->>Client : Return Response -end -else Non-Cacheable Request -Handler->>API : Process Request -API-->>Handler : Response -Handler->>Client : Return Response -end -``` - -**Diagram sources** -- [webserver_plugin.cpp:352-495](file://plugins/webserver/webserver_plugin.cpp#L352-L495) - -**Updated** Enhanced with fc::variant-based JSON parsing, robust error handling, improved cache management, comprehensive fc::variant object processing, and modernized std::bind-based handler implementations. - -### Configuration and Options -The plugin supports extensive configuration through command-line options and configuration files with enhanced processing order: - -| Option | Default | Description | -|--------|---------|-------------| -| `webserver-http-endpoint` | (none) | HTTP listen endpoint (IP:port) | -| `webserver-ws-endpoint` | (none) | WebSocket listen endpoint (IP:port) | -| `rpc-endpoint` | (none) | Combined HTTP/WS endpoint (deprecated) | -| `webserver-thread-pool-size` | 256 | Number of handler threads | -| `webserver-cache-enabled` | true | Enable response caching | -| `webserver-cache-size` | 10000 | Maximum cached responses | - -**Updated** Enhanced with actual implementation details and current default values, including improved rpc-endpoint processing order that prioritizes specific endpoints over deprecated combined endpoints. - -**Section sources** -- [webserver_plugin.cpp:503-517](file://plugins/webserver/webserver_plugin.cpp#L503-L517) -- [webserver-plugin.md:111-124](file://documentation/webserver-plugin.md#L111-L124) - -## Dependency Analysis -The webserver plugin has well-defined dependencies that enable its functionality with enhanced fc::variant integration and modernized std::bind usage: - -```mermaid -graph LR -subgraph "External Dependencies" -A[Boost.Asio] -B[websocketpp] -C[FC Library] -D[AppBase Framework] -E[fc::json::from_string] -F[fc::variant] -G[fc::mutable_variant_object] -H[std::bind/std::placeholders] -I[ANSI Color Sequences] -J[Terminal Logging] -end -subgraph "Internal Dependencies" -K[JSON-RPC Plugin with Enhanced Logging] -L[Chain Plugin] -M[Application Core] -end -subgraph "Webserver Plugin" -N[webserver_plugin] -O[is_cacheable_request] -P[make_cache_key] -Q[extract_request_id] -R[patch_response_id] -S[fc::variant Parser] -T[Cache Key Generator] -U[Response ID Patcher] -V[std::bind Message Handlers] -W[Diagnostic Logging] -X[Colorized Output] -end -J --> I -K --> W -W --> X -L --> K -L --> M -L --> N -N --> A -N --> B -N --> C -N --> D -N --> E -N --> F -N --> G -N --> H -N --> I -N --> J -O --> P -P --> Q -Q --> R -R --> S -S --> T -T --> U -U --> V -W --> X -``` - -**Diagram sources** -- [webserver_plugin.hpp:3-9](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L3-L9) -- [webserver_plugin.cpp:12-31](file://plugins/webserver/webserver_plugin.cpp#L12-L31) -- [webserver_plugin.cpp:87-113](file://plugins/webserver/webserver_plugin.cpp#L87-L113) -- [plugin.cpp:258-288](file://plugins/json_rpc/plugin.cpp#L258-L288) - -### JSON-RPC Integration Details -The plugin integrates with the JSON-RPC system through method registration and call delegation using fc::json::from_string for proper JSON parsing with enhanced fc::variant object handling, modernized std::bind-based handler implementations, and enhanced diagnostic logging with ANSI color support: - -```mermaid -sequenceDiagram -participant WS as "Webserver Plugin" -participant JR as "JSON-RPC Plugin with Enhanced Logging" -participant AR as "API Registry" -participant AP as "API Method" -WS->>JR : call(json_body, callback) -JR->>AR : Find API method -AR->>AP : Execute method(args) -AP-->>AR : Return result -AR-->>JR : Return variant result -JR-->>WS : Stringified response with colored diagnostics -WS-->>Client : Send response -``` - -**Diagram sources** -- [plugin.cpp:180-200](file://plugins/json_rpc/plugin.cpp#L180-L200) -- [webserver_plugin.cpp:398](file://plugins/webserver/webserver_plugin.cpp#L398) -- [webserver_plugin.cpp:468](file://plugins/webserver/webserver_plugin.cpp#L468) - -**Updated** Enhanced with fc::json::from_string-based JSON parsing, robust error handling, comprehensive fc::variant object processing, modernized std::bind-based handler implementations, and enhanced diagnostic logging with ANSI gray color support. - -**Section sources** -- [webserver_plugin.hpp:38](file://plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp#L38) -- [webserver_plugin.cpp:224](file://plugins/webserver/webserver_plugin.cpp#L224) -- [plugin.cpp:159-178](file://plugins/json_rpc/plugin.cpp#L159-L178) - -## Performance Considerations -The webserver plugin implements several performance optimization strategies with intelligent caching control using fc::variant-based JSON parsing and modernized std::bind bindings: - -### Intelligent Caching Strategy -- **Request Classification**: Automatic determination of cacheable vs non-cacheable requests based on API mutability using fc::variant parsing -- **SHA256 Hash Keys**: Unique request identification for cache entries using cryptographic hashing with fc::json::from_string -- **Block-Based Invalidation**: Cache cleared on each new block to prevent stale data through blockchain event subscription -- **Thread-Safe Operations**: Mutex protection for concurrent access across multiple worker threads -- **Eviction Policy**: Automatic cache clearing when maximum size is reached to prevent memory exhaustion -- **Selective Caching**: Prevents cache pollution from mutating API calls (network_broadcast_api, debug_node) -- **Id-Independent Keys**: Prevents cache bypass attacks via id rotation patterns using fc::variant-based key generation -- **Robust JSON Parsing**: Reliable fc::json::from_string-based request parsing instead of complex object traversal -- **fc::variant Efficiency**: Optimized fc::variant usage for JSON parsing and manipulation with proper object lifetime management -- **Modernized Bindings**: Efficient std::bind usage with std::placeholders for better C++11 compatibility and performance -- **Enhanced Logging Performance**: ANSI color logging with minimal overhead for improved debugging without impacting performance - -### Concurrency Model -- **Separate IO Services**: HTTP and WebSocket servers use dedicated io_service instances for isolation -- **Configurable Thread Pool**: Adjustable worker thread count based on workload using appbase scheduler with modernized std::bind bindings -- **Non-blocking Operations**: Async processing prevents thread starvation and improves throughput -- **Connection Pooling**: Efficient WebSocket connection handling with proper resource management - -### Memory Management -- **Smart Pointers**: Proper resource management for server instances and cache entries -- **RAII Patterns**: Automatic cleanup on plugin shutdown through destructor implementations -- **Cache Size Limits**: Configurable maximum cache size to prevent unbounded memory growth -- **Blacklist Optimization**: Reduces unnecessary cache storage for mutating API calls -- **fc::variant Efficiency**: Optimized fc::variant usage for JSON parsing and manipulation with proper memory management -- **Modernized Bindings**: Efficient std::bind usage with std::placeholders for better performance and C++11 compatibility -- **Color Logging Overhead**: Minimal performance impact from ANSI color sequences in diagnostic logging - -**Updated** Enhanced with fc::variant-based JSON parsing, robust cache validation, comprehensive performance optimizations, improved fc::variant object handling, modernized std::bind-based thread pool management, and enhanced diagnostic logging with ANSI gray color support. - -**Section sources** -- [webserver-plugin.md:29-64](file://documentation/webserver-plugin.md#L29-L64) -- [webserver_plugin.cpp:207-234](file://plugins/webserver/webserver_plugin.cpp#L207-L234) -- [webserver_plugin.cpp:87-113](file://plugins/webserver/webserver_plugin.cpp#L87-L113) - -## Security Considerations -The webserver plugin provides multiple layers of security for production deployments with enhanced API access control using fc::variant-based JSON parsing and modernized std::bind bindings: - -### Network Security -- **Localhost Binding**: Recommended practice for internal services using 127.0.0.1 binding -- **External Access Control**: Use 0.0.0.0 binding only for trusted networks -- **Port Management**: Separate HTTP (8090) and WebSocket (8091) ports for different access patterns - -### API Access Control -- **Public API Restriction**: Use `public-api` configuration to limit exposed API surface -- **Authentication**: Implement `api-user` authentication for sensitive operations -- **Rate Limiting**: Consider external rate limiting solutions for public APIs -- **Mutating API Protection**: Automatic blacklist prevents caching of state-changing operations - -### Input Validation -- **JSON-RPC Validation**: Built-in validation of JSON-RPC 2.0 compliance using fc::json::from_string -- **Method Whitelisting**: Only registered API methods are callable -- **Parameter Validation**: Type checking and parameter validation for API calls -- **Request Classification**: Automatic detection of potentially malicious mutating requests using fc::variant parsing - -### Resource Protection -- **Thread Pool Limits**: Configurable thread pool size prevents resource exhaustion -- **Cache Size Limits**: Configurable cache limits prevent memory abuse -- **Connection Limits**: WebSocket connections managed through proper thread pool utilization -- **Blacklist Enforcement**: Prevents cache poisoning from mutating API calls -- **Cache Bypass Prevention**: Id-independent keys prevent cache bypass attacks via request id rotation -- **Robust Error Handling**: Comprehensive fc::variant-based error handling prevents crashes -- **Malformed Request Protection**: Invalid JSON requests are handled gracefully without cache pollution -- **Modernized Bindings**: Efficient std::bind usage with std::placeholders for better performance and security -- **Enhanced Logging Security**: ANSI color logging provides clear visibility without exposing sensitive data - -**Updated** Enhanced with fc::variant-based JSON parsing, robust error handling, comprehensive security measures, improved fc::variant object validation, modernized std::bind-based security implementations, and enhanced diagnostic logging with ANSI gray color support. - -**Section sources** -- [webserver-plugin.md:77-108](file://documentation/webserver-plugin.md#L77-L108) - -## Configuration Guide - -### Basic Configuration -Enable the webserver plugin in `config.ini`: - -```ini -plugin = webserver - -# HTTP endpoint (required for HTTP API access) -webserver-http-endpoint = 127.0.0.1:8090 - -# WebSocket endpoint (required for WebSocket API access) -webserver-ws-endpoint = 127.0.0.1:8091 - -# Or use a single endpoint for both (deprecated) -# rpc-endpoint = 127.0.0.1:8090 -``` - -### Advanced Configuration -```ini -# Thread pool configuration for high concurrency -webserver-thread-pool-size = 256 - -# Response caching configuration -webserver-cache-enabled = true -webserver-cache-size = 10000 - -# API access control -public-api = database_api -public-api = network_broadcast_api - -# Authentication -api-user = username:password:database_api -``` - -### Production Configuration -For production deployments, consider: - -```ini -# High performance settings -webserver-thread-pool-size = 512 -webserver-cache-size = 50000 - -# Security settings -webserver-http-endpoint = 127.0.0.1:8090 -webserver-ws-endpoint = 127.0.0.1:8091 - -# API restrictions -public-api = database_api -public-api = account_by_key -``` - -**Updated** Enhanced with actual implementation details and current configuration options, including improved rpc-endpoint processing order that prioritizes specific endpoints over deprecated combined endpoints. - -**Section sources** -- [webserver-plugin.md:12-27](file://documentation/webserver-plugin.md#L12-L27) -- [webserver-plugin.md:40-48](file://documentation/webserver-plugin.md#L40-L48) -- [webserver-plugin.md:109-125](file://documentation/webserver-plugin.md#L109-L125) - -## Troubleshooting Guide - -### Common Issues and Solutions - -#### Server Binding Failures -**Problem**: Unable to bind to specified endpoints -**Solution**: Verify port availability and network permissions -- Check if ports are already in use -- Ensure proper network interface binding -- Verify firewall configuration - -#### High Memory Usage -**Problem**: Excessive memory consumption from caching -**Solution**: Adjust cache configuration -- Reduce `webserver-cache-size` value -- Disable caching for low-traffic scenarios -- Monitor cache hit ratios and memory usage - -#### Performance Degradation -**Problem**: Slow response times under load -**Solution**: Optimize thread pool configuration -- Increase `webserver-thread-pool-size` -- Monitor thread utilization and queue lengths -- Consider hardware resource allocation - -### Error Handling Patterns -The plugin implements comprehensive error handling with intelligent request classification using fc::variant-based JSON parsing: - -```mermaid -flowchart TD -Request[Incoming Request] --> Parse[fc::json::from_string] -Parse --> Valid{Valid JSON?} -Valid --> |No| ParseError[Return Parse Error] -Valid --> |Yes| Classify[Classify Request Type] -Classify --> Mutating{Mutating API?} -Mutating --> |Yes| ProcessDirect[Process Directly] -Mutating --> |No| CacheCheck[Check Cache] -CacheCheck --> CacheHit{Cache Hit?} -CacheHit --> |Yes| PatchID[Patch Response ID] -PatchID --> SendCached[Send Cached Response] -CacheHit --> |No| Process[Process Request] -ProcessDirect --> SendResponse[Send Response] -Process --> Success{Success?} -Success --> |Yes| CacheStore[Store in Cache] -Success --> |No| SendError[Return Error Response] -CacheStore --> SendResponse -SendCached --> Complete[Complete] -SendResponse --> Complete -SendError --> Complete -ParseError --> Complete -``` - -**Diagram sources** -- [webserver_plugin.cpp:352-416](file://plugins/webserver/webserver_plugin.cpp#L352-L416) -- [webserver_plugin.cpp:418-495](file://plugins/webserver/webserver_plugin.cpp#L418-L495) -- [webserver_plugin.cpp:398](file://plugins/webserver/webserver_plugin.cpp#L398) - -**Updated** Enhanced with fc::variant-based JSON parsing, robust error handling, intelligent request classification, comprehensive fc::variant object processing, and modernized std::bind-based error handling implementations. - -### Debugging and Monitoring -- **Log Levels**: Configure appropriate log levels for debugging -- **Connection Monitoring**: Monitor active WebSocket connections -- **Performance Metrics**: Track cache hit rates and thread pool utilization -- **Error Analysis**: Review error logs for common issues -- **Request Classification**: Monitor which requests are classified as mutating vs non-mutating -- **Cache Efficiency**: Monitor cache key generation and collision rates -- **fc::variant Parsing**: Monitor JSON parsing performance and error rates -- **Configuration Processing**: Monitor rpc-endpoint processing order and endpoint resolution -- **Modernized Bindings**: Monitor std::bind usage and std::placeholders performance -- **Enhanced Logging**: Monitor ANSI color logging output for improved debugging visibility - -**Updated** Enhanced with fc::variant-based JSON parsing monitoring, comprehensive debugging capabilities, improved configuration processing diagnostics, modernized std::bind-based monitoring implementations, and enhanced diagnostic logging with ANSI gray color support. - -**Section sources** -- [webserver_plugin.cpp:352-416](file://plugins/webserver/webserver_plugin.cpp#L352-L416) -- [webserver_plugin.cpp:418-495](file://plugins/webserver/webserver_plugin.cpp#L418-L495) -- [webserver_plugin.cpp:398](file://plugins/webserver/webserver_plugin.cpp#L398) - -## Logging and Diagnostics - -### Enhanced Diagnostic Logging with ANSI Color Support -The JSON RPC plugin now includes enhanced diagnostic logging with ANSI gray color support to help developers quickly distinguish between normal operation and diagnostic information: - -```mermaid -sequenceDiagram -participant Client as "Client" -participant JSONRPC as "JSON-RPC Plugin with Enhanced Logging" -participant Timer as "dump_rpc_time" -participant Logger as "Diagnostic Logger" -Client->>JSONRPC : JSON-RPC Request -JSONRPC->>Timer : Create timer instance -Timer->>Logger : Log colored diagnostic data -Logger-->>Timer : Colored output : "data : ${data}" (ANSI Gray) -Timer->>JSONRPC : Process request -JSONRPC->>Timer : Handle completion -alt Success -Timer->>Logger : Log elapsed time and data -Logger-->>Client : Colored output : "elapsed : ${time} sec, data : ${data}" (ANSI Gray) -else Error -Timer->>Logger : Log elapsed time, error, and data -Logger-->>Client : Colored output : "elapsed : ${time} sec, error : '${error}', data : ${data}" (ANSI Gray) -end -``` - -**Diagram sources** -- [plugin.cpp:258-288](file://plugins/json_rpc/plugin.cpp#L258-L288) - -### ANSI Color Coding Features -The diagnostic logging system uses ANSI escape sequences for visual distinction: - -- **Gray Color Codes**: `\033[90m` for diagnostic information -- **Reset Code**: `\033[0m` to restore normal terminal colors -- **Timing Information**: Elapsed time measurements in seconds -- **Data Processing**: Request/response data visualization with enhanced readability -- **Error Context**: Error messages with associated timing data -- **Improved Debugging**: Visual separation between normal application logs and diagnostic information - -### Developer Experience Improvements -- **Visual Separation**: Gray-colored diagnostic logs help distinguish from normal application logs -- **Real-time Timing**: Precise timing measurements for request processing -- **Data Visibility**: Structured logging of request/response data with enhanced formatting -- **Error Tracking**: Comprehensive error logging with timing context for better debugging -- **Performance Insights**: Easy identification of slow operations through timing data -- **Enhanced Readability**: Improved log readability with color-coded diagnostic information - -**Updated** Enhanced with fc::variant-based JSON parsing and comprehensive diagnostic logging with ANSI gray color support for improved developer experience and debugging capabilities. - -**Section sources** -- [plugin.cpp:258-288](file://plugins/json_rpc/plugin.cpp#L258-L288) - -## Conclusion -The Webserver Plugin provides a robust, high-performance solution for exposing VIZ blockchain functionality through HTTP and WebSocket interfaces. Its architecture emphasizes scalability through concurrent processing, reliability through comprehensive error handling, and efficiency through intelligent caching mechanisms with request classification using fc::variant-based JSON parsing. The plugin's modular design and extensive configuration options make it suitable for various deployment scenarios, from development environments to production public API services. - -Key strengths of the implementation include: -- **High Concurrency**: Thread pool architecture supporting thousands of concurrent requests with modernized std::bind bindings -- **Intelligent Caching**: Block-aware cache invalidation with automatic request classification preventing stale data using fc::variant parsing -- **Selective Caching**: Automatic blacklist for mutating API calls (network_broadcast_api, debug_node) preventing cache pollution -- **Flexible Deployment**: Separate HTTP and WebSocket endpoints with independent configuration -- **Production Ready**: Comprehensive error handling and graceful degradation -- **Security Features**: Multiple layers of security including intelligent request classification for mutating APIs -- **Enhanced Diagnostics**: ANSI color-coded logging system with gray color support for improved developer experience -- **Extensible Design**: Clean separation of concerns enabling easy maintenance and enhancement -- **Performance Optimizations**: Major improvements to caching mechanism with id-independent keys and fc::variant-based JSON parsing -- **Robust Request Processing**: Enhanced WebSocket/HTTP handler support with improved request classification and cache management using modernized std::bind bindings -- **fc::variant Integration**: Comprehensive fc::variant-based JSON parsing and manipulation for optimal performance -- **Comprehensive Error Handling**: Robust fc::json::from_string-based error handling preventing crashes and improving reliability -- **Enhanced Configuration Management**: Improved rpc-endpoint processing order with proper endpoint resolution and deprecation warnings -- **Modernized C++11 Compatibility**: Efficient std::bind usage with std::placeholders for better C++11 compatibility and performance -- **Efficient Thread Pool Management**: Modernized std::bind-based thread pool management with std::placeholders for optimal performance -- **Enhanced Logging System**: ANSI color-coded diagnostic logging with gray color support for improved debugging and monitoring capabilities - -The plugin serves as an excellent foundation for building applications that require programmatic access to VIZ blockchain data and operations, with performance characteristics suitable for both private deployments and public API services. Its sophisticated caching mechanism with intelligent request classification, multi-threaded architecture with modernized std::bind bindings, comprehensive error handling, fc::variant-based JSON parsing, enhanced diagnostic logging with ANSI gray color support, improved configuration management with rpc-endpoint processing order changes, and efficient std::bind-based thread pool management make it a production-ready solution for enterprise-grade blockchain applications. - -**Updated** Enhanced conclusion reflecting the expanded implementation details, fc::variant-based JSON parsing, intelligent request classification system, selective caching mechanisms, enhanced WebSocket/HTTP handler support with modernized std::bind bindings, major performance optimizations including id-independent cache keys, comprehensive cache configuration options, improved configuration management with rpc-endpoint processing order changes, modernized C++11 compatibility with std::bind and std::placeholders usage, and enhanced diagnostic logging with ANSI gray color support for improved debugging capabilities. \ No newline at end of file diff --git a/.qoder/repowiki/en/meta/repowiki-metadata.json b/.qoder/repowiki/en/meta/repowiki-metadata.json deleted file mode 100644 index fb570f482d..0000000000 --- a/.qoder/repowiki/en/meta/repowiki-metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"code_snippets":[{"id":"e6b951c57c5f8fb2b3553ce8db430760","path":"plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","line_range":"18-55","gmt_create":"2026-04-28T09:55:13.5601426+04:00","gmt_modified":"2026-04-28T09:55:13.5601426+04:00"},{"id":"467b9030fcd47369d3417c84998c20d0","path":"plugins/p2p/p2p_plugin.cpp","line_range":"910-979","gmt_create":"2026-04-28T09:55:13.5607279+04:00","gmt_modified":"2026-04-28T09:55:13.5607279+04:00"},{"id":"cbfe85acce275b65a2edb3315aec2941","path":"libraries/network/include/graphene/network/node.hpp","line_range":"190-320","gmt_create":"2026-04-28T09:55:13.5617916+04:00","gmt_modified":"2026-04-28T09:55:13.5617916+04:00"},{"id":"9e18fa1bdbee1d9c96d8437bfe20515c","path":"plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","line_range":"1-57","gmt_create":"2026-04-28T09:55:13.5619843+04:00","gmt_modified":"2026-04-28T09:55:13.5619843+04:00"},{"id":"5dce2933cfb42430c2bbcdf0cacc25c3","path":"plugins/p2p/CMakeLists.txt","line_range":"1-49","gmt_create":"2026-04-28T09:55:13.562487+04:00","gmt_modified":"2026-04-28T09:55:13.562487+04:00"},{"id":"1b55f505ae64e9ea22be5142cfa67f93","path":"plugins/p2p/p2p_plugin.cpp","line_range":"49-126","gmt_create":"2026-04-28T09:55:13.5630878+04:00","gmt_modified":"2026-04-28T09:55:13.5630878+04:00"},{"id":"8a161abeb389c25b1279bc23d6ff4e57","path":"libraries/network/include/graphene/network/node.hpp","line_range":"60-167","gmt_create":"2026-04-28T09:55:13.5637371+04:00","gmt_modified":"2026-04-28T09:55:13.5637371+04:00"},{"id":"f85f57d0c6b461ab78f906ef6d5854c0","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"79-354","gmt_create":"2026-04-28T09:55:13.5646848+04:00","gmt_modified":"2026-04-28T09:55:13.5646848+04:00"},{"id":"21076248fc123c7aacc8cb6e67cd0068","path":"plugins/p2p/p2p_plugin.cpp","line_range":"758-823","gmt_create":"2026-04-28T09:55:13.5651893+04:00","gmt_modified":"2026-04-28T09:55:13.5651893+04:00"},{"id":"4e79c62ed5491dcd85510f3dab144813","path":"libraries/network/node.cpp","line_range":"1-200","gmt_create":"2026-04-28T09:55:13.5661929+04:00","gmt_modified":"2026-04-28T09:55:13.5661929+04:00"},{"id":"fe82427a3c86c02f05708734fa4c589c","path":"plugins/p2p/p2p_plugin.cpp","line_range":"216-245","gmt_create":"2026-04-28T09:55:13.5665017+04:00","gmt_modified":"2026-04-28T09:55:13.5665017+04:00"},{"id":"15bc72540b02de4c57e4c976c8150f35","path":"plugins/p2p/p2p_plugin.cpp","line_range":"855-865","gmt_create":"2026-04-28T09:55:13.5671967+04:00","gmt_modified":"2026-04-28T09:55:13.5671967+04:00"},{"id":"cd0a62c9a78bb77d3b59a9d5872577f4","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"82-106","gmt_create":"2026-04-28T09:55:13.5671967+04:00","gmt_modified":"2026-04-28T09:55:13.5671967+04:00"},{"id":"7eaff221b9d5916b8e18aa7786630566","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"188-218","gmt_create":"2026-04-28T09:55:13.5671967+04:00","gmt_modified":"2026-04-28T09:55:13.5671967+04:00"},{"id":"9ec3ef7b5beba7ccd4c8172983e359a7","path":"plugins/p2p/p2p_plugin.cpp","line_range":"247-301","gmt_create":"2026-04-28T09:55:13.5681968+04:00","gmt_modified":"2026-04-28T09:55:13.5681968+04:00"},{"id":"685c2a44fc90d96152180fc6a5a63df4","path":"plugins/p2p/p2p_plugin.cpp","line_range":"129-208","gmt_create":"2026-04-28T09:55:13.5681968+04:00","gmt_modified":"2026-04-28T09:55:13.5681968+04:00"},{"id":"9ad98a7be17ee5186d08088816474c52","path":"plugins/witness/witness.cpp","line_range":"540-552","gmt_create":"2026-04-28T09:55:13.5691969+04:00","gmt_modified":"2026-04-28T09:55:13.5691969+04:00"},{"id":"a273323d20c428afec092114bb480a23","path":"thirdparty/chainbase/include/chainbase/chainbase.hpp","line_range":"1078-1115","gmt_create":"2026-04-28T09:55:13.5714297+04:00","gmt_modified":"2026-04-28T09:55:13.5714297+04:00"},{"id":"27c21c9dfb07f579bd0db9fa97c8fd19","path":"thirdparty/chainbase/include/chainbase/chainbase.hpp","line_range":"1130-1137","gmt_create":"2026-04-28T09:55:13.5724293+04:00","gmt_modified":"2026-04-28T09:55:13.5724293+04:00"},{"id":"3b4fd0aa5c9c47621979a050b80b5fc2","path":"plugins/p2p/p2p_plugin.cpp","line_range":"173-208","gmt_create":"2026-04-28T09:55:13.5724293+04:00","gmt_modified":"2026-04-28T09:55:13.5724293+04:00"},{"id":"411e466fa1c626bc1fff0647607acabd","path":"plugins/p2p/p2p_plugin.cpp","line_range":"151-156","gmt_create":"2026-04-28T09:55:13.5734294+04:00","gmt_modified":"2026-04-28T09:55:13.5734294+04:00"},{"id":"8eb355e55d14f0a3eec62805ff783a2f","path":"plugins/p2p/CMakeLists.txt","line_range":"27-34","gmt_create":"2026-04-28T09:55:13.5734294+04:00","gmt_modified":"2026-04-28T09:55:13.5734294+04:00"},{"id":"4fc812a0df4303ac6e74df39697a0893","path":"plugins/p2p/p2p_plugin.cpp","line_range":"1-13","gmt_create":"2026-04-28T09:55:13.5734294+04:00","gmt_modified":"2026-04-28T09:55:13.5734294+04:00"},{"id":"cd8c02da5ea31d3411ad151149d2f64e","path":"programs/vizd/main.cpp","line_range":"63-92","gmt_create":"2026-04-28T09:57:03.8238509+04:00","gmt_modified":"2026-04-28T09:57:03.8238509+04:00"},{"id":"2d883d06f58fd34d81e8588c75185aa9","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"34-68","gmt_create":"2026-04-28T09:57:03.8238509+04:00","gmt_modified":"2026-04-28T09:57:03.8238509+04:00"},{"id":"b6e11846d82ee129d5956cf9b8cbbea8","path":"plugins/witness/witness.cpp","line_range":"59-118","gmt_create":"2026-04-28T09:57:03.8256998+04:00","gmt_modified":"2026-04-28T09:57:03.8256998+04:00"},{"id":"cda9a1d47dfdb3a7374fa817887892c0","path":"plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp","line_range":"56-98","gmt_create":"2026-04-28T09:57:03.8256998+04:00","gmt_modified":"2026-04-28T09:57:03.8256998+04:00"},{"id":"f5891db138d66a58674791b9e99bd337","path":"plugins/witness_api/plugin.cpp","line_range":"13-28","gmt_create":"2026-04-28T09:57:03.8256998+04:00","gmt_modified":"2026-04-28T09:57:03.8256998+04:00"},{"id":"51169b91af554f837e41d2913dacad48","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"37-83","gmt_create":"2026-04-28T09:57:03.8262406+04:00","gmt_modified":"2026-04-28T09:57:03.8262406+04:00"},{"id":"5aed64f2f61be210a303b341a970b0cc","path":"libraries/chain/include/graphene/chain/witness_objects.hpp","line_range":"27-132","gmt_create":"2026-04-28T09:57:03.8262406+04:00","gmt_modified":"2026-04-28T09:57:03.8262406+04:00"},{"id":"47b98e10075d52a89428f617d837a5e5","path":"libraries/chain/include/graphene/chain/chain_objects.hpp","line_range":"174-201","gmt_create":"2026-04-28T09:57:03.8262406+04:00","gmt_modified":"2026-04-28T09:57:03.8262406+04:00"},{"id":"42aa356d9e26fadf05fda749f1d89cff","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"53-81","gmt_create":"2026-04-28T09:57:03.8262406+04:00","gmt_modified":"2026-04-28T09:57:03.8262406+04:00"},{"id":"19e78b124cb1653f5e72af6789493e08","path":"libraries/time/time.cpp","line_range":"13-53","gmt_create":"2026-04-28T09:57:03.8267656+04:00","gmt_modified":"2026-04-28T09:57:03.8267656+04:00"},{"id":"1bf53ebbc25ba8c147446f02ce5e44e2","path":"plugins/snapshot/plugin.cpp","line_range":"1267-1276","gmt_create":"2026-04-28T09:57:03.8272866+04:00","gmt_modified":"2026-04-28T09:57:03.8272866+04:00"},{"id":"cecb2c27bddde9783761743ffbbfac88","path":"plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","line_range":"50-55","gmt_create":"2026-04-28T09:57:03.8272866+04:00","gmt_modified":"2026-04-28T09:57:03.8272866+04:00"},{"id":"4a84a6b27fbcb47e0994f0bda545816f","path":"plugins/witness/witness.cpp","line_range":"206-249","gmt_create":"2026-04-28T09:57:03.8278629+04:00","gmt_modified":"2026-04-28T09:57:03.8278629+04:00"},{"id":"3d0cbd79a1648b655b90b7629307cad1","path":"plugins/witness/witness.cpp","line_range":"206-276","gmt_create":"2026-04-28T09:57:03.8283666+04:00","gmt_modified":"2026-04-28T09:57:03.8283666+04:00"},{"id":"6abe7f6efde355ee9f2d7cf0776677ff","path":"plugins/witness/witness.cpp","line_range":"278-423","gmt_create":"2026-04-28T09:57:03.8288828+04:00","gmt_modified":"2026-04-28T09:57:03.8288828+04:00"},{"id":"1cf7bf28dd5011954754492ccf7873f5","path":"plugins/witness/witness.cpp","line_range":"447-471","gmt_create":"2026-04-28T09:57:03.8288828+04:00","gmt_modified":"2026-04-28T09:57:03.8288828+04:00"},{"id":"31e5e32f87baccd25fbb2183951a67bd","path":"plugins/witness/witness.cpp","line_range":"590-695","gmt_create":"2026-04-28T09:57:03.8288828+04:00","gmt_modified":"2026-04-28T09:57:03.8288828+04:00"},{"id":"1844592144295f47f4238341e8868e6b","path":"plugins/witness/witness.cpp","line_range":"263-266","gmt_create":"2026-04-28T09:57:03.8288828+04:00","gmt_modified":"2026-04-28T09:57:03.8288828+04:00"},{"id":"15a3537ebe2816e5402e7fb60462b58e","path":"libraries/chain/database.cpp","line_range":"4317-4332","gmt_create":"2026-04-28T09:57:03.8293937+04:00","gmt_modified":"2026-04-28T09:57:03.8293937+04:00"},{"id":"6af53e8de30910078bc6fd9dab1d2f7b","path":"libraries/time/time.cpp","line_range":"74-76","gmt_create":"2026-04-28T09:57:03.8293937+04:00","gmt_modified":"2026-04-28T09:57:03.8293937+04:00"},{"id":"0ef7b0d7933da804905c2ff76f92cd94","path":"libraries/chain/database.cpp","line_range":"2824-2839","gmt_create":"2026-04-28T09:57:03.8293937+04:00","gmt_modified":"2026-04-28T09:57:03.8293937+04:00"},{"id":"667d252413c23e04beb2c069531a1372","path":"libraries/chain/database.cpp","line_range":"2871-2886","gmt_create":"2026-04-28T09:57:03.8293937+04:00","gmt_modified":"2026-04-28T09:57:03.8293937+04:00"},{"id":"62ea8f0eed608d8eb1dd0911e43f28c3","path":"libraries/chain/database.cpp","line_range":"1223-1267","gmt_create":"2026-04-28T09:57:03.8299086+04:00","gmt_modified":"2026-04-28T09:57:03.8299086+04:00"},{"id":"1b91062fbd3e8ce21a7ec705a5ef21ae","path":"plugins/witness/witness.cpp","line_range":"125-133","gmt_create":"2026-04-28T09:57:03.8304179+04:00","gmt_modified":"2026-04-28T09:57:03.8304179+04:00"},{"id":"c57b368c9aec32de084799a61fc21d81","path":"plugins/witness/witness.cpp","line_range":"149-155","gmt_create":"2026-04-28T09:57:03.8304179+04:00","gmt_modified":"2026-04-28T09:57:03.8304179+04:00"},{"id":"9a1726ad4c4d7942894eafbb2fb7c20a","path":"plugins/witness/witness.cpp","line_range":"222-224","gmt_create":"2026-04-28T09:57:03.8309331+04:00","gmt_modified":"2026-04-28T09:57:03.8309331+04:00"},{"id":"d572e2edecf45b7b050d30cbb14368d8","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"57-58","gmt_create":"2026-04-28T09:57:03.8309331+04:00","gmt_modified":"2026-04-28T09:57:03.8309331+04:00"},{"id":"a3b204b149312d56bea1667800a95fb6","path":"share/vizd/config/config.ini","line_range":"99-103","gmt_create":"2026-04-28T09:57:03.8314489+04:00","gmt_modified":"2026-04-28T09:57:03.8314489+04:00"},{"id":"f72faf82a21dd9049d68549d9c7e5c4f","path":"share/vizd/config/config_witness.ini","line_range":"76-80","gmt_create":"2026-04-28T09:57:03.8319591+04:00","gmt_modified":"2026-04-28T09:57:03.8319591+04:00"},{"id":"c5701be8b76f9a4a85b659f219a10f95","path":"plugins/witness/witness.cpp","line_range":"509-555","gmt_create":"2026-04-28T09:57:03.8329908+04:00","gmt_modified":"2026-04-28T09:57:03.8329908+04:00"},{"id":"7f2c3ab5ba63b977d9642aa1c78a2c43","path":"plugins/witness/witness.cpp","line_range":"120-169","gmt_create":"2026-04-28T09:57:03.8335072+04:00","gmt_modified":"2026-04-28T09:57:03.8335072+04:00"},{"id":"737d623fe091f7ae2629dcda699b0efa","path":"plugins/witness/witness.cpp","line_range":"171-192","gmt_create":"2026-04-28T09:57:03.8335072+04:00","gmt_modified":"2026-04-28T09:57:03.8335072+04:00"},{"id":"fba8be1bbb523071f8ce7ad55a13d0f2","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"31","gmt_create":"2026-04-28T09:57:03.8345403+04:00","gmt_modified":"2026-04-28T09:57:03.8345403+04:00"},{"id":"2a7a24b7119edca00eb0b21200f484ec","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"88","gmt_create":"2026-04-28T09:57:03.8345403+04:00","gmt_modified":"2026-04-28T09:57:03.8345403+04:00"},{"id":"c9048f7e0344e917d91b3b45d3804a0d","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"73","gmt_create":"2026-04-28T09:57:03.8345403+04:00","gmt_modified":"2026-04-28T09:57:03.8345403+04:00"},{"id":"ff4cacfd8a6a1ce746ce49bd2259ef47","path":"libraries/chain/fork_database.cpp","line_range":"151-166","gmt_create":"2026-04-28T09:57:03.8350501+04:00","gmt_modified":"2026-04-28T09:57:03.8350501+04:00"},{"id":"78279a6057ca0eaea7f987e920fada7f","path":"libraries/chain/database.cpp","line_range":"1456-1471","gmt_create":"2026-04-28T09:57:03.8350501+04:00","gmt_modified":"2026-04-28T09:57:03.8350501+04:00"},{"id":"95e9eb6df5c5b54fc25131e15cebca7b","path":"libraries/chain/fork_database.cpp","line_range":"269-274","gmt_create":"2026-04-28T09:57:03.8350501+04:00","gmt_modified":"2026-04-28T09:57:03.8350501+04:00"},{"id":"4c8c235c40a9885b9ce181cc9af786fe","path":"libraries/chain/database.cpp","line_range":"2807-2839","gmt_create":"2026-04-28T09:57:03.8361473+04:00","gmt_modified":"2026-04-28T09:57:03.8361473+04:00"},{"id":"29354043db86eeb48566453a908645c7","path":"libraries/chain/database.cpp","line_range":"2897-2914","gmt_create":"2026-04-28T09:57:03.8361473+04:00","gmt_modified":"2026-04-28T09:57:03.8361473+04:00"},{"id":"6e4547d3d8a2b1ce7fb2eb8442ba9631","path":"libraries/chain/database.cpp","line_range":"1294-1311","gmt_create":"2026-04-28T09:57:03.8366585+04:00","gmt_modified":"2026-04-28T09:57:03.8366585+04:00"},{"id":"0dec6783542ea54ba7d81fbeb930e442","path":"plugins/witness_api/plugin.cpp","line_range":"30-49","gmt_create":"2026-04-28T09:57:03.8366585+04:00","gmt_modified":"2026-04-28T09:57:03.8366585+04:00"},{"id":"85675dcfc30f216052bdb5cedc7b435c","path":"plugins/witness_api/plugin.cpp","line_range":"75-91","gmt_create":"2026-04-28T09:57:03.8366585+04:00","gmt_modified":"2026-04-28T09:57:03.8366585+04:00"},{"id":"7f42fa8b501a589d403cb682d1620581","path":"plugins/witness_api/plugin.cpp","line_range":"102-125","gmt_create":"2026-04-28T09:57:03.8371754+04:00","gmt_modified":"2026-04-28T09:57:03.8371754+04:00"},{"id":"17a2c941cfb814db6c1623046d8dac1e","path":"plugins/witness_api/plugin.cpp","line_range":"127-159","gmt_create":"2026-04-28T09:57:03.8371754+04:00","gmt_modified":"2026-04-28T09:57:03.8371754+04:00"},{"id":"53a82d703bff53e589353336964d2eed","path":"plugins/witness_api/plugin.cpp","line_range":"161-169","gmt_create":"2026-04-28T09:57:03.8371754+04:00","gmt_modified":"2026-04-28T09:57:03.8371754+04:00"},{"id":"4fcf4072cf8ebe5cd019e9a0da762901","path":"plugins/witness_api/plugin.cpp","line_range":"171-203","gmt_create":"2026-04-28T09:57:03.8371754+04:00","gmt_modified":"2026-04-28T09:57:03.8371754+04:00"},{"id":"c4f66fb8fb1d6eeb25bd48eec2ba80a6","path":"plugins/witness_api/plugin.cpp","line_range":"102-159","gmt_create":"2026-04-28T09:57:03.837694+04:00","gmt_modified":"2026-04-28T09:57:03.837694+04:00"},{"id":"68e0135d2e3b03eff760c57654b97092","path":"plugins/witness_api/plugin.cpp","line_range":"161-203","gmt_create":"2026-04-28T09:57:03.837694+04:00","gmt_modified":"2026-04-28T09:57:03.837694+04:00"},{"id":"eeebc7e5a0ce3570715e7391da03b065","path":"libraries/chain/include/graphene/chain/witness_objects.hpp","line_range":"104-171","gmt_create":"2026-04-28T09:57:03.8382054+04:00","gmt_modified":"2026-04-28T09:57:03.8382054+04:00"},{"id":"ef4797348572b382b96b9d19a362eed7","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"90-95","gmt_create":"2026-04-28T09:57:03.8382054+04:00","gmt_modified":"2026-04-28T09:57:03.8382054+04:00"},{"id":"85e55e5f6d83a36cd6afac5fcb62fb42","path":"libraries/chain/database.cpp","line_range":"1626-1805","gmt_create":"2026-04-28T09:57:03.8392306+04:00","gmt_modified":"2026-04-28T09:57:03.8392306+04:00"},{"id":"1d8a3a8529f55f725cbd52ef78db6a1f","path":"libraries/chain/database.cpp","line_range":"4334-4463","gmt_create":"2026-04-28T09:57:03.8392306+04:00","gmt_modified":"2026-04-28T09:57:03.8392306+04:00"},{"id":"87584d47dc52c8658341b565e96c989d","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"492-499","gmt_create":"2026-04-28T09:57:03.8392306+04:00","gmt_modified":"2026-04-28T09:57:03.8392306+04:00"},{"id":"cda7dad93173bc2161ab2ff3c92e81ce","path":"libraries/time/time.cpp","line_range":"36-39","gmt_create":"2026-04-28T09:57:03.8402638+04:00","gmt_modified":"2026-04-28T09:57:03.8402638+04:00"},{"id":"73dca3cd312efbc6ecb517ae118fd869","path":"thirdparty/fc/src/network/ntp.cpp","line_range":"184-201","gmt_create":"2026-04-28T09:57:03.8402638+04:00","gmt_modified":"2026-04-28T09:57:03.8402638+04:00"},{"id":"c69f6ef1a64e88829a12d7ab4c190897","path":"thirdparty/fc/src/network/ntp.cpp","line_range":"236-266","gmt_create":"2026-04-28T09:57:03.8402638+04:00","gmt_modified":"2026-04-28T09:57:03.8402638+04:00"},{"id":"26905e829dbbc0af740b97400068843b","path":"plugins/witness/witness.cpp","line_range":"255-271","gmt_create":"2026-04-28T09:57:03.8423223+04:00","gmt_modified":"2026-04-28T09:57:03.8423223+04:00"},{"id":"1eb7cc21b9daf17a2c908f3121bcf2f0","path":"plugins/witness/witness.cpp","line_range":"387-396","gmt_create":"2026-04-28T09:57:03.8423223+04:00","gmt_modified":"2026-04-28T09:57:03.8423223+04:00"},{"id":"cc4d2fca7cfbc2ed2aa9dc9016360fb5","path":"libraries/chain/database.cpp","line_range":"2826-2836","gmt_create":"2026-04-28T09:57:03.8433619+04:00","gmt_modified":"2026-04-28T09:57:03.8433619+04:00"},{"id":"e0e1ada694da4e9e256e0d6d39aa73e5","path":"libraries/chain/database.cpp","line_range":"2873-2883","gmt_create":"2026-04-28T09:57:03.8433619+04:00","gmt_modified":"2026-04-28T09:57:03.8433619+04:00"},{"id":"27593eff1e7989c53fb119e30b38a106","path":"libraries/chain/fork_database.cpp","line_range":"81-88","gmt_create":"2026-04-28T09:57:57.433751+04:00","gmt_modified":"2026-04-28T09:57:57.433751+04:00"},{"id":"188a46b66d800240516e280b06e7f041","path":"libraries/chain/include/graphene/chain/global_property_object.hpp","line_range":"24-146","gmt_create":"2026-04-28T09:57:57.4342664+04:00","gmt_modified":"2026-04-28T09:57:57.4342664+04:00"},{"id":"02a1a9fcc78ccfc4daf328d04696eb6f","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"114-124","gmt_create":"2026-04-28T09:57:57.4347869+04:00","gmt_modified":"2026-04-28T09:57:57.4347869+04:00"},{"id":"971acfd6fe75fe0b8a1522de5c46bf48","path":"libraries/chain/include/graphene/chain/witness_objects.hpp","line_range":"47-61","gmt_create":"2026-04-28T09:57:57.4347869+04:00","gmt_modified":"2026-04-28T09:57:57.4347869+04:00"},{"id":"ad1ea51f6c6764f6694b4b89a834e8f6","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"110-128","gmt_create":"2026-04-28T09:57:57.4347869+04:00","gmt_modified":"2026-04-28T09:57:57.4347869+04:00"},{"id":"3c48450ddf4126f562a2691715c15905","path":"libraries/chain/fork_database.cpp","line_range":"80-87","gmt_create":"2026-04-28T09:57:57.4373768+04:00","gmt_modified":"2026-04-28T09:57:57.4373768+04:00"},{"id":"e2e78ec9bb315562ae4436bac3d06fb5","path":"libraries/chain/database.cpp","line_range":"1556","gmt_create":"2026-04-28T09:57:57.4390702+04:00","gmt_modified":"2026-04-28T09:57:57.4390702+04:00"},{"id":"0fda0369897c65053dee851ef9ec01f9","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"37-612","gmt_create":"2026-04-28T09:57:57.4401671+04:00","gmt_modified":"2026-04-28T09:57:57.4401671+04:00"},{"id":"2ad3ade1c893ee16ff7640c396428e46","path":"thirdparty/chainbase/include/chainbase/chainbase.hpp","line_range":"1078-1120","gmt_create":"2026-04-28T10:02:32.5941108+04:00","gmt_modified":"2026-04-28T10:02:32.5941108+04:00"},{"id":"27490494b39fa9968667b183f60e215a","path":"thirdparty/chainbase/src/chainbase.cpp","line_range":"1-200","gmt_create":"2026-04-28T10:02:32.5941108+04:00","gmt_modified":"2026-04-28T10:02:32.5941108+04:00"},{"id":"2c17018b7a7ecf1dd7b6432e97d0a586","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"1-75","gmt_create":"2026-04-28T10:02:32.5941108+04:00","gmt_modified":"2026-04-28T10:02:32.5941108+04:00"},{"id":"fef8201a8783aa794440fbd2f9b1ff17","path":"libraries/chain/block_log.cpp","line_range":"1-302","gmt_create":"2026-04-28T10:02:32.5941108+04:00","gmt_modified":"2026-04-28T10:02:32.5941108+04:00"},{"id":"6ebf29a038d578e8864ca6c9c9366bda","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"1-76","gmt_create":"2026-04-28T10:02:32.5941108+04:00","gmt_modified":"2026-04-28T10:02:32.5941108+04:00"},{"id":"d3bee62a496fa43717911daed4f0bb13","path":"libraries/chain/fork_database.cpp","line_range":"1-271","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"ba99a3c0ac8bffedf50f03f7f8a09c06","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","line_range":"1-136","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"0397697ee2095dedcc01fa148c7079b9","path":"libraries/chain/include/graphene/chain/db_with.hpp","line_range":"1-154","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"b2901b8a7a24569b4a61c38b4448db06","path":"plugins/snapshot/plugin.cpp","line_range":"1180-1379","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"77520f9eb913c04b5230e07f8f3f4ef8","path":"plugins/witness/witness.cpp","line_range":"270-469","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"340636e744f71de65b91146c5b8a20bd","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"38-73","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"c05f511b950fdae3b96260134880f8e4","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"111-118","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"101205728a0401f1dc07b5e31abe4b30","path":"libraries/network/node.cpp","line_range":"3185-3384","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"832619f974a664566d9bae6712c5e6a1","path":"libraries/network/include/graphene/network/exceptions.hpp","line_range":"27-48","gmt_create":"2026-04-28T10:02:32.5950686+04:00","gmt_modified":"2026-04-28T10:02:32.5950686+04:00"},{"id":"8939bbbd6e1bb4a18e6bb534a037d0b8","path":"plugins/p2p/p2p_plugin.cpp","line_range":"225-424","gmt_create":"2026-04-28T10:02:32.5960631+04:00","gmt_modified":"2026-04-28T10:02:32.5960631+04:00"},{"id":"b437e864a36924899b70d6b9295e4ac0","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"61-115","gmt_create":"2026-04-28T10:02:32.5980608+04:00","gmt_modified":"2026-04-28T10:02:32.5980608+04:00"},{"id":"476cdc272b600cf1a7bfe2b524767872","path":"libraries/chain/database.cpp","line_range":"281-324","gmt_create":"2026-04-28T10:02:32.5980608+04:00","gmt_modified":"2026-04-28T10:02:32.5980608+04:00"},{"id":"5c73e14f98ff45ef03bb3a7c9e413218","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"38-75","gmt_create":"2026-04-28T10:02:32.5980608+04:00","gmt_modified":"2026-04-28T10:02:32.5980608+04:00"},{"id":"6742da18bac301be1056c8e6e5adcf69","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"35-72","gmt_create":"2026-04-28T10:02:32.5980608+04:00","gmt_modified":"2026-04-28T10:02:32.5980608+04:00"},{"id":"6d7b6e4198a348bc27c0bb28230cb3f9","path":"libraries/chain/database.cpp","line_range":"929-984","gmt_create":"2026-04-28T10:02:32.5980608+04:00","gmt_modified":"2026-04-28T10:02:32.5980608+04:00"},{"id":"186fa6ce927d55c0b153413a2981237e","path":"libraries/chain/include/graphene/chain/db_with.hpp","line_range":"33-100","gmt_create":"2026-04-28T10:02:32.5995674+04:00","gmt_modified":"2026-04-28T10:02:32.5995674+04:00"},{"id":"99a2db97d03705f31a3929010634a458","path":"thirdparty/chainbase/src/chainbase.cpp","line_range":"225-279","gmt_create":"2026-04-28T10:02:32.5995674+04:00","gmt_modified":"2026-04-28T10:02:32.5995674+04:00"},{"id":"30a9101c41868617ba6f2a2daa15b849","path":"libraries/chain/database.cpp","line_range":"94-184","gmt_create":"2026-04-28T10:02:32.6005802+04:00","gmt_modified":"2026-04-28T10:02:32.6005802+04:00"},{"id":"3e02993eaec7af3cec0bfb1f83a665d3","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","line_range":"83","gmt_create":"2026-04-28T10:02:32.6005802+04:00","gmt_modified":"2026-04-28T10:02:32.6005802+04:00"},{"id":"99f54a4b93eefbb48ed1667eff0fa9d3","path":"libraries/chain/database.cpp","line_range":"330-410","gmt_create":"2026-04-28T10:02:32.6015813+04:00","gmt_modified":"2026-04-28T10:02:32.6015813+04:00"},{"id":"408bde042901c8590a87dffdf56f7b44","path":"libraries/chain/database.cpp","line_range":"134-184","gmt_create":"2026-04-28T10:02:32.6015813+04:00","gmt_modified":"2026-04-28T10:02:32.6015813+04:00"},{"id":"e69115f35f4572b29fb65e977de046e0","path":"libraries/chain/database.cpp","line_range":"503-519","gmt_create":"2026-04-28T10:02:32.6015813+04:00","gmt_modified":"2026-04-28T10:02:32.6015813+04:00"},{"id":"1198bd7cc69669237a261463e8cd3c9d","path":"libraries/chain/database.cpp","line_range":"3986-4039","gmt_create":"2026-04-28T10:02:32.603573+04:00","gmt_modified":"2026-04-28T10:02:32.603573+04:00"},{"id":"a8eaae161939961c892a4e5ff9b1b68f","path":"libraries/chain/database.cpp","line_range":"4144-4175","gmt_create":"2026-04-28T10:02:32.603573+04:00","gmt_modified":"2026-04-28T10:02:32.603573+04:00"},{"id":"17b75751a836de13af2093485914a80b","path":"libraries/chain/database.cpp","line_range":"1147-1202","gmt_create":"2026-04-28T10:02:32.6055731+04:00","gmt_modified":"2026-04-28T10:02:32.6055731+04:00"},{"id":"3fd79dc7253b83f3fd4a1db36b691537","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"79-96","gmt_create":"2026-04-28T10:02:32.6055731+04:00","gmt_modified":"2026-04-28T10:02:32.6055731+04:00"},{"id":"fc817fa1448591c306f1d8c94a4912b0","path":"libraries/chain/database.cpp","line_range":"340-350","gmt_create":"2026-04-28T10:02:32.6055731+04:00","gmt_modified":"2026-04-28T10:02:32.6055731+04:00"},{"id":"2b22b083099e12af5fb5eff69ac7c45b","path":"libraries/chain/database.cpp","line_range":"4346-4366","gmt_create":"2026-04-28T10:02:32.6055731+04:00","gmt_modified":"2026-04-28T10:02:32.6055731+04:00"},{"id":"ad0c51e89fbda89a4c7ba4a8b1c23f6e","path":"libraries/chain/database.cpp","line_range":"948-970","gmt_create":"2026-04-28T10:02:32.6055731+04:00","gmt_modified":"2026-04-28T10:02:32.6055731+04:00"},{"id":"1bc38fc420c17ebaaf14eb62dd9dd77e","path":"libraries/chain/database.cpp","line_range":"3652-3711","gmt_create":"2026-04-28T10:02:32.6065844+04:00","gmt_modified":"2026-04-28T10:02:32.6065844+04:00"},{"id":"a0ef31a365b500c015295fa0a77cb02a","path":"libraries/chain/database.cpp","line_range":"639-673","gmt_create":"2026-04-28T10:02:32.6065844+04:00","gmt_modified":"2026-04-28T10:02:32.6065844+04:00"},{"id":"bad0cf5ac8c5e25ab7697c72386f0c6e","path":"libraries/chain/database.cpp","line_range":"562-605","gmt_create":"2026-04-28T10:02:32.6065844+04:00","gmt_modified":"2026-04-28T10:02:32.6065844+04:00"},{"id":"145b14d90766df6ec3acffdb3b52a1a7","path":"libraries/chain/database.cpp","line_range":"412-422","gmt_create":"2026-04-28T10:02:32.6075786+04:00","gmt_modified":"2026-04-28T10:02:32.6075786+04:00"},{"id":"5ae77d32160a48045d586a25c4949703","path":"libraries/chain/database.cpp","line_range":"454-482","gmt_create":"2026-04-28T10:02:32.6075786+04:00","gmt_modified":"2026-04-28T10:02:32.6075786+04:00"},{"id":"fb42540947b6b7d56487ccd9ec782f86","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"148-164","gmt_create":"2026-04-28T10:02:32.6075786+04:00","gmt_modified":"2026-04-28T10:02:32.6075786+04:00"},{"id":"4eb8ce2a423658c16ae4df90aeba2184","path":"libraries/chain/database.cpp","line_range":"546-556","gmt_create":"2026-04-28T10:02:32.6075786+04:00","gmt_modified":"2026-04-28T10:02:32.6075786+04:00"},{"id":"0172b0ea2a031177f1c72341a3922614","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"631-632","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"e8dd15ab10626a2ce715fe8c3f03ca85","path":"libraries/chain/database.cpp","line_range":"1106-1145","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"8509be38b1ab9f14d108445df0dcd2f1","path":"libraries/chain/database.cpp","line_range":"1460-1470","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"732bc579d5f86ebf0e986ecfbdfa490d","path":"libraries/chain/fork_database.cpp","line_range":"34-46","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"d1e1e1bc28ff1dfbd77617edbf4a23b0","path":"libraries/chain/database.cpp","line_range":"1295-1377","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"42f304cea32d3254d3d28d390f99a4f4","path":"libraries/chain/database.cpp","line_range":"1216-1286","gmt_create":"2026-04-28T10:02:32.6085719+04:00","gmt_modified":"2026-04-28T10:02:32.6085719+04:00"},{"id":"21021513e3f47136fbd9b77f25ac0dda","path":"plugins/p2p/p2p_plugin.cpp","line_range":"175-192","gmt_create":"2026-04-28T10:02:32.6100752+04:00","gmt_modified":"2026-04-28T10:02:32.6100752+04:00"},{"id":"978bc8c4cf93eea58a5004412f5a0740","path":"libraries/network/node.cpp","line_range":"3192-3211","gmt_create":"2026-04-28T10:02:32.6100752+04:00","gmt_modified":"2026-04-28T10:02:32.6100752+04:00"},{"id":"9a7186666130ca998f114a82a0decdff","path":"plugins/p2p/p2p_plugin.cpp","line_range":"181-196","gmt_create":"2026-04-28T10:02:32.6100752+04:00","gmt_modified":"2026-04-28T10:02:32.6100752+04:00"},{"id":"ac1d251c502e1e4341518133a47346b6","path":"libraries/chain/database.cpp","line_range":"1556-1588","gmt_create":"2026-04-28T10:02:32.6110794+04:00","gmt_modified":"2026-04-28T10:02:32.6110794+04:00"},{"id":"03c29e794349e78edd559069a4ea589f","path":"libraries/chain/database.cpp","line_range":"1593-1594","gmt_create":"2026-04-28T10:02:32.6110794+04:00","gmt_modified":"2026-04-28T10:02:32.6110794+04:00"},{"id":"bc5ca04bd394cfbe05b91187be1ef3e1","path":"plugins/witness/witness.cpp","line_range":"271-300","gmt_create":"2026-04-28T10:02:32.6110794+04:00","gmt_modified":"2026-04-28T10:02:32.6110794+04:00"},{"id":"32c3cd87cb292dbfecb6d81dc0fc6739","path":"plugins/witness/witness.cpp","line_range":"506-507","gmt_create":"2026-04-28T10:02:32.6110794+04:00","gmt_modified":"2026-04-28T10:02:32.6110794+04:00"},{"id":"ba68b0a6c770e5eb7e9c206147e04add","path":"plugins/p2p/p2p_plugin.cpp","line_range":"232-243","gmt_create":"2026-04-28T10:02:32.6110794+04:00","gmt_modified":"2026-04-28T10:02:32.6110794+04:00"},{"id":"bf868153550f3b995f99ef4e396ddd77","path":"libraries/chain/database.cpp","line_range":"3444-3499","gmt_create":"2026-04-28T10:02:32.6130814+04:00","gmt_modified":"2026-04-28T10:02:32.6130814+04:00"},{"id":"e5c1c7808f2985bb68bc174eb390298a","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"218-224","gmt_create":"2026-04-28T10:02:32.6130814+04:00","gmt_modified":"2026-04-28T10:02:32.6130814+04:00"},{"id":"e6c849182922d3df412daeb900b9e173","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"284-307","gmt_create":"2026-04-28T10:02:32.6150792+04:00","gmt_modified":"2026-04-28T10:02:32.6150792+04:00"},{"id":"05db694a94704c3e51ed70ce0118a1da","path":"libraries/chain/database.cpp","line_range":"1158-1198","gmt_create":"2026-04-28T10:02:32.6150792+04:00","gmt_modified":"2026-04-28T10:02:32.6150792+04:00"},{"id":"e6a9a48c0e930773f0a82fa246c53f98","path":"libraries/chain/database.cpp","line_range":"3652-3655","gmt_create":"2026-04-28T10:02:32.6150792+04:00","gmt_modified":"2026-04-28T10:02:32.6150792+04:00"},{"id":"bd530cb9e845767f0a9b3ff967997984","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"93-141","gmt_create":"2026-04-28T10:02:32.6150792+04:00","gmt_modified":"2026-04-28T10:02:32.6150792+04:00"},{"id":"f10623a85ff8726287ec33204df6d61a","path":"libraries/chain/database.cpp","line_range":"458-584","gmt_create":"2026-04-28T10:02:32.6150792+04:00","gmt_modified":"2026-04-28T10:02:32.6150792+04:00"},{"id":"8f391118507fdd830a986c86e989a317","path":"libraries/chain/database.cpp","line_range":"2047-2144","gmt_create":"2026-04-28T10:02:32.6160791+04:00","gmt_modified":"2026-04-28T10:02:32.6160791+04:00"},{"id":"fa62adcb3d13201bfc9729dde67be04f","path":"libraries/chain/database.cpp","line_range":"4378-4416","gmt_create":"2026-04-28T10:02:32.6160791+04:00","gmt_modified":"2026-04-28T10:02:32.6160791+04:00"},{"id":"98ed598d82d28fa1553560148bcda24e","path":"libraries/chain/database.cpp","line_range":"2125-2142","gmt_create":"2026-04-28T10:02:32.6160791+04:00","gmt_modified":"2026-04-28T10:02:32.6160791+04:00"},{"id":"5a5c235262f9722ff7bdf0586bfd8e26","path":"libraries/chain/database.cpp","line_range":"4220-4230","gmt_create":"2026-04-28T10:02:32.6297326+04:00","gmt_modified":"2026-04-28T10:02:32.6297326+04:00"},{"id":"39b6820362e87b0f937201fb8f54dee6","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"1-10","gmt_create":"2026-04-28T10:02:32.6313259+04:00","gmt_modified":"2026-04-28T10:02:32.6313259+04:00"},{"id":"1efc9fdbd77068cf27cb00354deff17a","path":"libraries/chain/database.cpp","line_range":"1-30","gmt_create":"2026-04-28T10:02:32.631839+04:00","gmt_modified":"2026-04-28T10:02:32.631839+04:00"},{"id":"d0e2616c3e70f0e809256dcb448916ab","path":"libraries/chain/database.cpp","line_range":"270-279","gmt_create":"2026-04-28T10:02:32.6329165+04:00","gmt_modified":"2026-04-28T10:02:32.6329165+04:00"},{"id":"0855c233a79de418e4577d44bd54b9ba","path":"libraries/chain/database.cpp","line_range":"492-501","gmt_create":"2026-04-28T10:02:32.6329165+04:00","gmt_modified":"2026-04-28T10:02:32.6329165+04:00"},{"id":"f2c0625ed2d13bb0a3699a45bf25d6cc","path":"plugins/snapshot/plugin.cpp","line_range":"1-50","gmt_create":"2026-04-28T12:27:40.7724634+04:00","gmt_modified":"2026-04-28T12:27:40.7724634+04:00"},{"id":"b49193d53f2bca5e5a84c905c1f90429","path":"plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","line_range":"1-88","gmt_create":"2026-04-28T12:27:40.7724634+04:00","gmt_modified":"2026-04-28T12:27:40.7724634+04:00"},{"id":"ca74187bf1151ee3b389754df4ce08d1","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp","line_range":"1-52","gmt_create":"2026-04-28T12:27:40.7724634+04:00","gmt_modified":"2026-04-28T12:27:40.7724634+04:00"},{"id":"60ec378a66a7653324d69f456e1242c4","path":"plugins/snapshot/CMakeLists.txt","line_range":"1-52","gmt_create":"2026-04-28T12:27:40.7730421+04:00","gmt_modified":"2026-04-28T12:27:40.7730421+04:00"},{"id":"93f965590673de9c5fe2a34fbc24af1c","path":"plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","line_range":"42-76","gmt_create":"2026-04-28T12:27:40.7730421+04:00","gmt_modified":"2026-04-28T12:27:40.7730421+04:00"},{"id":"98907d07c594fe14c157ba203649b596","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp","line_range":"16-52","gmt_create":"2026-04-28T12:27:40.7735457+04:00","gmt_modified":"2026-04-28T12:27:40.7735457+04:00"},{"id":"aba83bcb80fe7ecb8f1f224f2fca05da","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp","line_range":"30-158","gmt_create":"2026-04-28T12:27:40.7735457+04:00","gmt_modified":"2026-04-28T12:27:40.7735457+04:00"},{"id":"33fc7efcd171685ef3235423dc636724","path":"plugins/snapshot/plugin.cpp","line_range":"675-780","gmt_create":"2026-04-28T12:27:40.7735457+04:00","gmt_modified":"2026-04-28T12:27:40.7735457+04:00"},{"id":"0a6e409382fdf7cc6924a9f918b5a4d8","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp","line_range":"37-107","gmt_create":"2026-04-28T12:27:40.7735457+04:00","gmt_modified":"2026-04-28T12:27:40.7735457+04:00"},{"id":"d419300bbe8000129fd9765417390c9d","path":"plugins/snapshot/plugin.cpp","line_range":"885-987","gmt_create":"2026-04-28T12:27:40.7740619+04:00","gmt_modified":"2026-04-28T12:27:40.7740619+04:00"},{"id":"c331a645eb7848bda9b3f651866478ec","path":"plugins/snapshot/plugin.cpp","line_range":"789-883","gmt_create":"2026-04-28T12:27:40.7740619+04:00","gmt_modified":"2026-04-28T12:27:40.7740619+04:00"},{"id":"06ca849a27b79d1edd6a6faaabf7a1fa","path":"plugins/snapshot/plugin.cpp","line_range":"1400-1484","gmt_create":"2026-04-28T12:27:40.7740619+04:00","gmt_modified":"2026-04-28T12:27:40.7740619+04:00"},{"id":"9102ca0b920a6d527e069776bf786565","path":"plugins/snapshot/plugin.cpp","line_range":"1046-1288","gmt_create":"2026-04-28T12:27:40.7745804+04:00","gmt_modified":"2026-04-28T12:27:40.7745804+04:00"},{"id":"272ad74758e94f746c862c4c91c17496","path":"plugins/snapshot/plugin.cpp","line_range":"1902-2038","gmt_create":"2026-04-28T12:27:40.7746421+04:00","gmt_modified":"2026-04-28T12:27:40.7746421+04:00"},{"id":"ea6973621046033cdcd6899b7a2bcb0f","path":"plugins/snapshot/plugin.cpp","line_range":"1470-1599","gmt_create":"2026-04-28T12:27:40.7746421+04:00","gmt_modified":"2026-04-28T12:27:40.7746421+04:00"},{"id":"2f7386ded19c5e4ae6581ef6148fdd81","path":"plugins/snapshot/plugin.cpp","line_range":"2473-2510","gmt_create":"2026-04-28T12:27:40.7746421+04:00","gmt_modified":"2026-04-28T12:27:40.7746421+04:00"},{"id":"5fcc5bdcf25fd73b110eede565277186","path":"documentation/snapshot-plugin.md","line_range":"247-273","gmt_create":"2026-04-28T12:27:40.7746421+04:00","gmt_modified":"2026-04-28T12:27:40.7746421+04:00"},{"id":"7c62e5936f0fc7f60f9a5587800a2578","path":"plugins/snapshot/plugin.cpp","line_range":"1418-1436","gmt_create":"2026-04-28T12:27:40.7752108+04:00","gmt_modified":"2026-04-28T12:27:40.7752108+04:00"},{"id":"983d0185105181e4f539d636abc549c9","path":"plugins/snapshot/plugin.cpp","line_range":"737-743","gmt_create":"2026-04-28T12:27:40.7757149+04:00","gmt_modified":"2026-04-28T12:27:40.7757149+04:00"},{"id":"82acc28cade2d06dac2a207816ccf888","path":"plugins/snapshot/plugin.cpp","line_range":"1390-1484","gmt_create":"2026-04-28T12:27:40.7757149+04:00","gmt_modified":"2026-04-28T12:27:40.7757149+04:00"},{"id":"1d3d2cb1a9886c18b5c14d6f4bbbec7c","path":"plugins/snapshot/plugin.cpp","line_range":"1440-1449","gmt_create":"2026-04-28T12:27:40.7757149+04:00","gmt_modified":"2026-04-28T12:27:40.7757149+04:00"},{"id":"de42aaaef014331a40dc6a645093a785","path":"plugins/witness/witness.cpp","line_range":"335-551","gmt_create":"2026-04-28T12:27:40.7757149+04:00","gmt_modified":"2026-04-28T12:27:40.7757149+04:00"},{"id":"e9427d96ecb45f8e18859dbaff6e2b3a","path":"plugins/snapshot/plugin.cpp","line_range":"1326-1376","gmt_create":"2026-04-28T12:27:40.7757149+04:00","gmt_modified":"2026-04-28T12:27:40.7757149+04:00"},{"id":"ddc5b6727e7907a53519cc63983aabb7","path":"plugins/snapshot/plugin.cpp","line_range":"1426-1435","gmt_create":"2026-04-28T12:27:40.7762434+04:00","gmt_modified":"2026-04-28T12:27:40.7762434+04:00"},{"id":"a54238157d7db2d12e89ea767738f5ea","path":"plugins/snapshot/plugin.cpp","line_range":"745-750","gmt_create":"2026-04-28T12:27:40.776339+04:00","gmt_modified":"2026-04-28T12:27:40.776339+04:00"},{"id":"8481665c6e787cad6255e9ace82fe2c2","path":"plugins/snapshot/plugin.cpp","line_range":"697-700","gmt_create":"2026-04-28T12:27:40.776339+04:00","gmt_modified":"2026-04-28T12:27:40.776339+04:00"},{"id":"91b6373025370a39784ff61586453267","path":"plugins/snapshot/plugin.cpp","line_range":"2831-2845","gmt_create":"2026-04-28T12:27:40.776339+04:00","gmt_modified":"2026-04-28T12:27:40.776339+04:00"},{"id":"fa6088c57e5552b03a53d22a8b3371cd","path":"plugins/snapshot/plugin.cpp","line_range":"1719-1748","gmt_create":"2026-04-28T12:27:40.776339+04:00","gmt_modified":"2026-04-28T12:27:40.776339+04:00"},{"id":"2ef1c85090d0812eda040eb10dbfab00","path":"plugins/snapshot/plugin.cpp","line_range":"1706-1748","gmt_create":"2026-04-28T12:27:40.776339+04:00","gmt_modified":"2026-04-28T12:27:40.776339+04:00"},{"id":"6c4fffc1a4b8a3dccdccf3bc8b6e478c","path":"plugins/chain/plugin.cpp","line_range":"490-560","gmt_create":"2026-04-28T12:27:40.7768431+04:00","gmt_modified":"2026-04-28T12:27:40.7768431+04:00"},{"id":"002084afc1181b400d0ac1f626010b50","path":"plugins/snapshot/plugin.cpp","line_range":"2945-2959","gmt_create":"2026-04-28T12:27:40.7769365+04:00","gmt_modified":"2026-04-28T12:27:40.7769365+04:00"},{"id":"a9ac85c210bf25017dc2f3043429bcff","path":"libraries/chain/database.cpp","line_range":"441-5201","gmt_create":"2026-04-28T12:27:40.7769365+04:00","gmt_modified":"2026-04-28T12:27:40.7769365+04:00"},{"id":"4083d0aedccff773e235c49f483acdee","path":"plugins/chain/plugin.cpp","line_range":"542-559","gmt_create":"2026-04-28T12:27:40.7769365+04:00","gmt_modified":"2026-04-28T12:27:40.7769365+04:00"},{"id":"5b61f5ff88b75190fc4b2051750444dd","path":"plugins/snapshot/plugin.cpp","line_range":"2976-3009","gmt_create":"2026-04-28T12:27:40.7774392+04:00","gmt_modified":"2026-04-28T12:27:40.7774392+04:00"},{"id":"133becde6f5eef3f56c38aa3650af39f","path":"plugins/snapshot/plugin.cpp","line_range":"2468-2570","gmt_create":"2026-04-28T12:27:40.7774392+04:00","gmt_modified":"2026-04-28T12:27:40.7774392+04:00"},{"id":"7c3bbfa78db4dbdd170795e4ff786767","path":"plugins/p2p/p2p_plugin.cpp","line_range":"689-697","gmt_create":"2026-04-28T12:27:40.7774392+04:00","gmt_modified":"2026-04-28T12:27:40.7774392+04:00"},{"id":"de95ec3c9606ef77f32c319a1cee9d67","path":"libraries/network/node.cpp","line_range":"5241-5274","gmt_create":"2026-04-28T12:27:40.7774392+04:00","gmt_modified":"2026-04-28T12:27:40.7774392+04:00"},{"id":"4ad076dd99ea06a22ba2703dfdfbef50","path":"libraries/network/include/graphene/network/node.hpp","line_range":"284-290","gmt_create":"2026-04-28T12:27:40.7774392+04:00","gmt_modified":"2026-04-28T12:27:40.7774392+04:00"},{"id":"d21d0e6c03944b9bd0683917197d45ec","path":"plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","line_range":"86-88","gmt_create":"2026-04-28T12:27:40.7779679+04:00","gmt_modified":"2026-04-28T12:27:40.7779679+04:00"},{"id":"ce8c1f15287ef92650480373eef95fb8","path":"plugins/snapshot/plugin.cpp","line_range":"735-740","gmt_create":"2026-04-28T12:27:40.7779679+04:00","gmt_modified":"2026-04-28T12:27:40.7779679+04:00"},{"id":"474f1f81f21526cb90fc2564fdc36457","path":"plugins/snapshot/plugin.cpp","line_range":"1814-1862","gmt_create":"2026-04-28T12:27:40.7779679+04:00","gmt_modified":"2026-04-28T12:27:40.7779679+04:00"},{"id":"3fcde09e22fa6291183075924ea0ea2a","path":"plugins/snapshot/plugin.cpp","line_range":"772-785","gmt_create":"2026-04-28T12:27:40.7779679+04:00","gmt_modified":"2026-04-28T12:27:40.7779679+04:00"},{"id":"25271321cea3b037da1bd49f4a9c73e3","path":"documentation/snapshot-plugin.md","line_range":"339-374","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"ffac59891823846e038c48de0f7fa754","path":"plugins/p2p/p2p_plugin.cpp","line_range":"585-649","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"ce8fa82841cb9ff1bb572dde21cd2dca","path":"plugins/p2p/p2p_plugin.cpp","line_range":"673-677","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"31a0e1cdb8f61a661ea048c18a0c31ab","path":"plugins/p2p/p2p_plugin.cpp","line_range":"744-755","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"e360b37afb60df02b8a51d89f141bf95","path":"plugins/snapshot/plugin.cpp","line_range":"165-176","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"a4b87380168ea56eda2691254c138879","path":"plugins/snapshot/plugin.cpp","line_range":"1587-1596","gmt_create":"2026-04-28T12:27:40.7784837+04:00","gmt_modified":"2026-04-28T12:27:40.7784837+04:00"},{"id":"0442d9dfa5137479a458da6803ce6d7d","path":"plugins/snapshot/plugin.cpp","line_range":"1610-1620","gmt_create":"2026-04-28T12:27:40.7790074+04:00","gmt_modified":"2026-04-28T12:27:40.7790074+04:00"},{"id":"5f1666b71febd2ce3545e7b9c05598fa","path":"plugins/snapshot/plugin.cpp","line_range":"1812-1877","gmt_create":"2026-04-28T12:27:40.7790074+04:00","gmt_modified":"2026-04-28T12:27:40.7790074+04:00"},{"id":"f7cc310f8ee11ed3c2ac13ce575146d4","path":"plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","line_range":"24-34","gmt_create":"2026-04-28T12:27:40.7790074+04:00","gmt_modified":"2026-04-28T12:27:40.7790074+04:00"},{"id":"24d1f458412bbfade9d25c0ed1521322","path":"plugins/snapshot/plugin.cpp","line_range":"2598-2680","gmt_create":"2026-04-28T12:27:40.7795307+04:00","gmt_modified":"2026-04-28T12:27:40.7795307+04:00"},{"id":"985521912575155bfda8b7bce74494df","path":"plugins/chain/plugin.cpp","line_range":"364-432","gmt_create":"2026-04-28T12:27:40.7795307+04:00","gmt_modified":"2026-04-28T12:27:40.7795307+04:00"},{"id":"299aedc88851dabd155fc2edbbad96ef","path":"plugins/snapshot/CMakeLists.txt","line_range":"27-38","gmt_create":"2026-04-28T12:27:40.7795307+04:00","gmt_modified":"2026-04-28T12:27:40.7795307+04:00"},{"id":"2a76e2c48df7946c93b84c330a1c08ae","path":"plugins/snapshot/plugin.cpp","line_range":"2294-2464","gmt_create":"2026-04-28T12:27:40.7795307+04:00","gmt_modified":"2026-04-28T12:27:40.7795307+04:00"},{"id":"d7fc3783ff3c58fa7beaff10948417fa","path":"plugins/snapshot/plugin.cpp","line_range":"1378-1464","gmt_create":"2026-04-28T12:27:40.7800446+04:00","gmt_modified":"2026-04-28T12:27:40.7800446+04:00"},{"id":"0acaf479cbd8b11ed2774cc96aa68335","path":"libraries/protocol/include/graphene/protocol/block_header.hpp","line_range":"1-43","gmt_create":"2026-04-28T12:54:08.069392+04:00","gmt_modified":"2026-04-28T12:54:08.069392+04:00"},{"id":"65b16a5b2283f9a71e063b5381577bae","path":"libraries/protocol/include/graphene/protocol/block.hpp","line_range":"1-19","gmt_create":"2026-04-28T12:54:08.0699133+04:00","gmt_modified":"2026-04-28T12:54:08.0699133+04:00"},{"id":"54d3aec8b80d5706beb75720a6232861","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"1-561","gmt_create":"2026-04-28T12:54:08.0699133+04:00","gmt_modified":"2026-04-28T12:54:08.0699133+04:00"},{"id":"0b148db227f6081cc819c2f686550d84","path":"libraries/chain/database.cpp","line_range":"737-913","gmt_create":"2026-04-28T12:54:08.0699133+04:00","gmt_modified":"2026-04-28T12:54:08.0699133+04:00"},{"id":"3409eb023f550b5d11bccc50d317764a","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"1-125","gmt_create":"2026-04-28T12:54:08.0699133+04:00","gmt_modified":"2026-04-28T12:54:08.0699133+04:00"},{"id":"e29d6a6310d6247eaf38fa2c35b35373","path":"libraries/chain/fork_database.cpp","line_range":"33-90","gmt_create":"2026-04-28T12:54:08.0699133+04:00","gmt_modified":"2026-04-28T12:54:08.0699133+04:00"},{"id":"faea01a77c78aa0e75d22b0d5cafa704","path":"libraries/chain/block_log.cpp","line_range":"238-300","gmt_create":"2026-04-28T12:54:08.070423+04:00","gmt_modified":"2026-04-28T12:54:08.070423+04:00"},{"id":"60cef3a5a468a40533451ed7d7e09503","path":"libraries/chain/dlt_block_log.cpp","line_range":"162-242","gmt_create":"2026-04-28T12:54:08.070423+04:00","gmt_modified":"2026-04-28T12:54:08.070423+04:00"},{"id":"10f717e60b716201555827209e101cba","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"1-70","gmt_create":"2026-04-28T12:54:08.0709497+04:00","gmt_modified":"2026-04-28T12:54:08.0709497+04:00"},{"id":"04c7b01cbc51b1f23ab4704279190eda","path":"plugins/witness/witness.cpp","line_range":"295-341","gmt_create":"2026-04-28T12:54:08.0709497+04:00","gmt_modified":"2026-04-28T12:54:08.0709497+04:00"},{"id":"11090a858982a9991f12a111ff65ebec","path":"libraries/protocol/include/graphene/protocol/block.hpp","line_range":"9-13","gmt_create":"2026-04-28T12:54:08.0719836+04:00","gmt_modified":"2026-04-28T12:54:08.0719836+04:00"},{"id":"91b8b7279712d5789fb67e0c06442732","path":"libraries/protocol/include/graphene/protocol/block_header.hpp","line_range":"25-35","gmt_create":"2026-04-28T12:54:08.0719836+04:00","gmt_modified":"2026-04-28T12:54:08.0719836+04:00"},{"id":"5800e8f7ef6353fa3f37c39ea75ff454","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"53-96","gmt_create":"2026-04-28T12:54:08.0719836+04:00","gmt_modified":"2026-04-28T12:54:08.0719836+04:00"},{"id":"6da448acd4e86b4234427febab48fbca","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"38-68","gmt_create":"2026-04-28T12:54:08.0719836+04:00","gmt_modified":"2026-04-28T12:54:08.0719836+04:00"},{"id":"35d8d0314587b8714a154437fe7243af","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"13-33","gmt_create":"2026-04-28T12:54:08.0725034+04:00","gmt_modified":"2026-04-28T12:54:08.0725034+04:00"},{"id":"827fa8459b891ae8c31d3194640245da","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"36-287","gmt_create":"2026-04-28T12:54:08.0725034+04:00","gmt_modified":"2026-04-28T12:54:08.0725034+04:00"},{"id":"7d0d371be208eb98ecc21b182f56ab1b","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"20-32","gmt_create":"2026-04-28T12:54:08.0725034+04:00","gmt_modified":"2026-04-28T12:54:08.0725034+04:00"},{"id":"0b84b82025c87f3b725ddf0c3804f197","path":"libraries/chain/block_log.cpp","line_range":"253-257","gmt_create":"2026-04-28T12:54:08.0730148+04:00","gmt_modified":"2026-04-28T12:54:08.0730148+04:00"},{"id":"01b277ebba52e972b94566a19ab057fd","path":"libraries/chain/dlt_block_log.cpp","line_range":"336-340","gmt_create":"2026-04-28T12:54:08.0730148+04:00","gmt_modified":"2026-04-28T12:54:08.0730148+04:00"},{"id":"161ddc3f0d369da41719390d93b735c9","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"194-206","gmt_create":"2026-04-28T12:54:08.0735948+04:00","gmt_modified":"2026-04-28T12:54:08.0735948+04:00"},{"id":"d4957d3a60b33265b5b19edffd627403","path":"libraries/chain/database.cpp","line_range":"737-757","gmt_create":"2026-04-28T12:54:08.0735948+04:00","gmt_modified":"2026-04-28T12:54:08.0735948+04:00"},{"id":"9025ea64db0b2dfc92ca8bab0394cc08","path":"libraries/chain/database.cpp","line_range":"3443-3509","gmt_create":"2026-04-28T12:54:08.0735948+04:00","gmt_modified":"2026-04-28T12:54:08.0735948+04:00"},{"id":"fa4bc24d813810d4fe658d78919900b7","path":"libraries/chain/database.cpp","line_range":"812-825","gmt_create":"2026-04-28T12:54:08.0735948+04:00","gmt_modified":"2026-04-28T12:54:08.0735948+04:00"},{"id":"423e0e34f575bf3a7563c57bb997739b","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"56-73","gmt_create":"2026-04-28T12:54:08.0735948+04:00","gmt_modified":"2026-04-28T12:54:08.0735948+04:00"},{"id":"c7518bf7e6927e1b54afebcbb8cf3d5a","path":"libraries/chain/fork_database.cpp","line_range":"168-210","gmt_create":"2026-04-28T12:54:08.0751505+04:00","gmt_modified":"2026-04-28T12:54:08.0751505+04:00"},{"id":"f8faa71211c346e22bdea2dbbd1cc994","path":"libraries/chain/block_log.cpp","line_range":"134-193","gmt_create":"2026-04-28T12:54:08.0751505+04:00","gmt_modified":"2026-04-28T12:54:08.0751505+04:00"},{"id":"fd6ccb853bf752497d776a99eba9c7e2","path":"libraries/chain/block_log.cpp","line_range":"115-132","gmt_create":"2026-04-28T12:54:08.0751505+04:00","gmt_modified":"2026-04-28T12:54:08.0751505+04:00"},{"id":"6d71835687e91bd31fc0bba06adc43a1","path":"libraries/chain/block_log.cpp","line_range":"195-219","gmt_create":"2026-04-28T12:54:08.0751505+04:00","gmt_modified":"2026-04-28T12:54:08.0751505+04:00"},{"id":"21313db2130a5ad3661163e46e6eb28d","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"13-36","gmt_create":"2026-04-28T12:54:08.0756778+04:00","gmt_modified":"2026-04-28T12:54:08.0756778+04:00"},{"id":"1cd86ca915ed082dac6b3930d1822c8d","path":"libraries/chain/database.cpp","line_range":"846-913","gmt_create":"2026-04-28T12:54:08.0761996+04:00","gmt_modified":"2026-04-28T12:54:08.0761996+04:00"},{"id":"180a1810a21b0ec9cfa9bf2239b68849","path":"libraries/chain/fork_database.cpp","line_range":"47-71","gmt_create":"2026-04-28T12:54:08.0767246+04:00","gmt_modified":"2026-04-28T12:54:08.0767246+04:00"},{"id":"3e995e6e2441ab172c06a81ab175d467","path":"libraries/chain/fork_database.cpp","line_range":"79-90","gmt_create":"2026-04-28T12:54:08.0767246+04:00","gmt_modified":"2026-04-28T12:54:08.0767246+04:00"},{"id":"742afd64fbe28a0b4b264ad2c80c3f13","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","line_range":"34-65","gmt_create":"2026-04-28T12:54:08.0767246+04:00","gmt_modified":"2026-04-28T12:54:08.0767246+04:00"},{"id":"8982624b20d4012f524d7608d0e898df","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"214-226","gmt_create":"2026-04-28T12:54:08.0772386+04:00","gmt_modified":"2026-04-28T12:54:08.0772386+04:00"},{"id":"ed8569143dcfa15ac6f3519b0aa6b31b","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"423-428","gmt_create":"2026-04-28T12:54:08.0777619+04:00","gmt_modified":"2026-04-28T12:54:08.0777619+04:00"},{"id":"dea1056d264deb0399cea4b15ce31eff","path":"libraries/chain/fork_database.cpp","line_range":"38-44","gmt_create":"2026-04-28T12:54:08.0798427+04:00","gmt_modified":"2026-04-28T12:54:08.0798427+04:00"},{"id":"9050957c1241bdff17fa2cda2294cc02","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","line_range":"83-83","gmt_create":"2026-04-28T12:54:08.0798427+04:00","gmt_modified":"2026-04-28T12:54:08.0798427+04:00"},{"id":"69496892894b525caf293d463cec60ac","path":"libraries/chain/block_log.cpp","line_range":"163-193","gmt_create":"2026-04-28T12:54:08.0798427+04:00","gmt_modified":"2026-04-28T12:54:08.0798427+04:00"},{"id":"7a0064bf94d855137c23263ebefc4086","path":"plugins/witness/witness.cpp","line_range":"305-307","gmt_create":"2026-04-28T12:54:08.0798427+04:00","gmt_modified":"2026-04-28T12:54:08.0798427+04:00"},{"id":"4f05f855970de061eacdd41742b1c8f6","path":"libraries/chain/database.cpp","line_range":"5395-5419","gmt_create":"2026-04-28T12:54:08.0803549+04:00","gmt_modified":"2026-04-28T12:54:08.0803549+04:00"},{"id":"620825701e1a1b114e822bbda1ceb234","path":"libraries/chain/dlt_block_log.cpp","line_range":"1-454","gmt_create":"2026-04-28T12:55:56.0777355+04:00","gmt_modified":"2026-04-28T12:55:56.0777355+04:00"},{"id":"233a2d8be5340ec151c42900fcd58a96","path":"libraries/chain/database.cpp","line_range":"220-271","gmt_create":"2026-04-28T12:55:56.0782548+04:00","gmt_modified":"2026-04-28T12:55:56.0782548+04:00"},{"id":"02b88f06fab1f8f2b384ec38dfea95a8","path":"libraries/chain/fork_database.cpp","line_range":"1-258","gmt_create":"2026-04-28T12:55:56.0787776+04:00","gmt_modified":"2026-04-28T12:55:56.0787776+04:00"},{"id":"c6c440b24137364c19bc7fe7a800ce3e","path":"plugins/chain/plugin.cpp","line_range":"320-330","gmt_create":"2026-04-28T12:55:56.0787776+04:00","gmt_modified":"2026-04-28T12:55:56.0787776+04:00"},{"id":"7c7114ff694eca47458deb9031af3874","path":"plugins/snapshot/plugin.cpp","line_range":"1960-2039","gmt_create":"2026-04-28T12:55:56.0792994+04:00","gmt_modified":"2026-04-28T12:55:56.0792994+04:00"},{"id":"5c9a153931730742e72d3183f4f76128","path":"plugins/p2p/p2p_plugin.cpp","line_range":"255-286","gmt_create":"2026-04-28T12:55:56.0792994+04:00","gmt_modified":"2026-04-28T12:55:56.0792994+04:00"},{"id":"77740b8f659f6e4296624292e035f0b6","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"515-516","gmt_create":"2026-04-28T12:55:56.0792994+04:00","gmt_modified":"2026-04-28T12:55:56.0792994+04:00"},{"id":"44c647e6bdaeba8176c9fd58d7bf204f","path":"libraries/chain/dlt_block_log.cpp","line_range":"18-278","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"1fec0c281b15b8cb253758a81bda9d53","path":"libraries/chain/database.cpp","line_range":"230-231","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"20be4db8cc88d28b2576cc8c6640d89d","path":"libraries/chain/fork_database.cpp","line_range":"24-28","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"4aaf8248e16bc831caf0d6215227a347","path":"plugins/chain/plugin.cpp","line_range":"327-329","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"2496b05edb9e2cce32ff03d614866f80","path":"plugins/snapshot/plugin.cpp","line_range":"1968-1970","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"bd936d7f114a4d7505d38477591a432b","path":"plugins/p2p/p2p_plugin.cpp","line_range":"265-272","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"09e49fa0e3657a309d205da532bae0d4","path":"plugins/snapshot/plugin.cpp","line_range":"1414-1500","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"89fd5aa6e93582e3684130e9c0920e33","path":"libraries/chain/database.cpp","line_range":"438-544","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"1e55d2aee2f6d3f5d6247eb14ca9350a","path":"libraries/chain/database.cpp","line_range":"230-268","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"05c7b54032266aa804fecdd672849759","path":"libraries/chain/database.cpp","line_range":"560-627","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"d00cc75cac98bab547f7549076e3504d","path":"libraries/chain/block_log.cpp","line_range":"238-241","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"3f58d42a32421c25e81f24320b1d1f20","path":"libraries/chain/dlt_block_log.cpp","line_range":"313-328","gmt_create":"2026-04-28T12:55:56.081347+04:00","gmt_modified":"2026-04-28T12:55:56.081347+04:00"},{"id":"7a9e26fca49ab5e068040d1db9fed41f","path":"plugins/p2p/p2p_plugin.cpp","line_range":"259-286","gmt_create":"2026-04-28T12:55:56.0829766+04:00","gmt_modified":"2026-04-28T12:55:56.0829766+04:00"},{"id":"d059ab60b812d6e824e8fef796efa497","path":"libraries/chain/dlt_block_log.cpp","line_range":"161-209","gmt_create":"2026-04-28T12:55:56.0829766+04:00","gmt_modified":"2026-04-28T12:55:56.0829766+04:00"},{"id":"343b12b915179b0ceab0474a3260def1","path":"libraries/chain/dlt_block_log.cpp","line_range":"125-159","gmt_create":"2026-04-28T12:55:56.0829766+04:00","gmt_modified":"2026-04-28T12:55:56.0829766+04:00"},{"id":"edc66ae920408eb6412dad9e65c69f63","path":"libraries/chain/dlt_block_log.cpp","line_range":"211-268","gmt_create":"2026-04-28T12:55:56.0829766+04:00","gmt_modified":"2026-04-28T12:55:56.0829766+04:00"},{"id":"c87f750598b8e3aeb391ebd49f3c8730","path":"libraries/chain/dlt_block_log.cpp","line_range":"356-411","gmt_create":"2026-04-28T12:55:56.0839825+04:00","gmt_modified":"2026-04-28T12:55:56.0839825+04:00"},{"id":"85e42052e68826778bf6fc0a5c348061","path":"libraries/chain/database.cpp","line_range":"266-292","gmt_create":"2026-04-28T12:55:56.0839825+04:00","gmt_modified":"2026-04-28T12:55:56.0839825+04:00"},{"id":"44fcac467d4197ec65011a88dcc9b983","path":"plugins/snapshot/plugin.cpp","line_range":"942-1054","gmt_create":"2026-04-28T12:55:56.0849828+04:00","gmt_modified":"2026-04-28T12:55:56.0849828+04:00"},{"id":"d866d0710f48a708f384cfe833d19819","path":"plugins/snapshot/plugin.cpp","line_range":"2790-2791","gmt_create":"2026-04-28T12:55:56.0849828+04:00","gmt_modified":"2026-04-28T12:55:56.0849828+04:00"},{"id":"cc2057fd8aeaa6b63ca70e0d4192d8f6","path":"plugins/chain/plugin.cpp","line_range":"542-555","gmt_create":"2026-04-28T12:55:56.0849828+04:00","gmt_modified":"2026-04-28T12:55:56.0849828+04:00"},{"id":"5985a883b7cd6e373fa45e06af549458","path":"libraries/chain/dlt_block_log.cpp","line_range":"172-202","gmt_create":"2026-04-28T12:55:56.0859831+04:00","gmt_modified":"2026-04-28T12:55:56.0859831+04:00"},{"id":"27ad3a44022480b087c9dee522cf8f53","path":"libraries/chain/dlt_block_log.cpp","line_range":"432-444","gmt_create":"2026-04-28T12:55:56.0859831+04:00","gmt_modified":"2026-04-28T12:55:56.0859831+04:00"},{"id":"5df133f8f7e5465f2256280233f7492a","path":"libraries/chain/database.cpp","line_range":"4005-4036","gmt_create":"2026-04-28T12:55:56.0864871+04:00","gmt_modified":"2026-04-28T12:55:56.0864871+04:00"},{"id":"7ed16e639125b23aeb82bbb3768334fb","path":"libraries/chain/database.cpp","line_range":"4170-4172","gmt_create":"2026-04-28T12:55:56.0864871+04:00","gmt_modified":"2026-04-28T12:55:56.0864871+04:00"},{"id":"ed64be85dbceaa49c4d38b1fd7b0537f","path":"libraries/chain/database.cpp","line_range":"4392-4394","gmt_create":"2026-04-28T12:55:56.0864871+04:00","gmt_modified":"2026-04-28T12:55:56.0864871+04:00"},{"id":"770f933f07c1261bce810845c6711ec4","path":"libraries/chain/database.cpp","line_range":"4043-4047","gmt_create":"2026-04-28T12:55:56.0864871+04:00","gmt_modified":"2026-04-28T12:55:56.0864871+04:00"},{"id":"5988d2bd7b0d5bec2b97a885d1928110","path":"libraries/chain/database.cpp","line_range":"4189-4192","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"a9078dfa0e86bfbf3c1bef4a473eb117","path":"libraries/chain/database.cpp","line_range":"4419-4421","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"4af3002393266cb7f00332d69f2019ca","path":"plugins/chain/plugin.cpp","line_range":"233-236","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"36faa15d1b9669c10ef981b57dd230bc","path":"plugins/chain/plugin.cpp","line_range":"326-329","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"69112cf16468224f02ecd1fbd49ea64f","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"1-10","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"6456782ce4d45cbdc58f90d5677ca2c2","path":"libraries/chain/dlt_block_log.cpp","line_range":"1-7","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"fce2bc849f6a01aeb1da861120260037","path":"libraries/chain/block_log.cpp","line_range":"1-6","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"ab61b06105c0618ce476f62fc42d04c5","path":"libraries/chain/database.cpp","line_range":"1-10","gmt_create":"2026-04-28T12:55:56.0874924+04:00","gmt_modified":"2026-04-28T12:55:56.0874924+04:00"},{"id":"cf34d537814cc823a0786b3fa43ffca0","path":"libraries/chain/fork_database.cpp","line_range":"1-6","gmt_create":"2026-04-28T12:55:56.0884917+04:00","gmt_modified":"2026-04-28T12:55:56.0884917+04:00"},{"id":"7bd018a7b3dab28cc6792e89ffa39efd","path":"plugins/chain/plugin.cpp","line_range":"1-10","gmt_create":"2026-04-28T12:55:56.0884917+04:00","gmt_modified":"2026-04-28T12:55:56.0884917+04:00"},{"id":"96e5aca4a37cf627dff138e440efffa2","path":"plugins/p2p/p2p_plugin.cpp","line_range":"1-10","gmt_create":"2026-04-28T12:55:56.0884917+04:00","gmt_modified":"2026-04-28T12:55:56.0884917+04:00"},{"id":"8e436d067efeeee9365369d51dc3fd02","path":"libraries/chain/database.cpp","line_range":"250-271","gmt_create":"2026-04-28T12:55:56.0894921+04:00","gmt_modified":"2026-04-28T12:55:56.0894921+04:00"},{"id":"2fb2b5eefe1dda70f9332bca41575f3d","path":"libraries/chain/database.cpp","line_range":"259-268","gmt_create":"2026-04-28T12:55:56.0894921+04:00","gmt_modified":"2026-04-28T12:55:56.0894921+04:00"},{"id":"5864019a1f5c741338aa5810a4a9a2a4","path":"libraries/chain/database.cpp","line_range":"262-267","gmt_create":"2026-04-28T12:55:56.0894921+04:00","gmt_modified":"2026-04-28T12:55:56.0894921+04:00"},{"id":"ac84b774b43ade0dc3ca1ecbd3b60ea5","path":"libraries/chain/database.cpp","line_range":"576-580","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"29ef92399939d0e10862168a6d547c18","path":"libraries/chain/database.cpp","line_range":"609-613","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"50f4656fe0d323b661f41cd93f59398f","path":"libraries/chain/database.cpp","line_range":"599-621","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"f1468b7365f4d06080c1395db0eb5819","path":"libraries/chain/database.cpp","line_range":"623-640","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"06b382c82ee3f42c24d858503dcde41b","path":"libraries/chain/dlt_block_log.cpp","line_range":"241-249","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"ce3f0826aff2367e46f4cd37417c2f67","path":"libraries/chain/dlt_block_log.cpp","line_range":"320-325","gmt_create":"2026-04-28T12:55:56.0904911+04:00","gmt_modified":"2026-04-28T12:55:56.0904911+04:00"},{"id":"55755f9121d991a7682722b9a8b3ab80","path":"libraries/chain/database.cpp","line_range":"560-595","gmt_create":"2026-04-28T12:55:56.0919937+04:00","gmt_modified":"2026-04-28T12:55:56.0919937+04:00"},{"id":"86ba814ebeaa92690f62613e16aa5e7d","path":"libraries/chain/database.cpp","line_range":"656-697","gmt_create":"2026-04-28T12:55:56.0919937+04:00","gmt_modified":"2026-04-28T12:55:56.0919937+04:00"},{"id":"ce99ae12d13aaa7b2653e47db773bcce","path":"plugins/snapshot/plugin.cpp","line_range":"1435-1500","gmt_create":"2026-04-28T12:55:56.0919937+04:00","gmt_modified":"2026-04-28T12:55:56.0919937+04:00"},{"id":"a370301bb49e9efcf0ef5d6724ac9dd2","path":"plugins/snapshot/plugin.cpp","line_range":"2691-2696","gmt_create":"2026-04-28T12:55:56.0919937+04:00","gmt_modified":"2026-04-28T12:55:56.0919937+04:00"},{"id":"09819e68e897288cd817074594e4f548","path":"plugins/snapshot/plugin.cpp","line_range":"2863-2866","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"b44834f88165b1116477f30dc5f88a3e","path":"libraries/chain/database.cpp","line_range":"4581-4608","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"c6612598fe076c0f7d5ca15ca94cf26b","path":"plugins/chain/plugin.cpp","line_range":"627-627","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"62962be4cb55c4466a47fba7a814b326","path":"plugins/snapshot/plugin.cpp","line_range":"1473-1476","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"798b9ae312576643f8fefd434b40bddc","path":"plugins/chain/plugin.cpp","line_range":"626-632","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"02c2555684691e747182b4078de2ed9b","path":"plugins/snapshot/plugin.cpp","line_range":"1472-1477","gmt_create":"2026-04-28T12:55:56.0929972+04:00","gmt_modified":"2026-04-28T12:55:56.0929972+04:00"},{"id":"590d1dfeeb49a4029c52d3c49b2f0362","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"1-144","gmt_create":"2026-04-28T13:00:52.0145244+04:00","gmt_modified":"2026-04-28T13:00:52.0145244+04:00"},{"id":"d599d8eb734647e07f075785246b447f","path":"libraries/chain/fork_database.cpp","line_range":"1-278","gmt_create":"2026-04-28T13:00:52.0150341+04:00","gmt_modified":"2026-04-28T13:00:52.0150341+04:00"},{"id":"268918c988500bd0972ad80cef38bdd3","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"53-144","gmt_create":"2026-04-28T13:00:52.0199161+04:00","gmt_modified":"2026-04-28T13:00:52.0199161+04:00"},{"id":"24e53b6bba24767d436a386f584d39b1","path":"plugins/p2p/p2p_plugin.cpp","line_range":"330-364","gmt_create":"2026-04-28T14:54:15.686411+04:00","gmt_modified":"2026-04-28T14:54:15.686411+04:00"},{"id":"e24259987d3c50dee1a87e13d63ccf03","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"57-78","gmt_create":"2026-04-28T14:54:15.686411+04:00","gmt_modified":"2026-04-28T14:54:15.686411+04:00"},{"id":"163647b506865a0b9039e6ab0e61b35b","path":"plugins/p2p/p2p_plugin.cpp","line_range":"290-364","gmt_create":"2026-04-28T14:54:15.686411+04:00","gmt_modified":"2026-04-28T14:54:15.686411+04:00"},{"id":"909f520b94e82193bac04c745bf8f67c","path":"plugins/p2p/p2p_plugin.cpp","line_range":"614-650","gmt_create":"2026-04-28T14:54:15.687411+04:00","gmt_modified":"2026-04-28T14:54:15.687411+04:00"},{"id":"c45e7282b5fb1668e8ae6f5a8da708ea","path":"plugins/p2p/p2p_plugin.cpp","line_range":"151-208","gmt_create":"2026-04-28T14:54:15.688411+04:00","gmt_modified":"2026-04-28T14:54:15.688411+04:00"},{"id":"29d1adb11bc96c1e7216be1c31cb57f7","path":"plugins/p2p/p2p_plugin.cpp","line_range":"173-204","gmt_create":"2026-04-28T14:54:15.6894111+04:00","gmt_modified":"2026-04-28T14:54:15.6894111+04:00"},{"id":"b1416c15172aac5cdff13f12c0d385b6","path":"libraries/network/include/graphene/network/node.hpp","line_range":"180-355","gmt_create":"2026-04-28T14:54:34.9410488+04:00","gmt_modified":"2026-04-28T14:54:34.9410488+04:00"},{"id":"b2e1954ed604c23c3fe69090870838ec","path":"libraries/network/node.cpp","line_range":"869-905","gmt_create":"2026-04-28T14:54:34.9410488+04:00","gmt_modified":"2026-04-28T14:54:34.9410488+04:00"},{"id":"7b85de17d00c3c33f3e6ce72493cea24","path":"libraries/network/include/graphene/network/peer_database.hpp","line_range":"104-134","gmt_create":"2026-04-28T14:54:34.9410488+04:00","gmt_modified":"2026-04-28T14:54:34.9410488+04:00"},{"id":"4a47af89ac294fea1a93e8ab87bc62a8","path":"libraries/network/include/graphene/network/message.hpp","line_range":"42-114","gmt_create":"2026-04-28T14:54:34.9410488+04:00","gmt_modified":"2026-04-28T14:54:34.9410488+04:00"},{"id":"fcf5471e2941c73aa4796f0d15ca9d4f","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"111-120","gmt_create":"2026-04-28T14:54:34.9410488+04:00","gmt_modified":"2026-04-28T14:54:34.9410488+04:00"},{"id":"7d072be9a3f767f13a99da4cd6df4783","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"110-123","gmt_create":"2026-04-28T14:54:34.9421314+04:00","gmt_modified":"2026-04-28T14:54:34.9421314+04:00"},{"id":"4f55b43e070bade6f117e02d6faaaac2","path":"libraries/chain/dlt_block_log.cpp","line_range":"368-379","gmt_create":"2026-04-28T14:54:34.9421314+04:00","gmt_modified":"2026-04-28T14:54:34.9421314+04:00"},{"id":"5b2dac9b59c644b7b47e991af481e627","path":"plugins/p2p/p2p_plugin.cpp","line_range":"330-360","gmt_create":"2026-04-28T14:54:34.9426338+04:00","gmt_modified":"2026-04-28T14:54:34.9426338+04:00"},{"id":"d9910f1ea9014fede12810a52c49c4a4","path":"libraries/network/node.cpp","line_range":"952-1047","gmt_create":"2026-04-28T14:54:34.9441396+04:00","gmt_modified":"2026-04-28T14:54:34.9441396+04:00"},{"id":"2d0f35d8035d544c59943ce9488d042e","path":"libraries/network/node.cpp","line_range":"1623-1654","gmt_create":"2026-04-28T14:54:34.9451427+04:00","gmt_modified":"2026-04-28T14:54:34.9451427+04:00"},{"id":"4cb233e3e08980c2c2c76e7762ad457b","path":"libraries/network/node.cpp","line_range":"2282-2350","gmt_create":"2026-04-28T14:54:34.9451427+04:00","gmt_modified":"2026-04-28T14:54:34.9451427+04:00"},{"id":"465b6e48aad6641d48e75039b1ba6cf7","path":"libraries/network/node.cpp","line_range":"869-931","gmt_create":"2026-04-28T14:54:34.9451427+04:00","gmt_modified":"2026-04-28T14:54:34.9451427+04:00"},{"id":"64eac8af7d3939075658361c76c2a7f4","path":"libraries/network/node.cpp","line_range":"2029-2230","gmt_create":"2026-04-28T14:54:34.9451427+04:00","gmt_modified":"2026-04-28T14:54:34.9451427+04:00"},{"id":"63a72fb69b4b837d5841f87d654e6835","path":"libraries/network/node.cpp","line_range":"2232-2250","gmt_create":"2026-04-28T14:54:34.9451427+04:00","gmt_modified":"2026-04-28T14:54:34.9451427+04:00"},{"id":"7d1df83c34f12b0c857fb327e688236b","path":"libraries/network/node.cpp","line_range":"1400-1621","gmt_create":"2026-04-28T14:54:34.9474075+04:00","gmt_modified":"2026-04-28T14:54:34.9474075+04:00"},{"id":"3497c413bfbe054ece4588e4c9764e38","path":"libraries/network/include/graphene/network/node.hpp","line_range":"79-80","gmt_create":"2026-04-28T14:54:34.9480006+04:00","gmt_modified":"2026-04-28T14:54:34.9480006+04:00"},{"id":"832f176e5f919dc138e93f3d848899bb","path":"libraries/network/node.cpp","line_range":"3117-3199","gmt_create":"2026-04-28T14:54:34.9480006+04:00","gmt_modified":"2026-04-28T14:54:34.9480006+04:00"},{"id":"d93f64e1090b7fb0448056ce453003b2","path":"libraries/network/include/graphene/network/node.hpp","line_range":"200-294","gmt_create":"2026-04-28T14:54:34.9485694+04:00","gmt_modified":"2026-04-28T14:54:34.9485694+04:00"},{"id":"8422adca0104a424dd0293e0e0b74399","path":"libraries/network/node.cpp","line_range":"933-950","gmt_create":"2026-04-28T14:54:34.9485694+04:00","gmt_modified":"2026-04-28T14:54:34.9485694+04:00"},{"id":"f88975c9b8df22394830934bbd2b8fec","path":"libraries/network/node.cpp","line_range":"1686-1713","gmt_create":"2026-04-28T14:54:34.9491379+04:00","gmt_modified":"2026-04-28T14:54:34.9491379+04:00"},{"id":"140ecf3fedde255af2f0a4ce07a0edaa","path":"libraries/network/include/graphene/network/node.hpp","line_range":"211-296","gmt_create":"2026-04-28T14:54:34.9491379+04:00","gmt_modified":"2026-04-28T14:54:34.9491379+04:00"},{"id":"2a546861a7d7c1c0f13a5e81a60a2663","path":"libraries/network/node.cpp","line_range":"1788-1841","gmt_create":"2026-04-28T14:54:34.9491379+04:00","gmt_modified":"2026-04-28T14:54:34.9491379+04:00"},{"id":"e9dd01a70c4ccc4eff5ea6c67ea751d4","path":"libraries/network/node.cpp","line_range":"1326-1398","gmt_create":"2026-04-28T14:54:34.9497751+04:00","gmt_modified":"2026-04-28T14:54:34.9497751+04:00"},{"id":"e396600c03187cea5577399428a6bc7a","path":"libraries/network/node.cpp","line_range":"2830-2892","gmt_create":"2026-04-28T14:54:34.9497751+04:00","gmt_modified":"2026-04-28T14:54:34.9497751+04:00"},{"id":"4d84381505174d8f3190a51bf7d50f11","path":"libraries/network/node.cpp","line_range":"111-217","gmt_create":"2026-04-28T14:54:34.9497751+04:00","gmt_modified":"2026-04-28T14:54:34.9497751+04:00"},{"id":"d9e91362d84f2e5c27205bacead0d8e5","path":"libraries/network/node.cpp","line_range":"2251-2280","gmt_create":"2026-04-28T14:54:34.9582805+04:00","gmt_modified":"2026-04-28T14:54:34.9582805+04:00"},{"id":"b0c24aab481fd56f8134b091b5bf0525","path":"libraries/network/node.cpp","line_range":"2137-2168","gmt_create":"2026-04-28T14:54:34.9582805+04:00","gmt_modified":"2026-04-28T14:54:34.9582805+04:00"},{"id":"731063774f04d46e1f2c0d64963dfe33","path":"libraries/chain/database.cpp","line_range":"4455-4460","gmt_create":"2026-04-28T14:54:34.9592806+04:00","gmt_modified":"2026-04-28T14:54:34.9592806+04:00"},{"id":"733f077750798ad212e3907d2e15c841","path":"libraries/chain/database.cpp","line_range":"835-858","gmt_create":"2026-04-28T14:55:54.6404091+04:00","gmt_modified":"2026-04-28T14:55:54.6404091+04:00"},{"id":"c31e2a585be22edd01d86dba51c51e79","path":"plugins/p2p/p2p_plugin.cpp","line_range":"294-302","gmt_create":"2026-04-28T14:55:54.6601866+04:00","gmt_modified":"2026-04-28T14:55:54.6601866+04:00"},{"id":"6ef04fbc3dcdfebcf2580c7e7146cbc3","path":"plugins/p2p/p2p_plugin.cpp","line_range":"317-323","gmt_create":"2026-04-28T14:55:54.6601866+04:00","gmt_modified":"2026-04-28T14:55:54.6601866+04:00"},{"id":"5e4bd94274850728b00115526a2479ee","path":"libraries/chain/database.cpp","line_range":"860-882","gmt_create":"2026-04-28T14:55:54.6617664+04:00","gmt_modified":"2026-04-28T14:55:54.6617664+04:00"},{"id":"c53a6db24cea4db25b30783459c40125","path":"libraries/chain/database.cpp","line_range":"884-901","gmt_create":"2026-04-28T14:55:54.6622692+04:00","gmt_modified":"2026-04-28T14:55:54.6622692+04:00"},{"id":"88d1d1609201e580c6cdf488fcd22fad","path":"plugins/p2p/p2p_plugin.cpp","line_range":"370-489","gmt_create":"2026-04-28T14:55:54.6622692+04:00","gmt_modified":"2026-04-28T14:55:54.6622692+04:00"},{"id":"929cc0269a5814a951b45c3300f44597","path":"libraries/chain/database.cpp","line_range":"789-827","gmt_create":"2026-04-28T15:02:14.7298629+04:00","gmt_modified":"2026-04-28T15:02:14.7298629+04:00"},{"id":"6abfbb22aee54a4b386173dfc74da72b","path":"libraries/chain/database.cpp","line_range":"5452-5482","gmt_create":"2026-04-28T15:02:14.7314238+04:00","gmt_modified":"2026-04-28T15:02:14.7314238+04:00"},{"id":"2ba1e391be7a79f5151c8abeb655315d","path":"libraries/chain/database.cpp","line_range":"5467-5480","gmt_create":"2026-04-28T15:02:14.7314853+04:00","gmt_modified":"2026-04-28T15:02:14.7314853+04:00"},{"id":"55ed0cee7e5f683b8caac133899cb8cd","path":"plugins/p2p/p2p_plugin.cpp","line_range":"295-340","gmt_create":"2026-04-28T17:51:11.5333641+04:00","gmt_modified":"2026-04-28T17:51:11.5333641+04:00"},{"id":"0dc933c238ae7ab73de36f0171dfb48b","path":"plugins/p2p/p2p_plugin.cpp","line_range":"371-405","gmt_create":"2026-04-28T17:51:11.5338875+04:00","gmt_modified":"2026-04-28T17:51:11.5338875+04:00"},{"id":"5a09c4b30cf4ad7363c8ddc12bc7c8db","path":"plugins/p2p/p2p_plugin.cpp","line_range":"290-405","gmt_create":"2026-04-28T17:51:11.5344061+04:00","gmt_modified":"2026-04-28T17:51:11.5344061+04:00"},{"id":"d8698088d1f1c1cd1343a5552104c443","path":"plugins/p2p/p2p_plugin.cpp","line_range":"295-405","gmt_create":"2026-04-28T17:51:11.5375192+04:00","gmt_modified":"2026-04-28T17:51:11.5375192+04:00"},{"id":"bccfbcb90cc33fcb1bad654d203eab3a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"308-340","gmt_create":"2026-04-28T17:51:11.5386681+04:00","gmt_modified":"2026-04-28T17:51:11.5386681+04:00"},{"id":"3e4f7ec74d72ee9c1f4f5cf2a0f86844","path":"plugins/p2p/p2p_plugin.cpp","line_range":"298-302","gmt_create":"2026-04-28T17:51:11.5389893+04:00","gmt_modified":"2026-04-28T17:51:11.5389893+04:00"},{"id":"e13810e67e91d0b4940124f48b98095c","path":"plugins/p2p/p2p_plugin.cpp","line_range":"335-338","gmt_create":"2026-04-28T17:51:11.5394927+04:00","gmt_modified":"2026-04-28T17:51:11.5394927+04:00"},{"id":"30fcbbca25b602851122e4d2b5ae4754","path":"plugins/p2p/p2p_plugin.cpp","line_range":"701-765","gmt_create":"2026-04-28T17:51:11.5400458+04:00","gmt_modified":"2026-04-28T17:51:11.5400458+04:00"},{"id":"2d0ff08ccbd1994ff4f46985361fc3d4","path":"plugins/p2p/p2p_plugin.cpp","line_range":"355-364","gmt_create":"2026-04-28T17:51:11.541049+04:00","gmt_modified":"2026-04-28T17:51:11.541049+04:00"},{"id":"f195c24b5ab419ffbcc0c59a70fc3b0b","path":"plugins/p2p/p2p_plugin.cpp","line_range":"520-528","gmt_create":"2026-04-28T17:51:11.541049+04:00","gmt_modified":"2026-04-28T17:51:11.541049+04:00"},{"id":"1638be790588edb6a3913a76064f24e0","path":"plugins/p2p/p2p_plugin.cpp","line_range":"992-1061","gmt_create":"2026-04-28T17:51:11.5471656+04:00","gmt_modified":"2026-04-28T17:51:11.5471656+04:00"},{"id":"cfa97ba993c799f350895b1deb5bfa1a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"596-699","gmt_create":"2026-04-28T17:51:11.5541826+04:00","gmt_modified":"2026-04-28T17:51:11.5541826+04:00"},{"id":"87dbe393410d68cf0b46ab22827e33fe","path":"plugins/snapshot/plugin.cpp","line_range":"3252-3290","gmt_create":"2026-04-28T17:52:33.4426757+04:00","gmt_modified":"2026-04-28T17:52:33.4426757+04:00"},{"id":"98c57a9cc27d3a9e444c74d23a63bf9e","path":"libraries/chain/database.cpp","line_range":"4945-4947","gmt_create":"2026-04-28T17:52:33.4431784+04:00","gmt_modified":"2026-04-28T17:52:33.4431784+04:00"},{"id":"2d706a9e6bc734297fc6693a4cec7176","path":"libraries/chain/database.cpp","line_range":"5139-5140","gmt_create":"2026-04-28T17:52:33.4431784+04:00","gmt_modified":"2026-04-28T17:52:33.4431784+04:00"},{"id":"95d10140a46b090a8cea978c1c73a9bb","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"337-338","gmt_create":"2026-04-28T17:52:33.4431784+04:00","gmt_modified":"2026-04-28T17:52:33.4431784+04:00"},{"id":"95da2daaa0065c2230410221cb5b5dbd","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"1-670","gmt_create":"2026-04-28T17:55:35.3290491+04:00","gmt_modified":"2026-04-28T17:55:35.3290491+04:00"},{"id":"86991432e69878d08cc76b9d386b7d8f","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"1-80","gmt_create":"2026-04-28T17:55:35.3305561+04:00","gmt_modified":"2026-04-28T17:55:35.3305561+04:00"},{"id":"cdc31aad39121f507723919db7d70dee","path":"libraries/chain/dlt_block_log.cpp","line_range":"1-476","gmt_create":"2026-04-28T17:55:35.3305561+04:00","gmt_modified":"2026-04-28T17:55:35.3305561+04:00"},{"id":"31f6fa48f80c0c6d8c5b09074b2f3f45","path":"libraries/chain/database.cpp","line_range":"4910-5150","gmt_create":"2026-04-28T17:57:38.432734+04:00","gmt_modified":"2026-04-28T17:57:38.432734+04:00"},{"id":"7f9a564b8011c536e8ff555516dffbae","path":"plugins/snapshot/plugin.cpp","line_range":"3254","gmt_create":"2026-04-28T17:57:38.4363285+04:00","gmt_modified":"2026-04-28T17:57:38.4363285+04:00"},{"id":"17512b930411cc392fa7b28fa3ad2b84","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"332-338","gmt_create":"2026-04-28T17:57:38.4456022+04:00","gmt_modified":"2026-04-28T17:57:38.4456022+04:00"},{"id":"930f47bc2c95f0cac4086eeca5749e2c","path":"libraries/network/include/graphene/network/node.hpp","line_range":"190-304","gmt_create":"2026-04-28T18:50:34.3821408+04:00","gmt_modified":"2026-04-28T18:50:34.3821408+04:00"},{"id":"9f8690911ef66c966743475f294ffb7e","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"79-351","gmt_create":"2026-04-28T18:50:34.3821408+04:00","gmt_modified":"2026-04-28T18:50:34.3821408+04:00"},{"id":"a480bfeb1604076e7d1db7746687a3b4","path":"libraries/network/include/graphene/network/message.hpp","line_range":"42-106","gmt_create":"2026-04-28T18:50:34.382644+04:00","gmt_modified":"2026-04-28T18:50:34.382644+04:00"},{"id":"c54e54629fd9cd255341b311da9b6be1","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"72-573","gmt_create":"2026-04-28T18:50:34.382644+04:00","gmt_modified":"2026-04-28T18:50:34.382644+04:00"},{"id":"4e8bc2cdd3d4fc68b2f7138c54288174","path":"libraries/network/include/graphene/network/stcp_socket.hpp","line_range":"37-93","gmt_create":"2026-04-28T18:50:34.382644+04:00","gmt_modified":"2026-04-28T18:50:34.382644+04:00"},{"id":"ff11a77da594972e0b8a78df4289ada5","path":"libraries/network/include/graphene/network/message_oriented_connection.hpp","line_range":"45-79","gmt_create":"2026-04-28T18:50:34.382644+04:00","gmt_modified":"2026-04-28T18:50:34.382644+04:00"},{"id":"d614fc51360bb61b8f521167a6db1e11","path":"libraries/network/include/graphene/network/config.hpp","line_range":"26-106","gmt_create":"2026-04-28T18:50:34.382644+04:00","gmt_modified":"2026-04-28T18:50:34.382644+04:00"},{"id":"411a87e4e085e019827e9bd8085b8328","path":"plugins/p2p/p2p_plugin.cpp","line_range":"500-560","gmt_create":"2026-04-28T18:50:34.3836471+04:00","gmt_modified":"2026-04-28T18:50:34.3836471+04:00"},{"id":"6a050f797e4d75bb2867072fae629c2a","path":"libraries/network/node.cpp","line_range":"5281-5286","gmt_create":"2026-04-28T18:50:34.3836471+04:00","gmt_modified":"2026-04-28T18:50:34.3836471+04:00"},{"id":"448218400a050ac2d3a0f1ee290faf50","path":"libraries/network/node.cpp","line_range":"346-347","gmt_create":"2026-04-28T18:50:34.3836471+04:00","gmt_modified":"2026-04-28T18:50:34.3836471+04:00"},{"id":"34550b8d6e01a13e99a0ed70072db86b","path":"libraries/network/include/graphene/network/node.hpp","line_range":"1-355","gmt_create":"2026-04-28T18:50:34.3846488+04:00","gmt_modified":"2026-04-28T18:50:34.3846488+04:00"},{"id":"9847129d410beb4256be18f2e7489d18","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"1-383","gmt_create":"2026-04-28T18:50:34.3849215+04:00","gmt_modified":"2026-04-28T18:50:34.3849215+04:00"},{"id":"a3e6f8b4e51c838c44eaef16bb205031","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"1-573","gmt_create":"2026-04-28T18:50:34.3849215+04:00","gmt_modified":"2026-04-28T18:50:34.3849215+04:00"},{"id":"53a676bf1df5198ba31b6ebe848a29bd","path":"libraries/network/include/graphene/network/stcp_socket.hpp","line_range":"1-99","gmt_create":"2026-04-28T18:50:34.3855102+04:00","gmt_modified":"2026-04-28T18:50:34.3855102+04:00"},{"id":"f14b0ce0c1ba142fb55271fdc6c2ee9f","path":"libraries/network/include/graphene/network/peer_database.hpp","line_range":"1-141","gmt_create":"2026-04-28T18:50:34.3860136+04:00","gmt_modified":"2026-04-28T18:50:34.3860136+04:00"},{"id":"f59f370133646ba0c40ebdd11ee6d697","path":"libraries/network/include/graphene/network/message.hpp","line_range":"1-114","gmt_create":"2026-04-28T18:50:34.3860943+04:00","gmt_modified":"2026-04-28T18:50:34.3860943+04:00"},{"id":"762c4b81ed454ad789c0b3b3cb00cc88","path":"libraries/network/include/graphene/network/message_oriented_connection.hpp","line_range":"1-85","gmt_create":"2026-04-28T18:50:34.3860943+04:00","gmt_modified":"2026-04-28T18:50:34.3860943+04:00"},{"id":"bc9b507990af077f95d7bbe7203d51f0","path":"libraries/network/include/graphene/network/config.hpp","line_range":"1-106","gmt_create":"2026-04-28T18:50:34.3865969+04:00","gmt_modified":"2026-04-28T18:50:34.3865969+04:00"},{"id":"b54da9d3dceb59e39a6cd88a5a99b593","path":"plugins/p2p/p2p_plugin.cpp","line_range":"1-742","gmt_create":"2026-04-28T18:50:34.3866975+04:00","gmt_modified":"2026-04-28T18:50:34.3866975+04:00"},{"id":"54ba2e42561f4bf9913449b2a78838bb","path":"libraries/network/include/graphene/network/node.hpp","line_range":"182-304","gmt_create":"2026-04-28T18:50:34.3866975+04:00","gmt_modified":"2026-04-28T18:50:34.3866975+04:00"},{"id":"94c69e0f6c696d5856c9a52b4dbcda00","path":"libraries/network/node.cpp","line_range":"780-790","gmt_create":"2026-04-28T18:50:34.3882034+04:00","gmt_modified":"2026-04-28T18:50:34.3882034+04:00"},{"id":"d6f1f5c1ab7e33b9a558f648113330fb","path":"libraries/network/peer_connection.cpp","line_range":"208-242","gmt_create":"2026-04-28T18:50:34.3882034+04:00","gmt_modified":"2026-04-28T18:50:34.3882034+04:00"},{"id":"db2f58e50720e139a95c598355919158","path":"libraries/network/stcp_socket.cpp","line_range":"69-72","gmt_create":"2026-04-28T18:50:34.3882034+04:00","gmt_modified":"2026-04-28T18:50:34.3882034+04:00"},{"id":"a6b2b3362f68c7523a4e0d06a2a4352f","path":"libraries/network/node.cpp","line_range":"424-799","gmt_create":"2026-04-28T18:50:34.3893282+04:00","gmt_modified":"2026-04-28T18:50:34.3893282+04:00"},{"id":"20359a9271432a216b6faf9dc97fa5c6","path":"libraries/network/peer_connection.cpp","line_range":"169-206","gmt_create":"2026-04-28T18:50:34.3905804+04:00","gmt_modified":"2026-04-28T18:50:34.3905804+04:00"},{"id":"fee43b750e5fa7d56e56ac6251e6b5bb","path":"libraries/network/peer_connection.cpp","line_range":"41-66","gmt_create":"2026-04-28T18:50:34.3917964+04:00","gmt_modified":"2026-04-28T18:50:34.3917964+04:00"},{"id":"25c0bdec5e0fb6c8d410577e1478ea78","path":"libraries/network/peer_connection.cpp","line_range":"310-354","gmt_create":"2026-04-28T18:50:34.3923001+04:00","gmt_modified":"2026-04-28T18:50:34.3923001+04:00"},{"id":"e81b900c80dc9c266a93a66cc60486de","path":"libraries/network/core_messages.cpp","line_range":"30-49","gmt_create":"2026-04-28T18:50:34.3930151+04:00","gmt_modified":"2026-04-28T18:50:34.3930151+04:00"},{"id":"0b26d723a87937f5a3f58770c522d067","path":"libraries/network/stcp_socket.cpp","line_range":"49-72","gmt_create":"2026-04-28T18:50:34.3940938+04:00","gmt_modified":"2026-04-28T18:50:34.3940938+04:00"},{"id":"d4b4e356cc64c1eac490f25138ad8337","path":"libraries/network/stcp_socket.cpp","line_range":"132-177","gmt_create":"2026-04-28T18:50:34.3940938+04:00","gmt_modified":"2026-04-28T18:50:34.3940938+04:00"},{"id":"b43af1b0b5dbbe32011b0ab877770800","path":"libraries/network/stcp_socket.cpp","line_range":"49-177","gmt_create":"2026-04-28T18:50:34.3940938+04:00","gmt_modified":"2026-04-28T18:50:34.3940938+04:00"},{"id":"fd44e8ec8ed78651240bac55efcc1f20","path":"libraries/network/peer_database.cpp","line_range":"41-82","gmt_create":"2026-04-28T18:50:34.3950971+04:00","gmt_modified":"2026-04-28T18:50:34.3950971+04:00"},{"id":"ee53a7a714337d597cc0a626fceec27f","path":"libraries/network/peer_database.cpp","line_range":"100-174","gmt_create":"2026-04-28T18:50:34.3951753+04:00","gmt_modified":"2026-04-28T18:50:34.3951753+04:00"},{"id":"aae2609ed41db2a866f07ce766cbb938","path":"libraries/network/include/graphene/network/message.hpp","line_range":"70-105","gmt_create":"2026-04-28T18:50:34.3956782+04:00","gmt_modified":"2026-04-28T18:50:34.3956782+04:00"},{"id":"023d67279bae7acc551e276826dc0ff1","path":"libraries/network/node.cpp","line_range":"3710-3723","gmt_create":"2026-04-28T18:50:34.3956782+04:00","gmt_modified":"2026-04-28T18:50:34.3956782+04:00"},{"id":"b7e9099b5e14dfe6396c0a1c5c308eb7","path":"libraries/network/node.cpp","line_range":"312-381","gmt_create":"2026-04-28T18:50:34.3956782+04:00","gmt_modified":"2026-04-28T18:50:34.3956782+04:00"},{"id":"26b49296ed2024fd0dde20e6f7e40b88","path":"libraries/network/node.cpp","line_range":"383-420","gmt_create":"2026-04-28T18:50:34.3956782+04:00","gmt_modified":"2026-04-28T18:50:34.3956782+04:00"},{"id":"41d27526c610abf125f7a7d008632585","path":"libraries/network/include/graphene/network/node.hpp","line_range":"173-179","gmt_create":"2026-04-28T18:50:34.3956782+04:00","gmt_modified":"2026-04-28T18:50:34.3956782+04:00"},{"id":"868fa39acf5aeee17dc7a8161740807d","path":"libraries/network/node.cpp","line_range":"4920-4970","gmt_create":"2026-04-28T18:50:34.3966815+04:00","gmt_modified":"2026-04-28T18:50:34.3966815+04:00"},{"id":"9814b4d33f73344843377eb1e1b063d8","path":"libraries/network/node.cpp","line_range":"5128-5131","gmt_create":"2026-04-28T18:50:34.3966815+04:00","gmt_modified":"2026-04-28T18:50:34.3966815+04:00"},{"id":"380d27e76ccd3471d37efe9e980c19ae","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"322-346","gmt_create":"2026-04-28T18:50:34.3966815+04:00","gmt_modified":"2026-04-28T18:50:34.3966815+04:00"},{"id":"569091d2a8631dcfd98eaa50ae2bfc44","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"428-448","gmt_create":"2026-04-28T18:50:34.3966815+04:00","gmt_modified":"2026-04-28T18:50:34.3966815+04:00"},{"id":"1ed9d91d6dd0223209ee65abf9542242","path":"libraries/network/node.cpp","line_range":"4900-4970","gmt_create":"2026-04-28T18:50:34.3976813+04:00","gmt_modified":"2026-04-28T18:50:34.3976813+04:00"},{"id":"b8d925dd432a091aeeb11648caa2eb44","path":"libraries/network/node.cpp","line_range":"4164-4168","gmt_create":"2026-04-28T18:50:34.3987829+04:00","gmt_modified":"2026-04-28T18:50:34.3987829+04:00"},{"id":"bf71a71910c5567123121789e437c062","path":"libraries/network/include/graphene/network/node.hpp","line_range":"298-304","gmt_create":"2026-04-28T18:50:34.399451+04:00","gmt_modified":"2026-04-28T18:50:34.399451+04:00"},{"id":"690241d99c53c94e7cfd1435215c90f7","path":"plugins/p2p/p2p_plugin.cpp","line_range":"616-618","gmt_create":"2026-04-28T18:50:34.4000241+04:00","gmt_modified":"2026-04-28T18:50:34.4000241+04:00"},{"id":"8df3a4b9e7bead2487cc1ffc6cd49cae","path":"plugins/p2p/p2p_plugin.cpp","line_range":"16-19","gmt_create":"2026-04-28T18:50:34.4005266+04:00","gmt_modified":"2026-04-28T18:50:34.4005266+04:00"},{"id":"84d9f61aa92a7de46576a47f269a5dcd","path":"plugins/p2p/p2p_plugin.cpp","line_range":"169-171","gmt_create":"2026-04-28T18:50:34.4005266+04:00","gmt_modified":"2026-04-28T18:50:34.4005266+04:00"},{"id":"0be17f1ab260a4b3bcead7596649bfc6","path":"libraries/network/node.cpp","line_range":"81-81","gmt_create":"2026-04-28T18:50:34.4005266+04:00","gmt_modified":"2026-04-28T18:50:34.4005266+04:00"},{"id":"271449375aea639d1f03a23e291eaea3","path":"libraries/network/node.cpp","line_range":"1187-1194","gmt_create":"2026-04-28T18:50:34.4005266+04:00","gmt_modified":"2026-04-28T18:50:34.4005266+04:00"},{"id":"14c432cf8aa5e9ce797534c3d40b187f","path":"libraries/network/node.cpp","line_range":"1200-1202","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"c63bedc7eec5da82c3e0783176a7a564","path":"libraries/network/node.cpp","line_range":"2651-2663","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"95b247631c8b269b2a98c7e385bac407","path":"libraries/network/node.cpp","line_range":"2772-2779","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"e5fedb1d60d7f5a29bddbc403ff3d857","path":"libraries/network/node.cpp","line_range":"2790-2796","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"b30577f67d2d7eafe760daf3f3f386b0","path":"libraries/network/include/graphene/network/node.hpp","line_range":"26-28","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"8d12769b91a5f0a7c02fe172ecffd5ef","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"26-29","gmt_create":"2026-04-28T18:50:34.4015296+04:00","gmt_modified":"2026-04-28T18:50:34.4015296+04:00"},{"id":"b4c2646d470a9f4262288b71e7b10e89","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"26-28","gmt_create":"2026-04-28T18:50:34.4025295+04:00","gmt_modified":"2026-04-28T18:50:34.4025295+04:00"},{"id":"055bd4ac99dff0f7dad3d2d929f83b6a","path":"libraries/network/include/graphene/network/stcp_socket.hpp","line_range":"26-28","gmt_create":"2026-04-28T18:50:34.4026147+04:00","gmt_modified":"2026-04-28T18:50:34.4026147+04:00"},{"id":"eb6ddb4ecbe9eb87c395f2865107ea0e","path":"libraries/network/include/graphene/network/message_oriented_connection.hpp","line_range":"26-27","gmt_create":"2026-04-28T18:50:34.4026147+04:00","gmt_modified":"2026-04-28T18:50:34.4026147+04:00"},{"id":"660390a5b68b3f21fd886800f24fcc78","path":"libraries/network/include/graphene/network/peer_database.hpp","line_range":"39-45","gmt_create":"2026-04-28T18:50:34.4041203+04:00","gmt_modified":"2026-04-28T18:50:34.4041203+04:00"},{"id":"688ff5b9bf8ff49c734540b2a73a1251","path":"libraries/network/include/graphene/network/node.hpp","line_range":"288-298","gmt_create":"2026-04-28T18:50:34.4050997+04:00","gmt_modified":"2026-04-28T18:50:34.4050997+04:00"},{"id":"34e2f989664fd5eff332f3ac19b8b16e","path":"libraries/network/include/graphene/network/message.hpp","line_range":"85-105","gmt_create":"2026-04-28T18:50:34.4056028+04:00","gmt_modified":"2026-04-28T18:50:34.4056028+04:00"},{"id":"16865a1a8de25574f1f934ab4b21167f","path":"plugins/snapshot/plugin.cpp","line_range":"1595-1624","gmt_create":"2026-04-28T18:53:18.2448781+04:00","gmt_modified":"2026-04-28T18:53:18.2448781+04:00"},{"id":"9a668be3a6e1e9f3afa6fcd90677d0b3","path":"libraries/chain/database.cpp","line_range":"5482-5499","gmt_create":"2026-04-28T18:54:23.6340341+04:00","gmt_modified":"2026-04-28T18:54:23.6340341+04:00"},{"id":"e2711f14cc959993e82e19c033761fff","path":"plugins/p2p/p2p_plugin.cpp","line_range":"16-21","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"c66e1ad4dc89d485e77e61d3776d5e80","path":"plugins/p2p/p2p_plugin.cpp","line_range":"299-301","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"d6af3938508b615a82ba5a3820d850c0","path":"plugins/p2p/p2p_plugin.cpp","line_range":"522-528","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"10e2e9b3ec934c86877d6a4b57e21d34","path":"plugins/p2p/p2p_plugin.cpp","line_range":"321-327","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"5cdb837c5a6e5f183ed9a818f50b2abf","path":"plugins/p2p/p2p_plugin.cpp","line_range":"336-338","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"4a61426778eec404639d3aa8059fbe1a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"357-364","gmt_create":"2026-04-28T19:27:53.5877256+04:00","gmt_modified":"2026-04-28T19:27:53.5877256+04:00"},{"id":"f9ff6c6bb4dec49a31a1b770a5d8e89f","path":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","line_range":"38-108","gmt_create":"2026-04-28T19:48:38.8563572+04:00","gmt_modified":"2026-04-28T19:48:38.8563572+04:00"},{"id":"c914b1a14377d172e66d3320eee0a043","path":"plugins/debug_node/plugin.cpp","line_range":"25-94","gmt_create":"2026-04-28T19:48:38.8563572+04:00","gmt_modified":"2026-04-28T19:48:38.8563572+04:00"},{"id":"f3cc232f0f51afc8747a00f6b9906c3d","path":"plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp","line_range":"1-108","gmt_create":"2026-04-28T19:48:38.8563572+04:00","gmt_modified":"2026-04-28T19:48:38.8563572+04:00"},{"id":"b9491b3f2a4f089e194b8c382d40e3ed","path":"programs/util/sign_transaction.cpp","line_range":"12-26","gmt_create":"2026-04-28T19:48:38.8574734+04:00","gmt_modified":"2026-04-28T19:48:38.8574734+04:00"},{"id":"80d96f5a237fbc996d591a3a6738455e","path":"programs/util/sign_digest.cpp","line_range":"12-24","gmt_create":"2026-04-28T19:48:38.8574734+04:00","gmt_modified":"2026-04-28T19:48:38.8574734+04:00"},{"id":"3aa63104c48be9af56ac2394a0ff0465","path":"plugins/p2p/p2p_plugin.cpp","line_range":"1-200","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"035cfc0826dd0b5915c1d3c58d1ef13d","path":"libraries/network/include/graphene/network/node.hpp","line_range":"190-200","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"775f3dad042fb99fc87d2a984fb10026","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"79-200","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"ab666734d7a7b8fd90bcfb1f1a312813","path":"share/vizd/config/config_debug.ini","line_range":"1-126","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"6fca2c5700dd39ca35022a36a9d989cf","path":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","line_range":"1-111","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"12ee4287ffb75b424c50950e8f5b2df5","path":"plugins/debug_node/plugin.cpp","line_range":"1-668","gmt_create":"2026-04-28T19:48:38.857976+04:00","gmt_modified":"2026-04-28T19:48:38.857976+04:00"},{"id":"1bbdcbd551f6b6db613208a506ed663b","path":"programs/util/sign_transaction.cpp","line_range":"1-54","gmt_create":"2026-04-28T19:48:38.8589794+04:00","gmt_modified":"2026-04-28T19:48:38.8589794+04:00"},{"id":"fca351b915d815422a74e940fcde8cdb","path":"programs/util/sign_digest.cpp","line_range":"1-49","gmt_create":"2026-04-28T19:48:38.8589794+04:00","gmt_modified":"2026-04-28T19:48:38.8589794+04:00"},{"id":"07bbb44ee7833965e9eb8064c7dca3a5","path":"libraries/network/include/graphene/network/node.hpp","line_range":"1-200","gmt_create":"2026-04-28T19:48:38.8589794+04:00","gmt_modified":"2026-04-28T19:48:38.8589794+04:00"},{"id":"5dbe534429ba35b6a93bafccda79ab2b","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"1-200","gmt_create":"2026-04-28T19:48:38.8599791+04:00","gmt_modified":"2026-04-28T19:48:38.8599791+04:00"},{"id":"e4d3b0996d354976a0f8d7be27bba43f","path":"plugins/debug_node/plugin.cpp","line_range":"222-288","gmt_create":"2026-04-28T19:48:38.8599791+04:00","gmt_modified":"2026-04-28T19:48:38.8599791+04:00"},{"id":"073296e0c0907087372d72bd8ed5a30d","path":"plugins/debug_node/plugin.cpp","line_range":"321-420","gmt_create":"2026-04-28T19:48:38.8609791+04:00","gmt_modified":"2026-04-28T19:48:38.8609791+04:00"},{"id":"8a25fc8080abd566cbef2d584b42c23b","path":"plugins/debug_node/plugin.cpp","line_range":"489-555","gmt_create":"2026-04-28T19:48:38.8609791+04:00","gmt_modified":"2026-04-28T19:48:38.8609791+04:00"},{"id":"06bbb8421071aa4e70ada689b0e8d0de","path":"plugins/p2p/p2p_plugin.cpp","line_range":"118-170","gmt_create":"2026-04-28T19:48:38.8609791+04:00","gmt_modified":"2026-04-28T19:48:38.8609791+04:00"},{"id":"be7f7c455b691c95a3dd6a2789b92a2a","path":"plugins/debug_node/plugin.cpp","line_range":"489-511","gmt_create":"2026-04-28T19:48:38.8609791+04:00","gmt_modified":"2026-04-28T19:48:38.8609791+04:00"},{"id":"3e4f072495a91bf2b13739f1f9d95a9c","path":"plugins/debug_node/plugin.cpp","line_range":"321-372","gmt_create":"2026-04-28T19:48:38.8609791+04:00","gmt_modified":"2026-04-28T19:48:38.8609791+04:00"},{"id":"a31a8b940a678fa2f3d45d33ed52e2a8","path":"plugins/debug_node/plugin.cpp","line_range":"222-555","gmt_create":"2026-04-28T19:48:38.863177+04:00","gmt_modified":"2026-04-28T19:48:38.863177+04:00"},{"id":"b7b962f2d1cc506c60851cf76e545c68","path":"plugins/debug_node/plugin.cpp","line_range":"441-454","gmt_create":"2026-04-28T19:48:38.8637428+04:00","gmt_modified":"2026-04-28T19:48:38.8637428+04:00"},{"id":"5ad89d11099370a27a89a9f7d0346730","path":"plugins/debug_node/plugin.cpp","line_range":"422-430","gmt_create":"2026-04-28T19:48:38.8637428+04:00","gmt_modified":"2026-04-28T19:48:38.8637428+04:00"},{"id":"20bc4d17331e9bb80414df521e933386","path":"plugins/debug_node/plugin.cpp","line_range":"117-136","gmt_create":"2026-04-28T19:48:38.8637428+04:00","gmt_modified":"2026-04-28T19:48:38.8637428+04:00"},{"id":"1a03b72ef4884dc486a6cf695bdec9e1","path":"programs/util/sign_transaction.cpp","line_range":"28-53","gmt_create":"2026-04-28T19:48:38.8643339+04:00","gmt_modified":"2026-04-28T19:48:38.8643339+04:00"},{"id":"ececdaf0999d8a83addb93f95d0039d3","path":"programs/util/sign_digest.cpp","line_range":"26-48","gmt_create":"2026-04-28T19:48:38.8643339+04:00","gmt_modified":"2026-04-28T19:48:38.8643339+04:00"},{"id":"8e15df455552a1b9105a9a8b25797f1e","path":"plugins/p2p/p2p_plugin.cpp","line_range":"169-172","gmt_create":"2026-04-28T19:48:38.8658392+04:00","gmt_modified":"2026-04-28T19:48:38.8658392+04:00"},{"id":"9be51c5b9724dc743dc15a2758b6e4b2","path":"plugins/p2p/p2p_plugin.cpp","line_range":"605-652","gmt_create":"2026-04-28T19:48:38.8658392+04:00","gmt_modified":"2026-04-28T19:48:38.8658392+04:00"},{"id":"7232f04ac5a3f960659a84db72e3c8c6","path":"libraries/network/node.cpp","line_range":"79-83","gmt_create":"2026-04-28T19:48:38.8658392+04:00","gmt_modified":"2026-04-28T19:48:38.8658392+04:00"},{"id":"86b86c367842460e75e043fb87b0f88f","path":"libraries/network/node.cpp","line_range":"5091-5108","gmt_create":"2026-04-28T19:48:38.8658392+04:00","gmt_modified":"2026-04-28T19:48:38.8658392+04:00"},{"id":"d46277833fc133df8624346cd33cb6f3","path":"plugins/p2p/p2p_plugin.cpp","line_range":"298-365","gmt_create":"2026-04-28T19:48:38.866962+04:00","gmt_modified":"2026-04-28T19:48:38.866962+04:00"},{"id":"9178051ee4765210ad69eba44f39c87a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"521-530","gmt_create":"2026-04-28T19:48:38.866962+04:00","gmt_modified":"2026-04-28T19:48:38.866962+04:00"},{"id":"cd9f1eabe9bd89866fea8372b8de3fb2","path":"plugins/p2p/p2p_plugin.cpp","line_range":"605-686","gmt_create":"2026-04-28T19:48:38.8674647+04:00","gmt_modified":"2026-04-28T19:48:38.8674647+04:00"},{"id":"b988e082f7d48dc4995d1e872598437c","path":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","line_range":"40-41","gmt_create":"2026-04-28T19:48:38.868048+04:00","gmt_modified":"2026-04-28T19:48:38.868048+04:00"},{"id":"870cbffea14b19ef183293221413ec5c","path":"share/vizd/config/config_debug.ini","line_range":"36-47","gmt_create":"2026-04-28T19:48:38.8696234+04:00","gmt_modified":"2026-04-28T19:48:38.8696234+04:00"},{"id":"1448971e80d721aa1c85a46aea3da577","path":"share/vizd/config/config_debug.ini","line_range":"49-67","gmt_create":"2026-04-28T19:48:38.8696234+04:00","gmt_modified":"2026-04-28T19:48:38.8696234+04:00"},{"id":"d64fee9bc095b55a1d7636f437075323","path":"plugins/debug_node/plugin.cpp","line_range":"244-248","gmt_create":"2026-04-28T19:48:38.8726263+04:00","gmt_modified":"2026-04-28T19:48:38.8726263+04:00"},{"id":"076badf84cd673f3b9244504dca95861","path":"plugins/debug_node/plugin.cpp","line_range":"363-366","gmt_create":"2026-04-28T19:48:38.8736263+04:00","gmt_modified":"2026-04-28T19:48:38.8736263+04:00"},{"id":"a9154fa6ace3118ba37f67a132a8951a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"124-133","gmt_create":"2026-04-28T19:48:38.8736263+04:00","gmt_modified":"2026-04-28T19:48:38.8736263+04:00"},{"id":"d7d14eee16cef3e1cf0039ec5f52febf","path":"share/vizd/config/config_debug.ini","line_range":"107-126","gmt_create":"2026-04-28T19:48:38.8736263+04:00","gmt_modified":"2026-04-28T19:48:38.8736263+04:00"},{"id":"154f8101227c15750c6aa53260e9b84f","path":"plugins/debug_node/plugin.cpp","line_range":"374-420","gmt_create":"2026-04-28T19:48:38.8746264+04:00","gmt_modified":"2026-04-28T19:48:38.8746264+04:00"},{"id":"020b183f2967c754e5327defd9a63415","path":"documentation/debug_node_plugin.md","line_range":"50-134","gmt_create":"2026-04-28T19:48:38.8746264+04:00","gmt_modified":"2026-04-28T19:48:38.8746264+04:00"},{"id":"f7356b2eafc5252755db0df36458992f","path":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","line_range":"62-90","gmt_create":"2026-04-28T19:48:38.8746264+04:00","gmt_modified":"2026-04-28T19:48:38.8746264+04:00"},{"id":"82787c8d2e7394cf00fa87735394c3d5","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"72-95","gmt_create":"2026-04-28T20:32:44.1474859+04:00","gmt_modified":"2026-04-28T20:32:44.1474859+04:00"},{"id":"ab73f6cda0f4389d2bef214161afef81","path":"libraries/network/node.cpp","line_range":"593-601","gmt_create":"2026-04-28T20:32:44.1488964+04:00","gmt_modified":"2026-04-28T20:32:44.1488964+04:00"},{"id":"8caf3345fc407dc61382d80fab63bc93","path":"libraries/network/node.cpp","line_range":"5240-5274","gmt_create":"2026-04-28T20:32:44.1488964+04:00","gmt_modified":"2026-04-28T20:32:44.1488964+04:00"},{"id":"8e54da669dc427d415acec15fb6a804a","path":"plugins/snapshot/plugin.cpp","line_range":"3039-3045","gmt_create":"2026-04-28T20:32:44.1488964+04:00","gmt_modified":"2026-04-28T20:32:44.1488964+04:00"},{"id":"e6da7f673c730dddfe0373c2e796f71a","path":"libraries/chain/database.cpp","line_range":"1215-1246","gmt_create":"2026-04-28T20:32:44.1499023+04:00","gmt_modified":"2026-04-28T20:32:44.1499023+04:00"},{"id":"f02c5e6d0090d5de89e01b0a1d478c5c","path":"libraries/network/include/graphene/network/exceptions.hpp","line_range":"33-45","gmt_create":"2026-04-28T20:32:44.1499023+04:00","gmt_modified":"2026-04-28T20:32:44.1499023+04:00"},{"id":"f5f7d5764818ed749bc9b829f7aea2ff","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"1-386","gmt_create":"2026-04-28T20:32:44.1499023+04:00","gmt_modified":"2026-04-28T20:32:44.1499023+04:00"},{"id":"56968eec4c8adc4f9edd153c6ce9e231","path":"libraries/network/include/graphene/network/node.hpp","line_range":"1-374","gmt_create":"2026-04-28T20:32:44.1516513+04:00","gmt_modified":"2026-04-28T20:32:44.1516513+04:00"},{"id":"8923fae736f09b1cb255636af9a52069","path":"libraries/chain/database.cpp","line_range":"1-6389","gmt_create":"2026-04-28T20:32:44.1521543+04:00","gmt_modified":"2026-04-28T20:32:44.1521543+04:00"},{"id":"18382ca1b0f5cd7c4280e057d0242410","path":"libraries/network/include/graphene/network/exceptions.hpp","line_range":"1-49","gmt_create":"2026-04-28T20:32:44.1521543+04:00","gmt_modified":"2026-04-28T20:32:44.1521543+04:00"},{"id":"a41d1e5edd6d2706424bcd3b39295264","path":"libraries/network/peer_connection.cpp","line_range":"68-162","gmt_create":"2026-04-28T20:32:44.1537603+04:00","gmt_modified":"2026-04-28T20:32:44.1537603+04:00"},{"id":"3de0360b8d19b4e6a521e737d44e1eec","path":"libraries/network/message_oriented_connection.cpp","line_range":"128-140","gmt_create":"2026-04-28T20:32:44.1537603+04:00","gmt_modified":"2026-04-28T20:32:44.1537603+04:00"},{"id":"df02d50a1fa9064e2cfe4b033b6ecfc8","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"233-306","gmt_create":"2026-04-28T20:32:44.1547962+04:00","gmt_modified":"2026-04-28T20:32:44.1547962+04:00"},{"id":"c32e26ac2223fcbd9ec8280f135d338c","path":"libraries/network/message_oriented_connection.cpp","line_range":"135-140","gmt_create":"2026-04-28T20:32:44.1578223+04:00","gmt_modified":"2026-04-28T20:32:44.1578223+04:00"},{"id":"0543ad31da0059b627fc7cfd5bac0cad","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"233-272","gmt_create":"2026-04-28T20:32:44.1578223+04:00","gmt_modified":"2026-04-28T20:32:44.1578223+04:00"},{"id":"fa47faf491ab252556d3fc50f00c6a8d","path":"libraries/network/node.cpp","line_range":"662-718","gmt_create":"2026-04-28T20:32:44.1583243+04:00","gmt_modified":"2026-04-28T20:32:44.1583243+04:00"},{"id":"09cde54d90657149861df59444b291ba","path":"libraries/network/peer_connection.cpp","line_range":"244-338","gmt_create":"2026-04-28T20:32:44.1597444+04:00","gmt_modified":"2026-04-28T20:32:44.1597444+04:00"},{"id":"e3f78790c3dfc7c45569ce78697bf9ef","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"240-278","gmt_create":"2026-04-28T20:32:44.1597444+04:00","gmt_modified":"2026-04-28T20:32:44.1597444+04:00"},{"id":"5212be0912badd41a65263c4ef5ab6fc","path":"libraries/network/message_oriented_connection.cpp","line_range":"237-283","gmt_create":"2026-04-28T20:32:44.1597444+04:00","gmt_modified":"2026-04-28T20:32:44.1597444+04:00"},{"id":"8743a349115da7520b9567a7d855ca18","path":"libraries/network/message_oriented_connection.cpp","line_range":"148-235","gmt_create":"2026-04-28T20:32:44.1597444+04:00","gmt_modified":"2026-04-28T20:32:44.1597444+04:00"},{"id":"8c4475690fa2dd5b99756637ea5c7358","path":"libraries/network/peer_connection.cpp","line_range":"356-369","gmt_create":"2026-04-28T20:32:44.1639126+04:00","gmt_modified":"2026-04-28T20:32:44.1639126+04:00"},{"id":"c71708bd330ca79e1ba386a1763f5154","path":"libraries/network/node.cpp","line_range":"718-740","gmt_create":"2026-04-28T20:32:44.1639126+04:00","gmt_modified":"2026-04-28T20:32:44.1639126+04:00"},{"id":"9aacd835d38b395734ce6c87619ff59b","path":"libraries/network/node.cpp","line_range":"5272-5274","gmt_create":"2026-04-28T20:32:44.1649088+04:00","gmt_modified":"2026-04-28T20:32:44.1649088+04:00"},{"id":"a1b4ebbf3bdbfda373c476ae64175283","path":"libraries/network/peer_connection.cpp","line_range":"169-242","gmt_create":"2026-04-28T20:32:44.1649088+04:00","gmt_modified":"2026-04-28T20:32:44.1649088+04:00"},{"id":"179c82a5b5dc0ef88ef0f3d348aeabf7","path":"libraries/network/peer_connection.cpp","line_range":"310-338","gmt_create":"2026-04-28T20:32:44.1659092+04:00","gmt_modified":"2026-04-28T20:32:44.1659092+04:00"},{"id":"50fe97d449649d053646df017c7d5108","path":"libraries/network/peer_connection.cpp","line_range":"255-308","gmt_create":"2026-04-28T20:32:44.1659092+04:00","gmt_modified":"2026-04-28T20:32:44.1659092+04:00"},{"id":"707909d344d5db986aaec2161fe7ec64","path":"libraries/network/include/graphene/network/config.hpp","line_range":"58-58","gmt_create":"2026-04-28T20:32:44.1659092+04:00","gmt_modified":"2026-04-28T20:32:44.1659092+04:00"},{"id":"b07239f8068fdc811cbe0313fbee8a56","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"175-279","gmt_create":"2026-04-28T20:32:44.1676511+04:00","gmt_modified":"2026-04-28T20:32:44.1676511+04:00"},{"id":"89fa671fe61671f5b5ab01a94646d7a3","path":"libraries/network/peer_connection.cpp","line_range":"428-480","gmt_create":"2026-04-28T20:32:44.1676511+04:00","gmt_modified":"2026-04-28T20:32:44.1676511+04:00"},{"id":"f57a019298b7b9496ef4f4a85f921f75","path":"libraries/network/include/graphene/network/peer_database.hpp","line_range":"47-71","gmt_create":"2026-04-28T20:32:44.1681537+04:00","gmt_modified":"2026-04-28T20:32:44.1681537+04:00"},{"id":"228fc59a5268956db45d2f696afd5586","path":"libraries/network/node.cpp","line_range":"518-526","gmt_create":"2026-04-28T20:32:44.1685282+04:00","gmt_modified":"2026-04-28T20:32:44.1685282+04:00"},{"id":"8f4a83adbe444c72194effc3001fe32c","path":"libraries/network/node.cpp","line_range":"5265-5274","gmt_create":"2026-04-28T20:32:44.1691095+04:00","gmt_modified":"2026-04-28T20:32:44.1691095+04:00"},{"id":"4488509fca59b45f940f83b5db6daa2a","path":"libraries/network/node.cpp","line_range":"3874-3908","gmt_create":"2026-04-28T20:32:44.1696126+04:00","gmt_modified":"2026-04-28T20:32:44.1696126+04:00"},{"id":"313eca37529d6d0a87af6db00b3cae76","path":"libraries/network/node.cpp","line_range":"3598-3626","gmt_create":"2026-04-28T20:32:44.1696126+04:00","gmt_modified":"2026-04-28T20:32:44.1696126+04:00"},{"id":"88cfd8edcbcced125d9358898750ad6a","path":"plugins/p2p/p2p_plugin.cpp","line_range":"172-182","gmt_create":"2026-04-28T20:32:44.1707128+04:00","gmt_modified":"2026-04-28T20:32:44.1707128+04:00"},{"id":"3442c112ec40ff3a7ce211827dd731fb","path":"libraries/network/node.cpp","line_range":"599-600","gmt_create":"2026-04-28T20:32:44.1707128+04:00","gmt_modified":"2026-04-28T20:32:44.1707128+04:00"},{"id":"d2465d6814378cac309bb4813312e463","path":"libraries/network/node.cpp","line_range":"4472-4479","gmt_create":"2026-04-28T20:32:44.1725426+04:00","gmt_modified":"2026-04-28T20:32:44.1725426+04:00"},{"id":"028e9730d5a18007052fca00e208de6c","path":"libraries/network/node.cpp","line_range":"5016-5021","gmt_create":"2026-04-28T20:32:44.1730455+04:00","gmt_modified":"2026-04-28T20:32:44.1730455+04:00"},{"id":"22da7c51b4640e33df6b1774de67e615","path":"libraries/network/peer_database.cpp","line_range":"120-137","gmt_create":"2026-04-28T20:32:44.1730455+04:00","gmt_modified":"2026-04-28T20:32:44.1730455+04:00"},{"id":"0ff96f9f66fe11cb2bba96b2257c56cc","path":"libraries/network/node.cpp","line_range":"5013-5014","gmt_create":"2026-04-28T20:32:44.1740487+04:00","gmt_modified":"2026-04-28T20:32:44.1740487+04:00"},{"id":"f6e4014b53decf8540f03050dcb248a7","path":"libraries/network/node.cpp","line_range":"3061-3062","gmt_create":"2026-04-28T20:32:44.1740487+04:00","gmt_modified":"2026-04-28T20:32:44.1740487+04:00"},{"id":"3a3515773dce3d23274f19f11b24b8a1","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"279-283","gmt_create":"2026-04-28T20:32:44.1751837+04:00","gmt_modified":"2026-04-28T20:32:44.1751837+04:00"},{"id":"bced6dc0057c5231cbd868d55b0f5331","path":"libraries/network/peer_connection.cpp","line_range":"340-354","gmt_create":"2026-04-28T20:32:44.1763468+04:00","gmt_modified":"2026-04-28T20:32:44.1763468+04:00"},{"id":"1496fd024a306e65ca11a1074f83e158","path":"libraries/network/peer_connection.cpp","line_range":"371-399","gmt_create":"2026-04-28T20:32:44.1763468+04:00","gmt_modified":"2026-04-28T20:32:44.1763468+04:00"},{"id":"e196c8cfa8e7dbe5852841c2e099bad5","path":"share/vizd/config/config.ini","line_range":"96-101","gmt_create":"2026-04-28T20:32:44.17685+04:00","gmt_modified":"2026-04-28T20:32:44.17685+04:00"},{"id":"c1db40762caab4c9462bb6bc70748152","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"26-45","gmt_create":"2026-04-28T20:32:44.1798586+04:00","gmt_modified":"2026-04-28T20:32:44.1798586+04:00"},{"id":"973153247aad2260b57a9e4842ddfeb7","path":"libraries/network/include/graphene/network/message_oriented_connection.hpp","line_range":"26-28","gmt_create":"2026-04-28T20:32:44.1798586+04:00","gmt_modified":"2026-04-28T20:32:44.1798586+04:00"},{"id":"37d9a1a0250d6f2b30d0b5acfef7b606","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"26-35","gmt_create":"2026-04-28T20:32:44.1808586+04:00","gmt_modified":"2026-04-28T20:32:44.1808586+04:00"},{"id":"9fbb8ea1084712b6e00c9f6b9ad60c72","path":"libraries/network/include/graphene/network/node.hpp","line_range":"26-31","gmt_create":"2026-04-28T20:32:44.1808586+04:00","gmt_modified":"2026-04-28T20:32:44.1808586+04:00"},{"id":"63f471b93ce70266253197686f8d7df6","path":"libraries/network/include/graphene/network/peer_database.hpp","line_range":"26-35","gmt_create":"2026-04-28T20:32:44.1815978+04:00","gmt_modified":"2026-04-28T20:32:44.1815978+04:00"},{"id":"f18f4bdd5e9956c9abb9a7a52882581a","path":"libraries/network/include/graphene/network/message.hpp","line_range":"26-31","gmt_create":"2026-04-28T20:32:44.1815978+04:00","gmt_modified":"2026-04-28T20:32:44.1815978+04:00"},{"id":"03beec6b648d43a165d35e195b3eb81e","path":"libraries/network/include/graphene/network/core_messages.hpp","line_range":"285-306","gmt_create":"2026-04-28T20:32:44.1841058+04:00","gmt_modified":"2026-04-28T20:32:44.1841058+04:00"},{"id":"8620e966ce1a76d2ab405f5a49743457","path":"libraries/network/include/graphene/network/config.hpp","line_range":"48-50","gmt_create":"2026-04-28T20:32:44.184706+04:00","gmt_modified":"2026-04-28T20:32:44.184706+04:00"},{"id":"d6ed83bad3a3124e13f09c4c1191b96a","path":"libraries/network/peer_connection.cpp","line_range":"314-325","gmt_create":"2026-04-28T20:32:44.1852092+04:00","gmt_modified":"2026-04-28T20:32:44.1852092+04:00"},{"id":"fcdabf2022a050e8a2414fb979f5c419","path":"libraries/network/node.cpp","line_range":"3448-3470","gmt_create":"2026-04-28T20:32:44.1852906+04:00","gmt_modified":"2026-04-28T20:32:44.1852906+04:00"},{"id":"70f9beafdbca4132e0349e28e51fcd6a","path":"libraries/chain/database.cpp","line_range":"1239-1241","gmt_create":"2026-04-28T20:32:44.1868738+04:00","gmt_modified":"2026-04-28T20:32:44.1868738+04:00"},{"id":"e4313416f9a67f60a9a17f977b2367f6","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","line_range":"86-86","gmt_create":"2026-04-28T20:32:44.1868738+04:00","gmt_modified":"2026-04-28T20:32:44.1868738+04:00"},{"id":"b0498790fa704db3f0e0545f4299a7ba","path":"libraries/network/node.cpp","line_range":"79-82","gmt_create":"2026-04-28T20:32:44.1868738+04:00","gmt_modified":"2026-04-28T20:32:44.1868738+04:00"},{"id":"34cf64d4d37824f3883c4c577708cd70","path":"libraries/network/node.cpp","line_range":"3278-3281","gmt_create":"2026-04-28T20:32:44.1868738+04:00","gmt_modified":"2026-04-28T20:32:44.1868738+04:00"},{"id":"9619a9ec94b261a592033e0c0b3be117","path":"libraries/network/node.cpp","line_range":"3633-3636","gmt_create":"2026-04-28T20:32:44.1878771+04:00","gmt_modified":"2026-04-28T20:32:44.1878771+04:00"},{"id":"99d4fcb1177774e0710d2bd69e6b48d3","path":"libraries/network/node.cpp","line_range":"3653-3656","gmt_create":"2026-04-28T20:32:44.1878771+04:00","gmt_modified":"2026-04-28T20:32:44.1878771+04:00"},{"id":"f652bd37bb37781168ae6561fb03f9b4","path":"libraries/network/node.cpp","line_range":"3671-3674","gmt_create":"2026-04-28T20:32:44.1878771+04:00","gmt_modified":"2026-04-28T20:32:44.1878771+04:00"},{"id":"1fc0915e82dd4c943724dcd2e29106cb","path":"plugins/p2p/p2p_plugin.cpp","line_range":"159-175","gmt_create":"2026-04-28T20:38:58.1508088+04:00","gmt_modified":"2026-04-28T20:38:58.1508088+04:00"},{"id":"b89fc00b26b800a29e1692b23ada0d56","path":"plugins/p2p/p2p_plugin.cpp","line_range":"168-172","gmt_create":"2026-04-28T20:38:58.1560489+04:00","gmt_modified":"2026-04-28T20:38:58.1560489+04:00"},{"id":"4c7480a472e5a837a77edfce9accd782","path":"libraries/chain/database.cpp","line_range":"1360-1380","gmt_create":"2026-04-28T20:42:58.7136976+04:00","gmt_modified":"2026-04-28T20:42:58.7136976+04:00"},{"id":"509be78f5e90ad720bc5cb62f8252773","path":"libraries/chain/database.cpp","line_range":"1204-1270","gmt_create":"2026-04-28T21:02:01.9400592+04:00","gmt_modified":"2026-04-28T21:02:01.9400592+04:00"},{"id":"2f3627b50fb7b7e496ab7f3d82bb011c","path":"plugins/witness/witness.cpp","line_range":"521-544","gmt_create":"2026-04-28T21:02:01.9400592+04:00","gmt_modified":"2026-04-28T21:02:01.9400592+04:00"},{"id":"2426f410a167c0334267f66a00c3b706","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"1-200","gmt_create":"2026-04-28T21:02:01.941062+04:00","gmt_modified":"2026-04-28T21:02:01.941062+04:00"},{"id":"13ad0bfb014506790d3eea0ac1e240eb","path":"plugins/witness/witness.cpp","line_range":"1-697","gmt_create":"2026-04-28T21:02:01.9420619+04:00","gmt_modified":"2026-04-28T21:02:01.9420619+04:00"},{"id":"adbfa85db79875fa5ba5450da427c626","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"110-124","gmt_create":"2026-04-28T21:02:01.9420619+04:00","gmt_modified":"2026-04-28T21:02:01.9420619+04:00"},{"id":"9f5944a7feb01c0c201e4a490c1c6d47","path":"libraries/chain/hardfork.d/12.hf","line_range":"1-7","gmt_create":"2026-04-28T21:02:01.9420619+04:00","gmt_modified":"2026-04-28T21:02:01.9420619+04:00"},{"id":"3697c4125ef62ecb76b9032b46a67ad2","path":"libraries/chain/fork_database.cpp","line_range":"33-92","gmt_create":"2026-04-28T21:02:01.9431433+04:00","gmt_modified":"2026-04-28T21:02:01.9431433+04:00"},{"id":"3ae8431619379889035afee8a7f98a96","path":"libraries/chain/database.cpp","line_range":"1300-1399","gmt_create":"2026-04-28T21:02:01.9442084+04:00","gmt_modified":"2026-04-28T21:02:01.9442084+04:00"},{"id":"4dbf49507663ef2d477a4e56e7ad4113","path":"libraries/chain/fork_database.cpp","line_range":"48-84","gmt_create":"2026-04-28T21:02:01.9453075+04:00","gmt_modified":"2026-04-28T21:02:01.9453075+04:00"},{"id":"a0f13c35d9ba18928ea0803560d59338","path":"libraries/chain/fork_database.cpp","line_range":"48-55","gmt_create":"2026-04-28T21:02:01.9453075+04:00","gmt_modified":"2026-04-28T21:02:01.9453075+04:00"},{"id":"78b7d2f924e066f18e5bf4ed42de6954","path":"libraries/chain/fork_database.cpp","line_range":"33-278","gmt_create":"2026-04-28T21:02:01.9458107+04:00","gmt_modified":"2026-04-28T21:02:01.9458107+04:00"},{"id":"f32c5cb0846168684a2574ccb17d2cd7","path":"libraries/chain/fork_database.cpp","line_range":"189-231","gmt_create":"2026-04-28T21:02:01.9468841+04:00","gmt_modified":"2026-04-28T21:02:01.9468841+04:00"},{"id":"7066405016bb2acea5a040cdac13b646","path":"libraries/chain/database.cpp","line_range":"1037-1177","gmt_create":"2026-04-28T21:02:01.94698+04:00","gmt_modified":"2026-04-28T21:02:01.94698+04:00"},{"id":"1c914e70d8a846e0ed416af007bd2b78","path":"libraries/chain/database.cpp","line_range":"259-294","gmt_create":"2026-04-28T21:02:01.948086+04:00","gmt_modified":"2026-04-28T21:02:01.948086+04:00"},{"id":"d2b082cb10acf9968b8eb975d61abc92","path":"libraries/chain/database.cpp","line_range":"4444-4533","gmt_create":"2026-04-28T21:02:01.948086+04:00","gmt_modified":"2026-04-28T21:02:01.948086+04:00"},{"id":"da4792d808b920542e8e3f85c533f97d","path":"plugins/p2p/p2p_plugin.cpp","line_range":"118-164","gmt_create":"2026-04-28T21:02:01.9490892+04:00","gmt_modified":"2026-04-28T21:02:01.9490892+04:00"},{"id":"fb711bedba071dd61482af3dd825bb98","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"115-128","gmt_create":"2026-04-28T21:02:01.9490892+04:00","gmt_modified":"2026-04-28T21:02:01.9490892+04:00"},{"id":"83d7c3cd276c8b6c3a77f6379e8968e4","path":"libraries/chain/database.cpp","line_range":"561-580","gmt_create":"2026-04-28T21:02:01.9500444+04:00","gmt_modified":"2026-04-28T21:02:01.9500444+04:00"},{"id":"420ba4d931c9392dd8824c0faaf3b99b","path":"libraries/chain/database.cpp","line_range":"738-792","gmt_create":"2026-04-28T21:02:01.9500444+04:00","gmt_modified":"2026-04-28T21:02:01.9500444+04:00"},{"id":"fc699eb749d790d44345a92dd356956e","path":"libraries/chain/database.cpp","line_range":"206-230","gmt_create":"2026-04-28T21:02:01.9505472+04:00","gmt_modified":"2026-04-28T21:02:01.9505472+04:00"},{"id":"217f231a3e1f1591acfb14f4b40fb2b3","path":"libraries/chain/database.cpp","line_range":"476-515","gmt_create":"2026-04-28T21:02:01.9506352+04:00","gmt_modified":"2026-04-28T21:02:01.9506352+04:00"},{"id":"b25bd7f79844225b0a1356e5a6dbee8b","path":"libraries/chain/fork_database.cpp","line_range":"92-103","gmt_create":"2026-04-28T21:02:01.9517314+04:00","gmt_modified":"2026-04-28T21:02:01.9517314+04:00"},{"id":"447323529866a4410bcb34a227ea5b5a","path":"libraries/chain/database.cpp","line_range":"1075-1087","gmt_create":"2026-04-28T21:02:01.9517314+04:00","gmt_modified":"2026-04-28T21:02:01.9517314+04:00"},{"id":"d59a4116db64f54b5d2ce9c64e1c2c50","path":"libraries/chain/database.cpp","line_range":"4581-4594","gmt_create":"2026-04-28T21:02:01.9517314+04:00","gmt_modified":"2026-04-28T21:02:01.9517314+04:00"},{"id":"aa98d4cf2cd33ba5c1e2a0fee44c3645","path":"plugins/witness/witness.cpp","line_range":"597-612","gmt_create":"2026-04-28T21:02:01.9527344+04:00","gmt_modified":"2026-04-28T21:02:01.9527344+04:00"},{"id":"a8acea32ccb60d16cf2952aa7df51926","path":"libraries/chain/database.cpp","line_range":"4334-4438","gmt_create":"2026-04-28T21:02:01.9527344+04:00","gmt_modified":"2026-04-28T21:02:01.9527344+04:00"},{"id":"cda8d76def01f28cd58e347939faf10a","path":"libraries/chain/database.cpp","line_range":"4420-4438","gmt_create":"2026-04-28T21:02:01.9527344+04:00","gmt_modified":"2026-04-28T21:02:01.9527344+04:00"},{"id":"119ec7c643a34aa808f9d5b76965a662","path":"libraries/chain/database.cpp","line_range":"4444-4450","gmt_create":"2026-04-28T21:02:01.9527344+04:00","gmt_modified":"2026-04-28T21:02:01.9527344+04:00"},{"id":"9d352185df5c8af06a8101e30a248ef8","path":"libraries/chain/database.cpp","line_range":"4360-4398","gmt_create":"2026-04-28T21:02:01.9537343+04:00","gmt_modified":"2026-04-28T21:02:01.9537343+04:00"},{"id":"315cdb5412a417207b9932317c120c97","path":"libraries/chain/database.cpp","line_range":"4400-4419","gmt_create":"2026-04-28T21:02:01.9537343+04:00","gmt_modified":"2026-04-28T21:02:01.9537343+04:00"},{"id":"450f29f1b3febed1e121639037851576","path":"plugins/witness/witness.cpp","line_range":"521-526","gmt_create":"2026-04-28T21:02:01.9537343+04:00","gmt_modified":"2026-04-28T21:02:01.9537343+04:00"},{"id":"17c7b337a56de7a5cd94cd10c3d44dac","path":"libraries/chain/database.cpp","line_range":"4428-4430","gmt_create":"2026-04-28T21:02:01.954817+04:00","gmt_modified":"2026-04-28T21:02:01.954817+04:00"},{"id":"48593fdf91cfb9e4763322dc0efe26f4","path":"plugins/witness/witness.cpp","line_range":"565-656","gmt_create":"2026-04-28T21:02:01.954817+04:00","gmt_modified":"2026-04-28T21:02:01.954817+04:00"},{"id":"b71278e4b4266bb8a15b6aba152b2962","path":"plugins/witness/witness.cpp","line_range":"121","gmt_create":"2026-04-28T21:02:01.9553197+04:00","gmt_modified":"2026-04-28T21:02:01.9553197+04:00"},{"id":"065d68f5f096b48e88dfb2982a30bcb6","path":"libraries/chain/fork_database.cpp","line_range":"114-146","gmt_create":"2026-04-28T21:02:01.9563228+04:00","gmt_modified":"2026-04-28T21:02:01.9563228+04:00"},{"id":"c2ea6047c89205fb8308a32ce5248eee","path":"libraries/chain/fork_database.cpp","line_range":"48-103","gmt_create":"2026-04-28T21:02:01.9616165+04:00","gmt_modified":"2026-04-28T21:02:01.9616165+04:00"},{"id":"811ab9cb3d00924a080202c009434d6e","path":"libraries/chain/database.cpp","line_range":"1254-1298","gmt_create":"2026-04-28T21:02:01.9616165+04:00","gmt_modified":"2026-04-28T21:02:01.9616165+04:00"},{"id":"33f7190f97ab910175bbc25c0d3288cc","path":"libraries/chain/fork_database.cpp","line_range":"38-46","gmt_create":"2026-04-28T21:02:01.9645537+04:00","gmt_modified":"2026-04-28T21:02:01.9645537+04:00"},{"id":"536ce91c592f598c4853f295a9a28e59","path":"libraries/chain/fork_database.cpp","line_range":"59-75","gmt_create":"2026-04-28T21:02:01.9650569+04:00","gmt_modified":"2026-04-28T21:02:01.9650569+04:00"},{"id":"49ed36643f75c3d722e6b1a2ff17d7e0","path":"libraries/chain/database.cpp","line_range":"1390-1465","gmt_create":"2026-04-28T21:02:01.9650569+04:00","gmt_modified":"2026-04-28T21:02:01.9650569+04:00"},{"id":"58d38a217f74656ded3587bd3c6f7dc1","path":"plugins/witness/witness.cpp","line_range":"614-646","gmt_create":"2026-04-28T21:02:01.9650569+04:00","gmt_modified":"2026-04-28T21:02:01.9650569+04:00"},{"id":"73975f89dd3f307861db3a250bbdd78c","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"36-200","gmt_create":"2026-04-28T21:03:48.5316429+04:00","gmt_modified":"2026-04-28T21:03:48.5316429+04:00"},{"id":"7624493910e6464a6ff493726bdeee9d","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"53-122","gmt_create":"2026-04-28T21:03:48.5322599+04:00","gmt_modified":"2026-04-28T21:03:48.5322599+04:00"},{"id":"945c89d3db9c4818f2b0a69c5686f53c","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"38-71","gmt_create":"2026-04-28T21:03:48.5322599+04:00","gmt_modified":"2026-04-28T21:03:48.5322599+04:00"},{"id":"6e1a4f8dfd8b1b6545342d2b70d91400","path":"libraries/chain/include/graphene/chain/block_summary_object.hpp","line_range":"19-42","gmt_create":"2026-04-28T21:03:48.5322599+04:00","gmt_modified":"2026-04-28T21:03:48.5322599+04:00"},{"id":"8fef9b15033051e7fdc3504d87a3d365","path":"libraries/network/node.cpp","line_range":"3354-3366","gmt_create":"2026-04-28T21:03:48.5328419+04:00","gmt_modified":"2026-04-28T21:03:48.5328419+04:00"},{"id":"eb846b95ed45c45ecbc3ee5ab1ebd24f","path":"plugins/p2p/p2p_plugin.cpp","line_range":"152-157","gmt_create":"2026-04-28T21:03:48.5328419+04:00","gmt_modified":"2026-04-28T21:03:48.5328419+04:00"},{"id":"5b3217d2dd702e5291fda9a14af9defe","path":"plugins/chain/plugin.cpp","line_range":"104-121","gmt_create":"2026-04-28T21:03:48.5333464+04:00","gmt_modified":"2026-04-28T21:03:48.5333464+04:00"},{"id":"b18325dfe4c9f546850aa53aae935765","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"193-196","gmt_create":"2026-04-28T21:03:48.535692+04:00","gmt_modified":"2026-04-28T21:03:48.535692+04:00"},{"id":"7f585b7ee9cce4a8ab1f33b5b34f7f81","path":"libraries/chain/database.cpp","line_range":"737-792","gmt_create":"2026-04-28T21:03:48.535692+04:00","gmt_modified":"2026-04-28T21:03:48.535692+04:00"},{"id":"a2dca3272c082a5aafb990a745f3fd75","path":"plugins/p2p/p2p_plugin.cpp","line_range":"142-174","gmt_create":"2026-04-28T21:03:48.5366953+04:00","gmt_modified":"2026-04-28T21:03:48.5366953+04:00"},{"id":"5256db9d4dcb3c7fd627ebb8f8547f74","path":"plugins/chain/plugin.cpp","line_range":"103-142","gmt_create":"2026-04-28T21:03:48.5366953+04:00","gmt_modified":"2026-04-28T21:03:48.5366953+04:00"},{"id":"6e54a9c0d543d98384d205535ead2c39","path":"libraries/chain/database.cpp","line_range":"800-925","gmt_create":"2026-04-28T21:03:48.5366953+04:00","gmt_modified":"2026-04-28T21:03:48.5366953+04:00"},{"id":"d2efa60ce77e110221f81af1427289e6","path":"libraries/chain/block_log.cpp","line_range":"195-226","gmt_create":"2026-04-28T21:03:48.5384867+04:00","gmt_modified":"2026-04-28T21:03:48.5384867+04:00"},{"id":"fdfd8e0c768f197ad065fbd7ffc0d0c1","path":"libraries/chain/block_log.cpp","line_range":"263-299","gmt_create":"2026-04-28T21:03:48.5384867+04:00","gmt_modified":"2026-04-28T21:03:48.5384867+04:00"},{"id":"5573208de1a8f72a275c35db65fc7bd8","path":"libraries/chain/database.cpp","line_range":"847-925","gmt_create":"2026-04-28T21:03:48.5423108+04:00","gmt_modified":"2026-04-28T21:03:48.5423108+04:00"},{"id":"2f1395bd486711cb5d7bc0cd80794c96","path":"libraries/chain/database.cpp","line_range":"3443-3500","gmt_create":"2026-04-28T21:03:48.5428819+04:00","gmt_modified":"2026-04-28T21:03:48.5428819+04:00"},{"id":"1c4d9b7ff7c2fd8f72e2d64d37f89138","path":"libraries/chain/database.cpp","line_range":"3723-3748","gmt_create":"2026-04-28T21:03:48.5428819+04:00","gmt_modified":"2026-04-28T21:03:48.5428819+04:00"},{"id":"a5660f23ac4e94b12f678a1bbc729490","path":"libraries/chain/database.cpp","line_range":"3750-3757","gmt_create":"2026-04-28T21:03:48.5428819+04:00","gmt_modified":"2026-04-28T21:03:48.5428819+04:00"},{"id":"54e518a8354b5d7fb8af8a31a68d3a41","path":"libraries/chain/database.cpp","line_range":"3759-3873","gmt_create":"2026-04-28T21:03:48.5433845+04:00","gmt_modified":"2026-04-28T21:03:48.5433845+04:00"},{"id":"bbb78af6252229f84570f752f6e862a7","path":"libraries/chain/database.cpp","line_range":"2824-2837","gmt_create":"2026-04-28T21:03:48.5434552+04:00","gmt_modified":"2026-04-28T21:03:48.5434552+04:00"},{"id":"a18ffbd92c9d4b692fc557c3652088aa","path":"libraries/chain/database.cpp","line_range":"2871-2884","gmt_create":"2026-04-28T21:03:48.5439578+04:00","gmt_modified":"2026-04-28T21:03:48.5439578+04:00"},{"id":"fce8b0371886adfbccd297ca25bedd14","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"185-187","gmt_create":"2026-04-28T21:03:48.5444769+04:00","gmt_modified":"2026-04-28T21:03:48.5444769+04:00"},{"id":"6f9d8d9e0dc35b4525248327639277c9","path":"libraries/chain/database.cpp","line_range":"3724-3748","gmt_create":"2026-04-28T21:03:48.5444769+04:00","gmt_modified":"2026-04-28T21:03:48.5444769+04:00"},{"id":"601b79126e6723e1b2405eb7e5f8be93","path":"libraries/chain/database.cpp","line_range":"270-300","gmt_create":"2026-04-28T21:03:48.5459287+04:00","gmt_modified":"2026-04-28T21:03:48.5459287+04:00"},{"id":"5f0e48d3f7fad098a67eed7a88dc6134","path":"libraries/chain/database.cpp","line_range":"250-257","gmt_create":"2026-04-28T21:03:48.5459287+04:00","gmt_modified":"2026-04-28T21:03:48.5459287+04:00"},{"id":"a0d3e919d8c2dcef090c5eb962daae1a","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"3-8","gmt_create":"2026-04-28T21:03:48.5481192+04:00","gmt_modified":"2026-04-28T21:03:48.5481192+04:00"},{"id":"54b31fbe33ef1eb12566c9f84fcf779d","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"3-18","gmt_create":"2026-04-28T21:03:48.5491225+04:00","gmt_modified":"2026-04-28T21:03:48.5491225+04:00"},{"id":"3503ce5765018277af90477a590846e3","path":"libraries/chain/include/graphene/chain/block_log.hpp","line_range":"3-9","gmt_create":"2026-04-28T21:03:48.5491225+04:00","gmt_modified":"2026-04-28T21:03:48.5491225+04:00"},{"id":"24fdd3fcf0b1451195e987e21e994f65","path":"libraries/chain/database.cpp","line_range":"804-823","gmt_create":"2026-04-28T21:03:48.5511255+04:00","gmt_modified":"2026-04-28T21:03:48.5511255+04:00"},{"id":"3758345d86110e6830e316917030c83c","path":"libraries/chain/database.cpp","line_range":"1-6669","gmt_create":"2026-04-28T22:02:38.4590665+04:00","gmt_modified":"2026-04-28T22:02:38.4590665+04:00"},{"id":"73a54c033320ed8363fc781d798df0be","path":"libraries/chain/database.cpp","line_range":"1420-1510","gmt_create":"2026-04-28T22:02:38.4631999+04:00","gmt_modified":"2026-04-28T22:02:38.4631999+04:00"},{"id":"21fa05f4a65dabefa29dcd9515e99399","path":"libraries/chain/database.cpp","line_range":"1432-1498","gmt_create":"2026-04-28T22:02:38.4631999+04:00","gmt_modified":"2026-04-28T22:02:38.4631999+04:00"},{"id":"67ee60a8299f84cdefc03cf72aeb2083","path":"thirdparty/fc/include/fc/exception/exception.hpp","line_range":"177-215","gmt_create":"2026-04-28T22:07:48.9822613+04:00","gmt_modified":"2026-04-28T22:07:48.9822613+04:00"},{"id":"6b69ae0fdd0cccce913fc2d7aaa732b0","path":"thirdparty/fc/src/exception.cpp","line_range":"166-186","gmt_create":"2026-04-28T22:07:48.9822613+04:00","gmt_modified":"2026-04-28T22:07:48.9822613+04:00"},{"id":"7df358ffe779de2ba25c910aced557fd","path":"libraries/protocol/include/graphene/protocol/exceptions.hpp","line_range":"21-46","gmt_create":"2026-04-28T22:07:48.9822613+04:00","gmt_modified":"2026-04-28T22:07:48.9822613+04:00"},{"id":"6fb08c879f27957a5d358cff4532c031","path":"libraries/chain/database.cpp","line_range":"1440-1500","gmt_create":"2026-04-28T22:07:49.0133794+04:00","gmt_modified":"2026-04-28T22:07:49.0133794+04:00"},{"id":"672cdc6d6a7b32cf5afabd6fdbce20d3","path":"libraries/network/node.cpp","line_range":"3540-3562","gmt_create":"2026-04-28T22:30:12.955321+04:00","gmt_modified":"2026-04-28T22:30:12.955321+04:00"},{"id":"4c8e75baa374d11c9e8793b8772d0db9","path":"libraries/network/node.cpp","line_range":"3920-3940","gmt_create":"2026-04-28T22:30:12.955321+04:00","gmt_modified":"2026-04-28T22:30:12.955321+04:00"},{"id":"a6bfdd40fb3a5836fbabdb5158fa34fe","path":"share/vizd/config/config.ini","line_range":"103-108","gmt_create":"2026-04-28T22:30:12.955321+04:00","gmt_modified":"2026-04-28T22:30:12.955321+04:00"},{"id":"209759d869965a0c3eba1e658fa84845","path":"plugins/p2p/p2p_plugin.cpp","line_range":"633-689","gmt_create":"2026-04-28T22:30:12.9593209+04:00","gmt_modified":"2026-04-28T22:30:12.9593209+04:00"},{"id":"3d75047030281d13fb2d55905e0c69c8","path":"plugins/chain/plugin.cpp","line_range":"183-649","gmt_create":"2026-04-29T06:59:11.2767199+04:00","gmt_modified":"2026-04-29T06:59:11.2767199+04:00"},{"id":"f75d35fc9523fc188eb18b8741e33f6d","path":"libraries/chain/database.cpp","line_range":"351-544","gmt_create":"2026-04-29T06:59:11.2772632+04:00","gmt_modified":"2026-04-29T06:59:11.2772632+04:00"},{"id":"22a0b873abfd87b49bc4ca088c641dcd","path":"plugins/snapshot/plugin.cpp","line_range":"3031-3118","gmt_create":"2026-04-29T06:59:11.2784558+04:00","gmt_modified":"2026-04-29T06:59:11.2784558+04:00"},{"id":"2568823f5e70aacc0929c3200c44c688","path":"plugins/chain/plugin.cpp","line_range":"1-694","gmt_create":"2026-04-29T06:59:11.2791061+04:00","gmt_modified":"2026-04-29T06:59:11.2791061+04:00"},{"id":"7171e5fb841e1d5c8e4435a9e0e75f56","path":"libraries/chain/database.cpp","line_range":"1-6314","gmt_create":"2026-04-29T06:59:11.2796088+04:00","gmt_modified":"2026-04-29T06:59:11.2796088+04:00"},{"id":"668e6362de53625901201e8370b90e80","path":"plugins/chain/include/graphene/plugins/chain/plugin.hpp","line_range":"21-124","gmt_create":"2026-04-29T06:59:11.2796088+04:00","gmt_modified":"2026-04-29T06:59:11.2796088+04:00"},{"id":"86f066e47903bbd61b02a545ae4e6551","path":"plugins/chain/plugin.cpp","line_range":"21-93","gmt_create":"2026-04-29T06:59:11.2801286+04:00","gmt_modified":"2026-04-29T06:59:11.2801286+04:00"},{"id":"9c28f276f937ea7573f48b90b8f92d7f","path":"plugins/chain/plugin.cpp","line_range":"103-183","gmt_create":"2026-04-29T06:59:11.2806462+04:00","gmt_modified":"2026-04-29T06:59:11.2806462+04:00"},{"id":"371ae6e78ddcaea6c7ab821b81b12e35","path":"plugins/chain/plugin.cpp","line_range":"650-666","gmt_create":"2026-04-29T06:59:11.2811934+04:00","gmt_modified":"2026-04-29T06:59:11.2811934+04:00"},{"id":"13058dc3cfe4c9f00b04c9e22c6c9b70","path":"plugins/chain/plugin.cpp","line_range":"197-272","gmt_create":"2026-04-29T06:59:11.2811934+04:00","gmt_modified":"2026-04-29T06:59:11.2811934+04:00"},{"id":"16a421cb814c03e0297d814e4c7fcbcf","path":"plugins/chain/plugin.cpp","line_range":"274-386","gmt_create":"2026-04-29T06:59:11.2817133+04:00","gmt_modified":"2026-04-29T06:59:11.2817133+04:00"},{"id":"e76a2e15b7d528b5eb96fad4fe23bd9c","path":"plugins/chain/plugin.cpp","line_range":"388-649","gmt_create":"2026-04-29T06:59:11.2817133+04:00","gmt_modified":"2026-04-29T06:59:11.2817133+04:00"},{"id":"2fa9c0e59e88a84f214e07f4a5eba712","path":"libraries/chain/database.cpp","line_range":"4253-4323","gmt_create":"2026-04-29T06:59:11.2822306+04:00","gmt_modified":"2026-04-29T06:59:11.2822306+04:00"},{"id":"e9a71b0c283c28e9108702f7ca2163f7","path":"libraries/chain/database.cpp","line_range":"4314-4323","gmt_create":"2026-04-29T06:59:11.2827407+04:00","gmt_modified":"2026-04-29T06:59:11.2827407+04:00"},{"id":"97ee13777a0aa5665ed9d742b01a6df1","path":"plugins/chain/plugin.cpp","line_range":"420-475","gmt_create":"2026-04-29T06:59:11.283867+04:00","gmt_modified":"2026-04-29T06:59:11.283867+04:00"},{"id":"bd4c9ed516dc18cb55f239f6feab6a30","path":"plugins/snapshot/plugin.cpp","line_range":"3031-3042","gmt_create":"2026-04-29T06:59:11.2843824+04:00","gmt_modified":"2026-04-29T06:59:11.2843824+04:00"},{"id":"284384a88a8e22967e75aef3b6e3562e","path":"plugins/chain/plugin.cpp","line_range":"566-649","gmt_create":"2026-04-29T06:59:11.2848966+04:00","gmt_modified":"2026-04-29T06:59:11.2848966+04:00"},{"id":"00e1ac390ce60cf05032160e029fc05c","path":"plugins/chain/plugin.cpp","line_range":"344-382","gmt_create":"2026-04-29T06:59:11.2854101+04:00","gmt_modified":"2026-04-29T06:59:11.2854101+04:00"},{"id":"759a8a5afbc2bd120cc23c1a54071c79","path":"plugins/snapshot/plugin.cpp","line_range":"2817-2861","gmt_create":"2026-04-29T06:59:11.2854101+04:00","gmt_modified":"2026-04-29T06:59:11.2854101+04:00"},{"id":"4370e8763bbca8a166f9af80993701e9","path":"plugins/snapshot/plugin.cpp","line_range":"2908-2920","gmt_create":"2026-04-29T06:59:11.2859241+04:00","gmt_modified":"2026-04-29T06:59:11.2859241+04:00"},{"id":"8c0eb1fd78ceb38fa43fd2a1b7f10412","path":"plugins/chain/plugin.cpp","line_range":"105-121","gmt_create":"2026-04-29T06:59:11.2869502+04:00","gmt_modified":"2026-04-29T06:59:11.2869502+04:00"},{"id":"a4377fbb29614b9499ed7cba50185337","path":"thirdparty/fc/src/log/console_appender.cpp","line_range":"71-84","gmt_create":"2026-04-29T06:59:11.2869502+04:00","gmt_modified":"2026-04-29T06:59:11.2869502+04:00"},{"id":"9d89f7774c243fa2dcd1a6b44f750558","path":"thirdparty/fc/src/log/console_defines.h","line_range":"146-188","gmt_create":"2026-04-29T06:59:11.2874695+04:00","gmt_modified":"2026-04-29T06:59:11.2874695+04:00"},{"id":"8a80f90958428689e890e5b0a8e84f60","path":"thirdparty/fc/src/log/logger_config.cpp","line_range":"69-89","gmt_create":"2026-04-29T06:59:11.2874695+04:00","gmt_modified":"2026-04-29T06:59:11.2874695+04:00"},{"id":"65bbe0fb033855becef1089d08ed50bf","path":"programs/vizd/main.cpp","line_range":"234-250","gmt_create":"2026-04-29T06:59:11.2879852+04:00","gmt_modified":"2026-04-29T06:59:11.2879852+04:00"},{"id":"37d1a2d00fcd56aea0848ebca3f2a926","path":"plugins/chain/plugin.cpp","line_range":"757-816","gmt_create":"2026-04-29T06:59:11.2879852+04:00","gmt_modified":"2026-04-29T06:59:11.2879852+04:00"},{"id":"621d366163e32d2a00e77366a0cca1ea","path":"plugins/chain/plugin.cpp","line_range":"547-600","gmt_create":"2026-04-29T06:59:11.2879852+04:00","gmt_modified":"2026-04-29T06:59:11.2879852+04:00"},{"id":"be8f40bd072828763bbdf031b6f1620e","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","line_range":"122","gmt_create":"2026-04-29T06:59:11.2885025+04:00","gmt_modified":"2026-04-29T06:59:11.2885025+04:00"},{"id":"db43b1af690cc5f915a6971cef72f698","path":"plugins/chain/plugin.cpp","line_range":"1-12","gmt_create":"2026-04-29T06:59:11.2890192+04:00","gmt_modified":"2026-04-29T06:59:11.2890192+04:00"},{"id":"46d15c6ef6c17169ac51cbdc06ed7053","path":"plugins/chain/include/graphene/plugins/chain/plugin.hpp","line_range":"23-24","gmt_create":"2026-04-29T06:59:11.2890192+04:00","gmt_modified":"2026-04-29T06:59:11.2890192+04:00"},{"id":"2727250a5ed0225f9707859ab095dfe8","path":"plugins/chain/plugin.cpp","line_range":"92-105","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":"9bf43751ce7ff4f9e6f159edc4314caf","path":"plugins/chain/plugin.cpp","line_range":"24-51","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":"0cd78f3f9caeaceed6acf82a3b374de0","path":"plugins/chain/plugin.cpp","line_range":"398-418","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":"c0c7e7261cd9841beac6c26b47f47cf6","path":"plugins/chain/plugin.cpp","line_range":"562-601","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":"a8aa23bf7495e9cc8c7a2560a6157222","path":"plugins/chain/plugin.cpp","line_range":"251-271","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":"a7270a78978a13ee55ddc7f94813e3df","path":"libraries/chain/database.cpp","line_range":"1680-1693","gmt_create":"2026-04-29T07:04:36.8236407+04:00","gmt_modified":"2026-04-29T07:04:36.8236407+04:00"},{"id":"a7f5c35a309d6a9851c0491c125c63d9","path":"libraries/chain/database.cpp","line_range":"3224-3236","gmt_create":"2026-04-29T07:04:36.8236407+04:00","gmt_modified":"2026-04-29T07:04:36.8236407+04:00"},{"id":"2f5c46c8352dc73f0b90e01cef1bcc9d","path":"libraries/chain/database.cpp","line_range":"3272-3284","gmt_create":"2026-04-29T07:04:36.8243301+04:00","gmt_modified":"2026-04-29T07:04:36.8243301+04:00"},{"id":"26495d5b0fffb6fefe7f8c69d291521e","path":"plugins/witness/witness.cpp","line_range":"738-742","gmt_create":"2026-04-29T07:04:36.8243301+04:00","gmt_modified":"2026-04-29T07:04:36.8243301+04:00"},{"id":"3bdfaf9a009f1c5236532831eedfa66b","path":"plugins/chain/plugin.cpp","line_range":"760-770","gmt_create":"2026-04-29T07:04:36.8243301+04:00","gmt_modified":"2026-04-29T07:04:36.8243301+04:00"},{"id":"943ef4fb5df40c9942aadddd7040bc7c","path":"libraries/chain/database.cpp","line_range":"4863-5004","gmt_create":"2026-04-29T22:58:12.6480888+04:00","gmt_modified":"2026-04-29T22:58:12.6480888+04:00"},{"id":"1273c494621ef1c9351fa8b783dc6ae6","path":"plugins/witness/witness.cpp","line_range":"422-427","gmt_create":"2026-04-29T22:58:12.649406+04:00","gmt_modified":"2026-04-29T22:58:12.649406+04:00"},{"id":"cf67769b74f5699e4a347dc2d7092ceb","path":"thirdparty/chainbase/include/chainbase/chainbase.hpp","line_range":"1097-1115","gmt_create":"2026-04-29T22:58:12.6499089+04:00","gmt_modified":"2026-04-29T22:58:12.6499089+04:00"},{"id":"ffdc85ed129bbf1af13ac8fb289ef5cc","path":"libraries/chain/database.cpp","line_range":"4887-4906","gmt_create":"2026-04-29T22:58:12.6537575+04:00","gmt_modified":"2026-04-29T22:58:12.6537575+04:00"},{"id":"c1530ddb1ea5d36cd757849d7b1bae47","path":"libraries/chain/database.cpp","line_range":"2614-2631","gmt_create":"2026-04-29T22:58:12.6558059+04:00","gmt_modified":"2026-04-29T22:58:12.6558059+04:00"},{"id":"e233bb5840d58fff00c516dfc7186b2f","path":"libraries/protocol/include/graphene/protocol/config.hpp","line_range":"125-128","gmt_create":"2026-04-29T22:58:12.6558059+04:00","gmt_modified":"2026-04-29T22:58:12.6558059+04:00"},{"id":"d2f89808b761a3c0eca43468d945f372","path":"libraries/chain/database.cpp","line_range":"1721","gmt_create":"2026-04-29T22:58:12.6575821+04:00","gmt_modified":"2026-04-29T22:58:12.6575821+04:00"},{"id":"2b851e123aa78f2afb16a52472781e64","path":"plugins/witness/witness.cpp","line_range":"228-233","gmt_create":"2026-04-29T23:00:33.6611122+04:00","gmt_modified":"2026-04-29T23:00:33.6611122+04:00"},{"id":"0c5e33130a4b0128f85c5ef5837b2837","path":"plugins/witness/witness.cpp","line_range":"338-407","gmt_create":"2026-04-29T23:00:33.6751487+04:00","gmt_modified":"2026-04-29T23:00:33.6751487+04:00"},{"id":"b4b9171ebcdf9b3750b66cea688f5e6b","path":"plugins/witness/witness.cpp","line_range":"411-419","gmt_create":"2026-04-29T23:00:33.6751487+04:00","gmt_modified":"2026-04-29T23:00:33.6751487+04:00"},{"id":"673f7fff8a03580c3caedc629fc67cd4","path":"libraries/chain/include/graphene/chain/database.hpp","line_range":"60","gmt_create":"2026-04-29T23:00:33.6751487+04:00","gmt_modified":"2026-04-29T23:00:33.6751487+04:00"},{"id":"dbf1a067fe97d23702c1dcb8e2df53b6","path":"libraries/chain/database.cpp","line_range":"1890-1892","gmt_create":"2026-04-29T23:00:33.6761486+04:00","gmt_modified":"2026-04-29T23:00:33.6761486+04:00"},{"id":"2ad181689b70c433e1ec262fbbedb608","path":"libraries/chain/database.cpp","line_range":"4536-4573","gmt_create":"2026-04-29T23:00:33.6762262+04:00","gmt_modified":"2026-04-29T23:00:33.6762262+04:00"},{"id":"73337c954cb4cc654d9a0b55b95b2480","path":"libraries/chain/database.cpp","line_range":"5530-5655","gmt_create":"2026-04-29T23:00:33.6762262+04:00","gmt_modified":"2026-04-29T23:00:33.6762262+04:00"},{"id":"8c1b3bca4f56b317e9e0acdb4be83a00","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"1-89","gmt_create":"2026-04-29T23:01:32.2785851+04:00","gmt_modified":"2026-04-29T23:01:32.2785851+04:00"},{"id":"a3ae1dbcc1c9bd6ef59dec7fb6a6e6be","path":"libraries/chain/dlt_block_log.cpp","line_range":"1-582","gmt_create":"2026-04-29T23:01:32.2801985+04:00","gmt_modified":"2026-04-29T23:01:32.2801985+04:00"},{"id":"445ddb5941dc16c8a6313b9ec556f75a","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","line_range":"35-89","gmt_create":"2026-04-29T23:01:32.282913+04:00","gmt_modified":"2026-04-29T23:01:32.282913+04:00"},{"id":"8d97625477363c05b9feab2d2cbb781b","path":"libraries/chain/dlt_block_log.cpp","line_range":"31-38","gmt_create":"2026-04-29T23:01:32.2889728+04:00","gmt_modified":"2026-04-29T23:01:32.2889728+04:00"},{"id":"1b89c3c75aec06d4b094f1f6692436f9","path":"libraries/chain/dlt_block_log.cpp","line_range":"59-66","gmt_create":"2026-04-29T23:01:32.2889728+04:00","gmt_modified":"2026-04-29T23:01:32.2889728+04:00"},{"id":"3f4e4b4d64c6750b34e1fe180b376017","path":"libraries/chain/dlt_block_log.cpp","line_range":"119-136","gmt_create":"2026-04-29T23:01:32.2894757+04:00","gmt_modified":"2026-04-29T23:01:32.2894757+04:00"},{"id":"1853975a7087e8a5073352a9a8ea53c6","path":"libraries/chain/dlt_block_log.cpp","line_range":"138-155","gmt_create":"2026-04-29T23:01:32.2897898+04:00","gmt_modified":"2026-04-29T23:01:32.2897898+04:00"},{"id":"23c70bfc8bc9d7d6ea64c01cbc8cfa74","path":"libraries/chain/dlt_block_log.cpp","line_range":"545-579","gmt_create":"2026-04-29T23:01:32.2936387+04:00","gmt_modified":"2026-04-29T23:01:32.2936387+04:00"},{"id":"57b5a41ba76b9bfcb250e93e89805515","path":"plugins/p2p/p2p_plugin.cpp","line_range":"761-765","gmt_create":"2026-04-29T23:01:32.2940378+04:00","gmt_modified":"2026-04-29T23:01:32.2940378+04:00"},{"id":"3397b02998da3d1df1abfc39e178cd35","path":"libraries/chain/dlt_block_log.cpp","line_range":"74-100","gmt_create":"2026-04-29T23:01:32.2982799+04:00","gmt_modified":"2026-04-29T23:01:32.2982799+04:00"},{"id":"dfc65f88824f860423d799827fdee7aa","path":"libraries/chain/dlt_block_log.cpp","line_range":"545-574","gmt_create":"2026-04-29T23:01:32.2982799+04:00","gmt_modified":"2026-04-29T23:01:32.2982799+04:00"},{"id":"443c70bf08a7229603f07d4b6e2ceb04","path":"libraries/chain/dlt_block_log.cpp","line_range":"304-369","gmt_create":"2026-04-29T23:01:32.2994015+04:00","gmt_modified":"2026-04-29T23:01:32.2994015+04:00"},{"id":"766ad50513305c2c4955788de08b2f70","path":"plugins/p2p/p2p_plugin.cpp","line_range":"757-765","gmt_create":"2026-04-29T23:01:32.3140419+04:00","gmt_modified":"2026-04-29T23:01:32.3140419+04:00"},{"id":"61447f1b270e050eaf1594622e8344cb","path":"libraries/chain/database.cpp","line_range":"303-357","gmt_create":"2026-04-30T07:13:19.6582717+04:00","gmt_modified":"2026-04-30T07:13:19.6582717+04:00"},{"id":"87460891e469970ebd1b4357e65a305d","path":"libraries/chain/database.cpp","line_range":"2561-2591","gmt_create":"2026-04-30T07:13:19.658785+04:00","gmt_modified":"2026-04-30T07:13:19.658785+04:00"},{"id":"e8bcacd1aeb9acccff2e7846bdb418ea","path":"libraries/chain/database.cpp","line_range":"2596-2612","gmt_create":"2026-04-30T07:13:19.658785+04:00","gmt_modified":"2026-04-30T07:13:19.658785+04:00"},{"id":"3addab2306735a8fd2b97c7337a752aa","path":"libraries/chain/database.cpp","line_range":"5473-5545","gmt_create":"2026-04-30T07:13:19.6598205+04:00","gmt_modified":"2026-04-30T07:13:19.6598205+04:00"},{"id":"cf15af9ccdfa43fad1c61be4c143bb9f","path":"libraries/chain/database.cpp","line_range":"5515-5529","gmt_create":"2026-04-30T07:13:19.6603381+04:00","gmt_modified":"2026-04-30T07:13:19.6603381+04:00"},{"id":"4e999921565c672e1c3f31f949a25803","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"128-150","gmt_create":"2026-04-30T07:19:20.4192293+04:00","gmt_modified":"2026-04-30T07:19:20.4192293+04:00"},{"id":"2f228d36a18a021f1d730c1fa50466da","path":"plugins/p2p/p2p_plugin.cpp","line_range":"739-760","gmt_create":"2026-04-30T07:19:20.4207886+04:00","gmt_modified":"2026-04-30T07:19:20.4207886+04:00"},{"id":"da0076fc30299f9f1dd09e50dc181609","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"1-168","gmt_create":"2026-04-30T07:19:20.4207886+04:00","gmt_modified":"2026-04-30T07:19:20.4207886+04:00"},{"id":"24e9e8b3ff6a7469a09e87e94f9832b8","path":"plugins/p2p/p2p_plugin.cpp","line_range":"735-771","gmt_create":"2026-04-30T07:19:20.422349+04:00","gmt_modified":"2026-04-30T07:19:20.422349+04:00"},{"id":"532021a3aea4c3d7bfe25231df5687c0","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"53-168","gmt_create":"2026-04-30T07:19:20.4229287+04:00","gmt_modified":"2026-04-30T07:19:20.4229287+04:00"},{"id":"32f0435e4c1faa3d0978c1dcac09d7ce","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"20-168","gmt_create":"2026-04-30T07:19:20.4250024+04:00","gmt_modified":"2026-04-30T07:19:20.4250024+04:00"},{"id":"de96a3aab8e8260a79d1b9c380481b26","path":"libraries/chain/include/graphene/chain/fork_database.hpp","line_range":"111-168","gmt_create":"2026-04-30T07:19:20.4250024+04:00","gmt_modified":"2026-04-30T07:19:20.4250024+04:00"},{"id":"cde5dc8aa90fe3ae3c802f8d7f235e74","path":"plugins/p2p/p2p_plugin.cpp","line_range":"762-770","gmt_create":"2026-04-30T07:19:20.4318176+04:00","gmt_modified":"2026-04-30T07:19:20.4318176+04:00"},{"id":"51d09407b23ce3234d4e1de6142dce78","path":"plugins/p2p/p2p_plugin.cpp","line_range":"739-771","gmt_create":"2026-04-30T07:19:20.4318176+04:00","gmt_modified":"2026-04-30T07:19:20.4318176+04:00"},{"id":"45d31a7a748eda3ea48f7df17810d4cb","path":"libraries/network/peer_connection.cpp","line_range":"419-448","gmt_create":"2026-04-30T07:20:23.7936849+04:00","gmt_modified":"2026-04-30T07:20:23.7936849+04:00"},{"id":"b06d8268387488f1ba89995b6c673d7f","path":"libraries/network/node.cpp","line_range":"1805-1865","gmt_create":"2026-04-30T07:20:23.7987029+04:00","gmt_modified":"2026-04-30T07:20:23.7987029+04:00"},{"id":"d1aff9a930eaeb19127cc400cd6df14b","path":"libraries/network/node.cpp","line_range":"5281-5320","gmt_create":"2026-04-30T07:20:23.7992062+04:00","gmt_modified":"2026-04-30T07:20:23.7992062+04:00"},{"id":"4f2bc001f6d8d7b016c08476699c545c","path":"libraries/network/node.cpp","line_range":"3396-3475","gmt_create":"2026-04-30T07:20:23.7992652+04:00","gmt_modified":"2026-04-30T07:20:23.7992652+04:00"},{"id":"a3ff28e788c1b6c8bf86034c0dc8dfec","path":"libraries/network/node.cpp","line_range":"3280-3351","gmt_create":"2026-04-30T07:20:23.7992652+04:00","gmt_modified":"2026-04-30T07:20:23.7992652+04:00"},{"id":"fa40cce63b48435566df6c01e8048d9f","path":"libraries/network/peer_connection.cpp","line_range":"428-448","gmt_create":"2026-04-30T07:20:23.7992652+04:00","gmt_modified":"2026-04-30T07:20:23.7992652+04:00"},{"id":"1029e6d2173388f17be8ad02924bec51","path":"libraries/network/node.cpp","line_range":"5321-5351","gmt_create":"2026-04-30T07:20:23.7992652+04:00","gmt_modified":"2026-04-30T07:20:23.7992652+04:00"},{"id":"9448259d344c27f9c6996ae60cf5aca0","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"276-298","gmt_create":"2026-04-30T07:20:23.7997683+04:00","gmt_modified":"2026-04-30T07:20:23.7997683+04:00"},{"id":"6e13c0b7bd5f1729508c365e49c421e2","path":"libraries/network/node.cpp","line_range":"3413-3428","gmt_create":"2026-04-30T07:20:23.802979+04:00","gmt_modified":"2026-04-30T07:20:23.802979+04:00"},{"id":"50f93c7183f911eb73a238f8bcc6a562","path":"libraries/network/node.cpp","line_range":"3355-3394","gmt_create":"2026-04-30T07:20:23.802979+04:00","gmt_modified":"2026-04-30T07:20:23.802979+04:00"},{"id":"90fd78bbe7cb7704cadf5d5f0735cb01","path":"libraries/network/node.cpp","line_range":"3334-3351","gmt_create":"2026-04-30T07:20:23.8034959+04:00","gmt_modified":"2026-04-30T07:20:23.8034959+04:00"},{"id":"3926b37345d6d1e98bd8faf06e492e48","path":"plugins/p2p/p2p_plugin.cpp","line_range":"722-771","gmt_create":"2026-04-30T07:26:56.344451+04:00","gmt_modified":"2026-04-30T07:26:56.344451+04:00"},{"id":"f00d25f601ba380af2e6c7e1cc5c9bd5","path":"libraries/chain/database.cpp","line_range":"1-6760","gmt_create":"2026-04-30T07:30:11.7801188+04:00","gmt_modified":"2026-04-30T07:30:11.7801188+04:00"},{"id":"02d86b87b26250b29b6e613abead3df4","path":"thirdparty/fc/src/stacktrace.cpp","line_range":"1-78","gmt_create":"2026-04-30T07:30:11.7827475+04:00","gmt_modified":"2026-04-30T07:30:11.7827475+04:00"},{"id":"b730f8795ffebcda8a8f085fd025dc0b","path":"thirdparty/fc/src/stacktrace.cpp","line_range":"72-78","gmt_create":"2026-04-30T07:30:11.7878598+04:00","gmt_modified":"2026-04-30T07:30:11.7878598+04:00"},{"id":"67e81d60b5109e19786b8bfbc4a80abd","path":"libraries/chain/database.cpp","line_range":"2281-2283","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"09f8b4a6f66776095afcdc7473efbaf2","path":"libraries/chain/database.cpp","line_range":"2466-2467","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"9a263f97b2eae42c0e192fb1cfee8776","path":"libraries/chain/database.cpp","line_range":"2526-2527","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"ea9495482bd4ecf48df793f9abf39cc1","path":"libraries/chain/database.cpp","line_range":"2536-2537","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"47d651650f297dcd4ffcf47ee28027f2","path":"libraries/chain/database.cpp","line_range":"4536-4537","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"5452e208808a1bd3d416cced7e6d6f0a","path":"libraries/chain/database.cpp","line_range":"4538-4539","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"5affc96a80f081a4ef8bd4b5177ef1a8","path":"libraries/chain/database.cpp","line_range":"4544-4545","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"dd981f6523bfe5386b3d4a97ca575fdf","path":"libraries/chain/database.cpp","line_range":"4567-4568","gmt_create":"2026-04-30T07:30:11.8080168+04:00","gmt_modified":"2026-04-30T07:30:11.8080168+04:00"},{"id":"e0ef3c7d489444d0a7bf6cd609a98c05","path":"libraries/chain/database.cpp","line_range":"4569-4570","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"13ee871790dddd2f670c1493c6665f41","path":"libraries/chain/database.cpp","line_range":"4571-4572","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"90331ddec7a3725739758ff2180d5b8e","path":"libraries/chain/database.cpp","line_range":"4573-4574","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"654c2896a03be742e37554a614a0244c","path":"libraries/chain/database.cpp","line_range":"5530-5531","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"e9e61fd4b1cf8706755eb1dfa541ccc7","path":"libraries/chain/database.cpp","line_range":"5543-5544","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"b7aaa429e07e8abc0d4999c4c496d854","path":"libraries/chain/database.cpp","line_range":"5677-5678","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"1f43be6f2eea9de96bd24d20b575c860","path":"libraries/chain/database.cpp","line_range":"5680-5681","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"d9dbf24fcc1a502e794d92f729bcd372","path":"plugins/witness/witness.cpp","line_range":"159-160","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"abeb5e992b22812a0cdfc0c3dca91067","path":"plugins/witness/witness.cpp","line_range":"338-340","gmt_create":"2026-04-30T07:30:11.8090159+04:00","gmt_modified":"2026-04-30T07:30:11.8090159+04:00"},{"id":"956e60e52272d2047c3d89d0f1fe96a3","path":"plugins/witness/witness.cpp","line_range":"356-357","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"70499ce1f567f2564154072ea2576c3b","path":"plugins/witness/witness.cpp","line_range":"403-405","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"aad86469ecab79c7481892069f6100df","path":"plugins/witness/witness.cpp","line_range":"411-412","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"57d63528cfa5d7410afabeee4a42845e","path":"plugins/witness/witness.cpp","line_range":"416-417","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"daa5dca768a6e2ed062d953de56c3dc6","path":"plugins/witness/witness.cpp","line_range":"418-419","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"f0fa917f2268095d00a5c33920129393","path":"thirdparty/fc/src/stacktrace.cpp","line_range":"48-78","gmt_create":"2026-04-30T07:30:11.8100159+04:00","gmt_modified":"2026-04-30T07:30:11.8100159+04:00"},{"id":"b372b2c20cc0d9d9abd9e2254bfefb17","path":"libraries/chain/dlt_block_log.cpp","line_range":"576-602","gmt_create":"2026-04-30T07:46:04.9316707+04:00","gmt_modified":"2026-04-30T07:46:04.9316707+04:00"},{"id":"a1ef6908e910771a074aa8ccbc10adef","path":"plugins/p2p/p2p_plugin.cpp","line_range":"773-795","gmt_create":"2026-04-30T07:47:41.3249647+04:00","gmt_modified":"2026-04-30T07:47:41.3249647+04:00"},{"id":"463f1a4ea4700713bc6ca4afa0c86f4f","path":"share/vizd/config/config.ini","line_range":"1-143","gmt_create":"2026-04-30T07:47:41.332047+04:00","gmt_modified":"2026-04-30T07:47:41.332047+04:00"},{"id":"321d8cd55620ec252c0b570fa95fd592","path":"libraries/chain/database.cpp","line_range":"5092-5105","gmt_create":"2026-04-30T08:00:09.9159109+04:00","gmt_modified":"2026-04-30T08:00:09.9159109+04:00"},{"id":"118584993a6d2e21fefe6c8f98dbe2f6","path":"libraries/chain/database.cpp","line_range":"5283-5297","gmt_create":"2026-04-30T08:00:09.9169083+04:00","gmt_modified":"2026-04-30T08:00:09.9169083+04:00"},{"id":"26650c218a6c596d28668797b6045c8c","path":"libraries/chain/database.cpp","line_range":"5616-5635","gmt_create":"2026-04-30T08:00:09.9169083+04:00","gmt_modified":"2026-04-30T08:00:09.9169083+04:00"},{"id":"82dadfd972805d70bffa99ce756460c4","path":"plugins/p2p/p2p_plugin.cpp","line_range":"307-327","gmt_create":"2026-04-30T08:47:09.8060145+04:00","gmt_modified":"2026-04-30T08:47:09.8060145+04:00"},{"id":"ee32480b501d0e9284fc1a7aa7d20b4c","path":"plugins/p2p/p2p_plugin.cpp","line_range":"1042-1113","gmt_create":"2026-04-30T08:47:09.8065171+04:00","gmt_modified":"2026-04-30T08:47:09.8065171+04:00"},{"id":"f12cdb54f6351fe38c307c4907f93868","path":"plugins/p2p/p2p_plugin.cpp","line_range":"783-791","gmt_create":"2026-04-30T08:47:09.814313+04:00","gmt_modified":"2026-04-30T08:47:09.814313+04:00"},{"id":"8c9490ebae702a4725d10dc509074042","path":"plugins/p2p/p2p_plugin.cpp","line_range":"812-816","gmt_create":"2026-04-30T08:47:09.814313+04:00","gmt_modified":"2026-04-30T08:47:09.814313+04:00"},{"id":"04677ace577bc003b34701bfd451a89d","path":"libraries/chain/dlt_block_log.cpp","line_range":"523-543","gmt_create":"2026-04-30T11:11:44.1591074+04:00","gmt_modified":"2026-04-30T11:11:44.1591074+04:00"},{"id":"16437c2399403aa03ec5eb0bceca78b8","path":"plugins/p2p/p2p_plugin.cpp","line_range":"653-770","gmt_create":"2026-04-30T11:12:37.4404904+04:00","gmt_modified":"2026-04-30T11:12:37.4404904+04:00"},{"id":"d74767289d3d8b429633502bc075cc48","path":"plugins/p2p/p2p_plugin.cpp","line_range":"773-813","gmt_create":"2026-04-30T11:12:37.4404904+04:00","gmt_modified":"2026-04-30T11:12:37.4404904+04:00"},{"id":"5eaed48196ffe1d0e73f557aacdc6096","path":"plugins/p2p/p2p_plugin.cpp","line_range":"760-768","gmt_create":"2026-04-30T11:12:37.4404904+04:00","gmt_modified":"2026-04-30T11:12:37.4404904+04:00"},{"id":"18300366cc04c934739121e96aa33a18","path":"libraries/network/node.cpp","line_range":"2520-2590","gmt_create":"2026-04-30T12:37:20.9950535+04:00","gmt_modified":"2026-04-30T12:37:20.9950535+04:00"},{"id":"5c8f4ea594d62170eaa300eb27c60cab","path":"libraries/network/include/graphene/network/peer_connection.hpp","line_range":"285-289","gmt_create":"2026-04-30T12:37:20.9950535+04:00","gmt_modified":"2026-04-30T12:37:20.9950535+04:00"},{"id":"68421d68d4a7045f55767bcf48a402ad","path":"plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp","line_range":"11-48","gmt_create":"2026-04-30T12:39:24.14723+04:00","gmt_modified":"2026-04-30T12:39:24.14723+04:00"},{"id":"262c71a35dc67c134fb0ac33f44ffb3c","path":"plugins/witness_guard/witness_guard.cpp","line_range":"27-78","gmt_create":"2026-04-30T12:39:24.1477324+04:00","gmt_modified":"2026-04-30T12:39:24.1477324+04:00"},{"id":"2768582067cb0ed11345dd25d7b2a582","path":"plugins/witness_guard/witness_guard.cpp","line_range":"83-191","gmt_create":"2026-04-30T12:39:24.1493137+04:00","gmt_modified":"2026-04-30T12:39:24.1493137+04:00"},{"id":"9bfd91580e85c0c0436b214ea3ff332a","path":"plugins/witness_guard/witness_guard.cpp","line_range":"360-369","gmt_create":"2026-04-30T12:39:24.1498381+04:00","gmt_modified":"2026-04-30T12:39:24.1498381+04:00"},{"id":"f82119bed73a4a0e0870145102b96214","path":"plugins/witness_guard/witness_guard.cpp","line_range":"455-544","gmt_create":"2026-04-30T12:39:24.1515583+04:00","gmt_modified":"2026-04-30T12:39:24.1515583+04:00"},{"id":"410cd37dc3943354d37ce7542843e6c0","path":"plugins/witness_guard/witness_guard.cpp","line_range":"301-328","gmt_create":"2026-04-30T12:39:24.1536407+04:00","gmt_modified":"2026-04-30T12:39:24.1536407+04:00"},{"id":"804dc1cd57f82825de2acc450a8496c3","path":"plugins/witness_guard/witness_guard.cpp","line_range":"330-408","gmt_create":"2026-04-30T12:39:24.1536407+04:00","gmt_modified":"2026-04-30T12:39:24.1536407+04:00"},{"id":"9ea04ad05deddb408f8a972fd04ba0d0","path":"share/vizd/config/config_witness.ini","line_range":"128-141","gmt_create":"2026-04-30T12:39:24.1556439+04:00","gmt_modified":"2026-04-30T12:39:24.1556439+04:00"},{"id":"f46e3fd7859017b5e2c1e7b5c296cb4f","path":"plugins/witness_guard/witness_guard.cpp","line_range":"197-246","gmt_create":"2026-04-30T12:39:24.1682132+04:00","gmt_modified":"2026-04-30T12:39:24.1682132+04:00"},{"id":"9d47a587156b7ae6cd73b0e5b5ad4f56","path":"plugins/witness_guard/witness_guard.cpp","line_range":"252-294","gmt_create":"2026-04-30T12:39:24.1682132+04:00","gmt_modified":"2026-04-30T12:39:24.1682132+04:00"},{"id":"322bbb26c4fa89c5b6c197da6defb3b0","path":"plugins/witness_guard/witness_guard.cpp","line_range":"301-408","gmt_create":"2026-04-30T12:39:24.1682132+04:00","gmt_modified":"2026-04-30T12:39:24.1682132+04:00"},{"id":"4c7449e318e56d7531d2b650c48cda91","path":"plugins/witness_guard/witness_guard.cpp","line_range":"410-555","gmt_create":"2026-04-30T12:39:24.1687158+04:00","gmt_modified":"2026-04-30T12:39:24.1687158+04:00"},{"id":"09dcfe86b88d969bbe651733cb34fc2d","path":"libraries/chain/include/graphene/chain/global_property_object.hpp","line_range":"139","gmt_create":"2026-04-30T12:39:24.173875+04:00","gmt_modified":"2026-04-30T12:39:24.173875+04:00"}],"knowledge_relations":[{"id":34629,"source_id":"448c0fd26faf791081a54cd407662e4d","target_id":"e6b951c57c5f8fb2b3553ce8db430760","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-55","gmt_create":"2026-04-28T09:55:13.582936+04:00","gmt_modified":"2026-04-28T09:55:13.582936+04:00"},{"id":34631,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"467b9030fcd47369d3417c84998c20d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 910-979","gmt_create":"2026-04-28T09:55:13.582936+04:00","gmt_modified":"2026-04-28T09:55:13.582936+04:00"},{"id":34633,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"cbfe85acce275b65a2edb3315aec2941","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 190-320","gmt_create":"2026-04-28T09:55:13.5839359+04:00","gmt_modified":"2026-04-28T09:55:13.5839359+04:00"},{"id":34635,"source_id":"448c0fd26faf791081a54cd407662e4d","target_id":"9e18fa1bdbee1d9c96d8437bfe20515c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-57","gmt_create":"2026-04-28T09:55:13.5864433+04:00","gmt_modified":"2026-04-28T09:55:13.5864433+04:00"},{"id":34637,"source_id":"f7be79ec222a56c210b7999322790a2f","target_id":"5dce2933cfb42430c2bbcdf0cacc25c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-49","gmt_create":"2026-04-28T09:55:13.5874434+04:00","gmt_modified":"2026-04-28T09:55:13.5874434+04:00"},{"id":34639,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"1b55f505ae64e9ea22be5142cfa67f93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-126","gmt_create":"2026-04-28T09:55:13.588443+04:00","gmt_modified":"2026-04-28T09:55:13.588443+04:00"},{"id":34641,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"8a161abeb389c25b1279bc23d6ff4e57","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 60-167","gmt_create":"2026-04-28T09:55:13.588443+04:00","gmt_modified":"2026-04-28T09:55:13.588443+04:00"},{"id":34643,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"f85f57d0c6b461ab78f906ef6d5854c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-354","gmt_create":"2026-04-28T09:55:13.5894427+04:00","gmt_modified":"2026-04-28T09:55:13.5894427+04:00"},{"id":34645,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"21076248fc123c7aacc8cb6e67cd0068","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 758-823","gmt_create":"2026-04-28T09:55:13.5904431+04:00","gmt_modified":"2026-04-28T09:55:13.5904431+04:00"},{"id":34647,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4e79c62ed5491dcd85510f3dab144813","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T09:55:13.5904431+04:00","gmt_modified":"2026-04-28T09:55:13.5904431+04:00"},{"id":34649,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"fe82427a3c86c02f05708734fa4c589c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 216-245","gmt_create":"2026-04-28T09:55:13.5924442+04:00","gmt_modified":"2026-04-28T09:55:13.5924442+04:00"},{"id":34651,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"15bc72540b02de4c57e4c976c8150f35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 855-865","gmt_create":"2026-04-28T09:55:13.5924442+04:00","gmt_modified":"2026-04-28T09:55:13.5924442+04:00"},{"id":34653,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"cd0a62c9a78bb77d3b59a9d5872577f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 82-106","gmt_create":"2026-04-28T09:55:13.5934435+04:00","gmt_modified":"2026-04-28T09:55:13.5934435+04:00"},{"id":34655,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"7eaff221b9d5916b8e18aa7786630566","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 188-218","gmt_create":"2026-04-28T09:55:13.5944434+04:00","gmt_modified":"2026-04-28T09:55:13.5944434+04:00"},{"id":34657,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"9ec3ef7b5beba7ccd4c8172983e359a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 247-301","gmt_create":"2026-04-28T09:55:13.5944434+04:00","gmt_modified":"2026-04-28T09:55:13.5944434+04:00"},{"id":34659,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"685c2a44fc90d96152180fc6a5a63df4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 129-208","gmt_create":"2026-04-28T09:55:13.5959468+04:00","gmt_modified":"2026-04-28T09:55:13.5959468+04:00"},{"id":34661,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"9ad98a7be17ee5186d08088816474c52","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 540-552","gmt_create":"2026-04-28T09:55:13.5969503+04:00","gmt_modified":"2026-04-28T09:55:13.5969503+04:00"},{"id":34663,"source_id":"ee77bf4eb6bfbfb3636aa0bd57416552","target_id":"a273323d20c428afec092114bb480a23","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1078-1115","gmt_create":"2026-04-28T09:55:13.5999505+04:00","gmt_modified":"2026-04-28T09:55:13.5999505+04:00"},{"id":34665,"source_id":"ee77bf4eb6bfbfb3636aa0bd57416552","target_id":"27c21c9dfb07f579bd0db9fa97c8fd19","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1130-1137","gmt_create":"2026-04-28T09:55:13.6009501+04:00","gmt_modified":"2026-04-28T09:55:13.6009501+04:00"},{"id":34667,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"3b4fd0aa5c9c47621979a050b80b5fc2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 173-208","gmt_create":"2026-04-28T09:55:13.6009501+04:00","gmt_modified":"2026-04-28T09:55:13.6009501+04:00"},{"id":34669,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"411e466fa1c626bc1fff0647607acabd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 151-156","gmt_create":"2026-04-28T09:55:13.6019502+04:00","gmt_modified":"2026-04-28T09:55:13.6019502+04:00"},{"id":34671,"source_id":"f7be79ec222a56c210b7999322790a2f","target_id":"8eb355e55d14f0a3eec62805ff783a2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-34","gmt_create":"2026-04-28T09:55:13.60295+04:00","gmt_modified":"2026-04-28T09:55:13.60295+04:00"},{"id":34673,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"4fc812a0df4303ac6e74df39697a0893","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-13","gmt_create":"2026-04-28T09:55:13.60295+04:00","gmt_modified":"2026-04-28T09:55:13.60295+04:00"},{"id":34675,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5870c5d584940972a4d3fe2081558f6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 659-756","gmt_create":"2026-04-28T09:55:13.6039501+04:00","gmt_modified":"2026-04-28T09:55:13.6039501+04:00"},{"id":34677,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"2c4431ca7f506fb549c312462fdb7a89","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 512-649","gmt_create":"2026-04-28T09:55:13.6039501+04:00","gmt_modified":"2026-04-28T09:55:13.6039501+04:00"},{"id":34679,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"ffb31b89372e5944d03cf7f549ce0151","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 659-683","gmt_create":"2026-04-28T09:55:13.60495+04:00","gmt_modified":"2026-04-28T09:55:13.60495+04:00"},{"id":34681,"source_id":"18555f254f50536a15d8591acf982406","target_id":"adf436395e284632e3b1ef4d74d647f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-136","gmt_create":"2026-04-28T09:55:13.60495+04:00","gmt_modified":"2026-04-28T09:55:13.60495+04:00"},{"id":34702,"source_id":"fcabf234b34f00b60b0d784b2da5a052","target_id":"cd8c02da5ea31d3411ad151149d2f64e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 63-92","gmt_create":"2026-04-28T09:57:03.8479631+04:00","gmt_modified":"2026-04-28T09:57:03.8479631+04:00"},{"id":34704,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"2d883d06f58fd34d81e8588c75185aa9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-68","gmt_create":"2026-04-28T09:57:03.8479631+04:00","gmt_modified":"2026-04-28T09:57:03.8479631+04:00"},{"id":34706,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"b6e11846d82ee129d5956cf9b8cbbea8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-118","gmt_create":"2026-04-28T09:57:03.8494864+04:00","gmt_modified":"2026-04-28T09:57:03.8494864+04:00"},{"id":34708,"source_id":"f8bd5a2c3a4664ae9d5ec472684610dc","target_id":"cda9a1d47dfdb3a7374fa817887892c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-98","gmt_create":"2026-04-28T09:57:03.8494864+04:00","gmt_modified":"2026-04-28T09:57:03.8494864+04:00"},{"id":34710,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"f5891db138d66a58674791b9e99bd337","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-28","gmt_create":"2026-04-28T09:57:03.8504899+04:00","gmt_modified":"2026-04-28T09:57:03.8504899+04:00"},{"id":34712,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"51169b91af554f837e41d2913dacad48","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-83","gmt_create":"2026-04-28T09:57:03.8504899+04:00","gmt_modified":"2026-04-28T09:57:03.8504899+04:00"},{"id":34714,"source_id":"cf72debd284e30d5218a88ae08868205","target_id":"5aed64f2f61be210a303b341a970b0cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-132","gmt_create":"2026-04-28T09:57:03.8514893+04:00","gmt_modified":"2026-04-28T09:57:03.8514893+04:00"},{"id":34716,"source_id":"bebd7920dd0967c6039c2adb16d4c52c","target_id":"47b98e10075d52a89428f617d837a5e5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 174-201","gmt_create":"2026-04-28T09:57:03.8524901+04:00","gmt_modified":"2026-04-28T09:57:03.8524901+04:00"},{"id":34718,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"42aa356d9e26fadf05fda749f1d89cff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-81","gmt_create":"2026-04-28T09:57:03.8524901+04:00","gmt_modified":"2026-04-28T09:57:03.8524901+04:00"},{"id":34720,"source_id":"13c87583e5739bb6062ee5706cbed132","target_id":"19e78b124cb1653f5e72af6789493e08","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-53","gmt_create":"2026-04-28T09:57:03.8535253+04:00","gmt_modified":"2026-04-28T09:57:03.8535253+04:00"},{"id":34722,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"1bf53ebbc25ba8c147446f02ce5e44e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1267-1276","gmt_create":"2026-04-28T09:57:03.8545251+04:00","gmt_modified":"2026-04-28T09:57:03.8545251+04:00"},{"id":34724,"source_id":"448c0fd26faf791081a54cd407662e4d","target_id":"cecb2c27bddde9783761743ffbbfac88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 50-55","gmt_create":"2026-04-28T09:57:03.855525+04:00","gmt_modified":"2026-04-28T09:57:03.855525+04:00"},{"id":34726,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"4a84a6b27fbcb47e0994f0bda545816f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 206-249","gmt_create":"2026-04-28T09:57:03.855525+04:00","gmt_modified":"2026-04-28T09:57:03.855525+04:00"},{"id":34728,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"3d0cbd79a1648b655b90b7629307cad1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 206-276","gmt_create":"2026-04-28T09:57:03.8565256+04:00","gmt_modified":"2026-04-28T09:57:03.8565256+04:00"},{"id":34730,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"6abe7f6efde355ee9f2d7cf0776677ff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 278-423","gmt_create":"2026-04-28T09:57:03.8565256+04:00","gmt_modified":"2026-04-28T09:57:03.8565256+04:00"},{"id":34732,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"1cf7bf28dd5011954754492ccf7873f5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 447-471","gmt_create":"2026-04-28T09:57:03.8580305+04:00","gmt_modified":"2026-04-28T09:57:03.8580305+04:00"},{"id":34734,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"31e5e32f87baccd25fbb2183951a67bd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 590-695","gmt_create":"2026-04-28T09:57:03.8580305+04:00","gmt_modified":"2026-04-28T09:57:03.8580305+04:00"},{"id":34736,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"1844592144295f47f4238341e8868e6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 263-266","gmt_create":"2026-04-28T09:57:03.8590354+04:00","gmt_modified":"2026-04-28T09:57:03.8590354+04:00"},{"id":34738,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"15a3537ebe2816e5402e7fb60462b58e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4317-4332","gmt_create":"2026-04-28T09:57:03.8590354+04:00","gmt_modified":"2026-04-28T09:57:03.8590354+04:00"},{"id":34740,"source_id":"13c87583e5739bb6062ee5706cbed132","target_id":"6af53e8de30910078bc6fd9dab1d2f7b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-76","gmt_create":"2026-04-28T09:57:03.8590354+04:00","gmt_modified":"2026-04-28T09:57:03.8590354+04:00"},{"id":34742,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"0ef7b0d7933da804905c2ff76f92cd94","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2824-2839","gmt_create":"2026-04-28T09:57:03.8600352+04:00","gmt_modified":"2026-04-28T09:57:03.8600352+04:00"},{"id":34744,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"667d252413c23e04beb2c069531a1372","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2871-2886","gmt_create":"2026-04-28T09:57:03.8610357+04:00","gmt_modified":"2026-04-28T09:57:03.8610357+04:00"},{"id":34746,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"62ea8f0eed608d8eb1dd0911e43f28c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1223-1267","gmt_create":"2026-04-28T09:57:03.8610357+04:00","gmt_modified":"2026-04-28T09:57:03.8610357+04:00"},{"id":34748,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"1b91062fbd3e8ce21a7ec705a5ef21ae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 125-133","gmt_create":"2026-04-28T09:57:03.8610357+04:00","gmt_modified":"2026-04-28T09:57:03.8610357+04:00"},{"id":34750,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"c57b368c9aec32de084799a61fc21d81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 149-155","gmt_create":"2026-04-28T09:57:03.8620352+04:00","gmt_modified":"2026-04-28T09:57:03.8620352+04:00"},{"id":34752,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"9a1726ad4c4d7942894eafbb2fb7c20a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 222-224","gmt_create":"2026-04-28T09:57:03.8620352+04:00","gmt_modified":"2026-04-28T09:57:03.8620352+04:00"},{"id":34754,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"d572e2edecf45b7b050d30cbb14368d8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-58","gmt_create":"2026-04-28T09:57:03.8620352+04:00","gmt_modified":"2026-04-28T09:57:03.8620352+04:00"},{"id":34756,"source_id":"18555f254f50536a15d8591acf982406","target_id":"a3b204b149312d56bea1667800a95fb6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 99-103","gmt_create":"2026-04-28T09:57:03.8640358+04:00","gmt_modified":"2026-04-28T09:57:03.8640358+04:00"},{"id":34758,"source_id":"bb293be9318768f10f69c80fd6b68517","target_id":"f72faf82a21dd9049d68549d9c7e5c4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 76-80","gmt_create":"2026-04-28T09:57:03.8640358+04:00","gmt_modified":"2026-04-28T09:57:03.8640358+04:00"},{"id":34760,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"c5701be8b76f9a4a85b659f219a10f95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 509-555","gmt_create":"2026-04-28T09:57:03.8655386+04:00","gmt_modified":"2026-04-28T09:57:03.8655386+04:00"},{"id":34762,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"7f2c3ab5ba63b977d9642aa1c78a2c43","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 120-169","gmt_create":"2026-04-28T09:57:03.8655386+04:00","gmt_modified":"2026-04-28T09:57:03.8655386+04:00"},{"id":34764,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"737d623fe091f7ae2629dcda699b0efa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 171-192","gmt_create":"2026-04-28T09:57:03.8655386+04:00","gmt_modified":"2026-04-28T09:57:03.8655386+04:00"},{"id":34766,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"fba8be1bbb523071f8ce7ad55a13d0f2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31","gmt_create":"2026-04-28T09:57:03.8775694+04:00","gmt_modified":"2026-04-28T09:57:03.8775694+04:00"},{"id":34768,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"2a7a24b7119edca00eb0b21200f484ec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 88","gmt_create":"2026-04-28T09:57:03.8785683+04:00","gmt_modified":"2026-04-28T09:57:03.8785683+04:00"},{"id":34770,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"c9048f7e0344e917d91b3b45d3804a0d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 73","gmt_create":"2026-04-28T09:57:03.8785683+04:00","gmt_modified":"2026-04-28T09:57:03.8785683+04:00"},{"id":34772,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"ff4cacfd8a6a1ce746ce49bd2259ef47","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 151-166","gmt_create":"2026-04-28T09:57:03.8795944+04:00","gmt_modified":"2026-04-28T09:57:03.8795944+04:00"},{"id":34774,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"78279a6057ca0eaea7f987e920fada7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1456-1471","gmt_create":"2026-04-28T09:57:03.8795944+04:00","gmt_modified":"2026-04-28T09:57:03.8795944+04:00"},{"id":34776,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"95e9eb6df5c5b54fc25131e15cebca7b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 269-274","gmt_create":"2026-04-28T09:57:03.8795944+04:00","gmt_modified":"2026-04-28T09:57:03.8795944+04:00"},{"id":34778,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"4c8c235c40a9885b9ce181cc9af786fe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2807-2839","gmt_create":"2026-04-28T09:57:03.8805955+04:00","gmt_modified":"2026-04-28T09:57:03.8805955+04:00"},{"id":34780,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"29354043db86eeb48566453a908645c7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2897-2914","gmt_create":"2026-04-28T09:57:03.8815941+04:00","gmt_modified":"2026-04-28T09:57:03.8815941+04:00"},{"id":34782,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6e4547d3d8a2b1ce7fb2eb8442ba9631","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1294-1311","gmt_create":"2026-04-28T09:57:03.8871036+04:00","gmt_modified":"2026-04-28T09:57:03.8871036+04:00"},{"id":34784,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"0dec6783542ea54ba7d81fbeb930e442","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-49","gmt_create":"2026-04-28T09:57:03.8871036+04:00","gmt_modified":"2026-04-28T09:57:03.8871036+04:00"},{"id":34786,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"85675dcfc30f216052bdb5cedc7b435c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 75-91","gmt_create":"2026-04-28T09:57:03.8886221+04:00","gmt_modified":"2026-04-28T09:57:03.8886221+04:00"},{"id":34788,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"7f42fa8b501a589d403cb682d1620581","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 102-125","gmt_create":"2026-04-28T09:57:03.8886221+04:00","gmt_modified":"2026-04-28T09:57:03.8886221+04:00"},{"id":34790,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"17a2c941cfb814db6c1623046d8dac1e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 127-159","gmt_create":"2026-04-28T09:57:03.8891498+04:00","gmt_modified":"2026-04-28T09:57:03.8891498+04:00"},{"id":34792,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"53a82d703bff53e589353336964d2eed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-169","gmt_create":"2026-04-28T09:57:03.8896673+04:00","gmt_modified":"2026-04-28T09:57:03.8896673+04:00"},{"id":34794,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"4fcf4072cf8ebe5cd019e9a0da762901","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 171-203","gmt_create":"2026-04-28T09:57:03.8896673+04:00","gmt_modified":"2026-04-28T09:57:03.8896673+04:00"},{"id":34796,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"c4f66fb8fb1d6eeb25bd48eec2ba80a6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 102-159","gmt_create":"2026-04-28T09:57:03.8901745+04:00","gmt_modified":"2026-04-28T09:57:03.8901745+04:00"},{"id":34798,"source_id":"a4f11ca2018649a28877cfdeecdff9a6","target_id":"68e0135d2e3b03eff760c57654b97092","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-203","gmt_create":"2026-04-28T09:57:03.8906938+04:00","gmt_modified":"2026-04-28T09:57:03.8906938+04:00"},{"id":34800,"source_id":"cf72debd284e30d5218a88ae08868205","target_id":"eeebc7e5a0ce3570715e7391da03b065","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 104-171","gmt_create":"2026-04-28T09:57:03.8912137+04:00","gmt_modified":"2026-04-28T09:57:03.8912137+04:00"},{"id":34802,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"ef4797348572b382b96b9d19a362eed7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 90-95","gmt_create":"2026-04-28T09:57:03.8917283+04:00","gmt_modified":"2026-04-28T09:57:03.8917283+04:00"},{"id":34804,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"85e55e5f6d83a36cd6afac5fcb62fb42","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1626-1805","gmt_create":"2026-04-28T09:57:03.8927583+04:00","gmt_modified":"2026-04-28T09:57:03.8927583+04:00"},{"id":34806,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1d8a3a8529f55f725cbd52ef78db6a1f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4334-4463","gmt_create":"2026-04-28T09:57:03.8932701+04:00","gmt_modified":"2026-04-28T09:57:03.8932701+04:00"},{"id":34808,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"87584d47dc52c8658341b565e96c989d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 492-499","gmt_create":"2026-04-28T09:57:03.8932701+04:00","gmt_modified":"2026-04-28T09:57:03.8932701+04:00"},{"id":34810,"source_id":"13c87583e5739bb6062ee5706cbed132","target_id":"cda7dad93173bc2161ab2ff3c92e81ce","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-39","gmt_create":"2026-04-28T09:57:03.8937802+04:00","gmt_modified":"2026-04-28T09:57:03.8937802+04:00"},{"id":34812,"source_id":"b58bf8be210d82c70605d7f2482ced82","target_id":"73dca3cd312efbc6ecb517ae118fd869","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 184-201","gmt_create":"2026-04-28T09:57:03.894298+04:00","gmt_modified":"2026-04-28T09:57:03.894298+04:00"},{"id":34814,"source_id":"b58bf8be210d82c70605d7f2482ced82","target_id":"c69f6ef1a64e88829a12d7ab4c190897","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 236-266","gmt_create":"2026-04-28T09:57:03.8948136+04:00","gmt_modified":"2026-04-28T09:57:03.8948136+04:00"},{"id":34816,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"26905e829dbbc0af740b97400068843b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 255-271","gmt_create":"2026-04-28T09:57:03.8963611+04:00","gmt_modified":"2026-04-28T09:57:03.8963611+04:00"},{"id":34818,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"1eb7cc21b9daf17a2c908f3121bcf2f0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 387-396","gmt_create":"2026-04-28T09:57:03.8968723+04:00","gmt_modified":"2026-04-28T09:57:03.8968723+04:00"},{"id":34820,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"cc4d2fca7cfbc2ed2aa9dc9016360fb5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2826-2836","gmt_create":"2026-04-28T09:57:03.8974708+04:00","gmt_modified":"2026-04-28T09:57:03.8974708+04:00"},{"id":34822,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e0e1ada694da4e9e256e0d6d39aa73e5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2873-2883","gmt_create":"2026-04-28T09:57:03.8979743+04:00","gmt_modified":"2026-04-28T09:57:03.8979743+04:00"},{"id":34837,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d74594b2821f5c9e747d2630c3784bb1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4669-4822","gmt_create":"2026-04-28T09:57:57.4427714+04:00","gmt_modified":"2026-04-28T09:57:57.4427714+04:00"},{"id":34839,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"27593eff1e7989c53fb119e30b38a106","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 81-88","gmt_create":"2026-04-28T09:57:57.4432949+04:00","gmt_modified":"2026-04-28T09:57:57.4432949+04:00"},{"id":34841,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"f5099185b2e70ff258ed1ff6f4405b90","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 509-524","gmt_create":"2026-04-28T09:57:57.4438097+04:00","gmt_modified":"2026-04-28T09:57:57.4438097+04:00"},{"id":34843,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"3613ea0b8ae4f848819d0ac0b87c1bc9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 562-590","gmt_create":"2026-04-28T09:57:57.4438097+04:00","gmt_modified":"2026-04-28T09:57:57.4438097+04:00"},{"id":34845,"source_id":"ee77bf4eb6bfbfb3636aa0bd57416552","target_id":"4988a66040303855b9d94a173232f966","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1075-1115","gmt_create":"2026-04-28T09:57:57.4448562+04:00","gmt_modified":"2026-04-28T09:57:57.4448562+04:00"},{"id":34847,"source_id":"7ae785f9d5ab154dce6f8eb295b93456","target_id":"188a46b66d800240516e280b06e7f041","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-146","gmt_create":"2026-04-28T09:57:57.4448562+04:00","gmt_modified":"2026-04-28T09:57:57.4448562+04:00"},{"id":34850,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"02a1a9fcc78ccfc4daf328d04696eb6f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 114-124","gmt_create":"2026-04-28T09:57:57.4453669+04:00","gmt_modified":"2026-04-28T09:57:57.4453669+04:00"},{"id":34852,"source_id":"cf72debd284e30d5218a88ae08868205","target_id":"971acfd6fe75fe0b8a1522de5c46bf48","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-61","gmt_create":"2026-04-28T09:57:57.445884+04:00","gmt_modified":"2026-04-28T09:57:57.445884+04:00"},{"id":34854,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"ad1ea51f6c6764f6694b4b89a834e8f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 110-128","gmt_create":"2026-04-28T09:57:57.4463953+04:00","gmt_modified":"2026-04-28T09:57:57.4463953+04:00"},{"id":34856,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"9fae7d65cba1bc4e0e4e2ca7efd9c99b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4675-4703","gmt_create":"2026-04-28T09:57:57.446906+04:00","gmt_modified":"2026-04-28T09:57:57.446906+04:00"},{"id":34858,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e454b40f3a2a945e952f73a4f2009cad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4707-4720","gmt_create":"2026-04-28T09:57:57.446906+04:00","gmt_modified":"2026-04-28T09:57:57.446906+04:00"},{"id":34860,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"255c8e4bd9e7ab0c2242bce46c0e863e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 405-406","gmt_create":"2026-04-28T09:57:57.4474213+04:00","gmt_modified":"2026-04-28T09:57:57.4474213+04:00"},{"id":34862,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"3c48450ddf4126f562a2691715c15905","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 80-87","gmt_create":"2026-04-28T09:57:57.4479563+04:00","gmt_modified":"2026-04-28T09:57:57.4479563+04:00"},{"id":34864,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"cc9483d821847e02b4d24e6c9a0d47b3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 260-262","gmt_create":"2026-04-28T09:57:57.4479563+04:00","gmt_modified":"2026-04-28T09:57:57.4479563+04:00"},{"id":34866,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"79f094abff66ff28914dcda338045f88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2428-2444","gmt_create":"2026-04-28T09:57:57.4484877+04:00","gmt_modified":"2026-04-28T09:57:57.4484877+04:00"},{"id":34868,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"fc2ee24e4f7c33ca03ec4cd65b733437","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 126-128","gmt_create":"2026-04-28T09:57:57.4490006+04:00","gmt_modified":"2026-04-28T09:57:57.4490006+04:00"},{"id":34870,"source_id":"8ede002b6c76d0a07d75e34f812e8305","target_id":"11e880557c78471a43830064f7284407","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6","gmt_create":"2026-04-28T09:57:57.44951+04:00","gmt_modified":"2026-04-28T09:57:57.44951+04:00"},{"id":34872,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e2e78ec9bb315562ae4436bac3d06fb5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1556","gmt_create":"2026-04-28T09:57:57.450026+04:00","gmt_modified":"2026-04-28T09:57:57.450026+04:00"},{"id":34874,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b77936a3b7e26cb05376897c149ba871","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1593","gmt_create":"2026-04-28T09:57:57.4505548+04:00","gmt_modified":"2026-04-28T09:57:57.4505548+04:00"},{"id":34876,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"0fda0369897c65053dee851ef9ec01f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-612","gmt_create":"2026-04-28T09:57:57.4515744+04:00","gmt_modified":"2026-04-28T09:57:57.4515744+04:00"},{"id":34878,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"56869b4c37aaf198953050ee291096aa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 113-145","gmt_create":"2026-04-28T09:57:57.4589075+04:00","gmt_modified":"2026-04-28T09:57:57.4589075+04:00"},{"id":34899,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"825feab7f9d0991ba63a9c56f38beff9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-642","gmt_create":"2026-04-28T10:02:32.6413191+04:00","gmt_modified":"2026-04-28T10:02:32.6413191+04:00"},{"id":34901,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"4715ce884086b88c16e3424c68d37757","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6506","gmt_create":"2026-04-28T10:02:32.6418484+04:00","gmt_modified":"2026-04-28T10:02:32.6418484+04:00"},{"id":34903,"source_id":"ee77bf4eb6bfbfb3636aa0bd57416552","target_id":"2ad3ade1c893ee16ff7640c396428e46","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1078-1120","gmt_create":"2026-04-28T10:02:32.6423686+04:00","gmt_modified":"2026-04-28T10:02:32.6423686+04:00"},{"id":34905,"source_id":"1ade3cebbc11a4634bcdf1a7fdb2756e","target_id":"27490494b39fa9968667b183f60e215a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T10:02:32.6423686+04:00","gmt_modified":"2026-04-28T10:02:32.6423686+04:00"},{"id":34907,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"2c17018b7a7ecf1dd7b6432e97d0a586","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-75","gmt_create":"2026-04-28T10:02:32.6428831+04:00","gmt_modified":"2026-04-28T10:02:32.6428831+04:00"},{"id":34909,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"fef8201a8783aa794440fbd2f9b1ff17","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-302","gmt_create":"2026-04-28T10:02:32.6434036+04:00","gmt_modified":"2026-04-28T10:02:32.6434036+04:00"},{"id":34911,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"6ebf29a038d578e8864ca6c9c9366bda","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-76","gmt_create":"2026-04-28T10:02:32.6439232+04:00","gmt_modified":"2026-04-28T10:02:32.6439232+04:00"},{"id":34913,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"1a161423d84a286d1a1c4eeb95bcfd01","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-414","gmt_create":"2026-04-28T10:02:32.6439232+04:00","gmt_modified":"2026-04-28T10:02:32.6439232+04:00"},{"id":34915,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"d2a63eaaf3635885b145b52cf4640747","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-138","gmt_create":"2026-04-28T10:02:32.6444419+04:00","gmt_modified":"2026-04-28T10:02:32.6444419+04:00"},{"id":34917,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"d3bee62a496fa43717911daed4f0bb13","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-271","gmt_create":"2026-04-28T10:02:32.644965+04:00","gmt_modified":"2026-04-28T10:02:32.644965+04:00"},{"id":34919,"source_id":"cb29035725926be38d36ad8c01792b7e","target_id":"ba99a3c0ac8bffedf50f03f7f8a09c06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-136","gmt_create":"2026-04-28T10:02:32.6454737+04:00","gmt_modified":"2026-04-28T10:02:32.6454737+04:00"},{"id":34921,"source_id":"57e07111ef7b80720c419255780e7ece","target_id":"0397697ee2095dedcc01fa148c7079b9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-154","gmt_create":"2026-04-28T10:02:32.6459947+04:00","gmt_modified":"2026-04-28T10:02:32.6459947+04:00"},{"id":34923,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"b2901b8a7a24569b4a61c38b4448db06","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1180-1379","gmt_create":"2026-04-28T10:02:32.647113+04:00","gmt_modified":"2026-04-28T10:02:32.647113+04:00"},{"id":34925,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"77520f9eb913c04b5230e07f8f3f4ef8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 270-469","gmt_create":"2026-04-28T10:02:32.647623+04:00","gmt_modified":"2026-04-28T10:02:32.647623+04:00"},{"id":34927,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"340636e744f71de65b91146c5b8a20bd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-73","gmt_create":"2026-04-28T10:02:32.6481554+04:00","gmt_modified":"2026-04-28T10:02:32.6481554+04:00"},{"id":34929,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"c05f511b950fdae3b96260134880f8e4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-118","gmt_create":"2026-04-28T10:02:32.6486856+04:00","gmt_modified":"2026-04-28T10:02:32.6486856+04:00"},{"id":34931,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"101205728a0401f1dc07b5e31abe4b30","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3185-3384","gmt_create":"2026-04-28T10:02:32.6486856+04:00","gmt_modified":"2026-04-28T10:02:32.6486856+04:00"},{"id":34933,"source_id":"3948eb588d15d01acf21ffd439ec508c","target_id":"832619f974a664566d9bae6712c5e6a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-48","gmt_create":"2026-04-28T10:02:32.6491998+04:00","gmt_modified":"2026-04-28T10:02:32.6491998+04:00"},{"id":34935,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"8939bbbd6e1bb4a18e6bb534a037d0b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 225-424","gmt_create":"2026-04-28T10:02:32.6491998+04:00","gmt_modified":"2026-04-28T10:02:32.6491998+04:00"},{"id":34937,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"b437e864a36924899b70d6b9295e4ac0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-115","gmt_create":"2026-04-28T10:02:32.6513176+04:00","gmt_modified":"2026-04-28T10:02:32.6513176+04:00"},{"id":34939,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"476cdc272b600cf1a7bfe2b524767872","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 281-324","gmt_create":"2026-04-28T10:02:32.6518456+04:00","gmt_modified":"2026-04-28T10:02:32.6518456+04:00"},{"id":34941,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"5c73e14f98ff45ef03bb3a7c9e413218","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-75","gmt_create":"2026-04-28T10:02:32.6523696+04:00","gmt_modified":"2026-04-28T10:02:32.6523696+04:00"},{"id":34943,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"6742da18bac301be1056c8e6e5adcf69","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-72","gmt_create":"2026-04-28T10:02:32.6523696+04:00","gmt_modified":"2026-04-28T10:02:32.6523696+04:00"},{"id":34945,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"8f2e19d22fb34a00bbf819d0f5088b92","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-138","gmt_create":"2026-04-28T10:02:32.6528954+04:00","gmt_modified":"2026-04-28T10:02:32.6528954+04:00"},{"id":34947,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6d7b6e4198a348bc27c0bb28230cb3f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 929-984","gmt_create":"2026-04-28T10:02:32.6528954+04:00","gmt_modified":"2026-04-28T10:02:32.6528954+04:00"},{"id":34949,"source_id":"57e07111ef7b80720c419255780e7ece","target_id":"186fa6ce927d55c0b153413a2981237e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-100","gmt_create":"2026-04-28T10:02:32.6528954+04:00","gmt_modified":"2026-04-28T10:02:32.6528954+04:00"},{"id":34951,"source_id":"1ade3cebbc11a4634bcdf1a7fdb2756e","target_id":"99a2db97d03705f31a3929010634a458","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 225-279","gmt_create":"2026-04-28T10:02:32.6539489+04:00","gmt_modified":"2026-04-28T10:02:32.6539489+04:00"},{"id":34953,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"30a9101c41868617ba6f2a2daa15b849","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 94-184","gmt_create":"2026-04-28T10:02:32.6555587+04:00","gmt_modified":"2026-04-28T10:02:32.6555587+04:00"},{"id":34955,"source_id":"cb29035725926be38d36ad8c01792b7e","target_id":"3e02993eaec7af3cec0bfb1f83a665d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 83","gmt_create":"2026-04-28T10:02:32.6560893+04:00","gmt_modified":"2026-04-28T10:02:32.6560893+04:00"},{"id":34957,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"99f54a4b93eefbb48ed1667eff0fa9d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 330-410","gmt_create":"2026-04-28T10:02:32.6566219+04:00","gmt_modified":"2026-04-28T10:02:32.6566219+04:00"},{"id":34959,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"408bde042901c8590a87dffdf56f7b44","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 134-184","gmt_create":"2026-04-28T10:02:32.6566219+04:00","gmt_modified":"2026-04-28T10:02:32.6566219+04:00"},{"id":34961,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e69115f35f4572b29fb65e977de046e0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 503-519","gmt_create":"2026-04-28T10:02:32.6571435+04:00","gmt_modified":"2026-04-28T10:02:32.6571435+04:00"},{"id":34963,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"c7f51cc5681ac282586b460766078a35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 61-68","gmt_create":"2026-04-28T10:02:32.6576613+04:00","gmt_modified":"2026-04-28T10:02:32.6576613+04:00"},{"id":34965,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"bc9cfd1e8fd5529888f9a16b60e4ac68","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1424-1426","gmt_create":"2026-04-28T10:02:32.658182+04:00","gmt_modified":"2026-04-28T10:02:32.658182+04:00"},{"id":34967,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e5fa51f083d1ac49273aea5904dea32f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 704-752","gmt_create":"2026-04-28T10:02:32.6587013+04:00","gmt_modified":"2026-04-28T10:02:32.6587013+04:00"},{"id":34969,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1198bd7cc69669237a261463e8cd3c9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3986-4039","gmt_create":"2026-04-28T10:02:32.6592137+04:00","gmt_modified":"2026-04-28T10:02:32.6592137+04:00"},{"id":34971,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a8eaae161939961c892a4e5ff9b1b68f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4144-4175","gmt_create":"2026-04-28T10:02:32.6592137+04:00","gmt_modified":"2026-04-28T10:02:32.6592137+04:00"},{"id":34973,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7cb385b30473b1f25ba53b2a6825c874","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4384-4424","gmt_create":"2026-04-28T10:02:32.6602175+04:00","gmt_modified":"2026-04-28T10:02:32.6602175+04:00"},{"id":34975,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"ec354a277b7a096cd5e5a4cebe2b7d7a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 70-73","gmt_create":"2026-04-28T10:02:32.6602175+04:00","gmt_modified":"2026-04-28T10:02:32.6602175+04:00"},{"id":34977,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b86a1f199ae24604cb9b125824afc0a0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 292-292","gmt_create":"2026-04-28T10:02:32.6602175+04:00","gmt_modified":"2026-04-28T10:02:32.6602175+04:00"},{"id":34979,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ddaa6fa138e94fe8af5d2b77014c29f0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4460-4490","gmt_create":"2026-04-28T10:02:32.6627707+04:00","gmt_modified":"2026-04-28T10:02:32.6627707+04:00"},{"id":34981,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"47787fc2ed2dde075eda3ebf991e2fc9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 75-77","gmt_create":"2026-04-28T10:02:32.6627707+04:00","gmt_modified":"2026-04-28T10:02:32.6627707+04:00"},{"id":34983,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"17b75751a836de13af2093485914a80b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1147-1202","gmt_create":"2026-04-28T10:02:32.6637686+04:00","gmt_modified":"2026-04-28T10:02:32.6637686+04:00"},{"id":34985,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"3fd79dc7253b83f3fd4a1db36b691537","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-96","gmt_create":"2026-04-28T10:02:32.6637686+04:00","gmt_modified":"2026-04-28T10:02:32.6637686+04:00"},{"id":34987,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"fc817fa1448591c306f1d8c94a4912b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 340-350","gmt_create":"2026-04-28T10:02:32.6637686+04:00","gmt_modified":"2026-04-28T10:02:32.6637686+04:00"},{"id":34989,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2b22b083099e12af5fb5eff69ac7c45b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4346-4366","gmt_create":"2026-04-28T10:02:32.6647727+04:00","gmt_modified":"2026-04-28T10:02:32.6647727+04:00"},{"id":34991,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ad0c51e89fbda89a4c7ba4a8b1c23f6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 948-970","gmt_create":"2026-04-28T10:02:32.6647727+04:00","gmt_modified":"2026-04-28T10:02:32.6647727+04:00"},{"id":34993,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1bc38fc420c17ebaaf14eb62dd9dd77e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3652-3711","gmt_create":"2026-04-28T10:02:32.6652839+04:00","gmt_modified":"2026-04-28T10:02:32.6652839+04:00"},{"id":34995,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a0ef31a365b500c015295fa0a77cb02a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 639-673","gmt_create":"2026-04-28T10:02:32.6652839+04:00","gmt_modified":"2026-04-28T10:02:32.6652839+04:00"},{"id":34997,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"bad0cf5ac8c5e25ab7697c72386f0c6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 562-605","gmt_create":"2026-04-28T10:02:32.6652839+04:00","gmt_modified":"2026-04-28T10:02:32.6652839+04:00"},{"id":34999,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"145b14d90766df6ec3acffdb3b52a1a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 412-422","gmt_create":"2026-04-28T10:02:32.6662888+04:00","gmt_modified":"2026-04-28T10:02:32.6662888+04:00"},{"id":35001,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5ae77d32160a48045d586a25c4949703","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 454-482","gmt_create":"2026-04-28T10:02:32.6753196+04:00","gmt_modified":"2026-04-28T10:02:32.6753196+04:00"},{"id":35003,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"fb42540947b6b7d56487ccd9ec782f86","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-164","gmt_create":"2026-04-28T10:02:32.6773154+04:00","gmt_modified":"2026-04-28T10:02:32.6773154+04:00"},{"id":35005,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"4eb8ce2a423658c16ae4df90aeba2184","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 546-556","gmt_create":"2026-04-28T10:02:32.6773154+04:00","gmt_modified":"2026-04-28T10:02:32.6773154+04:00"},{"id":35007,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"0172b0ea2a031177f1c72341a3922614","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 631-632","gmt_create":"2026-04-28T10:02:32.6783155+04:00","gmt_modified":"2026-04-28T10:02:32.6783155+04:00"},{"id":35009,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e8dd15ab10626a2ce715fe8c3f03ca85","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1106-1145","gmt_create":"2026-04-28T10:02:32.6783155+04:00","gmt_modified":"2026-04-28T10:02:32.6783155+04:00"},{"id":35011,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"8509be38b1ab9f14d108445df0dcd2f1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1460-1470","gmt_create":"2026-04-28T10:02:32.6793146+04:00","gmt_modified":"2026-04-28T10:02:32.6793146+04:00"},{"id":35013,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"732bc579d5f86ebf0e986ecfbdfa490d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-46","gmt_create":"2026-04-28T10:02:32.6793146+04:00","gmt_modified":"2026-04-28T10:02:32.6793146+04:00"},{"id":35016,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d1e1e1bc28ff1dfbd77617edbf4a23b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1295-1377","gmt_create":"2026-04-28T10:02:32.680817+04:00","gmt_modified":"2026-04-28T10:02:32.680817+04:00"},{"id":35018,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"42f304cea32d3254d3d28d390f99a4f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1216-1286","gmt_create":"2026-04-28T10:02:32.6818238+04:00","gmt_modified":"2026-04-28T10:02:32.6818238+04:00"},{"id":35020,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"21021513e3f47136fbd9b77f25ac0dda","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 175-192","gmt_create":"2026-04-28T10:02:32.6828252+04:00","gmt_modified":"2026-04-28T10:02:32.6828252+04:00"},{"id":35022,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"978bc8c4cf93eea58a5004412f5a0740","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3192-3211","gmt_create":"2026-04-28T10:02:32.6828252+04:00","gmt_modified":"2026-04-28T10:02:32.6828252+04:00"},{"id":35024,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"9a7186666130ca998f114a82a0decdff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 181-196","gmt_create":"2026-04-28T10:02:32.6838216+04:00","gmt_modified":"2026-04-28T10:02:32.6838216+04:00"},{"id":35026,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ac1d251c502e1e4341518133a47346b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1556-1588","gmt_create":"2026-04-28T10:02:32.6838216+04:00","gmt_modified":"2026-04-28T10:02:32.6838216+04:00"},{"id":35028,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"03c29e794349e78edd559069a4ea589f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1593-1594","gmt_create":"2026-04-28T10:02:32.6848229+04:00","gmt_modified":"2026-04-28T10:02:32.6848229+04:00"},{"id":35030,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"bc5ca04bd394cfbe05b91187be1ef3e1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 271-300","gmt_create":"2026-04-28T10:02:32.6848229+04:00","gmt_modified":"2026-04-28T10:02:32.6848229+04:00"},{"id":35032,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"32c3cd87cb292dbfecb6d81dc0fc6739","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 506-507","gmt_create":"2026-04-28T10:02:32.6848229+04:00","gmt_modified":"2026-04-28T10:02:32.6848229+04:00"},{"id":35034,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"ba68b0a6c770e5eb7e9c206147e04add","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 232-243","gmt_create":"2026-04-28T10:02:32.6858226+04:00","gmt_modified":"2026-04-28T10:02:32.6858226+04:00"},{"id":35036,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"bf868153550f3b995f99ef4e396ddd77","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3444-3499","gmt_create":"2026-04-28T10:02:32.6868226+04:00","gmt_modified":"2026-04-28T10:02:32.6868226+04:00"},{"id":35038,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"e5c1c7808f2985bb68bc174eb390298a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 218-224","gmt_create":"2026-04-28T10:02:32.6878231+04:00","gmt_modified":"2026-04-28T10:02:32.6878231+04:00"},{"id":35040,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"e6c849182922d3df412daeb900b9e173","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 284-307","gmt_create":"2026-04-28T10:02:32.6888247+04:00","gmt_modified":"2026-04-28T10:02:32.6888247+04:00"},{"id":35042,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"05db694a94704c3e51ed70ce0118a1da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1158-1198","gmt_create":"2026-04-28T10:02:32.6888247+04:00","gmt_modified":"2026-04-28T10:02:32.6888247+04:00"},{"id":35044,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e6a9a48c0e930773f0a82fa246c53f98","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3652-3655","gmt_create":"2026-04-28T10:02:32.6898255+04:00","gmt_modified":"2026-04-28T10:02:32.6898255+04:00"},{"id":35046,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"bd530cb9e845767f0a9b3ff967997984","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 93-141","gmt_create":"2026-04-28T10:02:32.6898255+04:00","gmt_modified":"2026-04-28T10:02:32.6898255+04:00"},{"id":35048,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f10623a85ff8726287ec33204df6d61a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 458-584","gmt_create":"2026-04-28T10:02:32.6913308+04:00","gmt_modified":"2026-04-28T10:02:32.6913308+04:00"},{"id":35051,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"8f391118507fdd830a986c86e989a317","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2047-2144","gmt_create":"2026-04-28T10:02:32.6923361+04:00","gmt_modified":"2026-04-28T10:02:32.6923361+04:00"},{"id":35053,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"fa62adcb3d13201bfc9729dde67be04f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4378-4416","gmt_create":"2026-04-28T10:02:32.6923361+04:00","gmt_modified":"2026-04-28T10:02:32.6923361+04:00"},{"id":35055,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"98ed598d82d28fa1553560148bcda24e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2125-2142","gmt_create":"2026-04-28T10:02:32.6933365+04:00","gmt_modified":"2026-04-28T10:02:32.6933365+04:00"},{"id":35057,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5a5c235262f9722ff7bdf0586bfd8e26","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4220-4230","gmt_create":"2026-04-28T10:02:32.6933365+04:00","gmt_modified":"2026-04-28T10:02:32.6933365+04:00"},{"id":35059,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a8be8b7489d70072d66f1155610965d8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4517-4620","gmt_create":"2026-04-28T10:02:32.694335+04:00","gmt_modified":"2026-04-28T10:02:32.694335+04:00"},{"id":35061,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"39b6820362e87b0f937201fb8f54dee6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-28T10:02:32.694335+04:00","gmt_modified":"2026-04-28T10:02:32.694335+04:00"},{"id":35063,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1efc9fdbd77068cf27cb00354deff17a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-30","gmt_create":"2026-04-28T10:02:32.6953369+04:00","gmt_modified":"2026-04-28T10:02:32.6953369+04:00"},{"id":35065,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"92782cde6e026e561c0d55de0457f7a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 800-830","gmt_create":"2026-04-28T10:02:32.6973382+04:00","gmt_modified":"2026-04-28T10:02:32.6973382+04:00"},{"id":35067,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d0e2616c3e70f0e809256dcb448916ab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 270-279","gmt_create":"2026-04-28T10:02:32.6973382+04:00","gmt_modified":"2026-04-28T10:02:32.6973382+04:00"},{"id":35069,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"0855c233a79de418e4577d44bd54b9ba","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 492-501","gmt_create":"2026-04-28T10:02:32.6983352+04:00","gmt_modified":"2026-04-28T10:02:32.6983352+04:00"},{"id":35070,"source_id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","target_id":"fec1e146-3e5c-4c90-9824-44c18fd37d36","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 419b0fb1-31a5-4b4b-87f1-7adba3743630 -\u003e fec1e146-3e5c-4c90-9824-44c18fd37d36","gmt_create":"2026-04-28T10:05:07.3069155+04:00","gmt_modified":"2026-04-28T10:05:07.3069155+04:00"},{"id":35071,"source_id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","target_id":"c6931d42-c58d-4696-88f0-c17996821ffa","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 419b0fb1-31a5-4b4b-87f1-7adba3743630 -\u003e c6931d42-c58d-4696-88f0-c17996821ffa","gmt_create":"2026-04-28T10:05:07.3069155+04:00","gmt_modified":"2026-04-28T10:05:07.3069155+04:00"},{"id":35072,"source_id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","target_id":"724010bf-a048-4a08-bf63-fc4bcac656b4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 419b0fb1-31a5-4b4b-87f1-7adba3743630 -\u003e 724010bf-a048-4a08-bf63-fc4bcac656b4","gmt_create":"2026-04-28T10:05:07.3074363+04:00","gmt_modified":"2026-04-28T10:05:07.3074363+04:00"},{"id":35073,"source_id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","target_id":"9e5f8d60-bebb-4161-a630-0880704f9f81","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 419b0fb1-31a5-4b4b-87f1-7adba3743630 -\u003e 9e5f8d60-bebb-4161-a630-0880704f9f81","gmt_create":"2026-04-28T10:05:07.3079528+04:00","gmt_modified":"2026-04-28T10:05:07.3079528+04:00"},{"id":35074,"source_id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","target_id":"06bc216a-07e4-48fb-bdff-38335db957cc","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 419b0fb1-31a5-4b4b-87f1-7adba3743630 -\u003e 06bc216a-07e4-48fb-bdff-38335db957cc","gmt_create":"2026-04-28T10:05:07.3079528+04:00","gmt_modified":"2026-04-28T10:05:07.3079528+04:00"},{"id":35075,"source_id":"f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce","target_id":"4d58ea88-1cbb-46a1-9bb9-477c8e3d9846","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce -\u003e 4d58ea88-1cbb-46a1-9bb9-477c8e3d9846","gmt_create":"2026-04-28T10:05:07.3084628+04:00","gmt_modified":"2026-04-28T10:05:07.3084628+04:00"},{"id":35077,"source_id":"f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce","target_id":"24d2e14a-472d-4051-8c51-776999cfe4cc","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce -\u003e 24d2e14a-472d-4051-8c51-776999cfe4cc","gmt_create":"2026-04-28T10:05:07.3089777+04:00","gmt_modified":"2026-04-28T10:05:07.3089777+04:00"},{"id":35079,"source_id":"ecd87c29-4938-4318-9bbb-b3c2a87a2d22","target_id":"0be54f9c-0831-4de9-a839-fe492741178a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ecd87c29-4938-4318-9bbb-b3c2a87a2d22 -\u003e 0be54f9c-0831-4de9-a839-fe492741178a","gmt_create":"2026-04-28T10:05:07.3100135+04:00","gmt_modified":"2026-04-28T10:05:07.3100135+04:00"},{"id":35080,"source_id":"4493b728-953f-4c7d-9b30-89aa33255a3b","target_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4493b728-953f-4c7d-9b30-89aa33255a3b -\u003e c4b8579d-6410-4a31-8523-e38a9b1d69d3","gmt_create":"2026-04-28T10:05:07.3105347+04:00","gmt_modified":"2026-04-28T10:05:07.3105347+04:00"},{"id":35081,"source_id":"4493b728-953f-4c7d-9b30-89aa33255a3b","target_id":"0cb251fd-c588-4acc-8c03-1b2980db606b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4493b728-953f-4c7d-9b30-89aa33255a3b -\u003e 0cb251fd-c588-4acc-8c03-1b2980db606b","gmt_create":"2026-04-28T10:05:07.3105347+04:00","gmt_modified":"2026-04-28T10:05:07.3105347+04:00"},{"id":35083,"source_id":"4493b728-953f-4c7d-9b30-89aa33255a3b","target_id":"be44fe88-0512-4e4b-a4b8-9e082214a604","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4493b728-953f-4c7d-9b30-89aa33255a3b -\u003e be44fe88-0512-4e4b-a4b8-9e082214a604","gmt_create":"2026-04-28T10:05:07.3110487+04:00","gmt_modified":"2026-04-28T10:05:07.3110487+04:00"},{"id":35084,"source_id":"e885f837-dcb8-4f4a-b0ff-5c620c375d5e","target_id":"0fc8c6be-5e2e-4d16-aa17-5e6b88335450","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e885f837-dcb8-4f4a-b0ff-5c620c375d5e -\u003e 0fc8c6be-5e2e-4d16-aa17-5e6b88335450","gmt_create":"2026-04-28T10:05:07.3110487+04:00","gmt_modified":"2026-04-28T10:05:07.3110487+04:00"},{"id":35085,"source_id":"e885f837-dcb8-4f4a-b0ff-5c620c375d5e","target_id":"efbfc523-380a-4c5c-89b1-b1b22375fdd1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e885f837-dcb8-4f4a-b0ff-5c620c375d5e -\u003e efbfc523-380a-4c5c-89b1-b1b22375fdd1","gmt_create":"2026-04-28T10:05:07.3115703+04:00","gmt_modified":"2026-04-28T10:05:07.3115703+04:00"},{"id":35086,"source_id":"e885f837-dcb8-4f4a-b0ff-5c620c375d5e","target_id":"ecdb8c95-8cbb-4c16-b315-822594095634","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e885f837-dcb8-4f4a-b0ff-5c620c375d5e -\u003e ecdb8c95-8cbb-4c16-b315-822594095634","gmt_create":"2026-04-28T10:05:07.3115703+04:00","gmt_modified":"2026-04-28T10:05:07.3115703+04:00"},{"id":35087,"source_id":"e885f837-dcb8-4f4a-b0ff-5c620c375d5e","target_id":"52d914f6-5cef-4a53-bd37-4c7c074ddcb2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e885f837-dcb8-4f4a-b0ff-5c620c375d5e -\u003e 52d914f6-5cef-4a53-bd37-4c7c074ddcb2","gmt_create":"2026-04-28T10:05:07.3120911+04:00","gmt_modified":"2026-04-28T10:05:07.3120911+04:00"},{"id":35088,"source_id":"cafaced8-cceb-47ca-9052-70e14192d570","target_id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cafaced8-cceb-47ca-9052-70e14192d570 -\u003e 101024ac-5da4-4315-80c7-0cd7955ea4f8","gmt_create":"2026-04-28T10:05:07.3120911+04:00","gmt_modified":"2026-04-28T10:05:07.3120911+04:00"},{"id":35089,"source_id":"cafaced8-cceb-47ca-9052-70e14192d570","target_id":"46914ef3-870f-4299-b0b1-9b5d299c5cad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cafaced8-cceb-47ca-9052-70e14192d570 -\u003e 46914ef3-870f-4299-b0b1-9b5d299c5cad","gmt_create":"2026-04-28T10:05:07.3224035+04:00","gmt_modified":"2026-04-28T10:05:07.3224035+04:00"},{"id":35090,"source_id":"cafaced8-cceb-47ca-9052-70e14192d570","target_id":"760f37d6-5fcd-49a4-ac1d-f5e886377331","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cafaced8-cceb-47ca-9052-70e14192d570 -\u003e 760f37d6-5fcd-49a4-ac1d-f5e886377331","gmt_create":"2026-04-28T10:05:07.3224035+04:00","gmt_modified":"2026-04-28T10:05:07.3224035+04:00"},{"id":35091,"source_id":"cafaced8-cceb-47ca-9052-70e14192d570","target_id":"a3afccb6-22df-4d5b-bb93-2f591af782bf","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cafaced8-cceb-47ca-9052-70e14192d570 -\u003e a3afccb6-22df-4d5b-bb93-2f591af782bf","gmt_create":"2026-04-28T10:05:07.3224035+04:00","gmt_modified":"2026-04-28T10:05:07.3224035+04:00"},{"id":35092,"source_id":"43570872-cdce-4428-b8dd-dd01164aa9b3","target_id":"d992f398-cce4-49e2-a21a-44ff13893da3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 43570872-cdce-4428-b8dd-dd01164aa9b3 -\u003e d992f398-cce4-49e2-a21a-44ff13893da3","gmt_create":"2026-04-28T10:05:07.3234036+04:00","gmt_modified":"2026-04-28T10:05:07.3234036+04:00"},{"id":35093,"source_id":"43570872-cdce-4428-b8dd-dd01164aa9b3","target_id":"c9cc2572-d693-45ec-a7b0-6a1fa0a3d47e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 43570872-cdce-4428-b8dd-dd01164aa9b3 -\u003e c9cc2572-d693-45ec-a7b0-6a1fa0a3d47e","gmt_create":"2026-04-28T10:05:07.3234036+04:00","gmt_modified":"2026-04-28T10:05:07.3234036+04:00"},{"id":35094,"source_id":"43570872-cdce-4428-b8dd-dd01164aa9b3","target_id":"4f51c881-94ed-4e49-b8cf-e3b1fab21e0e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 43570872-cdce-4428-b8dd-dd01164aa9b3 -\u003e 4f51c881-94ed-4e49-b8cf-e3b1fab21e0e","gmt_create":"2026-04-28T10:05:07.3234036+04:00","gmt_modified":"2026-04-28T10:05:07.3234036+04:00"},{"id":35095,"source_id":"43570872-cdce-4428-b8dd-dd01164aa9b3","target_id":"09728486-f6d3-4cf1-bb8b-b5b404117331","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 43570872-cdce-4428-b8dd-dd01164aa9b3 -\u003e 09728486-f6d3-4cf1-bb8b-b5b404117331","gmt_create":"2026-04-28T10:05:07.3234036+04:00","gmt_modified":"2026-04-28T10:05:07.3234036+04:00"},{"id":35096,"source_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","target_id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c4b8579d-6410-4a31-8523-e38a9b1d69d3 -\u003e e9540698-3e7d-4a1c-bdaa-0d96c8be0745","gmt_create":"2026-04-28T10:05:07.3244037+04:00","gmt_modified":"2026-04-28T10:05:07.3244037+04:00"},{"id":35097,"source_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","target_id":"18a3eced-7204-4ae6-ace6-9325629f7540","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c4b8579d-6410-4a31-8523-e38a9b1d69d3 -\u003e 18a3eced-7204-4ae6-ace6-9325629f7540","gmt_create":"2026-04-28T10:05:07.3244037+04:00","gmt_modified":"2026-04-28T10:05:07.3244037+04:00"},{"id":35098,"source_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","target_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c4b8579d-6410-4a31-8523-e38a9b1d69d3 -\u003e bf24a62f-5138-4dfb-9ecb-9d4133953010","gmt_create":"2026-04-28T10:05:07.3244037+04:00","gmt_modified":"2026-04-28T10:05:07.3244037+04:00"},{"id":35099,"source_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","target_id":"85f42623-d6f4-4a64-9df9-84d74edb3ff8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c4b8579d-6410-4a31-8523-e38a9b1d69d3 -\u003e 85f42623-d6f4-4a64-9df9-84d74edb3ff8","gmt_create":"2026-04-28T10:05:07.3244037+04:00","gmt_modified":"2026-04-28T10:05:07.3244037+04:00"},{"id":35100,"source_id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","target_id":"f1d8e320-e614-4981-b139-99ffa4534e71","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c4b8579d-6410-4a31-8523-e38a9b1d69d3 -\u003e f1d8e320-e614-4981-b139-99ffa4534e71","gmt_create":"2026-04-28T10:05:07.3254054+04:00","gmt_modified":"2026-04-28T10:05:07.3254054+04:00"},{"id":35101,"source_id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","target_id":"f7e77aea-7354-410f-a8b6-ad12fbed8361","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 101024ac-5da4-4315-80c7-0cd7955ea4f8 -\u003e f7e77aea-7354-410f-a8b6-ad12fbed8361","gmt_create":"2026-04-28T10:05:07.3254054+04:00","gmt_modified":"2026-04-28T10:05:07.3254054+04:00"},{"id":35102,"source_id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","target_id":"7e78b6cc-7d2d-4326-820e-37969b08647b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 101024ac-5da4-4315-80c7-0cd7955ea4f8 -\u003e 7e78b6cc-7d2d-4326-820e-37969b08647b","gmt_create":"2026-04-28T10:05:07.3254054+04:00","gmt_modified":"2026-04-28T10:05:07.3254054+04:00"},{"id":35103,"source_id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","target_id":"3b02cb64-064b-4b4c-804e-62b2ba00d9ad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 101024ac-5da4-4315-80c7-0cd7955ea4f8 -\u003e 3b02cb64-064b-4b4c-804e-62b2ba00d9ad","gmt_create":"2026-04-28T10:05:07.3254054+04:00","gmt_modified":"2026-04-28T10:05:07.3254054+04:00"},{"id":35104,"source_id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","target_id":"64d83c3f-4775-41fd-9d42-d6c12ca8054b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 101024ac-5da4-4315-80c7-0cd7955ea4f8 -\u003e 64d83c3f-4775-41fd-9d42-d6c12ca8054b","gmt_create":"2026-04-28T10:05:07.3254054+04:00","gmt_modified":"2026-04-28T10:05:07.3254054+04:00"},{"id":35105,"source_id":"0cb251fd-c588-4acc-8c03-1b2980db606b","target_id":"c08ac7ca-a94d-4e15-8e9e-3dae3b1a5752","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0cb251fd-c588-4acc-8c03-1b2980db606b -\u003e c08ac7ca-a94d-4e15-8e9e-3dae3b1a5752","gmt_create":"2026-04-28T10:05:07.3269109+04:00","gmt_modified":"2026-04-28T10:05:07.3269109+04:00"},{"id":35106,"source_id":"0cb251fd-c588-4acc-8c03-1b2980db606b","target_id":"36300f0a-f814-4ee7-8fea-443822b5ee7e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0cb251fd-c588-4acc-8c03-1b2980db606b -\u003e 36300f0a-f814-4ee7-8fea-443822b5ee7e","gmt_create":"2026-04-28T10:05:07.3269109+04:00","gmt_modified":"2026-04-28T10:05:07.3269109+04:00"},{"id":35107,"source_id":"c6931d42-c58d-4696-88f0-c17996821ffa","target_id":"cc17934e-5862-4f4b-99a7-0ed4fd1c2e2a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c6931d42-c58d-4696-88f0-c17996821ffa -\u003e cc17934e-5862-4f4b-99a7-0ed4fd1c2e2a","gmt_create":"2026-04-28T10:05:07.3269109+04:00","gmt_modified":"2026-04-28T10:05:07.3269109+04:00"},{"id":35108,"source_id":"c6931d42-c58d-4696-88f0-c17996821ffa","target_id":"6ff3d5ed-5a93-44e9-b8fc-ee03618c7b1c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c6931d42-c58d-4696-88f0-c17996821ffa -\u003e 6ff3d5ed-5a93-44e9-b8fc-ee03618c7b1c","gmt_create":"2026-04-28T10:05:07.3269109+04:00","gmt_modified":"2026-04-28T10:05:07.3269109+04:00"},{"id":35109,"source_id":"c6931d42-c58d-4696-88f0-c17996821ffa","target_id":"20e80b63-adb3-4fae-a0ff-7b4553335673","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c6931d42-c58d-4696-88f0-c17996821ffa -\u003e 20e80b63-adb3-4fae-a0ff-7b4553335673","gmt_create":"2026-04-28T10:05:07.3279896+04:00","gmt_modified":"2026-04-28T10:05:07.3279896+04:00"},{"id":35110,"source_id":"c6931d42-c58d-4696-88f0-c17996821ffa","target_id":"faf4c29b-a303-4f0e-b3de-f9679789aa09","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c6931d42-c58d-4696-88f0-c17996821ffa -\u003e faf4c29b-a303-4f0e-b3de-f9679789aa09","gmt_create":"2026-04-28T10:05:07.3279896+04:00","gmt_modified":"2026-04-28T10:05:07.3279896+04:00"},{"id":35115,"source_id":"724010bf-a048-4a08-bf63-fc4bcac656b4","target_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 724010bf-a048-4a08-bf63-fc4bcac656b4 -\u003e 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","gmt_create":"2026-04-28T10:05:07.3289902+04:00","gmt_modified":"2026-04-28T10:05:07.3289902+04:00"},{"id":35116,"source_id":"724010bf-a048-4a08-bf63-fc4bcac656b4","target_id":"b52202cc-02f2-44ed-bba8-d9428b217809","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 724010bf-a048-4a08-bf63-fc4bcac656b4 -\u003e b52202cc-02f2-44ed-bba8-d9428b217809","gmt_create":"2026-04-28T10:05:07.32999+04:00","gmt_modified":"2026-04-28T10:05:07.32999+04:00"},{"id":35118,"source_id":"724010bf-a048-4a08-bf63-fc4bcac656b4","target_id":"32f6a790-8183-436f-a550-04552fa6b462","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 724010bf-a048-4a08-bf63-fc4bcac656b4 -\u003e 32f6a790-8183-436f-a550-04552fa6b462","gmt_create":"2026-04-28T10:05:07.32999+04:00","gmt_modified":"2026-04-28T10:05:07.32999+04:00"},{"id":35119,"source_id":"9e5f8d60-bebb-4161-a630-0880704f9f81","target_id":"28f563ee-bb1b-42be-8243-e7bfa17eb793","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9e5f8d60-bebb-4161-a630-0880704f9f81 -\u003e 28f563ee-bb1b-42be-8243-e7bfa17eb793","gmt_create":"2026-04-28T10:05:07.32999+04:00","gmt_modified":"2026-04-28T10:05:07.32999+04:00"},{"id":35121,"source_id":"9e5f8d60-bebb-4161-a630-0880704f9f81","target_id":"f8aac207-e623-4724-8003-ced4b4d90bf8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9e5f8d60-bebb-4161-a630-0880704f9f81 -\u003e f8aac207-e623-4724-8003-ced4b4d90bf8","gmt_create":"2026-04-28T10:05:07.3309899+04:00","gmt_modified":"2026-04-28T10:05:07.3309899+04:00"},{"id":35122,"source_id":"9e5f8d60-bebb-4161-a630-0880704f9f81","target_id":"aedcc69e-d00f-471d-a338-b290a71a8310","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9e5f8d60-bebb-4161-a630-0880704f9f81 -\u003e aedcc69e-d00f-471d-a338-b290a71a8310","gmt_create":"2026-04-28T10:05:07.3309899+04:00","gmt_modified":"2026-04-28T10:05:07.3309899+04:00"},{"id":35123,"source_id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","target_id":"371d43b9-4b79-40d6-a740-d0e09043a493","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e9540698-3e7d-4a1c-bdaa-0d96c8be0745 -\u003e 371d43b9-4b79-40d6-a740-d0e09043a493","gmt_create":"2026-04-28T10:05:07.3319916+04:00","gmt_modified":"2026-04-28T10:05:07.3319916+04:00"},{"id":35124,"source_id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","target_id":"818151df-a208-4937-9c96-909884f6bbb8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e9540698-3e7d-4a1c-bdaa-0d96c8be0745 -\u003e 818151df-a208-4937-9c96-909884f6bbb8","gmt_create":"2026-04-28T10:05:07.3319916+04:00","gmt_modified":"2026-04-28T10:05:07.3319916+04:00"},{"id":35125,"source_id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","target_id":"93891608-7b30-4aca-9ab2-5d88a2e3225f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e9540698-3e7d-4a1c-bdaa-0d96c8be0745 -\u003e 93891608-7b30-4aca-9ab2-5d88a2e3225f","gmt_create":"2026-04-28T10:05:07.3319916+04:00","gmt_modified":"2026-04-28T10:05:07.3319916+04:00"},{"id":35126,"source_id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","target_id":"3e146dd5-1515-4f08-a766-7c555069570d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e9540698-3e7d-4a1c-bdaa-0d96c8be0745 -\u003e 3e146dd5-1515-4f08-a766-7c555069570d","gmt_create":"2026-04-28T10:05:07.3329938+04:00","gmt_modified":"2026-04-28T10:05:07.3329938+04:00"},{"id":35128,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"81bc0ef1-cb71-44d4-a313-c0adacd3b67b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 81bc0ef1-cb71-44d4-a313-c0adacd3b67b","gmt_create":"2026-04-28T10:05:07.3339936+04:00","gmt_modified":"2026-04-28T10:05:07.3339936+04:00"},{"id":35131,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"0c2a4f4d-a142-41b8-81d4-a4c72022cd6d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 0c2a4f4d-a142-41b8-81d4-a4c72022cd6d","gmt_create":"2026-04-28T10:05:07.3349907+04:00","gmt_modified":"2026-04-28T10:05:07.3349907+04:00"},{"id":35132,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"03ac3143-5983-4c15-be9a-0e032445a800","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 03ac3143-5983-4c15-be9a-0e032445a800","gmt_create":"2026-04-28T10:05:07.3349907+04:00","gmt_modified":"2026-04-28T10:05:07.3349907+04:00"},{"id":35134,"source_id":"b52202cc-02f2-44ed-bba8-d9428b217809","target_id":"83f9e213-4dbf-4d44-8484-71f9339f5ed7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b52202cc-02f2-44ed-bba8-d9428b217809 -\u003e 83f9e213-4dbf-4d44-8484-71f9339f5ed7","gmt_create":"2026-04-28T10:05:07.3349907+04:00","gmt_modified":"2026-04-28T10:05:07.3349907+04:00"},{"id":35135,"source_id":"b52202cc-02f2-44ed-bba8-d9428b217809","target_id":"c911bbfb-6d46-458b-ac1c-dbba112490e9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b52202cc-02f2-44ed-bba8-d9428b217809 -\u003e c911bbfb-6d46-458b-ac1c-dbba112490e9","gmt_create":"2026-04-28T10:05:07.3359902+04:00","gmt_modified":"2026-04-28T10:05:07.3359902+04:00"},{"id":35136,"source_id":"b52202cc-02f2-44ed-bba8-d9428b217809","target_id":"0f6511c5-05bc-4ef7-8e04-442a302db49c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b52202cc-02f2-44ed-bba8-d9428b217809 -\u003e 0f6511c5-05bc-4ef7-8e04-442a302db49c","gmt_create":"2026-04-28T10:05:07.3359902+04:00","gmt_modified":"2026-04-28T10:05:07.3359902+04:00"},{"id":35137,"source_id":"b52202cc-02f2-44ed-bba8-d9428b217809","target_id":"d7562df5-2f68-4c8b-9b1b-1aff56d025ab","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b52202cc-02f2-44ed-bba8-d9428b217809 -\u003e d7562df5-2f68-4c8b-9b1b-1aff56d025ab","gmt_create":"2026-04-28T10:05:07.3359902+04:00","gmt_modified":"2026-04-28T10:05:07.3359902+04:00"},{"id":35138,"source_id":"b52202cc-02f2-44ed-bba8-d9428b217809","target_id":"52188625-f997-45b2-ab6a-1b01391bde00","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b52202cc-02f2-44ed-bba8-d9428b217809 -\u003e 52188625-f997-45b2-ab6a-1b01391bde00","gmt_create":"2026-04-28T10:05:07.3359902+04:00","gmt_modified":"2026-04-28T10:05:07.3359902+04:00"},{"id":35139,"source_id":"18a3eced-7204-4ae6-ace6-9325629f7540","target_id":"6173e746-57a9-469a-ac23-90061ef56ab6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18a3eced-7204-4ae6-ace6-9325629f7540 -\u003e 6173e746-57a9-469a-ac23-90061ef56ab6","gmt_create":"2026-04-28T10:05:07.3359902+04:00","gmt_modified":"2026-04-28T10:05:07.3359902+04:00"},{"id":35140,"source_id":"18a3eced-7204-4ae6-ace6-9325629f7540","target_id":"cbe0e279-74ff-4c6f-bc5d-ac88e9bcc6ac","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18a3eced-7204-4ae6-ace6-9325629f7540 -\u003e cbe0e279-74ff-4c6f-bc5d-ac88e9bcc6ac","gmt_create":"2026-04-28T10:05:07.3369899+04:00","gmt_modified":"2026-04-28T10:05:07.3369899+04:00"},{"id":35141,"source_id":"18a3eced-7204-4ae6-ace6-9325629f7540","target_id":"43b1b513-1146-4508-9929-bfca0e7bc21d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18a3eced-7204-4ae6-ace6-9325629f7540 -\u003e 43b1b513-1146-4508-9929-bfca0e7bc21d","gmt_create":"2026-04-28T10:05:07.3369899+04:00","gmt_modified":"2026-04-28T10:05:07.3369899+04:00"},{"id":35142,"source_id":"18a3eced-7204-4ae6-ace6-9325629f7540","target_id":"75c788ef-0d7a-4a59-a02a-d56403aa3459","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18a3eced-7204-4ae6-ace6-9325629f7540 -\u003e 75c788ef-0d7a-4a59-a02a-d56403aa3459","gmt_create":"2026-04-28T10:05:07.3369899+04:00","gmt_modified":"2026-04-28T10:05:07.3369899+04:00"},{"id":35143,"source_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","target_id":"9c3a79b2-0a34-4da6-8159-eb775b084846","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: bf24a62f-5138-4dfb-9ecb-9d4133953010 -\u003e 9c3a79b2-0a34-4da6-8159-eb775b084846","gmt_create":"2026-04-28T10:05:07.3369899+04:00","gmt_modified":"2026-04-28T10:05:07.3369899+04:00"},{"id":35144,"source_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","target_id":"58e53605-3c83-4017-8c41-9a5919796003","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: bf24a62f-5138-4dfb-9ecb-9d4133953010 -\u003e 58e53605-3c83-4017-8c41-9a5919796003","gmt_create":"2026-04-28T10:05:07.3381724+04:00","gmt_modified":"2026-04-28T10:05:07.3381724+04:00"},{"id":35145,"source_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","target_id":"2d5de852-4c30-4e77-8e31-3963f875ae85","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: bf24a62f-5138-4dfb-9ecb-9d4133953010 -\u003e 2d5de852-4c30-4e77-8e31-3963f875ae85","gmt_create":"2026-04-28T10:05:07.3381724+04:00","gmt_modified":"2026-04-28T10:05:07.3381724+04:00"},{"id":35146,"source_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","target_id":"e2b16877-3e41-4465-91f2-48e5dacfd2ad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: bf24a62f-5138-4dfb-9ecb-9d4133953010 -\u003e e2b16877-3e41-4465-91f2-48e5dacfd2ad","gmt_create":"2026-04-28T10:05:07.3381724+04:00","gmt_modified":"2026-04-28T10:05:07.3381724+04:00"},{"id":35147,"source_id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","target_id":"44884ed2-2c27-4d94-af1e-c939b85e2dba","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: bf24a62f-5138-4dfb-9ecb-9d4133953010 -\u003e 44884ed2-2c27-4d94-af1e-c939b85e2dba","gmt_create":"2026-04-28T10:05:07.3381724+04:00","gmt_modified":"2026-04-28T10:05:07.3381724+04:00"},{"id":35436,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"f2c0625ed2d13bb0a3699a45bf25d6cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-50","gmt_create":"2026-04-28T12:27:40.783289+04:00","gmt_modified":"2026-04-28T12:27:40.783289+04:00"},{"id":35438,"source_id":"bd196d115b6bd3d5310dfa247f1e25b2","target_id":"b49193d53f2bca5e5a84c905c1f90429","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-88","gmt_create":"2026-04-28T12:27:40.783289+04:00","gmt_modified":"2026-04-28T12:27:40.783289+04:00"},{"id":35440,"source_id":"991938d306a547ff48a759fb9bd1c5a4","target_id":"ca74187bf1151ee3b389754df4ce08d1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-52","gmt_create":"2026-04-28T12:27:40.7838156+04:00","gmt_modified":"2026-04-28T12:27:40.7838156+04:00"},{"id":35442,"source_id":"dc43b9a20a2ae22effbe51aecf8ca751","target_id":"60ec378a66a7653324d69f456e1242c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-52","gmt_create":"2026-04-28T12:27:40.7843455+04:00","gmt_modified":"2026-04-28T12:27:40.7843455+04:00"},{"id":35444,"source_id":"bd196d115b6bd3d5310dfa247f1e25b2","target_id":"93f965590673de9c5fe2a34fbc24af1c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-76","gmt_create":"2026-04-28T12:27:40.7848635+04:00","gmt_modified":"2026-04-28T12:27:40.7848635+04:00"},{"id":35446,"source_id":"991938d306a547ff48a759fb9bd1c5a4","target_id":"98907d07c594fe14c157ba203649b596","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-52","gmt_create":"2026-04-28T12:27:40.7848635+04:00","gmt_modified":"2026-04-28T12:27:40.7848635+04:00"},{"id":35448,"source_id":"d8e14923de7e4be8f600e264a03ea281","target_id":"aba83bcb80fe7ecb8f1f224f2fca05da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-158","gmt_create":"2026-04-28T12:27:40.7853793+04:00","gmt_modified":"2026-04-28T12:27:40.7853793+04:00"},{"id":35450,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"33fc7efcd171685ef3235423dc636724","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 675-780","gmt_create":"2026-04-28T12:27:40.7853793+04:00","gmt_modified":"2026-04-28T12:27:40.7853793+04:00"},{"id":35452,"source_id":"d8e14923de7e4be8f600e264a03ea281","target_id":"0a6e409382fdf7cc6924a9f918b5a4d8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-107","gmt_create":"2026-04-28T12:27:40.7858969+04:00","gmt_modified":"2026-04-28T12:27:40.7858969+04:00"},{"id":35454,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"d419300bbe8000129fd9765417390c9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 885-987","gmt_create":"2026-04-28T12:27:40.7864124+04:00","gmt_modified":"2026-04-28T12:27:40.7864124+04:00"},{"id":35456,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"c331a645eb7848bda9b3f651866478ec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 789-883","gmt_create":"2026-04-28T12:27:40.7869301+04:00","gmt_modified":"2026-04-28T12:27:40.7869301+04:00"},{"id":35458,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"06ca849a27b79d1edd6a6faaabf7a1fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1400-1484","gmt_create":"2026-04-28T12:27:40.7869301+04:00","gmt_modified":"2026-04-28T12:27:40.7869301+04:00"},{"id":35460,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"9102ca0b920a6d527e069776bf786565","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1046-1288","gmt_create":"2026-04-28T12:27:40.7874488+04:00","gmt_modified":"2026-04-28T12:27:40.7874488+04:00"},{"id":35462,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"272ad74758e94f746c862c4c91c17496","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1902-2038","gmt_create":"2026-04-28T12:27:40.7874488+04:00","gmt_modified":"2026-04-28T12:27:40.7874488+04:00"},{"id":35464,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"ea6973621046033cdcd6899b7a2bcb0f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1470-1599","gmt_create":"2026-04-28T12:27:40.7879647+04:00","gmt_modified":"2026-04-28T12:27:40.7879647+04:00"},{"id":35466,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"2f7386ded19c5e4ae6581ef6148fdd81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2473-2510","gmt_create":"2026-04-28T12:27:40.7884803+04:00","gmt_modified":"2026-04-28T12:27:40.7884803+04:00"},{"id":35468,"source_id":"4d5bf798ac6e167d6d0e20a669431373","target_id":"5fcc5bdcf25fd73b110eede565277186","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 247-273","gmt_create":"2026-04-28T12:27:40.7890081+04:00","gmt_modified":"2026-04-28T12:27:40.7890081+04:00"},{"id":35470,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"7c62e5936f0fc7f60f9a5587800a2578","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1418-1436","gmt_create":"2026-04-28T12:27:40.7895307+04:00","gmt_modified":"2026-04-28T12:27:40.7895307+04:00"},{"id":35472,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"983d0185105181e4f539d636abc549c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 737-743","gmt_create":"2026-04-28T12:27:40.7900433+04:00","gmt_modified":"2026-04-28T12:27:40.7900433+04:00"},{"id":35474,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"82acc28cade2d06dac2a207816ccf888","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1390-1484","gmt_create":"2026-04-28T12:27:40.7900433+04:00","gmt_modified":"2026-04-28T12:27:40.7900433+04:00"},{"id":35476,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"1d3d2cb1a9886c18b5c14d6f4bbbec7c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1440-1449","gmt_create":"2026-04-28T12:27:40.790638+04:00","gmt_modified":"2026-04-28T12:27:40.790638+04:00"},{"id":35478,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"de42aaaef014331a40dc6a645093a785","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 335-551","gmt_create":"2026-04-28T12:27:40.790638+04:00","gmt_modified":"2026-04-28T12:27:40.790638+04:00"},{"id":35480,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"e9427d96ecb45f8e18859dbaff6e2b3a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1326-1376","gmt_create":"2026-04-28T12:27:40.7911415+04:00","gmt_modified":"2026-04-28T12:27:40.7911415+04:00"},{"id":35482,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"ddc5b6727e7907a53519cc63983aabb7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1426-1435","gmt_create":"2026-04-28T12:27:40.7916629+04:00","gmt_modified":"2026-04-28T12:27:40.7916629+04:00"},{"id":35484,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"a54238157d7db2d12e89ea767738f5ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 745-750","gmt_create":"2026-04-28T12:27:40.7916629+04:00","gmt_modified":"2026-04-28T12:27:40.7916629+04:00"},{"id":35486,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"8481665c6e787cad6255e9ace82fe2c2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 697-700","gmt_create":"2026-04-28T12:27:40.7921765+04:00","gmt_modified":"2026-04-28T12:27:40.7921765+04:00"},{"id":35488,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"91b6373025370a39784ff61586453267","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2831-2845","gmt_create":"2026-04-28T12:27:40.7921765+04:00","gmt_modified":"2026-04-28T12:27:40.7921765+04:00"},{"id":35490,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"fa6088c57e5552b03a53d22a8b3371cd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1719-1748","gmt_create":"2026-04-28T12:27:40.7927025+04:00","gmt_modified":"2026-04-28T12:27:40.7927025+04:00"},{"id":35492,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"2ef1c85090d0812eda040eb10dbfab00","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1706-1748","gmt_create":"2026-04-28T12:27:40.7927025+04:00","gmt_modified":"2026-04-28T12:27:40.7927025+04:00"},{"id":35494,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"6c4fffc1a4b8a3dccdccf3bc8b6e478c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 490-560","gmt_create":"2026-04-28T12:27:40.7927025+04:00","gmt_modified":"2026-04-28T12:27:40.7927025+04:00"},{"id":35496,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"002084afc1181b400d0ac1f626010b50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2945-2959","gmt_create":"2026-04-28T12:27:40.7932232+04:00","gmt_modified":"2026-04-28T12:27:40.7932232+04:00"},{"id":35498,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a9ac85c210bf25017dc2f3043429bcff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 441-5201","gmt_create":"2026-04-28T12:27:40.7937357+04:00","gmt_modified":"2026-04-28T12:27:40.7937357+04:00"},{"id":35500,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"4083d0aedccff773e235c49f483acdee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 542-559","gmt_create":"2026-04-28T12:27:40.7942525+04:00","gmt_modified":"2026-04-28T12:27:40.7942525+04:00"},{"id":35502,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"5b61f5ff88b75190fc4b2051750444dd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2976-3009","gmt_create":"2026-04-28T12:27:40.7942525+04:00","gmt_modified":"2026-04-28T12:27:40.7942525+04:00"},{"id":35504,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"133becde6f5eef3f56c38aa3650af39f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2468-2570","gmt_create":"2026-04-28T12:27:40.7947682+04:00","gmt_modified":"2026-04-28T12:27:40.7947682+04:00"},{"id":35506,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"7c3bbfa78db4dbdd170795e4ff786767","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 689-697","gmt_create":"2026-04-28T12:27:40.7947682+04:00","gmt_modified":"2026-04-28T12:27:40.7947682+04:00"},{"id":35508,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"de95ec3c9606ef77f32c319a1cee9d67","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5241-5274","gmt_create":"2026-04-28T12:27:40.7953867+04:00","gmt_modified":"2026-04-28T12:27:40.7953867+04:00"},{"id":35510,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"4ad076dd99ea06a22ba2703dfdfbef50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 284-290","gmt_create":"2026-04-28T12:27:40.8035734+04:00","gmt_modified":"2026-04-28T12:27:40.8035734+04:00"},{"id":35512,"source_id":"bd196d115b6bd3d5310dfa247f1e25b2","target_id":"d21d0e6c03944b9bd0683917197d45ec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-88","gmt_create":"2026-04-28T12:27:40.8035734+04:00","gmt_modified":"2026-04-28T12:27:40.8035734+04:00"},{"id":35514,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"ce8c1f15287ef92650480373eef95fb8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 735-740","gmt_create":"2026-04-28T12:27:40.8045729+04:00","gmt_modified":"2026-04-28T12:27:40.8045729+04:00"},{"id":35516,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"474f1f81f21526cb90fc2564fdc36457","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1814-1862","gmt_create":"2026-04-28T12:27:40.8045729+04:00","gmt_modified":"2026-04-28T12:27:40.8045729+04:00"},{"id":35518,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"3fcde09e22fa6291183075924ea0ea2a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 772-785","gmt_create":"2026-04-28T12:27:40.8045729+04:00","gmt_modified":"2026-04-28T12:27:40.8045729+04:00"},{"id":35520,"source_id":"4d5bf798ac6e167d6d0e20a669431373","target_id":"25271321cea3b037da1bd49f4a9c73e3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 339-374","gmt_create":"2026-04-28T12:27:40.8045729+04:00","gmt_modified":"2026-04-28T12:27:40.8045729+04:00"},{"id":35522,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"ffac59891823846e038c48de0f7fa754","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 585-649","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35524,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"ce8fa82841cb9ff1bb572dde21cd2dca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 673-677","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35526,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"31a0e1cdb8f61a661ea048c18a0c31ab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 744-755","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35528,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"e360b37afb60df02b8a51d89f141bf95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 165-176","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35530,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"a4b87380168ea56eda2691254c138879","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1587-1596","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35532,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"0442d9dfa5137479a458da6803ce6d7d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1610-1620","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35534,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"5f1666b71febd2ce3545e7b9c05598fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1812-1877","gmt_create":"2026-04-28T12:27:40.8055727+04:00","gmt_modified":"2026-04-28T12:27:40.8055727+04:00"},{"id":35536,"source_id":"bd196d115b6bd3d5310dfa247f1e25b2","target_id":"f7cc310f8ee11ed3c2ac13ce575146d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-34","gmt_create":"2026-04-28T12:27:40.8070771+04:00","gmt_modified":"2026-04-28T12:27:40.8070771+04:00"},{"id":35538,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"24d1f458412bbfade9d25c0ed1521322","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2598-2680","gmt_create":"2026-04-28T12:27:40.8076056+04:00","gmt_modified":"2026-04-28T12:27:40.8076056+04:00"},{"id":35540,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"985521912575155bfda8b7bce74494df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 364-432","gmt_create":"2026-04-28T12:27:40.8076056+04:00","gmt_modified":"2026-04-28T12:27:40.8076056+04:00"},{"id":35542,"source_id":"dc43b9a20a2ae22effbe51aecf8ca751","target_id":"299aedc88851dabd155fc2edbbad96ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-38","gmt_create":"2026-04-28T12:27:40.8076056+04:00","gmt_modified":"2026-04-28T12:27:40.8076056+04:00"},{"id":35544,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"2a76e2c48df7946c93b84c330a1c08ae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2294-2464","gmt_create":"2026-04-28T12:27:40.8081245+04:00","gmt_modified":"2026-04-28T12:27:40.8081245+04:00"},{"id":35546,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"d7fc3783ff3c58fa7beaff10948417fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1378-1464","gmt_create":"2026-04-28T12:27:40.8081245+04:00","gmt_modified":"2026-04-28T12:27:40.8081245+04:00"},{"id":35683,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"4238a9561f85e50a38f76813baeadd7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/block_log.hpp","gmt_create":"2026-04-28T12:54:08.0803549+04:00","gmt_modified":"2026-04-28T12:54:08.0803549+04:00"},{"id":35684,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"d2090ff9016be0d896d06e843936e0f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/block_log.cpp","gmt_create":"2026-04-28T12:54:08.0803549+04:00","gmt_modified":"2026-04-28T12:54:08.0803549+04:00"},{"id":35685,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-28T12:54:08.0803549+04:00","gmt_modified":"2026-04-28T12:54:08.0803549+04:00"},{"id":35686,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-28T12:54:08.0808764+04:00","gmt_modified":"2026-04-28T12:54:08.0808764+04:00"},{"id":35687,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-28T12:54:08.0819174+04:00","gmt_modified":"2026-04-28T12:54:08.0819174+04:00"},{"id":35688,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-28T12:54:08.0819174+04:00","gmt_modified":"2026-04-28T12:54:08.0819174+04:00"},{"id":35689,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-28T12:54:08.0824359+04:00","gmt_modified":"2026-04-28T12:54:08.0824359+04:00"},{"id":35690,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-28T12:54:08.0824359+04:00","gmt_modified":"2026-04-28T12:54:08.0824359+04:00"},{"id":35691,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"d6fb716d9203d54e5aaccd580adc4703","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/block.hpp","gmt_create":"2026-04-28T12:54:08.0824359+04:00","gmt_modified":"2026-04-28T12:54:08.0824359+04:00"},{"id":35692,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"3b0d308523637c64e62fac4d1a2a4a66","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/block_header.hpp","gmt_create":"2026-04-28T12:54:08.0824359+04:00","gmt_modified":"2026-04-28T12:54:08.0824359+04:00"},{"id":35693,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"0dd2a38630da83b11fb3596ad4d60705","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/include/graphene/plugins/witness/witness.hpp","gmt_create":"2026-04-28T12:54:08.0824359+04:00","gmt_modified":"2026-04-28T12:54:08.0824359+04:00"},{"id":35694,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-28T12:54:08.0829598+04:00","gmt_modified":"2026-04-28T12:54:08.0829598+04:00"},{"id":35695,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"cb29035725926be38d36ad8c01792b7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database_exceptions.hpp","gmt_create":"2026-04-28T12:54:08.0829598+04:00","gmt_modified":"2026-04-28T12:54:08.0829598+04:00"},{"id":35696,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"0acaf479cbd8b11ed2774cc96aa68335","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/block_header.hpp#1-43","gmt_create":"2026-04-28T12:54:08.0829598+04:00","gmt_modified":"2026-04-28T12:54:08.0829598+04:00"},{"id":35697,"source_id":"3b0d308523637c64e62fac4d1a2a4a66","target_id":"0acaf479cbd8b11ed2774cc96aa68335","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-43","gmt_create":"2026-04-28T12:54:08.0829598+04:00","gmt_modified":"2026-04-28T12:54:08.0829598+04:00"},{"id":35698,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"65b16a5b2283f9a71e063b5381577bae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/block.hpp#1-19","gmt_create":"2026-04-28T12:54:08.0834764+04:00","gmt_modified":"2026-04-28T12:54:08.0834764+04:00"},{"id":35699,"source_id":"d6fb716d9203d54e5aaccd580adc4703","target_id":"65b16a5b2283f9a71e063b5381577bae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-19","gmt_create":"2026-04-28T12:54:08.0834764+04:00","gmt_modified":"2026-04-28T12:54:08.0834764+04:00"},{"id":35700,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"54d3aec8b80d5706beb75720a6232861","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#1-561","gmt_create":"2026-04-28T12:54:08.0834764+04:00","gmt_modified":"2026-04-28T12:54:08.0834764+04:00"},{"id":35701,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"54d3aec8b80d5706beb75720a6232861","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-561","gmt_create":"2026-04-28T12:54:08.083993+04:00","gmt_modified":"2026-04-28T12:54:08.083993+04:00"},{"id":35702,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"0b148db227f6081cc819c2f686550d84","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#737-913","gmt_create":"2026-04-28T12:54:08.083993+04:00","gmt_modified":"2026-04-28T12:54:08.083993+04:00"},{"id":35703,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"0b148db227f6081cc819c2f686550d84","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 737-913","gmt_create":"2026-04-28T12:54:08.083993+04:00","gmt_modified":"2026-04-28T12:54:08.083993+04:00"},{"id":35704,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"3409eb023f550b5d11bccc50d317764a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#1-125","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35705,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"3409eb023f550b5d11bccc50d317764a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-125","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35706,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"e29d6a6310d6247eaf38fa2c35b35373","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#33-90","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35707,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"e29d6a6310d6247eaf38fa2c35b35373","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-90","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35708,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"2c17018b7a7ecf1dd7b6432e97d0a586","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#1-75","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35709,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"faea01a77c78aa0e75d22b0d5cafa704","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#238-300","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35710,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"faea01a77c78aa0e75d22b0d5cafa704","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 238-300","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35711,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"6ebf29a038d578e8864ca6c9c9366bda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#1-76","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35712,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"60cef3a5a468a40533451ed7d7e09503","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#162-242","gmt_create":"2026-04-28T12:54:08.0845151+04:00","gmt_modified":"2026-04-28T12:54:08.0845151+04:00"},{"id":35713,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"60cef3a5a468a40533451ed7d7e09503","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 162-242","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35714,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"10f717e60b716201555827209e101cba","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#1-70","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35715,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"10f717e60b716201555827209e101cba","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-70","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35716,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"04c7b01cbc51b1f23ab4704279190eda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#295-341","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35717,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"04c7b01cbc51b1f23ab4704279190eda","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 295-341","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35718,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"11090a858982a9991f12a111ff65ebec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/block.hpp#9-13","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35719,"source_id":"d6fb716d9203d54e5aaccd580adc4703","target_id":"11090a858982a9991f12a111ff65ebec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-13","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35720,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"91b8b7279712d5789fb67e0c06442732","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/block_header.hpp#25-35","gmt_create":"2026-04-28T12:54:08.0855185+04:00","gmt_modified":"2026-04-28T12:54:08.0855185+04:00"},{"id":35721,"source_id":"3b0d308523637c64e62fac4d1a2a4a66","target_id":"91b8b7279712d5789fb67e0c06442732","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-35","gmt_create":"2026-04-28T12:54:08.0870693+04:00","gmt_modified":"2026-04-28T12:54:08.0870693+04:00"},{"id":35722,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"5800e8f7ef6353fa3f37c39ea75ff454","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#53-96","gmt_create":"2026-04-28T12:54:08.0870693+04:00","gmt_modified":"2026-04-28T12:54:08.0870693+04:00"},{"id":35723,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"5800e8f7ef6353fa3f37c39ea75ff454","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-96","gmt_create":"2026-04-28T12:54:08.0870693+04:00","gmt_modified":"2026-04-28T12:54:08.0870693+04:00"},{"id":35724,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"6da448acd4e86b4234427febab48fbca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#38-68","gmt_create":"2026-04-28T12:54:08.0870693+04:00","gmt_modified":"2026-04-28T12:54:08.0870693+04:00"},{"id":35725,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"6da448acd4e86b4234427febab48fbca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-68","gmt_create":"2026-04-28T12:54:08.0870693+04:00","gmt_modified":"2026-04-28T12:54:08.0870693+04:00"},{"id":35726,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"35d8d0314587b8714a154437fe7243af","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#13-33","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35727,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"35d8d0314587b8714a154437fe7243af","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-33","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35728,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"827fa8459b891ae8c31d3194640245da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#36-287","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35729,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"827fa8459b891ae8c31d3194640245da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-287","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35730,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"7d0d371be208eb98ecc21b182f56ab1b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#20-32","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35731,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"7d0d371be208eb98ecc21b182f56ab1b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-32","gmt_create":"2026-04-28T12:54:08.088074+04:00","gmt_modified":"2026-04-28T12:54:08.088074+04:00"},{"id":35732,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"0b84b82025c87f3b725ddf0c3804f197","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#253-257","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35733,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"0b84b82025c87f3b725ddf0c3804f197","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 253-257","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35734,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"01b277ebba52e972b94566a19ab057fd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#336-340","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35735,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"01b277ebba52e972b94566a19ab057fd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 336-340","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35736,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"161ddc3f0d369da41719390d93b735c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#194-206","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35737,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"161ddc3f0d369da41719390d93b735c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 194-206","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35738,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"d4957d3a60b33265b5b19edffd627403","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#737-757","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35739,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d4957d3a60b33265b5b19edffd627403","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 737-757","gmt_create":"2026-04-28T12:54:08.0890755+04:00","gmt_modified":"2026-04-28T12:54:08.0890755+04:00"},{"id":35740,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"9025ea64db0b2dfc92ca8bab0394cc08","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3443-3509","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35741,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"9025ea64db0b2dfc92ca8bab0394cc08","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3443-3509","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35742,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"fa4bc24d813810d4fe658d78919900b7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#812-825","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35743,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"fa4bc24d813810d4fe658d78919900b7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 812-825","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35744,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"423e0e34f575bf3a7563c57bb997739b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#56-73","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35745,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"423e0e34f575bf3a7563c57bb997739b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-73","gmt_create":"2026-04-28T12:54:08.0900741+04:00","gmt_modified":"2026-04-28T12:54:08.0900741+04:00"},{"id":35746,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"c7518bf7e6927e1b54afebcbb8cf3d5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#168-210","gmt_create":"2026-04-28T12:54:08.0911239+04:00","gmt_modified":"2026-04-28T12:54:08.0911239+04:00"},{"id":35747,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"c7518bf7e6927e1b54afebcbb8cf3d5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 168-210","gmt_create":"2026-04-28T12:54:08.0911239+04:00","gmt_modified":"2026-04-28T12:54:08.0911239+04:00"},{"id":35748,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"f8faa71211c346e22bdea2dbbd1cc994","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#134-193","gmt_create":"2026-04-28T12:54:08.0911239+04:00","gmt_modified":"2026-04-28T12:54:08.0911239+04:00"},{"id":35749,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"f8faa71211c346e22bdea2dbbd1cc994","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 134-193","gmt_create":"2026-04-28T12:54:08.0911239+04:00","gmt_modified":"2026-04-28T12:54:08.0911239+04:00"},{"id":35750,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"fd6ccb853bf752497d776a99eba9c7e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#115-132","gmt_create":"2026-04-28T12:54:08.0911239+04:00","gmt_modified":"2026-04-28T12:54:08.0911239+04:00"},{"id":35751,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"fd6ccb853bf752497d776a99eba9c7e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 115-132","gmt_create":"2026-04-28T12:54:08.0921227+04:00","gmt_modified":"2026-04-28T12:54:08.0921227+04:00"},{"id":35752,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"6d71835687e91bd31fc0bba06adc43a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#195-219","gmt_create":"2026-04-28T12:54:08.0921227+04:00","gmt_modified":"2026-04-28T12:54:08.0921227+04:00"},{"id":35753,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"6d71835687e91bd31fc0bba06adc43a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 195-219","gmt_create":"2026-04-28T12:54:08.0921227+04:00","gmt_modified":"2026-04-28T12:54:08.0921227+04:00"},{"id":35754,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"21313db2130a5ad3661163e46e6eb28d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#13-36","gmt_create":"2026-04-28T12:54:08.0921227+04:00","gmt_modified":"2026-04-28T12:54:08.0921227+04:00"},{"id":35755,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"21313db2130a5ad3661163e46e6eb28d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 13-36","gmt_create":"2026-04-28T12:54:08.0921227+04:00","gmt_modified":"2026-04-28T12:54:08.0921227+04:00"},{"id":35756,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"1cd86ca915ed082dac6b3930d1822c8d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#846-913","gmt_create":"2026-04-28T12:54:08.0931234+04:00","gmt_modified":"2026-04-28T12:54:08.0931234+04:00"},{"id":35757,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1cd86ca915ed082dac6b3930d1822c8d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 846-913","gmt_create":"2026-04-28T12:54:08.0931234+04:00","gmt_modified":"2026-04-28T12:54:08.0931234+04:00"},{"id":35758,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"180a1810a21b0ec9cfa9bf2239b68849","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#47-71","gmt_create":"2026-04-28T12:54:08.0931234+04:00","gmt_modified":"2026-04-28T12:54:08.0931234+04:00"},{"id":35759,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"180a1810a21b0ec9cfa9bf2239b68849","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-71","gmt_create":"2026-04-28T12:54:08.0931234+04:00","gmt_modified":"2026-04-28T12:54:08.0931234+04:00"},{"id":35760,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"3e995e6e2441ab172c06a81ab175d467","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#79-90","gmt_create":"2026-04-28T12:54:08.1006305+04:00","gmt_modified":"2026-04-28T12:54:08.1006305+04:00"},{"id":35761,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"3e995e6e2441ab172c06a81ab175d467","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-90","gmt_create":"2026-04-28T12:54:08.1006305+04:00","gmt_modified":"2026-04-28T12:54:08.1006305+04:00"},{"id":35762,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"742afd64fbe28a0b4b264ad2c80c3f13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#34-65","gmt_create":"2026-04-28T12:54:08.1006305+04:00","gmt_modified":"2026-04-28T12:54:08.1006305+04:00"},{"id":35763,"source_id":"0dd2a38630da83b11fb3596ad4d60705","target_id":"742afd64fbe28a0b4b264ad2c80c3f13","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-65","gmt_create":"2026-04-28T12:54:08.1016326+04:00","gmt_modified":"2026-04-28T12:54:08.1016326+04:00"},{"id":35764,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"8982624b20d4012f524d7608d0e898df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#214-226","gmt_create":"2026-04-28T12:54:08.1016326+04:00","gmt_modified":"2026-04-28T12:54:08.1016326+04:00"},{"id":35765,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"8982624b20d4012f524d7608d0e898df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 214-226","gmt_create":"2026-04-28T12:54:08.1016326+04:00","gmt_modified":"2026-04-28T12:54:08.1016326+04:00"},{"id":35766,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"ed8569143dcfa15ac6f3519b0aa6b31b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#423-428","gmt_create":"2026-04-28T12:54:08.1026317+04:00","gmt_modified":"2026-04-28T12:54:08.1026317+04:00"},{"id":35767,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"ed8569143dcfa15ac6f3519b0aa6b31b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 423-428","gmt_create":"2026-04-28T12:54:08.1026317+04:00","gmt_modified":"2026-04-28T12:54:08.1026317+04:00"},{"id":35768,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"dea1056d264deb0399cea4b15ce31eff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#38-44","gmt_create":"2026-04-28T12:54:08.1036312+04:00","gmt_modified":"2026-04-28T12:54:08.1036312+04:00"},{"id":35769,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"dea1056d264deb0399cea4b15ce31eff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-44","gmt_create":"2026-04-28T12:54:08.1036312+04:00","gmt_modified":"2026-04-28T12:54:08.1036312+04:00"},{"id":35770,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"9050957c1241bdff17fa2cda2294cc02","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#83-83","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35771,"source_id":"cb29035725926be38d36ad8c01792b7e","target_id":"9050957c1241bdff17fa2cda2294cc02","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 83-83","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35772,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"69496892894b525caf293d463cec60ac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#163-193","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35773,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"69496892894b525caf293d463cec60ac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 163-193","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35774,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"7a0064bf94d855137c23263ebefc4086","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#305-307","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35775,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"7a0064bf94d855137c23263ebefc4086","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 305-307","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35776,"source_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","target_id":"4f05f855970de061eacdd41742b1c8f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5395-5419","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35777,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"4f05f855970de061eacdd41742b1c8f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5395-5419","gmt_create":"2026-04-28T12:54:08.1046315+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"id":35789,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"620825701e1a1b114e822bbda1ceb234","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-454","gmt_create":"2026-04-28T12:55:56.0979984+04:00","gmt_modified":"2026-04-28T12:55:56.0979984+04:00"},{"id":35792,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"233a2d8be5340ec151c42900fcd58a96","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 220-271","gmt_create":"2026-04-28T12:55:56.0979984+04:00","gmt_modified":"2026-04-28T12:55:56.0979984+04:00"},{"id":35794,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"02b88f06fab1f8f2b384ec38dfea95a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-258","gmt_create":"2026-04-28T12:55:56.0989987+04:00","gmt_modified":"2026-04-28T12:55:56.0989987+04:00"},{"id":35796,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"c6c440b24137364c19bc7fe7a800ce3e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 320-330","gmt_create":"2026-04-28T12:55:56.0989987+04:00","gmt_modified":"2026-04-28T12:55:56.0989987+04:00"},{"id":35798,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"7c7114ff694eca47458deb9031af3874","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1960-2039","gmt_create":"2026-04-28T12:55:56.0989987+04:00","gmt_modified":"2026-04-28T12:55:56.0989987+04:00"},{"id":35800,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5c9a153931730742e72d3183f4f76128","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 255-286","gmt_create":"2026-04-28T12:55:56.0989987+04:00","gmt_modified":"2026-04-28T12:55:56.0989987+04:00"},{"id":35802,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"77740b8f659f6e4296624292e035f0b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 515-516","gmt_create":"2026-04-28T12:55:56.0999988+04:00","gmt_modified":"2026-04-28T12:55:56.0999988+04:00"},{"id":35805,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"44c647e6bdaeba8176c9fd58d7bf204f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 18-278","gmt_create":"2026-04-28T12:55:56.1009972+04:00","gmt_modified":"2026-04-28T12:55:56.1009972+04:00"},{"id":35807,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1fec0c281b15b8cb253758a81bda9d53","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 230-231","gmt_create":"2026-04-28T12:55:56.1009972+04:00","gmt_modified":"2026-04-28T12:55:56.1009972+04:00"},{"id":35809,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"20be4db8cc88d28b2576cc8c6640d89d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-28","gmt_create":"2026-04-28T12:55:56.1009972+04:00","gmt_modified":"2026-04-28T12:55:56.1009972+04:00"},{"id":35811,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"4aaf8248e16bc831caf0d6215227a347","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 327-329","gmt_create":"2026-04-28T12:55:56.101998+04:00","gmt_modified":"2026-04-28T12:55:56.101998+04:00"},{"id":35813,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"2496b05edb9e2cce32ff03d614866f80","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1968-1970","gmt_create":"2026-04-28T12:55:56.101998+04:00","gmt_modified":"2026-04-28T12:55:56.101998+04:00"},{"id":35815,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"bd936d7f114a4d7505d38477591a432b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 265-272","gmt_create":"2026-04-28T12:55:56.101998+04:00","gmt_modified":"2026-04-28T12:55:56.101998+04:00"},{"id":35817,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"09e49fa0e3657a309d205da532bae0d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1414-1500","gmt_create":"2026-04-28T12:55:56.101998+04:00","gmt_modified":"2026-04-28T12:55:56.101998+04:00"},{"id":35819,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"89fd5aa6e93582e3684130e9c0920e33","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 438-544","gmt_create":"2026-04-28T12:55:56.101998+04:00","gmt_modified":"2026-04-28T12:55:56.101998+04:00"},{"id":35821,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1e55d2aee2f6d3f5d6247eb14ca9350a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 230-268","gmt_create":"2026-04-28T12:55:56.1030316+04:00","gmt_modified":"2026-04-28T12:55:56.1030316+04:00"},{"id":35823,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"05c7b54032266aa804fecdd672849759","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 560-627","gmt_create":"2026-04-28T12:55:56.1030316+04:00","gmt_modified":"2026-04-28T12:55:56.1030316+04:00"},{"id":35825,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"d00cc75cac98bab547f7549076e3504d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 238-241","gmt_create":"2026-04-28T12:55:56.1030316+04:00","gmt_modified":"2026-04-28T12:55:56.1030316+04:00"},{"id":35827,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"3f58d42a32421c25e81f24320b1d1f20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 313-328","gmt_create":"2026-04-28T12:55:56.1030316+04:00","gmt_modified":"2026-04-28T12:55:56.1030316+04:00"},{"id":35829,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"7a9e26fca49ab5e068040d1db9fed41f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 259-286","gmt_create":"2026-04-28T12:55:56.1040322+04:00","gmt_modified":"2026-04-28T12:55:56.1040322+04:00"},{"id":35831,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"d059ab60b812d6e824e8fef796efa497","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 161-209","gmt_create":"2026-04-28T12:55:56.1040322+04:00","gmt_modified":"2026-04-28T12:55:56.1040322+04:00"},{"id":35833,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"343b12b915179b0ceab0474a3260def1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 125-159","gmt_create":"2026-04-28T12:55:56.1050323+04:00","gmt_modified":"2026-04-28T12:55:56.1050323+04:00"},{"id":35835,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"edc66ae920408eb6412dad9e65c69f63","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 211-268","gmt_create":"2026-04-28T12:55:56.1050323+04:00","gmt_modified":"2026-04-28T12:55:56.1050323+04:00"},{"id":35837,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"c87f750598b8e3aeb391ebd49f3c8730","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 356-411","gmt_create":"2026-04-28T12:55:56.1060321+04:00","gmt_modified":"2026-04-28T12:55:56.1060321+04:00"},{"id":35839,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"85e42052e68826778bf6fc0a5c348061","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 266-292","gmt_create":"2026-04-28T12:55:56.1060321+04:00","gmt_modified":"2026-04-28T12:55:56.1060321+04:00"},{"id":35841,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"44fcac467d4197ec65011a88dcc9b983","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 942-1054","gmt_create":"2026-04-28T12:55:56.1070331+04:00","gmt_modified":"2026-04-28T12:55:56.1070331+04:00"},{"id":35843,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"d866d0710f48a708f384cfe833d19819","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2790-2791","gmt_create":"2026-04-28T12:55:56.1070331+04:00","gmt_modified":"2026-04-28T12:55:56.1070331+04:00"},{"id":35845,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"cc2057fd8aeaa6b63ca70e0d4192d8f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 542-555","gmt_create":"2026-04-28T12:55:56.108034+04:00","gmt_modified":"2026-04-28T12:55:56.108034+04:00"},{"id":35847,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"01a99d91c53d13ef4ba094c44e59df35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-65","gmt_create":"2026-04-28T12:55:56.108034+04:00","gmt_modified":"2026-04-28T12:55:56.108034+04:00"},{"id":35849,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"93d04b438bd28d7bb695e44a81c65fad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 146-159","gmt_create":"2026-04-28T12:55:56.108034+04:00","gmt_modified":"2026-04-28T12:55:56.108034+04:00"},{"id":35851,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"bdb42378c1617c8167b38c65ff9277f8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 253-297","gmt_create":"2026-04-28T12:55:56.108034+04:00","gmt_modified":"2026-04-28T12:55:56.108034+04:00"},{"id":35853,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"5985a883b7cd6e373fa45e06af549458","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 172-202","gmt_create":"2026-04-28T12:55:56.1090334+04:00","gmt_modified":"2026-04-28T12:55:56.1090334+04:00"},{"id":35855,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"27ad3a44022480b087c9dee522cf8f53","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 432-444","gmt_create":"2026-04-28T12:55:56.1090334+04:00","gmt_modified":"2026-04-28T12:55:56.1090334+04:00"},{"id":35857,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5df133f8f7e5465f2256280233f7492a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4005-4036","gmt_create":"2026-04-28T12:55:56.1100329+04:00","gmt_modified":"2026-04-28T12:55:56.1100329+04:00"},{"id":35859,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7ed16e639125b23aeb82bbb3768334fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4170-4172","gmt_create":"2026-04-28T12:55:56.1100329+04:00","gmt_modified":"2026-04-28T12:55:56.1100329+04:00"},{"id":35861,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ed64be85dbceaa49c4d38b1fd7b0537f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4392-4394","gmt_create":"2026-04-28T12:55:56.1175534+04:00","gmt_modified":"2026-04-28T12:55:56.1175534+04:00"},{"id":35863,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"770f933f07c1261bce810845c6711ec4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4043-4047","gmt_create":"2026-04-28T12:55:56.1175534+04:00","gmt_modified":"2026-04-28T12:55:56.1175534+04:00"},{"id":35865,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5988d2bd7b0d5bec2b97a885d1928110","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4189-4192","gmt_create":"2026-04-28T12:55:56.1185519+04:00","gmt_modified":"2026-04-28T12:55:56.1185519+04:00"},{"id":35867,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a9078dfa0e86bfbf3c1bef4a473eb117","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4419-4421","gmt_create":"2026-04-28T12:55:56.1185519+04:00","gmt_modified":"2026-04-28T12:55:56.1185519+04:00"},{"id":35869,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"4af3002393266cb7f00332d69f2019ca","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 233-236","gmt_create":"2026-04-28T12:55:56.1185519+04:00","gmt_modified":"2026-04-28T12:55:56.1185519+04:00"},{"id":35871,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"36faa15d1b9669c10ef981b57dd230bc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 326-329","gmt_create":"2026-04-28T12:55:56.1195517+04:00","gmt_modified":"2026-04-28T12:55:56.1195517+04:00"},{"id":35873,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"69112cf16468224f02ecd1fbd49ea64f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-28T12:55:56.1195517+04:00","gmt_modified":"2026-04-28T12:55:56.1195517+04:00"},{"id":35875,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"6456782ce4d45cbdc58f90d5677ca2c2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-7","gmt_create":"2026-04-28T12:55:56.1195517+04:00","gmt_modified":"2026-04-28T12:55:56.1195517+04:00"},{"id":35877,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"fce2bc849f6a01aeb1da861120260037","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6","gmt_create":"2026-04-28T12:55:56.1195517+04:00","gmt_modified":"2026-04-28T12:55:56.1195517+04:00"},{"id":35879,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ab61b06105c0618ce476f62fc42d04c5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-28T12:55:56.1195517+04:00","gmt_modified":"2026-04-28T12:55:56.1195517+04:00"},{"id":35881,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"cf34d537814cc823a0786b3fa43ffca0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6","gmt_create":"2026-04-28T12:55:56.1205515+04:00","gmt_modified":"2026-04-28T12:55:56.1205515+04:00"},{"id":35883,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"7bd018a7b3dab28cc6792e89ffa39efd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-28T12:55:56.1205515+04:00","gmt_modified":"2026-04-28T12:55:56.1205515+04:00"},{"id":35885,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"96e5aca4a37cf627dff138e440efffa2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-04-28T12:55:56.1205515+04:00","gmt_modified":"2026-04-28T12:55:56.1205515+04:00"},{"id":35887,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"8e436d067efeeee9365369d51dc3fd02","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 250-271","gmt_create":"2026-04-28T12:55:56.121552+04:00","gmt_modified":"2026-04-28T12:55:56.121552+04:00"},{"id":35889,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2fb2b5eefe1dda70f9332bca41575f3d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 259-268","gmt_create":"2026-04-28T12:55:56.121552+04:00","gmt_modified":"2026-04-28T12:55:56.121552+04:00"},{"id":35891,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5864019a1f5c741338aa5810a4a9a2a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 262-267","gmt_create":"2026-04-28T12:55:56.122552+04:00","gmt_modified":"2026-04-28T12:55:56.122552+04:00"},{"id":35893,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ac84b774b43ade0dc3ca1ecbd3b60ea5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 576-580","gmt_create":"2026-04-28T12:55:56.122552+04:00","gmt_modified":"2026-04-28T12:55:56.122552+04:00"},{"id":35895,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"29ef92399939d0e10862168a6d547c18","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 609-613","gmt_create":"2026-04-28T12:55:56.122552+04:00","gmt_modified":"2026-04-28T12:55:56.122552+04:00"},{"id":35897,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"50f4656fe0d323b661f41cd93f59398f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 599-621","gmt_create":"2026-04-28T12:55:56.1235737+04:00","gmt_modified":"2026-04-28T12:55:56.1235737+04:00"},{"id":35899,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f1468b7365f4d06080c1395db0eb5819","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 623-640","gmt_create":"2026-04-28T12:55:56.1235737+04:00","gmt_modified":"2026-04-28T12:55:56.1235737+04:00"},{"id":35901,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"06b382c82ee3f42c24d858503dcde41b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 241-249","gmt_create":"2026-04-28T12:55:56.1235737+04:00","gmt_modified":"2026-04-28T12:55:56.1235737+04:00"},{"id":35903,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"ce3f0826aff2367e46f4cd37417c2f67","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 320-325","gmt_create":"2026-04-28T12:55:56.1235737+04:00","gmt_modified":"2026-04-28T12:55:56.1235737+04:00"},{"id":35905,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"55755f9121d991a7682722b9a8b3ab80","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 560-595","gmt_create":"2026-04-28T12:55:56.1245736+04:00","gmt_modified":"2026-04-28T12:55:56.1245736+04:00"},{"id":35907,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"86ba814ebeaa92690f62613e16aa5e7d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 656-697","gmt_create":"2026-04-28T12:55:56.1255737+04:00","gmt_modified":"2026-04-28T12:55:56.1255737+04:00"},{"id":35909,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"ce99ae12d13aaa7b2653e47db773bcce","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1435-1500","gmt_create":"2026-04-28T12:55:56.1255737+04:00","gmt_modified":"2026-04-28T12:55:56.1255737+04:00"},{"id":35911,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"a370301bb49e9efcf0ef5d6724ac9dd2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2691-2696","gmt_create":"2026-04-28T12:55:56.1255737+04:00","gmt_modified":"2026-04-28T12:55:56.1255737+04:00"},{"id":35913,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"09819e68e897288cd817074594e4f548","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2863-2866","gmt_create":"2026-04-28T12:55:56.1265735+04:00","gmt_modified":"2026-04-28T12:55:56.1265735+04:00"},{"id":35915,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b44834f88165b1116477f30dc5f88a3e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4581-4608","gmt_create":"2026-04-28T12:55:56.1265735+04:00","gmt_modified":"2026-04-28T12:55:56.1265735+04:00"},{"id":35917,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"c6612598fe076c0f7d5ca15ca94cf26b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 627-627","gmt_create":"2026-04-28T12:55:56.1265735+04:00","gmt_modified":"2026-04-28T12:55:56.1265735+04:00"},{"id":35919,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"62962be4cb55c4466a47fba7a814b326","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1473-1476","gmt_create":"2026-04-28T12:55:56.1275762+04:00","gmt_modified":"2026-04-28T12:55:56.1275762+04:00"},{"id":35921,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"798b9ae312576643f8fefd434b40bddc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 626-632","gmt_create":"2026-04-28T12:55:56.1275762+04:00","gmt_modified":"2026-04-28T12:55:56.1275762+04:00"},{"id":35923,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"02c2555684691e747182b4078de2ed9b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1472-1477","gmt_create":"2026-04-28T12:55:56.1275762+04:00","gmt_modified":"2026-04-28T12:55:56.1275762+04:00"},{"id":35944,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"acad56e778bef31e851bbfe9812907e3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-655","gmt_create":"2026-04-28T13:00:52.0416758+04:00","gmt_modified":"2026-04-28T13:00:52.0416758+04:00"},{"id":35946,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e9ccdfc3f5a6e39a50944bf264e9f186","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6539","gmt_create":"2026-04-28T13:00:52.0416758+04:00","gmt_modified":"2026-04-28T13:00:52.0416758+04:00"},{"id":35954,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"590d1dfeeb49a4029c52d3c49b2f0362","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-144","gmt_create":"2026-04-28T13:00:52.042675+04:00","gmt_modified":"2026-04-28T13:00:52.042675+04:00"},{"id":35956,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"d599d8eb734647e07f075785246b447f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-278","gmt_create":"2026-04-28T13:00:52.042675+04:00","gmt_modified":"2026-04-28T13:00:52.042675+04:00"},{"id":35971,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"268918c988500bd0972ad80cef38bdd3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-144","gmt_create":"2026-04-28T13:00:52.0466739+04:00","gmt_modified":"2026-04-28T13:00:52.0466739+04:00"},{"id":35989,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f79e33b8389fbdcd06f18bdcc93dc600","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5399-5417","gmt_create":"2026-04-28T13:00:52.0601814+04:00","gmt_modified":"2026-04-28T13:00:52.0601814+04:00"},{"id":35992,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b34a0ea07e8be722ec91b23e3790def6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 805-824","gmt_create":"2026-04-28T13:00:52.0601814+04:00","gmt_modified":"2026-04-28T13:00:52.0601814+04:00"},{"id":35994,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5dbf7e59d79e02ad4264f7fbf7bdd28f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 835-856","gmt_create":"2026-04-28T13:00:52.0601814+04:00","gmt_modified":"2026-04-28T13:00:52.0601814+04:00"},{"id":35996,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b6f94c70f9336700bbf26e4d787f9105","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 859-875","gmt_create":"2026-04-28T13:00:52.0616858+04:00","gmt_modified":"2026-04-28T13:00:52.0616858+04:00"},{"id":35998,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f8046595bff9cdc6c60e330d85bd886a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5080-5105","gmt_create":"2026-04-28T13:00:52.0616858+04:00","gmt_modified":"2026-04-28T13:00:52.0616858+04:00"},{"id":36000,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7b1db3050efae2995a8447733afa6894","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5442-5456","gmt_create":"2026-04-28T13:00:52.0616858+04:00","gmt_modified":"2026-04-28T13:00:52.0616858+04:00"},{"id":36046,"source_id":"9e5f8d60-bebb-4161-a630-0880704f9f81","target_id":"885ce864-d616-4f9f-8a3e-6198a88feda6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9e5f8d60-bebb-4161-a630-0880704f9f81 -\u003e 885ce864-d616-4f9f-8a3e-6198a88feda6","gmt_create":"2026-04-28T13:00:52.7021163+04:00","gmt_modified":"2026-04-28T13:00:52.7021163+04:00"},{"id":36083,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"67775c086bbf192f443fef2bdac726ee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 290-325","gmt_create":"2026-04-28T14:54:15.7093879+04:00","gmt_modified":"2026-04-28T14:54:15.7093879+04:00"},{"id":36085,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"24e53b6bba24767d436a386f584d39b1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 330-364","gmt_create":"2026-04-28T14:54:15.7093879+04:00","gmt_modified":"2026-04-28T14:54:15.7093879+04:00"},{"id":36087,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"e24259987d3c50dee1a87e13d63ccf03","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 57-78","gmt_create":"2026-04-28T14:54:15.7093879+04:00","gmt_modified":"2026-04-28T14:54:15.7093879+04:00"},{"id":36090,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"163647b506865a0b9039e6ab0e61b35b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 290-364","gmt_create":"2026-04-28T14:54:15.7098902+04:00","gmt_modified":"2026-04-28T14:54:15.7098902+04:00"},{"id":36092,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"909f520b94e82193bac04c745bf8f67c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 614-650","gmt_create":"2026-04-28T14:54:15.7098902+04:00","gmt_modified":"2026-04-28T14:54:15.7098902+04:00"},{"id":36094,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"88e819e823c1dfa5a1120f734b8b99e4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 342-350","gmt_create":"2026-04-28T14:54:15.7105432+04:00","gmt_modified":"2026-04-28T14:54:15.7105432+04:00"},{"id":36096,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"de6b88d0d6cc0f704dd82fdef474a555","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 660-724","gmt_create":"2026-04-28T14:54:15.7105432+04:00","gmt_modified":"2026-04-28T14:54:15.7105432+04:00"},{"id":36098,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"e1e9fa05835bc27c4c0c558c27e51829","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 297-323","gmt_create":"2026-04-28T14:54:15.7110456+04:00","gmt_modified":"2026-04-28T14:54:15.7110456+04:00"},{"id":36100,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"bc6ec56aa2075f5d4f63b9761791d35b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 480-487","gmt_create":"2026-04-28T14:54:15.7111308+04:00","gmt_modified":"2026-04-28T14:54:15.7111308+04:00"},{"id":36102,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"c45e7282b5fb1668e8ae6f5a8da708ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 151-208","gmt_create":"2026-04-28T14:54:15.7111308+04:00","gmt_modified":"2026-04-28T14:54:15.7111308+04:00"},{"id":36104,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"cf6fe4716897ebef51503d6e48f458c2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 566-644","gmt_create":"2026-04-28T14:54:15.7111308+04:00","gmt_modified":"2026-04-28T14:54:15.7111308+04:00"},{"id":36106,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"9a05d082478a1b4a7c5d0f3aae5e5d61","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 336-350","gmt_create":"2026-04-28T14:54:15.7116333+04:00","gmt_modified":"2026-04-28T14:54:15.7116333+04:00"},{"id":36108,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"29d1adb11bc96c1e7216be1c31cb57f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 173-204","gmt_create":"2026-04-28T14:54:15.7122299+04:00","gmt_modified":"2026-04-28T14:54:15.7122299+04:00"},{"id":36110,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"a53e81cce3125afb7be85b22de187020","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 951-1020","gmt_create":"2026-04-28T14:54:15.7122299+04:00","gmt_modified":"2026-04-28T14:54:15.7122299+04:00"},{"id":36139,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"b1416c15172aac5cdff13f12c0d385b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 180-355","gmt_create":"2026-04-28T14:54:34.9634137+04:00","gmt_modified":"2026-04-28T14:54:34.9634137+04:00"},{"id":36141,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b2e1954ed604c23c3fe69090870838ec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 869-905","gmt_create":"2026-04-28T14:54:34.9634137+04:00","gmt_modified":"2026-04-28T14:54:34.9634137+04:00"},{"id":36144,"source_id":"3a8d8a10556a0b6501e25aa43e91f913","target_id":"7b85de17d00c3c33f3e6ce72493cea24","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 104-134","gmt_create":"2026-04-28T14:54:34.9644249+04:00","gmt_modified":"2026-04-28T14:54:34.9644249+04:00"},{"id":36146,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"4a47af89ac294fea1a93e8ab87bc62a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-114","gmt_create":"2026-04-28T14:54:34.9722109+04:00","gmt_modified":"2026-04-28T14:54:34.9722109+04:00"},{"id":36148,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"fcf5471e2941c73aa4796f0d15ca9d4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-120","gmt_create":"2026-04-28T14:54:34.972721+04:00","gmt_modified":"2026-04-28T14:54:34.972721+04:00"},{"id":36151,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"7d072be9a3f767f13a99da4cd6df4783","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 110-123","gmt_create":"2026-04-28T14:54:34.973233+04:00","gmt_modified":"2026-04-28T14:54:34.973233+04:00"},{"id":36153,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"4f55b43e070bade6f117e02d6faaaac2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 368-379","gmt_create":"2026-04-28T14:54:34.973233+04:00","gmt_modified":"2026-04-28T14:54:34.973233+04:00"},{"id":36155,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5b2dac9b59c644b7b47e991af481e627","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 330-360","gmt_create":"2026-04-28T14:54:34.973233+04:00","gmt_modified":"2026-04-28T14:54:34.973233+04:00"},{"id":36157,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"d9910f1ea9014fede12810a52c49c4a4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 952-1047","gmt_create":"2026-04-28T14:54:34.9747815+04:00","gmt_modified":"2026-04-28T14:54:34.9747815+04:00"},{"id":36159,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"2d0f35d8035d544c59943ce9488d042e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1623-1654","gmt_create":"2026-04-28T14:54:34.9747815+04:00","gmt_modified":"2026-04-28T14:54:34.9747815+04:00"},{"id":36161,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4cb233e3e08980c2c2c76e7762ad457b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2282-2350","gmt_create":"2026-04-28T14:54:34.975299+04:00","gmt_modified":"2026-04-28T14:54:34.975299+04:00"},{"id":36163,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"465b6e48aad6641d48e75039b1ba6cf7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 869-931","gmt_create":"2026-04-28T14:54:34.975299+04:00","gmt_modified":"2026-04-28T14:54:34.975299+04:00"},{"id":36165,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"64eac8af7d3939075658361c76c2a7f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2029-2230","gmt_create":"2026-04-28T14:54:34.9758158+04:00","gmt_modified":"2026-04-28T14:54:34.9758158+04:00"},{"id":36167,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"63a72fb69b4b837d5841f87d654e6835","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2232-2250","gmt_create":"2026-04-28T14:54:34.9764386+04:00","gmt_modified":"2026-04-28T14:54:34.9764386+04:00"},{"id":36169,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"7d1df83c34f12b0c857fb327e688236b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1400-1621","gmt_create":"2026-04-28T14:54:34.9769418+04:00","gmt_modified":"2026-04-28T14:54:34.9769418+04:00"},{"id":36171,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"3497c413bfbe054ece4588e4c9764e38","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-80","gmt_create":"2026-04-28T14:54:34.9774578+04:00","gmt_modified":"2026-04-28T14:54:34.9774578+04:00"},{"id":36173,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"832f176e5f919dc138e93f3d848899bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3117-3199","gmt_create":"2026-04-28T14:54:34.9774578+04:00","gmt_modified":"2026-04-28T14:54:34.9774578+04:00"},{"id":36175,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"d93f64e1090b7fb0448056ce453003b2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 200-294","gmt_create":"2026-04-28T14:54:34.9779776+04:00","gmt_modified":"2026-04-28T14:54:34.9779776+04:00"},{"id":36177,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"8422adca0104a424dd0293e0e0b74399","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 933-950","gmt_create":"2026-04-28T14:54:34.9779776+04:00","gmt_modified":"2026-04-28T14:54:34.9779776+04:00"},{"id":36179,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"f88975c9b8df22394830934bbd2b8fec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1686-1713","gmt_create":"2026-04-28T14:54:34.9784903+04:00","gmt_modified":"2026-04-28T14:54:34.9784903+04:00"},{"id":36181,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"140ecf3fedde255af2f0a4ce07a0edaa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 211-296","gmt_create":"2026-04-28T14:54:34.9784903+04:00","gmt_modified":"2026-04-28T14:54:34.9784903+04:00"},{"id":36183,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"2a546861a7d7c1c0f13a5e81a60a2663","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1788-1841","gmt_create":"2026-04-28T14:54:34.9784903+04:00","gmt_modified":"2026-04-28T14:54:34.9784903+04:00"},{"id":36185,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"e9dd01a70c4ccc4eff5ea6c67ea751d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1326-1398","gmt_create":"2026-04-28T14:54:34.9789986+04:00","gmt_modified":"2026-04-28T14:54:34.9789986+04:00"},{"id":36187,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"e396600c03187cea5577399428a6bc7a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2830-2892","gmt_create":"2026-04-28T14:54:34.9795086+04:00","gmt_modified":"2026-04-28T14:54:34.9795086+04:00"},{"id":36189,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4d84381505174d8f3190a51bf7d50f11","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-217","gmt_create":"2026-04-28T14:54:34.9795086+04:00","gmt_modified":"2026-04-28T14:54:34.9795086+04:00"},{"id":36191,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"7b14802356f080ebee34dc774e07624c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3574-3629","gmt_create":"2026-04-28T14:54:34.980024+04:00","gmt_modified":"2026-04-28T14:54:34.980024+04:00"},{"id":36193,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"50f62c7fc3da12388428d618747f9efb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3436-3458","gmt_create":"2026-04-28T14:54:34.9806723+04:00","gmt_modified":"2026-04-28T14:54:34.9806723+04:00"},{"id":36195,"source_id":"3948eb588d15d01acf21ffd439ec508c","target_id":"0945d0202cc0f557ece19e5847d25784","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45","gmt_create":"2026-04-28T14:54:34.9806723+04:00","gmt_modified":"2026-04-28T14:54:34.9806723+04:00"},{"id":36197,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"a3bdee51f93df3b62a4e4fdb0a7dedb4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3444-3458","gmt_create":"2026-04-28T14:54:34.9811753+04:00","gmt_modified":"2026-04-28T14:54:34.9811753+04:00"},{"id":36199,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"bbde504b5dfd07112221bccec888d422","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3574-3595","gmt_create":"2026-04-28T14:54:34.9816905+04:00","gmt_modified":"2026-04-28T14:54:34.9816905+04:00"},{"id":36201,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"8ad4beaaf873dcab9dbc1423c81a1be3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3436-3449","gmt_create":"2026-04-28T14:54:34.9816905+04:00","gmt_modified":"2026-04-28T14:54:34.9816905+04:00"},{"id":36203,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"6df9093f4da150f4dc814ac83c7e8e90","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3428-3449","gmt_create":"2026-04-28T14:54:34.9816905+04:00","gmt_modified":"2026-04-28T14:54:34.9816905+04:00"},{"id":36207,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"b8b4ec7ad2e061ee8af94b012e12e61f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 479-489","gmt_create":"2026-04-28T14:54:34.9832283+04:00","gmt_modified":"2026-04-28T14:54:34.9832283+04:00"},{"id":36209,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"61c8442a024b1f3b64d9a00c6fd078be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5015-5030","gmt_create":"2026-04-28T14:54:34.9832283+04:00","gmt_modified":"2026-04-28T14:54:34.9832283+04:00"},{"id":36211,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"fb7100979bb6f3fc24f7989f7d731054","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5042-5050","gmt_create":"2026-04-28T14:54:34.9832283+04:00","gmt_modified":"2026-04-28T14:54:34.9832283+04:00"},{"id":36213,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4d5886271588a3ca7dcd269511761120","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2840-2847","gmt_create":"2026-04-28T14:54:34.9837462+04:00","gmt_modified":"2026-04-28T14:54:34.9837462+04:00"},{"id":36215,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"069b9408b99542da15a9163e6c66de5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2848-2873","gmt_create":"2026-04-28T14:54:34.9837462+04:00","gmt_modified":"2026-04-28T14:54:34.9837462+04:00"},{"id":36217,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b76d7561641e0b9544f923bd5aa66e1e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2395-2500","gmt_create":"2026-04-28T14:54:34.9842585+04:00","gmt_modified":"2026-04-28T14:54:34.9842585+04:00"},{"id":36219,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"5c39e132de390652b9995c75c9dd7b40","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2572-2592","gmt_create":"2026-04-28T14:54:34.9842585+04:00","gmt_modified":"2026-04-28T14:54:34.9842585+04:00"},{"id":36221,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"d9e91362d84f2e5c27205bacead0d8e5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2251-2280","gmt_create":"2026-04-28T14:54:34.9852894+04:00","gmt_modified":"2026-04-28T14:54:34.9852894+04:00"},{"id":36223,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b0c24aab481fd56f8134b091b5bf0525","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2137-2168","gmt_create":"2026-04-28T14:54:34.9858051+04:00","gmt_modified":"2026-04-28T14:54:34.9858051+04:00"},{"id":36225,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"731063774f04d46e1f2c0d64963dfe33","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4455-4460","gmt_create":"2026-04-28T14:54:34.9863217+04:00","gmt_modified":"2026-04-28T14:54:34.9863217+04:00"},{"id":36254,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"733f077750798ad212e3907d2e15c841","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 835-858","gmt_create":"2026-04-28T14:55:54.6734992+04:00","gmt_modified":"2026-04-28T14:55:54.6734992+04:00"},{"id":36308,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"c31e2a585be22edd01d86dba51c51e79","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 294-302","gmt_create":"2026-04-28T14:55:54.6997652+04:00","gmt_modified":"2026-04-28T14:55:54.6997652+04:00"},{"id":36310,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"6ef04fbc3dcdfebcf2580c7e7146cbc3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 317-323","gmt_create":"2026-04-28T14:55:54.6997652+04:00","gmt_modified":"2026-04-28T14:55:54.6997652+04:00"},{"id":36312,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5e4bd94274850728b00115526a2479ee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 860-882","gmt_create":"2026-04-28T14:55:54.7007652+04:00","gmt_modified":"2026-04-28T14:55:54.7007652+04:00"},{"id":36314,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"c53a6db24cea4db25b30783459c40125","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 884-901","gmt_create":"2026-04-28T14:55:54.7007652+04:00","gmt_modified":"2026-04-28T14:55:54.7007652+04:00"},{"id":36317,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"88d1d1609201e580c6cdf488fcd22fad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 370-489","gmt_create":"2026-04-28T14:55:54.7017655+04:00","gmt_modified":"2026-04-28T14:55:54.7017655+04:00"},{"id":36378,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"57113fdc395a5c98d34b2e59cf16018d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5420-5444","gmt_create":"2026-04-28T15:02:14.7764007+04:00","gmt_modified":"2026-04-28T15:02:14.7764007+04:00"},{"id":36381,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"929cc0269a5814a951b45c3300f44597","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 789-827","gmt_create":"2026-04-28T15:02:14.7774004+04:00","gmt_modified":"2026-04-28T15:02:14.7774004+04:00"},{"id":36385,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6abfbb22aee54a4b386173dfc74da72b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5452-5482","gmt_create":"2026-04-28T15:02:14.7784002+04:00","gmt_modified":"2026-04-28T15:02:14.7784002+04:00"},{"id":36387,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2ba1e391be7a79f5151c8abeb655315d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5467-5480","gmt_create":"2026-04-28T15:02:14.7784002+04:00","gmt_modified":"2026-04-28T15:02:14.7784002+04:00"},{"id":36470,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"55ed0cee7e5f683b8caac133899cb8cd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 295-340","gmt_create":"2026-04-28T17:51:11.5952731+04:00","gmt_modified":"2026-04-28T17:51:11.5952731+04:00"},{"id":36472,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"0dc933c238ae7ab73de36f0171dfb48b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 371-405","gmt_create":"2026-04-28T17:51:11.5952731+04:00","gmt_modified":"2026-04-28T17:51:11.5952731+04:00"},{"id":36476,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5a09c4b30cf4ad7363c8ddc12bc7c8db","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 290-405","gmt_create":"2026-04-28T17:51:11.5957891+04:00","gmt_modified":"2026-04-28T17:51:11.5957891+04:00"},{"id":36478,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"d8698088d1f1c1cd1343a5552104c443","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 295-405","gmt_create":"2026-04-28T17:51:11.5968267+04:00","gmt_modified":"2026-04-28T17:51:11.5968267+04:00"},{"id":36480,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"bccfbcb90cc33fcb1bad654d203eab3a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 308-340","gmt_create":"2026-04-28T17:51:11.5968267+04:00","gmt_modified":"2026-04-28T17:51:11.5968267+04:00"},{"id":36482,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"3e4f7ec74d72ee9c1f4f5cf2a0f86844","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 298-302","gmt_create":"2026-04-28T17:51:11.5973383+04:00","gmt_modified":"2026-04-28T17:51:11.5973383+04:00"},{"id":36484,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"e13810e67e91d0b4940124f48b98095c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 335-338","gmt_create":"2026-04-28T17:51:11.5973383+04:00","gmt_modified":"2026-04-28T17:51:11.5973383+04:00"},{"id":36487,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"30fcbbca25b602851122e4d2b5ae4754","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 701-765","gmt_create":"2026-04-28T17:51:11.5978575+04:00","gmt_modified":"2026-04-28T17:51:11.5978575+04:00"},{"id":36489,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"2d0ff08ccbd1994ff4f46985361fc3d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 355-364","gmt_create":"2026-04-28T17:51:11.600892+04:00","gmt_modified":"2026-04-28T17:51:11.600892+04:00"},{"id":36491,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"f195c24b5ab419ffbcc0c59a70fc3b0b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 520-528","gmt_create":"2026-04-28T17:51:11.600892+04:00","gmt_modified":"2026-04-28T17:51:11.600892+04:00"},{"id":36495,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"1638be790588edb6a3913a76064f24e0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 992-1061","gmt_create":"2026-04-28T17:51:11.6035214+04:00","gmt_modified":"2026-04-28T17:51:11.6035214+04:00"},{"id":36504,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"cfa97ba993c799f350895b1deb5bfa1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 596-699","gmt_create":"2026-04-28T17:51:11.6115462+04:00","gmt_modified":"2026-04-28T17:51:11.6115462+04:00"},{"id":36561,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"87dbe393410d68cf0b46ab22827e33fe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3252-3290","gmt_create":"2026-04-28T17:52:33.4726022+04:00","gmt_modified":"2026-04-28T17:52:33.4726022+04:00"},{"id":36563,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"98c57a9cc27d3a9e444c74d23a63bf9e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4945-4947","gmt_create":"2026-04-28T17:52:33.4726876+04:00","gmt_modified":"2026-04-28T17:52:33.4726876+04:00"},{"id":36565,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2d706a9e6bc734297fc6693a4cec7176","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5139-5140","gmt_create":"2026-04-28T17:52:33.4736196+04:00","gmt_modified":"2026-04-28T17:52:33.4736196+04:00"},{"id":36567,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"95d10140a46b090a8cea978c1c73a9bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 337-338","gmt_create":"2026-04-28T17:52:33.4742694+04:00","gmt_modified":"2026-04-28T17:52:33.4742694+04:00"},{"id":36611,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"95da2daaa0065c2230410221cb5b5dbd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-670","gmt_create":"2026-04-28T17:55:35.3910266+04:00","gmt_modified":"2026-04-28T17:55:35.3910266+04:00"},{"id":36613,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e381e37084462c877d129f82d20ff00a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6623","gmt_create":"2026-04-28T17:55:35.3915293+04:00","gmt_modified":"2026-04-28T17:55:35.3915293+04:00"},{"id":36619,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"86991432e69878d08cc76b9d386b7d8f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-80","gmt_create":"2026-04-28T17:55:35.3939384+04:00","gmt_modified":"2026-04-28T17:55:35.3939384+04:00"},{"id":36621,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"cdc31aad39121f507723919db7d70dee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-476","gmt_create":"2026-04-28T17:55:35.3944414+04:00","gmt_modified":"2026-04-28T17:55:35.3944414+04:00"},{"id":36749,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"7f7ad64f5cbf50ccfc4c9382214c8ec2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5113-5150","gmt_create":"2026-04-28T17:55:59.5724875+04:00","gmt_modified":"2026-04-28T17:55:59.5724875+04:00"},{"id":36751,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"ad3b81ed34c5384299f6f2e32cca10ed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5152-5207","gmt_create":"2026-04-28T17:55:59.5734892+04:00","gmt_modified":"2026-04-28T17:55:59.5734892+04:00"},{"id":36753,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"5f552c130950ae2424391d5588a6d221","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2616-2663","gmt_create":"2026-04-28T17:55:59.5734892+04:00","gmt_modified":"2026-04-28T17:55:59.5734892+04:00"},{"id":36755,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"283622d9bcc1bce9d94e8923c2f25f8d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2649-2663","gmt_create":"2026-04-28T17:55:59.5744885+04:00","gmt_modified":"2026-04-28T17:55:59.5744885+04:00"},{"id":36757,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"53f0c930ae76bfa54d695357483cfd14","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1574-1590","gmt_create":"2026-04-28T17:55:59.5744885+04:00","gmt_modified":"2026-04-28T17:55:59.5744885+04:00"},{"id":36759,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"3ee025d1596a00346251c53e81140245","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1600-1603","gmt_create":"2026-04-28T17:55:59.5754874+04:00","gmt_modified":"2026-04-28T17:55:59.5754874+04:00"},{"id":36761,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"cd28c0d27d7ee3f81690b82569787afd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1615-1618","gmt_create":"2026-04-28T17:55:59.5754874+04:00","gmt_modified":"2026-04-28T17:55:59.5754874+04:00"},{"id":36763,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"50e65d04bb14ac9f5de0d5e24fb1bc95","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5234-5312","gmt_create":"2026-04-28T17:55:59.5754874+04:00","gmt_modified":"2026-04-28T17:55:59.5754874+04:00"},{"id":36765,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"782b21b9fe9078ddf841f9c5edb30a5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5134-5150","gmt_create":"2026-04-28T17:55:59.5764874+04:00","gmt_modified":"2026-04-28T17:55:59.5764874+04:00"},{"id":36767,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"c440df88a010dbe878f2183c720c9bd4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5073-5111","gmt_create":"2026-04-28T17:55:59.5764874+04:00","gmt_modified":"2026-04-28T17:55:59.5764874+04:00"},{"id":36769,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"d40711c4a4526e9360e24999d3a60c4c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1561-1561","gmt_create":"2026-04-28T17:55:59.5774877+04:00","gmt_modified":"2026-04-28T17:55:59.5774877+04:00"},{"id":36771,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"ab3013cc4873cf8f4df651d34931505a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2890-2901","gmt_create":"2026-04-28T17:55:59.5774877+04:00","gmt_modified":"2026-04-28T17:55:59.5774877+04:00"},{"id":36773,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"a867692b466336c352cc15b0f4f2df75","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3034-3038","gmt_create":"2026-04-28T17:55:59.5774877+04:00","gmt_modified":"2026-04-28T17:55:59.5774877+04:00"},{"id":36775,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"dfd73892c200f1d97774665580c6e71f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2951-2956","gmt_create":"2026-04-28T17:55:59.5784874+04:00","gmt_modified":"2026-04-28T17:55:59.5784874+04:00"},{"id":36777,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"01940ab830f5b568738f999638e911f5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3052-3077","gmt_create":"2026-04-28T17:55:59.5784874+04:00","gmt_modified":"2026-04-28T17:55:59.5784874+04:00"},{"id":36779,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"3c85ac88e286b8cc43c883b8df381dc4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2903-2910","gmt_create":"2026-04-28T17:55:59.5784874+04:00","gmt_modified":"2026-04-28T17:55:59.5784874+04:00"},{"id":36781,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"6c44a74a07d60a21476756afc2a21751","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2906-2908","gmt_create":"2026-04-28T17:55:59.579991+04:00","gmt_modified":"2026-04-28T17:55:59.579991+04:00"},{"id":36783,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"f93b14aeceeb7a9cd9ffe6f5eb64aa31","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5119-5127","gmt_create":"2026-04-28T17:55:59.579991+04:00","gmt_modified":"2026-04-28T17:55:59.579991+04:00"},{"id":36785,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"3139928b0a5ec8f18b756ec5a2002d53","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5116-5118","gmt_create":"2026-04-28T17:55:59.5809967+04:00","gmt_modified":"2026-04-28T17:55:59.5809967+04:00"},{"id":36787,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"e3459f7af1223806827d89c0dc203eea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5135-5139","gmt_create":"2026-04-28T17:55:59.5819951+04:00","gmt_modified":"2026-04-28T17:55:59.5819951+04:00"},{"id":36789,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"41f0eb3c878b82cdb92e49b6aaeb78a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2517-2522","gmt_create":"2026-04-28T17:55:59.5911087+04:00","gmt_modified":"2026-04-28T17:55:59.5911087+04:00"},{"id":36822,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"31f6fa48f80c0c6d8c5b09074b2f3f45","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4910-5150","gmt_create":"2026-04-28T17:57:38.4551102+04:00","gmt_modified":"2026-04-28T17:57:38.4551102+04:00"},{"id":36833,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"850a6c0029d8ecca44d93e902433bd6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 453-473","gmt_create":"2026-04-28T17:57:38.4571105+04:00","gmt_modified":"2026-04-28T17:57:38.4571105+04:00"},{"id":36838,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"7f9a564b8011c536e8ff555516dffbae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3254","gmt_create":"2026-04-28T17:57:38.4591249+04:00","gmt_modified":"2026-04-28T17:57:38.4591249+04:00"},{"id":36876,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"17512b930411cc392fa7b28fa3ad2b84","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 332-338","gmt_create":"2026-04-28T17:57:38.4691427+04:00","gmt_modified":"2026-04-28T17:57:38.4691427+04:00"},{"id":36906,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"930f47bc2c95f0cac4086eeca5749e2c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 190-304","gmt_create":"2026-04-28T18:50:34.4094415+04:00","gmt_modified":"2026-04-28T18:50:34.4094415+04:00"},{"id":36908,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"9f8690911ef66c966743475f294ffb7e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-351","gmt_create":"2026-04-28T18:50:34.4094415+04:00","gmt_modified":"2026-04-28T18:50:34.4094415+04:00"},{"id":36910,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"a480bfeb1604076e7d1db7746687a3b4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-106","gmt_create":"2026-04-28T18:50:34.4105267+04:00","gmt_modified":"2026-04-28T18:50:34.4105267+04:00"},{"id":36912,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"c54e54629fd9cd255341b311da9b6be1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-573","gmt_create":"2026-04-28T18:50:34.4105267+04:00","gmt_modified":"2026-04-28T18:50:34.4105267+04:00"},{"id":36914,"source_id":"398d9d4b02b6383c0b752cb0196a0475","target_id":"4e8bc2cdd3d4fc68b2f7138c54288174","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 37-93","gmt_create":"2026-04-28T18:50:34.4126371+04:00","gmt_modified":"2026-04-28T18:50:34.4126371+04:00"},{"id":36917,"source_id":"6e587b97bf4080c7754c5ed73736fca7","target_id":"ff11a77da594972e0b8a78df4289ada5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 45-79","gmt_create":"2026-04-28T18:50:34.4135396+04:00","gmt_modified":"2026-04-28T18:50:34.4135396+04:00"},{"id":36919,"source_id":"c82262dc5275e094efc9474032d15922","target_id":"d614fc51360bb61b8f521167a6db1e11","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-106","gmt_create":"2026-04-28T18:50:34.414043+04:00","gmt_modified":"2026-04-28T18:50:34.414043+04:00"},{"id":36921,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"411a87e4e085e019827e9bd8085b8328","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 500-560","gmt_create":"2026-04-28T18:50:34.414043+04:00","gmt_modified":"2026-04-28T18:50:34.414043+04:00"},{"id":36923,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"6a050f797e4d75bb2867072fae629c2a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5281-5286","gmt_create":"2026-04-28T18:50:34.4151271+04:00","gmt_modified":"2026-04-28T18:50:34.4151271+04:00"},{"id":36925,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"448218400a050ac2d3a0f1ee290faf50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 346-347","gmt_create":"2026-04-28T18:50:34.4151271+04:00","gmt_modified":"2026-04-28T18:50:34.4151271+04:00"},{"id":36927,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"34550b8d6e01a13e99a0ed70072db86b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-355","gmt_create":"2026-04-28T18:50:34.4162025+04:00","gmt_modified":"2026-04-28T18:50:34.4162025+04:00"},{"id":36929,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"9847129d410beb4256be18f2e7489d18","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-383","gmt_create":"2026-04-28T18:50:34.4162025+04:00","gmt_modified":"2026-04-28T18:50:34.4162025+04:00"},{"id":36931,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"a3e6f8b4e51c838c44eaef16bb205031","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-573","gmt_create":"2026-04-28T18:50:34.4162025+04:00","gmt_modified":"2026-04-28T18:50:34.4162025+04:00"},{"id":36933,"source_id":"398d9d4b02b6383c0b752cb0196a0475","target_id":"53a676bf1df5198ba31b6ebe848a29bd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-99","gmt_create":"2026-04-28T18:50:34.4172058+04:00","gmt_modified":"2026-04-28T18:50:34.4172058+04:00"},{"id":36935,"source_id":"3a8d8a10556a0b6501e25aa43e91f913","target_id":"f14b0ce0c1ba142fb55271fdc6c2ee9f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-141","gmt_create":"2026-04-28T18:50:34.4172058+04:00","gmt_modified":"2026-04-28T18:50:34.4172058+04:00"},{"id":36937,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"f59f370133646ba0c40ebdd11ee6d697","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-114","gmt_create":"2026-04-28T18:50:34.4172058+04:00","gmt_modified":"2026-04-28T18:50:34.4172058+04:00"},{"id":36939,"source_id":"6e587b97bf4080c7754c5ed73736fca7","target_id":"762c4b81ed454ad789c0b3b3cb00cc88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-85","gmt_create":"2026-04-28T18:50:34.4182946+04:00","gmt_modified":"2026-04-28T18:50:34.4182946+04:00"},{"id":36941,"source_id":"c82262dc5275e094efc9474032d15922","target_id":"bc9b507990af077f95d7bbe7203d51f0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-106","gmt_create":"2026-04-28T18:50:34.4182946+04:00","gmt_modified":"2026-04-28T18:50:34.4182946+04:00"},{"id":36943,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"b54da9d3dceb59e39a6cd88a5a99b593","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-742","gmt_create":"2026-04-28T18:50:34.4193737+04:00","gmt_modified":"2026-04-28T18:50:34.4193737+04:00"},{"id":36945,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"54ba2e42561f4bf9913449b2a78838bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 182-304","gmt_create":"2026-04-28T18:50:34.4193737+04:00","gmt_modified":"2026-04-28T18:50:34.4193737+04:00"},{"id":36947,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"94c69e0f6c696d5856c9a52b4dbcda00","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 780-790","gmt_create":"2026-04-28T18:50:34.4220565+04:00","gmt_modified":"2026-04-28T18:50:34.4220565+04:00"},{"id":36949,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"d6f1f5c1ab7e33b9a558f648113330fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 208-242","gmt_create":"2026-04-28T18:50:34.4221458+04:00","gmt_modified":"2026-04-28T18:50:34.4221458+04:00"},{"id":36951,"source_id":"01e57c63d684a56829f909c03b8ea162","target_id":"db2f58e50720e139a95c598355919158","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-72","gmt_create":"2026-04-28T18:50:34.4221458+04:00","gmt_modified":"2026-04-28T18:50:34.4221458+04:00"},{"id":36953,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"a6b2b3362f68c7523a4e0d06a2a4352f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 424-799","gmt_create":"2026-04-28T18:50:34.4448355+04:00","gmt_modified":"2026-04-28T18:50:34.4448355+04:00"},{"id":36956,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"20359a9271432a216b6faf9dc97fa5c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 169-206","gmt_create":"2026-04-28T18:50:34.4458606+04:00","gmt_modified":"2026-04-28T18:50:34.4458606+04:00"},{"id":36958,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"fee43b750e5fa7d56e56ac6251e6b5bb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 41-66","gmt_create":"2026-04-28T18:50:34.4458606+04:00","gmt_modified":"2026-04-28T18:50:34.4458606+04:00"},{"id":36960,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"25c0bdec5e0fb6c8d410577e1478ea78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 310-354","gmt_create":"2026-04-28T18:50:34.4463761+04:00","gmt_modified":"2026-04-28T18:50:34.4463761+04:00"},{"id":36962,"source_id":"2c99501f0c511d0792a2e5a56e4debfa","target_id":"e81b900c80dc9c266a93a66cc60486de","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-49","gmt_create":"2026-04-28T18:50:34.4463761+04:00","gmt_modified":"2026-04-28T18:50:34.4463761+04:00"},{"id":36964,"source_id":"01e57c63d684a56829f909c03b8ea162","target_id":"0b26d723a87937f5a3f58770c522d067","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-72","gmt_create":"2026-04-28T18:50:34.4472155+04:00","gmt_modified":"2026-04-28T18:50:34.4472155+04:00"},{"id":36966,"source_id":"01e57c63d684a56829f909c03b8ea162","target_id":"d4b4e356cc64c1eac490f25138ad8337","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 132-177","gmt_create":"2026-04-28T18:50:34.4472155+04:00","gmt_modified":"2026-04-28T18:50:34.4472155+04:00"},{"id":36968,"source_id":"01e57c63d684a56829f909c03b8ea162","target_id":"b43af1b0b5dbbe32011b0ab877770800","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-177","gmt_create":"2026-04-28T18:50:34.4477185+04:00","gmt_modified":"2026-04-28T18:50:34.4477185+04:00"},{"id":36970,"source_id":"c70caf63ce77b078dcf89380b228a71a","target_id":"fd44e8ec8ed78651240bac55efcc1f20","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 41-82","gmt_create":"2026-04-28T18:50:34.4477185+04:00","gmt_modified":"2026-04-28T18:50:34.4477185+04:00"},{"id":36972,"source_id":"c70caf63ce77b078dcf89380b228a71a","target_id":"ee53a7a714337d597cc0a626fceec27f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 100-174","gmt_create":"2026-04-28T18:50:34.4487235+04:00","gmt_modified":"2026-04-28T18:50:34.4487235+04:00"},{"id":36974,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"aae2609ed41db2a866f07ce766cbb938","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 70-105","gmt_create":"2026-04-28T18:50:34.4487235+04:00","gmt_modified":"2026-04-28T18:50:34.4487235+04:00"},{"id":36976,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"023d67279bae7acc551e276826dc0ff1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3710-3723","gmt_create":"2026-04-28T18:50:34.4497233+04:00","gmt_modified":"2026-04-28T18:50:34.4497233+04:00"},{"id":36978,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b7e9099b5e14dfe6396c0a1c5c308eb7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 312-381","gmt_create":"2026-04-28T18:50:34.4497233+04:00","gmt_modified":"2026-04-28T18:50:34.4497233+04:00"},{"id":36980,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"26b49296ed2024fd0dde20e6f7e40b88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 383-420","gmt_create":"2026-04-28T18:50:34.4507268+04:00","gmt_modified":"2026-04-28T18:50:34.4507268+04:00"},{"id":36982,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"41d27526c610abf125f7a7d008632585","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 173-179","gmt_create":"2026-04-28T18:50:34.4507268+04:00","gmt_modified":"2026-04-28T18:50:34.4507268+04:00"},{"id":36984,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"868fa39acf5aeee17dc7a8161740807d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4920-4970","gmt_create":"2026-04-28T18:50:34.4517267+04:00","gmt_modified":"2026-04-28T18:50:34.4517267+04:00"},{"id":36986,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"9814b4d33f73344843377eb1e1b063d8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5128-5131","gmt_create":"2026-04-28T18:50:34.4524989+04:00","gmt_modified":"2026-04-28T18:50:34.4524989+04:00"},{"id":36988,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"380d27e76ccd3471d37efe9e980c19ae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 322-346","gmt_create":"2026-04-28T18:50:34.4530856+04:00","gmt_modified":"2026-04-28T18:50:34.4530856+04:00"},{"id":36990,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"569091d2a8631dcfd98eaa50ae2bfc44","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 428-448","gmt_create":"2026-04-28T18:50:34.4536651+04:00","gmt_modified":"2026-04-28T18:50:34.4536651+04:00"},{"id":36992,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"1ed9d91d6dd0223209ee65abf9542242","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4900-4970","gmt_create":"2026-04-28T18:50:34.4543112+04:00","gmt_modified":"2026-04-28T18:50:34.4543112+04:00"},{"id":36994,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b8d925dd432a091aeeb11648caa2eb44","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4164-4168","gmt_create":"2026-04-28T18:50:34.4560148+04:00","gmt_modified":"2026-04-28T18:50:34.4560148+04:00"},{"id":36996,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"bf71a71910c5567123121789e437c062","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 298-304","gmt_create":"2026-04-28T18:50:34.4565303+04:00","gmt_modified":"2026-04-28T18:50:34.4565303+04:00"},{"id":36998,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"690241d99c53c94e7cfd1435215c90f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 616-618","gmt_create":"2026-04-28T18:50:34.4565303+04:00","gmt_modified":"2026-04-28T18:50:34.4565303+04:00"},{"id":37000,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"8df3a4b9e7bead2487cc1ffc6cd49cae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-19","gmt_create":"2026-04-28T18:50:34.4575335+04:00","gmt_modified":"2026-04-28T18:50:34.4575335+04:00"},{"id":37002,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"84d9f61aa92a7de46576a47f269a5dcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 169-171","gmt_create":"2026-04-28T18:50:34.4575335+04:00","gmt_modified":"2026-04-28T18:50:34.4575335+04:00"},{"id":37004,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"0be17f1ab260a4b3bcead7596649bfc6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 81-81","gmt_create":"2026-04-28T18:50:34.4575335+04:00","gmt_modified":"2026-04-28T18:50:34.4575335+04:00"},{"id":37006,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"271449375aea639d1f03a23e291eaea3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1187-1194","gmt_create":"2026-04-28T18:50:34.4585336+04:00","gmt_modified":"2026-04-28T18:50:34.4585336+04:00"},{"id":37008,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"14c432cf8aa5e9ce797534c3d40b187f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1200-1202","gmt_create":"2026-04-28T18:50:34.4585336+04:00","gmt_modified":"2026-04-28T18:50:34.4585336+04:00"},{"id":37010,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"c63bedc7eec5da82c3e0783176a7a564","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2651-2663","gmt_create":"2026-04-28T18:50:34.4585336+04:00","gmt_modified":"2026-04-28T18:50:34.4585336+04:00"},{"id":37012,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"95b247631c8b269b2a98c7e385bac407","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2772-2779","gmt_create":"2026-04-28T18:50:34.4595337+04:00","gmt_modified":"2026-04-28T18:50:34.4595337+04:00"},{"id":37014,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"e5fedb1d60d7f5a29bddbc403ff3d857","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2790-2796","gmt_create":"2026-04-28T18:50:34.4595337+04:00","gmt_modified":"2026-04-28T18:50:34.4595337+04:00"},{"id":37016,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"b30577f67d2d7eafe760daf3f3f386b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-28","gmt_create":"2026-04-28T18:50:34.4605335+04:00","gmt_modified":"2026-04-28T18:50:34.4605335+04:00"},{"id":37018,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"8d12769b91a5f0a7c02fe172ecffd5ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-29","gmt_create":"2026-04-28T18:50:34.4610774+04:00","gmt_modified":"2026-04-28T18:50:34.4610774+04:00"},{"id":37020,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"b4c2646d470a9f4262288b71e7b10e89","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-28","gmt_create":"2026-04-28T18:50:34.4616314+04:00","gmt_modified":"2026-04-28T18:50:34.4616314+04:00"},{"id":37022,"source_id":"398d9d4b02b6383c0b752cb0196a0475","target_id":"055bd4ac99dff0f7dad3d2d929f83b6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-28","gmt_create":"2026-04-28T18:50:34.4622131+04:00","gmt_modified":"2026-04-28T18:50:34.4622131+04:00"},{"id":37024,"source_id":"6e587b97bf4080c7754c5ed73736fca7","target_id":"eb6ddb4ecbe9eb87c395f2865107ea0e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-27","gmt_create":"2026-04-28T18:50:34.4627918+04:00","gmt_modified":"2026-04-28T18:50:34.4627918+04:00"},{"id":37026,"source_id":"3a8d8a10556a0b6501e25aa43e91f913","target_id":"660390a5b68b3f21fd886800f24fcc78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-45","gmt_create":"2026-04-28T18:50:34.4644202+04:00","gmt_modified":"2026-04-28T18:50:34.4644202+04:00"},{"id":37028,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"688ff5b9bf8ff49c734540b2a73a1251","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 288-298","gmt_create":"2026-04-28T18:50:34.4649279+04:00","gmt_modified":"2026-04-28T18:50:34.4649279+04:00"},{"id":37030,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"34e2f989664fd5eff332f3ac19b8b16e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 85-105","gmt_create":"2026-04-28T18:50:34.4655215+04:00","gmt_modified":"2026-04-28T18:50:34.4655215+04:00"},{"id":37099,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"16865a1a8de25574f1f934ab4b21167f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1595-1624","gmt_create":"2026-04-28T18:53:18.2656376+04:00","gmt_modified":"2026-04-28T18:53:18.2656376+04:00"},{"id":37195,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"9a668be3a6e1e9f3afa6fcd90677d0b3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5482-5499","gmt_create":"2026-04-28T18:54:23.698664+04:00","gmt_modified":"2026-04-28T18:54:23.698664+04:00"},{"id":37345,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"e2711f14cc959993e82e19c033761fff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 16-21","gmt_create":"2026-04-28T19:27:53.6199688+04:00","gmt_modified":"2026-04-28T19:27:53.6199688+04:00"},{"id":37348,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"c66e1ad4dc89d485e77e61d3776d5e80","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 299-301","gmt_create":"2026-04-28T19:27:53.620969+04:00","gmt_modified":"2026-04-28T19:27:53.620969+04:00"},{"id":37350,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"d6af3938508b615a82ba5a3820d850c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 522-528","gmt_create":"2026-04-28T19:27:53.620969+04:00","gmt_modified":"2026-04-28T19:27:53.620969+04:00"},{"id":37352,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"10e2e9b3ec934c86877d6a4b57e21d34","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 321-327","gmt_create":"2026-04-28T19:27:53.6219687+04:00","gmt_modified":"2026-04-28T19:27:53.6219687+04:00"},{"id":37354,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5cdb837c5a6e5f183ed9a818f50b2abf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 336-338","gmt_create":"2026-04-28T19:27:53.6219687+04:00","gmt_modified":"2026-04-28T19:27:53.6219687+04:00"},{"id":37356,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"4a61426778eec404639d3aa8059fbe1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 357-364","gmt_create":"2026-04-28T19:27:53.6219687+04:00","gmt_modified":"2026-04-28T19:27:53.6219687+04:00"},{"id":37461,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"3f9fffa35f3712fd1f90ebc3c0593373","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: documentation/debug_node_plugin.md","gmt_create":"2026-04-28T19:48:38.8756263+04:00","gmt_modified":"2026-04-28T19:48:38.8756263+04:00"},{"id":37462,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"85e109c379780f5df7bb2695b2862fba","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","gmt_create":"2026-04-28T19:48:38.8766264+04:00","gmt_modified":"2026-04-28T19:48:38.8766264+04:00"},{"id":37463,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"796d893189111ab0df5e606d82fea700","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/debug_node/plugin.cpp","gmt_create":"2026-04-28T19:48:38.8766264+04:00","gmt_modified":"2026-04-28T19:48:38.8766264+04:00"},{"id":37464,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"fb3a9999324017fb4d2fad7f61f2660e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp","gmt_create":"2026-04-28T19:48:38.8766264+04:00","gmt_modified":"2026-04-28T19:48:38.8766264+04:00"},{"id":37465,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"2b777822e4399aff7d4e5ea26fcbe8b9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config_debug.ini","gmt_create":"2026-04-28T19:48:38.8766264+04:00","gmt_modified":"2026-04-28T19:48:38.8766264+04:00"},{"id":37466,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"89eb7bdd3591c729dfa6f00de5cdfa1c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: programs/util/sign_transaction.cpp","gmt_create":"2026-04-28T19:48:38.8766264+04:00","gmt_modified":"2026-04-28T19:48:38.8766264+04:00"},{"id":37467,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"2819790574404236d7b1bca0b253c524","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: programs/util/sign_digest.cpp","gmt_create":"2026-04-28T19:48:38.8777272+04:00","gmt_modified":"2026-04-28T19:48:38.8777272+04:00"},{"id":37468,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-28T19:48:38.8777272+04:00","gmt_modified":"2026-04-28T19:48:38.8777272+04:00"},{"id":37469,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-28T19:48:38.8777272+04:00","gmt_modified":"2026-04-28T19:48:38.8777272+04:00"},{"id":37470,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"d72b348a2c3c7943e4a7abb7dbdaa751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_connection.hpp","gmt_create":"2026-04-28T19:48:38.8782298+04:00","gmt_modified":"2026-04-28T19:48:38.8782298+04:00"},{"id":37471,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-28T19:48:38.8783137+04:00","gmt_modified":"2026-04-28T19:48:38.8783137+04:00"},{"id":37472,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"f9ff6c6bb4dec49a31a1b770a5d8e89f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#38-108","gmt_create":"2026-04-28T19:48:38.8783137+04:00","gmt_modified":"2026-04-28T19:48:38.8783137+04:00"},{"id":37473,"source_id":"85e109c379780f5df7bb2695b2862fba","target_id":"f9ff6c6bb4dec49a31a1b770a5d8e89f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-108","gmt_create":"2026-04-28T19:48:38.8789249+04:00","gmt_modified":"2026-04-28T19:48:38.8789249+04:00"},{"id":37474,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"c914b1a14377d172e66d3320eee0a043","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#25-94","gmt_create":"2026-04-28T19:48:38.8789249+04:00","gmt_modified":"2026-04-28T19:48:38.8789249+04:00"},{"id":37475,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"c914b1a14377d172e66d3320eee0a043","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-94","gmt_create":"2026-04-28T19:48:38.8789249+04:00","gmt_modified":"2026-04-28T19:48:38.8789249+04:00"},{"id":37476,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"f3cc232f0f51afc8747a00f6b9906c3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp#1-108","gmt_create":"2026-04-28T19:48:38.8795322+04:00","gmt_modified":"2026-04-28T19:48:38.8795322+04:00"},{"id":37477,"source_id":"fb3a9999324017fb4d2fad7f61f2660e","target_id":"f3cc232f0f51afc8747a00f6b9906c3d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-108","gmt_create":"2026-04-28T19:48:38.8795322+04:00","gmt_modified":"2026-04-28T19:48:38.8795322+04:00"},{"id":37478,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"b9491b3f2a4f089e194b8c382d40e3ed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_transaction.cpp#12-26","gmt_create":"2026-04-28T19:48:38.8800347+04:00","gmt_modified":"2026-04-28T19:48:38.8800347+04:00"},{"id":37479,"source_id":"89eb7bdd3591c729dfa6f00de5cdfa1c","target_id":"b9491b3f2a4f089e194b8c382d40e3ed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-26","gmt_create":"2026-04-28T19:48:38.8801072+04:00","gmt_modified":"2026-04-28T19:48:38.8801072+04:00"},{"id":37480,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"80d96f5a237fbc996d591a3a6738455e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_digest.cpp#12-24","gmt_create":"2026-04-28T19:48:38.8801072+04:00","gmt_modified":"2026-04-28T19:48:38.8801072+04:00"},{"id":37481,"source_id":"2819790574404236d7b1bca0b253c524","target_id":"80d96f5a237fbc996d591a3a6738455e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-24","gmt_create":"2026-04-28T19:48:38.8801072+04:00","gmt_modified":"2026-04-28T19:48:38.8801072+04:00"},{"id":37482,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"3aa63104c48be9af56ac2394a0ff0465","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#1-200","gmt_create":"2026-04-28T19:48:38.8806797+04:00","gmt_modified":"2026-04-28T19:48:38.8806797+04:00"},{"id":37483,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"3aa63104c48be9af56ac2394a0ff0465","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T19:48:38.8806797+04:00","gmt_modified":"2026-04-28T19:48:38.8806797+04:00"},{"id":37484,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"035cfc0826dd0b5915c1d3c58d1ef13d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#190-200","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37485,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"035cfc0826dd0b5915c1d3c58d1ef13d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 190-200","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37486,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"775f3dad042fb99fc87d2a984fb10026","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#79-200","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37487,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"775f3dad042fb99fc87d2a984fb10026","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-200","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37488,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"ab666734d7a7b8fd90bcfb1f1a312813","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_debug.ini#1-126","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37489,"source_id":"2b777822e4399aff7d4e5ea26fcbe8b9","target_id":"ab666734d7a7b8fd90bcfb1f1a312813","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-126","gmt_create":"2026-04-28T19:48:38.8811822+04:00","gmt_modified":"2026-04-28T19:48:38.8811822+04:00"},{"id":37490,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"6fca2c5700dd39ca35022a36a9d989cf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#1-111","gmt_create":"2026-04-28T19:48:38.8824615+04:00","gmt_modified":"2026-04-28T19:48:38.8824615+04:00"},{"id":37491,"source_id":"85e109c379780f5df7bb2695b2862fba","target_id":"6fca2c5700dd39ca35022a36a9d989cf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-111","gmt_create":"2026-04-28T19:48:38.8824615+04:00","gmt_modified":"2026-04-28T19:48:38.8824615+04:00"},{"id":37492,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"12ee4287ffb75b424c50950e8f5b2df5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#1-668","gmt_create":"2026-04-28T19:48:38.8824615+04:00","gmt_modified":"2026-04-28T19:48:38.8824615+04:00"},{"id":37493,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"12ee4287ffb75b424c50950e8f5b2df5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-668","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37494,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"1bbdcbd551f6b6db613208a506ed663b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_transaction.cpp#1-54","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37495,"source_id":"89eb7bdd3591c729dfa6f00de5cdfa1c","target_id":"1bbdcbd551f6b6db613208a506ed663b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-54","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37496,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"fca351b915d815422a74e940fcde8cdb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_digest.cpp#1-49","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37497,"source_id":"2819790574404236d7b1bca0b253c524","target_id":"fca351b915d815422a74e940fcde8cdb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-49","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37498,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"07bbb44ee7833965e9eb8064c7dca3a5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#1-200","gmt_create":"2026-04-28T19:48:38.8829645+04:00","gmt_modified":"2026-04-28T19:48:38.8829645+04:00"},{"id":37499,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"07bbb44ee7833965e9eb8064c7dca3a5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T19:48:38.8844722+04:00","gmt_modified":"2026-04-28T19:48:38.8844722+04:00"},{"id":37500,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"5dbe534429ba35b6a93bafccda79ab2b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#1-200","gmt_create":"2026-04-28T19:48:38.8844722+04:00","gmt_modified":"2026-04-28T19:48:38.8844722+04:00"},{"id":37501,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"5dbe534429ba35b6a93bafccda79ab2b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T19:48:38.8844722+04:00","gmt_modified":"2026-04-28T19:48:38.8844722+04:00"},{"id":37502,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"e4d3b0996d354976a0f8d7be27bba43f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#222-288","gmt_create":"2026-04-28T19:48:38.8844722+04:00","gmt_modified":"2026-04-28T19:48:38.8844722+04:00"},{"id":37503,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"e4d3b0996d354976a0f8d7be27bba43f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 222-288","gmt_create":"2026-04-28T19:48:38.8854751+04:00","gmt_modified":"2026-04-28T19:48:38.8854751+04:00"},{"id":37504,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"073296e0c0907087372d72bd8ed5a30d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#321-420","gmt_create":"2026-04-28T19:48:38.887196+04:00","gmt_modified":"2026-04-28T19:48:38.887196+04:00"},{"id":37505,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"073296e0c0907087372d72bd8ed5a30d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 321-420","gmt_create":"2026-04-28T19:48:38.887196+04:00","gmt_modified":"2026-04-28T19:48:38.887196+04:00"},{"id":37506,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"8a25fc8080abd566cbef2d584b42c23b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#489-555","gmt_create":"2026-04-28T19:48:38.887196+04:00","gmt_modified":"2026-04-28T19:48:38.887196+04:00"},{"id":37507,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"8a25fc8080abd566cbef2d584b42c23b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 489-555","gmt_create":"2026-04-28T19:48:38.887196+04:00","gmt_modified":"2026-04-28T19:48:38.887196+04:00"},{"id":37508,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"06bbb8421071aa4e70ada689b0e8d0de","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#118-170","gmt_create":"2026-04-28T19:48:38.8877895+04:00","gmt_modified":"2026-04-28T19:48:38.8877895+04:00"},{"id":37509,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"06bbb8421071aa4e70ada689b0e8d0de","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 118-170","gmt_create":"2026-04-28T19:48:38.8877895+04:00","gmt_modified":"2026-04-28T19:48:38.8877895+04:00"},{"id":37510,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"e2711f14cc959993e82e19c033761fff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#16-21","gmt_create":"2026-04-28T19:48:38.8877895+04:00","gmt_modified":"2026-04-28T19:48:38.8877895+04:00"},{"id":37511,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"be7f7c455b691c95a3dd6a2789b92a2a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#489-511","gmt_create":"2026-04-28T19:48:38.8883968+04:00","gmt_modified":"2026-04-28T19:48:38.8883968+04:00"},{"id":37512,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"be7f7c455b691c95a3dd6a2789b92a2a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 489-511","gmt_create":"2026-04-28T19:48:38.8883968+04:00","gmt_modified":"2026-04-28T19:48:38.8883968+04:00"},{"id":37513,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"3e4f072495a91bf2b13739f1f9d95a9c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#321-372","gmt_create":"2026-04-28T19:48:38.8888994+04:00","gmt_modified":"2026-04-28T19:48:38.8888994+04:00"},{"id":37514,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"3e4f072495a91bf2b13739f1f9d95a9c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 321-372","gmt_create":"2026-04-28T19:48:38.8889786+04:00","gmt_modified":"2026-04-28T19:48:38.8889786+04:00"},{"id":37515,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"a31a8b940a678fa2f3d45d33ed52e2a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#222-555","gmt_create":"2026-04-28T19:48:38.8895524+04:00","gmt_modified":"2026-04-28T19:48:38.8895524+04:00"},{"id":37516,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"a31a8b940a678fa2f3d45d33ed52e2a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 222-555","gmt_create":"2026-04-28T19:48:38.8895524+04:00","gmt_modified":"2026-04-28T19:48:38.8895524+04:00"},{"id":37517,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"b7b962f2d1cc506c60851cf76e545c68","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#441-454","gmt_create":"2026-04-28T19:48:38.8901466+04:00","gmt_modified":"2026-04-28T19:48:38.8901466+04:00"},{"id":37518,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"b7b962f2d1cc506c60851cf76e545c68","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 441-454","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37519,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"5ad89d11099370a27a89a9f7d0346730","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#422-430","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37520,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"5ad89d11099370a27a89a9f7d0346730","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 422-430","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37521,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"20bc4d17331e9bb80414df521e933386","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#117-136","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37522,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"20bc4d17331e9bb80414df521e933386","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 117-136","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37523,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"1a03b72ef4884dc486a6cf695bdec9e1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_transaction.cpp#28-53","gmt_create":"2026-04-28T19:48:38.8906491+04:00","gmt_modified":"2026-04-28T19:48:38.8906491+04:00"},{"id":37524,"source_id":"89eb7bdd3591c729dfa6f00de5cdfa1c","target_id":"1a03b72ef4884dc486a6cf695bdec9e1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-53","gmt_create":"2026-04-28T19:48:38.8916518+04:00","gmt_modified":"2026-04-28T19:48:38.8916518+04:00"},{"id":37525,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"ececdaf0999d8a83addb93f95d0039d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/util/sign_digest.cpp#26-48","gmt_create":"2026-04-28T19:48:38.8916518+04:00","gmt_modified":"2026-04-28T19:48:38.8916518+04:00"},{"id":37526,"source_id":"2819790574404236d7b1bca0b253c524","target_id":"ececdaf0999d8a83addb93f95d0039d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-48","gmt_create":"2026-04-28T19:48:38.8916518+04:00","gmt_modified":"2026-04-28T19:48:38.8916518+04:00"},{"id":37527,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"8e15df455552a1b9105a9a8b25797f1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#169-172","gmt_create":"2026-04-28T19:48:38.892652+04:00","gmt_modified":"2026-04-28T19:48:38.892652+04:00"},{"id":37528,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"8e15df455552a1b9105a9a8b25797f1e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 169-172","gmt_create":"2026-04-28T19:48:38.892652+04:00","gmt_modified":"2026-04-28T19:48:38.892652+04:00"},{"id":37529,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"9be51c5b9724dc743dc15a2758b6e4b2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#605-652","gmt_create":"2026-04-28T19:48:38.892652+04:00","gmt_modified":"2026-04-28T19:48:38.892652+04:00"},{"id":37530,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"9be51c5b9724dc743dc15a2758b6e4b2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 605-652","gmt_create":"2026-04-28T19:48:38.892652+04:00","gmt_modified":"2026-04-28T19:48:38.892652+04:00"},{"id":37531,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"7232f04ac5a3f960659a84db72e3c8c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#79-83","gmt_create":"2026-04-28T19:48:38.8936519+04:00","gmt_modified":"2026-04-28T19:48:38.8936519+04:00"},{"id":37532,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"7232f04ac5a3f960659a84db72e3c8c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-83","gmt_create":"2026-04-28T19:48:38.8936519+04:00","gmt_modified":"2026-04-28T19:48:38.8936519+04:00"},{"id":37533,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"86b86c367842460e75e043fb87b0f88f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5091-5108","gmt_create":"2026-04-28T19:48:38.8936519+04:00","gmt_modified":"2026-04-28T19:48:38.8936519+04:00"},{"id":37534,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"86b86c367842460e75e043fb87b0f88f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5091-5108","gmt_create":"2026-04-28T19:48:38.8936519+04:00","gmt_modified":"2026-04-28T19:48:38.8936519+04:00"},{"id":37535,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"d46277833fc133df8624346cd33cb6f3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#298-365","gmt_create":"2026-04-28T19:48:38.894752+04:00","gmt_modified":"2026-04-28T19:48:38.894752+04:00"},{"id":37536,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"d46277833fc133df8624346cd33cb6f3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 298-365","gmt_create":"2026-04-28T19:48:38.894752+04:00","gmt_modified":"2026-04-28T19:48:38.894752+04:00"},{"id":37537,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"9178051ee4765210ad69eba44f39c87a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#521-530","gmt_create":"2026-04-28T19:48:38.8952547+04:00","gmt_modified":"2026-04-28T19:48:38.8952547+04:00"},{"id":37538,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"9178051ee4765210ad69eba44f39c87a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 521-530","gmt_create":"2026-04-28T19:48:38.8953242+04:00","gmt_modified":"2026-04-28T19:48:38.8953242+04:00"},{"id":37539,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"cd9f1eabe9bd89866fea8372b8de3fb2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#605-686","gmt_create":"2026-04-28T19:48:38.8953242+04:00","gmt_modified":"2026-04-28T19:48:38.8953242+04:00"},{"id":37540,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"cd9f1eabe9bd89866fea8372b8de3fb2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 605-686","gmt_create":"2026-04-28T19:48:38.9043108+04:00","gmt_modified":"2026-04-28T19:48:38.9043108+04:00"},{"id":37541,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"b988e082f7d48dc4995d1e872598437c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#40-41","gmt_create":"2026-04-28T19:48:38.905334+04:00","gmt_modified":"2026-04-28T19:48:38.905334+04:00"},{"id":37542,"source_id":"85e109c379780f5df7bb2695b2862fba","target_id":"b988e082f7d48dc4995d1e872598437c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-41","gmt_create":"2026-04-28T19:48:38.905334+04:00","gmt_modified":"2026-04-28T19:48:38.905334+04:00"},{"id":37543,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"870cbffea14b19ef183293221413ec5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_debug.ini#36-47","gmt_create":"2026-04-28T19:48:38.9063824+04:00","gmt_modified":"2026-04-28T19:48:38.9063824+04:00"},{"id":37544,"source_id":"2b777822e4399aff7d4e5ea26fcbe8b9","target_id":"870cbffea14b19ef183293221413ec5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-47","gmt_create":"2026-04-28T19:48:38.9063824+04:00","gmt_modified":"2026-04-28T19:48:38.9063824+04:00"},{"id":37545,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"1448971e80d721aa1c85a46aea3da577","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_debug.ini#49-67","gmt_create":"2026-04-28T19:48:38.9069109+04:00","gmt_modified":"2026-04-28T19:48:38.9069109+04:00"},{"id":37546,"source_id":"2b777822e4399aff7d4e5ea26fcbe8b9","target_id":"1448971e80d721aa1c85a46aea3da577","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 49-67","gmt_create":"2026-04-28T19:48:38.9069109+04:00","gmt_modified":"2026-04-28T19:48:38.9069109+04:00"},{"id":37547,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"d64fee9bc095b55a1d7636f437075323","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#244-248","gmt_create":"2026-04-28T19:48:38.9085032+04:00","gmt_modified":"2026-04-28T19:48:38.9085032+04:00"},{"id":37548,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"d64fee9bc095b55a1d7636f437075323","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 244-248","gmt_create":"2026-04-28T19:48:38.9085032+04:00","gmt_modified":"2026-04-28T19:48:38.9085032+04:00"},{"id":37549,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"076badf84cd673f3b9244504dca95861","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#363-366","gmt_create":"2026-04-28T19:48:38.9085032+04:00","gmt_modified":"2026-04-28T19:48:38.9085032+04:00"},{"id":37550,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"076badf84cd673f3b9244504dca95861","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 363-366","gmt_create":"2026-04-28T19:48:38.9085032+04:00","gmt_modified":"2026-04-28T19:48:38.9085032+04:00"},{"id":37551,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"a9154fa6ace3118ba37f67a132a8951a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#124-133","gmt_create":"2026-04-28T19:48:38.9085032+04:00","gmt_modified":"2026-04-28T19:48:38.9085032+04:00"},{"id":37552,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"a9154fa6ace3118ba37f67a132a8951a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 124-133","gmt_create":"2026-04-28T19:48:38.9090174+04:00","gmt_modified":"2026-04-28T19:48:38.9090174+04:00"},{"id":37553,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"d7d14eee16cef3e1cf0039ec5f52febf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_debug.ini#107-126","gmt_create":"2026-04-28T19:48:38.9090174+04:00","gmt_modified":"2026-04-28T19:48:38.9090174+04:00"},{"id":37554,"source_id":"2b777822e4399aff7d4e5ea26fcbe8b9","target_id":"d7d14eee16cef3e1cf0039ec5f52febf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 107-126","gmt_create":"2026-04-28T19:48:38.9090174+04:00","gmt_modified":"2026-04-28T19:48:38.9090174+04:00"},{"id":37555,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"154f8101227c15750c6aa53260e9b84f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/plugin.cpp#374-420","gmt_create":"2026-04-28T19:48:38.909541+04:00","gmt_modified":"2026-04-28T19:48:38.909541+04:00"},{"id":37556,"source_id":"796d893189111ab0df5e606d82fea700","target_id":"154f8101227c15750c6aa53260e9b84f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 374-420","gmt_create":"2026-04-28T19:48:38.909541+04:00","gmt_modified":"2026-04-28T19:48:38.909541+04:00"},{"id":37557,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"020b183f2967c754e5327defd9a63415","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: documentation/debug_node_plugin.md#50-134","gmt_create":"2026-04-28T19:48:38.909541+04:00","gmt_modified":"2026-04-28T19:48:38.909541+04:00"},{"id":37558,"source_id":"3f9fffa35f3712fd1f90ebc3c0593373","target_id":"020b183f2967c754e5327defd9a63415","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 50-134","gmt_create":"2026-04-28T19:48:38.9100511+04:00","gmt_modified":"2026-04-28T19:48:38.9100511+04:00"},{"id":37559,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"f7356b2eafc5252755db0df36458992f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp#62-90","gmt_create":"2026-04-28T19:48:38.9105723+04:00","gmt_modified":"2026-04-28T19:48:38.9105723+04:00"},{"id":37560,"source_id":"85e109c379780f5df7bb2695b2862fba","target_id":"f7356b2eafc5252755db0df36458992f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 62-90","gmt_create":"2026-04-28T19:48:38.9105723+04:00","gmt_modified":"2026-04-28T19:48:38.9105723+04:00"},{"id":37710,"source_id":"4493b728-953f-4c7d-9b30-89aa33255a3b","target_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4493b728-953f-4c7d-9b30-89aa33255a3b -\u003e 3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","gmt_create":"2026-04-28T19:53:06.3555351+04:00","gmt_modified":"2026-04-28T19:53:06.3555351+04:00"},{"id":37711,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"589f3f8e-0048-4b0d-befe-693f063b0ce4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3db3b667-c9b0-4ef0-bdbd-1e4638995b5c -\u003e 589f3f8e-0048-4b0d-befe-693f063b0ce4","gmt_create":"2026-04-28T19:53:06.3588937+04:00","gmt_modified":"2026-04-28T19:53:06.3588937+04:00"},{"id":37712,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"3c6c03d8-c73c-48e4-8076-4deaff61fc83","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3db3b667-c9b0-4ef0-bdbd-1e4638995b5c -\u003e 3c6c03d8-c73c-48e4-8076-4deaff61fc83","gmt_create":"2026-04-28T19:53:06.3588937+04:00","gmt_modified":"2026-04-28T19:53:06.3588937+04:00"},{"id":37713,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"7e6094b6-9310-43af-993d-e3bebf0c7ee7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3db3b667-c9b0-4ef0-bdbd-1e4638995b5c -\u003e 7e6094b6-9310-43af-993d-e3bebf0c7ee7","gmt_create":"2026-04-28T19:53:06.3594842+04:00","gmt_modified":"2026-04-28T19:53:06.3594842+04:00"},{"id":37714,"source_id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","target_id":"40c4f036-b025-4e82-846a-a71cf89d5e5a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3db3b667-c9b0-4ef0-bdbd-1e4638995b5c -\u003e 40c4f036-b025-4e82-846a-a71cf89d5e5a","gmt_create":"2026-04-28T19:53:06.3594842+04:00","gmt_modified":"2026-04-28T19:53:06.3594842+04:00"},{"id":37742,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"82787c8d2e7394cf00fa87735394c3d5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-95","gmt_create":"2026-04-28T20:32:44.2192103+04:00","gmt_modified":"2026-04-28T20:32:44.2192103+04:00"},{"id":37747,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"ab73f6cda0f4389d2bef214161afef81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 593-601","gmt_create":"2026-04-28T20:32:44.2202162+04:00","gmt_modified":"2026-04-28T20:32:44.2202162+04:00"},{"id":37749,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"8caf3345fc407dc61382d80fab63bc93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5240-5274","gmt_create":"2026-04-28T20:32:44.221214+04:00","gmt_modified":"2026-04-28T20:32:44.221214+04:00"},{"id":37752,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"8e54da669dc427d415acec15fb6a804a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3039-3045","gmt_create":"2026-04-28T20:32:44.2222136+04:00","gmt_modified":"2026-04-28T20:32:44.2222136+04:00"},{"id":37754,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e6da7f673c730dddfe0373c2e796f71a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1215-1246","gmt_create":"2026-04-28T20:32:44.2222136+04:00","gmt_modified":"2026-04-28T20:32:44.2222136+04:00"},{"id":37757,"source_id":"3948eb588d15d01acf21ffd439ec508c","target_id":"f02c5e6d0090d5de89e01b0a1d478c5c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-45","gmt_create":"2026-04-28T20:32:44.2232056+04:00","gmt_modified":"2026-04-28T20:32:44.2232056+04:00"},{"id":37759,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"f5f7d5764818ed749bc9b829f7aea2ff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-386","gmt_create":"2026-04-28T20:32:44.2242947+04:00","gmt_modified":"2026-04-28T20:32:44.2242947+04:00"},{"id":37764,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"56968eec4c8adc4f9edd153c6ce9e231","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-374","gmt_create":"2026-04-28T20:32:44.2260949+04:00","gmt_modified":"2026-04-28T20:32:44.2260949+04:00"},{"id":37768,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"8923fae736f09b1cb255636af9a52069","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6389","gmt_create":"2026-04-28T20:32:44.2274126+04:00","gmt_modified":"2026-04-28T20:32:44.2274126+04:00"},{"id":37771,"source_id":"3948eb588d15d01acf21ffd439ec508c","target_id":"18382ca1b0f5cd7c4280e057d0242410","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-49","gmt_create":"2026-04-28T20:32:44.2280338+04:00","gmt_modified":"2026-04-28T20:32:44.2280338+04:00"},{"id":37773,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"a41d1e5edd6d2706424bcd3b39295264","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 68-162","gmt_create":"2026-04-28T20:32:44.2291474+04:00","gmt_modified":"2026-04-28T20:32:44.2291474+04:00"},{"id":37775,"source_id":"69291a4b8d9de900b397578829d3e0d9","target_id":"3de0360b8d19b4e6a521e737d44e1eec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 128-140","gmt_create":"2026-04-28T20:32:44.2291474+04:00","gmt_modified":"2026-04-28T20:32:44.2291474+04:00"},{"id":37778,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"df02d50a1fa9064e2cfe4b033b6ecfc8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 233-306","gmt_create":"2026-04-28T20:32:44.2306744+04:00","gmt_modified":"2026-04-28T20:32:44.2306744+04:00"},{"id":37783,"source_id":"69291a4b8d9de900b397578829d3e0d9","target_id":"c32e26ac2223fcbd9ec8280f135d338c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 135-140","gmt_create":"2026-04-28T20:32:44.2334797+04:00","gmt_modified":"2026-04-28T20:32:44.2334797+04:00"},{"id":37786,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"0543ad31da0059b627fc7cfd5bac0cad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 233-272","gmt_create":"2026-04-28T20:32:44.2339834+04:00","gmt_modified":"2026-04-28T20:32:44.2339834+04:00"},{"id":37788,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"fa47faf491ab252556d3fc50f00c6a8d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 662-718","gmt_create":"2026-04-28T20:32:44.2339834+04:00","gmt_modified":"2026-04-28T20:32:44.2339834+04:00"},{"id":37791,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"09cde54d90657149861df59444b291ba","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 244-338","gmt_create":"2026-04-28T20:32:44.2359867+04:00","gmt_modified":"2026-04-28T20:32:44.2359867+04:00"},{"id":37793,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"e3f78790c3dfc7c45569ce78697bf9ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 240-278","gmt_create":"2026-04-28T20:32:44.2359867+04:00","gmt_modified":"2026-04-28T20:32:44.2359867+04:00"},{"id":37795,"source_id":"69291a4b8d9de900b397578829d3e0d9","target_id":"5212be0912badd41a65263c4ef5ab6fc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 237-283","gmt_create":"2026-04-28T20:32:44.2359867+04:00","gmt_modified":"2026-04-28T20:32:44.2359867+04:00"},{"id":37797,"source_id":"69291a4b8d9de900b397578829d3e0d9","target_id":"8743a349115da7520b9567a7d855ca18","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 148-235","gmt_create":"2026-04-28T20:32:44.2376163+04:00","gmt_modified":"2026-04-28T20:32:44.2376163+04:00"},{"id":37801,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"8c4475690fa2dd5b99756637ea5c7358","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 356-369","gmt_create":"2026-04-28T20:32:44.2411885+04:00","gmt_modified":"2026-04-28T20:32:44.2411885+04:00"},{"id":37803,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"c71708bd330ca79e1ba386a1763f5154","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 718-740","gmt_create":"2026-04-28T20:32:44.2418022+04:00","gmt_modified":"2026-04-28T20:32:44.2418022+04:00"},{"id":37805,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"9aacd835d38b395734ce6c87619ff59b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5272-5274","gmt_create":"2026-04-28T20:32:44.2423052+04:00","gmt_modified":"2026-04-28T20:32:44.2423052+04:00"},{"id":37807,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"a1b4ebbf3bdbfda373c476ae64175283","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 169-242","gmt_create":"2026-04-28T20:32:44.2423052+04:00","gmt_modified":"2026-04-28T20:32:44.2423052+04:00"},{"id":37809,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"179c82a5b5dc0ef88ef0f3d348aeabf7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 310-338","gmt_create":"2026-04-28T20:32:44.2433084+04:00","gmt_modified":"2026-04-28T20:32:44.2433084+04:00"},{"id":37811,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"50fe97d449649d053646df017c7d5108","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 255-308","gmt_create":"2026-04-28T20:32:44.2440526+04:00","gmt_modified":"2026-04-28T20:32:44.2440526+04:00"},{"id":37813,"source_id":"c82262dc5275e094efc9474032d15922","target_id":"707909d344d5db986aaec2161fe7ec64","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 58-58","gmt_create":"2026-04-28T20:32:44.2446234+04:00","gmt_modified":"2026-04-28T20:32:44.2446234+04:00"},{"id":37815,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"b07239f8068fdc811cbe0313fbee8a56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 175-279","gmt_create":"2026-04-28T20:32:44.2463141+04:00","gmt_modified":"2026-04-28T20:32:44.2463141+04:00"},{"id":37817,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"89fa671fe61671f5b5ab01a94646d7a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 428-480","gmt_create":"2026-04-28T20:32:44.2464113+04:00","gmt_modified":"2026-04-28T20:32:44.2464113+04:00"},{"id":37819,"source_id":"3a8d8a10556a0b6501e25aa43e91f913","target_id":"f57a019298b7b9496ef4f4a85f921f75","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 47-71","gmt_create":"2026-04-28T20:32:44.2469161+04:00","gmt_modified":"2026-04-28T20:32:44.2469161+04:00"},{"id":37821,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"228fc59a5268956db45d2f696afd5586","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 518-526","gmt_create":"2026-04-28T20:32:44.2469161+04:00","gmt_modified":"2026-04-28T20:32:44.2469161+04:00"},{"id":37823,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"8f4a83adbe444c72194effc3001fe32c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5265-5274","gmt_create":"2026-04-28T20:32:44.2480151+04:00","gmt_modified":"2026-04-28T20:32:44.2480151+04:00"},{"id":37825,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4488509fca59b45f940f83b5db6daa2a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3874-3908","gmt_create":"2026-04-28T20:32:44.2485196+04:00","gmt_modified":"2026-04-28T20:32:44.2485196+04:00"},{"id":37827,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"313eca37529d6d0a87af6db00b3cae76","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3598-3626","gmt_create":"2026-04-28T20:32:44.2485196+04:00","gmt_modified":"2026-04-28T20:32:44.2485196+04:00"},{"id":37829,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"88cfd8edcbcced125d9358898750ad6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 172-182","gmt_create":"2026-04-28T20:32:44.2495238+04:00","gmt_modified":"2026-04-28T20:32:44.2495238+04:00"},{"id":37831,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"3442c112ec40ff3a7ce211827dd731fb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 599-600","gmt_create":"2026-04-28T20:32:44.2495238+04:00","gmt_modified":"2026-04-28T20:32:44.2495238+04:00"},{"id":37833,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"d2465d6814378cac309bb4813312e463","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4472-4479","gmt_create":"2026-04-28T20:32:44.2514671+04:00","gmt_modified":"2026-04-28T20:32:44.2514671+04:00"},{"id":37835,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"028e9730d5a18007052fca00e208de6c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5016-5021","gmt_create":"2026-04-28T20:32:44.252754+04:00","gmt_modified":"2026-04-28T20:32:44.252754+04:00"},{"id":37837,"source_id":"c70caf63ce77b078dcf89380b228a71a","target_id":"22da7c51b4640e33df6b1774de67e615","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 120-137","gmt_create":"2026-04-28T20:32:44.2533932+04:00","gmt_modified":"2026-04-28T20:32:44.2533932+04:00"},{"id":37839,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"0ff96f9f66fe11cb2bba96b2257c56cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5013-5014","gmt_create":"2026-04-28T20:32:44.2539907+04:00","gmt_modified":"2026-04-28T20:32:44.2539907+04:00"},{"id":37841,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"f6e4014b53decf8540f03050dcb248a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3061-3062","gmt_create":"2026-04-28T20:32:44.2546123+04:00","gmt_modified":"2026-04-28T20:32:44.2546123+04:00"},{"id":37843,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"3a3515773dce3d23274f19f11b24b8a1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 279-283","gmt_create":"2026-04-28T20:32:44.2551934+04:00","gmt_modified":"2026-04-28T20:32:44.2551934+04:00"},{"id":37845,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"bced6dc0057c5231cbd868d55b0f5331","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 340-354","gmt_create":"2026-04-28T20:32:44.2564626+04:00","gmt_modified":"2026-04-28T20:32:44.2564626+04:00"},{"id":37847,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"1496fd024a306e65ca11a1074f83e158","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 371-399","gmt_create":"2026-04-28T20:32:44.2569663+04:00","gmt_modified":"2026-04-28T20:32:44.2569663+04:00"},{"id":37849,"source_id":"18555f254f50536a15d8591acf982406","target_id":"e196c8cfa8e7dbe5852841c2e099bad5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 96-101","gmt_create":"2026-04-28T20:32:44.2579708+04:00","gmt_modified":"2026-04-28T20:32:44.2579708+04:00"},{"id":37851,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"c1db40762caab4c9462bb6bc70748152","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-45","gmt_create":"2026-04-28T20:32:44.2614959+04:00","gmt_modified":"2026-04-28T20:32:44.2614959+04:00"},{"id":37853,"source_id":"6e587b97bf4080c7754c5ed73736fca7","target_id":"973153247aad2260b57a9e4842ddfeb7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-28","gmt_create":"2026-04-28T20:32:44.2620208+04:00","gmt_modified":"2026-04-28T20:32:44.2620208+04:00"},{"id":37856,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"37d9a1a0250d6f2b30d0b5acfef7b606","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-35","gmt_create":"2026-04-28T20:32:44.2630248+04:00","gmt_modified":"2026-04-28T20:32:44.2630248+04:00"},{"id":37858,"source_id":"f7dedf31e491c7adbaf05e957360c531","target_id":"9fbb8ea1084712b6e00c9f6b9ad60c72","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-31","gmt_create":"2026-04-28T20:32:44.2635279+04:00","gmt_modified":"2026-04-28T20:32:44.2635279+04:00"},{"id":37860,"source_id":"3a8d8a10556a0b6501e25aa43e91f913","target_id":"63f471b93ce70266253197686f8d7df6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-35","gmt_create":"2026-04-28T20:32:44.2857552+04:00","gmt_modified":"2026-04-28T20:32:44.2857552+04:00"},{"id":37862,"source_id":"b4467ca30cb6f6d587fc200900ee9ec9","target_id":"f18f4bdd5e9956c9abb9a7a52882581a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-31","gmt_create":"2026-04-28T20:32:44.2863601+04:00","gmt_modified":"2026-04-28T20:32:44.2863601+04:00"},{"id":37864,"source_id":"3a6c30f4bb3b265155c881ccfafa980e","target_id":"03beec6b648d43a165d35e195b3eb81e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 285-306","gmt_create":"2026-04-28T20:32:44.2886911+04:00","gmt_modified":"2026-04-28T20:32:44.2886911+04:00"},{"id":37866,"source_id":"c82262dc5275e094efc9474032d15922","target_id":"8620e966ce1a76d2ab405f5a49743457","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-50","gmt_create":"2026-04-28T20:32:44.2886911+04:00","gmt_modified":"2026-04-28T20:32:44.2886911+04:00"},{"id":37868,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"d6ed83bad3a3124e13f09c4c1191b96a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 314-325","gmt_create":"2026-04-28T20:32:44.2898464+04:00","gmt_modified":"2026-04-28T20:32:44.2898464+04:00"},{"id":37870,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"fcdabf2022a050e8a2414fb979f5c419","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3448-3470","gmt_create":"2026-04-28T20:32:44.2903506+04:00","gmt_modified":"2026-04-28T20:32:44.2903506+04:00"},{"id":37873,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"70f9beafdbca4132e0349e28e51fcd6a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1239-1241","gmt_create":"2026-04-28T20:32:44.2920603+04:00","gmt_modified":"2026-04-28T20:32:44.2920603+04:00"},{"id":37875,"source_id":"cb29035725926be38d36ad8c01792b7e","target_id":"e4313416f9a67f60a9a17f977b2367f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 86-86","gmt_create":"2026-04-28T20:32:44.2925879+04:00","gmt_modified":"2026-04-28T20:32:44.2925879+04:00"},{"id":37877,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b0498790fa704db3f0e0545f4299a7ba","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 79-82","gmt_create":"2026-04-28T20:32:44.2935951+04:00","gmt_modified":"2026-04-28T20:32:44.2935951+04:00"},{"id":37879,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"34cf64d4d37824f3883c4c577708cd70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3278-3281","gmt_create":"2026-04-28T20:32:44.3000122+04:00","gmt_modified":"2026-04-28T20:32:44.3000122+04:00"},{"id":37881,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"9619a9ec94b261a592033e0c0b3be117","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3633-3636","gmt_create":"2026-04-28T20:32:44.3010127+04:00","gmt_modified":"2026-04-28T20:32:44.3010127+04:00"},{"id":37883,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"99d4fcb1177774e0710d2bd69e6b48d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3653-3656","gmt_create":"2026-04-28T20:32:44.3010127+04:00","gmt_modified":"2026-04-28T20:32:44.3010127+04:00"},{"id":37885,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"f652bd37bb37781168ae6561fb03f9b4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3671-3674","gmt_create":"2026-04-28T20:32:44.3020116+04:00","gmt_modified":"2026-04-28T20:32:44.3020116+04:00"},{"id":37937,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"c6554da5c3030abf996fb5a45f613846","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3874-3909","gmt_create":"2026-04-28T20:33:17.151438+04:00","gmt_modified":"2026-04-28T20:33:17.151438+04:00"},{"id":37939,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"bb2f9b88565dffaafac5243508216aad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3883","gmt_create":"2026-04-28T20:33:17.1524413+04:00","gmt_modified":"2026-04-28T20:33:17.1524413+04:00"},{"id":37941,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"2b7b8d880d43c3e7cdf61f5c181897fa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3895","gmt_create":"2026-04-28T20:33:17.1524413+04:00","gmt_modified":"2026-04-28T20:33:17.1524413+04:00"},{"id":37943,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"49a1105e8b0a1091759ed0dd8456fc18","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3717-3739","gmt_create":"2026-04-28T20:33:17.1534413+04:00","gmt_modified":"2026-04-28T20:33:17.1534413+04:00"},{"id":37945,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"82fada5a3bea92890319c59908b5d6af","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 595-603","gmt_create":"2026-04-28T20:33:17.1544449+04:00","gmt_modified":"2026-04-28T20:33:17.1544449+04:00"},{"id":37947,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"9f97ef4b79b69efdb12cdc50f9ef0041","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 595-598","gmt_create":"2026-04-28T20:33:17.1544449+04:00","gmt_modified":"2026-04-28T20:33:17.1544449+04:00"},{"id":37949,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"370a3f3d23b4e8b36669b9d077f388d6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5493-5498","gmt_create":"2026-04-28T20:33:17.155442+04:00","gmt_modified":"2026-04-28T20:33:17.155442+04:00"},{"id":37951,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"81b23e3b2e8218a8eb6600e8f2e88066","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 601-602","gmt_create":"2026-04-28T20:33:17.155442+04:00","gmt_modified":"2026-04-28T20:33:17.155442+04:00"},{"id":37953,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"9a4c9be971e9ec84202ea73657bbdd6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3523-3533","gmt_create":"2026-04-28T20:33:17.1564433+04:00","gmt_modified":"2026-04-28T20:33:17.1564433+04:00"},{"id":37955,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"abeeffae57c62e28daad08e42b7697e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3892-3895","gmt_create":"2026-04-28T20:33:17.1564433+04:00","gmt_modified":"2026-04-28T20:33:17.1564433+04:00"},{"id":37963,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"a2e60c6967300f8a131741ffe433fb3c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3885-3895","gmt_create":"2026-04-28T20:33:17.1588804+04:00","gmt_modified":"2026-04-28T20:33:17.1588804+04:00"},{"id":38115,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"1fc0915e82dd4c943724dcd2e29106cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 159-175","gmt_create":"2026-04-28T20:38:58.1779414+04:00","gmt_modified":"2026-04-28T20:38:58.1779414+04:00"},{"id":38124,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"b89fc00b26b800a29e1692b23ada0d56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 168-172","gmt_create":"2026-04-28T20:38:58.1805172+04:00","gmt_modified":"2026-04-28T20:38:58.1805172+04:00"},{"id":38215,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"4c7480a472e5a837a77edfce9accd782","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1360-1380","gmt_create":"2026-04-28T20:42:58.7586084+04:00","gmt_modified":"2026-04-28T20:42:58.7586084+04:00"},{"id":38369,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"509be78f5e90ad720bc5cb62f8252773","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1204-1270","gmt_create":"2026-04-28T21:02:01.9680597+04:00","gmt_modified":"2026-04-28T21:02:01.9680597+04:00"},{"id":38371,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"2f3627b50fb7b7e496ab7f3d82bb011c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 521-544","gmt_create":"2026-04-28T21:02:01.9680597+04:00","gmt_modified":"2026-04-28T21:02:01.9680597+04:00"},{"id":38375,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"2426f410a167c0334267f66a00c3b706","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-200","gmt_create":"2026-04-28T21:02:01.9690597+04:00","gmt_modified":"2026-04-28T21:02:01.9690597+04:00"},{"id":38380,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"13ad0bfb014506790d3eea0ac1e240eb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-697","gmt_create":"2026-04-28T21:02:01.9813722+04:00","gmt_modified":"2026-04-28T21:02:01.9813722+04:00"},{"id":38382,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"adbfa85db79875fa5ba5450da427c626","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 110-124","gmt_create":"2026-04-28T21:02:01.9813722+04:00","gmt_modified":"2026-04-28T21:02:01.9813722+04:00"},{"id":38384,"source_id":"8ede002b6c76d0a07d75e34f812e8305","target_id":"9f5944a7feb01c0c201e4a490c1c6d47","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-7","gmt_create":"2026-04-28T21:02:01.9818898+04:00","gmt_modified":"2026-04-28T21:02:01.9818898+04:00"},{"id":38387,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"3697c4125ef62ecb76b9032b46a67ad2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-92","gmt_create":"2026-04-28T21:02:01.9824071+04:00","gmt_modified":"2026-04-28T21:02:01.9824071+04:00"},{"id":38392,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"3ae8431619379889035afee8a7f98a96","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1300-1399","gmt_create":"2026-04-28T21:02:01.9834512+04:00","gmt_modified":"2026-04-28T21:02:01.9834512+04:00"},{"id":38394,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"4dbf49507663ef2d477a4e56e7ad4113","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-84","gmt_create":"2026-04-28T21:02:01.9834512+04:00","gmt_modified":"2026-04-28T21:02:01.9834512+04:00"},{"id":38396,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"a0f13c35d9ba18928ea0803560d59338","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-55","gmt_create":"2026-04-28T21:02:01.9834512+04:00","gmt_modified":"2026-04-28T21:02:01.9834512+04:00"},{"id":38398,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"b241a3148f38f58dc134c0db61057fbe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-144","gmt_create":"2026-04-28T21:02:01.9845602+04:00","gmt_modified":"2026-04-28T21:02:01.9845602+04:00"},{"id":38400,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"78b7d2f924e066f18e5bf4ed42de6954","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-278","gmt_create":"2026-04-28T21:02:01.9853589+04:00","gmt_modified":"2026-04-28T21:02:01.9853589+04:00"},{"id":38402,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"4166755ed54cfd6a56e5d4acb8144b2e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-144","gmt_create":"2026-04-28T21:02:01.9859735+04:00","gmt_modified":"2026-04-28T21:02:01.9859735+04:00"},{"id":38405,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"f32c5cb0846168684a2574ccb17d2cd7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 189-231","gmt_create":"2026-04-28T21:02:01.9865516+04:00","gmt_modified":"2026-04-28T21:02:01.9865516+04:00"},{"id":38407,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7066405016bb2acea5a040cdac13b646","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1037-1177","gmt_create":"2026-04-28T21:02:01.9871318+04:00","gmt_modified":"2026-04-28T21:02:01.9871318+04:00"},{"id":38409,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1c914e70d8a846e0ed416af007bd2b78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 259-294","gmt_create":"2026-04-28T21:02:01.9877186+04:00","gmt_modified":"2026-04-28T21:02:01.9877186+04:00"},{"id":38412,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d2b082cb10acf9968b8eb975d61abc92","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4444-4533","gmt_create":"2026-04-28T21:02:01.9889113+04:00","gmt_modified":"2026-04-28T21:02:01.9889113+04:00"},{"id":38415,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"da4792d808b920542e8e3f85c533f97d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 118-164","gmt_create":"2026-04-28T21:02:01.9894139+04:00","gmt_modified":"2026-04-28T21:02:01.9894139+04:00"},{"id":38417,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"fb711bedba071dd61482af3dd825bb98","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 115-128","gmt_create":"2026-04-28T21:02:01.9904171+04:00","gmt_modified":"2026-04-28T21:02:01.9904171+04:00"},{"id":38419,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"83d7c3cd276c8b6c3a77f6379e8968e4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 561-580","gmt_create":"2026-04-28T21:02:01.9904171+04:00","gmt_modified":"2026-04-28T21:02:01.9904171+04:00"},{"id":38421,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"420ba4d931c9392dd8824c0faaf3b99b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 738-792","gmt_create":"2026-04-28T21:02:01.9904171+04:00","gmt_modified":"2026-04-28T21:02:01.9904171+04:00"},{"id":38423,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"fc699eb749d790d44345a92dd356956e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 206-230","gmt_create":"2026-04-28T21:02:01.9917637+04:00","gmt_modified":"2026-04-28T21:02:01.9917637+04:00"},{"id":38425,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"217f231a3e1f1591acfb14f4b40fb2b3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 476-515","gmt_create":"2026-04-28T21:02:01.9922668+04:00","gmt_modified":"2026-04-28T21:02:01.9922668+04:00"},{"id":38427,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"b25bd7f79844225b0a1356e5a6dbee8b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 92-103","gmt_create":"2026-04-28T21:02:01.9937452+04:00","gmt_modified":"2026-04-28T21:02:01.9937452+04:00"},{"id":38429,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"447323529866a4410bcb34a227ea5b5a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1075-1087","gmt_create":"2026-04-28T21:02:01.9942487+04:00","gmt_modified":"2026-04-28T21:02:01.9942487+04:00"},{"id":38431,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d59a4116db64f54b5d2ce9c64e1c2c50","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4581-4594","gmt_create":"2026-04-28T21:02:01.9942487+04:00","gmt_modified":"2026-04-28T21:02:01.9942487+04:00"},{"id":38434,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"aa98d4cf2cd33ba5c1e2a0fee44c3645","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 597-612","gmt_create":"2026-04-28T21:02:01.9952524+04:00","gmt_modified":"2026-04-28T21:02:01.9952524+04:00"},{"id":38436,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a8acea32ccb60d16cf2952aa7df51926","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4334-4438","gmt_create":"2026-04-28T21:02:01.9962521+04:00","gmt_modified":"2026-04-28T21:02:01.9962521+04:00"},{"id":38438,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"cda8d76def01f28cd58e347939faf10a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4420-4438","gmt_create":"2026-04-28T21:02:01.9962521+04:00","gmt_modified":"2026-04-28T21:02:01.9962521+04:00"},{"id":38440,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"119ec7c643a34aa808f9d5b76965a662","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4444-4450","gmt_create":"2026-04-28T21:02:01.9962521+04:00","gmt_modified":"2026-04-28T21:02:01.9962521+04:00"},{"id":38443,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"9d352185df5c8af06a8101e30a248ef8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4360-4398","gmt_create":"2026-04-28T21:02:01.997252+04:00","gmt_modified":"2026-04-28T21:02:01.997252+04:00"},{"id":38445,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"315cdb5412a417207b9932317c120c97","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4400-4419","gmt_create":"2026-04-28T21:02:01.997252+04:00","gmt_modified":"2026-04-28T21:02:01.997252+04:00"},{"id":38447,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"450f29f1b3febed1e121639037851576","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 521-526","gmt_create":"2026-04-28T21:02:01.9982523+04:00","gmt_modified":"2026-04-28T21:02:01.9982523+04:00"},{"id":38449,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"17c7b337a56de7a5cd94cd10c3d44dac","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4428-4430","gmt_create":"2026-04-28T21:02:01.9992273+04:00","gmt_modified":"2026-04-28T21:02:01.9992273+04:00"},{"id":38451,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"48593fdf91cfb9e4763322dc0efe26f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 565-656","gmt_create":"2026-04-28T21:02:01.9997631+04:00","gmt_modified":"2026-04-28T21:02:01.9997631+04:00"},{"id":38453,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"b71278e4b4266bb8a15b6aba152b2962","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 121","gmt_create":"2026-04-28T21:02:02.0004254+04:00","gmt_modified":"2026-04-28T21:02:02.0004254+04:00"},{"id":38455,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"065d68f5f096b48e88dfb2982a30bcb6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 114-146","gmt_create":"2026-04-28T21:02:02.0010139+04:00","gmt_modified":"2026-04-28T21:02:02.0010139+04:00"},{"id":38458,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"c2ea6047c89205fb8308a32ce5248eee","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-103","gmt_create":"2026-04-28T21:02:02.0044444+04:00","gmt_modified":"2026-04-28T21:02:02.0044444+04:00"},{"id":38460,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"811ab9cb3d00924a080202c009434d6e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1254-1298","gmt_create":"2026-04-28T21:02:02.0061844+04:00","gmt_modified":"2026-04-28T21:02:02.0061844+04:00"},{"id":38462,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"33f7190f97ab910175bbc25c0d3288cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-46","gmt_create":"2026-04-28T21:02:02.0078591+04:00","gmt_modified":"2026-04-28T21:02:02.0078591+04:00"},{"id":38464,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"536ce91c592f598c4853f295a9a28e59","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-75","gmt_create":"2026-04-28T21:02:02.0084982+04:00","gmt_modified":"2026-04-28T21:02:02.0084982+04:00"},{"id":38466,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"49ed36643f75c3d722e6b1a2ff17d7e0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1390-1465","gmt_create":"2026-04-28T21:02:02.0090723+04:00","gmt_modified":"2026-04-28T21:02:02.0090723+04:00"},{"id":38468,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"58d38a217f74656ded3587bd3c6f7dc1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 614-646","gmt_create":"2026-04-28T21:02:02.0097348+04:00","gmt_modified":"2026-04-28T21:02:02.0097348+04:00"},{"id":38469,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"4238a9561f85e50a38f76813baeadd7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/block_log.hpp","gmt_create":"2026-04-28T21:03:48.5527991+04:00","gmt_modified":"2026-04-28T21:03:48.5527991+04:00"},{"id":38470,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"d2090ff9016be0d896d06e843936e0f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/block_log.cpp","gmt_create":"2026-04-28T21:03:48.5533394+04:00","gmt_modified":"2026-04-28T21:03:48.5533394+04:00"},{"id":38471,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"01456fc1d03088da2d9080a7ba380f5f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/block_summary_object.hpp","gmt_create":"2026-04-28T21:03:48.5533394+04:00","gmt_modified":"2026-04-28T21:03:48.5533394+04:00"},{"id":38472,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-28T21:03:48.5539209+04:00","gmt_modified":"2026-04-28T21:03:48.5539209+04:00"},{"id":38473,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-28T21:03:48.5539209+04:00","gmt_modified":"2026-04-28T21:03:48.5539209+04:00"},{"id":38474,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-28T21:03:48.5539209+04:00","gmt_modified":"2026-04-28T21:03:48.5539209+04:00"},{"id":38475,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-28T21:03:48.5545273+04:00","gmt_modified":"2026-04-28T21:03:48.5545273+04:00"},{"id":38476,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-28T21:03:48.5545273+04:00","gmt_modified":"2026-04-28T21:03:48.5545273+04:00"},{"id":38477,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"6c94b84fdfd5c7016b5eeadf8099133e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/plugin.cpp","gmt_create":"2026-04-28T21:03:48.5545273+04:00","gmt_modified":"2026-04-28T21:03:48.5545273+04:00"},{"id":38478,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-28T21:03:48.5551092+04:00","gmt_modified":"2026-04-28T21:03:48.5551092+04:00"},{"id":38479,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"73975f89dd3f307861db3a250bbdd78c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#36-200","gmt_create":"2026-04-28T21:03:48.5551092+04:00","gmt_modified":"2026-04-28T21:03:48.5551092+04:00"},{"id":38480,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"73975f89dd3f307861db3a250bbdd78c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-200","gmt_create":"2026-04-28T21:03:48.5556117+04:00","gmt_modified":"2026-04-28T21:03:48.5556117+04:00"},{"id":38481,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"7624493910e6464a6ff493726bdeee9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#53-122","gmt_create":"2026-04-28T21:03:48.5556905+04:00","gmt_modified":"2026-04-28T21:03:48.5556905+04:00"},{"id":38482,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"7624493910e6464a6ff493726bdeee9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-122","gmt_create":"2026-04-28T21:03:48.5556905+04:00","gmt_modified":"2026-04-28T21:03:48.5556905+04:00"},{"id":38483,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"945c89d3db9c4818f2b0a69c5686f53c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#38-71","gmt_create":"2026-04-28T21:03:48.5562744+04:00","gmt_modified":"2026-04-28T21:03:48.5562744+04:00"},{"id":38484,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"945c89d3db9c4818f2b0a69c5686f53c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-71","gmt_create":"2026-04-28T21:03:48.5562744+04:00","gmt_modified":"2026-04-28T21:03:48.5562744+04:00"},{"id":38485,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"6e1a4f8dfd8b1b6545342d2b70d91400","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_summary_object.hpp#19-42","gmt_create":"2026-04-28T21:03:48.5567771+04:00","gmt_modified":"2026-04-28T21:03:48.5567771+04:00"},{"id":38486,"source_id":"01456fc1d03088da2d9080a7ba380f5f","target_id":"6e1a4f8dfd8b1b6545342d2b70d91400","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-42","gmt_create":"2026-04-28T21:03:48.556929+04:00","gmt_modified":"2026-04-28T21:03:48.556929+04:00"},{"id":38487,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"8fef9b15033051e7fdc3504d87a3d365","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3354-3366","gmt_create":"2026-04-28T21:03:48.556929+04:00","gmt_modified":"2026-04-28T21:03:48.556929+04:00"},{"id":38488,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"8fef9b15033051e7fdc3504d87a3d365","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3354-3366","gmt_create":"2026-04-28T21:03:48.5574316+04:00","gmt_modified":"2026-04-28T21:03:48.5574316+04:00"},{"id":38489,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"eb846b95ed45c45ecbc3ee5ab1ebd24f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#152-157","gmt_create":"2026-04-28T21:03:48.5574316+04:00","gmt_modified":"2026-04-28T21:03:48.5574316+04:00"},{"id":38490,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"eb846b95ed45c45ecbc3ee5ab1ebd24f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 152-157","gmt_create":"2026-04-28T21:03:48.5574316+04:00","gmt_modified":"2026-04-28T21:03:48.5574316+04:00"},{"id":38491,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"5b3217d2dd702e5291fda9a14af9defe","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#104-121","gmt_create":"2026-04-28T21:03:48.5574316+04:00","gmt_modified":"2026-04-28T21:03:48.5574316+04:00"},{"id":38492,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"5b3217d2dd702e5291fda9a14af9defe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 104-121","gmt_create":"2026-04-28T21:03:48.5574316+04:00","gmt_modified":"2026-04-28T21:03:48.5574316+04:00"},{"id":38493,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"f8faa71211c346e22bdea2dbbd1cc994","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#134-193","gmt_create":"2026-04-28T21:03:48.5670475+04:00","gmt_modified":"2026-04-28T21:03:48.5670475+04:00"},{"id":38494,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"e29d6a6310d6247eaf38fa2c35b35373","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#33-90","gmt_create":"2026-04-28T21:03:48.5684052+04:00","gmt_modified":"2026-04-28T21:03:48.5684052+04:00"},{"id":38495,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"b18325dfe4c9f546850aa53aae935765","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#193-196","gmt_create":"2026-04-28T21:03:48.5684052+04:00","gmt_modified":"2026-04-28T21:03:48.5684052+04:00"},{"id":38496,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"b18325dfe4c9f546850aa53aae935765","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 193-196","gmt_create":"2026-04-28T21:03:48.5684052+04:00","gmt_modified":"2026-04-28T21:03:48.5684052+04:00"},{"id":38497,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"7f585b7ee9cce4a8ab1f33b5b34f7f81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#737-792","gmt_create":"2026-04-28T21:03:48.5689197+04:00","gmt_modified":"2026-04-28T21:03:48.5689197+04:00"},{"id":38498,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7f585b7ee9cce4a8ab1f33b5b34f7f81","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 737-792","gmt_create":"2026-04-28T21:03:48.5689197+04:00","gmt_modified":"2026-04-28T21:03:48.5689197+04:00"},{"id":38499,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"a2dca3272c082a5aafb990a745f3fd75","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#142-174","gmt_create":"2026-04-28T21:03:48.5689197+04:00","gmt_modified":"2026-04-28T21:03:48.5689197+04:00"},{"id":38500,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"a2dca3272c082a5aafb990a745f3fd75","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 142-174","gmt_create":"2026-04-28T21:03:48.5694321+04:00","gmt_modified":"2026-04-28T21:03:48.5694321+04:00"},{"id":38501,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"5256db9d4dcb3c7fd627ebb8f8547f74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#103-142","gmt_create":"2026-04-28T21:03:48.5694321+04:00","gmt_modified":"2026-04-28T21:03:48.5694321+04:00"},{"id":38502,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"5256db9d4dcb3c7fd627ebb8f8547f74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 103-142","gmt_create":"2026-04-28T21:03:48.5694321+04:00","gmt_modified":"2026-04-28T21:03:48.5694321+04:00"},{"id":38503,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"6e54a9c0d543d98384d205535ead2c39","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#800-925","gmt_create":"2026-04-28T21:03:48.5694321+04:00","gmt_modified":"2026-04-28T21:03:48.5694321+04:00"},{"id":38504,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6e54a9c0d543d98384d205535ead2c39","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 800-925","gmt_create":"2026-04-28T21:03:48.5694321+04:00","gmt_modified":"2026-04-28T21:03:48.5694321+04:00"},{"id":38505,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"0b84b82025c87f3b725ddf0c3804f197","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#253-257","gmt_create":"2026-04-28T21:03:48.5699406+04:00","gmt_modified":"2026-04-28T21:03:48.5699406+04:00"},{"id":38506,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"d2efa60ce77e110221f81af1427289e6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#195-226","gmt_create":"2026-04-28T21:03:48.5699406+04:00","gmt_modified":"2026-04-28T21:03:48.5699406+04:00"},{"id":38507,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"d2efa60ce77e110221f81af1427289e6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 195-226","gmt_create":"2026-04-28T21:03:48.5704486+04:00","gmt_modified":"2026-04-28T21:03:48.5704486+04:00"},{"id":38508,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"fdfd8e0c768f197ad065fbd7ffc0d0c1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#263-299","gmt_create":"2026-04-28T21:03:48.5704486+04:00","gmt_modified":"2026-04-28T21:03:48.5704486+04:00"},{"id":38509,"source_id":"d2090ff9016be0d896d06e843936e0f4","target_id":"fdfd8e0c768f197ad065fbd7ffc0d0c1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 263-299","gmt_create":"2026-04-28T21:03:48.5704486+04:00","gmt_modified":"2026-04-28T21:03:48.5704486+04:00"},{"id":38510,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"5573208de1a8f72a275c35db65fc7bd8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#847-925","gmt_create":"2026-04-28T21:03:48.5720571+04:00","gmt_modified":"2026-04-28T21:03:48.5720571+04:00"},{"id":38511,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5573208de1a8f72a275c35db65fc7bd8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 847-925","gmt_create":"2026-04-28T21:03:48.5720571+04:00","gmt_modified":"2026-04-28T21:03:48.5720571+04:00"},{"id":38512,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"2f1395bd486711cb5d7bc0cd80794c96","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3443-3500","gmt_create":"2026-04-28T21:03:48.5720571+04:00","gmt_modified":"2026-04-28T21:03:48.5720571+04:00"},{"id":38513,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2f1395bd486711cb5d7bc0cd80794c96","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3443-3500","gmt_create":"2026-04-28T21:03:48.5720571+04:00","gmt_modified":"2026-04-28T21:03:48.5720571+04:00"},{"id":38514,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"1c4d9b7ff7c2fd8f72e2d64d37f89138","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3723-3748","gmt_create":"2026-04-28T21:03:48.5720571+04:00","gmt_modified":"2026-04-28T21:03:48.5720571+04:00"},{"id":38515,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1c4d9b7ff7c2fd8f72e2d64d37f89138","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3723-3748","gmt_create":"2026-04-28T21:03:48.572559+04:00","gmt_modified":"2026-04-28T21:03:48.572559+04:00"},{"id":38516,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"a5660f23ac4e94b12f678a1bbc729490","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3750-3757","gmt_create":"2026-04-28T21:03:48.572559+04:00","gmt_modified":"2026-04-28T21:03:48.572559+04:00"},{"id":38517,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a5660f23ac4e94b12f678a1bbc729490","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3750-3757","gmt_create":"2026-04-28T21:03:48.572559+04:00","gmt_modified":"2026-04-28T21:03:48.572559+04:00"},{"id":38518,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"54e518a8354b5d7fb8af8a31a68d3a41","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3759-3873","gmt_create":"2026-04-28T21:03:48.572559+04:00","gmt_modified":"2026-04-28T21:03:48.572559+04:00"},{"id":38519,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"54e518a8354b5d7fb8af8a31a68d3a41","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3759-3873","gmt_create":"2026-04-28T21:03:48.572559+04:00","gmt_modified":"2026-04-28T21:03:48.572559+04:00"},{"id":38520,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"6e4547d3d8a2b1ce7fb2eb8442ba9631","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1294-1311","gmt_create":"2026-04-28T21:03:48.573074+04:00","gmt_modified":"2026-04-28T21:03:48.573074+04:00"},{"id":38521,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"bbb78af6252229f84570f752f6e862a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2824-2837","gmt_create":"2026-04-28T21:03:48.573074+04:00","gmt_modified":"2026-04-28T21:03:48.573074+04:00"},{"id":38522,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"bbb78af6252229f84570f752f6e862a7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2824-2837","gmt_create":"2026-04-28T21:03:48.5736068+04:00","gmt_modified":"2026-04-28T21:03:48.5736068+04:00"},{"id":38523,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"a18ffbd92c9d4b692fc557c3652088aa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2871-2884","gmt_create":"2026-04-28T21:03:48.5736068+04:00","gmt_modified":"2026-04-28T21:03:48.5736068+04:00"},{"id":38524,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a18ffbd92c9d4b692fc557c3652088aa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2871-2884","gmt_create":"2026-04-28T21:03:48.5736068+04:00","gmt_modified":"2026-04-28T21:03:48.5736068+04:00"},{"id":38525,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"fce8b0371886adfbccd297ca25bedd14","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#185-187","gmt_create":"2026-04-28T21:03:48.5752824+04:00","gmt_modified":"2026-04-28T21:03:48.5752824+04:00"},{"id":38526,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"fce8b0371886adfbccd297ca25bedd14","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 185-187","gmt_create":"2026-04-28T21:03:48.5752824+04:00","gmt_modified":"2026-04-28T21:03:48.5752824+04:00"},{"id":38527,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"6f9d8d9e0dc35b4525248327639277c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3724-3748","gmt_create":"2026-04-28T21:03:48.5757852+04:00","gmt_modified":"2026-04-28T21:03:48.5757852+04:00"},{"id":38528,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6f9d8d9e0dc35b4525248327639277c9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3724-3748","gmt_create":"2026-04-28T21:03:48.5757852+04:00","gmt_modified":"2026-04-28T21:03:48.5757852+04:00"},{"id":38529,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"601b79126e6723e1b2405eb7e5f8be93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#270-300","gmt_create":"2026-04-28T21:03:48.5767884+04:00","gmt_modified":"2026-04-28T21:03:48.5767884+04:00"},{"id":38530,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"601b79126e6723e1b2405eb7e5f8be93","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 270-300","gmt_create":"2026-04-28T21:03:48.5767884+04:00","gmt_modified":"2026-04-28T21:03:48.5767884+04:00"},{"id":38531,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"5f0e48d3f7fad098a67eed7a88dc6134","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#250-257","gmt_create":"2026-04-28T21:03:48.5767884+04:00","gmt_modified":"2026-04-28T21:03:48.5767884+04:00"},{"id":38532,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5f0e48d3f7fad098a67eed7a88dc6134","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 250-257","gmt_create":"2026-04-28T21:03:48.5767884+04:00","gmt_modified":"2026-04-28T21:03:48.5767884+04:00"},{"id":38533,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"8df3a4b9e7bead2487cc1ffc6cd49cae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#16-19","gmt_create":"2026-04-28T21:03:48.5789025+04:00","gmt_modified":"2026-04-28T21:03:48.5789025+04:00"},{"id":38534,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"a0d3e919d8c2dcef090c5eb962daae1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#3-8","gmt_create":"2026-04-28T21:03:48.5789025+04:00","gmt_modified":"2026-04-28T21:03:48.5789025+04:00"},{"id":38535,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"a0d3e919d8c2dcef090c5eb962daae1a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-8","gmt_create":"2026-04-28T21:03:48.5789025+04:00","gmt_modified":"2026-04-28T21:03:48.5789025+04:00"},{"id":38536,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"54b31fbe33ef1eb12566c9f84fcf779d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#3-18","gmt_create":"2026-04-28T21:03:48.5794808+04:00","gmt_modified":"2026-04-28T21:03:48.5794808+04:00"},{"id":38537,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"54b31fbe33ef1eb12566c9f84fcf779d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-18","gmt_create":"2026-04-28T21:03:48.5794808+04:00","gmt_modified":"2026-04-28T21:03:48.5794808+04:00"},{"id":38538,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"3503ce5765018277af90477a590846e3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#3-9","gmt_create":"2026-04-28T21:03:48.5794808+04:00","gmt_modified":"2026-04-28T21:03:48.5794808+04:00"},{"id":38539,"source_id":"4238a9561f85e50a38f76813baeadd7e","target_id":"3503ce5765018277af90477a590846e3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3-9","gmt_create":"2026-04-28T21:03:48.5801244+04:00","gmt_modified":"2026-04-28T21:03:48.5801244+04:00"},{"id":38540,"source_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","target_id":"24fdd3fcf0b1451195e987e21e994f65","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#804-823","gmt_create":"2026-04-28T21:03:48.5818075+04:00","gmt_modified":"2026-04-28T21:03:48.5818075+04:00"},{"id":38541,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"24fdd3fcf0b1451195e987e21e994f65","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 804-823","gmt_create":"2026-04-28T21:03:48.582811+04:00","gmt_modified":"2026-04-28T21:03:48.582811+04:00"},{"id":38563,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"01108e5a8e624eede7c7c1ba5eabf3ed","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6643","gmt_create":"2026-04-28T21:05:29.6024784+04:00","gmt_modified":"2026-04-28T21:05:29.6024784+04:00"},{"id":38656,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"868816de-43fc-4fe0-9cf9-0e89f661447c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 868816de-43fc-4fe0-9cf9-0e89f661447c","gmt_create":"2026-04-28T21:05:34.7784809+04:00","gmt_modified":"2026-04-28T21:05:34.7784809+04:00"},{"id":38659,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-28T21:31:00.4452984+04:00","gmt_modified":"2026-04-28T21:31:00.4452984+04:00"},{"id":38660,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38661,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"d72b348a2c3c7943e4a7abb7dbdaa751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_connection.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38662,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/peer_connection.cpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38663,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"3a6c30f4bb3b265155c881ccfafa980e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/core_messages.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38664,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"2c99501f0c511d0792a2e5a56e4debfa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/core_messages.cpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38665,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"398d9d4b02b6383c0b752cb0196a0475","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/stcp_socket.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38666,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"01e57c63d684a56829f909c03b8ea162","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/stcp_socket.cpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38667,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"3a8d8a10556a0b6501e25aa43e91f913","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_database.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38668,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"c70caf63ce77b078dcf89380b228a71a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/peer_database.cpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38669,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b4467ca30cb6f6d587fc200900ee9ec9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38670,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"6e587b97bf4080c7754c5ed73736fca7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message_oriented_connection.hpp","gmt_create":"2026-04-28T21:31:00.4462984+04:00","gmt_modified":"2026-04-28T21:31:00.4462984+04:00"},{"id":38671,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"c82262dc5275e094efc9474032d15922","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/config.hpp","gmt_create":"2026-04-28T21:31:00.4478031+04:00","gmt_modified":"2026-04-28T21:31:00.4478031+04:00"},{"id":38672,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-28T21:31:00.4479719+04:00","gmt_modified":"2026-04-28T21:31:00.4479719+04:00"},{"id":38673,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"930f47bc2c95f0cac4086eeca5749e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#190-304","gmt_create":"2026-04-28T21:31:00.4479719+04:00","gmt_modified":"2026-04-28T21:31:00.4479719+04:00"},{"id":38674,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"9f8690911ef66c966743475f294ffb7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#79-351","gmt_create":"2026-04-28T21:31:00.4479719+04:00","gmt_modified":"2026-04-28T21:31:00.4479719+04:00"},{"id":38675,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"a480bfeb1604076e7d1db7746687a3b4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#42-106","gmt_create":"2026-04-28T21:31:00.4479719+04:00","gmt_modified":"2026-04-28T21:31:00.4479719+04:00"},{"id":38676,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"c54e54629fd9cd255341b311da9b6be1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#72-573","gmt_create":"2026-04-28T21:31:00.4479719+04:00","gmt_modified":"2026-04-28T21:31:00.4479719+04:00"},{"id":38677,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"4e8bc2cdd3d4fc68b2f7138c54288174","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#37-93","gmt_create":"2026-04-28T21:31:00.4488068+04:00","gmt_modified":"2026-04-28T21:31:00.4488068+04:00"},{"id":38678,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"7b85de17d00c3c33f3e6ce72493cea24","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#104-134","gmt_create":"2026-04-28T21:31:00.4488068+04:00","gmt_modified":"2026-04-28T21:31:00.4488068+04:00"},{"id":38679,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"ff11a77da594972e0b8a78df4289ada5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#45-79","gmt_create":"2026-04-28T21:31:00.4488068+04:00","gmt_modified":"2026-04-28T21:31:00.4488068+04:00"},{"id":38680,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"d614fc51360bb61b8f521167a6db1e11","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/config.hpp#26-106","gmt_create":"2026-04-28T21:31:00.4488068+04:00","gmt_modified":"2026-04-28T21:31:00.4488068+04:00"},{"id":38681,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"411a87e4e085e019827e9bd8085b8328","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#500-560","gmt_create":"2026-04-28T21:31:00.4488068+04:00","gmt_modified":"2026-04-28T21:31:00.4488068+04:00"},{"id":38682,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"6a050f797e4d75bb2867072fae629c2a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5281-5286","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38683,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"448218400a050ac2d3a0f1ee290faf50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#346-347","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38684,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"34550b8d6e01a13e99a0ed70072db86b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#1-355","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38685,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"9847129d410beb4256be18f2e7489d18","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#1-383","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38686,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"a3e6f8b4e51c838c44eaef16bb205031","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#1-573","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38687,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"53a676bf1df5198ba31b6ebe848a29bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#1-99","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38688,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"f14b0ce0c1ba142fb55271fdc6c2ee9f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#1-141","gmt_create":"2026-04-28T21:31:00.4498081+04:00","gmt_modified":"2026-04-28T21:31:00.4498081+04:00"},{"id":38689,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"f59f370133646ba0c40ebdd11ee6d697","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#1-114","gmt_create":"2026-04-28T21:31:00.4508077+04:00","gmt_modified":"2026-04-28T21:31:00.4508077+04:00"},{"id":38690,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"762c4b81ed454ad789c0b3b3cb00cc88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#1-85","gmt_create":"2026-04-28T21:31:00.4508077+04:00","gmt_modified":"2026-04-28T21:31:00.4508077+04:00"},{"id":38691,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"bc9b507990af077f95d7bbe7203d51f0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/config.hpp#1-106","gmt_create":"2026-04-28T21:31:00.4508077+04:00","gmt_modified":"2026-04-28T21:31:00.4508077+04:00"},{"id":38692,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b54da9d3dceb59e39a6cd88a5a99b593","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#1-742","gmt_create":"2026-04-28T21:31:00.4508077+04:00","gmt_modified":"2026-04-28T21:31:00.4508077+04:00"},{"id":38693,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"54ba2e42561f4bf9913449b2a78838bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#182-304","gmt_create":"2026-04-28T21:31:00.4508077+04:00","gmt_modified":"2026-04-28T21:31:00.4508077+04:00"},{"id":38694,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"94c69e0f6c696d5856c9a52b4dbcda00","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#780-790","gmt_create":"2026-04-28T21:31:00.4518063+04:00","gmt_modified":"2026-04-28T21:31:00.4518063+04:00"},{"id":38695,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"d6f1f5c1ab7e33b9a558f648113330fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#208-242","gmt_create":"2026-04-28T21:31:00.4518063+04:00","gmt_modified":"2026-04-28T21:31:00.4518063+04:00"},{"id":38696,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"db2f58e50720e139a95c598355919158","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#69-72","gmt_create":"2026-04-28T21:31:00.4518063+04:00","gmt_modified":"2026-04-28T21:31:00.4518063+04:00"},{"id":38697,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"a6b2b3362f68c7523a4e0d06a2a4352f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#424-799","gmt_create":"2026-04-28T21:31:00.4528077+04:00","gmt_modified":"2026-04-28T21:31:00.4528077+04:00"},{"id":38698,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"cd0a62c9a78bb77d3b59a9d5872577f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#82-106","gmt_create":"2026-04-28T21:31:00.4528077+04:00","gmt_modified":"2026-04-28T21:31:00.4528077+04:00"},{"id":38699,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"20359a9271432a216b6faf9dc97fa5c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#169-206","gmt_create":"2026-04-28T21:31:00.4528077+04:00","gmt_modified":"2026-04-28T21:31:00.4528077+04:00"},{"id":38700,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"fee43b750e5fa7d56e56ac6251e6b5bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#41-66","gmt_create":"2026-04-28T21:31:00.4528077+04:00","gmt_modified":"2026-04-28T21:31:00.4528077+04:00"},{"id":38701,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"25c0bdec5e0fb6c8d410577e1478ea78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#310-354","gmt_create":"2026-04-28T21:31:00.4538064+04:00","gmt_modified":"2026-04-28T21:31:00.4538064+04:00"},{"id":38702,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"e81b900c80dc9c266a93a66cc60486de","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/core_messages.cpp#30-49","gmt_create":"2026-04-28T21:31:00.4538064+04:00","gmt_modified":"2026-04-28T21:31:00.4538064+04:00"},{"id":38703,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"0b26d723a87937f5a3f58770c522d067","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#49-72","gmt_create":"2026-04-28T21:31:00.4538064+04:00","gmt_modified":"2026-04-28T21:31:00.4538064+04:00"},{"id":38704,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"d4b4e356cc64c1eac490f25138ad8337","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#132-177","gmt_create":"2026-04-28T21:31:00.4549933+04:00","gmt_modified":"2026-04-28T21:31:00.4549933+04:00"},{"id":38705,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b43af1b0b5dbbe32011b0ab877770800","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#49-177","gmt_create":"2026-04-28T21:31:00.4549933+04:00","gmt_modified":"2026-04-28T21:31:00.4549933+04:00"},{"id":38706,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"fd44e8ec8ed78651240bac55efcc1f20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_database.cpp#41-82","gmt_create":"2026-04-28T21:31:00.4549933+04:00","gmt_modified":"2026-04-28T21:31:00.4549933+04:00"},{"id":38707,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"ee53a7a714337d597cc0a626fceec27f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_database.cpp#100-174","gmt_create":"2026-04-28T21:31:00.4549933+04:00","gmt_modified":"2026-04-28T21:31:00.4549933+04:00"},{"id":38708,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"aae2609ed41db2a866f07ce766cbb938","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#70-105","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38709,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"023d67279bae7acc551e276826dc0ff1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3710-3723","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38710,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b7e9099b5e14dfe6396c0a1c5c308eb7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#312-381","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38711,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"26b49296ed2024fd0dde20e6f7e40b88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#383-420","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38712,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"41d27526c610abf125f7a7d008632585","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#173-179","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38713,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"868fa39acf5aeee17dc7a8161740807d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#4920-4970","gmt_create":"2026-04-28T21:31:00.4559944+04:00","gmt_modified":"2026-04-28T21:31:00.4559944+04:00"},{"id":38714,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"9814b4d33f73344843377eb1e1b063d8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5128-5131","gmt_create":"2026-04-28T21:31:00.4569941+04:00","gmt_modified":"2026-04-28T21:31:00.4569941+04:00"},{"id":38715,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"380d27e76ccd3471d37efe9e980c19ae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#322-346","gmt_create":"2026-04-28T21:31:00.4569941+04:00","gmt_modified":"2026-04-28T21:31:00.4569941+04:00"},{"id":38716,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"569091d2a8631dcfd98eaa50ae2bfc44","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#428-448","gmt_create":"2026-04-28T21:31:00.4569941+04:00","gmt_modified":"2026-04-28T21:31:00.4569941+04:00"},{"id":38717,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"1ed9d91d6dd0223209ee65abf9542242","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#4900-4970","gmt_create":"2026-04-28T21:31:00.4569941+04:00","gmt_modified":"2026-04-28T21:31:00.4569941+04:00"},{"id":38718,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b8d925dd432a091aeeb11648caa2eb44","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#4164-4168","gmt_create":"2026-04-28T21:31:00.4579934+04:00","gmt_modified":"2026-04-28T21:31:00.4579934+04:00"},{"id":38719,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"bf71a71910c5567123121789e437c062","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#298-304","gmt_create":"2026-04-28T21:31:00.4579934+04:00","gmt_modified":"2026-04-28T21:31:00.4579934+04:00"},{"id":38720,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"690241d99c53c94e7cfd1435215c90f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#616-618","gmt_create":"2026-04-28T21:31:00.4584972+04:00","gmt_modified":"2026-04-28T21:31:00.4584972+04:00"},{"id":38721,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"8df3a4b9e7bead2487cc1ffc6cd49cae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#16-19","gmt_create":"2026-04-28T21:31:00.4584972+04:00","gmt_modified":"2026-04-28T21:31:00.4584972+04:00"},{"id":38722,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"84d9f61aa92a7de46576a47f269a5dcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#169-171","gmt_create":"2026-04-28T21:31:00.4584972+04:00","gmt_modified":"2026-04-28T21:31:00.4584972+04:00"},{"id":38723,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"0be17f1ab260a4b3bcead7596649bfc6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#81-81","gmt_create":"2026-04-28T21:31:00.4584972+04:00","gmt_modified":"2026-04-28T21:31:00.4584972+04:00"},{"id":38724,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"271449375aea639d1f03a23e291eaea3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1187-1194","gmt_create":"2026-04-28T21:31:00.4584972+04:00","gmt_modified":"2026-04-28T21:31:00.4584972+04:00"},{"id":38725,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"14c432cf8aa5e9ce797534c3d40b187f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1200-1202","gmt_create":"2026-04-28T21:31:00.4595008+04:00","gmt_modified":"2026-04-28T21:31:00.4595008+04:00"},{"id":38726,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"c63bedc7eec5da82c3e0783176a7a564","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2651-2663","gmt_create":"2026-04-28T21:31:00.4596137+04:00","gmt_modified":"2026-04-28T21:31:00.4596137+04:00"},{"id":38727,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"95b247631c8b269b2a98c7e385bac407","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2772-2779","gmt_create":"2026-04-28T21:31:00.4596137+04:00","gmt_modified":"2026-04-28T21:31:00.4596137+04:00"},{"id":38728,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"e5fedb1d60d7f5a29bddbc403ff3d857","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2790-2796","gmt_create":"2026-04-28T21:31:00.4596137+04:00","gmt_modified":"2026-04-28T21:31:00.4596137+04:00"},{"id":38729,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b30577f67d2d7eafe760daf3f3f386b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#26-28","gmt_create":"2026-04-28T21:31:00.4596137+04:00","gmt_modified":"2026-04-28T21:31:00.4596137+04:00"},{"id":38730,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"8d12769b91a5f0a7c02fe172ecffd5ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#26-29","gmt_create":"2026-04-28T21:31:00.4596137+04:00","gmt_modified":"2026-04-28T21:31:00.4596137+04:00"},{"id":38731,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"b4c2646d470a9f4262288b71e7b10e89","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#26-28","gmt_create":"2026-04-28T21:31:00.4605058+04:00","gmt_modified":"2026-04-28T21:31:00.4605058+04:00"},{"id":38732,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"055bd4ac99dff0f7dad3d2d929f83b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#26-28","gmt_create":"2026-04-28T21:31:00.4605058+04:00","gmt_modified":"2026-04-28T21:31:00.4605058+04:00"},{"id":38733,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"eb6ddb4ecbe9eb87c395f2865107ea0e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#26-27","gmt_create":"2026-04-28T21:31:00.4605058+04:00","gmt_modified":"2026-04-28T21:31:00.4605058+04:00"},{"id":38734,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"660390a5b68b3f21fd886800f24fcc78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#39-45","gmt_create":"2026-04-28T21:31:00.461505+04:00","gmt_modified":"2026-04-28T21:31:00.461505+04:00"},{"id":38735,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"688ff5b9bf8ff49c734540b2a73a1251","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#288-298","gmt_create":"2026-04-28T21:31:00.461505+04:00","gmt_modified":"2026-04-28T21:31:00.461505+04:00"},{"id":38736,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"34e2f989664fd5eff332f3ac19b8b16e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#85-105","gmt_create":"2026-04-28T21:31:00.461505+04:00","gmt_modified":"2026-04-28T21:31:00.461505+04:00"},{"id":38806,"source_id":"724010bf-a048-4a08-bf63-fc4bcac656b4","target_id":"ed702015-695e-4ef5-87fc-be4645f73987","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 724010bf-a048-4a08-bf63-fc4bcac656b4 -\u003e ed702015-695e-4ef5-87fc-be4645f73987","gmt_create":"2026-04-28T21:34:21.0710176+04:00","gmt_modified":"2026-04-28T21:34:21.0710176+04:00"},{"id":38809,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"8908ad91-79b1-4190-aa7c-9a512f259dcb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e 8908ad91-79b1-4190-aa7c-9a512f259dcb","gmt_create":"2026-04-28T21:34:21.0780219+04:00","gmt_modified":"2026-04-28T21:34:21.0780219+04:00"},{"id":38810,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"446c4151-6374-4826-9947-cf5133b470cd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e 446c4151-6374-4826-9947-cf5133b470cd","gmt_create":"2026-04-28T21:34:21.0790228+04:00","gmt_modified":"2026-04-28T21:34:21.0790228+04:00"},{"id":38811,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"14f4dc36-feae-4d78-a12c-32f851999890","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e 14f4dc36-feae-4d78-a12c-32f851999890","gmt_create":"2026-04-28T21:34:21.0790228+04:00","gmt_modified":"2026-04-28T21:34:21.0790228+04:00"},{"id":38831,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"3758345d86110e6830e316917030c83c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6669","gmt_create":"2026-04-28T22:02:38.4781865+04:00","gmt_modified":"2026-04-28T22:02:38.4781865+04:00"},{"id":38852,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"73a54c033320ed8363fc781d798df0be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1420-1510","gmt_create":"2026-04-28T22:02:38.4841857+04:00","gmt_modified":"2026-04-28T22:02:38.4841857+04:00"},{"id":38854,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"21fa05f4a65dabefa29dcd9515e99399","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1432-1498","gmt_create":"2026-04-28T22:02:38.4841857+04:00","gmt_modified":"2026-04-28T22:02:38.4841857+04:00"},{"id":39013,"source_id":"1ccc033e927b7ba78550b64f23026d0b","target_id":"67ee60a8299f84cdefc03cf72aeb2083","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 177-215","gmt_create":"2026-04-28T22:07:49.3113859+04:00","gmt_modified":"2026-04-28T22:07:49.3113859+04:00"},{"id":39015,"source_id":"29a08e70168bdd56a054f1924f1f547c","target_id":"6b69ae0fdd0cccce913fc2d7aaa732b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 166-186","gmt_create":"2026-04-28T22:07:49.3142262+04:00","gmt_modified":"2026-04-28T22:07:49.3142262+04:00"},{"id":39017,"source_id":"5ba4c9dfb14a49e5bdc63880653930c6","target_id":"7df358ffe779de2ba25c910aced557fd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-46","gmt_create":"2026-04-28T22:07:49.3157395+04:00","gmt_modified":"2026-04-28T22:07:49.3157395+04:00"},{"id":39034,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"6fb08c879f27957a5d358cff4532c031","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1440-1500","gmt_create":"2026-04-28T22:07:49.3382713+04:00","gmt_modified":"2026-04-28T22:07:49.3382713+04:00"},{"id":39134,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"51b2088b237a2b23830a054ea53920ff","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5160-5196","gmt_create":"2026-04-28T22:30:12.9848422+04:00","gmt_modified":"2026-04-28T22:30:12.9848422+04:00"},{"id":39141,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"672cdc6d6a7b32cf5afabd6fdbce20d3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3540-3562","gmt_create":"2026-04-28T22:30:12.986345+04:00","gmt_modified":"2026-04-28T22:30:12.986345+04:00"},{"id":39143,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4c8e75baa374d11c9e8793b8772d0db9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3920-3940","gmt_create":"2026-04-28T22:30:12.9873482+04:00","gmt_modified":"2026-04-28T22:30:12.9873482+04:00"},{"id":39145,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"1170f10ffb0d10a348c893486b79ae55","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5501-5534","gmt_create":"2026-04-28T22:30:12.9873482+04:00","gmt_modified":"2026-04-28T22:30:12.9873482+04:00"},{"id":39147,"source_id":"18555f254f50536a15d8591acf982406","target_id":"a6bfdd40fb3a5836fbabdb5158fa34fe","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 103-108","gmt_create":"2026-04-28T22:30:12.9883482+04:00","gmt_modified":"2026-04-28T22:30:12.9883482+04:00"},{"id":39149,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"0eb11834610b569470f2b71aa759f15c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 276-283","gmt_create":"2026-04-28T22:30:12.9893481+04:00","gmt_modified":"2026-04-28T22:30:12.9893481+04:00"},{"id":39151,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"5a8c23e7fa97a43608f760d3dd4af004","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5281-5359","gmt_create":"2026-04-28T22:30:12.9893481+04:00","gmt_modified":"2026-04-28T22:30:12.9893481+04:00"},{"id":39153,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b4c0ee5e14c876c7ba33bc794823a9c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5181-5196","gmt_create":"2026-04-28T22:30:12.9893481+04:00","gmt_modified":"2026-04-28T22:30:12.9893481+04:00"},{"id":39155,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"65e89e734d42597ee19803d4235f8b40","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5139-5158","gmt_create":"2026-04-28T22:30:12.9893481+04:00","gmt_modified":"2026-04-28T22:30:12.9893481+04:00"},{"id":39164,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"ec345236fa256f6ac48c3f905522f12d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5166-5174","gmt_create":"2026-04-28T22:30:12.9923494+04:00","gmt_modified":"2026-04-28T22:30:12.9923494+04:00"},{"id":39166,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"5d28ce1f0b64958989a7799ef381c8d7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5163-5165","gmt_create":"2026-04-28T22:30:12.9923494+04:00","gmt_modified":"2026-04-28T22:30:12.9923494+04:00"},{"id":39168,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"7290ddf2f171b2a1565c4080ab334499","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5182-5187","gmt_create":"2026-04-28T22:30:12.9923494+04:00","gmt_modified":"2026-04-28T22:30:12.9923494+04:00"},{"id":39174,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"209759d869965a0c3eba1e658fa84845","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 633-689","gmt_create":"2026-04-28T22:30:12.9953495+04:00","gmt_modified":"2026-04-28T22:30:12.9953495+04:00"},{"id":39250,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"ba976b2f-ad3f-4c9c-bbde-af6e23216dbe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e ba976b2f-ad3f-4c9c-bbde-af6e23216dbe","gmt_create":"2026-04-28T22:34:00.955766+04:00","gmt_modified":"2026-04-28T22:34:00.955766+04:00"},{"id":39251,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"6c94b84fdfd5c7016b5eeadf8099133e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/plugin.cpp","gmt_create":"2026-04-29T06:59:11.2895379+04:00","gmt_modified":"2026-04-29T06:59:11.2895379+04:00"},{"id":39252,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"ae7188ee9396d8d8aca884b96e9bc4c1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/include/graphene/plugins/chain/plugin.hpp","gmt_create":"2026-04-29T06:59:11.2910629+04:00","gmt_modified":"2026-04-29T06:59:11.2910629+04:00"},{"id":39253,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39254,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"cb29035725926be38d36ad8c01792b7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database_exceptions.hpp","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39255,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39256,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"0e6f9014df8500eda2c1aa47cc9e4633","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/appbase/application.cpp","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39257,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"648e1d10af53280c425b922251db1464","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: README.md","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39258,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"4d5bf798ac6e167d6d0e20a669431373","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: documentation/snapshot-plugin.md","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39259,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"a53dc201b0a9ff736da577ae1c524abb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/log/console_appender.cpp","gmt_create":"2026-04-29T06:59:11.2920673+04:00","gmt_modified":"2026-04-29T06:59:11.2920673+04:00"},{"id":39260,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"455bdc0d380a2cbf0f62da93a6fe203d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/log/console_defines.h","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39261,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"d71a233c4690ddd107d80d74f5956ebf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/log/logger_config.cpp","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39262,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"fcabf234b34f00b60b0d784b2da5a052","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: programs/vizd/main.cpp","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39263,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"3d75047030281d13fb2d55905e0c69c8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#183-649","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39264,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"3d75047030281d13fb2d55905e0c69c8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 183-649","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39265,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"f75d35fc9523fc188eb18b8741e33f6d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#351-544","gmt_create":"2026-04-29T06:59:11.2931424+04:00","gmt_modified":"2026-04-29T06:59:11.2931424+04:00"},{"id":39266,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f75d35fc9523fc188eb18b8741e33f6d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 351-544","gmt_create":"2026-04-29T06:59:11.2946449+04:00","gmt_modified":"2026-04-29T06:59:11.2946449+04:00"},{"id":39267,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"22a0b873abfd87b49bc4ca088c641dcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#3031-3118","gmt_create":"2026-04-29T06:59:11.2952321+04:00","gmt_modified":"2026-04-29T06:59:11.2952321+04:00"},{"id":39268,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"22a0b873abfd87b49bc4ca088c641dcd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3031-3118","gmt_create":"2026-04-29T06:59:11.2952321+04:00","gmt_modified":"2026-04-29T06:59:11.2952321+04:00"},{"id":39269,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"2568823f5e70aacc0929c3200c44c688","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#1-694","gmt_create":"2026-04-29T06:59:11.2952321+04:00","gmt_modified":"2026-04-29T06:59:11.2952321+04:00"},{"id":39270,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"2568823f5e70aacc0929c3200c44c688","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-694","gmt_create":"2026-04-29T06:59:11.2961606+04:00","gmt_modified":"2026-04-29T06:59:11.2961606+04:00"},{"id":39271,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"7171e5fb841e1d5c8e4435a9e0e75f56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-6314","gmt_create":"2026-04-29T06:59:11.2961606+04:00","gmt_modified":"2026-04-29T06:59:11.2961606+04:00"},{"id":39272,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"7171e5fb841e1d5c8e4435a9e0e75f56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6314","gmt_create":"2026-04-29T06:59:11.2961606+04:00","gmt_modified":"2026-04-29T06:59:11.2961606+04:00"},{"id":39273,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"668e6362de53625901201e8370b90e80","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/include/graphene/plugins/chain/plugin.hpp#21-124","gmt_create":"2026-04-29T06:59:11.2971602+04:00","gmt_modified":"2026-04-29T06:59:11.2971602+04:00"},{"id":39274,"source_id":"ae7188ee9396d8d8aca884b96e9bc4c1","target_id":"668e6362de53625901201e8370b90e80","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-124","gmt_create":"2026-04-29T06:59:11.2971602+04:00","gmt_modified":"2026-04-29T06:59:11.2971602+04:00"},{"id":39275,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"86f066e47903bbd61b02a545ae4e6551","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#21-93","gmt_create":"2026-04-29T06:59:11.2971602+04:00","gmt_modified":"2026-04-29T06:59:11.2971602+04:00"},{"id":39276,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"86f066e47903bbd61b02a545ae4e6551","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-93","gmt_create":"2026-04-29T06:59:11.2971602+04:00","gmt_modified":"2026-04-29T06:59:11.2971602+04:00"},{"id":39277,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"9c28f276f937ea7573f48b90b8f92d7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#103-183","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39278,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"9c28f276f937ea7573f48b90b8f92d7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 103-183","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39279,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"89fd5aa6e93582e3684130e9c0920e33","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#438-544","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39280,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"371ae6e78ddcaea6c7ab821b81b12e35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#650-666","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39281,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"371ae6e78ddcaea6c7ab821b81b12e35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 650-666","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39282,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"13058dc3cfe4c9f00b04c9e22c6c9b70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#197-272","gmt_create":"2026-04-29T06:59:11.298161+04:00","gmt_modified":"2026-04-29T06:59:11.298161+04:00"},{"id":39283,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"13058dc3cfe4c9f00b04c9e22c6c9b70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 197-272","gmt_create":"2026-04-29T06:59:11.2996671+04:00","gmt_modified":"2026-04-29T06:59:11.2996671+04:00"},{"id":39284,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"16a421cb814c03e0297d814e4c7fcbcf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#274-386","gmt_create":"2026-04-29T06:59:11.3001825+04:00","gmt_modified":"2026-04-29T06:59:11.3001825+04:00"},{"id":39285,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"16a421cb814c03e0297d814e4c7fcbcf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 274-386","gmt_create":"2026-04-29T06:59:11.3001825+04:00","gmt_modified":"2026-04-29T06:59:11.3001825+04:00"},{"id":39286,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"e76a2e15b7d528b5eb96fad4fe23bd9c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#388-649","gmt_create":"2026-04-29T06:59:11.3001825+04:00","gmt_modified":"2026-04-29T06:59:11.3001825+04:00"},{"id":39287,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"e76a2e15b7d528b5eb96fad4fe23bd9c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 388-649","gmt_create":"2026-04-29T06:59:11.3001825+04:00","gmt_modified":"2026-04-29T06:59:11.3001825+04:00"},{"id":39288,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"2fa9c0e59e88a84f214e07f4a5eba712","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4253-4323","gmt_create":"2026-04-29T06:59:11.3011859+04:00","gmt_modified":"2026-04-29T06:59:11.3011859+04:00"},{"id":39289,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2fa9c0e59e88a84f214e07f4a5eba712","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4253-4323","gmt_create":"2026-04-29T06:59:11.3011859+04:00","gmt_modified":"2026-04-29T06:59:11.3011859+04:00"},{"id":39290,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"e9a71b0c283c28e9108702f7ca2163f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4314-4323","gmt_create":"2026-04-29T06:59:11.3021856+04:00","gmt_modified":"2026-04-29T06:59:11.3021856+04:00"},{"id":39291,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e9a71b0c283c28e9108702f7ca2163f7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4314-4323","gmt_create":"2026-04-29T06:59:11.3021856+04:00","gmt_modified":"2026-04-29T06:59:11.3021856+04:00"},{"id":39292,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"97ee13777a0aa5665ed9d742b01a6df1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#420-475","gmt_create":"2026-04-29T06:59:11.3031866+04:00","gmt_modified":"2026-04-29T06:59:11.3031866+04:00"},{"id":39293,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"97ee13777a0aa5665ed9d742b01a6df1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 420-475","gmt_create":"2026-04-29T06:59:11.3031866+04:00","gmt_modified":"2026-04-29T06:59:11.3031866+04:00"},{"id":39294,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"bd4c9ed516dc18cb55f239f6feab6a30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#3031-3042","gmt_create":"2026-04-29T06:59:11.3031866+04:00","gmt_modified":"2026-04-29T06:59:11.3031866+04:00"},{"id":39295,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"bd4c9ed516dc18cb55f239f6feab6a30","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3031-3042","gmt_create":"2026-04-29T06:59:11.3031866+04:00","gmt_modified":"2026-04-29T06:59:11.3031866+04:00"},{"id":39296,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"284384a88a8e22967e75aef3b6e3562e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#566-649","gmt_create":"2026-04-29T06:59:11.3041867+04:00","gmt_modified":"2026-04-29T06:59:11.3041867+04:00"},{"id":39297,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"284384a88a8e22967e75aef3b6e3562e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 566-649","gmt_create":"2026-04-29T06:59:11.3041867+04:00","gmt_modified":"2026-04-29T06:59:11.3041867+04:00"},{"id":39298,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"00e1ac390ce60cf05032160e029fc05c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#344-382","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39299,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"00e1ac390ce60cf05032160e029fc05c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 344-382","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39300,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"759a8a5afbc2bd120cc23c1a54071c79","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2817-2861","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39301,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"759a8a5afbc2bd120cc23c1a54071c79","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2817-2861","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39302,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"4370e8763bbca8a166f9af80993701e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2908-2920","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39303,"source_id":"c4447af409b7f3205a55e5b286557dfe","target_id":"4370e8763bbca8a166f9af80993701e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2908-2920","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39304,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"8c0eb1fd78ceb38fa43fd2a1b7f10412","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#105-121","gmt_create":"2026-04-29T06:59:11.3046915+04:00","gmt_modified":"2026-04-29T06:59:11.3046915+04:00"},{"id":39305,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"8c0eb1fd78ceb38fa43fd2a1b7f10412","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 105-121","gmt_create":"2026-04-29T06:59:11.3056967+04:00","gmt_modified":"2026-04-29T06:59:11.3056967+04:00"},{"id":39306,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"a4377fbb29614b9499ed7cba50185337","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/log/console_appender.cpp#71-84","gmt_create":"2026-04-29T06:59:11.306697+04:00","gmt_modified":"2026-04-29T06:59:11.306697+04:00"},{"id":39307,"source_id":"a53dc201b0a9ff736da577ae1c524abb","target_id":"a4377fbb29614b9499ed7cba50185337","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 71-84","gmt_create":"2026-04-29T06:59:11.306697+04:00","gmt_modified":"2026-04-29T06:59:11.306697+04:00"},{"id":39308,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"9d89f7774c243fa2dcd1a6b44f750558","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/log/console_defines.h#146-188","gmt_create":"2026-04-29T06:59:11.306697+04:00","gmt_modified":"2026-04-29T06:59:11.306697+04:00"},{"id":39309,"source_id":"455bdc0d380a2cbf0f62da93a6fe203d","target_id":"9d89f7774c243fa2dcd1a6b44f750558","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 146-188","gmt_create":"2026-04-29T06:59:11.3076955+04:00","gmt_modified":"2026-04-29T06:59:11.3076955+04:00"},{"id":39310,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"8a80f90958428689e890e5b0a8e84f60","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/log/logger_config.cpp#69-89","gmt_create":"2026-04-29T06:59:11.3076955+04:00","gmt_modified":"2026-04-29T06:59:11.3076955+04:00"},{"id":39311,"source_id":"d71a233c4690ddd107d80d74f5956ebf","target_id":"8a80f90958428689e890e5b0a8e84f60","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 69-89","gmt_create":"2026-04-29T06:59:11.3076955+04:00","gmt_modified":"2026-04-29T06:59:11.3076955+04:00"},{"id":39312,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"65bbe0fb033855becef1089d08ed50bf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/vizd/main.cpp#234-250","gmt_create":"2026-04-29T06:59:11.3086949+04:00","gmt_modified":"2026-04-29T06:59:11.3086949+04:00"},{"id":39313,"source_id":"fcabf234b34f00b60b0d784b2da5a052","target_id":"65bbe0fb033855becef1089d08ed50bf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 234-250","gmt_create":"2026-04-29T06:59:11.3086949+04:00","gmt_modified":"2026-04-29T06:59:11.3086949+04:00"},{"id":39314,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"37d1a2d00fcd56aea0848ebca3f2a926","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#757-816","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39315,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"37d1a2d00fcd56aea0848ebca3f2a926","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 757-816","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39316,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"621d366163e32d2a00e77366a0cca1ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#547-600","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39317,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"621d366163e32d2a00e77366a0cca1ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 547-600","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39318,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"be8f40bd072828763bbdf031b6f1620e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#122","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39319,"source_id":"cb29035725926be38d36ad8c01792b7e","target_id":"be8f40bd072828763bbdf031b6f1620e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 122","gmt_create":"2026-04-29T06:59:11.3102874+04:00","gmt_modified":"2026-04-29T06:59:11.3102874+04:00"},{"id":39320,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"db43b1af690cc5f915a6971cef72f698","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#1-12","gmt_create":"2026-04-29T06:59:11.3112909+04:00","gmt_modified":"2026-04-29T06:59:11.3112909+04:00"},{"id":39321,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"db43b1af690cc5f915a6971cef72f698","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-12","gmt_create":"2026-04-29T06:59:11.3112909+04:00","gmt_modified":"2026-04-29T06:59:11.3112909+04:00"},{"id":39322,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"ab61b06105c0618ce476f62fc42d04c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-10","gmt_create":"2026-04-29T06:59:11.3196209+04:00","gmt_modified":"2026-04-29T06:59:11.3196209+04:00"},{"id":39323,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"46d15c6ef6c17169ac51cbdc06ed7053","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/include/graphene/plugins/chain/plugin.hpp#23-24","gmt_create":"2026-04-29T06:59:11.32062+04:00","gmt_modified":"2026-04-29T06:59:11.32062+04:00"},{"id":39324,"source_id":"ae7188ee9396d8d8aca884b96e9bc4c1","target_id":"46d15c6ef6c17169ac51cbdc06ed7053","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-24","gmt_create":"2026-04-29T06:59:11.32062+04:00","gmt_modified":"2026-04-29T06:59:11.32062+04:00"},{"id":39325,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"2727250a5ed0225f9707859ab095dfe8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#92-105","gmt_create":"2026-04-29T06:59:11.3211231+04:00","gmt_modified":"2026-04-29T06:59:11.3211231+04:00"},{"id":39326,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"2727250a5ed0225f9707859ab095dfe8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 92-105","gmt_create":"2026-04-29T06:59:11.3211231+04:00","gmt_modified":"2026-04-29T06:59:11.3211231+04:00"},{"id":39327,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"9bf43751ce7ff4f9e6f159edc4314caf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#24-51","gmt_create":"2026-04-29T06:59:11.3211231+04:00","gmt_modified":"2026-04-29T06:59:11.3211231+04:00"},{"id":39328,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"9bf43751ce7ff4f9e6f159edc4314caf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-51","gmt_create":"2026-04-29T06:59:11.3211231+04:00","gmt_modified":"2026-04-29T06:59:11.3211231+04:00"},{"id":39329,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"0cd78f3f9caeaceed6acf82a3b374de0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#398-418","gmt_create":"2026-04-29T06:59:11.3216393+04:00","gmt_modified":"2026-04-29T06:59:11.3216393+04:00"},{"id":39330,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"0cd78f3f9caeaceed6acf82a3b374de0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 398-418","gmt_create":"2026-04-29T06:59:11.3216393+04:00","gmt_modified":"2026-04-29T06:59:11.3216393+04:00"},{"id":39331,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"c0c7e7261cd9841beac6c26b47f47cf6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#562-601","gmt_create":"2026-04-29T06:59:11.3221488+04:00","gmt_modified":"2026-04-29T06:59:11.3221488+04:00"},{"id":39332,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"c0c7e7261cd9841beac6c26b47f47cf6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 562-601","gmt_create":"2026-04-29T06:59:11.3221488+04:00","gmt_modified":"2026-04-29T06:59:11.3221488+04:00"},{"id":39333,"source_id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","target_id":"a8aa23bf7495e9cc8c7a2560a6157222","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#251-271","gmt_create":"2026-04-29T06:59:11.3221488+04:00","gmt_modified":"2026-04-29T06:59:11.3221488+04:00"},{"id":39334,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"a8aa23bf7495e9cc8c7a2560a6157222","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 251-271","gmt_create":"2026-04-29T06:59:11.3221488+04:00","gmt_modified":"2026-04-29T06:59:11.3221488+04:00"},{"id":39624,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a7270a78978a13ee55ddc7f94813e3df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1680-1693","gmt_create":"2026-04-29T07:04:36.8960015+04:00","gmt_modified":"2026-04-29T07:04:36.8960015+04:00"},{"id":39626,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"a7f5c35a309d6a9851c0491c125c63d9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3224-3236","gmt_create":"2026-04-29T07:04:36.8960015+04:00","gmt_modified":"2026-04-29T07:04:36.8960015+04:00"},{"id":39628,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2f5c46c8352dc73f0b90e01cef1bcc9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3272-3284","gmt_create":"2026-04-29T07:04:36.8970029+04:00","gmt_modified":"2026-04-29T07:04:36.8970029+04:00"},{"id":39630,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"26495d5b0fffb6fefe7f8c69d291521e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 738-742","gmt_create":"2026-04-29T07:04:36.8970029+04:00","gmt_modified":"2026-04-29T07:04:36.8970029+04:00"},{"id":39633,"source_id":"6c94b84fdfd5c7016b5eeadf8099133e","target_id":"3bdfaf9a009f1c5236532831eedfa66b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 760-770","gmt_create":"2026-04-29T07:04:36.8980042+04:00","gmt_modified":"2026-04-29T07:04:36.8980042+04:00"},{"id":39639,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"d21997e6-71b9-44d6-b43f-85770fe1e9dd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e d21997e6-71b9-44d6-b43f-85770fe1e9dd","gmt_create":"2026-04-29T07:04:37.6295296+04:00","gmt_modified":"2026-04-29T07:04:37.6295296+04:00"},{"id":39689,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"943ef4fb5df40c9942aadddd7040bc7c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4863-5004","gmt_create":"2026-04-29T22:58:12.6645298+04:00","gmt_modified":"2026-04-29T22:58:12.6645298+04:00"},{"id":39692,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"1273c494621ef1c9351fa8b783dc6ae6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 422-427","gmt_create":"2026-04-29T22:58:12.667034+04:00","gmt_modified":"2026-04-29T22:58:12.667034+04:00"},{"id":39695,"source_id":"ee77bf4eb6bfbfb3636aa0bd57416552","target_id":"cf67769b74f5699e4a347dc2d7092ceb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1097-1115","gmt_create":"2026-04-29T22:58:12.6690373+04:00","gmt_modified":"2026-04-29T22:58:12.6690373+04:00"},{"id":39702,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ffdc85ed129bbf1af13ac8fb289ef5cc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4887-4906","gmt_create":"2026-04-29T22:58:12.6720374+04:00","gmt_modified":"2026-04-29T22:58:12.6720374+04:00"},{"id":39704,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"0368dbe3efce9f73a7859fc98834220c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4907-4914","gmt_create":"2026-04-29T22:58:12.6745476+04:00","gmt_modified":"2026-04-29T22:58:12.6745476+04:00"},{"id":39706,"source_id":"73ada165e99c6ad5f938a94f11fb3e10","target_id":"90239aad5320ac7daf5e885e60b33925","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 261-263","gmt_create":"2026-04-29T22:58:12.6755451+04:00","gmt_modified":"2026-04-29T22:58:12.6755451+04:00"},{"id":39708,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"c1530ddb1ea5d36cd757849d7b1bae47","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2614-2631","gmt_create":"2026-04-29T22:58:12.678052+04:00","gmt_modified":"2026-04-29T22:58:12.678052+04:00"},{"id":39710,"source_id":"b4b9efd79d5b3c9fea00fccd613b2046","target_id":"e233bb5840d58fff00c516dfc7186b2f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 125-128","gmt_create":"2026-04-29T22:58:12.6790528+04:00","gmt_modified":"2026-04-29T22:58:12.6790528+04:00"},{"id":39713,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"d2f89808b761a3c0eca43468d945f372","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1721","gmt_create":"2026-04-29T22:58:12.6820519+04:00","gmt_modified":"2026-04-29T22:58:12.6820519+04:00"},{"id":39761,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"2b851e123aa78f2afb16a52472781e64","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 228-233","gmt_create":"2026-04-29T23:00:33.7910786+04:00","gmt_modified":"2026-04-29T23:00:33.7910786+04:00"},{"id":39778,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"0c5e33130a4b0128f85c5ef5837b2837","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 338-407","gmt_create":"2026-04-29T23:00:33.8068196+04:00","gmt_modified":"2026-04-29T23:00:33.8068196+04:00"},{"id":39780,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"b4b9171ebcdf9b3750b66cea688f5e6b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 411-419","gmt_create":"2026-04-29T23:00:33.8095439+04:00","gmt_modified":"2026-04-29T23:00:33.8095439+04:00"},{"id":39782,"source_id":"609365f8572668c8cf1e1cfa497989e4","target_id":"673f7fff8a03580c3caedc629fc67cd4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 60","gmt_create":"2026-04-29T23:00:33.8104885+04:00","gmt_modified":"2026-04-29T23:00:33.8104885+04:00"},{"id":39784,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"dbf1a067fe97d23702c1dcb8e2df53b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1890-1892","gmt_create":"2026-04-29T23:00:33.8115405+04:00","gmt_modified":"2026-04-29T23:00:33.8115405+04:00"},{"id":39786,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"2ad181689b70c433e1ec262fbbedb608","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4536-4573","gmt_create":"2026-04-29T23:00:33.8120693+04:00","gmt_modified":"2026-04-29T23:00:33.8120693+04:00"},{"id":39788,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"73337c954cb4cc654d9a0b55b95b2480","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5530-5655","gmt_create":"2026-04-29T23:00:33.8120693+04:00","gmt_modified":"2026-04-29T23:00:33.8120693+04:00"},{"id":39819,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"8c1b3bca4f56b317e9e0acdb4be83a00","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-89","gmt_create":"2026-04-29T23:01:32.3166187+04:00","gmt_modified":"2026-04-29T23:01:32.3166187+04:00"},{"id":39821,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"a3ae1dbcc1c9bd6ef59dec7fb6a6e6be","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-582","gmt_create":"2026-04-29T23:01:32.3181398+04:00","gmt_modified":"2026-04-29T23:01:32.3181398+04:00"},{"id":39830,"source_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","target_id":"445ddb5941dc16c8a6313b9ec556f75a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-89","gmt_create":"2026-04-29T23:01:32.3216473+04:00","gmt_modified":"2026-04-29T23:01:32.3216473+04:00"},{"id":39847,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"8d97625477363c05b9feab2d2cbb781b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 31-38","gmt_create":"2026-04-29T23:01:32.3281622+04:00","gmt_modified":"2026-04-29T23:01:32.3281622+04:00"},{"id":39849,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"1b89c3c75aec06d4b094f1f6692436f9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-66","gmt_create":"2026-04-29T23:01:32.3281622+04:00","gmt_modified":"2026-04-29T23:01:32.3281622+04:00"},{"id":39851,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"3f4e4b4d64c6750b34e1fe180b376017","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 119-136","gmt_create":"2026-04-29T23:01:32.3291615+04:00","gmt_modified":"2026-04-29T23:01:32.3291615+04:00"},{"id":39853,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"1853975a7087e8a5073352a9a8ea53c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 138-155","gmt_create":"2026-04-29T23:01:32.3291615+04:00","gmt_modified":"2026-04-29T23:01:32.3291615+04:00"},{"id":39860,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"23c70bfc8bc9d7d6ea64c01cbc8cfa74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 545-579","gmt_create":"2026-04-29T23:01:32.3311616+04:00","gmt_modified":"2026-04-29T23:01:32.3311616+04:00"},{"id":39862,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"57b5a41ba76b9bfcb250e93e89805515","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 761-765","gmt_create":"2026-04-29T23:01:32.3311616+04:00","gmt_modified":"2026-04-29T23:01:32.3311616+04:00"},{"id":39869,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"3397b02998da3d1df1abfc39e178cd35","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 74-100","gmt_create":"2026-04-29T23:01:32.3416718+04:00","gmt_modified":"2026-04-29T23:01:32.3416718+04:00"},{"id":39871,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"dfc65f88824f860423d799827fdee7aa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 545-574","gmt_create":"2026-04-29T23:01:32.3416718+04:00","gmt_modified":"2026-04-29T23:01:32.3416718+04:00"},{"id":39873,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"443c70bf08a7229603f07d4b6e2ceb04","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 304-369","gmt_create":"2026-04-29T23:01:32.3426911+04:00","gmt_modified":"2026-04-29T23:01:32.3426911+04:00"},{"id":39919,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"766ad50513305c2c4955788de08b2f70","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 757-765","gmt_create":"2026-04-29T23:01:32.3551881+04:00","gmt_modified":"2026-04-29T23:01:32.3551881+04:00"},{"id":39946,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"61447f1b270e050eaf1594622e8344cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 303-357","gmt_create":"2026-04-30T07:13:19.6681094+04:00","gmt_modified":"2026-04-30T07:13:19.6681094+04:00"},{"id":39948,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"87460891e469970ebd1b4357e65a305d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2561-2591","gmt_create":"2026-04-30T07:13:19.6686216+04:00","gmt_modified":"2026-04-30T07:13:19.6686216+04:00"},{"id":39950,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e8bcacd1aeb9acccff2e7846bdb418ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2596-2612","gmt_create":"2026-04-30T07:13:19.6696503+04:00","gmt_modified":"2026-04-30T07:13:19.6696503+04:00"},{"id":39954,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"3addab2306735a8fd2b97c7337a752aa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5473-5545","gmt_create":"2026-04-30T07:13:19.6701689+04:00","gmt_modified":"2026-04-30T07:13:19.6701689+04:00"},{"id":39956,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"cf15af9ccdfa43fad1c61be4c143bb9f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5515-5529","gmt_create":"2026-04-30T07:13:19.67068+04:00","gmt_modified":"2026-04-30T07:13:19.67068+04:00"},{"id":40058,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40059,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40060,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40061,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40062,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"4238a9561f85e50a38f76813baeadd7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/block_log.hpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40063,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40064,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40065,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40066,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T07:19:20.4378901+04:00","gmt_modified":"2026-04-30T07:19:20.4378901+04:00"},{"id":40067,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"b4b9efd79d5b3c9fea00fccd613b2046","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config.hpp","gmt_create":"2026-04-30T07:19:20.4388898+04:00","gmt_modified":"2026-04-30T07:19:20.4388898+04:00"},{"id":40068,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"8ede002b6c76d0a07d75e34f812e8305","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/hardfork.d/12.hf","gmt_create":"2026-04-30T07:19:20.4388898+04:00","gmt_modified":"2026-04-30T07:19:20.4388898+04:00"},{"id":40069,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"4e999921565c672e1c3f31f949a25803","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#128-150","gmt_create":"2026-04-30T07:19:20.4388898+04:00","gmt_modified":"2026-04-30T07:19:20.4388898+04:00"},{"id":40070,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"4e999921565c672e1c3f31f949a25803","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 128-150","gmt_create":"2026-04-30T07:19:20.4388898+04:00","gmt_modified":"2026-04-30T07:19:20.4388898+04:00"},{"id":40071,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"3c48450ddf4126f562a2691715c15905","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#80-87","gmt_create":"2026-04-30T07:19:20.4388898+04:00","gmt_modified":"2026-04-30T07:19:20.4388898+04:00"},{"id":40072,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"509be78f5e90ad720bc5cb62f8252773","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1204-1270","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40073,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"2f228d36a18a021f1d730c1fa50466da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#739-760","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40074,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"2f228d36a18a021f1d730c1fa50466da","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 739-760","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40075,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"2f3627b50fb7b7e496ab7f3d82bb011c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#521-544","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40076,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"da0076fc30299f9f1dd09e50dc181609","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#1-168","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40077,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"da0076fc30299f9f1dd09e50dc181609","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-168","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40078,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"d599d8eb734647e07f075785246b447f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#1-278","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40079,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"2426f410a167c0334267f66a00c3b706","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#1-200","gmt_create":"2026-04-30T07:19:20.4398905+04:00","gmt_modified":"2026-04-30T07:19:20.4398905+04:00"},{"id":40080,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"3758345d86110e6830e316917030c83c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-6669","gmt_create":"2026-04-30T07:19:20.440891+04:00","gmt_modified":"2026-04-30T07:19:20.440891+04:00"},{"id":40081,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"6ebf29a038d578e8864ca6c9c9366bda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#1-76","gmt_create":"2026-04-30T07:19:20.440891+04:00","gmt_modified":"2026-04-30T07:19:20.440891+04:00"},{"id":40082,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"620825701e1a1b114e822bbda1ceb234","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#1-454","gmt_create":"2026-04-30T07:19:20.440891+04:00","gmt_modified":"2026-04-30T07:19:20.440891+04:00"},{"id":40083,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"13ad0bfb014506790d3eea0ac1e240eb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#1-697","gmt_create":"2026-04-30T07:19:20.440891+04:00","gmt_modified":"2026-04-30T07:19:20.440891+04:00"},{"id":40084,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"24e9e8b3ff6a7469a09e87e94f9832b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#735-771","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40085,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"24e9e8b3ff6a7469a09e87e94f9832b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 735-771","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40086,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"adbfa85db79875fa5ba5450da427c626","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#110-124","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40087,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"9f5944a7feb01c0c201e4a490c1c6d47","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/hardfork.d/12.hf#1-7","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40088,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"532021a3aea4c3d7bfe25231df5687c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#53-168","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40089,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"532021a3aea4c3d7bfe25231df5687c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 53-168","gmt_create":"2026-04-30T07:19:20.4418907+04:00","gmt_modified":"2026-04-30T07:19:20.4418907+04:00"},{"id":40090,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"3697c4125ef62ecb76b9032b46a67ad2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#33-92","gmt_create":"2026-04-30T07:19:20.4429759+04:00","gmt_modified":"2026-04-30T07:19:20.4429759+04:00"},{"id":40091,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"62ea8f0eed608d8eb1dd0911e43f28c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1223-1267","gmt_create":"2026-04-30T07:19:20.4429759+04:00","gmt_modified":"2026-04-30T07:19:20.4429759+04:00"},{"id":40092,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"35d8d0314587b8714a154437fe7243af","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#13-33","gmt_create":"2026-04-30T07:19:20.4429759+04:00","gmt_modified":"2026-04-30T07:19:20.4429759+04:00"},{"id":40093,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"01b277ebba52e972b94566a19ab057fd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#336-340","gmt_create":"2026-04-30T07:19:20.4439765+04:00","gmt_modified":"2026-04-30T07:19:20.4439765+04:00"},{"id":40094,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"3ae8431619379889035afee8a7f98a96","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1300-1399","gmt_create":"2026-04-30T07:19:20.4439765+04:00","gmt_modified":"2026-04-30T07:19:20.4439765+04:00"},{"id":40095,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"4dbf49507663ef2d477a4e56e7ad4113","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#48-84","gmt_create":"2026-04-30T07:19:20.4449764+04:00","gmt_modified":"2026-04-30T07:19:20.4449764+04:00"},{"id":40096,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"a0f13c35d9ba18928ea0803560d59338","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#48-55","gmt_create":"2026-04-30T07:19:20.4449764+04:00","gmt_modified":"2026-04-30T07:19:20.4449764+04:00"},{"id":40097,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"32f0435e4c1faa3d0978c1dcac09d7ce","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#20-168","gmt_create":"2026-04-30T07:19:20.4449764+04:00","gmt_modified":"2026-04-30T07:19:20.4449764+04:00"},{"id":40098,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"32f0435e4c1faa3d0978c1dcac09d7ce","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-168","gmt_create":"2026-04-30T07:19:20.4449764+04:00","gmt_modified":"2026-04-30T07:19:20.4449764+04:00"},{"id":40099,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"78b7d2f924e066f18e5bf4ed42de6954","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#33-278","gmt_create":"2026-04-30T07:19:20.4459761+04:00","gmt_modified":"2026-04-30T07:19:20.4459761+04:00"},{"id":40100,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"de96a3aab8e8260a79d1b9c380481b26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#111-168","gmt_create":"2026-04-30T07:19:20.4459761+04:00","gmt_modified":"2026-04-30T07:19:20.4459761+04:00"},{"id":40101,"source_id":"75b9bb8cfd2db41c21f328241d191f32","target_id":"de96a3aab8e8260a79d1b9c380481b26","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 111-168","gmt_create":"2026-04-30T07:19:20.4459761+04:00","gmt_modified":"2026-04-30T07:19:20.4459761+04:00"},{"id":40102,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"95e9eb6df5c5b54fc25131e15cebca7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#269-274","gmt_create":"2026-04-30T07:19:20.4470111+04:00","gmt_modified":"2026-04-30T07:19:20.4470111+04:00"},{"id":40103,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"f32c5cb0846168684a2574ccb17d2cd7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#189-231","gmt_create":"2026-04-30T07:19:20.4470111+04:00","gmt_modified":"2026-04-30T07:19:20.4470111+04:00"},{"id":40104,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"7066405016bb2acea5a040cdac13b646","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1037-1177","gmt_create":"2026-04-30T07:19:20.4470111+04:00","gmt_modified":"2026-04-30T07:19:20.4470111+04:00"},{"id":40105,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"73a54c033320ed8363fc781d798df0be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1420-1510","gmt_create":"2026-04-30T07:19:20.4470111+04:00","gmt_modified":"2026-04-30T07:19:20.4470111+04:00"},{"id":40106,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"21fa05f4a65dabefa29dcd9515e99399","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1432-1498","gmt_create":"2026-04-30T07:19:20.4480121+04:00","gmt_modified":"2026-04-30T07:19:20.4480121+04:00"},{"id":40107,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"1c914e70d8a846e0ed416af007bd2b78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#259-294","gmt_create":"2026-04-30T07:19:20.4480121+04:00","gmt_modified":"2026-04-30T07:19:20.4480121+04:00"},{"id":40108,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"e24259987d3c50dee1a87e13d63ccf03","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#57-78","gmt_create":"2026-04-30T07:19:20.4480121+04:00","gmt_modified":"2026-04-30T07:19:20.4480121+04:00"},{"id":40109,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"d2b082cb10acf9968b8eb975d61abc92","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4444-4533","gmt_create":"2026-04-30T07:19:20.4480121+04:00","gmt_modified":"2026-04-30T07:19:20.4480121+04:00"},{"id":40110,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"6742da18bac301be1056c8e6e5adcf69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#35-72","gmt_create":"2026-04-30T07:19:20.4480121+04:00","gmt_modified":"2026-04-30T07:19:20.4480121+04:00"},{"id":40111,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"da4792d808b920542e8e3f85c533f97d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#118-164","gmt_create":"2026-04-30T07:19:20.4490112+04:00","gmt_modified":"2026-04-30T07:19:20.4490112+04:00"},{"id":40112,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"fb711bedba071dd61482af3dd825bb98","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#115-128","gmt_create":"2026-04-30T07:19:20.4490112+04:00","gmt_modified":"2026-04-30T07:19:20.4490112+04:00"},{"id":40113,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"83d7c3cd276c8b6c3a77f6379e8968e4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#561-580","gmt_create":"2026-04-30T07:19:20.4490112+04:00","gmt_modified":"2026-04-30T07:19:20.4490112+04:00"},{"id":40114,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"420ba4d931c9392dd8824c0faaf3b99b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#738-792","gmt_create":"2026-04-30T07:19:20.4490112+04:00","gmt_modified":"2026-04-30T07:19:20.4490112+04:00"},{"id":40115,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"fc699eb749d790d44345a92dd356956e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#206-230","gmt_create":"2026-04-30T07:19:20.4490112+04:00","gmt_modified":"2026-04-30T07:19:20.4490112+04:00"},{"id":40116,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"217f231a3e1f1591acfb14f4b40fb2b3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#476-515","gmt_create":"2026-04-30T07:19:20.4500189+04:00","gmt_modified":"2026-04-30T07:19:20.4500189+04:00"},{"id":40117,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"b25bd7f79844225b0a1356e5a6dbee8b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#92-103","gmt_create":"2026-04-30T07:19:20.4500189+04:00","gmt_modified":"2026-04-30T07:19:20.4500189+04:00"},{"id":40118,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"447323529866a4410bcb34a227ea5b5a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1075-1087","gmt_create":"2026-04-30T07:19:20.4500189+04:00","gmt_modified":"2026-04-30T07:19:20.4500189+04:00"},{"id":40119,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"d59a4116db64f54b5d2ce9c64e1c2c50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4581-4594","gmt_create":"2026-04-30T07:19:20.4500189+04:00","gmt_modified":"2026-04-30T07:19:20.4500189+04:00"},{"id":40120,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"98ed598d82d28fa1553560148bcda24e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2125-2142","gmt_create":"2026-04-30T07:19:20.4510137+04:00","gmt_modified":"2026-04-30T07:19:20.4510137+04:00"},{"id":40121,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"aa98d4cf2cd33ba5c1e2a0fee44c3645","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#597-612","gmt_create":"2026-04-30T07:19:20.4510137+04:00","gmt_modified":"2026-04-30T07:19:20.4510137+04:00"},{"id":40122,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"a8acea32ccb60d16cf2952aa7df51926","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4334-4438","gmt_create":"2026-04-30T07:19:20.4510137+04:00","gmt_modified":"2026-04-30T07:19:20.4510137+04:00"},{"id":40123,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"cda8d76def01f28cd58e347939faf10a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4420-4438","gmt_create":"2026-04-30T07:19:20.4510137+04:00","gmt_modified":"2026-04-30T07:19:20.4510137+04:00"},{"id":40124,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"119ec7c643a34aa808f9d5b76965a662","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4444-4450","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40125,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"02a1a9fcc78ccfc4daf328d04696eb6f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#114-124","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40126,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"9d352185df5c8af06a8101e30a248ef8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4360-4398","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40127,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"315cdb5412a417207b9932317c120c97","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4400-4419","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40128,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"450f29f1b3febed1e121639037851576","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#521-526","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40129,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"17c7b337a56de7a5cd94cd10c3d44dac","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4428-4430","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40130,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"48593fdf91cfb9e4763322dc0efe26f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#565-656","gmt_create":"2026-04-30T07:19:20.4520126+04:00","gmt_modified":"2026-04-30T07:19:20.4520126+04:00"},{"id":40131,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"b71278e4b4266bb8a15b6aba152b2962","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#121","gmt_create":"2026-04-30T07:19:20.4533619+04:00","gmt_modified":"2026-04-30T07:19:20.4533619+04:00"},{"id":40132,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"065d68f5f096b48e88dfb2982a30bcb6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#114-146","gmt_create":"2026-04-30T07:19:20.4543635+04:00","gmt_modified":"2026-04-30T07:19:20.4543635+04:00"},{"id":40133,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"cde5dc8aa90fe3ae3c802f8d7f235e74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#762-770","gmt_create":"2026-04-30T07:19:20.4553613+04:00","gmt_modified":"2026-04-30T07:19:20.4553613+04:00"},{"id":40134,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"cde5dc8aa90fe3ae3c802f8d7f235e74","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 762-770","gmt_create":"2026-04-30T07:19:20.4553613+04:00","gmt_modified":"2026-04-30T07:19:20.4553613+04:00"},{"id":40135,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"51d09407b23ce3234d4e1de6142dce78","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#739-771","gmt_create":"2026-04-30T07:19:20.4553613+04:00","gmt_modified":"2026-04-30T07:19:20.4553613+04:00"},{"id":40136,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"51d09407b23ce3234d4e1de6142dce78","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 739-771","gmt_create":"2026-04-30T07:19:20.4563617+04:00","gmt_modified":"2026-04-30T07:19:20.4563617+04:00"},{"id":40137,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"732bc579d5f86ebf0e986ecfbdfa490d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#34-46","gmt_create":"2026-04-30T07:19:20.4573626+04:00","gmt_modified":"2026-04-30T07:19:20.4573626+04:00"},{"id":40138,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"c2ea6047c89205fb8308a32ce5248eee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#48-103","gmt_create":"2026-04-30T07:19:20.4583616+04:00","gmt_modified":"2026-04-30T07:19:20.4583616+04:00"},{"id":40139,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"811ab9cb3d00924a080202c009434d6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1254-1298","gmt_create":"2026-04-30T07:19:20.4583616+04:00","gmt_modified":"2026-04-30T07:19:20.4583616+04:00"},{"id":40140,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"33f7190f97ab910175bbc25c0d3288cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#38-46","gmt_create":"2026-04-30T07:19:20.4593614+04:00","gmt_modified":"2026-04-30T07:19:20.4593614+04:00"},{"id":40141,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"536ce91c592f598c4853f295a9a28e59","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#59-75","gmt_create":"2026-04-30T07:19:20.4593614+04:00","gmt_modified":"2026-04-30T07:19:20.4593614+04:00"},{"id":40142,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"49ed36643f75c3d722e6b1a2ff17d7e0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1390-1465","gmt_create":"2026-04-30T07:19:20.4603602+04:00","gmt_modified":"2026-04-30T07:19:20.4603602+04:00"},{"id":40143,"source_id":"0227cdb3-c369-47eb-9251-d897b9181340","target_id":"58d38a217f74656ded3587bd3c6f7dc1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#614-646","gmt_create":"2026-04-30T07:19:20.4603602+04:00","gmt_modified":"2026-04-30T07:19:20.4603602+04:00"},{"id":40144,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-30T07:20:23.8055558+04:00","gmt_modified":"2026-04-30T07:20:23.8055558+04:00"},{"id":40145,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-30T07:20:23.8055558+04:00","gmt_modified":"2026-04-30T07:20:23.8055558+04:00"},{"id":40146,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"d72b348a2c3c7943e4a7abb7dbdaa751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_connection.hpp","gmt_create":"2026-04-30T07:20:23.8055558+04:00","gmt_modified":"2026-04-30T07:20:23.8055558+04:00"},{"id":40147,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/peer_connection.cpp","gmt_create":"2026-04-30T07:20:23.8060738+04:00","gmt_modified":"2026-04-30T07:20:23.8060738+04:00"},{"id":40148,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"3a8d8a10556a0b6501e25aa43e91f913","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_database.hpp","gmt_create":"2026-04-30T07:20:23.8060738+04:00","gmt_modified":"2026-04-30T07:20:23.8060738+04:00"},{"id":40149,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b4467ca30cb6f6d587fc200900ee9ec9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message.hpp","gmt_create":"2026-04-30T07:20:23.8060738+04:00","gmt_modified":"2026-04-30T07:20:23.8060738+04:00"},{"id":40150,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"c82262dc5275e094efc9474032d15922","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/config.hpp","gmt_create":"2026-04-30T07:20:23.8060738+04:00","gmt_modified":"2026-04-30T07:20:23.8060738+04:00"},{"id":40151,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"3a6c30f4bb3b265155c881ccfafa980e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/core_messages.hpp","gmt_create":"2026-04-30T07:20:23.8060738+04:00","gmt_modified":"2026-04-30T07:20:23.8060738+04:00"},{"id":40152,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"3948eb588d15d01acf21ffd439ec508c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/exceptions.hpp","gmt_create":"2026-04-30T07:20:23.8065903+04:00","gmt_modified":"2026-04-30T07:20:23.8065903+04:00"},{"id":40153,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"398d9d4b02b6383c0b752cb0196a0475","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/stcp_socket.hpp","gmt_create":"2026-04-30T07:20:23.8065903+04:00","gmt_modified":"2026-04-30T07:20:23.8065903+04:00"},{"id":40154,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"6e587b97bf4080c7754c5ed73736fca7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message_oriented_connection.hpp","gmt_create":"2026-04-30T07:20:23.8065903+04:00","gmt_modified":"2026-04-30T07:20:23.8065903+04:00"},{"id":40155,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-30T07:20:23.8065903+04:00","gmt_modified":"2026-04-30T07:20:23.8065903+04:00"},{"id":40156,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40157,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40158,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b4b9efd79d5b3c9fea00fccd613b2046","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config.hpp","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40159,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40160,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40161,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40162,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b1416c15172aac5cdff13f12c0d385b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#180-355","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40163,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b2e1954ed604c23c3fe69090870838ec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#869-905","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40164,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"f85f57d0c6b461ab78f906ef6d5854c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#79-354","gmt_create":"2026-04-30T07:20:23.8071051+04:00","gmt_modified":"2026-04-30T07:20:23.8071051+04:00"},{"id":40165,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"45d31a7a748eda3ea48f7df17810d4cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#419-448","gmt_create":"2026-04-30T07:20:23.8081084+04:00","gmt_modified":"2026-04-30T07:20:23.8081084+04:00"},{"id":40166,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"45d31a7a748eda3ea48f7df17810d4cb","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 419-448","gmt_create":"2026-04-30T07:20:23.8081084+04:00","gmt_modified":"2026-04-30T07:20:23.8081084+04:00"},{"id":40167,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"7b85de17d00c3c33f3e6ce72493cea24","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#104-134","gmt_create":"2026-04-30T07:20:23.8081084+04:00","gmt_modified":"2026-04-30T07:20:23.8081084+04:00"},{"id":40168,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4a47af89ac294fea1a93e8ab87bc62a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#42-114","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40169,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"fcf5471e2941c73aa4796f0d15ca9d4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#111-120","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40170,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"1d8a3a8529f55f725cbd52ef78db6a1f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4334-4463","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40171,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"7d072be9a3f767f13a99da4cd6df4783","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#110-123","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40172,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4f55b43e070bade6f117e02d6faaaac2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#368-379","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40173,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"5b2dac9b59c644b7b47e991af481e627","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#330-360","gmt_create":"2026-04-30T07:20:23.8096649+04:00","gmt_modified":"2026-04-30T07:20:23.8096649+04:00"},{"id":40174,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"d9910f1ea9014fede12810a52c49c4a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#952-1047","gmt_create":"2026-04-30T07:20:23.8116686+04:00","gmt_modified":"2026-04-30T07:20:23.8116686+04:00"},{"id":40175,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"2d0f35d8035d544c59943ce9488d042e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1623-1654","gmt_create":"2026-04-30T07:20:23.8116686+04:00","gmt_modified":"2026-04-30T07:20:23.8116686+04:00"},{"id":40176,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4cb233e3e08980c2c2c76e7762ad457b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2282-2350","gmt_create":"2026-04-30T07:20:23.8116686+04:00","gmt_modified":"2026-04-30T07:20:23.8116686+04:00"},{"id":40177,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"465b6e48aad6641d48e75039b1ba6cf7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#869-931","gmt_create":"2026-04-30T07:20:23.8116686+04:00","gmt_modified":"2026-04-30T07:20:23.8116686+04:00"},{"id":40178,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b06d8268387488f1ba89995b6c673d7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1805-1865","gmt_create":"2026-04-30T07:20:23.8116686+04:00","gmt_modified":"2026-04-30T07:20:23.8116686+04:00"},{"id":40179,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"b06d8268387488f1ba89995b6c673d7f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1805-1865","gmt_create":"2026-04-30T07:20:23.8126692+04:00","gmt_modified":"2026-04-30T07:20:23.8126692+04:00"},{"id":40180,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"d1aff9a930eaeb19127cc400cd6df14b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5281-5320","gmt_create":"2026-04-30T07:20:23.8126692+04:00","gmt_modified":"2026-04-30T07:20:23.8126692+04:00"},{"id":40181,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"d1aff9a930eaeb19127cc400cd6df14b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5281-5320","gmt_create":"2026-04-30T07:20:23.8126692+04:00","gmt_modified":"2026-04-30T07:20:23.8126692+04:00"},{"id":40182,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4f2bc001f6d8d7b016c08476699c545c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3396-3475","gmt_create":"2026-04-30T07:20:23.8126692+04:00","gmt_modified":"2026-04-30T07:20:23.8126692+04:00"},{"id":40183,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"4f2bc001f6d8d7b016c08476699c545c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3396-3475","gmt_create":"2026-04-30T07:20:23.8139658+04:00","gmt_modified":"2026-04-30T07:20:23.8139658+04:00"},{"id":40184,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"a3ff28e788c1b6c8bf86034c0dc8dfec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3280-3351","gmt_create":"2026-04-30T07:20:23.8139658+04:00","gmt_modified":"2026-04-30T07:20:23.8139658+04:00"},{"id":40185,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"a3ff28e788c1b6c8bf86034c0dc8dfec","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3280-3351","gmt_create":"2026-04-30T07:20:23.8139658+04:00","gmt_modified":"2026-04-30T07:20:23.8139658+04:00"},{"id":40186,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"fa40cce63b48435566df6c01e8048d9f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#428-448","gmt_create":"2026-04-30T07:20:23.8139658+04:00","gmt_modified":"2026-04-30T07:20:23.8139658+04:00"},{"id":40187,"source_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","target_id":"fa40cce63b48435566df6c01e8048d9f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 428-448","gmt_create":"2026-04-30T07:20:23.8149652+04:00","gmt_modified":"2026-04-30T07:20:23.8149652+04:00"},{"id":40188,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"1029e6d2173388f17be8ad02924bec51","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5321-5351","gmt_create":"2026-04-30T07:20:23.8149652+04:00","gmt_modified":"2026-04-30T07:20:23.8149652+04:00"},{"id":40189,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"1029e6d2173388f17be8ad02924bec51","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5321-5351","gmt_create":"2026-04-30T07:20:23.8149652+04:00","gmt_modified":"2026-04-30T07:20:23.8149652+04:00"},{"id":40190,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"9448259d344c27f9c6996ae60cf5aca0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#276-298","gmt_create":"2026-04-30T07:20:23.8149652+04:00","gmt_modified":"2026-04-30T07:20:23.8149652+04:00"},{"id":40191,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"9448259d344c27f9c6996ae60cf5aca0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 276-298","gmt_create":"2026-04-30T07:20:23.8149652+04:00","gmt_modified":"2026-04-30T07:20:23.8149652+04:00"},{"id":40192,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"64eac8af7d3939075658361c76c2a7f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2029-2230","gmt_create":"2026-04-30T07:20:23.8159649+04:00","gmt_modified":"2026-04-30T07:20:23.8159649+04:00"},{"id":40193,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"63a72fb69b4b837d5841f87d654e6835","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2232-2250","gmt_create":"2026-04-30T07:20:23.8159649+04:00","gmt_modified":"2026-04-30T07:20:23.8159649+04:00"},{"id":40194,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"7d1df83c34f12b0c857fb327e688236b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1400-1621","gmt_create":"2026-04-30T07:20:23.816965+04:00","gmt_modified":"2026-04-30T07:20:23.816965+04:00"},{"id":40195,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"3497c413bfbe054ece4588e4c9764e38","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#79-80","gmt_create":"2026-04-30T07:20:23.816965+04:00","gmt_modified":"2026-04-30T07:20:23.816965+04:00"},{"id":40196,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"832f176e5f919dc138e93f3d848899bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3117-3199","gmt_create":"2026-04-30T07:20:23.8179692+04:00","gmt_modified":"2026-04-30T07:20:23.8179692+04:00"},{"id":40197,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"d93f64e1090b7fb0448056ce453003b2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#200-294","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40198,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"8422adca0104a424dd0293e0e0b74399","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#933-950","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40199,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"f88975c9b8df22394830934bbd2b8fec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1686-1713","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40200,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"140ecf3fedde255af2f0a4ce07a0edaa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#211-296","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40201,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"2a546861a7d7c1c0f13a5e81a60a2663","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1788-1841","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40202,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"e9dd01a70c4ccc4eff5ea6c67ea751d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1326-1398","gmt_create":"2026-04-30T07:20:23.8184785+04:00","gmt_modified":"2026-04-30T07:20:23.8184785+04:00"},{"id":40203,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"e396600c03187cea5577399428a6bc7a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2830-2892","gmt_create":"2026-04-30T07:20:23.8194878+04:00","gmt_modified":"2026-04-30T07:20:23.8194878+04:00"},{"id":40204,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4d84381505174d8f3190a51bf7d50f11","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#111-217","gmt_create":"2026-04-30T07:20:23.8194878+04:00","gmt_modified":"2026-04-30T07:20:23.8194878+04:00"},{"id":40205,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"6e13c0b7bd5f1729508c365e49c421e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3413-3428","gmt_create":"2026-04-30T07:20:23.8204849+04:00","gmt_modified":"2026-04-30T07:20:23.8204849+04:00"},{"id":40206,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"6e13c0b7bd5f1729508c365e49c421e2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3413-3428","gmt_create":"2026-04-30T07:20:23.8204849+04:00","gmt_modified":"2026-04-30T07:20:23.8204849+04:00"},{"id":40207,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"50f93c7183f911eb73a238f8bcc6a562","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3355-3394","gmt_create":"2026-04-30T07:20:23.8204849+04:00","gmt_modified":"2026-04-30T07:20:23.8204849+04:00"},{"id":40208,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"50f93c7183f911eb73a238f8bcc6a562","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3355-3394","gmt_create":"2026-04-30T07:20:23.8204849+04:00","gmt_modified":"2026-04-30T07:20:23.8204849+04:00"},{"id":40209,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"90fd78bbe7cb7704cadf5d5f0735cb01","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3334-3351","gmt_create":"2026-04-30T07:20:23.8214833+04:00","gmt_modified":"2026-04-30T07:20:23.8214833+04:00"},{"id":40210,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"90fd78bbe7cb7704cadf5d5f0735cb01","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 3334-3351","gmt_create":"2026-04-30T07:20:23.8214833+04:00","gmt_modified":"2026-04-30T07:20:23.8214833+04:00"},{"id":40211,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"d9e91362d84f2e5c27205bacead0d8e5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2251-2280","gmt_create":"2026-04-30T07:20:23.8214833+04:00","gmt_modified":"2026-04-30T07:20:23.8214833+04:00"},{"id":40212,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"b0c24aab481fd56f8134b091b5bf0525","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2137-2168","gmt_create":"2026-04-30T07:20:23.8214833+04:00","gmt_modified":"2026-04-30T07:20:23.8214833+04:00"},{"id":40213,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"731063774f04d46e1f2c0d64963dfe33","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4455-4460","gmt_create":"2026-04-30T07:20:23.8229769+04:00","gmt_modified":"2026-04-30T07:20:23.8229769+04:00"},{"id":40214,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"209759d869965a0c3eba1e658fa84845","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#633-689","gmt_create":"2026-04-30T07:20:23.8229769+04:00","gmt_modified":"2026-04-30T07:20:23.8229769+04:00"},{"id":40215,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"672cdc6d6a7b32cf5afabd6fdbce20d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3540-3562","gmt_create":"2026-04-30T07:20:23.8229769+04:00","gmt_modified":"2026-04-30T07:20:23.8229769+04:00"},{"id":40216,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"4c8e75baa374d11c9e8793b8772d0db9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3920-3940","gmt_create":"2026-04-30T07:20:23.8229769+04:00","gmt_modified":"2026-04-30T07:20:23.8229769+04:00"},{"id":40217,"source_id":"9dfed239-6d34-405d-a774-0a99f673e816","target_id":"a6bfdd40fb3a5836fbabdb5158fa34fe","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config.ini#103-108","gmt_create":"2026-04-30T07:20:23.8229769+04:00","gmt_modified":"2026-04-30T07:20:23.8229769+04:00"},{"id":40267,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"3926b37345d6d1e98bd8faf06e492e48","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 722-771","gmt_create":"2026-04-30T07:26:56.3700198+04:00","gmt_modified":"2026-04-30T07:26:56.3700198+04:00"},{"id":40315,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"f00d25f601ba380af2e6c7e1cc5c9bd5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-6760","gmt_create":"2026-04-30T07:30:11.8225633+04:00","gmt_modified":"2026-04-30T07:30:11.8225633+04:00"},{"id":40337,"source_id":"cb10d0f5bb9015fb9ce5f22b75c10fed","target_id":"02d86b87b26250b29b6e613abead3df4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-78","gmt_create":"2026-04-30T07:30:11.8283385+04:00","gmt_modified":"2026-04-30T07:30:11.8283385+04:00"},{"id":40347,"source_id":"cb10d0f5bb9015fb9ce5f22b75c10fed","target_id":"b730f8795ffebcda8a8f085fd025dc0b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-78","gmt_create":"2026-04-30T07:30:11.8328416+04:00","gmt_modified":"2026-04-30T07:30:11.8328416+04:00"},{"id":40397,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"67e81d60b5109e19786b8bfbc4a80abd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2281-2283","gmt_create":"2026-04-30T07:30:11.8585167+04:00","gmt_modified":"2026-04-30T07:30:11.8585167+04:00"},{"id":40399,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"09f8b4a6f66776095afcdc7473efbaf2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2466-2467","gmt_create":"2026-04-30T07:30:11.8585167+04:00","gmt_modified":"2026-04-30T07:30:11.8585167+04:00"},{"id":40401,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"9a263f97b2eae42c0e192fb1cfee8776","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2526-2527","gmt_create":"2026-04-30T07:30:11.8595163+04:00","gmt_modified":"2026-04-30T07:30:11.8595163+04:00"},{"id":40403,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"ea9495482bd4ecf48df793f9abf39cc1","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2536-2537","gmt_create":"2026-04-30T07:30:11.8595163+04:00","gmt_modified":"2026-04-30T07:30:11.8595163+04:00"},{"id":40405,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"47d651650f297dcd4ffcf47ee28027f2","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4536-4537","gmt_create":"2026-04-30T07:30:11.8605162+04:00","gmt_modified":"2026-04-30T07:30:11.8605162+04:00"},{"id":40407,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5452e208808a1bd3d416cced7e6d6f0a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4538-4539","gmt_create":"2026-04-30T07:30:11.8605162+04:00","gmt_modified":"2026-04-30T07:30:11.8605162+04:00"},{"id":40409,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"5affc96a80f081a4ef8bd4b5177ef1a8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4544-4545","gmt_create":"2026-04-30T07:30:11.8605162+04:00","gmt_modified":"2026-04-30T07:30:11.8605162+04:00"},{"id":40411,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"dd981f6523bfe5386b3d4a97ca575fdf","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4567-4568","gmt_create":"2026-04-30T07:30:11.8615165+04:00","gmt_modified":"2026-04-30T07:30:11.8615165+04:00"},{"id":40413,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e0ef3c7d489444d0a7bf6cd609a98c05","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4569-4570","gmt_create":"2026-04-30T07:30:11.8615165+04:00","gmt_modified":"2026-04-30T07:30:11.8615165+04:00"},{"id":40415,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"13ee871790dddd2f670c1493c6665f41","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4571-4572","gmt_create":"2026-04-30T07:30:11.8615165+04:00","gmt_modified":"2026-04-30T07:30:11.8615165+04:00"},{"id":40417,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"90331ddec7a3725739758ff2180d5b8e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4573-4574","gmt_create":"2026-04-30T07:30:11.8626158+04:00","gmt_modified":"2026-04-30T07:30:11.8626158+04:00"},{"id":40419,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"654c2896a03be742e37554a614a0244c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5530-5531","gmt_create":"2026-04-30T07:30:11.8626158+04:00","gmt_modified":"2026-04-30T07:30:11.8626158+04:00"},{"id":40421,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"e9e61fd4b1cf8706755eb1dfa541ccc7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5543-5544","gmt_create":"2026-04-30T07:30:11.8626158+04:00","gmt_modified":"2026-04-30T07:30:11.8626158+04:00"},{"id":40423,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"b7aaa429e07e8abc0d4999c4c496d854","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5677-5678","gmt_create":"2026-04-30T07:30:11.8626158+04:00","gmt_modified":"2026-04-30T07:30:11.8626158+04:00"},{"id":40425,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"1f43be6f2eea9de96bd24d20b575c860","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5680-5681","gmt_create":"2026-04-30T07:30:11.8626158+04:00","gmt_modified":"2026-04-30T07:30:11.8626158+04:00"},{"id":40427,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"d9dbf24fcc1a502e794d92f729bcd372","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 159-160","gmt_create":"2026-04-30T07:30:11.863616+04:00","gmt_modified":"2026-04-30T07:30:11.863616+04:00"},{"id":40430,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"abeb5e992b22812a0cdfc0c3dca91067","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 338-340","gmt_create":"2026-04-30T07:30:11.863616+04:00","gmt_modified":"2026-04-30T07:30:11.863616+04:00"},{"id":40432,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"956e60e52272d2047c3d89d0f1fe96a3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 356-357","gmt_create":"2026-04-30T07:30:11.863616+04:00","gmt_modified":"2026-04-30T07:30:11.863616+04:00"},{"id":40434,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"70499ce1f567f2564154072ea2576c3b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 403-405","gmt_create":"2026-04-30T07:30:11.863616+04:00","gmt_modified":"2026-04-30T07:30:11.863616+04:00"},{"id":40436,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"aad86469ecab79c7481892069f6100df","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 411-412","gmt_create":"2026-04-30T07:30:11.8646163+04:00","gmt_modified":"2026-04-30T07:30:11.8646163+04:00"},{"id":40438,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"57d63528cfa5d7410afabeee4a42845e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 416-417","gmt_create":"2026-04-30T07:30:11.8646163+04:00","gmt_modified":"2026-04-30T07:30:11.8646163+04:00"},{"id":40440,"source_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","target_id":"daa5dca768a6e2ed062d953de56c3dc6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 418-419","gmt_create":"2026-04-30T07:30:11.8646163+04:00","gmt_modified":"2026-04-30T07:30:11.8646163+04:00"},{"id":40442,"source_id":"cb10d0f5bb9015fb9ce5f22b75c10fed","target_id":"f0fa917f2268095d00a5c33920129393","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 48-78","gmt_create":"2026-04-30T07:30:11.8646163+04:00","gmt_modified":"2026-04-30T07:30:11.8646163+04:00"},{"id":40462,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"0227cdb3-c369-47eb-9251-d897b9181340","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 0227cdb3-c369-47eb-9251-d897b9181340","gmt_create":"2026-04-30T07:30:12.4924554+04:00","gmt_modified":"2026-04-30T07:30:12.4924554+04:00"},{"id":40463,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"9dfed239-6d34-405d-a774-0a99f673e816","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e 9dfed239-6d34-405d-a774-0a99f673e816","gmt_create":"2026-04-30T07:30:12.4945148+04:00","gmt_modified":"2026-04-30T07:30:12.4945148+04:00"},{"id":40509,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"b372b2c20cc0d9d9abd9e2254bfefb17","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 576-602","gmt_create":"2026-04-30T07:46:04.9554747+04:00","gmt_modified":"2026-04-30T07:46:04.9554747+04:00"},{"id":40615,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"a1ef6908e910771a074aa8ccbc10adef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 773-795","gmt_create":"2026-04-30T07:47:41.3416854+04:00","gmt_modified":"2026-04-30T07:47:41.3416854+04:00"},{"id":40638,"source_id":"18555f254f50536a15d8591acf982406","target_id":"463f1a4ea4700713bc6ca4afa0c86f4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-143","gmt_create":"2026-04-30T07:47:41.3533333+04:00","gmt_modified":"2026-04-30T07:47:41.3533333+04:00"},{"id":40639,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T08:00:09.9239373+04:00","gmt_modified":"2026-04-30T08:00:09.9239373+04:00"},{"id":40640,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T08:00:09.9249344+04:00","gmt_modified":"2026-04-30T08:00:09.9249344+04:00"},{"id":40641,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ee77bf4eb6bfbfb3636aa0bd57416552","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/include/chainbase/chainbase.hpp","gmt_create":"2026-04-30T08:00:09.9249344+04:00","gmt_modified":"2026-04-30T08:00:09.9249344+04:00"},{"id":40642,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1ade3cebbc11a4634bcdf1a7fdb2756e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/src/chainbase.cpp","gmt_create":"2026-04-30T08:00:09.9249344+04:00","gmt_modified":"2026-04-30T08:00:09.9249344+04:00"},{"id":40643,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"4238a9561f85e50a38f76813baeadd7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/block_log.hpp","gmt_create":"2026-04-30T08:00:09.9307197+04:00","gmt_modified":"2026-04-30T08:00:09.9307197+04:00"},{"id":40644,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"d2090ff9016be0d896d06e843936e0f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/block_log.cpp","gmt_create":"2026-04-30T08:00:09.931604+04:00","gmt_modified":"2026-04-30T08:00:09.931604+04:00"},{"id":40645,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-30T08:00:09.9326076+04:00","gmt_modified":"2026-04-30T08:00:09.9326076+04:00"},{"id":40646,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T08:00:09.9326076+04:00","gmt_modified":"2026-04-30T08:00:09.9326076+04:00"},{"id":40647,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-30T08:00:09.9326076+04:00","gmt_modified":"2026-04-30T08:00:09.9326076+04:00"},{"id":40648,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40649,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"cb29035725926be38d36ad8c01792b7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database_exceptions.hpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40650,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40651,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"57e07111ef7b80720c419255780e7ece","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/db_with.hpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40652,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40653,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"0dd2a38630da83b11fb3596ad4d60705","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/include/graphene/plugins/witness/witness.hpp","gmt_create":"2026-04-30T08:00:09.9336054+04:00","gmt_modified":"2026-04-30T08:00:09.9336054+04:00"},{"id":40654,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b4b9efd79d5b3c9fea00fccd613b2046","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config.hpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40655,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40656,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"3948eb588d15d01acf21ffd439ec508c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/exceptions.hpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40657,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40658,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1ccc033e927b7ba78550b64f23026d0b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/include/fc/exception/exception.hpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40659,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"29a08e70168bdd56a054f1924f1f547c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/exception.cpp","gmt_create":"2026-04-30T08:00:09.9346027+04:00","gmt_modified":"2026-04-30T08:00:09.9346027+04:00"},{"id":40660,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5ba4c9dfb14a49e5bdc63880653930c6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/exceptions.hpp","gmt_create":"2026-04-30T08:00:09.9356026+04:00","gmt_modified":"2026-04-30T08:00:09.9356026+04:00"},{"id":40661,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"cb10d0f5bb9015fb9ce5f22b75c10fed","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/stacktrace.cpp","gmt_create":"2026-04-30T08:00:09.9356026+04:00","gmt_modified":"2026-04-30T08:00:09.9356026+04:00"},{"id":40662,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T08:00:09.9356026+04:00","gmt_modified":"2026-04-30T08:00:09.9356026+04:00"},{"id":40663,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"95da2daaa0065c2230410221cb5b5dbd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#1-670","gmt_create":"2026-04-30T08:00:09.9356026+04:00","gmt_modified":"2026-04-30T08:00:09.9356026+04:00"},{"id":40664,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"f00d25f601ba380af2e6c7e1cc5c9bd5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-6760","gmt_create":"2026-04-30T08:00:09.9366048+04:00","gmt_modified":"2026-04-30T08:00:09.9366048+04:00"},{"id":40665,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2ad3ade1c893ee16ff7640c396428e46","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/include/chainbase/chainbase.hpp#1078-1120","gmt_create":"2026-04-30T08:00:09.9371112+04:00","gmt_modified":"2026-04-30T08:00:09.9371112+04:00"},{"id":40666,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"27490494b39fa9968667b183f60e215a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/src/chainbase.cpp#1-200","gmt_create":"2026-04-30T08:00:09.9371112+04:00","gmt_modified":"2026-04-30T08:00:09.9371112+04:00"},{"id":40667,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2c17018b7a7ecf1dd7b6432e97d0a586","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#1-75","gmt_create":"2026-04-30T08:00:09.9371112+04:00","gmt_modified":"2026-04-30T08:00:09.9371112+04:00"},{"id":40668,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"fef8201a8783aa794440fbd2f9b1ff17","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#1-302","gmt_create":"2026-04-30T08:00:09.9381172+04:00","gmt_modified":"2026-04-30T08:00:09.9381172+04:00"},{"id":40669,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"86991432e69878d08cc76b9d386b7d8f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#1-80","gmt_create":"2026-04-30T08:00:09.9381172+04:00","gmt_modified":"2026-04-30T08:00:09.9381172+04:00"},{"id":40670,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"cdc31aad39121f507723919db7d70dee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#1-476","gmt_create":"2026-04-30T08:00:09.9381172+04:00","gmt_modified":"2026-04-30T08:00:09.9381172+04:00"},{"id":40671,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"590d1dfeeb49a4029c52d3c49b2f0362","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#1-144","gmt_create":"2026-04-30T08:00:09.9381172+04:00","gmt_modified":"2026-04-30T08:00:09.9381172+04:00"},{"id":40672,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"d599d8eb734647e07f075785246b447f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#1-278","gmt_create":"2026-04-30T08:00:09.9381172+04:00","gmt_modified":"2026-04-30T08:00:09.9381172+04:00"},{"id":40673,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ba99a3c0ac8bffedf50f03f7f8a09c06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#1-136","gmt_create":"2026-04-30T08:00:09.9391252+04:00","gmt_modified":"2026-04-30T08:00:09.9391252+04:00"},{"id":40674,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"0397697ee2095dedcc01fa148c7079b9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/db_with.hpp#1-154","gmt_create":"2026-04-30T08:00:09.9391252+04:00","gmt_modified":"2026-04-30T08:00:09.9391252+04:00"},{"id":40675,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b2901b8a7a24569b4a61c38b4448db06","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1180-1379","gmt_create":"2026-04-30T08:00:09.9391252+04:00","gmt_modified":"2026-04-30T08:00:09.9391252+04:00"},{"id":40676,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"77520f9eb913c04b5230e07f8f3f4ef8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#270-469","gmt_create":"2026-04-30T08:00:09.9391252+04:00","gmt_modified":"2026-04-30T08:00:09.9391252+04:00"},{"id":40677,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"340636e744f71de65b91146c5b8a20bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#38-73","gmt_create":"2026-04-30T08:00:09.9391252+04:00","gmt_modified":"2026-04-30T08:00:09.9391252+04:00"},{"id":40678,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"c05f511b950fdae3b96260134880f8e4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#111-118","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40679,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"101205728a0401f1dc07b5e31abe4b30","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3185-3384","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40680,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"832619f974a664566d9bae6712c5e6a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/exceptions.hpp#27-48","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40681,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"8939bbbd6e1bb4a18e6bb534a037d0b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#225-424","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40682,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"67ee60a8299f84cdefc03cf72aeb2083","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/include/fc/exception/exception.hpp#177-215","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40683,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6b69ae0fdd0cccce913fc2d7aaa732b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/exception.cpp#166-186","gmt_create":"2026-04-30T08:00:09.940122+04:00","gmt_modified":"2026-04-30T08:00:09.940122+04:00"},{"id":40684,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"7df358ffe779de2ba25c910aced557fd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/exceptions.hpp#21-46","gmt_create":"2026-04-30T08:00:09.9411218+04:00","gmt_modified":"2026-04-30T08:00:09.9411218+04:00"},{"id":40685,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"02d86b87b26250b29b6e613abead3df4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/stacktrace.cpp#1-78","gmt_create":"2026-04-30T08:00:09.9411218+04:00","gmt_modified":"2026-04-30T08:00:09.9411218+04:00"},{"id":40686,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b437e864a36924899b70d6b9295e4ac0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#61-115","gmt_create":"2026-04-30T08:00:09.943629+04:00","gmt_modified":"2026-04-30T08:00:09.943629+04:00"},{"id":40687,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"476cdc272b600cf1a7bfe2b524767872","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#281-324","gmt_create":"2026-04-30T08:00:09.943629+04:00","gmt_modified":"2026-04-30T08:00:09.943629+04:00"},{"id":40688,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5c73e14f98ff45ef03bb3a7c9e413218","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/block_log.hpp#38-75","gmt_create":"2026-04-30T08:00:09.943629+04:00","gmt_modified":"2026-04-30T08:00:09.943629+04:00"},{"id":40689,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6742da18bac301be1056c8e6e5adcf69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#35-72","gmt_create":"2026-04-30T08:00:09.943629+04:00","gmt_modified":"2026-04-30T08:00:09.943629+04:00"},{"id":40690,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"268918c988500bd0972ad80cef38bdd3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#53-144","gmt_create":"2026-04-30T08:00:09.9446302+04:00","gmt_modified":"2026-04-30T08:00:09.9446302+04:00"},{"id":40691,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6d7b6e4198a348bc27c0bb28230cb3f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#929-984","gmt_create":"2026-04-30T08:00:09.9446302+04:00","gmt_modified":"2026-04-30T08:00:09.9446302+04:00"},{"id":40692,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"186fa6ce927d55c0b153413a2981237e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/db_with.hpp#33-100","gmt_create":"2026-04-30T08:00:09.9446302+04:00","gmt_modified":"2026-04-30T08:00:09.9446302+04:00"},{"id":40693,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"99a2db97d03705f31a3929010634a458","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/src/chainbase.cpp#225-279","gmt_create":"2026-04-30T08:00:09.9446302+04:00","gmt_modified":"2026-04-30T08:00:09.9446302+04:00"},{"id":40694,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b730f8795ffebcda8a8f085fd025dc0b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/stacktrace.cpp#72-78","gmt_create":"2026-04-30T08:00:09.9456313+04:00","gmt_modified":"2026-04-30T08:00:09.9456313+04:00"},{"id":40695,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"30a9101c41868617ba6f2a2daa15b849","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#94-184","gmt_create":"2026-04-30T08:00:09.9456313+04:00","gmt_modified":"2026-04-30T08:00:09.9456313+04:00"},{"id":40696,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"3e02993eaec7af3cec0bfb1f83a665d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#83","gmt_create":"2026-04-30T08:00:09.9466291+04:00","gmt_modified":"2026-04-30T08:00:09.9466291+04:00"},{"id":40697,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"be8f40bd072828763bbdf031b6f1620e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#122","gmt_create":"2026-04-30T08:00:09.9466291+04:00","gmt_modified":"2026-04-30T08:00:09.9466291+04:00"},{"id":40698,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"99f54a4b93eefbb48ed1667eff0fa9d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#330-410","gmt_create":"2026-04-30T08:00:09.9466291+04:00","gmt_modified":"2026-04-30T08:00:09.9466291+04:00"},{"id":40699,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"408bde042901c8590a87dffdf56f7b44","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#134-184","gmt_create":"2026-04-30T08:00:09.9476287+04:00","gmt_modified":"2026-04-30T08:00:09.9476287+04:00"},{"id":40700,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e69115f35f4572b29fb65e977de046e0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#503-519","gmt_create":"2026-04-30T08:00:09.9476287+04:00","gmt_modified":"2026-04-30T08:00:09.9476287+04:00"},{"id":40701,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"732bc579d5f86ebf0e986ecfbdfa490d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#34-46","gmt_create":"2026-04-30T08:00:09.9491337+04:00","gmt_modified":"2026-04-30T08:00:09.9491337+04:00"},{"id":40702,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"27593eff1e7989c53fb119e30b38a106","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#81-88","gmt_create":"2026-04-30T08:00:09.9491337+04:00","gmt_modified":"2026-04-30T08:00:09.9491337+04:00"},{"id":40703,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6fb08c879f27957a5d358cff4532c031","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1440-1500","gmt_create":"2026-04-30T08:00:09.9491337+04:00","gmt_modified":"2026-04-30T08:00:09.9491337+04:00"},{"id":40704,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"42f304cea32d3254d3d28d390f99a4f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1216-1286","gmt_create":"2026-04-30T08:00:09.9491337+04:00","gmt_modified":"2026-04-30T08:00:09.9491337+04:00"},{"id":40705,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"4c7480a472e5a837a77edfce9accd782","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1360-1380","gmt_create":"2026-04-30T08:00:09.9501373+04:00","gmt_modified":"2026-04-30T08:00:09.9501373+04:00"},{"id":40706,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"21021513e3f47136fbd9b77f25ac0dda","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#175-192","gmt_create":"2026-04-30T08:00:09.9501373+04:00","gmt_modified":"2026-04-30T08:00:09.9501373+04:00"},{"id":40707,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"978bc8c4cf93eea58a5004412f5a0740","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3192-3211","gmt_create":"2026-04-30T08:00:09.9501373+04:00","gmt_modified":"2026-04-30T08:00:09.9501373+04:00"},{"id":40708,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"9a7186666130ca998f114a82a0decdff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#181-196","gmt_create":"2026-04-30T08:00:09.9511373+04:00","gmt_modified":"2026-04-30T08:00:09.9511373+04:00"},{"id":40709,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ac1d251c502e1e4341518133a47346b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1556-1588","gmt_create":"2026-04-30T08:00:09.9511373+04:00","gmt_modified":"2026-04-30T08:00:09.9511373+04:00"},{"id":40710,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"03c29e794349e78edd559069a4ea589f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1593-1594","gmt_create":"2026-04-30T08:00:09.9511373+04:00","gmt_modified":"2026-04-30T08:00:09.9511373+04:00"},{"id":40711,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"bc5ca04bd394cfbe05b91187be1ef3e1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#271-300","gmt_create":"2026-04-30T08:00:09.9511373+04:00","gmt_modified":"2026-04-30T08:00:09.9511373+04:00"},{"id":40712,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"32c3cd87cb292dbfecb6d81dc0fc6739","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#506-507","gmt_create":"2026-04-30T08:00:09.9521397+04:00","gmt_modified":"2026-04-30T08:00:09.9521397+04:00"},{"id":40713,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ba68b0a6c770e5eb7e9c206147e04add","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#232-243","gmt_create":"2026-04-30T08:00:09.9521397+04:00","gmt_modified":"2026-04-30T08:00:09.9521397+04:00"},{"id":40714,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"a0ef31a365b500c015295fa0a77cb02a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#639-673","gmt_create":"2026-04-30T08:00:09.9521397+04:00","gmt_modified":"2026-04-30T08:00:09.9521397+04:00"},{"id":40715,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"bad0cf5ac8c5e25ab7697c72386f0c6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#562-605","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40716,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"145b14d90766df6ec3acffdb3b52a1a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#412-422","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40717,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5ae77d32160a48045d586a25c4949703","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#454-482","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40718,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"fb42540947b6b7d56487ccd9ec782f86","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#148-164","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40719,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"4eb8ce2a423658c16ae4df90aeba2184","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#546-556","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40720,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"0172b0ea2a031177f1c72341a3922614","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#631-632","gmt_create":"2026-04-30T08:00:09.9531401+04:00","gmt_modified":"2026-04-30T08:00:09.9531401+04:00"},{"id":40721,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e8dd15ab10626a2ce715fe8c3f03ca85","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1106-1145","gmt_create":"2026-04-30T08:00:09.954648+04:00","gmt_modified":"2026-04-30T08:00:09.954648+04:00"},{"id":40722,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"8509be38b1ab9f14d108445df0dcd2f1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1460-1470","gmt_create":"2026-04-30T08:00:09.954648+04:00","gmt_modified":"2026-04-30T08:00:09.954648+04:00"},{"id":40723,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"d1e1e1bc28ff1dfbd77617edbf4a23b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1295-1377","gmt_create":"2026-04-30T08:00:09.955652+04:00","gmt_modified":"2026-04-30T08:00:09.955652+04:00"},{"id":40724,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"929cc0269a5814a951b45c3300f44597","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#789-827","gmt_create":"2026-04-30T08:00:09.955652+04:00","gmt_modified":"2026-04-30T08:00:09.955652+04:00"},{"id":40725,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5e4bd94274850728b00115526a2479ee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#860-882","gmt_create":"2026-04-30T08:00:09.955652+04:00","gmt_modified":"2026-04-30T08:00:09.955652+04:00"},{"id":40726,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"c53a6db24cea4db25b30783459c40125","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#884-901","gmt_create":"2026-04-30T08:00:09.955652+04:00","gmt_modified":"2026-04-30T08:00:09.955652+04:00"},{"id":40727,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6abfbb22aee54a4b386173dfc74da72b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5452-5482","gmt_create":"2026-04-30T08:00:09.9566529+04:00","gmt_modified":"2026-04-30T08:00:09.9566529+04:00"},{"id":40728,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2ba1e391be7a79f5151c8abeb655315d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5467-5480","gmt_create":"2026-04-30T08:00:09.9566529+04:00","gmt_modified":"2026-04-30T08:00:09.9566529+04:00"},{"id":40729,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"17b75751a836de13af2093485914a80b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1147-1202","gmt_create":"2026-04-30T08:00:09.9566529+04:00","gmt_modified":"2026-04-30T08:00:09.9566529+04:00"},{"id":40730,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"3fd79dc7253b83f3fd4a1db36b691537","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#79-96","gmt_create":"2026-04-30T08:00:09.9566529+04:00","gmt_modified":"2026-04-30T08:00:09.9566529+04:00"},{"id":40731,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"fc817fa1448591c306f1d8c94a4912b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#340-350","gmt_create":"2026-04-30T08:00:09.9576523+04:00","gmt_modified":"2026-04-30T08:00:09.9576523+04:00"},{"id":40732,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2b22b083099e12af5fb5eff69ac7c45b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4346-4366","gmt_create":"2026-04-30T08:00:09.9576523+04:00","gmt_modified":"2026-04-30T08:00:09.9576523+04:00"},{"id":40733,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ad0c51e89fbda89a4c7ba4a8b1c23f6e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#948-970","gmt_create":"2026-04-30T08:00:09.9576523+04:00","gmt_modified":"2026-04-30T08:00:09.9576523+04:00"},{"id":40734,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1bc38fc420c17ebaaf14eb62dd9dd77e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3652-3711","gmt_create":"2026-04-30T08:00:09.9576523+04:00","gmt_modified":"2026-04-30T08:00:09.9576523+04:00"},{"id":40735,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"bf868153550f3b995f99ef4e396ddd77","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3444-3499","gmt_create":"2026-04-30T08:00:09.9576523+04:00","gmt_modified":"2026-04-30T08:00:09.9576523+04:00"},{"id":40736,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e5c1c7808f2985bb68bc174eb390298a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#218-224","gmt_create":"2026-04-30T08:00:09.9586524+04:00","gmt_modified":"2026-04-30T08:00:09.9586524+04:00"},{"id":40737,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1198bd7cc69669237a261463e8cd3c9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3986-4039","gmt_create":"2026-04-30T08:00:09.9586524+04:00","gmt_modified":"2026-04-30T08:00:09.9586524+04:00"},{"id":40738,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"a8eaae161939961c892a4e5ff9b1b68f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4144-4175","gmt_create":"2026-04-30T08:00:09.9586524+04:00","gmt_modified":"2026-04-30T08:00:09.9586524+04:00"},{"id":40739,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e6c849182922d3df412daeb900b9e173","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#284-307","gmt_create":"2026-04-30T08:00:09.9597938+04:00","gmt_modified":"2026-04-30T08:00:09.9597938+04:00"},{"id":40740,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"05db694a94704c3e51ed70ce0118a1da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1158-1198","gmt_create":"2026-04-30T08:00:09.9597938+04:00","gmt_modified":"2026-04-30T08:00:09.9597938+04:00"},{"id":40741,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e6a9a48c0e930773f0a82fa246c53f98","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3652-3655","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40742,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"dbf1a067fe97d23702c1dcb8e2df53b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1890-1892","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40743,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"67e81d60b5109e19786b8bfbc4a80abd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2281-2283","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40744,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"09f8b4a6f66776095afcdc7473efbaf2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2466-2467","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40745,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"9a263f97b2eae42c0e192fb1cfee8776","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2526-2527","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40746,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"ea9495482bd4ecf48df793f9abf39cc1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2536-2537","gmt_create":"2026-04-30T08:00:09.960297+04:00","gmt_modified":"2026-04-30T08:00:09.960297+04:00"},{"id":40747,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"47d651650f297dcd4ffcf47ee28027f2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4536-4537","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40748,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5452e208808a1bd3d416cced7e6d6f0a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4538-4539","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40749,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5affc96a80f081a4ef8bd4b5177ef1a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4544-4545","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40750,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"dd981f6523bfe5386b3d4a97ca575fdf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4567-4568","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40751,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e0ef3c7d489444d0a7bf6cd609a98c05","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4569-4570","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40752,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"13ee871790dddd2f670c1493c6665f41","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4571-4572","gmt_create":"2026-04-30T08:00:09.9613004+04:00","gmt_modified":"2026-04-30T08:00:09.9613004+04:00"},{"id":40753,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"90331ddec7a3725739758ff2180d5b8e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4573-4574","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40754,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"654c2896a03be742e37554a614a0244c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5530-5531","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40755,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"e9e61fd4b1cf8706755eb1dfa541ccc7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5543-5544","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40756,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"b7aaa429e07e8abc0d4999c4c496d854","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5677-5678","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40757,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1f43be6f2eea9de96bd24d20b575c860","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5680-5681","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40758,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"d9dbf24fcc1a502e794d92f729bcd372","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#159-160","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40759,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2b851e123aa78f2afb16a52472781e64","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#228-233","gmt_create":"2026-04-30T08:00:09.9623005+04:00","gmt_modified":"2026-04-30T08:00:09.9623005+04:00"},{"id":40760,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"abeb5e992b22812a0cdfc0c3dca91067","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#338-340","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40761,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"956e60e52272d2047c3d89d0f1fe96a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#356-357","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40762,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"70499ce1f567f2564154072ea2576c3b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#403-405","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40763,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"aad86469ecab79c7481892069f6100df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#411-412","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40764,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"57d63528cfa5d7410afabeee4a42845e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#416-417","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40765,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"daa5dca768a6e2ed062d953de56c3dc6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#418-419","gmt_create":"2026-04-30T08:00:09.9633004+04:00","gmt_modified":"2026-04-30T08:00:09.9633004+04:00"},{"id":40766,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"f0fa917f2268095d00a5c33920129393","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/stacktrace.cpp#48-78","gmt_create":"2026-04-30T08:00:09.9643004+04:00","gmt_modified":"2026-04-30T08:00:09.9643004+04:00"},{"id":40767,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"321d8cd55620ec252c0b570fa95fd592","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5092-5105","gmt_create":"2026-04-30T08:00:09.9643004+04:00","gmt_modified":"2026-04-30T08:00:09.9643004+04:00"},{"id":40768,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"321d8cd55620ec252c0b570fa95fd592","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5092-5105","gmt_create":"2026-04-30T08:00:09.9643004+04:00","gmt_modified":"2026-04-30T08:00:09.9643004+04:00"},{"id":40769,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"118584993a6d2e21fefe6c8f98dbe2f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5283-5297","gmt_create":"2026-04-30T08:00:09.9643004+04:00","gmt_modified":"2026-04-30T08:00:09.9643004+04:00"},{"id":40770,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"118584993a6d2e21fefe6c8f98dbe2f6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5283-5297","gmt_create":"2026-04-30T08:00:09.9708292+04:00","gmt_modified":"2026-04-30T08:00:09.9708292+04:00"},{"id":40771,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"26650c218a6c596d28668797b6045c8c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5616-5635","gmt_create":"2026-04-30T08:00:09.9708292+04:00","gmt_modified":"2026-04-30T08:00:09.9708292+04:00"},{"id":40772,"source_id":"a5661951a63a8a4cb0a563b6ff08335e","target_id":"26650c218a6c596d28668797b6045c8c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 5616-5635","gmt_create":"2026-04-30T08:00:09.9708292+04:00","gmt_modified":"2026-04-30T08:00:09.9708292+04:00"},{"id":40773,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"bd530cb9e845767f0a9b3ff967997984","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#93-141","gmt_create":"2026-04-30T08:00:09.9708292+04:00","gmt_modified":"2026-04-30T08:00:09.9708292+04:00"},{"id":40774,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"f10623a85ff8726287ec33204df6d61a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#458-584","gmt_create":"2026-04-30T08:00:09.9708292+04:00","gmt_modified":"2026-04-30T08:00:09.9708292+04:00"},{"id":40775,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1d8a3a8529f55f725cbd52ef78db6a1f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4334-4463","gmt_create":"2026-04-30T08:00:09.9723323+04:00","gmt_modified":"2026-04-30T08:00:09.9723323+04:00"},{"id":40776,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"8f391118507fdd830a986c86e989a317","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2047-2144","gmt_create":"2026-04-30T08:00:09.9724388+04:00","gmt_modified":"2026-04-30T08:00:09.9724388+04:00"},{"id":40777,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"fa62adcb3d13201bfc9729dde67be04f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4378-4416","gmt_create":"2026-04-30T08:00:09.9724388+04:00","gmt_modified":"2026-04-30T08:00:09.9724388+04:00"},{"id":40778,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"98ed598d82d28fa1553560148bcda24e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2125-2142","gmt_create":"2026-04-30T08:00:09.9724388+04:00","gmt_modified":"2026-04-30T08:00:09.9724388+04:00"},{"id":40779,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"5a5c235262f9722ff7bdf0586bfd8e26","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4220-4230","gmt_create":"2026-04-30T08:00:09.9733359+04:00","gmt_modified":"2026-04-30T08:00:09.9733359+04:00"},{"id":40780,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"a7270a78978a13ee55ddc7f94813e3df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1680-1693","gmt_create":"2026-04-30T08:00:09.9733359+04:00","gmt_modified":"2026-04-30T08:00:09.9733359+04:00"},{"id":40781,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"a7f5c35a309d6a9851c0491c125c63d9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3224-3236","gmt_create":"2026-04-30T08:00:09.9733359+04:00","gmt_modified":"2026-04-30T08:00:09.9733359+04:00"},{"id":40782,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"2f5c46c8352dc73f0b90e01cef1bcc9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#3272-3284","gmt_create":"2026-04-30T08:00:09.9733359+04:00","gmt_modified":"2026-04-30T08:00:09.9733359+04:00"},{"id":40783,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"26495d5b0fffb6fefe7f8c69d291521e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#738-742","gmt_create":"2026-04-30T08:00:09.9733359+04:00","gmt_modified":"2026-04-30T08:00:09.9733359+04:00"},{"id":40784,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"6c94b84fdfd5c7016b5eeadf8099133e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/plugin.cpp","gmt_create":"2026-04-30T08:00:09.974339+04:00","gmt_modified":"2026-04-30T08:00:09.974339+04:00"},{"id":40785,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"3bdfaf9a009f1c5236532831eedfa66b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#760-770","gmt_create":"2026-04-30T08:00:09.974339+04:00","gmt_modified":"2026-04-30T08:00:09.974339+04:00"},{"id":40786,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"39b6820362e87b0f937201fb8f54dee6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#1-10","gmt_create":"2026-04-30T08:00:09.974339+04:00","gmt_modified":"2026-04-30T08:00:09.974339+04:00"},{"id":40787,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"1efc9fdbd77068cf27cb00354deff17a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-30","gmt_create":"2026-04-30T08:00:09.974339+04:00","gmt_modified":"2026-04-30T08:00:09.974339+04:00"},{"id":40788,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"d0e2616c3e70f0e809256dcb448916ab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#270-279","gmt_create":"2026-04-30T08:00:09.9763358+04:00","gmt_modified":"2026-04-30T08:00:09.9763358+04:00"},{"id":40789,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"0855c233a79de418e4577d44bd54b9ba","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#492-501","gmt_create":"2026-04-30T08:00:09.9763358+04:00","gmt_modified":"2026-04-30T08:00:09.9763358+04:00"},{"id":40790,"source_id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","target_id":"295c418f-33b4-4c06-80cf-224d6b633a76","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31 -\u003e 295c418f-33b4-4c06-80cf-224d6b633a76","gmt_create":"2026-04-30T08:00:15.1059847+04:00","gmt_modified":"2026-04-30T08:00:15.1059847+04:00"},{"id":40928,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"82dadfd972805d70bffa99ce756460c4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 307-327","gmt_create":"2026-04-30T08:47:09.8556473+04:00","gmt_modified":"2026-04-30T08:47:09.8556473+04:00"},{"id":40930,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"ee32480b501d0e9284fc1a7aa7d20b4c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1042-1113","gmt_create":"2026-04-30T08:47:09.8556473+04:00","gmt_modified":"2026-04-30T08:47:09.8556473+04:00"},{"id":40947,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"f12cdb54f6351fe38c307c4907f93868","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 783-791","gmt_create":"2026-04-30T08:47:09.8598101+04:00","gmt_modified":"2026-04-30T08:47:09.8598101+04:00"},{"id":40949,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"8c9490ebae702a4725d10dc509074042","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 812-816","gmt_create":"2026-04-30T08:47:09.8603579+04:00","gmt_modified":"2026-04-30T08:47:09.8603579+04:00"},{"id":40973,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-30T11:11:44.1777537+04:00","gmt_modified":"2026-04-30T11:11:44.1777537+04:00"},{"id":40974,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T11:11:44.179257+04:00","gmt_modified":"2026-04-30T11:11:44.179257+04:00"},{"id":40975,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"d2090ff9016be0d896d06e843936e0f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/block_log.cpp","gmt_create":"2026-04-30T11:11:44.179257+04:00","gmt_modified":"2026-04-30T11:11:44.179257+04:00"},{"id":40976,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T11:11:44.179257+04:00","gmt_modified":"2026-04-30T11:11:44.179257+04:00"},{"id":40977,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T11:11:44.1802619+04:00","gmt_modified":"2026-04-30T11:11:44.1802619+04:00"},{"id":40978,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"6c94b84fdfd5c7016b5eeadf8099133e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/plugin.cpp","gmt_create":"2026-04-30T11:11:44.1802619+04:00","gmt_modified":"2026-04-30T11:11:44.1802619+04:00"},{"id":40979,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-30T11:11:44.1802619+04:00","gmt_modified":"2026-04-30T11:11:44.1802619+04:00"},{"id":40980,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T11:11:44.1807664+04:00","gmt_modified":"2026-04-30T11:11:44.1807664+04:00"},{"id":40981,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T11:11:44.1807664+04:00","gmt_modified":"2026-04-30T11:11:44.1807664+04:00"},{"id":40982,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"8c1b3bca4f56b317e9e0acdb4be83a00","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#1-89","gmt_create":"2026-04-30T11:11:44.1807664+04:00","gmt_modified":"2026-04-30T11:11:44.1807664+04:00"},{"id":40983,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"a3ae1dbcc1c9bd6ef59dec7fb6a6e6be","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#1-582","gmt_create":"2026-04-30T11:11:44.1817708+04:00","gmt_modified":"2026-04-30T11:11:44.1817708+04:00"},{"id":40984,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"fef8201a8783aa794440fbd2f9b1ff17","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#1-302","gmt_create":"2026-04-30T11:11:44.1817708+04:00","gmt_modified":"2026-04-30T11:11:44.1817708+04:00"},{"id":40985,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"233a2d8be5340ec151c42900fcd58a96","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#220-271","gmt_create":"2026-04-30T11:11:44.1827706+04:00","gmt_modified":"2026-04-30T11:11:44.1827706+04:00"},{"id":40986,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"02b88f06fab1f8f2b384ec38dfea95a8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#1-258","gmt_create":"2026-04-30T11:11:44.1827706+04:00","gmt_modified":"2026-04-30T11:11:44.1827706+04:00"},{"id":40987,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c6c440b24137364c19bc7fe7a800ce3e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#320-330","gmt_create":"2026-04-30T11:11:44.1837705+04:00","gmt_modified":"2026-04-30T11:11:44.1837705+04:00"},{"id":40988,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"7c7114ff694eca47458deb9031af3874","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1960-2039","gmt_create":"2026-04-30T11:11:44.1837705+04:00","gmt_modified":"2026-04-30T11:11:44.1837705+04:00"},{"id":40989,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5c9a153931730742e72d3183f4f76128","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#255-286","gmt_create":"2026-04-30T11:11:44.1837705+04:00","gmt_modified":"2026-04-30T11:11:44.1837705+04:00"},{"id":40990,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"77740b8f659f6e4296624292e035f0b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#515-516","gmt_create":"2026-04-30T11:11:44.1847704+04:00","gmt_modified":"2026-04-30T11:11:44.1847704+04:00"},{"id":40991,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"445ddb5941dc16c8a6313b9ec556f75a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#35-89","gmt_create":"2026-04-30T11:11:44.1857959+04:00","gmt_modified":"2026-04-30T11:11:44.1857959+04:00"},{"id":40992,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"44c647e6bdaeba8176c9fd58d7bf204f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#18-278","gmt_create":"2026-04-30T11:11:44.1857959+04:00","gmt_modified":"2026-04-30T11:11:44.1857959+04:00"},{"id":40993,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"1fec0c281b15b8cb253758a81bda9d53","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#230-231","gmt_create":"2026-04-30T11:11:44.186796+04:00","gmt_modified":"2026-04-30T11:11:44.186796+04:00"},{"id":40994,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"20be4db8cc88d28b2576cc8c6640d89d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#24-28","gmt_create":"2026-04-30T11:11:44.186796+04:00","gmt_modified":"2026-04-30T11:11:44.186796+04:00"},{"id":40995,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"4aaf8248e16bc831caf0d6215227a347","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#327-329","gmt_create":"2026-04-30T11:11:44.186796+04:00","gmt_modified":"2026-04-30T11:11:44.186796+04:00"},{"id":40996,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"2496b05edb9e2cce32ff03d614866f80","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1968-1970","gmt_create":"2026-04-30T11:11:44.1877958+04:00","gmt_modified":"2026-04-30T11:11:44.1877958+04:00"},{"id":40997,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"bd936d7f114a4d7505d38477591a432b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#265-272","gmt_create":"2026-04-30T11:11:44.1887957+04:00","gmt_modified":"2026-04-30T11:11:44.1887957+04:00"},{"id":40998,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"09e49fa0e3657a309d205da532bae0d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1414-1500","gmt_create":"2026-04-30T11:11:44.1887957+04:00","gmt_modified":"2026-04-30T11:11:44.1887957+04:00"},{"id":40999,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"89fd5aa6e93582e3684130e9c0920e33","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#438-544","gmt_create":"2026-04-30T11:11:44.1887957+04:00","gmt_modified":"2026-04-30T11:11:44.1887957+04:00"},{"id":41000,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"733f077750798ad212e3907d2e15c841","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#835-858","gmt_create":"2026-04-30T11:11:44.1887957+04:00","gmt_modified":"2026-04-30T11:11:44.1887957+04:00"},{"id":41001,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"31f6fa48f80c0c6d8c5b09074b2f3f45","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4910-5150","gmt_create":"2026-04-30T11:11:44.1902997+04:00","gmt_modified":"2026-04-30T11:11:44.1902997+04:00"},{"id":41002,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"1e55d2aee2f6d3f5d6247eb14ca9350a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#230-268","gmt_create":"2026-04-30T11:11:44.1902997+04:00","gmt_modified":"2026-04-30T11:11:44.1902997+04:00"},{"id":41003,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"05c7b54032266aa804fecdd672849759","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#560-627","gmt_create":"2026-04-30T11:11:44.1902997+04:00","gmt_modified":"2026-04-30T11:11:44.1902997+04:00"},{"id":41004,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"d00cc75cac98bab547f7549076e3504d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#238-241","gmt_create":"2026-04-30T11:11:44.1908127+04:00","gmt_modified":"2026-04-30T11:11:44.1908127+04:00"},{"id":41005,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"3f58d42a32421c25e81f24320b1d1f20","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#313-328","gmt_create":"2026-04-30T11:11:44.1908127+04:00","gmt_modified":"2026-04-30T11:11:44.1908127+04:00"},{"id":41006,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"7a9e26fca49ab5e068040d1db9fed41f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#259-286","gmt_create":"2026-04-30T11:11:44.1908127+04:00","gmt_modified":"2026-04-30T11:11:44.1908127+04:00"},{"id":41007,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"8d97625477363c05b9feab2d2cbb781b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#31-38","gmt_create":"2026-04-30T11:11:44.1918162+04:00","gmt_modified":"2026-04-30T11:11:44.1918162+04:00"},{"id":41008,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"1b89c3c75aec06d4b094f1f6692436f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#59-66","gmt_create":"2026-04-30T11:11:44.1918162+04:00","gmt_modified":"2026-04-30T11:11:44.1918162+04:00"},{"id":41009,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"3f4e4b4d64c6750b34e1fe180b376017","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#119-136","gmt_create":"2026-04-30T11:11:44.1918162+04:00","gmt_modified":"2026-04-30T11:11:44.1918162+04:00"},{"id":41010,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"1853975a7087e8a5073352a9a8ea53c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#138-155","gmt_create":"2026-04-30T11:11:44.1918162+04:00","gmt_modified":"2026-04-30T11:11:44.1918162+04:00"},{"id":41011,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"d059ab60b812d6e824e8fef796efa497","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#161-209","gmt_create":"2026-04-30T11:11:44.1918162+04:00","gmt_modified":"2026-04-30T11:11:44.1918162+04:00"},{"id":41012,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"343b12b915179b0ceab0474a3260def1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#125-159","gmt_create":"2026-04-30T11:11:44.1928495+04:00","gmt_modified":"2026-04-30T11:11:44.1928495+04:00"},{"id":41013,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"edc66ae920408eb6412dad9e65c69f63","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#211-268","gmt_create":"2026-04-30T11:11:44.1928495+04:00","gmt_modified":"2026-04-30T11:11:44.1928495+04:00"},{"id":41014,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c87f750598b8e3aeb391ebd49f3c8730","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#356-411","gmt_create":"2026-04-30T11:11:44.1938481+04:00","gmt_modified":"2026-04-30T11:11:44.1938481+04:00"},{"id":41015,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"04677ace577bc003b34701bfd451a89d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#523-543","gmt_create":"2026-04-30T11:11:44.1938481+04:00","gmt_modified":"2026-04-30T11:11:44.1938481+04:00"},{"id":41016,"source_id":"ade43b15adadb0a3215b2b7a6866ef22","target_id":"04677ace577bc003b34701bfd451a89d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 523-543","gmt_create":"2026-04-30T11:11:44.1938481+04:00","gmt_modified":"2026-04-30T11:11:44.1938481+04:00"},{"id":41017,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"b372b2c20cc0d9d9abd9e2254bfefb17","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#576-602","gmt_create":"2026-04-30T11:11:44.1948465+04:00","gmt_modified":"2026-04-30T11:11:44.1948465+04:00"},{"id":41018,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"23c70bfc8bc9d7d6ea64c01cbc8cfa74","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#545-579","gmt_create":"2026-04-30T11:11:44.1958468+04:00","gmt_modified":"2026-04-30T11:11:44.1958468+04:00"},{"id":41019,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"57b5a41ba76b9bfcb250e93e89805515","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#761-765","gmt_create":"2026-04-30T11:11:44.1963515+04:00","gmt_modified":"2026-04-30T11:11:44.1963515+04:00"},{"id":41020,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"85e42052e68826778bf6fc0a5c348061","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#266-292","gmt_create":"2026-04-30T11:11:44.1963515+04:00","gmt_modified":"2026-04-30T11:11:44.1963515+04:00"},{"id":41021,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"44fcac467d4197ec65011a88dcc9b983","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#942-1054","gmt_create":"2026-04-30T11:11:44.1973552+04:00","gmt_modified":"2026-04-30T11:11:44.1973552+04:00"},{"id":41022,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"d866d0710f48a708f384cfe833d19819","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2790-2791","gmt_create":"2026-04-30T11:11:44.1973552+04:00","gmt_modified":"2026-04-30T11:11:44.1973552+04:00"},{"id":41023,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"7f9a564b8011c536e8ff555516dffbae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#3254","gmt_create":"2026-04-30T11:11:44.1983555+04:00","gmt_modified":"2026-04-30T11:11:44.1983555+04:00"},{"id":41024,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"cc2057fd8aeaa6b63ca70e0d4192d8f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#542-555","gmt_create":"2026-04-30T11:11:44.1983555+04:00","gmt_modified":"2026-04-30T11:11:44.1983555+04:00"},{"id":41025,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"3397b02998da3d1df1abfc39e178cd35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#74-100","gmt_create":"2026-04-30T11:11:44.1993551+04:00","gmt_modified":"2026-04-30T11:11:44.1993551+04:00"},{"id":41026,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"dfc65f88824f860423d799827fdee7aa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#545-574","gmt_create":"2026-04-30T11:11:44.1993551+04:00","gmt_modified":"2026-04-30T11:11:44.1993551+04:00"},{"id":41027,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"443c70bf08a7229603f07d4b6e2ceb04","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#304-369","gmt_create":"2026-04-30T11:11:44.2008582+04:00","gmt_modified":"2026-04-30T11:11:44.2008582+04:00"},{"id":41028,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5985a883b7cd6e373fa45e06af549458","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#172-202","gmt_create":"2026-04-30T11:11:44.2008582+04:00","gmt_modified":"2026-04-30T11:11:44.2008582+04:00"},{"id":41029,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"27ad3a44022480b087c9dee522cf8f53","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#432-444","gmt_create":"2026-04-30T11:11:44.2008582+04:00","gmt_modified":"2026-04-30T11:11:44.2008582+04:00"},{"id":41030,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5df133f8f7e5465f2256280233f7492a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4005-4036","gmt_create":"2026-04-30T11:11:44.2018621+04:00","gmt_modified":"2026-04-30T11:11:44.2018621+04:00"},{"id":41031,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"7ed16e639125b23aeb82bbb3768334fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4170-4172","gmt_create":"2026-04-30T11:11:44.2018621+04:00","gmt_modified":"2026-04-30T11:11:44.2018621+04:00"},{"id":41032,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ed64be85dbceaa49c4d38b1fd7b0537f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4392-4394","gmt_create":"2026-04-30T11:11:44.2018621+04:00","gmt_modified":"2026-04-30T11:11:44.2018621+04:00"},{"id":41033,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"770f933f07c1261bce810845c6711ec4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4043-4047","gmt_create":"2026-04-30T11:11:44.2028616+04:00","gmt_modified":"2026-04-30T11:11:44.2028616+04:00"},{"id":41034,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5988d2bd7b0d5bec2b97a885d1928110","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4189-4192","gmt_create":"2026-04-30T11:11:44.2028616+04:00","gmt_modified":"2026-04-30T11:11:44.2028616+04:00"},{"id":41035,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"a9078dfa0e86bfbf3c1bef4a473eb117","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4419-4421","gmt_create":"2026-04-30T11:11:44.2028616+04:00","gmt_modified":"2026-04-30T11:11:44.2028616+04:00"},{"id":41036,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"4af3002393266cb7f00332d69f2019ca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#233-236","gmt_create":"2026-04-30T11:11:44.2028616+04:00","gmt_modified":"2026-04-30T11:11:44.2028616+04:00"},{"id":41037,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"36faa15d1b9669c10ef981b57dd230bc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#326-329","gmt_create":"2026-04-30T11:11:44.2028616+04:00","gmt_modified":"2026-04-30T11:11:44.2028616+04:00"},{"id":41038,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"69112cf16468224f02ecd1fbd49ea64f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#1-10","gmt_create":"2026-04-30T11:11:44.2043647+04:00","gmt_modified":"2026-04-30T11:11:44.2043647+04:00"},{"id":41039,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"6456782ce4d45cbdc58f90d5677ca2c2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#1-7","gmt_create":"2026-04-30T11:11:44.2043647+04:00","gmt_modified":"2026-04-30T11:11:44.2043647+04:00"},{"id":41040,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"fce2bc849f6a01aeb1da861120260037","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/block_log.cpp#1-6","gmt_create":"2026-04-30T11:11:44.2043647+04:00","gmt_modified":"2026-04-30T11:11:44.2043647+04:00"},{"id":41041,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ab61b06105c0618ce476f62fc42d04c5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-10","gmt_create":"2026-04-30T11:11:44.2053684+04:00","gmt_modified":"2026-04-30T11:11:44.2053684+04:00"},{"id":41042,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"cf34d537814cc823a0786b3fa43ffca0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#1-6","gmt_create":"2026-04-30T11:11:44.2053684+04:00","gmt_modified":"2026-04-30T11:11:44.2053684+04:00"},{"id":41043,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"7bd018a7b3dab28cc6792e89ffa39efd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#1-10","gmt_create":"2026-04-30T11:11:44.2053684+04:00","gmt_modified":"2026-04-30T11:11:44.2053684+04:00"},{"id":41044,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"96e5aca4a37cf627dff138e440efffa2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#1-10","gmt_create":"2026-04-30T11:11:44.2063683+04:00","gmt_modified":"2026-04-30T11:11:44.2063683+04:00"},{"id":41045,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"8e436d067efeeee9365369d51dc3fd02","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#250-271","gmt_create":"2026-04-30T11:11:44.2073683+04:00","gmt_modified":"2026-04-30T11:11:44.2073683+04:00"},{"id":41046,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"2fb2b5eefe1dda70f9332bca41575f3d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#259-268","gmt_create":"2026-04-30T11:11:44.2083687+04:00","gmt_modified":"2026-04-30T11:11:44.2083687+04:00"},{"id":41047,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5864019a1f5c741338aa5810a4a9a2a4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#262-267","gmt_create":"2026-04-30T11:11:44.2083687+04:00","gmt_modified":"2026-04-30T11:11:44.2083687+04:00"},{"id":41048,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ac84b774b43ade0dc3ca1ecbd3b60ea5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#576-580","gmt_create":"2026-04-30T11:11:44.2093682+04:00","gmt_modified":"2026-04-30T11:11:44.2093682+04:00"},{"id":41049,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"29ef92399939d0e10862168a6d547c18","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#609-613","gmt_create":"2026-04-30T11:11:44.2093682+04:00","gmt_modified":"2026-04-30T11:11:44.2093682+04:00"},{"id":41050,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"50f4656fe0d323b661f41cd93f59398f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#599-621","gmt_create":"2026-04-30T11:11:44.2093682+04:00","gmt_modified":"2026-04-30T11:11:44.2093682+04:00"},{"id":41051,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"f1468b7365f4d06080c1395db0eb5819","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#623-640","gmt_create":"2026-04-30T11:11:44.2093682+04:00","gmt_modified":"2026-04-30T11:11:44.2093682+04:00"},{"id":41052,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"06b382c82ee3f42c24d858503dcde41b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#241-249","gmt_create":"2026-04-30T11:11:44.2110988+04:00","gmt_modified":"2026-04-30T11:11:44.2110988+04:00"},{"id":41053,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ce3f0826aff2367e46f4cd37417c2f67","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#320-325","gmt_create":"2026-04-30T11:11:44.2116948+04:00","gmt_modified":"2026-04-30T11:11:44.2116948+04:00"},{"id":41054,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"55755f9121d991a7682722b9a8b3ab80","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#560-595","gmt_create":"2026-04-30T11:11:44.2130379+04:00","gmt_modified":"2026-04-30T11:11:44.2130379+04:00"},{"id":41055,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"86ba814ebeaa92690f62613e16aa5e7d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#656-697","gmt_create":"2026-04-30T11:11:44.2135409+04:00","gmt_modified":"2026-04-30T11:11:44.2135409+04:00"},{"id":41056,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"ce99ae12d13aaa7b2653e47db773bcce","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1435-1500","gmt_create":"2026-04-30T11:11:44.2141616+04:00","gmt_modified":"2026-04-30T11:11:44.2141616+04:00"},{"id":41057,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"a370301bb49e9efcf0ef5d6724ac9dd2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2691-2696","gmt_create":"2026-04-30T11:11:44.2146646+04:00","gmt_modified":"2026-04-30T11:11:44.2146646+04:00"},{"id":41058,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"09819e68e897288cd817074594e4f548","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2863-2866","gmt_create":"2026-04-30T11:11:44.2146646+04:00","gmt_modified":"2026-04-30T11:11:44.2146646+04:00"},{"id":41059,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"b44834f88165b1116477f30dc5f88a3e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4581-4608","gmt_create":"2026-04-30T11:11:44.2153918+04:00","gmt_modified":"2026-04-30T11:11:44.2153918+04:00"},{"id":41060,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"17512b930411cc392fa7b28fa3ad2b84","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#332-338","gmt_create":"2026-04-30T11:11:44.2164987+04:00","gmt_modified":"2026-04-30T11:11:44.2164987+04:00"},{"id":41061,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"9a668be3a6e1e9f3afa6fcd90677d0b3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5482-5499","gmt_create":"2026-04-30T11:11:44.2170019+04:00","gmt_modified":"2026-04-30T11:11:44.2170019+04:00"},{"id":41062,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c6612598fe076c0f7d5ca15ca94cf26b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#627-627","gmt_create":"2026-04-30T11:11:44.2175254+04:00","gmt_modified":"2026-04-30T11:11:44.2175254+04:00"},{"id":41063,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"62962be4cb55c4466a47fba7a814b326","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1473-1476","gmt_create":"2026-04-30T11:11:44.2180455+04:00","gmt_modified":"2026-04-30T11:11:44.2180455+04:00"},{"id":41064,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"798b9ae312576643f8fefd434b40bddc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#626-632","gmt_create":"2026-04-30T11:11:44.2180455+04:00","gmt_modified":"2026-04-30T11:11:44.2180455+04:00"},{"id":41065,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"02c2555684691e747182b4078de2ed9b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1472-1477","gmt_create":"2026-04-30T11:11:44.2180455+04:00","gmt_modified":"2026-04-30T11:11:44.2180455+04:00"},{"id":41066,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c31e2a585be22edd01d86dba51c51e79","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#294-302","gmt_create":"2026-04-30T11:11:44.2185645+04:00","gmt_modified":"2026-04-30T11:11:44.2185645+04:00"},{"id":41067,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"6ef04fbc3dcdfebcf2580c7e7146cbc3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#317-323","gmt_create":"2026-04-30T11:11:44.2185645+04:00","gmt_modified":"2026-04-30T11:11:44.2185645+04:00"},{"id":41068,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"5e4bd94274850728b00115526a2479ee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#860-882","gmt_create":"2026-04-30T11:11:44.2190818+04:00","gmt_modified":"2026-04-30T11:11:44.2190818+04:00"},{"id":41069,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"c53a6db24cea4db25b30783459c40125","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#884-901","gmt_create":"2026-04-30T11:11:44.2190818+04:00","gmt_modified":"2026-04-30T11:11:44.2190818+04:00"},{"id":41070,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"24e53b6bba24767d436a386f584d39b1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#330-364","gmt_create":"2026-04-30T11:11:44.2190818+04:00","gmt_modified":"2026-04-30T11:11:44.2190818+04:00"},{"id":41071,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"88d1d1609201e580c6cdf488fcd22fad","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#370-489","gmt_create":"2026-04-30T11:11:44.219599+04:00","gmt_modified":"2026-04-30T11:11:44.219599+04:00"},{"id":41072,"source_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","target_id":"766ad50513305c2c4955788de08b2f70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#757-765","gmt_create":"2026-04-30T11:11:44.2204252+04:00","gmt_modified":"2026-04-30T11:11:44.2204252+04:00"},{"id":41073,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"448c0fd26faf791081a54cd407662e4d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","gmt_create":"2026-04-30T11:12:37.461325+04:00","gmt_modified":"2026-04-30T11:12:37.461325+04:00"},{"id":41074,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T11:12:37.461325+04:00","gmt_modified":"2026-04-30T11:12:37.461325+04:00"},{"id":41075,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-30T11:12:37.4621341+04:00","gmt_modified":"2026-04-30T11:12:37.4621341+04:00"},{"id":41076,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"d72b348a2c3c7943e4a7abb7dbdaa751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_connection.hpp","gmt_create":"2026-04-30T11:12:37.4627462+04:00","gmt_modified":"2026-04-30T11:12:37.4627462+04:00"},{"id":41077,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"3a8d8a10556a0b6501e25aa43e91f913","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_database.hpp","gmt_create":"2026-04-30T11:12:37.4627462+04:00","gmt_modified":"2026-04-30T11:12:37.4627462+04:00"},{"id":41078,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"3a6c30f4bb3b265155c881ccfafa980e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/core_messages.hpp","gmt_create":"2026-04-30T11:12:37.4627462+04:00","gmt_modified":"2026-04-30T11:12:37.4627462+04:00"},{"id":41079,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"b4467ca30cb6f6d587fc200900ee9ec9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message.hpp","gmt_create":"2026-04-30T11:12:37.4633262+04:00","gmt_modified":"2026-04-30T11:12:37.4633262+04:00"},{"id":41080,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"c82262dc5275e094efc9474032d15922","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/config.hpp","gmt_create":"2026-04-30T11:12:37.4633262+04:00","gmt_modified":"2026-04-30T11:12:37.4633262+04:00"},{"id":41081,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-30T11:12:37.4633262+04:00","gmt_modified":"2026-04-30T11:12:37.4633262+04:00"},{"id":41082,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T11:12:37.4638289+04:00","gmt_modified":"2026-04-30T11:12:37.4638289+04:00"},{"id":41083,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-30T11:12:37.4756666+04:00","gmt_modified":"2026-04-30T11:12:37.4756666+04:00"},{"id":41084,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T11:12:37.4776569+04:00","gmt_modified":"2026-04-30T11:12:37.4776569+04:00"},{"id":41085,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T11:12:37.4776569+04:00","gmt_modified":"2026-04-30T11:12:37.4776569+04:00"},{"id":41086,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"ee77bf4eb6bfbfb3636aa0bd57416552","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/include/chainbase/chainbase.hpp","gmt_create":"2026-04-30T11:12:37.4782387+04:00","gmt_modified":"2026-04-30T11:12:37.4782387+04:00"},{"id":41087,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T11:12:37.4782387+04:00","gmt_modified":"2026-04-30T11:12:37.4782387+04:00"},{"id":41088,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"f7be79ec222a56c210b7999322790a2f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/CMakeLists.txt","gmt_create":"2026-04-30T11:12:37.4782387+04:00","gmt_modified":"2026-04-30T11:12:37.4782387+04:00"},{"id":41089,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T11:12:37.4787417+04:00","gmt_modified":"2026-04-30T11:12:37.4787417+04:00"},{"id":41090,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"e6b951c57c5f8fb2b3553ce8db430760","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#18-55","gmt_create":"2026-04-30T11:12:37.4788215+04:00","gmt_modified":"2026-04-30T11:12:37.4788215+04:00"},{"id":41091,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"467b9030fcd47369d3417c84998c20d0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#910-979","gmt_create":"2026-04-30T11:12:37.4788215+04:00","gmt_modified":"2026-04-30T11:12:37.4788215+04:00"},{"id":41092,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"cbfe85acce275b65a2edb3315aec2941","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#190-320","gmt_create":"2026-04-30T11:12:37.4799027+04:00","gmt_modified":"2026-04-30T11:12:37.4799027+04:00"},{"id":41093,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"9e18fa1bdbee1d9c96d8437bfe20515c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#1-57","gmt_create":"2026-04-30T11:12:37.4799027+04:00","gmt_modified":"2026-04-30T11:12:37.4799027+04:00"},{"id":41094,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"5dce2933cfb42430c2bbcdf0cacc25c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/CMakeLists.txt#1-49","gmt_create":"2026-04-30T11:12:37.4799027+04:00","gmt_modified":"2026-04-30T11:12:37.4799027+04:00"},{"id":41095,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"1b55f505ae64e9ea22be5142cfa67f93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#49-126","gmt_create":"2026-04-30T11:12:37.4804293+04:00","gmt_modified":"2026-04-30T11:12:37.4804293+04:00"},{"id":41096,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"8a161abeb389c25b1279bc23d6ff4e57","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#60-167","gmt_create":"2026-04-30T11:12:37.4804293+04:00","gmt_modified":"2026-04-30T11:12:37.4804293+04:00"},{"id":41097,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"f85f57d0c6b461ab78f906ef6d5854c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#79-354","gmt_create":"2026-04-30T11:12:37.4809431+04:00","gmt_modified":"2026-04-30T11:12:37.4809431+04:00"},{"id":41098,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"21076248fc123c7aacc8cb6e67cd0068","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#758-823","gmt_create":"2026-04-30T11:12:37.481738+04:00","gmt_modified":"2026-04-30T11:12:37.481738+04:00"},{"id":41099,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"4e79c62ed5491dcd85510f3dab144813","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#1-200","gmt_create":"2026-04-30T11:12:37.4822408+04:00","gmt_modified":"2026-04-30T11:12:37.4822408+04:00"},{"id":41100,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"fe82427a3c86c02f05708734fa4c589c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#216-245","gmt_create":"2026-04-30T11:12:37.4826001+04:00","gmt_modified":"2026-04-30T11:12:37.4826001+04:00"},{"id":41101,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"15bc72540b02de4c57e4c976c8150f35","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#855-865","gmt_create":"2026-04-30T11:12:37.4834146+04:00","gmt_modified":"2026-04-30T11:12:37.4834146+04:00"},{"id":41102,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"cd0a62c9a78bb77d3b59a9d5872577f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#82-106","gmt_create":"2026-04-30T11:12:37.4839927+04:00","gmt_modified":"2026-04-30T11:12:37.4839927+04:00"},{"id":41103,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"7eaff221b9d5916b8e18aa7786630566","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#188-218","gmt_create":"2026-04-30T11:12:37.4839927+04:00","gmt_modified":"2026-04-30T11:12:37.4839927+04:00"},{"id":41104,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"9ec3ef7b5beba7ccd4c8172983e359a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#247-301","gmt_create":"2026-04-30T11:12:37.4851521+04:00","gmt_modified":"2026-04-30T11:12:37.4851521+04:00"},{"id":41105,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"685c2a44fc90d96152180fc6a5a63df4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#129-208","gmt_create":"2026-04-30T11:12:37.4851521+04:00","gmt_modified":"2026-04-30T11:12:37.4851521+04:00"},{"id":41106,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"16437c2399403aa03ec5eb0bceca78b8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#653-770","gmt_create":"2026-04-30T11:12:37.4851521+04:00","gmt_modified":"2026-04-30T11:12:37.4851521+04:00"},{"id":41107,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"16437c2399403aa03ec5eb0bceca78b8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 653-770","gmt_create":"2026-04-30T11:12:37.4858117+04:00","gmt_modified":"2026-04-30T11:12:37.4858117+04:00"},{"id":41108,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"d74767289d3d8b429633502bc075cc48","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#773-813","gmt_create":"2026-04-30T11:12:37.4858117+04:00","gmt_modified":"2026-04-30T11:12:37.4858117+04:00"},{"id":41109,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"d74767289d3d8b429633502bc075cc48","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 773-813","gmt_create":"2026-04-30T11:12:37.4858117+04:00","gmt_modified":"2026-04-30T11:12:37.4858117+04:00"},{"id":41110,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"5eaed48196ffe1d0e73f557aacdc6096","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#760-768","gmt_create":"2026-04-30T11:12:37.4863152+04:00","gmt_modified":"2026-04-30T11:12:37.4863152+04:00"},{"id":41111,"source_id":"66c6049f94b83d8f15dc55bb2424efbe","target_id":"5eaed48196ffe1d0e73f557aacdc6096","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 760-768","gmt_create":"2026-04-30T11:12:37.4863152+04:00","gmt_modified":"2026-04-30T11:12:37.4863152+04:00"},{"id":41112,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"55ed0cee7e5f683b8caac133899cb8cd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#295-340","gmt_create":"2026-04-30T11:12:37.4863152+04:00","gmt_modified":"2026-04-30T11:12:37.4863152+04:00"},{"id":41113,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"909f520b94e82193bac04c745bf8f67c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#614-650","gmt_create":"2026-04-30T11:12:37.4873184+04:00","gmt_modified":"2026-04-30T11:12:37.4873184+04:00"},{"id":41114,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"163647b506865a0b9039e6ab0e61b35b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#290-364","gmt_create":"2026-04-30T11:12:37.4873184+04:00","gmt_modified":"2026-04-30T11:12:37.4873184+04:00"},{"id":41115,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"0dc933c238ae7ab73de36f0171dfb48b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#371-405","gmt_create":"2026-04-30T11:12:37.4883183+04:00","gmt_modified":"2026-04-30T11:12:37.4883183+04:00"},{"id":41116,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"82dadfd972805d70bffa99ce756460c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#307-327","gmt_create":"2026-04-30T11:12:37.4883183+04:00","gmt_modified":"2026-04-30T11:12:37.4883183+04:00"},{"id":41117,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"ee32480b501d0e9284fc1a7aa7d20b4c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#1042-1113","gmt_create":"2026-04-30T11:12:37.4883183+04:00","gmt_modified":"2026-04-30T11:12:37.4883183+04:00"},{"id":41118,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"dfc65f88824f860423d799827fdee7aa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#545-574","gmt_create":"2026-04-30T11:12:37.4893183+04:00","gmt_modified":"2026-04-30T11:12:37.4893183+04:00"},{"id":41119,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"e24259987d3c50dee1a87e13d63ccf03","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#57-78","gmt_create":"2026-04-30T11:12:37.4893183+04:00","gmt_modified":"2026-04-30T11:12:37.4893183+04:00"},{"id":41120,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"6742da18bac301be1056c8e6e5adcf69","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/dlt_block_log.hpp#35-72","gmt_create":"2026-04-30T11:12:37.4899114+04:00","gmt_modified":"2026-04-30T11:12:37.4899114+04:00"},{"id":41121,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"5a09c4b30cf4ad7363c8ddc12bc7c8db","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#290-405","gmt_create":"2026-04-30T11:12:37.4904141+04:00","gmt_modified":"2026-04-30T11:12:37.4904141+04:00"},{"id":41122,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"d8698088d1f1c1cd1343a5552104c443","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#295-405","gmt_create":"2026-04-30T11:12:37.4917778+04:00","gmt_modified":"2026-04-30T11:12:37.4917778+04:00"},{"id":41123,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"bccfbcb90cc33fcb1bad654d203eab3a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#308-340","gmt_create":"2026-04-30T11:12:37.4923716+04:00","gmt_modified":"2026-04-30T11:12:37.4923716+04:00"},{"id":41124,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"3e4f7ec74d72ee9c1f4f5cf2a0f86844","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#298-302","gmt_create":"2026-04-30T11:12:37.4929891+04:00","gmt_modified":"2026-04-30T11:12:37.4929891+04:00"},{"id":41125,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"e13810e67e91d0b4940124f48b98095c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#335-338","gmt_create":"2026-04-30T11:12:37.4935761+04:00","gmt_modified":"2026-04-30T11:12:37.4935761+04:00"},{"id":41126,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"30fcbbca25b602851122e4d2b5ae4754","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#701-765","gmt_create":"2026-04-30T11:12:37.4940787+04:00","gmt_modified":"2026-04-30T11:12:37.4940787+04:00"},{"id":41127,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"2d0ff08ccbd1994ff4f46985361fc3d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#355-364","gmt_create":"2026-04-30T11:12:37.4950816+04:00","gmt_modified":"2026-04-30T11:12:37.4950816+04:00"},{"id":41128,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"f195c24b5ab419ffbcc0c59a70fc3b0b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#520-528","gmt_create":"2026-04-30T11:12:37.4950816+04:00","gmt_modified":"2026-04-30T11:12:37.4950816+04:00"},{"id":41129,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"10e2e9b3ec934c86877d6a4b57e21d34","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#321-327","gmt_create":"2026-04-30T11:12:37.4950816+04:00","gmt_modified":"2026-04-30T11:12:37.4950816+04:00"},{"id":41130,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"c45e7282b5fb1668e8ae6f5a8da708ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#151-208","gmt_create":"2026-04-30T11:12:37.4950816+04:00","gmt_modified":"2026-04-30T11:12:37.4950816+04:00"},{"id":41131,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"3926b37345d6d1e98bd8faf06e492e48","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#722-771","gmt_create":"2026-04-30T11:12:37.4960816+04:00","gmt_modified":"2026-04-30T11:12:37.4960816+04:00"},{"id":41132,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"f12cdb54f6351fe38c307c4907f93868","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#783-791","gmt_create":"2026-04-30T11:12:37.4960816+04:00","gmt_modified":"2026-04-30T11:12:37.4960816+04:00"},{"id":41133,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"8c9490ebae702a4725d10dc509074042","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#812-816","gmt_create":"2026-04-30T11:12:37.4968454+04:00","gmt_modified":"2026-04-30T11:12:37.4968454+04:00"},{"id":41134,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"a1ef6908e910771a074aa8ccbc10adef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#773-795","gmt_create":"2026-04-30T11:12:37.4974156+04:00","gmt_modified":"2026-04-30T11:12:37.4974156+04:00"},{"id":41135,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"e2711f14cc959993e82e19c033761fff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#16-21","gmt_create":"2026-04-30T11:12:37.4991416+04:00","gmt_modified":"2026-04-30T11:12:37.4991416+04:00"},{"id":41136,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"7232f04ac5a3f960659a84db72e3c8c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#79-83","gmt_create":"2026-04-30T11:12:37.4996627+04:00","gmt_modified":"2026-04-30T11:12:37.4996627+04:00"},{"id":41137,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"84d9f61aa92a7de46576a47f269a5dcd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#169-171","gmt_create":"2026-04-30T11:12:37.5001803+04:00","gmt_modified":"2026-04-30T11:12:37.5001803+04:00"},{"id":41138,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"c66e1ad4dc89d485e77e61d3776d5e80","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#299-301","gmt_create":"2026-04-30T11:12:37.5007012+04:00","gmt_modified":"2026-04-30T11:12:37.5007012+04:00"},{"id":41139,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"d6af3938508b615a82ba5a3820d850c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#522-528","gmt_create":"2026-04-30T11:12:37.5007012+04:00","gmt_modified":"2026-04-30T11:12:37.5007012+04:00"},{"id":41140,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"5cdb837c5a6e5f183ed9a818f50b2abf","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#336-338","gmt_create":"2026-04-30T11:12:37.5017042+04:00","gmt_modified":"2026-04-30T11:12:37.5017042+04:00"},{"id":41141,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"4a61426778eec404639d3aa8059fbe1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#357-364","gmt_create":"2026-04-30T11:12:37.5017042+04:00","gmt_modified":"2026-04-30T11:12:37.5017042+04:00"},{"id":41142,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"1fc0915e82dd4c943724dcd2e29106cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#159-175","gmt_create":"2026-04-30T11:12:37.504965+04:00","gmt_modified":"2026-04-30T11:12:37.504965+04:00"},{"id":41143,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"29d1adb11bc96c1e7216be1c31cb57f7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#173-204","gmt_create":"2026-04-30T11:12:37.5054676+04:00","gmt_modified":"2026-04-30T11:12:37.5054676+04:00"},{"id":41144,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"1638be790588edb6a3913a76064f24e0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#992-1061","gmt_create":"2026-04-30T11:12:37.5064704+04:00","gmt_modified":"2026-04-30T11:12:37.5064704+04:00"},{"id":41145,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"9ad98a7be17ee5186d08088816474c52","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#540-552","gmt_create":"2026-04-30T11:12:37.506583+04:00","gmt_modified":"2026-04-30T11:12:37.506583+04:00"},{"id":41146,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"a273323d20c428afec092114bb480a23","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/include/chainbase/chainbase.hpp#1078-1115","gmt_create":"2026-04-30T11:12:37.5070855+04:00","gmt_modified":"2026-04-30T11:12:37.5070855+04:00"},{"id":41147,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"27c21c9dfb07f579bd0db9fa97c8fd19","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/include/chainbase/chainbase.hpp#1130-1137","gmt_create":"2026-04-30T11:12:37.5083887+04:00","gmt_modified":"2026-04-30T11:12:37.5083887+04:00"},{"id":41148,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"3b4fd0aa5c9c47621979a050b80b5fc2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#173-208","gmt_create":"2026-04-30T11:12:37.5088913+04:00","gmt_modified":"2026-04-30T11:12:37.5088913+04:00"},{"id":41149,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"411e466fa1c626bc1fff0647607acabd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#151-156","gmt_create":"2026-04-30T11:12:37.5088913+04:00","gmt_modified":"2026-04-30T11:12:37.5088913+04:00"},{"id":41150,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"b89fc00b26b800a29e1692b23ada0d56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#168-172","gmt_create":"2026-04-30T11:12:37.5088913+04:00","gmt_modified":"2026-04-30T11:12:37.5088913+04:00"},{"id":41151,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"8eb355e55d14f0a3eec62805ff783a2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/CMakeLists.txt#27-34","gmt_create":"2026-04-30T11:12:37.5088913+04:00","gmt_modified":"2026-04-30T11:12:37.5088913+04:00"},{"id":41152,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"4fc812a0df4303ac6e74df39697a0893","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#1-13","gmt_create":"2026-04-30T11:12:37.5098942+04:00","gmt_modified":"2026-04-30T11:12:37.5098942+04:00"},{"id":41153,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"cfa97ba993c799f350895b1deb5bfa1a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#596-699","gmt_create":"2026-04-30T11:12:37.5107568+04:00","gmt_modified":"2026-04-30T11:12:37.5107568+04:00"},{"id":41154,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"b372b2c20cc0d9d9abd9e2254bfefb17","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/dlt_block_log.cpp#576-602","gmt_create":"2026-04-30T11:12:37.5112596+04:00","gmt_modified":"2026-04-30T11:12:37.5112596+04:00"},{"id":41155,"source_id":"6c14d115-1e64-4774-9d11-4861953aec78","target_id":"463f1a4ea4700713bc6ca4afa0c86f4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config.ini#1-143","gmt_create":"2026-04-30T11:12:37.5118703+04:00","gmt_modified":"2026-04-30T11:12:37.5118703+04:00"},{"id":41156,"source_id":"295c418f-33b4-4c06-80cf-224d6b633a76","target_id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c418f-33b4-4c06-80cf-224d6b633a76 -\u003e cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","gmt_create":"2026-04-30T11:12:38.225503+04:00","gmt_modified":"2026-04-30T11:12:38.225503+04:00"},{"id":41157,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T12:35:27.5150739+04:00","gmt_modified":"2026-04-30T12:35:27.5150739+04:00"},{"id":41158,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T12:35:27.5150739+04:00","gmt_modified":"2026-04-30T12:35:27.5150739+04:00"},{"id":41159,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"7ae785f9d5ab154dce6f8eb295b93456","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/global_property_object.hpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41160,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"cf72debd284e30d5218a88ae08868205","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/witness_objects.hpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41161,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41162,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41163,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"b4b9efd79d5b3c9fea00fccd613b2046","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config.hpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41164,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"bbbc42bba97165e48c1da269d1d84a04","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config_testnet.hpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41165,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T12:35:27.515588+04:00","gmt_modified":"2026-04-30T12:35:27.515588+04:00"},{"id":41166,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"0dd2a38630da83b11fb3596ad4d60705","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/include/graphene/plugins/witness/witness.hpp","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41167,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"8ede002b6c76d0a07d75e34f812e8305","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/hardfork.d/12.hf","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41168,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"1ade3cebbc11a4634bcdf1a7fdb2756e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/src/chainbase.cpp","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41169,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"ee77bf4eb6bfbfb3636aa0bd57416552","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/include/chainbase/chainbase.hpp","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41170,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"943ef4fb5df40c9942aadddd7040bc7c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4863-5004","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41171,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"27593eff1e7989c53fb119e30b38a106","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#81-88","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41172,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"1273c494621ef1c9351fa8b783dc6ae6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#422-427","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41173,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"e2e78ec9bb315562ae4436bac3d06fb5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1556","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41174,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"cf67769b74f5699e4a347dc2d7092ceb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/chainbase/include/chainbase/chainbase.hpp#1097-1115","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41175,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"188a46b66d800240516e280b06e7f041","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/global_property_object.hpp#24-146","gmt_create":"2026-04-30T12:35:27.5160994+04:00","gmt_modified":"2026-04-30T12:35:27.5160994+04:00"},{"id":41176,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"5aed64f2f61be210a303b341a970b0cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/witness_objects.hpp#27-132","gmt_create":"2026-04-30T12:35:27.5171032+04:00","gmt_modified":"2026-04-30T12:35:27.5171032+04:00"},{"id":41177,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"02a1a9fcc78ccfc4daf328d04696eb6f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#114-124","gmt_create":"2026-04-30T12:35:27.5176534+04:00","gmt_modified":"2026-04-30T12:35:27.5176534+04:00"},{"id":41178,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"971acfd6fe75fe0b8a1522de5c46bf48","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/witness_objects.hpp#47-61","gmt_create":"2026-04-30T12:35:27.5176534+04:00","gmt_modified":"2026-04-30T12:35:27.5176534+04:00"},{"id":41179,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"ad1ea51f6c6764f6694b4b89a834e8f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#110-128","gmt_create":"2026-04-30T12:35:27.5176534+04:00","gmt_modified":"2026-04-30T12:35:27.5176534+04:00"},{"id":41180,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"ffdc85ed129bbf1af13ac8fb289ef5cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4887-4906","gmt_create":"2026-04-30T12:35:27.5186566+04:00","gmt_modified":"2026-04-30T12:35:27.5186566+04:00"},{"id":41181,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"61447f1b270e050eaf1594622e8344cb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#303-357","gmt_create":"2026-04-30T12:35:27.5186566+04:00","gmt_modified":"2026-04-30T12:35:27.5186566+04:00"},{"id":41182,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"87460891e469970ebd1b4357e65a305d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2561-2591","gmt_create":"2026-04-30T12:35:27.5186566+04:00","gmt_modified":"2026-04-30T12:35:27.5186566+04:00"},{"id":41183,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"e8bcacd1aeb9acccff2e7846bdb418ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2596-2612","gmt_create":"2026-04-30T12:35:27.5322619+04:00","gmt_modified":"2026-04-30T12:35:27.5322619+04:00"},{"id":41184,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"c1530ddb1ea5d36cd757849d7b1bae47","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2614-2631","gmt_create":"2026-04-30T12:35:27.5327651+04:00","gmt_modified":"2026-04-30T12:35:27.5327651+04:00"},{"id":41185,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"e233bb5840d58fff00c516dfc7186b2f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#125-128","gmt_create":"2026-04-30T12:35:27.5332786+04:00","gmt_modified":"2026-04-30T12:35:27.5332786+04:00"},{"id":41186,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"3addab2306735a8fd2b97c7337a752aa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5473-5545","gmt_create":"2026-04-30T12:35:27.5332786+04:00","gmt_modified":"2026-04-30T12:35:27.5332786+04:00"},{"id":41187,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"cf15af9ccdfa43fad1c61be4c143bb9f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5515-5529","gmt_create":"2026-04-30T12:35:27.5338075+04:00","gmt_modified":"2026-04-30T12:35:27.5338075+04:00"},{"id":41188,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"9f5944a7feb01c0c201e4a490c1c6d47","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/hardfork.d/12.hf#1-7","gmt_create":"2026-04-30T12:35:27.5343326+04:00","gmt_modified":"2026-04-30T12:35:27.5343326+04:00"},{"id":41189,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"d2f89808b761a3c0eca43468d945f372","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1721","gmt_create":"2026-04-30T12:35:27.5343326+04:00","gmt_modified":"2026-04-30T12:35:27.5343326+04:00"},{"id":41190,"source_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","target_id":"0fda0369897c65053dee851ef9ec01f9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#37-612","gmt_create":"2026-04-30T12:35:27.5349376+04:00","gmt_modified":"2026-04-30T12:35:27.5349376+04:00"},{"id":41277,"source_id":"b4bd3a3265ac695da5624024015e0e81","target_id":"18300366cc04c934739121e96aa33a18","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 2520-2590","gmt_create":"2026-04-30T12:37:21.0215773+04:00","gmt_modified":"2026-04-30T12:37:21.0215773+04:00"},{"id":41279,"source_id":"d72b348a2c3c7943e4a7abb7dbdaa751","target_id":"5c8f4ea594d62170eaa300eb27c60cab","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 285-289","gmt_create":"2026-04-30T12:37:21.0225773+04:00","gmt_modified":"2026-04-30T12:37:21.0225773+04:00"},{"id":41304,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"0dd2a38630da83b11fb3596ad4d60705","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/include/graphene/plugins/witness/witness.hpp","gmt_create":"2026-04-30T12:39:24.1868037+04:00","gmt_modified":"2026-04-30T12:39:24.1868037+04:00"},{"id":41305,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T12:39:24.1868037+04:00","gmt_modified":"2026-04-30T12:39:24.1868037+04:00"},{"id":41306,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f8bd5a2c3a4664ae9d5ec472684610dc","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp","gmt_create":"2026-04-30T12:39:24.1868037+04:00","gmt_modified":"2026-04-30T12:39:24.1868037+04:00"},{"id":41307,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"a4f11ca2018649a28877cfdeecdff9a6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness_api/plugin.cpp","gmt_create":"2026-04-30T12:39:24.1868037+04:00","gmt_modified":"2026-04-30T12:39:24.1868037+04:00"},{"id":41308,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cf72debd284e30d5218a88ae08868205","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/witness_objects.hpp","gmt_create":"2026-04-30T12:39:24.1868037+04:00","gmt_modified":"2026-04-30T12:39:24.1868037+04:00"},{"id":41309,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"bebd7920dd0967c6039c2adb16d4c52c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/chain_objects.hpp","gmt_create":"2026-04-30T12:39:24.187887+04:00","gmt_modified":"2026-04-30T12:39:24.187887+04:00"},{"id":41310,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T12:39:24.187887+04:00","gmt_modified":"2026-04-30T12:39:24.187887+04:00"},{"id":41311,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T12:39:24.187887+04:00","gmt_modified":"2026-04-30T12:39:24.187887+04:00"},{"id":41312,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"75b9bb8cfd2db41c21f328241d191f32","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/fork_database.hpp","gmt_create":"2026-04-30T12:39:24.1884644+04:00","gmt_modified":"2026-04-30T12:39:24.1884644+04:00"},{"id":41313,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T12:39:24.1884644+04:00","gmt_modified":"2026-04-30T12:39:24.1884644+04:00"},{"id":41314,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"ebd71fe58bebecee1b2afacbe66909ca","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/time/time.hpp","gmt_create":"2026-04-30T12:39:24.1884644+04:00","gmt_modified":"2026-04-30T12:39:24.1884644+04:00"},{"id":41315,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"13c87583e5739bb6062ee5706cbed132","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/time/time.cpp","gmt_create":"2026-04-30T12:39:24.1884644+04:00","gmt_modified":"2026-04-30T12:39:24.1884644+04:00"},{"id":41316,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"b58bf8be210d82c70605d7f2482ced82","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/network/ntp.cpp","gmt_create":"2026-04-30T12:39:24.188967+04:00","gmt_modified":"2026-04-30T12:39:24.188967+04:00"},{"id":41317,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"fcabf234b34f00b60b0d784b2da5a052","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: programs/vizd/main.cpp","gmt_create":"2026-04-30T12:39:24.188967+04:00","gmt_modified":"2026-04-30T12:39:24.188967+04:00"},{"id":41318,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-30T12:39:24.1893352+04:00","gmt_modified":"2026-04-30T12:39:24.1893352+04:00"},{"id":41319,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"b4b9efd79d5b3c9fea00fccd613b2046","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/protocol/include/graphene/protocol/config.hpp","gmt_create":"2026-04-30T12:39:24.1898379+04:00","gmt_modified":"2026-04-30T12:39:24.1898379+04:00"},{"id":41320,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T12:39:24.1898379+04:00","gmt_modified":"2026-04-30T12:39:24.1898379+04:00"},{"id":41321,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"bb293be9318768f10f69c80fd6b68517","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config_witness.ini","gmt_create":"2026-04-30T12:39:24.1898379+04:00","gmt_modified":"2026-04-30T12:39:24.1898379+04:00"},{"id":41322,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"448c0fd26faf791081a54cd407662e4d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41323,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"a64d5e5f1d092e1fd6a7916d048be8da","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41324,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f0afc0a1f80132e4bf15ac9ff156e256","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness_guard/witness_guard.cpp","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41325,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"7ae785f9d5ab154dce6f8eb295b93456","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/global_property_object.hpp","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41326,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cd8c02da5ea31d3411ad151149d2f64e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: programs/vizd/main.cpp#63-92","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41327,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"2d883d06f58fd34d81e8588c75185aa9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#34-68","gmt_create":"2026-04-30T12:39:24.1904439+04:00","gmt_modified":"2026-04-30T12:39:24.1904439+04:00"},{"id":41328,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"b6e11846d82ee129d5956cf9b8cbbea8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#59-118","gmt_create":"2026-04-30T12:39:24.1914467+04:00","gmt_modified":"2026-04-30T12:39:24.1914467+04:00"},{"id":41329,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"68421d68d4a7045f55767bcf48a402ad","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp#11-48","gmt_create":"2026-04-30T12:39:24.1914467+04:00","gmt_modified":"2026-04-30T12:39:24.1914467+04:00"},{"id":41330,"source_id":"a64d5e5f1d092e1fd6a7916d048be8da","target_id":"68421d68d4a7045f55767bcf48a402ad","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 11-48","gmt_create":"2026-04-30T12:39:24.1914467+04:00","gmt_modified":"2026-04-30T12:39:24.1914467+04:00"},{"id":41331,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"262c71a35dc67c134fb0ac33f44ffb3c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#27-78","gmt_create":"2026-04-30T12:39:24.1914467+04:00","gmt_modified":"2026-04-30T12:39:24.1914467+04:00"},{"id":41332,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"262c71a35dc67c134fb0ac33f44ffb3c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-78","gmt_create":"2026-04-30T12:39:24.1914467+04:00","gmt_modified":"2026-04-30T12:39:24.1914467+04:00"},{"id":41333,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cda9a1d47dfdb3a7374fa817887892c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp#56-98","gmt_create":"2026-04-30T12:39:24.192973+04:00","gmt_modified":"2026-04-30T12:39:24.192973+04:00"},{"id":41334,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f5891db138d66a58674791b9e99bd337","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#13-28","gmt_create":"2026-04-30T12:39:24.192973+04:00","gmt_modified":"2026-04-30T12:39:24.192973+04:00"},{"id":41335,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"51169b91af554f837e41d2913dacad48","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#37-83","gmt_create":"2026-04-30T12:39:24.192973+04:00","gmt_modified":"2026-04-30T12:39:24.192973+04:00"},{"id":41336,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"5aed64f2f61be210a303b341a970b0cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/witness_objects.hpp#27-132","gmt_create":"2026-04-30T12:39:24.1939785+04:00","gmt_modified":"2026-04-30T12:39:24.1939785+04:00"},{"id":41337,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"47b98e10075d52a89428f617d837a5e5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/chain_objects.hpp#174-201","gmt_create":"2026-04-30T12:39:24.1939785+04:00","gmt_modified":"2026-04-30T12:39:24.1939785+04:00"},{"id":41338,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"42aa356d9e26fadf05fda749f1d89cff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#53-81","gmt_create":"2026-04-30T12:39:24.1949771+04:00","gmt_modified":"2026-04-30T12:39:24.1949771+04:00"},{"id":41339,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"19e78b124cb1653f5e72af6789493e08","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/time/time.cpp#13-53","gmt_create":"2026-04-30T12:39:24.1949771+04:00","gmt_modified":"2026-04-30T12:39:24.1949771+04:00"},{"id":41340,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1bf53ebbc25ba8c147446f02ce5e44e2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1267-1276","gmt_create":"2026-04-30T12:39:24.195481+04:00","gmt_modified":"2026-04-30T12:39:24.195481+04:00"},{"id":41341,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cecb2c27bddde9783761743ffbbfac88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp#50-55","gmt_create":"2026-04-30T12:39:24.195481+04:00","gmt_modified":"2026-04-30T12:39:24.195481+04:00"},{"id":41342,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"4a84a6b27fbcb47e0994f0bda545816f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#206-249","gmt_create":"2026-04-30T12:39:24.1960586+04:00","gmt_modified":"2026-04-30T12:39:24.1960586+04:00"},{"id":41343,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"2768582067cb0ed11345dd25d7b2a582","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#83-191","gmt_create":"2026-04-30T12:39:24.1969866+04:00","gmt_modified":"2026-04-30T12:39:24.1969866+04:00"},{"id":41344,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"2768582067cb0ed11345dd25d7b2a582","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 83-191","gmt_create":"2026-04-30T12:39:24.1969866+04:00","gmt_modified":"2026-04-30T12:39:24.1969866+04:00"},{"id":41345,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"9bfd91580e85c0c0436b214ea3ff332a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#360-369","gmt_create":"2026-04-30T12:39:24.1969866+04:00","gmt_modified":"2026-04-30T12:39:24.1969866+04:00"},{"id":41346,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"9bfd91580e85c0c0436b214ea3ff332a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 360-369","gmt_create":"2026-04-30T12:39:24.1979868+04:00","gmt_modified":"2026-04-30T12:39:24.1979868+04:00"},{"id":41347,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"3d0cbd79a1648b655b90b7629307cad1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#206-276","gmt_create":"2026-04-30T12:39:24.1989873+04:00","gmt_modified":"2026-04-30T12:39:24.1989873+04:00"},{"id":41348,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"6abe7f6efde355ee9f2d7cf0776677ff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#278-423","gmt_create":"2026-04-30T12:39:24.1989873+04:00","gmt_modified":"2026-04-30T12:39:24.1989873+04:00"},{"id":41349,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1cf7bf28dd5011954754492ccf7873f5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#447-471","gmt_create":"2026-04-30T12:39:24.1999876+04:00","gmt_modified":"2026-04-30T12:39:24.1999876+04:00"},{"id":41350,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"31e5e32f87baccd25fbb2183951a67bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#590-695","gmt_create":"2026-04-30T12:39:24.1999876+04:00","gmt_modified":"2026-04-30T12:39:24.1999876+04:00"},{"id":41351,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1844592144295f47f4238341e8868e6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#263-266","gmt_create":"2026-04-30T12:39:24.1999876+04:00","gmt_modified":"2026-04-30T12:39:24.1999876+04:00"},{"id":41352,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f82119bed73a4a0e0870145102b96214","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#455-544","gmt_create":"2026-04-30T12:39:24.2015956+04:00","gmt_modified":"2026-04-30T12:39:24.2015956+04:00"},{"id":41353,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"f82119bed73a4a0e0870145102b96214","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 455-544","gmt_create":"2026-04-30T12:39:24.2015956+04:00","gmt_modified":"2026-04-30T12:39:24.2015956+04:00"},{"id":41354,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"15a3537ebe2816e5402e7fb60462b58e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4317-4332","gmt_create":"2026-04-30T12:39:24.2015956+04:00","gmt_modified":"2026-04-30T12:39:24.2015956+04:00"},{"id":41355,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"6af53e8de30910078bc6fd9dab1d2f7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/time/time.cpp#74-76","gmt_create":"2026-04-30T12:39:24.2015956+04:00","gmt_modified":"2026-04-30T12:39:24.2015956+04:00"},{"id":41356,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"0ef7b0d7933da804905c2ff76f92cd94","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2824-2839","gmt_create":"2026-04-30T12:39:24.2024959+04:00","gmt_modified":"2026-04-30T12:39:24.2024959+04:00"},{"id":41357,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"667d252413c23e04beb2c069531a1372","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2871-2886","gmt_create":"2026-04-30T12:39:24.2024959+04:00","gmt_modified":"2026-04-30T12:39:24.2024959+04:00"},{"id":41358,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"62ea8f0eed608d8eb1dd0911e43f28c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1223-1267","gmt_create":"2026-04-30T12:39:24.2024959+04:00","gmt_modified":"2026-04-30T12:39:24.2024959+04:00"},{"id":41359,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1b91062fbd3e8ce21a7ec705a5ef21ae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#125-133","gmt_create":"2026-04-30T12:39:24.2034958+04:00","gmt_modified":"2026-04-30T12:39:24.2034958+04:00"},{"id":41360,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c57b368c9aec32de084799a61fc21d81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#149-155","gmt_create":"2026-04-30T12:39:24.2034958+04:00","gmt_modified":"2026-04-30T12:39:24.2034958+04:00"},{"id":41361,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"9a1726ad4c4d7942894eafbb2fb7c20a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#222-224","gmt_create":"2026-04-30T12:39:24.2034958+04:00","gmt_modified":"2026-04-30T12:39:24.2034958+04:00"},{"id":41362,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"2b851e123aa78f2afb16a52472781e64","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#228-233","gmt_create":"2026-04-30T12:39:24.2044954+04:00","gmt_modified":"2026-04-30T12:39:24.2044954+04:00"},{"id":41363,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"410cd37dc3943354d37ce7542843e6c0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#301-328","gmt_create":"2026-04-30T12:39:24.2044954+04:00","gmt_modified":"2026-04-30T12:39:24.2044954+04:00"},{"id":41364,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"410cd37dc3943354d37ce7542843e6c0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 301-328","gmt_create":"2026-04-30T12:39:24.2044954+04:00","gmt_modified":"2026-04-30T12:39:24.2044954+04:00"},{"id":41365,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"804dc1cd57f82825de2acc450a8496c3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#330-408","gmt_create":"2026-04-30T12:39:24.2054962+04:00","gmt_modified":"2026-04-30T12:39:24.2054962+04:00"},{"id":41366,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"804dc1cd57f82825de2acc450a8496c3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 330-408","gmt_create":"2026-04-30T12:39:24.2054962+04:00","gmt_modified":"2026-04-30T12:39:24.2054962+04:00"},{"id":41367,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"d572e2edecf45b7b050d30cbb14368d8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/protocol/include/graphene/protocol/config.hpp#57-58","gmt_create":"2026-04-30T12:39:24.2054962+04:00","gmt_modified":"2026-04-30T12:39:24.2054962+04:00"},{"id":41368,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"a3b204b149312d56bea1667800a95fb6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config.ini#99-103","gmt_create":"2026-04-30T12:39:24.2064968+04:00","gmt_modified":"2026-04-30T12:39:24.2064968+04:00"},{"id":41369,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f72faf82a21dd9049d68549d9c7e5c4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_witness.ini#76-80","gmt_create":"2026-04-30T12:39:24.2064968+04:00","gmt_modified":"2026-04-30T12:39:24.2064968+04:00"},{"id":41370,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"9ea04ad05deddb408f8a972fd04ba0d0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config_witness.ini#128-141","gmt_create":"2026-04-30T12:39:24.2064968+04:00","gmt_modified":"2026-04-30T12:39:24.2064968+04:00"},{"id":41371,"source_id":"bb293be9318768f10f69c80fd6b68517","target_id":"9ea04ad05deddb408f8a972fd04ba0d0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 128-141","gmt_create":"2026-04-30T12:39:24.2064968+04:00","gmt_modified":"2026-04-30T12:39:24.2064968+04:00"},{"id":41372,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c5701be8b76f9a4a85b659f219a10f95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#509-555","gmt_create":"2026-04-30T12:39:24.2064968+04:00","gmt_modified":"2026-04-30T12:39:24.2064968+04:00"},{"id":41373,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"7f2c3ab5ba63b977d9642aa1c78a2c43","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#120-169","gmt_create":"2026-04-30T12:39:24.2074969+04:00","gmt_modified":"2026-04-30T12:39:24.2074969+04:00"},{"id":41374,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"737d623fe091f7ae2629dcda699b0efa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#171-192","gmt_create":"2026-04-30T12:39:24.2074969+04:00","gmt_modified":"2026-04-30T12:39:24.2074969+04:00"},{"id":41375,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"fba8be1bbb523071f8ce7ad55a13d0f2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/include/graphene/plugins/witness/witness.hpp#31","gmt_create":"2026-04-30T12:39:24.2094956+04:00","gmt_modified":"2026-04-30T12:39:24.2094956+04:00"},{"id":41376,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"2a7a24b7119edca00eb0b21200f484ec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#88","gmt_create":"2026-04-30T12:39:24.2094956+04:00","gmt_modified":"2026-04-30T12:39:24.2094956+04:00"},{"id":41377,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c9048f7e0344e917d91b3b45d3804a0d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#73","gmt_create":"2026-04-30T12:39:24.2104954+04:00","gmt_modified":"2026-04-30T12:39:24.2104954+04:00"},{"id":41378,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"ff4cacfd8a6a1ce746ce49bd2259ef47","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#151-166","gmt_create":"2026-04-30T12:39:24.2104954+04:00","gmt_modified":"2026-04-30T12:39:24.2104954+04:00"},{"id":41379,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"78279a6057ca0eaea7f987e920fada7f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1456-1471","gmt_create":"2026-04-30T12:39:24.2104954+04:00","gmt_modified":"2026-04-30T12:39:24.2104954+04:00"},{"id":41380,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"95e9eb6df5c5b54fc25131e15cebca7b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#269-274","gmt_create":"2026-04-30T12:39:24.2104954+04:00","gmt_modified":"2026-04-30T12:39:24.2104954+04:00"},{"id":41381,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"4c8c235c40a9885b9ce181cc9af786fe","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2807-2839","gmt_create":"2026-04-30T12:39:24.2121026+04:00","gmt_modified":"2026-04-30T12:39:24.2121026+04:00"},{"id":41382,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"29354043db86eeb48566453a908645c7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2897-2914","gmt_create":"2026-04-30T12:39:24.2126725+04:00","gmt_modified":"2026-04-30T12:39:24.2126725+04:00"},{"id":41383,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"6e4547d3d8a2b1ce7fb2eb8442ba9631","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1294-1311","gmt_create":"2026-04-30T12:39:24.2140206+04:00","gmt_modified":"2026-04-30T12:39:24.2140206+04:00"},{"id":41384,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"0c5e33130a4b0128f85c5ef5837b2837","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#338-407","gmt_create":"2026-04-30T12:39:24.2145431+04:00","gmt_modified":"2026-04-30T12:39:24.2145431+04:00"},{"id":41385,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"b4b9171ebcdf9b3750b66cea688f5e6b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#411-419","gmt_create":"2026-04-30T12:39:24.215077+04:00","gmt_modified":"2026-04-30T12:39:24.215077+04:00"},{"id":41386,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"673f7fff8a03580c3caedc629fc67cd4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#60","gmt_create":"2026-04-30T12:39:24.2156096+04:00","gmt_modified":"2026-04-30T12:39:24.2156096+04:00"},{"id":41387,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"dbf1a067fe97d23702c1dcb8e2df53b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1890-1892","gmt_create":"2026-04-30T12:39:24.2156096+04:00","gmt_modified":"2026-04-30T12:39:24.2156096+04:00"},{"id":41388,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"2ad181689b70c433e1ec262fbbedb608","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4536-4573","gmt_create":"2026-04-30T12:39:24.2161297+04:00","gmt_modified":"2026-04-30T12:39:24.2161297+04:00"},{"id":41389,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"73337c954cb4cc654d9a0b55b95b2480","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5530-5655","gmt_create":"2026-04-30T12:39:24.2161297+04:00","gmt_modified":"2026-04-30T12:39:24.2161297+04:00"},{"id":41390,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"f46e3fd7859017b5e2c1e7b5c296cb4f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#197-246","gmt_create":"2026-04-30T12:39:24.2171332+04:00","gmt_modified":"2026-04-30T12:39:24.2171332+04:00"},{"id":41391,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"f46e3fd7859017b5e2c1e7b5c296cb4f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 197-246","gmt_create":"2026-04-30T12:39:24.2171332+04:00","gmt_modified":"2026-04-30T12:39:24.2171332+04:00"},{"id":41392,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"9d47a587156b7ae6cd73b0e5b5ad4f56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#252-294","gmt_create":"2026-04-30T12:39:24.2177181+04:00","gmt_modified":"2026-04-30T12:39:24.2177181+04:00"},{"id":41393,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"9d47a587156b7ae6cd73b0e5b5ad4f56","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 252-294","gmt_create":"2026-04-30T12:39:24.2177181+04:00","gmt_modified":"2026-04-30T12:39:24.2177181+04:00"},{"id":41394,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"322bbb26c4fa89c5b6c197da6defb3b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#301-408","gmt_create":"2026-04-30T12:39:24.2183088+04:00","gmt_modified":"2026-04-30T12:39:24.2183088+04:00"},{"id":41395,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"322bbb26c4fa89c5b6c197da6defb3b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 301-408","gmt_create":"2026-04-30T12:39:24.2183088+04:00","gmt_modified":"2026-04-30T12:39:24.2183088+04:00"},{"id":41396,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"4c7449e318e56d7531d2b650c48cda91","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_guard/witness_guard.cpp#410-555","gmt_create":"2026-04-30T12:39:24.2183088+04:00","gmt_modified":"2026-04-30T12:39:24.2183088+04:00"},{"id":41397,"source_id":"f0afc0a1f80132e4bf15ac9ff156e256","target_id":"4c7449e318e56d7531d2b650c48cda91","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 410-555","gmt_create":"2026-04-30T12:39:24.2188118+04:00","gmt_modified":"2026-04-30T12:39:24.2188118+04:00"},{"id":41398,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"0dec6783542ea54ba7d81fbeb930e442","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#30-49","gmt_create":"2026-04-30T12:39:24.2188118+04:00","gmt_modified":"2026-04-30T12:39:24.2188118+04:00"},{"id":41399,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"85675dcfc30f216052bdb5cedc7b435c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#75-91","gmt_create":"2026-04-30T12:39:24.2193374+04:00","gmt_modified":"2026-04-30T12:39:24.2193374+04:00"},{"id":41400,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"7f42fa8b501a589d403cb682d1620581","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#102-125","gmt_create":"2026-04-30T12:39:24.2198543+04:00","gmt_modified":"2026-04-30T12:39:24.2198543+04:00"},{"id":41401,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"17a2c941cfb814db6c1623046d8dac1e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#127-159","gmt_create":"2026-04-30T12:39:24.2202891+04:00","gmt_modified":"2026-04-30T12:39:24.2202891+04:00"},{"id":41402,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"53a82d703bff53e589353336964d2eed","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#161-169","gmt_create":"2026-04-30T12:39:24.2202891+04:00","gmt_modified":"2026-04-30T12:39:24.2202891+04:00"},{"id":41403,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"4fcf4072cf8ebe5cd019e9a0da762901","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#171-203","gmt_create":"2026-04-30T12:39:24.2208743+04:00","gmt_modified":"2026-04-30T12:39:24.2208743+04:00"},{"id":41404,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c4f66fb8fb1d6eeb25bd48eec2ba80a6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#102-159","gmt_create":"2026-04-30T12:39:24.2219552+04:00","gmt_modified":"2026-04-30T12:39:24.2219552+04:00"},{"id":41405,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"68e0135d2e3b03eff760c57654b97092","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness_api/plugin.cpp#161-203","gmt_create":"2026-04-30T12:39:24.2224985+04:00","gmt_modified":"2026-04-30T12:39:24.2224985+04:00"},{"id":41406,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"eeebc7e5a0ce3570715e7391da03b065","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/witness_objects.hpp#104-171","gmt_create":"2026-04-30T12:39:24.2230377+04:00","gmt_modified":"2026-04-30T12:39:24.2230377+04:00"},{"id":41407,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"ef4797348572b382b96b9d19a362eed7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/fork_database.hpp#90-95","gmt_create":"2026-04-30T12:39:24.2247256+04:00","gmt_modified":"2026-04-30T12:39:24.2247256+04:00"},{"id":41408,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"09dcfe86b88d969bbe651733cb34fc2d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/global_property_object.hpp#139","gmt_create":"2026-04-30T12:39:24.2257535+04:00","gmt_modified":"2026-04-30T12:39:24.2257535+04:00"},{"id":41409,"source_id":"7ae785f9d5ab154dce6f8eb295b93456","target_id":"09dcfe86b88d969bbe651733cb34fc2d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 139","gmt_create":"2026-04-30T12:39:24.2257535+04:00","gmt_modified":"2026-04-30T12:39:24.2257535+04:00"},{"id":41410,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"85e55e5f6d83a36cd6afac5fcb62fb42","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1626-1805","gmt_create":"2026-04-30T12:39:24.2274826+04:00","gmt_modified":"2026-04-30T12:39:24.2274826+04:00"},{"id":41411,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1d8a3a8529f55f725cbd52ef78db6a1f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4334-4463","gmt_create":"2026-04-30T12:39:24.2281758+04:00","gmt_modified":"2026-04-30T12:39:24.2281758+04:00"},{"id":41412,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"87584d47dc52c8658341b565e96c989d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#492-499","gmt_create":"2026-04-30T12:39:24.2286787+04:00","gmt_modified":"2026-04-30T12:39:24.2286787+04:00"},{"id":41413,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cda7dad93173bc2161ab2ff3c92e81ce","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/time/time.cpp#36-39","gmt_create":"2026-04-30T12:39:24.2305969+04:00","gmt_modified":"2026-04-30T12:39:24.2305969+04:00"},{"id":41414,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"73dca3cd312efbc6ecb517ae118fd869","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/network/ntp.cpp#184-201","gmt_create":"2026-04-30T12:39:24.2310995+04:00","gmt_modified":"2026-04-30T12:39:24.2310995+04:00"},{"id":41415,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"c69f6ef1a64e88829a12d7ab4c190897","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: thirdparty/fc/src/network/ntp.cpp#236-266","gmt_create":"2026-04-30T12:39:24.2312447+04:00","gmt_modified":"2026-04-30T12:39:24.2312447+04:00"},{"id":41416,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"26905e829dbbc0af740b97400068843b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#255-271","gmt_create":"2026-04-30T12:39:24.234719+04:00","gmt_modified":"2026-04-30T12:39:24.234719+04:00"},{"id":41417,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"1eb7cc21b9daf17a2c908f3121bcf2f0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#387-396","gmt_create":"2026-04-30T12:39:24.2350013+04:00","gmt_modified":"2026-04-30T12:39:24.2350013+04:00"},{"id":41418,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"cc4d2fca7cfbc2ed2aa9dc9016360fb5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2826-2836","gmt_create":"2026-04-30T12:39:24.2361746+04:00","gmt_modified":"2026-04-30T12:39:24.2361746+04:00"},{"id":41419,"source_id":"c93fa44d-294e-4802-9676-e73b1a162b2b","target_id":"e0e1ada694da4e9e256e0d6d39aa73e5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#2873-2883","gmt_create":"2026-04-30T12:39:24.2367541+04:00","gmt_modified":"2026-04-30T12:39:24.2367541+04:00"},{"id":41420,"source_id":"f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce","target_id":"6ae7ebac-bb25-4499-8364-0f2f7ac99d8a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce -\u003e 6ae7ebac-bb25-4499-8364-0f2f7ac99d8a","gmt_create":"2026-04-30T12:41:43.9043639+04:00","gmt_modified":"2026-04-30T12:41:43.9043639+04:00"},{"id":41421,"source_id":"ecd87c29-4938-4318-9bbb-b3c2a87a2d22","target_id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ecd87c29-4938-4318-9bbb-b3c2a87a2d22 -\u003e 61b10976-8eeb-45d9-a3fa-3b71c7d30939","gmt_create":"2026-04-30T12:41:43.9048693+04:00","gmt_modified":"2026-04-30T12:41:43.9048693+04:00"},{"id":41423,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-30T13:09:00.7529864+04:00","gmt_modified":"2026-04-30T13:09:00.7529864+04:00"},{"id":41424,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"bd196d115b6bd3d5310dfa247f1e25b2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","gmt_create":"2026-04-30T13:09:00.7535048+04:00","gmt_modified":"2026-04-30T13:09:00.7535048+04:00"},{"id":41425,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"991938d306a547ff48a759fb9bd1c5a4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp","gmt_create":"2026-04-30T13:09:00.7535048+04:00","gmt_modified":"2026-04-30T13:09:00.7535048+04:00"},{"id":41426,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"d8e14923de7e4be8f600e264a03ea281","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp","gmt_create":"2026-04-30T13:09:00.7535048+04:00","gmt_modified":"2026-04-30T13:09:00.7535048+04:00"},{"id":41427,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"dc43b9a20a2ae22effbe51aecf8ca751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/CMakeLists.txt","gmt_create":"2026-04-30T13:09:00.7535048+04:00","gmt_modified":"2026-04-30T13:09:00.7535048+04:00"},{"id":41428,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"55b60ae8ffadd70d41ebd01151dcb237","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/snapshot.json","gmt_create":"2026-04-30T13:09:00.7540292+04:00","gmt_modified":"2026-04-30T13:09:00.7540292+04:00"},{"id":41429,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"2eb0f5e7350fc53dec7939bb93e824ac","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/snapshot-testnet.json","gmt_create":"2026-04-30T13:09:00.7540292+04:00","gmt_modified":"2026-04-30T13:09:00.7540292+04:00"},{"id":41430,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"4d5bf798ac6e167d6d0e20a669431373","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: documentation/snapshot-plugin.md","gmt_create":"2026-04-30T13:09:00.7540292+04:00","gmt_modified":"2026-04-30T13:09:00.7540292+04:00"},{"id":41431,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"6c94b84fdfd5c7016b5eeadf8099133e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/plugin.cpp","gmt_create":"2026-04-30T13:09:00.7540292+04:00","gmt_modified":"2026-04-30T13:09:00.7540292+04:00"},{"id":41432,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ae7188ee9396d8d8aca884b96e9bc4c1","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/chain/include/graphene/plugins/chain/plugin.hpp","gmt_create":"2026-04-30T13:09:00.7540292+04:00","gmt_modified":"2026-04-30T13:09:00.7540292+04:00"},{"id":41433,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41434,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"609365f8572668c8cf1e1cfa497989e4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41435,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ade43b15adadb0a3215b2b7a6866ef22","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41436,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"7550b6fcbbc44fc4df4f050d5b4fb04a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/witness/witness.cpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41437,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"51c2f2c072611ae01260d171fbd12b59","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/interprocess/file_mutex.cpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41438,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41439,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-30T13:09:00.7545483+04:00","gmt_modified":"2026-04-30T13:09:00.7545483+04:00"},{"id":41440,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-30T13:09:00.7550662+04:00","gmt_modified":"2026-04-30T13:09:00.7550662+04:00"},{"id":41441,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T13:09:00.7550662+04:00","gmt_modified":"2026-04-30T13:09:00.7550662+04:00"},{"id":41442,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"d71a233c4690ddd107d80d74f5956ebf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/log/logger_config.cpp","gmt_create":"2026-04-30T13:09:00.7550662+04:00","gmt_modified":"2026-04-30T13:09:00.7550662+04:00"},{"id":41443,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"a53dc201b0a9ff736da577ae1c524abb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/fc/src/log/console_appender.cpp","gmt_create":"2026-04-30T13:09:00.7550662+04:00","gmt_modified":"2026-04-30T13:09:00.7550662+04:00"},{"id":41444,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"1ade3cebbc11a4634bcdf1a7fdb2756e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: thirdparty/chainbase/src/chainbase.cpp","gmt_create":"2026-04-30T13:09:00.7550662+04:00","gmt_modified":"2026-04-30T13:09:00.7550662+04:00"},{"id":41445,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"f2c0625ed2d13bb0a3699a45bf25d6cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1-50","gmt_create":"2026-04-30T13:09:00.7555778+04:00","gmt_modified":"2026-04-30T13:09:00.7555778+04:00"},{"id":41446,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"b49193d53f2bca5e5a84c905c1f90429","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#1-88","gmt_create":"2026-04-30T13:09:00.7555778+04:00","gmt_modified":"2026-04-30T13:09:00.7555778+04:00"},{"id":41447,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ca74187bf1151ee3b389754df4ce08d1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp#1-52","gmt_create":"2026-04-30T13:09:00.7555778+04:00","gmt_modified":"2026-04-30T13:09:00.7555778+04:00"},{"id":41448,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"60ec378a66a7653324d69f456e1242c4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/CMakeLists.txt#1-52","gmt_create":"2026-04-30T13:09:00.7560916+04:00","gmt_modified":"2026-04-30T13:09:00.7560916+04:00"},{"id":41449,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"93f965590673de9c5fe2a34fbc24af1c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#42-76","gmt_create":"2026-04-30T13:09:00.7560916+04:00","gmt_modified":"2026-04-30T13:09:00.7560916+04:00"},{"id":41450,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"98907d07c594fe14c157ba203649b596","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp#16-52","gmt_create":"2026-04-30T13:09:00.7560916+04:00","gmt_modified":"2026-04-30T13:09:00.7560916+04:00"},{"id":41451,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"aba83bcb80fe7ecb8f1f224f2fca05da","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp#30-158","gmt_create":"2026-04-30T13:09:00.7566029+04:00","gmt_modified":"2026-04-30T13:09:00.7566029+04:00"},{"id":41452,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"33fc7efcd171685ef3235423dc636724","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#675-780","gmt_create":"2026-04-30T13:09:00.7566029+04:00","gmt_modified":"2026-04-30T13:09:00.7566029+04:00"},{"id":41453,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"0a6e409382fdf7cc6924a9f918b5a4d8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp#37-107","gmt_create":"2026-04-30T13:09:00.7566029+04:00","gmt_modified":"2026-04-30T13:09:00.7566029+04:00"},{"id":41454,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"d419300bbe8000129fd9765417390c9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#885-987","gmt_create":"2026-04-30T13:09:00.7571149+04:00","gmt_modified":"2026-04-30T13:09:00.7571149+04:00"},{"id":41455,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"c331a645eb7848bda9b3f651866478ec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#789-883","gmt_create":"2026-04-30T13:09:00.7571149+04:00","gmt_modified":"2026-04-30T13:09:00.7571149+04:00"},{"id":41456,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"06ca849a27b79d1edd6a6faaabf7a1fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1400-1484","gmt_create":"2026-04-30T13:09:00.7571149+04:00","gmt_modified":"2026-04-30T13:09:00.7571149+04:00"},{"id":41457,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"9102ca0b920a6d527e069776bf786565","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1046-1288","gmt_create":"2026-04-30T13:09:00.7576256+04:00","gmt_modified":"2026-04-30T13:09:00.7576256+04:00"},{"id":41458,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"272ad74758e94f746c862c4c91c17496","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1902-2038","gmt_create":"2026-04-30T13:09:00.7576256+04:00","gmt_modified":"2026-04-30T13:09:00.7576256+04:00"},{"id":41459,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ea6973621046033cdcd6899b7a2bcb0f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1470-1599","gmt_create":"2026-04-30T13:09:00.7576256+04:00","gmt_modified":"2026-04-30T13:09:00.7576256+04:00"},{"id":41460,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"2f7386ded19c5e4ae6581ef6148fdd81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2473-2510","gmt_create":"2026-04-30T13:09:00.7581379+04:00","gmt_modified":"2026-04-30T13:09:00.7581379+04:00"},{"id":41461,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"5fcc5bdcf25fd73b110eede565277186","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: documentation/snapshot-plugin.md#247-273","gmt_create":"2026-04-30T13:09:00.7581379+04:00","gmt_modified":"2026-04-30T13:09:00.7581379+04:00"},{"id":41462,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"7c62e5936f0fc7f60f9a5587800a2578","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1418-1436","gmt_create":"2026-04-30T13:09:00.7581379+04:00","gmt_modified":"2026-04-30T13:09:00.7581379+04:00"},{"id":41463,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"983d0185105181e4f539d636abc549c9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#737-743","gmt_create":"2026-04-30T13:09:00.7586495+04:00","gmt_modified":"2026-04-30T13:09:00.7586495+04:00"},{"id":41464,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"82acc28cade2d06dac2a207816ccf888","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1390-1484","gmt_create":"2026-04-30T13:09:00.7586495+04:00","gmt_modified":"2026-04-30T13:09:00.7586495+04:00"},{"id":41465,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"1d3d2cb1a9886c18b5c14d6f4bbbec7c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1440-1449","gmt_create":"2026-04-30T13:09:00.7586495+04:00","gmt_modified":"2026-04-30T13:09:00.7586495+04:00"},{"id":41466,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"de42aaaef014331a40dc6a645093a785","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/witness/witness.cpp#335-551","gmt_create":"2026-04-30T13:09:00.7591596+04:00","gmt_modified":"2026-04-30T13:09:00.7591596+04:00"},{"id":41467,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"e9427d96ecb45f8e18859dbaff6e2b3a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1326-1376","gmt_create":"2026-04-30T13:09:00.7591596+04:00","gmt_modified":"2026-04-30T13:09:00.7591596+04:00"},{"id":41468,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ddc5b6727e7907a53519cc63983aabb7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1426-1435","gmt_create":"2026-04-30T13:09:00.7591596+04:00","gmt_modified":"2026-04-30T13:09:00.7591596+04:00"},{"id":41469,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"a54238157d7db2d12e89ea767738f5ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#745-750","gmt_create":"2026-04-30T13:09:00.7596894+04:00","gmt_modified":"2026-04-30T13:09:00.7596894+04:00"},{"id":41470,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"8481665c6e787cad6255e9ace82fe2c2","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#697-700","gmt_create":"2026-04-30T13:09:00.7596894+04:00","gmt_modified":"2026-04-30T13:09:00.7596894+04:00"},{"id":41471,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"91b6373025370a39784ff61586453267","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2831-2845","gmt_create":"2026-04-30T13:09:00.7602036+04:00","gmt_modified":"2026-04-30T13:09:00.7602036+04:00"},{"id":41472,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"fa6088c57e5552b03a53d22a8b3371cd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1719-1748","gmt_create":"2026-04-30T13:09:00.7602036+04:00","gmt_modified":"2026-04-30T13:09:00.7602036+04:00"},{"id":41473,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"2ef1c85090d0812eda040eb10dbfab00","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1706-1748","gmt_create":"2026-04-30T13:09:00.7607314+04:00","gmt_modified":"2026-04-30T13:09:00.7607314+04:00"},{"id":41474,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"6c4fffc1a4b8a3dccdccf3bc8b6e478c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#490-560","gmt_create":"2026-04-30T13:09:00.7607314+04:00","gmt_modified":"2026-04-30T13:09:00.7607314+04:00"},{"id":41475,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"002084afc1181b400d0ac1f626010b50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2945-2959","gmt_create":"2026-04-30T13:09:00.7607314+04:00","gmt_modified":"2026-04-30T13:09:00.7607314+04:00"},{"id":41476,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"a9ac85c210bf25017dc2f3043429bcff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#441-5201","gmt_create":"2026-04-30T13:09:00.7607314+04:00","gmt_modified":"2026-04-30T13:09:00.7607314+04:00"},{"id":41477,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"4083d0aedccff773e235c49f483acdee","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#542-559","gmt_create":"2026-04-30T13:09:00.7612446+04:00","gmt_modified":"2026-04-30T13:09:00.7612446+04:00"},{"id":41478,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"87dbe393410d68cf0b46ab22827e33fe","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#3252-3290","gmt_create":"2026-04-30T13:09:00.7612446+04:00","gmt_modified":"2026-04-30T13:09:00.7612446+04:00"},{"id":41479,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"98c57a9cc27d3a9e444c74d23a63bf9e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#4945-4947","gmt_create":"2026-04-30T13:09:00.7612446+04:00","gmt_modified":"2026-04-30T13:09:00.7612446+04:00"},{"id":41480,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"2d706a9e6bc734297fc6693a4cec7176","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#5139-5140","gmt_create":"2026-04-30T13:09:00.7617705+04:00","gmt_modified":"2026-04-30T13:09:00.7617705+04:00"},{"id":41481,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"95d10140a46b090a8cea978c1c73a9bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database.hpp#337-338","gmt_create":"2026-04-30T13:09:00.7617705+04:00","gmt_modified":"2026-04-30T13:09:00.7617705+04:00"},{"id":41482,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"5b61f5ff88b75190fc4b2051750444dd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2976-3009","gmt_create":"2026-04-30T13:09:00.7622901+04:00","gmt_modified":"2026-04-30T13:09:00.7622901+04:00"},{"id":41483,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"133becde6f5eef3f56c38aa3650af39f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2468-2570","gmt_create":"2026-04-30T13:09:00.7622901+04:00","gmt_modified":"2026-04-30T13:09:00.7622901+04:00"},{"id":41484,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"7c3bbfa78db4dbdd170795e4ff786767","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#689-697","gmt_create":"2026-04-30T13:09:00.7622901+04:00","gmt_modified":"2026-04-30T13:09:00.7622901+04:00"},{"id":41485,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"de95ec3c9606ef77f32c319a1cee9d67","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5241-5274","gmt_create":"2026-04-30T13:09:00.7622901+04:00","gmt_modified":"2026-04-30T13:09:00.7622901+04:00"},{"id":41486,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"4ad076dd99ea06a22ba2703dfdfbef50","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#284-290","gmt_create":"2026-04-30T13:09:00.7629213+04:00","gmt_modified":"2026-04-30T13:09:00.7629213+04:00"},{"id":41487,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"d21d0e6c03944b9bd0683917197d45ec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#86-88","gmt_create":"2026-04-30T13:09:00.7629213+04:00","gmt_modified":"2026-04-30T13:09:00.7629213+04:00"},{"id":41488,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ce8c1f15287ef92650480373eef95fb8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#735-740","gmt_create":"2026-04-30T13:09:00.7629213+04:00","gmt_modified":"2026-04-30T13:09:00.7629213+04:00"},{"id":41489,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"474f1f81f21526cb90fc2564fdc36457","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1814-1862","gmt_create":"2026-04-30T13:09:00.763425+04:00","gmt_modified":"2026-04-30T13:09:00.763425+04:00"},{"id":41490,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"3fcde09e22fa6291183075924ea0ea2a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#772-785","gmt_create":"2026-04-30T13:09:00.763425+04:00","gmt_modified":"2026-04-30T13:09:00.763425+04:00"},{"id":41491,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"16865a1a8de25574f1f934ab4b21167f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1595-1624","gmt_create":"2026-04-30T13:09:00.763425+04:00","gmt_modified":"2026-04-30T13:09:00.763425+04:00"},{"id":41492,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"25271321cea3b037da1bd49f4a9c73e3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: documentation/snapshot-plugin.md#339-374","gmt_create":"2026-04-30T13:09:00.7639416+04:00","gmt_modified":"2026-04-30T13:09:00.7639416+04:00"},{"id":41493,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ffac59891823846e038c48de0f7fa754","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#585-649","gmt_create":"2026-04-30T13:09:00.7639416+04:00","gmt_modified":"2026-04-30T13:09:00.7639416+04:00"},{"id":41494,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"ce8fa82841cb9ff1bb572dde21cd2dca","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#673-677","gmt_create":"2026-04-30T13:09:00.7639416+04:00","gmt_modified":"2026-04-30T13:09:00.7639416+04:00"},{"id":41495,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"31a0e1cdb8f61a661ea048c18a0c31ab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#744-755","gmt_create":"2026-04-30T13:09:00.7639416+04:00","gmt_modified":"2026-04-30T13:09:00.7639416+04:00"},{"id":41496,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"e360b37afb60df02b8a51d89f141bf95","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#165-176","gmt_create":"2026-04-30T13:09:00.7644557+04:00","gmt_modified":"2026-04-30T13:09:00.7644557+04:00"},{"id":41497,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"a4b87380168ea56eda2691254c138879","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1587-1596","gmt_create":"2026-04-30T13:09:00.7644557+04:00","gmt_modified":"2026-04-30T13:09:00.7644557+04:00"},{"id":41498,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"0442d9dfa5137479a458da6803ce6d7d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1610-1620","gmt_create":"2026-04-30T13:09:00.7644557+04:00","gmt_modified":"2026-04-30T13:09:00.7644557+04:00"},{"id":41499,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"5f1666b71febd2ce3545e7b9c05598fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1812-1877","gmt_create":"2026-04-30T13:09:00.7644557+04:00","gmt_modified":"2026-04-30T13:09:00.7644557+04:00"},{"id":41500,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"f7cc310f8ee11ed3c2ac13ce575146d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp#24-34","gmt_create":"2026-04-30T13:09:00.7649772+04:00","gmt_modified":"2026-04-30T13:09:00.7649772+04:00"},{"id":41501,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"24d1f458412bbfade9d25c0ed1521322","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2598-2680","gmt_create":"2026-04-30T13:09:00.7655018+04:00","gmt_modified":"2026-04-30T13:09:00.7655018+04:00"},{"id":41502,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"985521912575155bfda8b7bce74494df","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/chain/plugin.cpp#364-432","gmt_create":"2026-04-30T13:09:00.7655018+04:00","gmt_modified":"2026-04-30T13:09:00.7655018+04:00"},{"id":41503,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"299aedc88851dabd155fc2edbbad96ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/CMakeLists.txt#27-38","gmt_create":"2026-04-30T13:09:00.7655018+04:00","gmt_modified":"2026-04-30T13:09:00.7655018+04:00"},{"id":41504,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"2a76e2c48df7946c93b84c330a1c08ae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#2294-2464","gmt_create":"2026-04-30T13:09:00.7660159+04:00","gmt_modified":"2026-04-30T13:09:00.7660159+04:00"},{"id":41505,"source_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","target_id":"d7fc3783ff3c58fa7beaff10948417fa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#1378-1464","gmt_create":"2026-04-30T13:09:00.7660159+04:00","gmt_modified":"2026-04-30T13:09:00.7660159+04:00"},{"id":41506,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d72b348a2c3c7943e4a7abb7dbdaa751","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_connection.hpp","gmt_create":"2026-04-30T13:09:18.7937429+04:00","gmt_modified":"2026-04-30T13:09:18.7937429+04:00"},{"id":41507,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"6c8cc56bd5bd0ef7abed9b709d60f20b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/peer_connection.cpp","gmt_create":"2026-04-30T13:09:18.794743+04:00","gmt_modified":"2026-04-30T13:09:18.794743+04:00"},{"id":41508,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f7dedf31e491c7adbaf05e957360c531","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-30T13:09:18.794743+04:00","gmt_modified":"2026-04-30T13:09:18.794743+04:00"},{"id":41509,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"b4bd3a3265ac695da5624024015e0e81","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/node.cpp","gmt_create":"2026-04-30T13:09:18.794743+04:00","gmt_modified":"2026-04-30T13:09:18.794743+04:00"},{"id":41510,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"6e587b97bf4080c7754c5ed73736fca7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message_oriented_connection.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41511,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"69291a4b8d9de900b397578829d3e0d9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/message_oriented_connection.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41512,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"398d9d4b02b6383c0b752cb0196a0475","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/stcp_socket.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41513,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"01e57c63d684a56829f909c03b8ea162","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/stcp_socket.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41514,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3a6c30f4bb3b265155c881ccfafa980e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/core_messages.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41515,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"2c99501f0c511d0792a2e5a56e4debfa","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/core_messages.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41516,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c82262dc5275e094efc9474032d15922","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/config.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41517,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3a8d8a10556a0b6501e25aa43e91f913","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/peer_database.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41518,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c70caf63ce77b078dcf89380b228a71a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/peer_database.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41519,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"b4467ca30cb6f6d587fc200900ee9ec9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/message.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41520,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3948eb588d15d01acf21ffd439ec508c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/network/include/graphene/network/exceptions.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41521,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"66c6049f94b83d8f15dc55bb2424efbe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/p2p/p2p_plugin.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41522,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a5661951a63a8a4cb0a563b6ff08335e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/database.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41523,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"73ada165e99c6ad5f938a94f11fb3e10","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/fork_database.cpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41524,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"cb29035725926be38d36ad8c01792b7e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: libraries/chain/include/graphene/chain/database_exceptions.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41525,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"0becb65bb16186368dcabd6b936c5a80","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.hpp","gmt_create":"2026-04-30T13:09:18.7957438+04:00","gmt_modified":"2026-04-30T13:09:18.7957438+04:00"},{"id":41526,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c4447af409b7f3205a55e5b286557dfe","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: plugins/snapshot/plugin.cpp","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41527,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"4d5bf798ac6e167d6d0e20a669431373","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: documentation/snapshot-plugin.md","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41528,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"18555f254f50536a15d8591acf982406","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: share/vizd/config/config.ini","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41529,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"9f8690911ef66c966743475f294ffb7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#79-351","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41530,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"ff11a77da594972e0b8a78df4289ada5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#45-79","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41531,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"4e8bc2cdd3d4fc68b2f7138c54288174","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#37-93","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41532,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"82787c8d2e7394cf00fa87735394c3d5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#72-95","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41533,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a480bfeb1604076e7d1db7746687a3b4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#42-106","gmt_create":"2026-04-30T13:09:18.7972489+04:00","gmt_modified":"2026-04-30T13:09:18.7972489+04:00"},{"id":41534,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"930f47bc2c95f0cac4086eeca5749e2c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#190-304","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41535,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"7b85de17d00c3c33f3e6ce72493cea24","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#104-134","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41536,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"ab73f6cda0f4389d2bef214161afef81","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#593-601","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41537,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8caf3345fc407dc61382d80fab63bc93","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5240-5274","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41538,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"7c3bbfa78db4dbdd170795e4ff786767","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#689-697","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41539,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8e54da669dc427d415acec15fb6a804a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/snapshot/plugin.cpp#3039-3045","gmt_create":"2026-04-30T13:09:18.7982522+04:00","gmt_modified":"2026-04-30T13:09:18.7982522+04:00"},{"id":41540,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"e6da7f673c730dddfe0373c2e796f71a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1215-1246","gmt_create":"2026-04-30T13:09:18.7992536+04:00","gmt_modified":"2026-04-30T13:09:18.7992536+04:00"},{"id":41541,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"732bc579d5f86ebf0e986ecfbdfa490d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#34-46","gmt_create":"2026-04-30T13:09:18.7992536+04:00","gmt_modified":"2026-04-30T13:09:18.7992536+04:00"},{"id":41542,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f02c5e6d0090d5de89e01b0a1d478c5c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/exceptions.hpp#33-45","gmt_create":"2026-04-30T13:09:18.7992536+04:00","gmt_modified":"2026-04-30T13:09:18.7992536+04:00"},{"id":41543,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f5f7d5764818ed749bc9b829f7aea2ff","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#1-386","gmt_create":"2026-04-30T13:09:18.7992536+04:00","gmt_modified":"2026-04-30T13:09:18.7992536+04:00"},{"id":41544,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"762c4b81ed454ad789c0b3b3cb00cc88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#1-85","gmt_create":"2026-04-30T13:09:18.7992536+04:00","gmt_modified":"2026-04-30T13:09:18.7992536+04:00"},{"id":41545,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"53a676bf1df5198ba31b6ebe848a29bd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#1-99","gmt_create":"2026-04-30T13:09:18.8002536+04:00","gmt_modified":"2026-04-30T13:09:18.8002536+04:00"},{"id":41546,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a3e6f8b4e51c838c44eaef16bb205031","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#1-573","gmt_create":"2026-04-30T13:09:18.8002536+04:00","gmt_modified":"2026-04-30T13:09:18.8002536+04:00"},{"id":41547,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"56968eec4c8adc4f9edd153c6ce9e231","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#1-374","gmt_create":"2026-04-30T13:09:18.8002536+04:00","gmt_modified":"2026-04-30T13:09:18.8002536+04:00"},{"id":41548,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f14b0ce0c1ba142fb55271fdc6c2ee9f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#1-141","gmt_create":"2026-04-30T13:09:18.8002536+04:00","gmt_modified":"2026-04-30T13:09:18.8002536+04:00"},{"id":41549,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f59f370133646ba0c40ebdd11ee6d697","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#1-114","gmt_create":"2026-04-30T13:09:18.8002536+04:00","gmt_modified":"2026-04-30T13:09:18.8002536+04:00"},{"id":41550,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8923fae736f09b1cb255636af9a52069","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1-6389","gmt_create":"2026-04-30T13:09:18.8012548+04:00","gmt_modified":"2026-04-30T13:09:18.8012548+04:00"},{"id":41551,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d3bee62a496fa43717911daed4f0bb13","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/fork_database.cpp#1-271","gmt_create":"2026-04-30T13:09:18.8012548+04:00","gmt_modified":"2026-04-30T13:09:18.8012548+04:00"},{"id":41552,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"18382ca1b0f5cd7c4280e057d0242410","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/exceptions.hpp#1-49","gmt_create":"2026-04-30T13:09:18.8012548+04:00","gmt_modified":"2026-04-30T13:09:18.8012548+04:00"},{"id":41553,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a41d1e5edd6d2706424bcd3b39295264","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#68-162","gmt_create":"2026-04-30T13:09:18.8022551+04:00","gmt_modified":"2026-04-30T13:09:18.8022551+04:00"},{"id":41554,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3de0360b8d19b4e6a521e737d44e1eec","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/message_oriented_connection.cpp#128-140","gmt_create":"2026-04-30T13:09:18.8022551+04:00","gmt_modified":"2026-04-30T13:09:18.8022551+04:00"},{"id":41555,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"0b26d723a87937f5a3f58770c522d067","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#49-72","gmt_create":"2026-04-30T13:09:18.8022551+04:00","gmt_modified":"2026-04-30T13:09:18.8022551+04:00"},{"id":41556,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"df02d50a1fa9064e2cfe4b033b6ecfc8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#233-306","gmt_create":"2026-04-30T13:09:18.8022551+04:00","gmt_modified":"2026-04-30T13:09:18.8022551+04:00"},{"id":41557,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a6b2b3362f68c7523a4e0d06a2a4352f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#424-799","gmt_create":"2026-04-30T13:09:18.8022551+04:00","gmt_modified":"2026-04-30T13:09:18.8022551+04:00"},{"id":41558,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"ee53a7a714337d597cc0a626fceec27f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_database.cpp#100-174","gmt_create":"2026-04-30T13:09:18.8032547+04:00","gmt_modified":"2026-04-30T13:09:18.8032547+04:00"},{"id":41559,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d6f1f5c1ab7e33b9a558f648113330fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#208-242","gmt_create":"2026-04-30T13:09:18.8032547+04:00","gmt_modified":"2026-04-30T13:09:18.8032547+04:00"},{"id":41560,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c32e26ac2223fcbd9ec8280f135d338c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/message_oriented_connection.cpp#135-140","gmt_create":"2026-04-30T13:09:18.8042552+04:00","gmt_modified":"2026-04-30T13:09:18.8042552+04:00"},{"id":41561,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"db2f58e50720e139a95c598355919158","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#69-72","gmt_create":"2026-04-30T13:09:18.8042552+04:00","gmt_modified":"2026-04-30T13:09:18.8042552+04:00"},{"id":41562,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"0543ad31da0059b627fc7cfd5bac0cad","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#233-272","gmt_create":"2026-04-30T13:09:18.8042552+04:00","gmt_modified":"2026-04-30T13:09:18.8042552+04:00"},{"id":41563,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"fa47faf491ab252556d3fc50f00c6a8d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#662-718","gmt_create":"2026-04-30T13:09:18.8042552+04:00","gmt_modified":"2026-04-30T13:09:18.8042552+04:00"},{"id":41564,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"fee43b750e5fa7d56e56ac6251e6b5bb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#41-66","gmt_create":"2026-04-30T13:09:18.8052538+04:00","gmt_modified":"2026-04-30T13:09:18.8052538+04:00"},{"id":41565,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"09cde54d90657149861df59444b291ba","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#244-338","gmt_create":"2026-04-30T13:09:18.8052538+04:00","gmt_modified":"2026-04-30T13:09:18.8052538+04:00"},{"id":41566,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"e3f78790c3dfc7c45569ce78697bf9ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#240-278","gmt_create":"2026-04-30T13:09:18.8052538+04:00","gmt_modified":"2026-04-30T13:09:18.8052538+04:00"},{"id":41567,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"5212be0912badd41a65263c4ef5ab6fc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/message_oriented_connection.cpp#237-283","gmt_create":"2026-04-30T13:09:18.8052538+04:00","gmt_modified":"2026-04-30T13:09:18.8052538+04:00"},{"id":41568,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8743a349115da7520b9567a7d855ca18","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/message_oriented_connection.cpp#148-235","gmt_create":"2026-04-30T13:09:18.8052538+04:00","gmt_modified":"2026-04-30T13:09:18.8052538+04:00"},{"id":41569,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d4b4e356cc64c1eac490f25138ad8337","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/stcp_socket.cpp#132-177","gmt_create":"2026-04-30T13:09:18.8062526+04:00","gmt_modified":"2026-04-30T13:09:18.8062526+04:00"},{"id":41570,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"cd0a62c9a78bb77d3b59a9d5872577f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#82-106","gmt_create":"2026-04-30T13:09:18.8062526+04:00","gmt_modified":"2026-04-30T13:09:18.8062526+04:00"},{"id":41571,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8c4475690fa2dd5b99756637ea5c7358","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#356-369","gmt_create":"2026-04-30T13:09:18.8062526+04:00","gmt_modified":"2026-04-30T13:09:18.8062526+04:00"},{"id":41572,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c71708bd330ca79e1ba386a1763f5154","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#718-740","gmt_create":"2026-04-30T13:09:18.807757+04:00","gmt_modified":"2026-04-30T13:09:18.807757+04:00"},{"id":41573,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"9aacd835d38b395734ce6c87619ff59b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5272-5274","gmt_create":"2026-04-30T13:09:18.807757+04:00","gmt_modified":"2026-04-30T13:09:18.807757+04:00"},{"id":41574,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"a1b4ebbf3bdbfda373c476ae64175283","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#169-242","gmt_create":"2026-04-30T13:09:18.807757+04:00","gmt_modified":"2026-04-30T13:09:18.807757+04:00"},{"id":41575,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"179c82a5b5dc0ef88ef0f3d348aeabf7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#310-338","gmt_create":"2026-04-30T13:09:18.8087613+04:00","gmt_modified":"2026-04-30T13:09:18.8087613+04:00"},{"id":41576,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"50fe97d449649d053646df017c7d5108","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#255-308","gmt_create":"2026-04-30T13:09:18.8087613+04:00","gmt_modified":"2026-04-30T13:09:18.8087613+04:00"},{"id":41577,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"707909d344d5db986aaec2161fe7ec64","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/config.hpp#58-58","gmt_create":"2026-04-30T13:09:18.8087613+04:00","gmt_modified":"2026-04-30T13:09:18.8087613+04:00"},{"id":41578,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"b07239f8068fdc811cbe0313fbee8a56","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#175-279","gmt_create":"2026-04-30T13:09:18.8087613+04:00","gmt_modified":"2026-04-30T13:09:18.8087613+04:00"},{"id":41579,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"89fa671fe61671f5b5ab01a94646d7a3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#428-480","gmt_create":"2026-04-30T13:09:18.8087613+04:00","gmt_modified":"2026-04-30T13:09:18.8087613+04:00"},{"id":41580,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f57a019298b7b9496ef4f4a85f921f75","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#47-71","gmt_create":"2026-04-30T13:09:18.8097612+04:00","gmt_modified":"2026-04-30T13:09:18.8097612+04:00"},{"id":41581,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"228fc59a5268956db45d2f696afd5586","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#518-526","gmt_create":"2026-04-30T13:09:18.8097612+04:00","gmt_modified":"2026-04-30T13:09:18.8097612+04:00"},{"id":41582,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8f4a83adbe444c72194effc3001fe32c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5265-5274","gmt_create":"2026-04-30T13:09:18.8097612+04:00","gmt_modified":"2026-04-30T13:09:18.8097612+04:00"},{"id":41583,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"4488509fca59b45f940f83b5db6daa2a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3874-3908","gmt_create":"2026-04-30T13:09:18.8107603+04:00","gmt_modified":"2026-04-30T13:09:18.8107603+04:00"},{"id":41584,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"313eca37529d6d0a87af6db00b3cae76","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3598-3626","gmt_create":"2026-04-30T13:09:18.8107603+04:00","gmt_modified":"2026-04-30T13:09:18.8107603+04:00"},{"id":41585,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"88cfd8edcbcced125d9358898750ad6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: plugins/p2p/p2p_plugin.cpp#172-182","gmt_create":"2026-04-30T13:09:18.8107603+04:00","gmt_modified":"2026-04-30T13:09:18.8107603+04:00"},{"id":41586,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3442c112ec40ff3a7ce211827dd731fb","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#599-600","gmt_create":"2026-04-30T13:09:18.8107603+04:00","gmt_modified":"2026-04-30T13:09:18.8107603+04:00"},{"id":41587,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"22da7c51b4640e33df6b1774de67e615","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_database.cpp#120-137","gmt_create":"2026-04-30T13:09:18.811762+04:00","gmt_modified":"2026-04-30T13:09:18.811762+04:00"},{"id":41588,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"0ff96f9f66fe11cb2bba96b2257c56cc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5013-5014","gmt_create":"2026-04-30T13:09:18.811762+04:00","gmt_modified":"2026-04-30T13:09:18.811762+04:00"},{"id":41589,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f6e4014b53decf8540f03050dcb248a7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3061-3062","gmt_create":"2026-04-30T13:09:18.811762+04:00","gmt_modified":"2026-04-30T13:09:18.811762+04:00"},{"id":41590,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"3a3515773dce3d23274f19f11b24b8a1","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#279-283","gmt_create":"2026-04-30T13:09:18.8127618+04:00","gmt_modified":"2026-04-30T13:09:18.8127618+04:00"},{"id":41591,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"18300366cc04c934739121e96aa33a18","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#2520-2590","gmt_create":"2026-04-30T13:09:18.8127618+04:00","gmt_modified":"2026-04-30T13:09:18.8127618+04:00"},{"id":41592,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"5c8f4ea594d62170eaa300eb27c60cab","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#285-289","gmt_create":"2026-04-30T13:09:18.8127618+04:00","gmt_modified":"2026-04-30T13:09:18.8127618+04:00"},{"id":41593,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"bced6dc0057c5231cbd868d55b0f5331","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#340-354","gmt_create":"2026-04-30T13:09:18.8137618+04:00","gmt_modified":"2026-04-30T13:09:18.8137618+04:00"},{"id":41594,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"1496fd024a306e65ca11a1074f83e158","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#371-399","gmt_create":"2026-04-30T13:09:18.8137618+04:00","gmt_modified":"2026-04-30T13:09:18.8137618+04:00"},{"id":41595,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"e196c8cfa8e7dbe5852841c2e099bad5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: share/vizd/config/config.ini#96-101","gmt_create":"2026-04-30T13:09:18.8137618+04:00","gmt_modified":"2026-04-30T13:09:18.8137618+04:00"},{"id":41596,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"c1db40762caab4c9462bb6bc70748152","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_connection.hpp#26-45","gmt_create":"2026-04-30T13:09:18.8157618+04:00","gmt_modified":"2026-04-30T13:09:18.8157618+04:00"},{"id":41597,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"973153247aad2260b57a9e4842ddfeb7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message_oriented_connection.hpp#26-28","gmt_create":"2026-04-30T13:09:18.8157618+04:00","gmt_modified":"2026-04-30T13:09:18.8157618+04:00"},{"id":41598,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"055bd4ac99dff0f7dad3d2d929f83b6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/stcp_socket.hpp#26-28","gmt_create":"2026-04-30T13:09:18.8157618+04:00","gmt_modified":"2026-04-30T13:09:18.8157618+04:00"},{"id":41599,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"37d9a1a0250d6f2b30d0b5acfef7b606","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#26-35","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41600,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"9fbb8ea1084712b6e00c9f6b9ad60c72","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/node.hpp#26-31","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41601,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"63f471b93ce70266253197686f8d7df6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/peer_database.hpp#26-35","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41602,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f18f4bdd5e9956c9abb9a7a52882581a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/message.hpp#26-31","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41603,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"03beec6b648d43a165d35e195b3eb81e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/core_messages.hpp#285-306","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41604,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"8620e966ce1a76d2ab405f5a49743457","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/config.hpp#48-50","gmt_create":"2026-04-30T13:09:18.8167621+04:00","gmt_modified":"2026-04-30T13:09:18.8167621+04:00"},{"id":41605,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d6ed83bad3a3124e13f09c4c1191b96a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/peer_connection.cpp#314-325","gmt_create":"2026-04-30T13:09:18.8182667+04:00","gmt_modified":"2026-04-30T13:09:18.8182667+04:00"},{"id":41606,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"fcdabf2022a050e8a2414fb979f5c419","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3448-3470","gmt_create":"2026-04-30T13:09:18.8182667+04:00","gmt_modified":"2026-04-30T13:09:18.8182667+04:00"},{"id":41607,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d614fc51360bb61b8f521167a6db1e11","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/include/graphene/network/config.hpp#26-106","gmt_create":"2026-04-30T13:09:18.8182667+04:00","gmt_modified":"2026-04-30T13:09:18.8182667+04:00"},{"id":41608,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"70f9beafdbca4132e0349e28e51fcd6a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/database.cpp#1239-1241","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41609,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"e4313416f9a67f60a9a17f977b2367f6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/chain/include/graphene/chain/database_exceptions.hpp#86-86","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41610,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"b0498790fa704db3f0e0545f4299a7ba","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#79-82","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41611,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"34cf64d4d37824f3883c4c577708cd70","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3278-3281","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41612,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"9619a9ec94b261a592033e0c0b3be117","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3633-3636","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41613,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"99d4fcb1177774e0710d2bd69e6b48d3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3653-3656","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41614,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"f652bd37bb37781168ae6561fb03f9b4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#3671-3674","gmt_create":"2026-04-30T13:09:18.8192697+04:00","gmt_modified":"2026-04-30T13:09:18.8192697+04:00"},{"id":41615,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"d2465d6814378cac309bb4813312e463","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#4472-4479","gmt_create":"2026-04-30T13:09:18.8202706+04:00","gmt_modified":"2026-04-30T13:09:18.8202706+04:00"},{"id":41616,"source_id":"0505088e-5f10-4252-bc3b-307363fee60d","target_id":"028e9730d5a18007052fca00e208de6c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: libraries/network/node.cpp#5016-5021","gmt_create":"2026-04-30T13:09:18.8202706+04:00","gmt_modified":"2026-04-30T13:09:18.8202706+04:00"},{"id":41617,"source_id":"f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce","target_id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce -\u003e 0a955b97-eb9d-434a-80a4-9bf1bf937dfb","gmt_create":"2026-04-30T13:09:19.4363838+04:00","gmt_modified":"2026-04-30T13:09:19.4363838+04:00"},{"id":41618,"source_id":"ed702015-695e-4ef5-87fc-be4645f73987","target_id":"0505088e-5f10-4252-bc3b-307363fee60d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed702015-695e-4ef5-87fc-be4645f73987 -\u003e 0505088e-5f10-4252-bc3b-307363fee60d","gmt_create":"2026-04-30T13:09:19.4421382+04:00","gmt_modified":"2026-04-30T13:09:19.4421382+04:00"}],"source_files":[{"id":"448c0fd26faf791081a54cd407662e4d","path":"plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","filename":"p2p_plugin.hpp","gmt_create":"2026-04-28T09:55:13.5573041+04:00","gmt_modified":"2026-04-28T09:55:13.5573041+04:00"},{"id":"66c6049f94b83d8f15dc55bb2424efbe","path":"plugins/p2p/p2p_plugin.cpp","filename":"p2p_plugin.cpp","gmt_create":"2026-04-28T09:55:13.5578078+04:00","gmt_modified":"2026-04-28T09:55:13.5578078+04:00"},{"id":"f7dedf31e491c7adbaf05e957360c531","path":"libraries/network/include/graphene/network/node.hpp","filename":"node.hpp","gmt_create":"2026-04-28T09:55:13.5580195+04:00","gmt_modified":"2026-04-28T09:55:13.5580195+04:00"},{"id":"d72b348a2c3c7943e4a7abb7dbdaa751","path":"libraries/network/include/graphene/network/peer_connection.hpp","filename":"peer_connection.hpp","gmt_create":"2026-04-28T09:55:13.5585906+04:00","gmt_modified":"2026-04-28T09:55:13.5585906+04:00"},{"id":"3a8d8a10556a0b6501e25aa43e91f913","path":"libraries/network/include/graphene/network/peer_database.hpp","filename":"peer_database.hpp","gmt_create":"2026-04-28T09:55:13.5585906+04:00","gmt_modified":"2026-04-28T09:55:13.5585906+04:00"},{"id":"3a6c30f4bb3b265155c881ccfafa980e","path":"libraries/network/include/graphene/network/core_messages.hpp","filename":"core_messages.hpp","gmt_create":"2026-04-28T09:55:13.5590935+04:00","gmt_modified":"2026-04-28T09:55:13.5590935+04:00"},{"id":"b4467ca30cb6f6d587fc200900ee9ec9","path":"libraries/network/include/graphene/network/message.hpp","filename":"message.hpp","gmt_create":"2026-04-28T09:55:13.5590935+04:00","gmt_modified":"2026-04-28T09:55:13.5590935+04:00"},{"id":"c82262dc5275e094efc9474032d15922","path":"libraries/network/include/graphene/network/config.hpp","filename":"config.hpp","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"b4bd3a3265ac695da5624024015e0e81","path":"libraries/network/node.cpp","filename":"node.cpp","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"609365f8572668c8cf1e1cfa497989e4","path":"libraries/chain/include/graphene/chain/database.hpp","filename":"database.hpp","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"ee77bf4eb6bfbfb3636aa0bd57416552","path":"thirdparty/chainbase/include/chainbase/chainbase.hpp","filename":"chainbase.hpp","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"7550b6fcbbc44fc4df4f050d5b4fb04a","path":"plugins/witness/witness.cpp","filename":"witness.cpp","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"f7be79ec222a56c210b7999322790a2f","path":"plugins/p2p/CMakeLists.txt","filename":"CMakeLists.txt","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"18555f254f50536a15d8591acf982406","path":"share/vizd/config/config.ini","filename":"config.ini","gmt_create":"2026-04-28T09:55:13.5596195+04:00","gmt_modified":"2026-04-28T09:55:13.5596195+04:00"},{"id":"0dd2a38630da83b11fb3596ad4d60705","path":"plugins/witness/include/graphene/plugins/witness/witness.hpp","filename":"witness.hpp","gmt_create":"2026-04-28T09:57:03.8211824+04:00","gmt_modified":"2026-04-28T09:57:03.8211824+04:00"},{"id":"f8bd5a2c3a4664ae9d5ec472684610dc","path":"plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp","filename":"plugin.hpp","gmt_create":"2026-04-28T09:57:03.8217721+04:00","gmt_modified":"2026-04-28T09:57:03.8217721+04:00"},{"id":"a4f11ca2018649a28877cfdeecdff9a6","path":"plugins/witness_api/plugin.cpp","filename":"plugin.cpp","gmt_create":"2026-04-28T09:57:03.8222749+04:00","gmt_modified":"2026-04-28T09:57:03.8222749+04:00"},{"id":"cf72debd284e30d5218a88ae08868205","path":"libraries/chain/include/graphene/chain/witness_objects.hpp","filename":"witness_objects.hpp","gmt_create":"2026-04-28T09:57:03.8222749+04:00","gmt_modified":"2026-04-28T09:57:03.8222749+04:00"},{"id":"bebd7920dd0967c6039c2adb16d4c52c","path":"libraries/chain/include/graphene/chain/chain_objects.hpp","filename":"chain_objects.hpp","gmt_create":"2026-04-28T09:57:03.8222749+04:00","gmt_modified":"2026-04-28T09:57:03.8222749+04:00"},{"id":"a5661951a63a8a4cb0a563b6ff08335e","path":"libraries/chain/database.cpp","filename":"database.cpp","gmt_create":"2026-04-28T09:57:03.8226514+04:00","gmt_modified":"2026-04-28T09:57:03.8226514+04:00"},{"id":"75b9bb8cfd2db41c21f328241d191f32","path":"libraries/chain/include/graphene/chain/fork_database.hpp","filename":"fork_database.hpp","gmt_create":"2026-04-28T09:57:03.8226514+04:00","gmt_modified":"2026-04-28T09:57:03.8226514+04:00"},{"id":"73ada165e99c6ad5f938a94f11fb3e10","path":"libraries/chain/fork_database.cpp","filename":"fork_database.cpp","gmt_create":"2026-04-28T09:57:03.8226514+04:00","gmt_modified":"2026-04-28T09:57:03.8226514+04:00"},{"id":"ebd71fe58bebecee1b2afacbe66909ca","path":"libraries/time/time.hpp","filename":"time.hpp","gmt_create":"2026-04-28T09:57:03.8226514+04:00","gmt_modified":"2026-04-28T09:57:03.8226514+04:00"},{"id":"13c87583e5739bb6062ee5706cbed132","path":"libraries/time/time.cpp","filename":"time.cpp","gmt_create":"2026-04-28T09:57:03.8231617+04:00","gmt_modified":"2026-04-28T09:57:03.8231617+04:00"},{"id":"b58bf8be210d82c70605d7f2482ced82","path":"thirdparty/fc/src/network/ntp.cpp","filename":"ntp.cpp","gmt_create":"2026-04-28T09:57:03.8232724+04:00","gmt_modified":"2026-04-28T09:57:03.8232724+04:00"},{"id":"fcabf234b34f00b60b0d784b2da5a052","path":"programs/vizd/main.cpp","filename":"main.cpp","gmt_create":"2026-04-28T09:57:03.8232724+04:00","gmt_modified":"2026-04-28T09:57:03.8232724+04:00"},{"id":"c4447af409b7f3205a55e5b286557dfe","path":"plugins/snapshot/plugin.cpp","filename":"plugin.cpp","gmt_create":"2026-04-28T09:57:03.8232724+04:00","gmt_modified":"2026-04-28T09:57:03.8232724+04:00"},{"id":"b4b9efd79d5b3c9fea00fccd613b2046","path":"libraries/protocol/include/graphene/protocol/config.hpp","filename":"config.hpp","gmt_create":"2026-04-28T09:57:03.8232724+04:00","gmt_modified":"2026-04-28T09:57:03.8232724+04:00"},{"id":"bb293be9318768f10f69c80fd6b68517","path":"share/vizd/config/config_witness.ini","filename":"config_witness.ini","gmt_create":"2026-04-28T09:57:03.8232724+04:00","gmt_modified":"2026-04-28T09:57:03.8232724+04:00"},{"id":"7ae785f9d5ab154dce6f8eb295b93456","path":"libraries/chain/include/graphene/chain/global_property_object.hpp","filename":"global_property_object.hpp","gmt_create":"2026-04-28T09:57:57.4332426+04:00","gmt_modified":"2026-04-28T09:57:57.4332426+04:00"},{"id":"bbbc42bba97165e48c1da269d1d84a04","path":"libraries/protocol/include/graphene/protocol/config_testnet.hpp","filename":"config_testnet.hpp","gmt_create":"2026-04-28T09:57:57.4332426+04:00","gmt_modified":"2026-04-28T09:57:57.4332426+04:00"},{"id":"8ede002b6c76d0a07d75e34f812e8305","path":"libraries/chain/hardfork.d/12.hf","filename":"12.hf","gmt_create":"2026-04-28T09:57:57.433751+04:00","gmt_modified":"2026-04-28T09:57:57.433751+04:00"},{"id":"1ade3cebbc11a4634bcdf1a7fdb2756e","path":"thirdparty/chainbase/src/chainbase.cpp","filename":"chainbase.cpp","gmt_create":"2026-04-28T09:57:57.433751+04:00","gmt_modified":"2026-04-28T09:57:57.433751+04:00"},{"id":"4238a9561f85e50a38f76813baeadd7e","path":"libraries/chain/include/graphene/chain/block_log.hpp","filename":"block_log.hpp","gmt_create":"2026-04-28T10:02:32.5912942+04:00","gmt_modified":"2026-04-28T10:02:32.5912942+04:00"},{"id":"d2090ff9016be0d896d06e843936e0f4","path":"libraries/chain/block_log.cpp","filename":"block_log.cpp","gmt_create":"2026-04-28T10:02:32.5912942+04:00","gmt_modified":"2026-04-28T10:02:32.5912942+04:00"},{"id":"14f7f8b4c6f5b783b573d1fbbcfc1a11","path":"libraries/chain/include/graphene/chain/dlt_block_log.hpp","filename":"dlt_block_log.hpp","gmt_create":"2026-04-28T10:02:32.5912942+04:00","gmt_modified":"2026-04-28T10:02:32.5912942+04:00"},{"id":"ade43b15adadb0a3215b2b7a6866ef22","path":"libraries/chain/dlt_block_log.cpp","filename":"dlt_block_log.cpp","gmt_create":"2026-04-28T10:02:32.5912942+04:00","gmt_modified":"2026-04-28T10:02:32.5912942+04:00"},{"id":"cb29035725926be38d36ad8c01792b7e","path":"libraries/chain/include/graphene/chain/database_exceptions.hpp","filename":"database_exceptions.hpp","gmt_create":"2026-04-28T10:02:32.5925293+04:00","gmt_modified":"2026-04-28T10:02:32.5925293+04:00"},{"id":"57e07111ef7b80720c419255780e7ece","path":"libraries/chain/include/graphene/chain/db_with.hpp","filename":"db_with.hpp","gmt_create":"2026-04-28T10:02:32.5925293+04:00","gmt_modified":"2026-04-28T10:02:32.5925293+04:00"},{"id":"3948eb588d15d01acf21ffd439ec508c","path":"libraries/network/include/graphene/network/exceptions.hpp","filename":"exceptions.hpp","gmt_create":"2026-04-28T10:02:32.5925293+04:00","gmt_modified":"2026-04-28T10:02:32.5925293+04:00"},{"id":"bd196d115b6bd3d5310dfa247f1e25b2","path":"plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp","filename":"plugin.hpp","gmt_create":"2026-04-28T12:27:40.7714294+04:00","gmt_modified":"2026-04-28T12:27:40.7714294+04:00"},{"id":"991938d306a547ff48a759fb9bd1c5a4","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_types.hpp","filename":"snapshot_types.hpp","gmt_create":"2026-04-28T12:27:40.7714294+04:00","gmt_modified":"2026-04-28T12:27:40.7714294+04:00"},{"id":"d8e14923de7e4be8f600e264a03ea281","path":"plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp","filename":"snapshot_serializer.hpp","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"dc43b9a20a2ae22effbe51aecf8ca751","path":"plugins/snapshot/CMakeLists.txt","filename":"CMakeLists.txt","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"55b60ae8ffadd70d41ebd01151dcb237","path":"share/vizd/snapshot.json","filename":"snapshot.json","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"2eb0f5e7350fc53dec7939bb93e824ac","path":"share/vizd/snapshot-testnet.json","filename":"snapshot-testnet.json","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"4d5bf798ac6e167d6d0e20a669431373","path":"documentation/snapshot-plugin.md","filename":"snapshot-plugin.md","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"6c94b84fdfd5c7016b5eeadf8099133e","path":"plugins/chain/plugin.cpp","filename":"plugin.cpp","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"ae7188ee9396d8d8aca884b96e9bc4c1","path":"plugins/chain/include/graphene/plugins/chain/plugin.hpp","filename":"plugin.hpp","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"51c2f2c072611ae01260d171fbd12b59","path":"thirdparty/fc/src/interprocess/file_mutex.cpp","filename":"file_mutex.cpp","gmt_create":"2026-04-28T12:27:40.7719506+04:00","gmt_modified":"2026-04-28T12:27:40.7719506+04:00"},{"id":"d71a233c4690ddd107d80d74f5956ebf","path":"thirdparty/fc/src/log/logger_config.cpp","filename":"logger_config.cpp","gmt_create":"2026-04-28T12:27:40.7724634+04:00","gmt_modified":"2026-04-28T12:27:40.7724634+04:00"},{"id":"a53dc201b0a9ff736da577ae1c524abb","path":"thirdparty/fc/src/log/console_appender.cpp","filename":"console_appender.cpp","gmt_create":"2026-04-28T12:27:40.7724634+04:00","gmt_modified":"2026-04-28T12:27:40.7724634+04:00"},{"id":"d6fb716d9203d54e5aaccd580adc4703","path":"libraries/protocol/include/graphene/protocol/block.hpp","filename":"block.hpp","gmt_create":"2026-04-28T12:54:08.069392+04:00","gmt_modified":"2026-04-28T12:54:08.069392+04:00"},{"id":"3b0d308523637c64e62fac4d1a2a4a66","path":"libraries/protocol/include/graphene/protocol/block_header.hpp","filename":"block_header.hpp","gmt_create":"2026-04-28T12:54:08.069392+04:00","gmt_modified":"2026-04-28T12:54:08.069392+04:00"},{"id":"398d9d4b02b6383c0b752cb0196a0475","path":"libraries/network/include/graphene/network/stcp_socket.hpp","filename":"stcp_socket.hpp","gmt_create":"2026-04-28T14:54:34.9399731+04:00","gmt_modified":"2026-04-28T14:54:34.9399731+04:00"},{"id":"6e587b97bf4080c7754c5ed73736fca7","path":"libraries/network/include/graphene/network/message_oriented_connection.hpp","filename":"message_oriented_connection.hpp","gmt_create":"2026-04-28T14:54:34.9399731+04:00","gmt_modified":"2026-04-28T14:54:34.9399731+04:00"},{"id":"6c8cc56bd5bd0ef7abed9b709d60f20b","path":"libraries/network/peer_connection.cpp","filename":"peer_connection.cpp","gmt_create":"2026-04-28T18:50:34.3806901+04:00","gmt_modified":"2026-04-28T18:50:34.3806901+04:00"},{"id":"2c99501f0c511d0792a2e5a56e4debfa","path":"libraries/network/core_messages.cpp","filename":"core_messages.cpp","gmt_create":"2026-04-28T18:50:34.3809836+04:00","gmt_modified":"2026-04-28T18:50:34.3809836+04:00"},{"id":"01e57c63d684a56829f909c03b8ea162","path":"libraries/network/stcp_socket.cpp","filename":"stcp_socket.cpp","gmt_create":"2026-04-28T18:50:34.3809836+04:00","gmt_modified":"2026-04-28T18:50:34.3809836+04:00"},{"id":"c70caf63ce77b078dcf89380b228a71a","path":"libraries/network/peer_database.cpp","filename":"peer_database.cpp","gmt_create":"2026-04-28T18:50:34.3814865+04:00","gmt_modified":"2026-04-28T18:50:34.3814865+04:00"},{"id":"3f9fffa35f3712fd1f90ebc3c0593373","path":"documentation/debug_node_plugin.md","filename":"debug_node_plugin.md","gmt_create":"2026-04-28T19:48:38.8549045+04:00","gmt_modified":"2026-04-28T19:48:38.8549045+04:00"},{"id":"85e109c379780f5df7bb2695b2862fba","path":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp","filename":"plugin.hpp","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"796d893189111ab0df5e606d82fea700","path":"plugins/debug_node/plugin.cpp","filename":"plugin.cpp","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"fb3a9999324017fb4d2fad7f61f2660e","path":"plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp","filename":"api_helper.hpp","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"2b777822e4399aff7d4e5ea26fcbe8b9","path":"share/vizd/config/config_debug.ini","filename":"config_debug.ini","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"89eb7bdd3591c729dfa6f00de5cdfa1c","path":"programs/util/sign_transaction.cpp","filename":"sign_transaction.cpp","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"2819790574404236d7b1bca0b253c524","path":"programs/util/sign_digest.cpp","filename":"sign_digest.cpp","gmt_create":"2026-04-28T19:48:38.8558545+04:00","gmt_modified":"2026-04-28T19:48:38.8558545+04:00"},{"id":"69291a4b8d9de900b397578829d3e0d9","path":"libraries/network/message_oriented_connection.cpp","filename":"message_oriented_connection.cpp","gmt_create":"2026-04-28T20:32:44.1445931+04:00","gmt_modified":"2026-04-28T20:32:44.1445931+04:00"},{"id":"0becb65bb16186368dcabd6b936c5a80","path":"plugins/snapshot/plugin.hpp","filename":"plugin.hpp","gmt_create":"2026-04-28T20:32:44.14584+04:00","gmt_modified":"2026-04-28T20:32:44.14584+04:00"},{"id":"01456fc1d03088da2d9080a7ba380f5f","path":"libraries/chain/include/graphene/chain/block_summary_object.hpp","filename":"block_summary_object.hpp","gmt_create":"2026-04-28T21:03:48.5307667+04:00","gmt_modified":"2026-04-28T21:03:48.5307667+04:00"},{"id":"1ccc033e927b7ba78550b64f23026d0b","path":"thirdparty/fc/include/fc/exception/exception.hpp","filename":"exception.hpp","gmt_create":"2026-04-28T22:07:48.9742186+04:00","gmt_modified":"2026-04-28T22:07:48.9742186+04:00"},{"id":"29a08e70168bdd56a054f1924f1f547c","path":"thirdparty/fc/src/exception.cpp","filename":"exception.cpp","gmt_create":"2026-04-28T22:07:48.9752186+04:00","gmt_modified":"2026-04-28T22:07:48.9752186+04:00"},{"id":"5ba4c9dfb14a49e5bdc63880653930c6","path":"libraries/protocol/include/graphene/protocol/exceptions.hpp","filename":"exceptions.hpp","gmt_create":"2026-04-28T22:07:48.9752186+04:00","gmt_modified":"2026-04-28T22:07:48.9752186+04:00"},{"id":"0e6f9014df8500eda2c1aa47cc9e4633","path":"thirdparty/appbase/application.cpp","filename":"application.cpp","gmt_create":"2026-04-29T06:59:11.2761981+04:00","gmt_modified":"2026-04-29T06:59:11.2761981+04:00"},{"id":"648e1d10af53280c425b922251db1464","path":"README.md","filename":"README.md","gmt_create":"2026-04-29T06:59:11.2761981+04:00","gmt_modified":"2026-04-29T06:59:11.2761981+04:00"},{"id":"455bdc0d380a2cbf0f62da93a6fe203d","path":"thirdparty/fc/src/log/console_defines.h","filename":"console_defines.h","gmt_create":"2026-04-29T06:59:11.2767199+04:00","gmt_modified":"2026-04-29T06:59:11.2767199+04:00"},{"id":"cb10d0f5bb9015fb9ce5f22b75c10fed","path":"thirdparty/fc/src/stacktrace.cpp","filename":"stacktrace.cpp","gmt_create":"2026-04-30T07:30:11.779591+04:00","gmt_modified":"2026-04-30T07:30:11.779591+04:00"},{"id":"a64d5e5f1d092e1fd6a7916d048be8da","path":"plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp","filename":"witness_guard.hpp","gmt_create":"2026-04-30T12:39:24.1454414+04:00","gmt_modified":"2026-04-30T12:39:24.1454414+04:00"},{"id":"f0afc0a1f80132e4bf15ac9ff156e256","path":"plugins/witness_guard/witness_guard.cpp","filename":"witness_guard.cpp","gmt_create":"2026-04-30T12:39:24.1454414+04:00","gmt_modified":"2026-04-30T12:39:24.1454414+04:00"}],"wiki_catalogs":[{"id":"80d9e7dd-fa35-469c-bd78-95cb6616e64c","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Project Overview","description":"overview","prompt":"Create comprehensive content for the VIZ CPP Node project overview section. Explain the project's purpose as a Graphene-based blockchain implementation with Fair-DPOS consensus algorithm, its architecture as a full consensus node for the VIZ World platform, and its relationship to the broader blockchain ecosystem. Document the core value proposition, target audience (node operators, application developers, wallet developers), and key differentiators from other blockchain implementations. Include both conceptual overviews for beginners new to blockchain technology and technical highlights for experienced developers. Use terminology consistent with the VIZ codebase. Provide practical examples demonstrating common use cases such as running a full node, developing applications, and operating witness nodes. Document the project's position in the Graphene blockchain family and its unique features like Fair-DPOS consensus and social network integration.","progress_status":"completed","dependent_files":"README.md,programs/vizd/main.cpp,libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:31:56+04:00","raw_data":"WikiEncrypted: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"},{"id":"86d4d313-8f5e-4334-b5d1-220ec01d0971","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"System Overview","description":"system-overview","prompt":"Create comprehensive content for the VIZ CPP Node system overview section. Explain the overall architecture showing how the main vizd process orchestrates all components including the plugin system, core libraries, and external dependencies. Document the modular design that allows for flexible feature addition and removal through plugins. Describe the relationship between the application framework (appbase), the blockchain core (chain library), protocol definitions (protocol library), networking (network library), and wallet functionality (wallet library). Include system boundaries showing how the node interacts with peers, handles API requests, and manages persistent state. Provide high-level component diagrams illustrating the data flow from JSON-RPC requests through plugins to database operations, and explain the observer pattern used for event-driven architecture. Address the separation of concerns between different library layers and how they work together to form a complete blockchain node.","parent_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","progress_status":"completed","dependent_files":"programs/vizd/main.cpp,libraries/chain/include/graphene/chain/database.hpp,libraries/protocol/include/graphene/protocol/operations.hpp","gmt_create":"2026-03-03T07:28:18+04:00","gmt_modified":"2026-03-03T07:39:03+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Build System","description":"build-system","prompt":"Create comprehensive build system documentation for VIZ CPP Node. Document the CMake-based build configuration including cross-platform compilation, dependency management, and build targets. Explain the build helper tools including configure_build.py, cat_parts.py, and newplugin.py. Cover Docker-based development and production builds with detailed instructions for different environments. Document build options, compiler flags, and optimization settings. Include practical examples of common build scenarios such as development builds, release builds, and cross-compilation. Address troubleshooting common build issues, dependency conflicts, and platform-specific compilation problems. Explain the relationship between build configuration and runtime performance, making it accessible to developers while providing sufficient technical depth for advanced build customization.","parent_id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","progress_status":"completed","dependent_files":"install-deps-linux.sh,build-linux.sh,build-mac.sh,build-mingw.bat,build-msvc.bat,CMakeLists.txt,programs/build_helpers/,share/vizd/docker/,.github/workflows/","gmt_create":"2026-03-03T07:28:48+04:00","gmt_modified":"2026-04-21T16:26:53+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"61febd56-5be6-448d-b2a2-26975fe33d8d","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Node Configuration","description":"node-configuration","prompt":"Create comprehensive node configuration documentation for VIZ CPP Node. Document the complete configuration file structure including all available parameters, their purposes, default values, and acceptable ranges. Explain different node types (full node, witness node, low-memory node, testnet node) and their specific configuration requirements. Cover essential settings such as database location, plugin activation, network parameters, and performance tuning options. Document authentication settings, API access controls, and security configurations. Include practical examples of common configuration scenarios for different deployment environments. Address parameter validation, configuration file syntax, and troubleshooting invalid configurations. Provide guidance on configuration file organization, backup strategies, and version management.","parent_id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","progress_status":"completed","dependent_files":"share/vizd/config/config.ini,share/vizd/config/config_testnet.ini,share/vizd/config/config_witness.ini,share/vizd/config/config_mongo.ini,share/vizd/config/config_debug.ini","gmt_create":"2026-03-03T07:28:57+04:00","gmt_modified":"2026-03-03T07:40:51+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Node Deployment","description":"node-deployment","prompt":"Create comprehensive node deployment documentation for VIZ CPP Node. Document production deployment strategies including hardware requirements, system prerequisites, and installation procedures. Cover different node types including full nodes, witness nodes, and seed nodes with their specific configuration requirements and operational procedures. Explain the node startup process, configuration file management, and service integration. Include step-by-step installation guides for different operating systems, dependency management, and build optimization. Document performance tuning parameters, resource allocation recommendations, and capacity planning. Address security hardening procedures, firewall configuration, and access control setup. Provide troubleshooting guidance for common deployment issues, startup failures, and configuration errors.","parent_id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","progress_status":"completed","dependent_files":"share/vizd/config/config.ini,share/vizd/vizd.sh,programs/vizd/main.cpp,documentation/building.md","gmt_create":"2026-03-03T07:29:04+04:00","gmt_modified":"2026-03-03T07:40:48+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"bcdd0730-3bcf-4e55-aeac-7cc0a351046b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Plugin Lifecycle and Registration","description":"plugin-lifecycle-registration","prompt":"Create comprehensive content for plugin lifecycle and registration mechanisms. Document the complete plugin lifecycle from initialization to shutdown, including the plugin_initialize, plugin_startup, and plugin_shutdown phases. Explain how plugins register themselves with the appbase framework and the role of APPBASE_PLUGIN_REQUIRES macro in dependency management. Detail the plugin registration process in main.cpp and how the application framework manages plugin loading order. Include concrete examples of plugin initialization sequences and dependency resolution. Document the plugin naming conventions, static name() method implementation, and how plugins declare their requirements. Address plugin startup timing, error handling during initialization, and graceful shutdown procedures. Provide practical examples of plugin registration patterns and common pitfalls to avoid.","parent_id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","progress_status":"completed","dependent_files":"plugins/chain/plugin.cpp,plugins/snapshot/plugin.cpp,programs/vizd/main.cpp,libraries/utilities/include/graphene/utilities/git_revision.hpp","gmt_create":"2026-03-03T07:29:09+04:00","gmt_modified":"2026-04-20T10:26:06+04:00","raw_data":"WikiEncrypted:FgT6N5UmoqQ/n0GhU4kWL0J+Fybs3wSrBZ8i488xBvorI6lbBGjTYhS7bWXZzNetCm3S8JjcFgc9memzvSTO1YQPmT49Uldgjtl2WhFXjcF3WJX4hC0AP6UDYCYSCpEQRv9FPzViWgqq1DAOKLH+wBLA4uPKXHhu9yy+0mxa4aF6S4miAF3erjorTWHLA6eZthaZDF/KtxoS72PiMdX7my+r/UgxX2mhhzK4HFwOQsfLffXQD0QEh+3jSSXo7zksFg4c4HtLPHVniAghLUc4FaiLk4QFZXlsjRxPv9BGuHwpHdYEuf1paaNdIBxZnU6TwCa2zP+eoetFX/hv9cLPE3l34RJBTe3wc1a7XFlDFibG7B0J+cLTdLAoBbZhRWjZtE1jZ38MG19LiU8RC+/BMnG3Kez75HzaUyTdmrrQqVdzv7kWmLDr2ThjIUaJ8DQkZy04RHRESRIBA1lgvJHZvMT8NcvJs61mGdbbjPgm//7a9yxi7My3yX1iwGRqn3a/Lqro9m0YGAhxPL3igGWL4/yIH8gO/GppVOau8yklmHGVQu9sgROoFomlNcZjIUhjPnw/uM0DWMPEnpH8Oc+fqNXXVp8wpQDodiD65535YGFCx/7KABM6loSnvsPbRWYb9pV0KYB0b14G8jaRpOJbgJCApsYhcqTu5sydWErz6v3gUjTszz6cmK/3bvjy0SMoAl7MNDMYebUs8cZiR+8GzHYcHPs9ryxF5ofTQio5BxnxbKH1X7JB00SJVWogJHRL1KkShj5Asor6n/UugH/W+tclRJ/mK9WdtxaV1ifY61reOTJUCmD/eHgvDixPIrC6Z791SNiFzhWLqSJBwOIDrud9LLoSUYWRST13iunjJcEYVzRGkVxR2OU6rsDDFeb+ECIRi4WVM5Kte43i303/Po3fmPSmSdts5p3TU75MteEn71R5ONoH1vNowPjsyuyqGtNssow9U0prKW0nE5FZbXXi3IXUkFWtWroI0kR2htD6Ef70I+bG1C8j+UlcvM9Poffck/PbEruGH+aavXpaxMRcayIT6SGBEy4u+Iu6nughmmP9wKpSzEpStW6ZqgNOnYuOBqJihAHjutfprPUcZjdoifyNNnKRNxBO8EPMBsrIPEysvB7ubU5r0Gb29skV8Wb9LVqm5nGLBC24s8G5bmDfHCqyVxbx+b8AJOVVhAu8dKQK2Pt92R+PXA+VoTQEc0oaxgvsNPJjBx0W/dItwgUB+nItoqSytXeiucfQhINaKD6Ws/KvGKk3mRaS8i6KOJB0V0RoWpwWP0ZjUCGYZXr1i65I9ni82/QtacyhPKeR/dV508moShmcw2S3eD8BqmGKSnPAF7tH8RzIPcvuOFYLH9e7FNcoKV2NhKeNUgZdvVwTcf1NTZTx2ri19AUCa4vIawJUyhQ3/r7UxLrvqBxK8daQ+thKHrXe1gN1K0XAMQoNWSPy+srNGqhpD427EDMl03T99zDRZ8LbeufN2/KsYohFnR/rMKAsI/E1L0YR/5ZNtEKxqNbr68ADWZkE2Sup6GtbMqDmmgYV5G6HXTQsV5ZXSRJnextrT5JNJEoLW+HfSOESLc4syDu5fdoTXi7i772CuEzigL1YKaV1TzR4fpoHzc/CZh6rVObeBEVxqkaLniq228ZuM2e6omqfcHId8BjTE7hi5cBczbOJbVaUEErzMdIvr0EfHByOxwctdQ7JGbMQnxGnYwv2IqQgD1roNER2MFVMmabYAxqqlVGJvH4bRS4uAIK9R6j9O15/bsjfnsWIutsiUJq7WtMZ","layer_level":2},{"id":"56a9c3df-f2c3-4f59-8729-1fed0fcdb9d2","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Hardfork Management","description":"hardfork-management","prompt":"Create comprehensive hardfork management documentation for VIZ CPP Node. Document the hardfork system architecture including version management, scheduled upgrades, and backward compatibility handling. Explain the hardfork directory structure and how hardfork files are processed during node startup. Detail the migration procedures for upgrading from older versions, including data schema changes and state transitions. Cover the hardfork evaluation system and how different operation types are handled across hardfork boundaries. Document the rollback mechanisms and recovery procedures for failed upgrades. Include practical examples of implementing custom hardfork logic, adding new operation types, and modifying existing behavior. Address common hardfork scenarios such as protocol changes, bug fixes, and feature additions. Provide troubleshooting guidance for hardfork-related issues and validation procedures for ensuring successful upgrades.","parent_id":"7a20b53f-0b97-40ec-a630-7e9171a04006","progress_status":"completed","dependent_files":"libraries/chain/hardfork.d/0-preamble.hf,libraries/chain/database.cpp,libraries/chain/hardfork.d/12.hf,libraries/protocol/include/graphene/protocol/config.hpp,libraries/chain/hardfork.d/,libraries/chain/chain_evaluator.cpp","gmt_create":"2026-03-03T07:29:10+04:00","gmt_modified":"2026-04-20T11:24:22+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"08c2583a-92f0-4c14-aa9d-736878711ba1","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Transaction Processing Pipeline","description":"transaction-processing","prompt":"Create comprehensive documentation for the transaction processing pipeline in the VIZ node. Explain the complete flow from transaction reception through validation, operation processing, authority verification, and state application. Document the transaction validation stages including syntax checking, signature verification, and operation validation. Detail the evaluator registry mechanism and how different operation types are processed through their respective evaluators. Include the transaction object lifecycle, from creation to final application. Explain error handling throughout the pipeline and rollback mechanisms. Document performance optimizations like batch processing and caching strategies used during transaction validation.","parent_id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/protocol/transaction.cpp,libraries/chain/transaction_object.cpp,libraries/chain/chain_evaluator.cpp","gmt_create":"2026-03-03T07:29:21+04:00","gmt_modified":"2026-03-03T07:53:30+04:00","raw_data":"WikiEncrypted:pze/wTPA8hT9dADtWGlHVecGIju168riPHUw4TY8/AOhja4aeOzUlmfgdY/KTiokGkE0pwevgTXyU4//H92NNxIZ90VqY2mbD0yvEYoazibaKq9O1InwoMVUng4EkSsQB9oHT43atze2e4KWPpApnOpuXM/kNSqRnBSucHXjsMd+Tjj5PradoQvpJLU8cQA/Z7rNIJC0cpQOT83jnvDj0V6NqUee6Tv82FRi8ClWzP6EZWLJOwLqfzlzlavNBvEzOVrawfC21Hgjv0XI+S8iljUPDEK+/k4kPqQwBtNAZVNvSxdOMdQQd4H8dHYj42tsWQ4M2CHxt/jWDy4RZ7gusItaB76xjlAkrZESkdwZBkd//EMqxuKfE/A4/LQdGHNOTm+uaj6m8t76OHM9h4VR9V4eueF6t3bMM8jowIFMUsjHBlU+dkSn/NSR6LigMB4jIbNt61XMmwk1mFvwxws6PxL8XqLxS6WdTzKfDE4/IBBD7TZqimc2cA4z2+g/OZ39ZEQlIpiv8/TzTdAWlsxWrctDiJB94u/AwbbOehhEdFH2nS66e1wKUfknITsWMgsuyzC0CfWRd/fwrEG58bYEi74d+wo1sJlOuZEBaSfMiOosE7wvOH3oQ8Y2UgwJ0vjzgZUiE9G0ScjOOZWniMF0bqPEe06ztnJIGeefrHJOWjdIfN1dkS9ufS455XmgRlNSE/NqG4hDmxF9R9NWjkexlSw2BcqQfD6budkT9gXrT+DmvhvTAZNbhg3rbqVluS4bL3ruC2r+ajzWHoYzImenOWqpDXtY3PDdWzlF25dvXKPOiFCgnpIhx4/aEBmvfoFugNyi2rgkZ/GxUvgLFwYxUWsrXzOW3ghrF82KYZiOzclpGc9/z4O3aOx2rsywhd3+bwSLqnWiTUPCcJaACADsGSIk2O+4SSb/+dGgJEi0+9f+XVUkdntAmb/GY0r1Pj9Aggwk6gllw1jhIAFrhSeeN9YQkHHngVWQDTIqpEZrLiK8l9KRp0xOidl2MSvQPSjBk4h2qqynktmU6u6INK0QjvFuStt1EBvl9TX3ObV9TqdxQyTeD4wyygPZWQEip1CHg04iAihm5uA9siBylj/kLKn9MnuWugqJDyQmvMVc7PXW2PjXtPzhW7/Jb/SHMJoTD4Gr9dGOx46lLwizMVmH+Wdgu7ThE5TRiLm3zbM6Vva42JyyhlKovJOwOzbdE7oL4PEURcpIb7CwrNkCvuOclVRFhgGE6YTkuBTdHLlFpLoInX5qE2OW9+ydHnq5m3kxjp0jqHR1FEndp/SOAgjK8j5GUBfktjso1ePTCXqGifq82fcPCltrzG7k2QOtOSECTUa+pOeVnhutaJ3CR//hRALu3mrquQnFk0tLrX117kwCT9zFNRljPROygJRvN4BCTzDJgnqakMlqteAIkiRD3Fb0oHccw3FqJPY5lOQvvyGOgQeuBimDKH34MRTRl3pkYQbHOqjUqUi035eAfFu0Rvt/1KkKcP/6anglXytX8/wCssuFHVX8WLr/XarAK8wkI0F8fuBcwaifM6C4xWQNCD3dZMCNDxfik3SCqkRtAzmd1xC3HA1SQ5I/qlbrtzwC","layer_level":2},{"id":"e02c38ec-2618-428e-b338-f93cfe94dc72","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Chain Library","description":"chain-library","prompt":"Create comprehensive content for the Chain Library, which serves as the core blockchain state management system. Document the database.hpp/cpp implementation that handles blockchain state persistence, block validation, and fork resolution. Explain the chain_objects.hpp and chain_object_types.hpp that define the complete blockchain data model including account objects, transaction objects, witness objects, and committee objects. Detail the fork_database.hpp implementation for handling blockchain forks and maintaining consensus. Cover the block_log.hpp functionality for efficient block storage and retrieval. Include the database API methods for querying blockchain state, managing object lifecycles, and handling state transitions. Document the evaluator system for operation processing and the observer pattern implementation for event-driven architecture. Provide examples of common database operations, state queries, and performance optimization techniques.","parent_id":"139b0217-0190-433f-b41d-60fa08c9ee5f","progress_status":"completed","dependent_files":"plugins/chain/plugin.cpp,plugins/chain/include/graphene/plugins/chain/plugin.hpp,libraries/chain/include/graphene/chain/database.hpp,libraries/chain/database.cpp,libraries/chain/include/graphene/chain/chain_objects.hpp,libraries/chain/include/graphene/chain/chain_object_types.hpp,libraries/chain/include/graphene/chain/fork_database.hpp,libraries/chain/include/graphene/chain/block_log.hpp,libraries/chain/include/graphene/chain/transaction_object.hpp,libraries/chain/include/graphene/chain/account_object.hpp,libraries/chain/include/graphene/chain/witness_objects.hpp,libraries/chain/include/graphene/chain/committee_objects.hpp","gmt_create":"2026-03-03T07:29:24+04:00","gmt_modified":"2026-04-23T11:18:36+04:00","raw_data":"WikiEncrypted:2nxDQCjwbtJzhDuGjsVF7ha2W5xUiy+LwHkKv1AwRE0b/rDDxfehhG/4LXof9ham7nRXgecjnf0jkNePtLF/KDru1FvisuqgbQMdf8U2jd563cejqk111AaLkgMqeIi71RPGBfzE5jdBEKEEb3TPM0ecgDKGnpInSGR4eAl344BwRali3fXrtstBL20ZcJB5DMDDCkn0N7oNn/VTPXADci76Mdpc+j1yRZe68/yjrki3+hPf9Cqph5xZJM3JHoGpnMYJ08+Pn2y8TZDhiVuTdvR68AdVsVUX1tbQfZ5LTopxi6l7AI2IapXBbo/lUtdYbH3+bT7diV7dtBm8XMsuny+hzxU4+frt/iV5kCS/9HZVD+co5S85Y1fUL7e2sBtAN1d02TlrDr6SnrCwvxqTUYMJ6qTlAt7UxFh7zF9UwZ7eW4HjHeJ812Uzn/Ce+TKitW6S+vnUnQ80kxBva5dGgrkY5rUeABXK94itLE38RG9Z3I/QOM1AMvyZO03iNqbbZm98rI9i6qk3yt4ZmNVoPSaf+8NIJxplKozoPk0bJDO3dGi3rE/mq7bYtMhBIq76Cgcte7qfLZ6GhSLP5AqYZKuKDjUQuyjv//pqLCvjY/5JtLdHI4dRVsGsGHqpUIGVyWUIoFTqElarR0vXAFGan9OPbhvJFkDJQK3a/LrUn/mjGt7WbEVWhVLf6/o4PSEMySISlSMZE5zidG55X6R3OKwWA5eQPURmMjCvqbKerwNyrYz8kLQZvfMf0PRLAqkYk27TvOE724sallJNPubH8jEhJxtwSXhfZd3O3WyfNRtijt4w3zmO7RZI/fn39bLaaq8EPAYgeUOTdNpzJaTA8+FC9GIgHILBDMGEFxTpVWKJoTIkJYpwAznX2STRp9JO5XetdffrWq5HmQQcoQioX5uEp+MB4YEwXEgMyDZOf9j2+PjtpJQfQFP8G6IAOE30ZYKFIMtEMXMHI63c1WNXRNr+xwopEKSTK8yBUwBN0AILP/xGo05LipWplWIzLMLIFUUw5txv+I7LK+QKMWHyVSr/rom3/FkokcPvRqKi6EiWXZkWoO9sSgg8xY6swAHSc76xk4LmrbZvqXYrt2xiiUQ7Zq6ughw5jNPRztZ7PLFJwx3fq8KFjRMg2SYEeCl7MK2TTpD42k+WyGPhT67tR9xgzym8XevtNficMlcGKXDGheoNSqwfYt3XzYNwnaA0f/+jAJkOt/dTkl3uP3umhtgffhp/WJ3Z4YTR9pAXBs6Ck1H/RWKtEPHifdvzvdGDY3/0V0yCdUvsRjM9UfestohpTd5CItnU3HBt6H9doX8y5IYLoDr8/XvuHm+IQ03tiFlMOQfoHwsJBY83H/CsgYhjwdeReMT7uGAukY8tybXTqmVlNqPr5rAGk6fBssUiwhaTXyN28CZPHS4GY8UBWHn/e9iQOnFFfVjdFm5YyV9E/hA9F/Nh76WuxrYY45k0BOaPKFs34QcjAbKj5964wJCcHYo3WE/ZifwHpus0nbkDgh7qa1pSb9jh1YMEsohMROBlifawkjtNrSkSepksaZhFH8OFlLCi9eNqgC0TzyFQK6BFPONAtMi7iKwRyhFygIMoPvMBLiOpwdwlQPol+tQzTAt+RugFGGiEa5RTKXF/4mL7LQ74eIwqK299CbSGHIqXJ+aE/VuqbvXBgsQ8Cr7umTaI4boc0zhgJgSy9D+Ae0CFZ9zEnRNxM7i8xFthSY23CapWOKPms0MfdQprdOUFmGFtvJqkkDhLue9UgKKC5NYJoT2dGliCGRz8s4Ux0QbW+Jr6DyoYxjjeYynL4JkCUQ7NcsDidhChuP4SrbMwNI+KWtfpxaq4HHCcziqsoXFp+qmdw6Jk7zGlwY1IJgYA9jWfDY21y1N7MEyE+krq7ZblhHpQABAIMrqiVX4XPUhM8sOQLvXAn7+V27Hx6XVahI7wavRD1Mpd9bz6Iy7vr5zfpSDBnUZlZZM3Tolms0fvTfNDPOeGIwYEmWdKkIf6YyRwFSmHt9rtzm4lkovk1ivT4LGGS3NIZ3qCYCc4vMYjDBCJaOQNe4tGCPPoqhU2sGVU/T2E30T0dLacpOTx57sZ6r4FuZgRc2JjIz7uZG4lgzFOoC228+J20MGnHSMdvqbZUWKQK1tyZFPvnEoVTX1z+nWNHTV7A1VxR2vqIqGfuNo7UakgJC20X017RmZ+abJQAlMJc6ayZSlG1haHnIhbo51dEtn7s7UhZsd+Wl8Ooctk+RzzROGlBt1FuvrJrKBQDHmgT3LI5JfLj8/GaXaIvm+8A/r7aeuS4Wc642cSbsMvxa+jHUEh51QabcRSUJsmbQnssiXQ+EqIb4PxMK50+yQm1r/xLq1Q9mwcgILYdGjRaiRa4sOuNIiBJ5E9AdWjAIRzrwHRGroYvyaec7xKFq4jM/p3SPNH5fD0IxeLdUEd8+3eLw/HXItiabX8XClP0cciGVgBy6loUY/IKOSCRI2nbQu7iQxd6w7WsdmH7K7E6+Cp2v5fBvX0ZsTiBnPxMfDOq/cIefZ9TRhrIL7eVJTgk7mXdbVJdU22NBZS+UVumoT88+JBSbOjH0AuQugjmvsVvakf65o9z7IU5Cr8Wg08OEWhzcPqMpgX5wTD52eS7CcUGCKffUkmm20qhnnbiNd1zMt7M74J4Q2rBfYvuLbffswPlrw2w+d7rfehUfHtdFewMjYYzpP3LyZ/Jmp/ohCxWdfaxbPsM/a2TAwF/f1OEq52cq2idvua","layer_level":2},{"id":"317287b2-3937-4876-97d0-a8c96007d95c","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"CMake Configuration","description":"cmake-configuration","prompt":"Create comprehensive CMake configuration documentation for VIZ CPP Node. Document the primary CMakeLists.txt structure including project setup, compiler requirements (GCC 4.8+, Clang 3.3+), and platform-specific configurations for Windows, macOS, and Linux. Explain build options including BUILD_TESTNET, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, and ENABLE_MONGO_PLUGIN with their effects on compilation flags and feature availability. Detail the Boost library configuration with required components and static/dynamic linking options. Document compiler flags for different platforms, optimization settings, and debug/release configurations. Include practical examples of common CMake invocations for development, testing, and production builds. Address troubleshooting build configuration issues, dependency resolution problems, and platform-specific compilation challenges.","parent_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","progress_status":"completed","dependent_files":"CMakeLists.txt,programs/build_helpers/configure_build.py,programs/build_helpers/CMakeLists.txt","gmt_create":"2026-03-03T07:29:30+04:00","gmt_modified":"2026-03-03T07:53:46+04:00","raw_data":"WikiEncrypted:g3OHqDqjdBWAhmAZ37hW4JJS2u8qzwOVBZXve9aVGP6gazow1Wn8Wd0+UNTa//LywYD6BGd6YGJkamwOkpXAoi0OlYTJa1FWkUUdxN1EH33gTvgfxPrMV7qyTVAROvgnOaS+tl2HssNZt7914i9BaqorW50sTZye5RfdS89LYex/7mydM08IxLGVg4gJKjYPQuSdcpIS1hg+PsDlN9X/Ug8WYWzJ+yxiG9mx1LcaQ+EI6rrhmGEdPeGU6Qw9fk7ruPSqXVu9l9r4mKjSvUhBVKVkT1jFCBng1YqT9JGF0Ab6sCFyIsYqqszQOLVi+oQb1sqQjqb3zoWeB3SFa1Lms0I815Os4GqTE5eta8dnR9ObaTP2AARVEVUdZ6XTwAhUmyuVXzTyZN1URmGpLwWgMrDc7yhhGMV7769Lp1+4GlGgsYH3BI4ib6bfIlNusoofQp42/eD+SyU89DesRdReUag/QKOjfpsM4gI5MmmTVf7/VR5anxsQqwRyee+KZc9tNkW8u1ACyQ4rBstC3cBbHCmXMO3IBU0SyeskR3omlFced0DsX1iB9QuorjlKPKOnDPGIduPawhEA9p2q/FGQlRvsy69nI4aoEAtK8a1J2btjSCNTptMk8up5/UXig8N3WCwoOHQWylIeW1FS+voCO++HTscJGW8SiGRJ4Hy4okzLnJYhSbr2PCfyU0Ky/55gZOzwUC0tUzLaYJFPT6DhdVrucg/2QGwEW3Qr9xTXZWw3dbwyyJruOZAz9myg8yALLUnLa2oPa6JVEa8rMEXPYxLwUtxTvUz/9bta1Bk+8fV+yOKErm3S3c1Iy4rvdFrAw7EnK51nRMEgByN+6Mhz2At31gy/QH6NlKr9W84zJhxL89GRL+fFeY+cqb+D67sAZwA5Os1+hmQnNA0+Br0N5RCQFesEkPBNwX/P+dCzjBFVVFQJisw5esrClIk6Tyd6ZKfkBanNs/6jz0xhs4J4cSZEuVF1pZ5EuixRGZW9lG1ggwrToUFbxK/vlC48sFwKgMqKHoGLc3hYxJnNlOBzRmeUI0NkdGyBuynWi0YwdOhD+09MwmNRaykuqjMww/WUUvF8ZBftLHxEbkRWve/phBWR3zEpEWL7hxR0ofgKgm3y1glXck1Z4D6MFhfdGwNSXyxqBm/AAmQKEXGL2XLWC6HndhK60NNddB6HnvXjUpoJGUSL27pegS/wjGD2vIA5HXH68AzH+yt9UEj1PKzxWR1Zz9HaStw5nObACNkxOW4w/+j74auyHjuFC3/Hivjjf4vmpEAeRih0rkX3wAoDqZyG7g52qWlnNwPy/KoX2pJd87L865JOVDOXYigrgrSgb2t/CZVhSYYvk5bLD5RxJIbjyewxJ8dsPJ3k9edjffT6KwJ6N53zENqv1r6PPWxM2OVhkwbnKaIw9jBL+sA41LyFEcDjG8lzKt2jHbZvSlGkFf/GMK8ULEEMcLmhsz9337fYZohcNiYN9XyRV6WIL4steB3eN0xB7x25P+N+SzYXoVP4WJdaVruEIzfzwoN0yC4v9dhAWgq4exjh9o3QbKTxrsDjyG0PjP4gBYGypP4906w87pWPHheId+lDzjmGW09YAmm6Hg6SB285rTwUs1mbeWfEq3Xg4wqmBWF8gQp/ux8in34C2cYdn8ytE52DOq5OZbPQ4L9+/cMeoXuJZUBBxogig+Q8Qa3pwTCeedNxpddMOO6/qrfMbIaCm7xlKAkvQs31RM3WucVcQeDtL/0CpS/ECiSuk5lvuqy7Ua3KtF22KFv4BRoxy3FZZTUSw76br3o0DmfPWrDJYT1VoRMKMjztGzsy9kF7S5xcml4w3JpuWP559CFPYHvxznYSLIm6QhlLbIUKsz9WGweCxOnj09bqNE+GvddfuRisAa4=","layer_level":2},{"id":"3690c93b-e823-4c69-8ec9-862feb3c3549","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Unit Testing Infrastructure","description":"unit-testing-infrastructure","prompt":"Create comprehensive unit testing infrastructure documentation for VIZ CPP Node. Document the Boost.Test framework setup and configuration used throughout the testing suite. Explain the test categories including basic_tests for fundamental functionality, block_tests for blockchain operations, live_tests for historical data validation, operation_tests for individual operation validation, operation_time_tests for time-dependent operations, and serialization_tests for data encoding/decoding. Cover test execution commands using make chain_test and the generated chain_test executable. Document runtime configuration options including log_level settings (all, success, test_suite, message, warning, error, cpp_exception, system_error, fatal_error, nothing), report_level controls (no, confirm, short, detailed), and run_test filters for selective test execution. Include practical examples of running specific test suites, interpreting test results, and adding new test cases. Address test data management, mock object usage, and test environment isolation.","parent_id":"cbaaeab2-9ed7-42e0-888e-58f1dff3747b","progress_status":"completed","dependent_files":"documentation/testing.md,programs/util/schema_test.cpp,programs/util/test_block_log.cpp","gmt_create":"2026-03-03T07:29:31+04:00","gmt_modified":"2026-03-03T07:54:54+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"ff9d9cb4-10d6-40dd-a6c6-47f4665aee8b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Debug Node Plugin","description":"debug-node-plugin","prompt":"Create comprehensive documentation for the debug node plugin functionality. Document the plugin's purpose as a development and debugging tool for blockchain state manipulation. Explain the available debug APIs including debug_push_blocks, debug_push_json_blocks, debug_generate_blocks, debug_generate_blocks_until, debug_pop_block, debug_get_witness_schedule, debug_set_hardfork, and debug_has_hardfork. Detail the block generation capabilities for creating test scenarios and the block pushing functionality for importing existing blockchain data. Document the witness schedule inspection features and hardfork management utilities. Include practical examples of common debugging workflows such as creating test environments, reproducing edge cases, and validating blockchain state changes. Explain the plugin's integration with the chain plugin and JSON-RPC framework. Address security considerations and proper usage in development vs production environments.","parent_id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","progress_status":"completed","dependent_files":"plugins/debug_node/include/graphene/plugins/debug_node/plugin.hpp,plugins/debug_node/plugin.cpp,plugins/debug_node/include/graphene/plugins/debug_node/api_helper.hpp","gmt_create":"2026-03-03T07:29:38+04:00","gmt_modified":"2026-03-03T07:55:19+04:00","raw_data":"WikiEncrypted:eLqrgRpVcICDKOEA0n6udD6J34S+nQziyIR8bhYRgzG4WLa5ANv0/roaLYs3TeIeP7yn56tSxDFQa33KzttPxAGoHkigmT38kDqW63FZVc3xiNC4E0EAXHauycsT36dSMni8zok5Rh7fOJNVNnFD7GBwP7myKymwSIB4DYjYWUw8OcBWcaTgHQKezr7ghkdwvWVqqhf4g+CLQTxETRayupQEhglA4zzqR9mX3T82A/BJgugi0pDvTTun3ckycfp9Y0es8/GyQtyQn5TSrh/lIv2Cx41w/bsselHfTaAoat3rVJSbbvv/OwaTsJD9kXu313pNMvqbEEhIxN+8KFENpwDx1xf2UdvvVaGk0V8MiFzcmi4MoBjDj7t5F7tfVvWQndJGhFlsVomAmhByzTmZ3r7v2FwDveagSGU8KQEjNHHNywtSlw+K4XbkVK9cZDJTuYyCKQw+Uh74oWPfFWlyOrI0yp8v3nwG+kSOkNQh6a0iNjYIgW+RIPXNGfUcQBpilpV1EU+R3+UQt7URK1zwudp3aG5Kaiq0w9KT1ujV9hZQTIKWQi/U554bhAeGBJdLtAeIqLCXfGq3J7yhpa167JADM7Vr6myKrlW/7sTWlhhsuCAEX0c9KviNEy1tu5q2Q4rgtnxhyTpOxrp9AIKS2Y+y3RcyqvzEs6/Z+LMoLt5VfnDg6wxjYiQmh81SjmJ31NQ/9r4/UKBjGyH8QnN6Y5s9sp+d1z9HKI3z/hqfGWWEP4LvtWsjdVN89cASmx0sGsLHmrbDHYtf9OWOh/h1+wDipkLNKrlNQAIAYKtheSzndc8ubfFmzsNwVX8sg1zGWAFLuC6vGQjzUts14mCHZvPOqQAS0BowvxXYKDXqJ4nGmcYilzH14nVKZit9y8s9ji5kbHsyfc46xPx0e862BfjcrQUyEoE6R5Yw4AFSan5HTUnfDwVt0Wa9G0vAhUxucwow7nnD+D33vOsTWh5TaTqsh+JM1EC4LEiseKdbdSHVvrpPrbWgdflzq2oiVoAjyqYgC/op8QuE9/xK5O0Swu6rJg6gzOx/t+jy7oXwDmgBnsrYWqQolvjBoNm4va8rvQ3BzQpYj2eUwKkmYce+jay7M+pXcbKEqHMNOGX7vhhhr9ZNKs3I0AYqOzlJUcVAGKDCthPfLCDOnLLeqzJMKKM5fo/3IIY6rBwySweLe5DGjiFaCUM8Vq+sr4YGUUS8ly4CDiBxg76gRV4ZR4fF5GnyhXnaVjMkRQQ/He9ln4EJ5/66nV4pwOOGVsiqxnhOqSHHTrNbngKs3H6zHgZnIN8MlAigukSd+wfZQ/IqXcUcoeH9f/aCusKF1vQXBj7lcRde9bWMK0iVYUaKJE/lkoUsK4m7wwKYmzJ7HJK8M0SPOkgMdELmAhPzl9aL95jfDNeUS2l7XQOEZSQCzNqj9RidNeFjnyGa6ikfpb0dg53mscO1r7HxUYpCW0r+aQ6SVrkNAQ+wMOTJ5wNjDoCBJLABCOg5rAGhRbyxxhOn0i0h6hvzKYkfutbEgyXvC8YhJIYezF3Xd9ymX1MhQKxtQF9YM5ESYSZFOWG7fKRMywZxQZzUBQQ3nOtL4B9FNM48b58LorztnjT/K4xUyyVnd/vXfGMLQMe1qhmH1wK2Q7XF7KEpDCQTNRkk2cpfQrWQ0IuM1eSsx/ihCl3r0HFmZ8T1C+aEkWL2ST7c3zdNjCK0iJGFE1XY8NJ/O4ie934sPPxFFjGJOstwIs8v1Aino2JmGJGHv0Q49PuX+JpVJwBJLXfhhVRlkC15l2dA1lLvx9KjUUybehBSfyfhns8rLNpc8KL8zLwulptMoo/k4bAAFHhrsZ1+t7C8izK/msOkIGXIxIXt2lhkPtiOoEyvdcv4lITND1ZwIcDvr1pKg/6QZnIheCgt4gjGy8g/tpnoUrBvTuR16lmp+FuDpHdFIEh4o2Rj8uWHopo4l/SLoqbttF1Drl57ey2Eq+MvmTxrAtG6Lw8W/wHBzU4sDCNdlogaEGovOH3kMouxPS5Lx1NvnMEHjPQHzk5Ce/4JvkpNC0rSqdb3iofuEFPwX7ZMgRYz/lyREJlJDPGY7epeiAhZ05ol5SJ5cekPZpbDRg4qjvkZ4I1PnwxJdWtcb3gRokcqeEW4466Qcq0iCaT3K/lwetu0+n5VXHRvxPbvQ+DjmRgx/MkakaRCyOQ0GtFR+LtdO5Yi/IWo7PSYhvVe0h0=","layer_level":2},{"id":"a4025412-2ce8-4c57-91cb-0f16dac0132c","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Installation and Setup","description":"installation-setup","prompt":"Create comprehensive installation and setup documentation for VIZ CPP Node. Document system requirements including hardware specifications, operating system compatibility, and dependency prerequisites. Provide step-by-step installation procedures for different platforms (Linux, Windows, macOS) with detailed build instructions using CMake. Cover dependency management including Boost, OpenSSL, and other required libraries. Document cross-compilation procedures and platform-specific considerations. Include Docker containerization setup with pre-built images for production and development environments. Address common installation issues, build errors, and troubleshooting steps. Provide verification procedures to confirm successful installation and basic functionality testing.","parent_id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","progress_status":"completed","dependent_files":"documentation/building.md,CMakeLists.txt,share/vizd/config/config.ini,share/vizd/docker/Dockerfile-production,share/vizd/docker/Dockerfile-testnet","gmt_create":"2026-03-03T07:29:47+04:00","gmt_modified":"2026-03-03T07:56:01+04:00","raw_data":"WikiEncrypted:6nDTd1wU0hYJuRoAJhne4b5ashHc1omfgy81/++xSBe2w9rUrWuXSbrEHiZ6Cy0q5An6XvzHHLEqEmHIyn2epq5KEULOgH2CqfXy5wyGH0EduXcfrSX56fWPXFubhJoHVQNhHkotTEhKINivrUKUNsPV6o/SCw0uS9y0psxcKPtjaDoh0Fsz18Pdv9IgWC70bflhQsm2jmkHFIc62gg8wOTFVxbF44Nq2KVMgUmZu8HHDVmcWYlGBJG4KP3DT1WhmlX7YVXdIyz/7tiSMjzEmTAQvZZnyO7dKtsVFg3ASsOiAFqYVsIAD2SdlPu/dd4xojgsZw4HhAKnTZn+evhBpNEpL8R9UK82ostEvM0NLTbmE0HKj4B4RySYX7KYg/1d2bpsvrnoJ/ZhVZ8+9AvHl2H5pBA9HcIqHHTTGWu/WnGJDaaSjUfCPXaKPFx4joabBkzYJin7GRLyH+5IZNHA6n3VowgfhsraSEw/MnNETir9SG5GGrWTylTeglHHrcie14oBS34syZT+fNopbAHIhb02nGx/6OCLZ93UO3EGJgnIPuGoFjBUQoQNuOYYjLOAGMP/s+sfVM3r/HZHBua59+e/1tldVB/S2mDsKp26kPb8mx7mr2k/G7ZiBT9K41KCmTJsTej2HHTu0Ht9v/g6hYB9YXKnes9JogX33PqeOULXpDei3Xh9WM8PlpHH+Z9tHuDr+Q6CI5yHVart8aTTkL8zqZFHU9Bm9Ann/Nir98TTITDtqGSvAC+73P10xOYmx6FHJlBkoD+dc7yYj+YQF5ObJ3UCsFNrDQUGXpUUsQiSJkmzKzNwLSHkn0VHNi2webLwLUngr9FCvC/l4GtYDDIR0T5p5nJaaog5uzhpZiGACLuZeGcg4/VOQOZ4USyuIqDviAtW1szf7Okr5nIG3LbRQ9SN1zIGrTkdLys3ywOkB2ZE4kiRq5+GYL5cWQJMeWBkMo3pSPrk6Yv/4zQs/h3E1T/C7t+woDjnKOt+Wntxx2CrHFr7dWF+bWjfBTmGxufuACM44zSCzhOiruhjAnz71o70QjkErs3ZDcBYfB+ilY35E4CtfUoS9G4sNESCs4tQ+qt1zPgWOKYXR//oskpoDuzS6dAEiASGk9w0r7hEKuNo/gDh/qkL7UV3HebH2KL6Ugt15CizV8jt1wVKKxi/n1rsQJy7Sj080qAZtdDosKTgGzOwW0GXxC9h92lY/2ev69kX4pfXel0X1+l2LkwkOUqf64q6OSnAmzKWC903+LQT0RnvWZKVioCDvIGH9hSjaBI9wTHVoocTVmhPLLSj76MSfVnvx/2d0AUEliHgZGNzY7KlEJxsQUEc0ZjkXwY7BQwVKrOL8boU+LyTxj8zbBoMmaEykSzX2qgSwLOd1gEsM+jXNh14gKTgmUmO81ca/j13pbb6UIn6KIaAZSQv4dht4V9WEdvUqG+o9w5HClkedaVicqnp2cdRABOBYzxqZvEaumXpOtEg2YhaXBtv44HwWWahfIlw4O5DbN8+kiJ8G8GWQbKikFzXi+5/jDhEgYeNLInwwXK5bZ1ZYQZlLrVVgHDj0SkGxKpw5Aw/vIuOLro4OvglrGOXmuo6IUXnA/5Sz3eCRnEcsSND5LWjDpt6LskiimzqDwvjDD1Pl6sd9EGaILAbu6DSNyaU/xba0wiM22V4Pu11P932NcUzo7155XM9ungXueuXGtu6w/Gf8m7nGscdJw5fqfk1uLML5/6MFsG3RjtSzTgpiPSPNaIjHy3OEC1yI41UqM2FYg33NLyBV0/cmiQxGsPPGKhSp2mJVRVT2+ncIwxcNw==","layer_level":2},{"id":"5e42d05e-3b67-477e-8c56-8aa25b98889b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Operations Definition","description":"operations-definition","prompt":"Develop detailed content for the Operations Definition section covering the comprehensive operation type system. Document the static_variant definition in operations.hpp that enumerates all blockchain operations including account operations (transfer, account_update, account_create), asset operations (vesting transfers, withdrawals), content operations (content operations, votes), governance operations (proposals, witnesses), and specialized operations (committee requests, invites, paid subscriptions). Explain the operation_wrapper structure and serialization mechanisms. Detail the relationship between different operation categories and their hierarchical organization. Include examples of operation creation, validation, and serialization. Document the deprecated operations and their replacements. Address operation ordering requirements and hardfork implications.","parent_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/operations.hpp,libraries/protocol/operations.cpp,libraries/protocol/include/graphene/protocol/chain_operations.hpp,libraries/protocol/chain_operations.cpp,libraries/protocol/include/graphene/protocol/proposal_operations.hpp,libraries/protocol/proposal_operations.cpp","gmt_create":"2026-03-03T07:29:54+04:00","gmt_modified":"2026-03-03T08:29:14+04:00","raw_data":"WikiEncrypted:WmYz76ZuIeWtQgFK+sghtXF767cgFsJhrvsx9nsFYtfB5XvgI+IY8qvYq0/h998yGx0X+Dgr2b2iLXpkz+TmgaMpxhLilK+sobWU2aqDmbDndXA6D5tjoJfNBbgX2MM+5h6PtTeEWfh3jcub/MOm1xELBWkCOIkQbR2dWfj9pwA9WHeQK/TsUznoMqR0H+eSCxFzm3sZhtTxdFcx/1X4Z7rVp+g0fb5lKts9guqJLL2vhn1p5t5f/WRbR1lj1BEEZ/H9+BW3+niARpl+aTpKliwdQYlMyMBFR1O6MPihb3CQ+1zZIx+kYmgQvxZgmI6bNmbUtVIC/GKLBX87mg3vTfbnLwXNWlowpGesnDlZzrEx3P5SSHbYPxf3Nqs58mm2D2APH5PtVfvWQM1GPMAloPBAPaqRTdFNwKynsRIs5XIUg/fwKkVDemdjz4uAF2IBLLCvE8zj59gjQtNqbkvpYVwvT3H7u2RioPxY7A83eqXBFkRBq+VL3mmcsO9mnLx9KUDuZKw5fyIY6YHPoerUxIEaO2R0eM74oxnNXt7xL3GkVlA/p5NHqAuyB93+F5B6gNuSaqLwOVk/nieLGuV8mApifQ7mvk4r8AHzD9C15Nqi8TyAcopnkZs42DN5moJpBGADvrrVmDWvV2Q9BrvsTTE06Ym0HJaGC7dQNhMCWKjTRfzWBDdd/fVDf+SEglDdfoQUAUznB7CEvOErndZe0oyC03itZBtVjtklMVwk4FGx1G+P/A6ZvfmGJ2AFAhTASyPQqVmh0nR603jwCJYHifWTY1LB+u+/Go6XNf4DGqMY2FmbxHzpIvFeKqB2gv7CAkLPClSiyeH94JUkCbUKAOjK+eCoepVsZoOSvjC8eUnlCLcCUfUxi7qPr49/Z9btwrSUVowLbTDm4CeeQe5fu4YjrrQzE/AdGNHqCC465W9MlU8ekKT3mxtAzbzvxEluttPWRbFL+krpLarjasytFvbZL1aRqUoQw8ykcV4pqLhlgW/YtbWf3yloEQ68WraohvMt+DxICjT7R9jkxdqjO6b+bJbM9JPmEoiAtb+YWmGkb6LMOPaRSoxMwnXSwfyFGGIEDdjdFwAGk/S2adZeMCfzQeg5rxHJXuwlBMP7uQF783BZhOZ5aMjIJ+V+oa5wMrNkfc8qFtm1zCTS9fhAGpzckNbcDN4+0suzZ02tJ67HMLgxAUvQxre1zebhcgRiUgPoyAYIYaajWX3T1swYPNQj1HgnxTCSaq+NFBx5FQ+hM7Ia4Z+MMKZCfE3VYKKR/TeJqE/k3MOvqLY1mP9ERiEGxfSijZd/jJdvu84QVhjcEQYfBH8JYcdJBDTKGwI9ZdUxjQvk6WqYvHeuK8ulLJh1NAlYbtUyuN+S/sXMMGCC0mLPmx7Zg4uxahTINOJk0YjNY1OW7HF8Fq1pCPMcfoJAktfYDPCQJWiYCdVtfVw4BwZYL++Ua2ZqgMwQO7YhPdlxuejDOZ7Q9Gd6symlh+Bvf9aeoor7g35mEG/98dHEB80GoqMIYoSDJ+mtVX4jhoHkQXchjzm3U9QHvAwLL8DU76a/qYcNk3urfukXMILCtf5NrzImUM8gwpoDqhmdufzhwN/s+EeykpqZHigg4Su5u7vyY2dVUKTaklPneLJXJS27W90P07vT5XVr8U9irxarAnJKIGuhllU9VEhSxhfX3reYvlZ+54yTAKHxJHtFTvV6IW9zyWD3yuFU6G/TStOV3FTSEowaJqx986hkLs4jm9/92Pcr+Q10ULV8O8YtnU0gbS4nsYrnyFnpZwzHp28UTTkNj0h45BZM+6Emm4X8GIBRcJkqJ7nU85hewo9rMxjVIR6rn6xZF5EkZ1+CqoR7/o0ihhvY2mDt5ssA+o7an71DnC035AKeCKwfOvIc10JrXq7kgExwqupQgLqcBwaaz26gx47oXEoZ0DSOx8rKEDSjfmA9WKieS7wc7D+jctLU8AZYx2rPKYodgtCk6zX/5wYlvhxOCacM7YIdkysiqZ3//7lxPCLgHpnQGyy2bdTxNWy0fB6YRZsmIufteSu41cbwK6MyL4ZUZPORdA==","layer_level":3},{"id":"eb3415ba-4213-4e37-931c-49f45d7ebe37","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Database Management","description":"database-management","prompt":"Develop detailed content for the Database Management system that serves as the core state persistence layer for the VIZ blockchain. Document the database.hpp/cpp implementation including the database class constructor, destructor, and lifecycle management. Explain the open(), reindex(), and close() methods for database initialization and cleanup. Detail the validation steps enumeration (skip_nothing, skip_witness_signature, skip_transaction_signatures, etc.) and their use cases during block processing. Cover the database session management, memory allocation strategies, and shared memory configuration. Document the checkpoint system for fast synchronization and the block log integration. Include examples of database operations, state queries, and performance optimization techniques. Explain the relationship with chainbase database and the observer pattern implementation for event-driven state changes.","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/chain/include/graphene/chain/database_exceptions.hpp,plugins/witness/witness.cpp,plugins/chain/plugin.cpp,libraries/chain/include/graphene/chain/database.hpp,thirdparty/chainbase/include/chainbase/chainbase.hpp,plugins/p2p/p2p_plugin.cpp,libraries/chain/fork_database.cpp,libraries/chain/include/graphene/chain/db_with.hpp,libraries/chain/include/graphene/chain/shared_db_merkle.hpp","gmt_create":"2026-03-03T07:29:58+04:00","gmt_modified":"2026-04-30T08:00:09.9789246+04:00","raw_data":"WikiEncrypted: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","layer_level":3},{"id":"843bdf5b-2dea-4e14-97c9-d8ddaf902f92","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Node Management","description":"node-management","prompt":"Develop detailed content for the Node Management component that handles overall network node orchestration and peer coordination. Document the node.hpp class implementation including node lifecycle management, peer connection establishment, and network topology maintenance. Explain the node_delegate interface for blockchain integration, including block handling, transaction processing, and synchronization callbacks. Cover node configuration methods like load_configuration(), listen_to_p2p_network(), and connect_to_p2p_network(). Detail peer management functions including add_node(), connect_to_endpoint(), and get_connected_peers(). Document network broadcasting capabilities through broadcast() methods and inventory management. Include examples of node initialization, peer discovery workflows, and network synchronization processes. Address node state management, connection limits, and bandwidth throttling. Provide troubleshooting guidance for common node startup and connection issues.","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","progress_status":"completed","dependent_files":"libraries/network/node.cpp,libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-03-03T07:30:03+04:00","gmt_modified":"2026-04-30T07:20:23.8239769+04:00","raw_data":"WikiEncrypted:84sa6bLhPDu+UNjxUZw5rBAx9KYoUICf6oS5DojEq7h6OODVm92LmG6NSFskdLu4/BlwSqG4Jzo94ijeZaGGCOMnja8I3tGAEbT+3q+n8m/dw+d6coAvelXNpimAGqE+UgFSwNQ+QleFS2KnlnP0Ei+AyYS+W93RhzWk27zbV8GPjpKgme0so6woQQiGN1PmaTl8u03kRB5fRh9sxqVA8qa8YqnyO843mBnm8gceC1VG3ZkElSRJiah67i4rB8mwgmdDzWJDST7UlTgRtRQ6kxvZezrE60FHupzXUoNpmUzeCjYMp4HkB0VGqrOY7Q7zRwtBoyE2zfnXaZuAc8wCdI0TDc8rUfDnRTs2NEQ2+JDZfNlxp+Z5uhT2mCkfhIl0i8ciNT3yXwkxKft6tBOl1KVNCygqrecBFFjE2BprTsr8xv0rYl9g4nMfF8Q55xZxtZ0nrmobnFWDDLiF+5h6wM/rDMGbj5E/+UASJZFSPt4j/cQEKAjp5qI5Axm1BIDHQNDHicG76LbRl3iucTkM4QxCdPYuxcfR3SmzTeFQs2fnkQZKiwMAdWH9ef+B2FDRSverFsTbZg+sKOOw1MpmhghN9EtU6vwfWNi3TzrRj/VRfEnXqE50oX//jSWPsHota4t66ggpqucNRGurBl6aZfFkRXCSFyaYCRmH1sFMinKNS0aijN8tv6oPCYRS2atr0kIBzAX4Ru6MibCtvg80eKvDYujvZZr0bTH6Uh0fmuZwOX7YaDUX1KwBMuja4CmFymM7SGjnkJp/EI44GraxO1o0cuX/hnt5+jmnRqxjqQF5wJ8Tngw/Q3amWUMURWQhBFLGm5Af5QL4Hw5QDvbIJOl/gul82CDG6CC+TP4yW2TFhreAeUNMT8V+n8elOHPgLu7D1EtrLPjg1R4eU1pk1dIRJzlubWIspbm+ymQmlZzwV3AuDT3Eyu4iaY1qta/ZACGBg/DAHUgPDJIExAN5WVclSnIgChTAuOQoEQVMKRVb8oBis85sOEllEH2leXd6p4/vGKuhtX7F70sXWD/OrVT0KA5r/NX/+XUPqKH9WhVgt+kDGu/JcRKm/4MHupYjESCvRTu6orYpKaPYUC18zemoAkkHISq4eaQ4oDoCeyD3T3whl9FqTx4+RoYOrkMAStdijoz2OhY+PRgGaOgiO7MdjnDpj8zlYqbG8A9M/1Wal68lu5FLaOE8slWUY7e29fDGlQUDuUmkkx4FGt1XFM4ID7WgsmA3aNs2miYR/6ROruJVnMBP40Jp64j+HTyBlmE3zphn5KoQK0vPTcWzlXefUYsqxmCjwJ3xGytBa3Tf5p+pNj6gFMNTY/vP9d2W3IRG9Fanzo0hv+MAC4R5VLyipO0vFhsxx5veCg9bh8ZWZW5yobkatfzV/X+gS/CqtWBHf03gDsoxYbdfeLYXcrM4KvREqgVxShOXEBwCdo/g+ukZJkzzc1QYYqEn/Hptz4r8ByAPMzclKREd66MZDBbCj1goZ+J5MWyfy47ZXPJ10iT7neBSO8ggoQGAEs7RXp/SmzdmpYPRG3ScDN7RYIX/K1KenyTNlLuSXQYU4dvS4LmzX9hm2TAL8KScg6z4NSvtYSUR91oZ3EQFL+anrRDjR7TyasN4TdhENpsO2LuGTCeCFqGfDEsPfm06cB42ecQAwzAdVsOaHwhnpibENAAy/M8qD+tDmEiYAkqRDN8FLaIYjC8rRxUHQlx0uamaSK49tqLLd0OqNnpbG9HcJaqr1J1FjhffzOh5q0p4R1KY4ekSD3081e+XuggoOMzQfaJrMWcu+qIA3LFPGuBrC8J1ABpqqdvmYcsiO3d2aE1g1C1get3PYOByvGFsRCDu","layer_level":3},{"id":"c634ee15-c5d1-4600-8f5b-96016ecb0773","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Core Build Options","description":"core-build-options","prompt":"Create detailed documentation for VIZ CPP Node core build options and flags. Document the primary build configuration options including BUILD_TESTNET (enables test network compilation with -DBUILD_TESTNET), LOW_MEMORY_NODE (optimizes for reduced memory usage with -DIS_LOW_MEM), CHAINBASE_CHECK_LOCKING (enables chainbase locking checks with -DCHAINBASE_CHECK_LOCKING), and ENABLE_MONGO_PLUGIN (compiles MongoDB integration with -DMONGODB_PLUGIN_BUILT). Explain how each option affects compilation flags, feature availability, and runtime behavior. Include practical examples of CMake invocations with different option combinations for development, testing, and production environments. Document the relationship between build options and resulting executables, shared libraries, and plugin availability.","parent_id":"317287b2-3937-4876-97d0-a8c96007d95c","progress_status":"completed","dependent_files":"CMakeLists.txt,programs/build_helpers/configure_build.py","gmt_create":"2026-03-03T07:30:07+04:00","gmt_modified":"2026-03-03T08:11:41+04:00","raw_data":"WikiEncrypted:+hgVdflPLL0xmma3oFcNhzO50UdlcHF7zsXDx81IdubJW/ei3OO55+CdCQ8q5WiMdgjekSxvQIh/JW4dHdtvRsVOk97oJYxDnpMU2nARwm7MPVOE1fvGf21aemNsnNtFwaR6q/t3BG8xZS4vVWZKT5owJ77uYsNkUtyJqPayPXgZ6JPk8AgN3ErlK0xSf5sEg+aXImxZoamSb1RzUCLe/AJrMfwO/39F8fRnlooSObSAG9972AB8S3z8qkdT+/NvoP7Yu4c+O4xbkxSPRhVqqoDVzk2WqnvhZkuaibwIrH+emKKGGpww3D5gW5+moLgsLDC6m73VZEeZGSxbE7nms4iAyAJOciJRbc/48yTJ/q3q9oq0k/pV2FuB8A68A1zDWZAlutbh+29TzGfMBPNP1Wxrhno/VTrHMYsiQJOS6dZRxbbN0J/ByB5w5/JmntWDkKeEvOWRKrsw3CMHsKX66UataOYI1UWdk2eEDrSg4SRkNcr3T0prOUhOLk2WM73mmQYCcx/khTM2OtOAJoTBpshyseGs2nk+BdX6kCLmTglTkyiqV+OF0ycuk78gFPSyOQwkeOd6iPGQfzI3nr9VnuL8WYk7kBH9BCJcQTHkwRQjKZejrIH3O5WrLuzX+w5CTP/BrEW8dt29CEh/0s2L78fJo5pCvOsQslGF3j4tRYrDUGtDQ54GiDt0iYCnAIfzF27DbyQVNIkiMfPP9fmE0FoR6wYQKc7FT4NfQpMKTV1xjOzsPolWe2rzXbormwz9pfS0XN3kuarDHx1/UsspkBtInazzzduegUsyG5o1YBrMcnTKcmqphnb5eaQ3+QDWGjsouQfpiCUvowvf7Ajz9YMLtLvcPUK6fTnv47i5C0Ny5eNSnPexPKX+o2LEj1I46MTt2FZz9/UymAj0n5UlOpM297SrQ+WQoJBWKjh03W1x/aWrbpWhLOwmLQVUDz1lGMaKv68c9gNOWX3R8dtU+SuIfFQuMY1XgNpnzH+I1OsbcwOJNB1wtlirZ/XckeHB9fMocf8MICEkSMgPIS4PmRAfUJXh8Emr6GHkO/HIRdzEVykq2GTsMKcTIsnYzLwUsfmy1gH3nXTJRUvP3AdwxG5N4EG4ijcxXFKwenNLlvpzXvG/2uEgZjo728S+7Md1vhLZJ2dsepImJqn1TmEZv5WkEj3lbkemcfx37pZah1qkYgav2mrEVUBqbWdfZpYy6IwDPUCgE5TBzdESGu49HWgYaWW6oug4PTcbaul49Rbiv5LMbfwHEf4EKvuGqQiwjgcWsz+57SmE6omFem0XKE7PUiGMzl1vSMwIaUG3pfaRSMKE5UvrHPHaR1SrsVXt6OQ76yjj73HerLdyDRInKoUzQwkZ9jaHE1hft4Yste+Lej7O2OrUSKE4wzhhVBkwwh9AIUqntzEaaB9U4lFVk5uX6v6IJ9ssNwZMzl5j8bUVDfb+HDc2K26alme+A0EjEKlIL4ENYXCZk8zoRhhzibeDx1ZEZXPjSKdZz73dORKb78hvre4u88arxQuxwmwt","layer_level":3},{"id":"85611a9f-1537-4247-b45d-a6a5bcb6a4ca","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Production Dockerfile","description":"production-dockerfile","prompt":"Create detailed documentation for the production Dockerfile configuration used for VIZ CPP Node deployment. Explain the multi-stage build process, base image selection (phusion/baseimage:bionic-1.0.0), and build environment setup. Document the CMake configuration options including BUILD_SHARED_LIBRARIES, LOW_MEMORY_NODE, CHAINBASE_CHECK_LOCKING, and ENABLE_MONGO_PLUGIN settings. Cover the dependency installation process for Boost, OpenSSL, Python, and development tools. Explain the build optimization techniques including ccache usage and parallel compilation. Detail the runtime image construction, user creation, volume mounting configuration, and exposed ports (8090 for HTTP, 8091 for WebSocket, 2001 for P2P). Include practical examples of building and running the production container, volume management for persistent blockchain data, and network configuration for node connectivity.","parent_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-production","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:13:22+04:00","raw_data":"WikiEncrypted:1PcQ+NupkgQiLQ506NXlam2NaTESDp42+Zw7VpfY+CzCiLAg7GShqb8JCcPdfBZaP7WIo1Mgj6cRsriY4RimiUKdLamglD6mtocdtihAp1RQvMgjoGAVK79Z0f2cu7KECfA2Z+Ievqh+9tvt69UamhE1qHeFeJsTu0aWWWpl5rcj2YSIR5H0RebtCzB36Sv/CERib288ap2vqUEZU89BGsYKIWlHMuGgzeFzUMYrV+wk9eG5jVZjG906/zYCaDWTbh/TekpxoiIf6HSW4xXhrMD7AZJWn5k0n6jctguU6jEHQP9nzYFUiTMQ2lMvD/jnXKsLpwJqAZR71nU87TaUO8FVZul2iQ+vQFFwzyNXGE4ddtidjCMxKR2Ww73haXvYbAKHAAAdbw0OXyAcdKL7K2fcga/3WAuxnWWVMGg+E5msVSmXsJcIZSV5C5r4Va9hWjxCi27IEGMvBsLBQXwRNsAn8aSlu/fa/jYxeM297Dx450DFq32jM4NPOOXjC5XJaOBlCvsZa5P7zSnR6NJi/X+7fWOw9yjkvU8Py5K3PMH2RW0KfPHB4nSgLXhw7SBcxT1sdiFVcF6VrY01bksI3y6ZFQeU2Mr1vAWTAnZvhbpann/UGYuYmo9u7R6+OoRu7tP/uEmnBKM159+qF/2olZ7ZKbq0jX9b/9HGNcCEWiPovpxyKkfyNvPpJwaiKsoQKs7Z7VJXgM3qZUJI591RB+ZcnmWCqM8nEQcRvf71HmasT4O8Y3sTM2dBr8kEZhAlpbsQKQuv/tO4kgC39gsKvLSkt5o6PZ8rP/QWZKPdyO214qNoge+jhAzViysspNcJh6FXLe3DD6YtFK+txrue5yI9R1M3aoDc/bXI9A5j56VWBYXHbfPf23c5SX4VJL1tryaUnD7HopiWlFdRMMWK4Lkn/2+Q0acfSzOCJ0FwsfSAC8BpfNe60OO6hYvSrt4uhGDRMGa3SGJOJGLial88QaoDUKgcHRRq6xPKtHWGyD/spZpRXxFYPZcPv4y6RRPSrcytnWWxf2UWcR+HQRb1V4MNKxPXh0RW3gSVo9D7smSAIXNAwuZ5uJBZvg7CYavG0mjPm9+32YDh8vPLBHGXUa4i4T4KTfEvENMVQuZVw0amZ5S231HODaR8LmFhvy9QjC/c0hlkiAyQP5zq7Qh9tc8eQ4p8tuxKAPtrhzVy1xTTKXNmZrKKD55p/3sootgWp8RzFJapVolQ4JkSSNZVtNP7J04uG6jAGktkZw0eHLya0dr0D2IRcuFXNoDjTPzy0wVnv3PmAu8ao05iAinwPhwsx9RoTW58m44Z6rqM6uhOkoIi60y9hPWNK4tNtipS+4aX2ZgQanujtzdVUqDmmDQr/q6VdzTCSHieHN5LHp+5aCHW4oKBPABE9RL8gnzlgRxlPxgRzXW0rAj9TnTyuiD8c3HskKJARSiBAcF1oZKweAISYXvb6QGe1TG87AcdEsvUtzDqgcZuKJvULl/zRwIkJ2jDFaDAeUWeORgrzmYEFNQjYLKrqNZULFVqRxeouW732TCle3fBejZlmUVGxfeshmIRsezj254Gy3zs35hkwnB/9C/kBh4EfPu2rzOAqwbIKoHSfjewV2R4z74esD2maXgH255Nd22YvowdyqvJ7UyFouWyze17p/cTLztRvKY2xfFFQ/DFa8DuFRmLSA==","layer_level":3},{"id":"d0aa68e6-4e49-421c-8bfa-6ef641cd6656","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Code Assembly Tools","description":"code-assembly-tools","prompt":"Create comprehensive documentation for VIZ CPP Node code assembly tools. Document the cat-parts utility (cat-parts.cpp) for combining source code fragments from directory structures, including its command-line syntax, directory scanning logic, and file concatenation process. Explain the Python counterpart (cat_parts.py) for automated code assembly workflows. Detail the hardfork directory (.d) processing mechanism, file sorting algorithms, and change detection capabilities. Include practical examples of using these tools for code generation, schema assembly, and automated build processes. Address command-line options, input validation, error handling, and integration with the main build pipeline. Provide troubleshooting guidance for common file system issues and permission problems.","parent_id":"d54afe72-4975-48c8-b825-ab792ce92a46","progress_status":"completed","dependent_files":"programs/build_helpers/cat-parts.cpp,programs/build_helpers/cat_parts.py","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:13:01+04:00","raw_data":"WikiEncrypted:Ux5Ub3OP0MtzohTlWbMlC5lEm19o2HQfwDVneLB1a1hTXHDwEhsig5jNN5z+LIXqsxmLUM25wY69aB6+bwuz6D/wkQEy8W5IUBq/kV+7tBHA+L6qCLLNXOlhHVGHuo6JbY9p5a9HNMXuJ5REPOH2cRjbMvOpX2JPYNiqO0206sp7CU+POZ9RIr3gREMK5LT9JmW1upbSPZzeGpNAVcWFEvpI7hlGDI0xytSGBevLkpSH0dT1FJ93u/i1N/YAwGNI7V110fcuiklNuAMYwCAM+sTshWG1AasofpIxFVC3HWLgQc3T6aGyEx/vw988/JCZ3dzRc68yQHQgLyzP+e7VTGUrkw42ZTu7b1d0sFkwjZb3Q8i+O5hhuWGjDAb22Pnufu7fRCCbKxLrbs2IFj0YB2urm0PopQh9GmAVCyiTaLtmt2/GkT96Z5vQDYVAkCAXtWP/eXVV7W7HlEZ+x8N/gBpkGiAzDeauGpvdlpZcFTEv2jhqXIdDe/EIWHBYJ18Nwed4Bv3UQDgYA5s5TUXeVEyRF9243AurwhVMW0Y9x7figiVO3AFR5yoHHxjPwzLkI0F8Q1PLK5zs62CmA03WCostwnKhqG1Tj2x/E80KstYRsF7pR1TwqOmeX5gvlNeEir+x0afFhDoXKKLmFUhmqq3mThWMoxONDYxZSSFUNyI3oPDBvVyXHFQglhuFu+ZxTHn7fz1Tsced3XnAHVq/pcbZlt4wi5umSVXi1mPrz9zBZN9irqYU5bU20vhfwqSuLI/s911aqeeJEPIIxb7paftniC2Ou7p3IraD3n026CfuxsgUGDWGLLsopvN36hlEnPXNWCZgU1dVRqd/Na5f5DjzjUc25GCoUeqOSqboRpjxki0D7e5OM232kS+KKeTKrXQX6QPba7xdzt9dPKEfs2ehTU8E9OnosImfPwc7FM7LIswSmEV0xvaXnJehqLwtNs7ABTiNyZ3tst92hHxxBU6YtNfSCFk6lqVzVRBci7stxUXbF9JkIVPnRtaSqJhTQfd9RP9hfTOvPrihnlkWRJzyOMH2jhuVnCAMTFgkUKe8gVqBGrBLoMY0fzXFrkfsNvj5Vq3Rd9SmCtCHH5CvDL3FvgPJmrmwzbaVrQIThX9c383OKjjYmC3PFTFOekX7IxgCvF9eihK/cCM4WWMozIXKkm8UYPEtKApNGLISn3KlPrI9yOretN0iKCHD0gjF14ZgrGlpZdhtp9mp+9YIqTZtjCDAW+T+rgC/rEPcHwcNFJfpWEXvS4Btct7MDBZUq/irXLxBFJe6Js58ALQtDOPVtXH3F8wzTnsBxNeqgRcFPJZhksU2iu1OGRL/60p5RYLKGJ34USY9z+LghuRBh72H2K6GQOtlGNPjOyF9PlQirmbNa2iTGZv6RSnOAXUgtYRVY6FR7hul7EZ0V4V/oaBEnF1RjxZJlenfKmY18X2+yn5pmAy0s6nKT2rkh9iNN1f/LajWKwoV5kQfiyIG7VI2+eIKJq+u6TUy+VmmF630T0evodIP7j1gmAiqx1IQnqY+scdhg1aDsmUymhwjg76gHZ+BnMqHxas940dtVvNZsJT+ZDMIPoI/VF/2x+Jj","layer_level":3},{"id":"cb549eb1-0a24-4153-9474-eae1ed48e8e1","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Getting Started","description":"getting-started","prompt":"Create comprehensive getting started content for VIZ CPP Node. Cover prerequisites including system requirements (Linux Ubuntu LTS, macOS, Windows), dependency installation (Boost 1.57+, OpenSSL, CMake), and environment setup. Document multiple installation approaches including Docker deployment, manual compilation from source, and package installation. Provide step-by-step instructions for first-time node setup, configuration file customization, and initial synchronization. Include practical examples of common setup scenarios such as running a full node, testnet node, and witness node. Document basic troubleshooting for common installation issues, network connectivity problems, and configuration errors. Address security considerations for initial setup and provide guidance on monitoring node health. Make content accessible to beginners while ensuring experienced developers can quickly get up and running.","order":1,"progress_status":"completed","dependent_files":"documentation/building.md,share/vizd/config/config.ini,CMakeLists.txt,README.md","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:31:32+04:00","raw_data":"WikiEncrypted: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"},{"id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Plugin Architecture","description":"plugin-architecture","prompt":"Develop detailed content for the plugin architecture section. Thoroughly explain the modular plugin-based design that allows for flexible feature addition and removal. Document the plugin registration process, lifecycle management, and inter-plugin communication mechanisms. Include concrete examples from the actual codebase showing how plugins are registered in main.cpp and how they interact with the appbase framework. Explain the plugin template system created by newplugin.py and how custom plugins can be developed. Document the plugin API design patterns, including how plugins access the chain database, handle operations, and communicate with other plugins. Address plugin loading/unloading mechanisms, runtime plugin management, and the observer pattern implementation using Boost.Signals2. Include practical examples of plugin development workflows and best practices for extending the node functionality.","parent_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","order":1,"progress_status":"completed","dependent_files":"plugins/snapshot/plugin.cpp,plugins/snapshot/include/graphene/plugins/snapshot/snapshot_serializer.hpp,plugins/chain/include/graphene/plugins/chain/plugin.hpp,plugins/chain/plugin.cpp,programs/util/newplugin.py,libraries/utilities/include/graphene/utilities/git_revision.hpp","gmt_create":"2026-03-03T07:28:18+04:00","gmt_modified":"2026-04-15T13:00:48+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"cbaaeab2-9ed7-42e0-888e-58f1dff3747b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Testing Framework","description":"testing-framework","prompt":"Create detailed testing framework documentation for VIZ CPP Node. Document the complete testing infrastructure including unit tests, integration tests, and performance benchmarks. Explain the test categories including basic_tests, block_tests, live_tests, operation_tests, operation_time_tests, and serialization_tests. Cover the Boost.Test framework configuration, test execution commands, and reporting options. Document code coverage testing with lcov integration and HTML report generation. Include practical examples of writing new tests, running specific test suites, and interpreting test results. Address test data management, mock objects, and test environment setup. Explain continuous integration testing workflows and automated test execution. Document performance testing methodologies and benchmarking tools.","parent_id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","order":1,"progress_status":"completed","dependent_files":"documentation/testing.md,programs/util/schema_test.cpp,programs/util/test_block_log.cpp","gmt_create":"2026-03-03T07:28:48+04:00","gmt_modified":"2026-03-03T07:41:49+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"2c57cd51-91bf-4148-bbc4-53fda0ff7ec3","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Build Configuration","description":"build-configuration","prompt":"Create detailed build configuration documentation for VIZ CPP Node. Document the CMake build system including available build options, compiler flags, and feature toggles. Explain cross-platform compilation requirements, dependency management, and third-party library integration. Cover build variants such as debug builds, release builds, and optimized production builds. Document environment variable requirements, toolchain configuration, and platform-specific considerations. Include practical examples of common build scenarios including development builds, production deployments, and cross-compilation setups. Address build troubleshooting, dependency resolution, and performance optimization during compilation. Provide guidance on build system customization and integration with continuous integration pipelines.","parent_id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","order":1,"progress_status":"completed","dependent_files":"build-linux.sh,CMakeLists.txt,.gitmodules,thirdparty/fc/CMakeLists.txt,thirdparty/chainbase/CMakeLists.txt,thirdparty/appbase/CMakeLists.txt,programs/build_helpers/configure_build.py,programs/build_helpers/CMakeLists.txt","gmt_create":"2026-03-03T07:28:57+04:00","gmt_modified":"2026-04-23T06:46:47+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"7c381449-9427-4fc2-ab03-1a1301da306b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Containerization and Docker","description":"containerization-docker","prompt":"Create detailed containerization and Docker deployment documentation for VIZ CPP Node. Document Docker image variants including production, testnet, low-memory, and MongoDB-enabled containers with their specific use cases and configuration options. Explain Dockerfile construction, multi-stage builds, and optimization techniques for reduced image sizes. Cover container orchestration with Docker Compose, Kubernetes deployment patterns, and service discovery mechanisms. Document volume management for persistent data, configuration mounting, and network configuration. Include container security best practices, resource limits, and monitoring integration. Provide examples of container deployment workflows, scaling strategies, and upgrade procedures. Address troubleshooting container-related issues, log management, and performance optimization within containerized environments.","parent_id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","order":1,"progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-production,share/vizd/docker/Dockerfile-testnet,share/vizd/docker/Dockerfile-lowmem,share/vizd/docker/Dockerfile-mongo","gmt_create":"2026-03-03T07:29:04+04:00","gmt_modified":"2026-03-03T07:43:26+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"30dc8338-1212-4946-a037-0fcb2222ca44","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Inter-Plugin Communication","description":"inter-plugin-communication","prompt":"Develop detailed content for inter-plugin communication patterns and mechanisms. Thoroughly explain how plugins communicate with each other using the appbase framework's dependency injection system. Document the observer pattern implementation using Boost.Signals2 signals and slots for event-driven communication. Include concrete examples of signal emission and subscription patterns used throughout the codebase. Explain how plugins can expose APIs to other plugins and establish communication channels. Detail the plugin dependency graph and how required plugins are automatically initialized and made available. Document best practices for loose coupling between plugins and avoiding circular dependencies. Address thread safety considerations in plugin communication and synchronization mechanisms. Include practical examples of plugin-to-plugin messaging and event propagation patterns.","parent_id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","order":1,"progress_status":"completed","dependent_files":"plugins/chain/plugin.cpp,libraries/network/include/graphene/network/node.hpp,libraries/utilities/include/graphene/utilities/git_revision.hpp","gmt_create":"2026-03-03T07:29:09+04:00","gmt_modified":"2026-03-03T11:26:31+04:00","raw_data":"WikiEncrypted:+VS3nPXgxjNRzComTBushLS5L02zjsVFvaKCFsqlKpfaDTTPhP96kOqBLeSiPQLmJfMOrOA/aPyYvvtobOnI+yTy5f4Y/9dCTolJoifXEZ5XGFZqDjDoX+djFBEuFlLpFGPST8HMi5z0Ch/1DOLnzXQnZlkaKIp93GltP3r4YI5EER18kAyvOB0UR1rZAxG8UmuZGRoOeXBu0QnM0v3Xce8hayEwp3K/c36ogR1Qn7rZRVjpgCnyg+JP2l6grJxEgapS9MM4uzsM+Ku2QJq3iBjKpNcAZ6WmWmyMNpd6LesnnwaUonLuQ4YvpjRnZtu2lxPpCCkb7x1aYhJNhyhJr7lZkv6hmSrH/NFcjzW50VwA6Em7zVksqvKRHnrksPvdmJB2yWPRJ6MP3Lh+1zBUke1tfZ7evrMKetz1YDTeUWWu+3agM6kRBztnYqRzt+Y3m0UZHdyGo4XFJxZ8qG37YiuKh8xqwnalsKBrw5H7/qRF/eFE5AsjH/YG7zcDUtzMRgM+ajOULwE1//efI2uZyQfmQBLdop1uIFPEMAx/NXkHp5XYHw7pMpqYjjQGCGrI0L44iup2Hpb3t2EGQk5rubDPVo1hYprbomzKYd+3Cn9x1PyMFfGgrIUGNlHUPaxRZU3GgOXGJZ5jZkp5NY54lmzHhkUsxFqg2pKZhTFPZdG2KZJVn3lPEwY9VgOTYSK1mBkHD70mY+1hbRVecnF5biyhKYdxF9EHBRQmdwajNqqPikD4ZQHJztBaN0+1XL1B3E0MJF5y3SwH4i5fqn0nlx3dv88Gff7qR+VqR10q44CaCKYB0Y6xH8rWXqhY615nAuXq/vxY266kyLPhPbI11pWeCUqS9lM7EbQBUlH0Nl2HWMEtF07m4WGB2cFFC0nl0ncXt+htNKg9FQwCluyVL57GanbdPVJAXZHb/Lf663Mvkmy73MHwlPsdOX9JlciDGL0hvKypGxgJx/YXIS9sRec1lx8quZc8pHsMEl8w6+hYdyViF1Wi8K5uNOW5B6dK0N8VxDbgLarfB0b2tX+9W157CYhERVOXIYc1wwhGpMgbzpfrrHixuoUZwQHK2Vu2pUtFiq1x8utSzkwTfO/utllIdTkjMcm/rCGus0j1Gxe0GNTxjpJY4mJjFYDOTpqF1uFBlFy3z3P+aDXUktOK1/GvaHAHKaT9S+4m4n5PSOzjMSnTs7tI3m6ed9yvWgyD5NXmg7WdzkWu+1bmGXD7FkAxqM1n4ftetysxyvLJfm6il0cF1wj/r/gsAR9rXYdeaR/4YT46kEbQCKJNJ5XuE26c7pc3u53eafEB73iKkZ5DgjEdZvjeZEnQMYKoAYgucfPlmF6PxJGpNSzGg7GUrUk8bgQoz56XfSi/UPVqHvBzirD+HOvO0BqMFBirpsqit8ryr1rcIsubw9x/qpnxm32RWo/QZ/J+KTY2WScmFdKTREIXfPFgt8L5UH5+ZiUEHT00xmtYq9T4uWDklpxy4dDFpwdgzRQC6kdKLgSopQ0YTkb0uTzHOGTIzKcj0Qu7MDmB3JZOfN4GIzaRugdUa8ia0oyZsYHKdq1xd9jg11jOya0autYoLgHkNYV5kzcMIYWAAx7AkW6QqbAvd0Q+ZkpTF1hgq+dt3fJ6KUHA9feV15PnROyq29KGCVOFMahYdN1R2Um2mkHNW2xlpNO7w2TSXzFhPuLJMLd5mAfIXWt/Nyq1qTOe5nEQ0HxtWCqz9MRP+JyTlBDOEXB6TH/VrA==","layer_level":2},{"id":"ac1c2473-448f-4372-9f6e-3715d530d978","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Database Schema Design","description":"database-schema-design","prompt":"Create detailed database schema design documentation for VIZ CPP Node. Document the object persistence system including chain object types, database schema definitions, and storage optimization strategies. Explain the fork database implementation including conflict resolution algorithms, branch management, and state synchronization. Cover index management and optimization techniques for query performance including primary keys, foreign keys, and composite indexes. Detail the object relationship patterns and how different entities interact within the database schema. Document the schema evolution process including versioning, migration strategies, and backward compatibility considerations. Include practical examples of extending the database schema with custom objects and optimizing query patterns. Address database maintenance procedures including compaction, cleanup, and performance monitoring. Provide guidance on designing efficient data models for custom plugins and extensions.","parent_id":"7a20b53f-0b97-40ec-a630-7e9171a04006","order":1,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/chain_object_types.hpp,libraries/chain/chain_objects.cpp,libraries/chain/fork_database.cpp","gmt_create":"2026-03-03T07:29:10+04:00","gmt_modified":"2026-03-03T07:45:31+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"0b0666c8-2764-44f1-b24f-7a1cb2afaf30","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Block Processing and Validation","description":"block-processing","prompt":"Develop detailed documentation for block processing and validation mechanisms. Explain the complete block validation pipeline including header validation, transaction extraction, and state application. Document the fork resolution algorithms and how the node handles conflicting chains. Detail the block logging system and how blocks are persisted to disk. Explain the role of the fork database in maintaining chain history and handling reorganizations. Include block production coordination for witness nodes and block acceptance criteria. Document performance considerations for block processing and optimization techniques used in high-throughput scenarios.","parent_id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","order":1,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,plugins/witness/witness.cpp,libraries/protocol/block.cpp,libraries/chain/block_log.cpp,libraries/chain/fork_database.cpp","gmt_create":"2026-03-03T07:29:21+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00","raw_data":"WikiEncrypted:R9i/29qd1Uv5xEgS1tKQyKa0Xuqqfm5cq0GV9nRcndmrxsHsnYwJpAewisCUpG2ti9GxrCpxWosUOZaN9wIJ7/8/157xbaOnn2BOhyeyJDPEjOCeYSYjSjv1dxVt5lXdexGoI1KQL06BJsml/tJH8IGm3rSrWyMIJMVaaR4ggiUXOi0xrhPWQEb81TD+YKTlP68hIAEoY/BgSD3P3x3UVjbs9BVxlAPiZWRZtien2V8UiacqqlcKd/5Bq2z12bKdYKcIEsgawje1vnwy2FUKJpIxFZv2NRXi0YFuqTm1zjG5BYFXJtVGvg05szjd3u0osAndDv7ppuz6jwP5/Ew6xb5yos1BXUZKwLOb51aL5gOctkofzduDa21cq/a5y1RkqN+JkJHtVvUh6GpVkgf3cnVHO6oT1iVdi0EdN7ZqINAFcNbEpuCy9EkuvLFpJLSkh3DxvcnxAcCAvHXwF5fHMCC/zMpnOKQ9zMRA/NZbTMSpXtJBTezjkek+AT9ZokXCFWKUfArjXrp5XMS+ATDnIh7L5AWKZGNDCEhqokyGPVgYGyv7ITpD72SMrBjhhOOWpIBXbKvIkk8rV+KFvCgf3RU2Q5FG0EtbMj9qRS5i4WfhrADrKQPy+glGZLUE3i+MD8PqBVHJIM+cRq7Lt64sagUd710RSlu8axcaqivTj+yXzoOSmHvwVpgcU5oej6pNNR2jpAROGzjV9wXJWtgVNUYRyurjx1qi7EtmAsVYZye4c+ZsZjpzsnZqM88dMkuVDMx0qqMnS498ZQjdD6wIaxyPjrOFisUxFquVSzmrX5I+HqVSRMwu/e57OtQoLrfcOMI0kJPBNDrhH+Dn6Up2IzrTbYUNWgpMBLYLdxgBXoHgpJSEyzWV/gEI7+hO/5FqF3Pm9Em4gI9ch1SxblixxbUx+v3U/uDD934SQIebN9a7NXyZ4h+cXJLeR3iB+d9Ac+Z+tfx4j+ilQpBbzHyf7YMd/6nwFtHiAlrny4Ufp0Xhqm/VfELNse22sQdtsHZbd2CwIUmBiYADfZb0Y6X/phX3Mm0uMwodc80BGBo2g2+5Qa6b3iWBTr24aPcl2WkMWS47/AoLOzAbX2m6YUDJdiQQy8Fc5k7KnynVUkLlhr+QWyLZSSRcGt7lgpZIxHGsZJ08wl+L6Ws2rmSIow9ix5yTD5TTnZDSryfbYLt3a9fLIiIlLUe09j1jJkey5nz/DQq4ViHMVKC5/zeasHPTf8YSwUi1MJ11HbuTUYQrumO4jVflatFhP2yEmcZoeKFPELBAYUeXcRd0+wvKUb8kHRrz5pYrEdeIR6BFmxaZCBmoWxuSSzScFqvzaBy2YVOJhnfHOzlElJ2+r5e1epviiKvXNaEPnJDCnTdAPkppTGHPmHDc2dJt6EioeXY/JE9+2iUwBz5LlqmyiYw0gcTkptait8nAZbQbmWfnOppYQNrNFcOCewTodwFUYqjuDVILIWbf+MI+WP5f31Zr8VXFAyiXGVukmKTYnNDDwtbVJTP37RMyKAoDi4BMfS+KldcJHXfH8HxKQDF43PY7BCu2SQ==","layer_level":2},{"id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Protocol Library","description":"protocol-library","prompt":"Create comprehensive content for the Protocol Library that defines the blockchain's operational framework. Document the operations.hpp implementation containing all transaction operation types including account operations, asset operations, content operations, and governance operations. Explain the transaction.hpp structure for transaction validation, signature verification, and operation serialization. Detail the authority.hpp implementation for authority requirement calculation, multi-signature validation, and permission checking. Cover the block.hpp and block_header.hpp structures for block validation and consensus mechanisms. Document the chain_operations.hpp for blockchain-specific operations and their evaluation logic. Include the types.hpp definitions for blockchain data types and their serialization formats. Provide examples of operation creation, transaction building, authority verification, and block validation processes. Address the relationship between protocol definitions and chain library implementations.","parent_id":"139b0217-0190-433f-b41d-60fa08c9ee5f","order":1,"progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/operations.hpp,libraries/protocol/operations.cpp,libraries/protocol/include/graphene/protocol/transaction.hpp,libraries/protocol/transaction.cpp,libraries/protocol/include/graphene/protocol/authority.hpp,libraries/protocol/authority.cpp,libraries/protocol/include/graphene/protocol/types.hpp,libraries/protocol/include/graphene/protocol/block.hpp,libraries/protocol/include/graphene/protocol/block_header.hpp,libraries/protocol/include/graphene/protocol/chain_operations.hpp,libraries/protocol/chain_operations.cpp","gmt_create":"2026-03-03T07:29:24+04:00","gmt_modified":"2026-03-03T07:57:42+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"d54afe72-4975-48c8-b825-ab792ce92a46","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Build Helper Tools","description":"build-helpers","prompt":"Develop detailed documentation for VIZ CPP Node build helper tools. Document the cat-parts utility for combining source code fragments, cat_parts.py for automated code assembly, and check_reflect.py for reflection validation. Explain the newplugin.py template system for creating custom plugins with proper file structure and boilerplate code. Cover pretty_schema.py for generating formatted schema representations and schema_test.cpp for validating database schemas. Include practical examples of using each tool in the development workflow, command-line options, input/output formats, and integration with the main build process. Address common usage patterns, troubleshooting tool-specific issues, and best practices for maintaining code organization through these utilities.","parent_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","order":1,"progress_status":"completed","dependent_files":"install-deps-linux.sh,build-linux.sh,programs/build_helpers/cat-parts.cpp,programs/build_helpers/cat_parts.py,programs/build_helpers/check_reflect.py,programs/build_helpers/newplugin.py,programs/build_helpers/pretty_schema.py","gmt_create":"2026-03-03T07:29:30+04:00","gmt_modified":"2026-04-21T16:26:14+04:00","raw_data":"WikiEncrypted:zhwwHcEGfkuzROuyPGwGZAaP8JUBGCZQRchVoluTSwBG0F8TNTcA7NnVPcgD17bZ8tkkmKBmN15pV9qTETgIyoqoLH7M7WPfGtqxxySlrJyCUM6SfuR45v/C5WGemH+0hRlRLA0flEYfomMObFQbk5Yk+NHzIvo4JgCZLW5F0XN7DLQWn8LEfXvdWhYrpycEb2+gRUNqVLrMR4Lj9NZBJQro9Xc43t1OtdTxlnZzJErkb/KowYnn4nnYNDGxG9hIQyrHFcPMamMN8EZgZ0hCu2+dpSJriVuNhJjimoclo6Cw3pyOQAVdprPNkw2xEpbHhZQ+rmE3VZlXZ+MLkJTN/XZYKwiYTp2uKbNEPmGsQQ2LomqWACjNw8wv4WqiN7uh6Y3SVosPebV0G/ZcCESHnBvGtowAOOZYPRnPfpDmnecYGNdDURlmBbiLalrynqnRqKVeASYvVRhaPsQynz2xKpKXOOioDWeEmlzNcUP2D0WeKQdlTbEeVPO5aSdRnCUv+tX5viqMRFV/aZaStqyEbDFofDhf1JqBalT0wv/VNgNo8kTnAZFGDOZ7xz67uGXDGXqJn3n/4th3Mdab/0WAx8kakRGAUxfaS2vsxGHC+7QCunw2c0sltmNXkWX3iBbDI+DygDoA0gCMz/aHmapgS90n237xk3kir9qU9TcRxzWK40xmo7Sw6FKr9WMGDkhPOPoAQ1UyBvkEfiBD4MDJr2rlS6heSMFoZIx8/ywk7nCxEx+Q0GV5xO5lyoVZ7IcaG1qcjeCuXta5O4pp6D0sORk2+3lC3RyHKqAFvJLXJK4Rn0Qj8NxjSLxuPnrMMP/z4i53otH5KRVpmj7PDloLwxm7Se1nx7kDpNs35zcbLlEuIZtMbmAu66DwTp97t86Sb5wAJ/lIQ0mzUqFRHIcTAzQpuMVW8o9h0q6bHxq7EYSG4jTchqULmB+GCKY2k6PKr/7T3DauDBVkxIdONfkS9O9XGHXv2A5vsZxP7uwVDL3u08b+BhwDTNCzmwIX8o+rk/rdpGCvVgOqtfkcl6WaPW/IFKnAEIY8MylFSyU9s4XJ3iBGigwuXdomwt1cuBE7EUfi79p3HEL+wLR+AF4vVVMqJYqppha/U+KsYo4B6U+knbKdteYsN6s3vOK46UeNKZrWoIhf/ef7++6us2IsTJKuSlWUvT+AR/qvbLI8mYQWqGfA+Nb8+207lwvZfwI3+518nB+L/C0pagznPrYzjcKWpHAlmPmTmsqqLvjD4BjCKxbG2sCKnimWkVT0LB+hRvV7lMfAk7Gy5kdQSK26mxsceYr0fxKYmag8dKFwHkHvcghZVIR3IHq+9Ir+X7pUunTFXP9j1L31CRnGHLXOnqTcTVwVKYOpqRDDh+e1bBBdP0cL4At2JEOY/gLxBdDUSv45+taH1UJLnCwRwugCz4BpDWxszi1q2n5a6iwGwjrXT/hhAsY30aXJtxMwTMW0boSb16P/oT6iBHls+6cpem4KKYzDAMclvkD0PwTQVZ4jz1Mmkf/GzDs+VNNW7Kwsh5/pZ/6U0avqrOxjIwkpN6gsFPWWmd3ts2BukG8AQhcQyIbMqDtnfDPqrJoDT55qBSSxNiwZeT3Qd1vdF1BhC6WlQ0ypbxK+GA8206/RTjYD8gy0BauM0Subh2zzN2+NEXWDVhzLdt1B3E2JLbjSdF9G4rwdQk/c+yLBVhWZCKC1RV8Mjd8BCkDs5Codlql20owYs9eT2pD3qaecCu7DPM57z6cARZWlp9xRxrJdEeR6HyDqfUnwAI9CyvBUijzQaiJYOtmmYqFvKhFzcD+y41yyaKxk8e3R9kX6T35ElNuhNiIyEFCtrJZTVFRwpwAe","layer_level":2},{"id":"afe12b98-5441-4e08-9bd0-d8c604b2dbaa","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Code Coverage Analysis","description":"code-coverage-analysis","prompt":"Develop detailed code coverage analysis documentation for VIZ CPP Node testing framework. Document the complete lcov integration workflow including installation prerequisites (brew install lcov), debug build configuration with ENABLE_COVERAGE_TESTING flag, and the multi-step coverage capture process. Explain each stage of the coverage workflow: initial capture with base.info, test execution with chain_test, secondary capture with test.info, tracefile combination with total.info, filtering of test directories with interesting.info, and HTML report generation with genhtml. Cover the cmake configuration options for enabling coverage testing in Debug builds. Document the lcov command-line options including --capture, --initial, --directory traversal, --output-file specification, --no-external filtering, --add-tracefile combination, and --remove-pattern filtering. Include practical examples of generating coverage reports, interpreting coverage metrics, and integrating coverage analysis into CI/CD pipelines. Address common coverage analysis scenarios and troubleshooting coverage collection issues.","parent_id":"cbaaeab2-9ed7-42e0-888e-58f1dff3747b","order":1,"progress_status":"completed","dependent_files":"documentation/testing.md","gmt_create":"2026-03-03T07:29:31+04:00","gmt_modified":"2026-03-03T07:58:43+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"514b44cf-1ee9-477f-afb6-86b4f8c17ee2","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Transaction Debugging Tools","description":"transaction-debugging-tools","prompt":"Develop detailed documentation for transaction debugging utilities in VIZ CPP Node. Document the sign_transaction tool for debugging transaction signing issues, including command-line usage, input/output formats, and common error scenarios. Explain the sign_digest utility for debugging cryptographic operations and signature verification processes. Cover the JavaScript operation serializer for converting between JSON and binary operation formats. Include practical examples of debugging transaction validation failures, signature verification problems, and serialization issues. Document command-line options, input parameter formats, and output interpretation. Address common debugging scenarios such as transaction construction errors, authority verification failures, and network transmission issues. Provide troubleshooting guides for typical transaction-related problems and their solutions.","parent_id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","order":1,"progress_status":"completed","dependent_files":"programs/util/sign_transaction.cpp,programs/util/sign_digest.cpp,programs/util/js_operation_serializer/main.cpp","gmt_create":"2026-03-03T07:29:38+04:00","gmt_modified":"2026-03-03T07:59:59+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"eb3e00ca-26ca-455a-8670-e309bca1ae7d","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Node Types and Configurations","description":"node-types-configurations","prompt":"Create detailed documentation for different VIZ node types and their specific configurations. Document full node setup with complete blockchain synchronization and API exposure. Cover witness node configuration including block production setup, key management, and witness-specific parameters. Explain seed node configuration for network bootstrap and peer discovery. Document specialized configurations for testnet nodes, debug nodes, and MongoDB-integrated nodes. Include configuration file templates, parameter explanations, and operational differences between node types. Address performance tuning specific to each node type, resource allocation recommendations, and monitoring requirements. Provide comparison matrices showing feature availability and resource requirements across different node configurations.","parent_id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","order":1,"progress_status":"completed","dependent_files":"share/vizd/config/config.ini,share/vizd/config/config_witness.ini,share/vizd/vizd.sh,share/vizd/config/config_testnet.ini,share/vizd/config/config_mongo.ini,share/vizd/config/config_debug.ini","gmt_create":"2026-03-03T07:29:47+04:00","gmt_modified":"2026-04-21T15:32:31+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"6ab3219a-8693-407a-b403-239fa721b5a2","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Transaction Processing","description":"transaction-processing","prompt":"Create comprehensive content for Transaction Processing covering transaction structure, validation, and execution. Document the transaction.hpp implementation including transaction body structure, operation arrays, and metadata fields. Explain transaction validation rules including expiration checking, operation validation, and signature verification. Detail the sign_state.hpp functionality for multi-signature validation and authority checking. Cover transaction serialization formats and network transmission protocols. Include examples of transaction construction, signing workflows, and validation scenarios. Document the relationship between transactions and blocks, and transaction lifecycle management.","parent_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","order":1,"progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/transaction.hpp,libraries/protocol/transaction.cpp,libraries/protocol/include/graphene/protocol/sign_state.hpp,libraries/protocol/sign_state.cpp","gmt_create":"2026-03-03T07:29:54+04:00","gmt_modified":"2026-03-03T08:14:41+04:00","raw_data":"WikiEncrypted:pze/wTPA8hT9dADtWGlHVecGIju168riPHUw4TY8/AOhja4aeOzUlmfgdY/KTiokGkE0pwevgTXyU4//H92NNz2DvJDyylHUIIAgFa19IOR1rIcwnR+M5gYnWP+MfMyP9rJdHksUzaXlv9bu0L+nSwyEwxvRjUsxXSJzFBEFHqMkwXP+kKSmf2P5ac7NUAQiXV93Cqe+SJpTYieODHUA2aXvlp8c9CzuexfREJPFweCojE4iuz2MpwhzLDyHYWZ0+Oo13SyBMRm8TSYEiJJ1qEryT0ka1GRDrBNabqCzOK6uY1kcgMVU1jjPuzIozI89v9TgBpUe3ZUX2D/okuey3ZXKbQsrqjCWtXu4h/QZb8rYGL0z4J0n4KskmV2PKYbFtn4srZQu7EbpGVbjsDnBXaaURzTiBAn/5bNsIYm+cIxhaOEE0GSJWPZKvt9h0knjB7xU0AMvSOozrAlPI8UzxVBsdecMiFyAtTBrLnr25+mj3ZwaWngPIkUmE4QfDwFvVBktD5TvLYHH5fYgQ6FQEOqADFR/zowPRsBSgtdJ9Eb/rsHcEzSds3O4vfJPa1xBvv0oREt4BtnPPo7h1GW3BkQTBPCsCLRrdxXj7pn96rupr/KX+UZx+3o2WnK2p8s5xzHrxoZ9FQTtLMrP1QfdpEFyryeihlhvZrCXbyJ0kHE91R4y1JciNNxtI/Bjrh6mVBYmrKujPXiV5CFrRwoI2mH19Wti9DQS6W7gklFuAeemFd4jTCHLmR/CDXLjhJDffCUzHS8513myK6oVS5EH7w6YPaLheZxNpurE5ol03A8c/WxlMAXjnBxaf2ZeHj8uxa1EEM6YHmC9P5jSRuEuUUzsS2GRlFgZVAOID0om/E0ENC/0hYqwiXqX6y9n0EmcAgNlDJkUnWeNYJ0oupFu7tnzV85Ilx3SxDP4ea05c5oMYIfzSWji/XEPnZgnS/O9MC1xoLO1yNnHi+fYQCTlLY1nkz1d4gX6E4KMS0BEe2hiCUeZYF3Ve1o8UByfeYpm2dpWLCmdhlT93SxA9Tc+6H2PULFfOIr+EUDlgTwFIjJeGJARDD7Wv2Eq+POFmLHPM1FVpRzVCzAKsxnI7OCf4iC/EthL2PFmXmYvtkCvAvxwMgEwm493vGA2ADLGhz9VzIRDanfMsMnv783wuN+hvDAanYwmAbdNF/scEaa6o7YYzUlSQaAvJ69tNU51UvQmyiiKCXW4ScC0hZ79uAf0ch71hOj4u/b+KFez1SbDRZpKZRxeU0pm+ZGWNs896vkM3THcbIvEb2jp1FDd9tRhuoP5Pu6q9Dpx/wNYMV3VRE0XMIMwliEXXF/ZEjvZQSw6MJVwTNQ/T7UFKiwYPiWR7zu22AG747F3nrt1QQ12XPYHxupLZYDmpv313bFI77gWmFvQm4wKDhyr+8uPpOKb56paTtid6wBDN9/JGgmMGR7/oSz5cLuCQMv2AuLrUnmh9WKD4cydsTT0W5KNDaGRrHfnZiT88kkOALg/Qn0w8oNN2idlbOac//Mwluk7C0esxezBf92dkmhrQsXZ4LjPCkTjDkSGBbvMeU0JhEyVDtolDVSe8XLlbQRNkp31hO/lC1QhlvCzGrrmSgI32+fgI10SmRUU+tqWWL+USh7BGB/ohXpQ+pQkPB8krp6c+tkn","layer_level":3},{"id":"a8c1e706-27c9-4798-b664-a842a70058b4","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Object Model and Persistence","description":"object-model","prompt":"Create comprehensive content for the Object Model and Persistence system that defines the complete blockchain data structure. Document all object types including account_object, transaction_object, content_object, witness_object, committee_object, and their relationships. Explain the object schema definitions, field types, and validation rules in chain_object_types.hpp. Detail the object lifecycle management including creation, modification, deletion, and indexing strategies. Cover the multi-index container patterns used for efficient object lookup and querying. Document the object serialization, deserialization, and persistence mechanisms. Include examples of object creation, querying, and manipulation operations. Explain the relationship between different object types and how they interact within the blockchain state. Address object versioning, schema evolution, and backward compatibility considerations.","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":1,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/chain_objects.hpp,libraries/chain/include/graphene/chain/chain_object_types.hpp,libraries/chain/chain_objects.cpp","gmt_create":"2026-03-03T07:29:58+04:00","gmt_modified":"2026-03-03T08:15:23+04:00","raw_data":"WikiEncrypted:WrtF4UhzC84au2vkp01Wd8VhZuevsmYW0MiRsMATJ1XvzQRUZVUONQBd74I+5hpz5lJT7q5FmmBA+o8DqqOXNjGpt0nJ0BAMDy5P46t2LJR/9eNbkssWxJy2QJkEwyAnWrDBJjJ0RtuHhzMS9XMXa1dC84o0NwHImEkViQDS7Rpsr2tEFtNFHgqhdd5Zjk+OTwvCho2N8LT8e9ja8cNKp9BMFrmvVAq8aF9GWvThumhCK2w2w5CyEP2RMR4PW+tBxGQJFYDPJFgz9pTEzIVaFbKSiCUnWq0ESj25uR6wVSNMSVgq7zRG7y8IIsgrqnhJu+KgNUrZxmwpxoAcsJ0hKFwNo2lam+HL6ml2/2LVFk8Mzco7PC0p/zgxbfQrRFhP110QNXkeT0bYlTVVlMypAQ1Kxj3NBZ1KLmyLLs12q1EsOjSWSgxN9YXmkrXz8yLbFNZYT7qGDIBSXHVviTp2McCAVwIKGOXKskF71GBPcjqo9pXktSpgKxx7qaaBMhX83pvC95fYpq2cJc75oPgeq9KZXR//fZQakWRETvbbLxccAwa57y57RdnEaBfd9daY++/BbkT3oRJ2hqnpXXUBr2uUme/yb0WIntz6DyjzY8xSE7izPZxRsPcc8RJUWILAy7ZprMZASzMlwRn6/Ky/j23YT5a1e4zoyyoHebXifIGG6ZAse1LtKwo9TNNOQpHCamPfYntDKJg50qHWmO6/bi3qavsAFO/yitivdZkArtHqC398p+u7EFZ37JVRbVzlp3qeNVvPsjEgx8fT+bkd3/qwS7xa/muLbLdVBoTsgfnvYr2G3Is+K4mnBYPu/aNEpG4sm7qoBWE7KLYezbuMRJ9+1Fv1NpvrivJxTSjDVwbC5IA+oCD6Pro5lFg5VkenktCY0G79VFuE35+CL+R7esWyfgnM7V8YjaQTsnBr4DmI49qImBb8qqVwyWze9Zyo0WzDrFg59V/8kW+9HBbrh+JqtG2KpXW0GziW4YZTFW4dxYKV2I/LPpCoOMIgeP2YWhpZIV2nrw9FY4247hiAvnJCk2Q1xqRedjgoTM7IuMBq6LdX6BJU6JkzxAw8gnYuryYKtVkenMBIKVCzTQhreo+0OAPufetVLpssW3EcZU1Nn3pPyvncV+MvelP9nELnHgIKy1t6WMpRIx+q/1FhnSFI7ADmVelU+ntYSPmrDe6HoziMx5djs3WbbfCK+IaYGU8lay02M8Q5NC/UpELQYtdKRC/j738pt5904KOmXsVvbw8wRYjN0hqZut9fMN5dgepehlMduVsqXgzmRRVvgbk+K+O3/mGV3qj1swdiR9lt4skvBPrmh+jR2ACCL+MNoszJHNrglzKIBSUS029Nx5J+0ERK2muv4h27pkx2WHp1C44wXmad8a/qI84yR6y1KOFmGn0SIQ+wsUuTxHA37pOzS1mAJiYqLVgGMS+GNG/ENsAWGLkUVSYZohLq5i645j24mmoIj+BLI4PdQaPAXvBvMR4LdiMovmjf73UFLlA8t2TZ+TLEdIqQpAYHoqDj9ZMNLKTFLNkg/CbbVyL4uZpnscLgQGk1kyWR+sMsjy3nG/rQSGm5+rxc+wfeb+xLIM/ekGSKxF6TTOyDLC+fgVMNyQYE+2MRVg/lTKABDNjCFctgYnFwu39sxnx7gLLilxXTx98QGOM/Jp4L4U6eZYSLwI1pK6arSKqy9ls8TCZmRPFZJb3/RO+YK0K1S6R/aNh5Bn40Y5/rp5kYCDptiseq1xWjbUyVaGjKF5jsAkKQuiMnsaSAdYUEJ92RtZw9ZGhHskCV+3pzqkjd2Bsr8NK3ocd6GiMEHrapMKB+oJpQLFVtXgeck1Xl7v9nSipIUd9sDgGZuJ2u8IOf8JYlKi/NzTcJMCgtBM12aT5PPaM=","layer_level":3},{"id":"b47bb56b-832d-4e6d-8045-bdbee53d703a","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Peer Connection Management","description":"peer-connection","prompt":"Create comprehensive content for Peer Connection Management that handles individual peer communication and connection lifecycle. Document the peer_connection.hpp implementation for managing bidirectional peer communication channels, connection state tracking, and message routing. Explain peer connection establishment protocols, authentication mechanisms, and handshake procedures. Cover connection lifecycle management including connection initiation, maintenance, graceful disconnection, and error recovery. Detail peer state tracking, connection quality metrics, and peer reputation systems. Document message queuing, priority handling, and connection multiplexing. Include examples of peer connection setup, message exchange patterns, and connection monitoring. Address connection pooling strategies, timeout handling, and connection reuse optimization. Provide guidance on peer selection algorithms, connection balancing, and fault tolerance mechanisms.","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","order":1,"progress_status":"completed","dependent_files":"libraries/network/include/graphene/network/peer_connection.hpp,libraries/network/node.cpp,libraries/network/peer_connection.cpp,plugins/p2p/p2p_plugin.cpp,libraries/network/node.hpp","gmt_create":"2026-03-03T07:30:03+04:00","gmt_modified":"2026-04-30T13:09:18.8212712+04:00","raw_data":"WikiEncrypted:VR5KHiCGBNdKELy8Scjin5u2xY+Dj5+IyYWoQiU3xOSz7PDUoqR7wxPwIUx3wbq0KT3hCoqZJUqiKiMi3flUl1+CUwwthoJnvOb5U7feLpBHGIw6yavTfsvlZuEq8CPGgQzM3Xf662cw4b3flUYzJTiIoIjl0H3Y3gs2z6KJzJ6gHhDIHNAy16VnuE2k3XoKpoZpnopSt9Pef97+RW3DlL+lnpHu2YAxaUPgpUpwOcfmOvHDj/FtC/6AfRpR8JdNEzMyLX5mVrsDxE9xlzBHjJp18lC8L+VVOAANM7tfdEwhuQnj1QvkD5xEw2shgPbllS1DDgh15pIbYMiiKItSDQ3cQOzE2hSDLEPCXPZzOQLOm/vW5wIW4swJyLKpRsRbz4vichH0HMTnNZ3yz86ex9/1obZps8G1dNZzxHHHVW37DPGJIWjSmtmO9l8dGKrRz+0joIm5WQ3ITrgtKdLStz/mnKQaaU23kH7OM1o1W3ZOftVLejytc8sDy4zj226tENgoGv+KThy2apmYugKxVPbHaw7vXM+Y/+iB+7kwu+3YwX6FD69IMK84aOBotgYF7zvZ9f20RKtsC4MV4+ooocMaZkMKGCOvR034TGOHVW9ORbuwc3T97XUF6wZnbiaJBNgjkqEJ5ewBXSFreRJTTSmuWpgmhecUbuOuNoBX4nXnq7wbYxZ++Ci2gE0fiT8fuHbcQhEdaRCnDqfcsDYgvQuAdMC5mWFYvSL52BId1R1VYNSLHrREPaEwfvg42DRdKDfCVdh9hicPnUCo0DINFIlYy5moydHXlwzgScgQROJQ13oRPuV2oLFzye9WELN+/mcjUBB00n6TcrglmwwUyILQz3H4lfQ27Rnzm7jlQqr0mIT5bGCso1l4IlDaK51gu0epdRu5BRS/YKSGfPYn2vUNkwzLu4MOqB6uKSJqlyqn2P32EkPCI+8zcyVYr+g5ztImlJpOR/yTsHaWPhZFRTOTSYeF5KmpraGzm59MNwK7acLPqGwuQ5ueZprYE8pMefEuM8y59jar3RfLNdO2FXcP8K14CBR5wYAFZgkQzMmtFIaON+0hwS/McWzrOK6p/3G1E53AZwyO6eifGvjf6fwGk9NSPgaysoQhCWViSaYFvmlWV9UV2d5qFx161BxBoJa09nY1MdRV6wQcBSTq2H6ACzYwL3gf51/b9KorTmbbL0UO/HL9IX4Db/nNryXi+3jXHJmvFFpM0xvx3d9x5CuTg4S3KdwrkLJsnk8MUPz/QTlKXLKSiFV52Yk1SCmjOOztsf1JR3ga/+ZEnu3DiH34Ti+KRjo1CoZEcxyrCpVyYb4gX+cmWI8J0pK2vd0zEB+gHWZsvQJRNLI7O7pBTOFk/1CDR1YHlG8LM0KzgI3OMb/SOP6qI6otoEBXdufCboW0Be8Jtp6E4nhgBYfkw9oOhQxKGxazwH+UgP67YqSljeB29Vf/ST6qi4LRxtrEkY3yGBo9Uumh/+nAXzZZ9GD8kMflc5GxwejVvTXifndc58gDyG+xFjR58YAf3rTmr7rjIdF3jAYigHbKTIUc4coCT5lcFA9R5TxBA2pp+M7gNw/vka3yTE49nqMnf02BgJ1e6nRmQRl2fSwTy3WdsdkAwVxg+ItOC+WXky/1o8uUnyqecdgdDcX1QBmz7OCTaal502VGyz0t0nYF7WWKhn/7GujBuNbjy/aRor/m1XBn4r0fn3h+eZO3WVKYuWKoVBU1Zc1B/noXieGpEdC/N/gQeOEmEXBslWIn1GT4rZxcP0n4RjEk08Vc2LFiT01O4L/ekpoxZ5RIq2Sa/jbXtyfh5ESscZyZrDrxvcSeJgYGhtn8u57NWPTVG0O08ue6HNetZLUZjdecVGpIU3omNWCWKkKU8bX5VN3ysSnr/pk0DLGxXWDx7P9LuQOIhMJu","layer_level":3},{"id":"1ec7edf8-46f7-4e71-ba54-bc1cc3533453","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Platform Configurations","description":"platform-configurations","prompt":"Create comprehensive platform-specific CMake configuration documentation for VIZ CPP Node. Document Windows configuration including MSVC and MinGW compiler settings, static linking requirements, Visual Studio project flags (/SAFESEH:NO), and TCL library integration. Detail macOS configuration with libc++ standard library, C++14 standard requirements, and Apple-specific compiler flags. Explain Linux configuration including GCC optimization flags (-O3/-O2), static linking options, pthread and rt library requirements, and OpenSSL detection. Include compiler version requirements (GCC 4.8+, Clang 3.3+) and platform-specific dependency resolution. Provide troubleshooting guidance for common platform-specific build issues, missing libraries, and compiler compatibility problems.","parent_id":"317287b2-3937-4876-97d0-a8c96007d95c","order":1,"progress_status":"completed","dependent_files":"CMakeLists.txt","gmt_create":"2026-03-03T07:30:07+04:00","gmt_modified":"2026-04-17T10:42:56+04:00","raw_data":"WikiEncrypted:Lagc5vDVDWJKf0nDI9TGSA5WFJDHl+XgRFW9Z8nrevG3TCAhYIcpEYU1rn2otzoK0HrEK0jMDM9tEMjTdqSFUT2s/zXxLUj1fG7NZ4iHEEDHSkF3MnlEpA0VfBICYmIEysUPG+skLqepPVWG1KHiaLKuhh5y8KMFGz8vf9czZdpBEri/pDAO0R5RG/XkYCd7kytb28lf7+fpAZojUubG1v/nxZl8JrpQybJss1uZ23nrdEWd86bqk3Cw9sbqiahAhqPJE6VBMtgpmRW7Twshw9gjmP2j80RvHuwzEq8HYraiFBGULt2nREETqCLUSJVay9QdNPFHSmcgv1nlO749K6IOf8jvyJEL5BAqr1Y/QKrIDm7hHZauFcS1WEVy7L6mrCOWY7KUpONwVu+vOaFxTTsdNku0ALldwRVrXmGgQ/wjDv0Bn/PGUcOxgW7n2pG//giNon6YErHA7GEiUYieQFI90ZJ+5oD95pxRWJcMumNRJE+uxkCuFyklJfLs2SAfZuqM2ULw0OH1mNLsaUNTcbBDlArHPV78IzpvWoUgk4tcfConWKCNRv838iec6Z8u2rUUNZR0CDOL7K6RFjybi8Ma6P+3RIGnRE7ZozR893j6kSU/yrhYWxR0m1IewVwhBVq6o95yWyHoMTZu3E3nJeehkNDWLnoi+MOrsYflA/1XiMBKZS60IVPM47jZJkvb9DM+ZoVRcD9lgI7md5J8qRvODiXZARh/hLuyNZCKBLfQkl5GiF7F9F9fOuYavuL/Ejp+R77uxMFnjDgyeFETjfVChxb397xHwJApBA0Rw1Ibcn9X3cWsbgXJgKQixvjfXq3MwLMPYtRFI+o/I8iIS0k8JB8dHihnT9FoOMd4P3CK0HT4KLuS10bC8OG5b78Gv+zA/MwZVOoPkiNyyMKpCJki/1BU+0AW5ZhlyH6W34eNJy+hDKPYFHqxIJNyaNXlKWfY8IA6hQcS4TibT3iohEZixNXcfay5LNd6PBf30w6/zIkVmo1aWX20WM/kmC8aYo8cEpVEfHgwe6sEB8P0J8oQiM/eSBlEyidmCkzEae9bpUkL5zWjdfpbwvOZ+aHxxF+bbjH8bbYCU+Kuef+HNviE0s25BLZqPyeXbJmQvoTAzMRslswCGNNw/yAp6FHylTiRUi59aLjibzqFd3lfEy7fchb+nfgdFtMNW1e8mfi1F4TmMYR5xG72yDllegJCfzjpSCtlXellUaG8LIOrjJ/g5J5s9C+u9Z7AZ14gyUMWwAfpnldXvgup46MMQzWFnkdgtoAXdgnyWIzZPze6reTtZt6vzuK/H0+2JUGiQubKLCmJJtHAOAtMPeERunxT5S0bPLAaGC+dVPQ3Bus9B7CXAUApDxXCj6bbBPOmIvu1mcQRQFSywDqN14NSSnxCb4QM997FzIH+KO0Q6DfXMU6Gt+UcZTyL4slDGwH0v7zW/O2uJW/StZhZZNyCtE3eaOvA4KSKrn5WtUgUDnFScw==","layer_level":3},{"id":"7b9a46a1-f3d0-4034-a4c5-aec28be05f18","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Testnet Dockerfile","description":"testnet-dockerfile","prompt":"Create comprehensive documentation for the testnet Dockerfile variant designed for VIZ test network deployment. Explain the differences from the production configuration, focusing on testnet-specific CMake options and configuration files. Document the testnet bootstrap process, seed node configuration, and testnet-specific volume mounts. Cover the automated testnet snapshot loading, genesis block configuration, and testnet RPC endpoint setup. Include practical examples of running testnet containers, connecting to testnet networks, and testing blockchain functionality. Address testnet-specific security considerations, resource allocation, and monitoring approaches. Provide troubleshooting guidance for common testnet connectivity and synchronization issues.","parent_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","order":1,"progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-testnet","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:17:07+04:00","raw_data":"WikiEncrypted:1I+g3iB8Klr7mBC/4DeKMdGxNIcsjOObmJBHKNrFsun7NjeRSkAIkIjgPvn0Ch7mDdGDRfXoAe1bUR41yzysNp6O11x/lcS8a3Ql+s83U89N3Kn9QIK305NUVjepHpGRwCLfuUs6r49/Rmv3IvLnxRoEHmOVl0wtpa/lG3+y1Ne14xPHgmgdT5ReiUN/nXcbHA14+lOVT3SEcda9cKCVHqeI43P0FUZpZcLbL0Hb/8Q3ae4Zsguwd12Hpw95G68CsyAwN1Rm2xgHH7yDcTt5DjjL3XZq/H+YzSdgfFP+TLMsJAx4pY6R4M+6buO8lD5l3FFIQ3FqW/m8g7uM0jnK/8tbFSNYlPMJC1obXfxp0pVqUiYPm85iShtC8nhm/34/TVMpQqFGygDjckU7XuEi07HaP3hTRatT76OMoEXTDLpY232KsbsQjVW68uRk1yj+GQiMyb7g2BDZpxuY+P8Iu3o6DBn3sBUhF43BBVAJwKVoj56yKvSppF2SZfpScCkboybaiHmGwNGUoslVe/CgR9j0pv+uIbjmL2k+XefbYPqCW/DAFQD9YaPMLUX0rkDAGbiawu/EaTAXnYzCzevAwaBvaMimlEHB1EfzGhFbYsFJmwBz9wbcxtE9pPvkbFrzA9Rpz/eIVq7Ufg4lohlimnyu8OW9bP3a5hJML5Ul5tqAr1HfMAC9M5HnAzXqCnYYahVRIMMLjxVechrrwwfEDMHOFNxJmyWQ80unmDR5Dq53k9DL5jP6H6CB5r0z7U4mIMLp3E9yNZGY/1b2/XvcZJ/BWlpLyvfp1XVv+gQcNq7hAsIpyAq4XzBR3Yqlmgdfk2I3qg9AblCrpWwv9mZpvEFcEj8uTq7viBsiX4JurXfPsV79aRzkw0TExgPJV3ZXzglvZ1a49zfz1EcSqU42n68/5+COjjdk6vDvU95/6EoxQBb9zl7eOqluTjQ1R3vDbRKM6OJhrdgMS/nJD3qPjJPcnfGJxGmu5HjqHZm1rk/pqOg6NTm4jag3v1S9HO59r1uPwJXYh3p7tbUOlMYw/chuuNkmcsy6Uah+OKS/uLF9mgqmEey4XnX9U3GJhKy6dHYCUmi8IE4zgP2tWRR1dOX+pgluqLxW7Ub9RyuZ0KgsBEOBmJh5oNrmF602sSudrZcDN22O6PWNwKzukWJrg20wj+ZlZ5j1Hi4AoXBe06kKqLIPY2C8J7Sbra0PDHw14W9H90rpWsI/zOkUKdbcmrAM8x3wt1dBbFIZo7d7SDSMHqPo+MILMlP/cLh4e5zuOQolQhEsJkYT7fnqc3jAoOVSPoMpONhu1RcYpjX5zrVMMd/oJU/H4EVO421T6VMr5aYLgp7gVk6SvcmFXd5Q9NAIi5xge4XsGY8op5iz0Tr4lRrAB+GdneB9fiIOYJEk3L28A/kaWibKkbNe6YOBKCW86vLNQw9kNl0+1NwgRmpuEzxCvt5l7u67gfqHymyp","layer_level":3},{"id":"180359d7-c289-42ff-9805-28e742c9f10d","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Reflection Validation Tools","description":"reflection-validation","prompt":"Develop detailed documentation for the VIZ CPP Node reflection validation tool (check_reflect.py). Explain how this tool validates reflection metadata for blockchain objects and operations, ensuring proper serialization and deserialization capabilities. Document the reflection checking algorithms, validation rules, and error reporting mechanisms. Include practical examples of running reflection checks during development, interpreting validation results, and fixing reflection-related issues. Cover integration with the build system, automated validation workflows, and continuous integration scenarios. Address common reflection errors, debugging techniques, and best practices for maintaining reflection consistency across the codebase.","parent_id":"d54afe72-4975-48c8-b825-ab792ce92a46","order":1,"progress_status":"completed","dependent_files":"programs/build_helpers/check_reflect.py","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:17:31+04:00","raw_data":"WikiEncrypted:bzyetvPZRDtDTnozObvREtrhIrVNlzR9GjOxDARd8qaPKEK0AkNVEuyEWFfIrzjBn8DY6shjGjbqn7TVEpFIluO//1stc1a9TeIVJ9x9W8GnhxuSgajiCEqcxRq/kcWqzRcNq+G5PBS2Vke+Q50oFUmdFPFUbshtige+XHhAM+vr1VbcBaNCvAUnkMSy0cxMpdfxTVp6Lt2BW7voUFp5V5v4wm+eGDYDNJaR/hahDs2WNVGZLd5R0rgYfezTRSEExKq7Q6et6AXVy+pmVgjjZ8ZlGuiO0PQUrn8+34AQSx6pG1b2AZWeaLkhKX7nsekKrRfQhE8xHLo44PBWGtCeP3R+0FPsvW2qbTMUKtpZzwUnfEGZKLte10pyWg39bdvFi7yVl68CABfWhuGT1/bcj615AJhU1WyQObutow+jFnlBjYThqH3JssNmHv1sqy/vwX0aD+YYIftEC94eF7GLoiFluSmUz/f0jk77xwnNPi1B5b3Xp8OarYxWlENi1n//v1POhwuOiylv5EJC8A+vt+k3lyM/E/fLYsZsbN3dxZK5D3ysSEpx5bybq+EOSQCTsMFIqUpGc0keJMdoUq8tLhA8T0ihnlvY3IHyE0Ekojgbf42PCqR5UWjQ2UMuT4qse91Ss00aLjiozuB5ncWKd411zVc3w+V/RuIEOgA7CrShgVwyKQqJY79EvjliATv5Kh4krN0OFZSA5l2BSXKmie4wpSrsKPK0pmDxFlfeuKBCurgkt6vPrUYKtmLy4etO/X9W2BMiMkZQXJSTaIt0rCK7dCPCmeE975IT32alaUaDIlZnBEjvpBqkVFN/Pb046CjE33AdgDHbXQg+T8aNRvOpYZMal3BCnw7IzbMMlG3rawYhXmnXggCxRFexufLtLWKHkxRARivsT7EHcredBAeoSt26ETGMyGZ/Pop47RzOgk0kKCaT3BCAm/I7wZlU+XgnStRjYuMf0wJKf8P8SChYRpK/cUWIlepMtHy6/8E5fkFgrdv5SpyhUoF/wqEHskj5jLC0ZmIcw2l5LrYcd70U2s49AdI4uIuiH4ItRGiqN98cImdA2ryU2izjj9Xde5f1vqBBQpLowqdBNH35QXJsxqIb1RE4+bZ2ySAj7LtV4SPUMffW08rQSlhFImRB9BnWYdCK0Utm+7t/BahAZTEI7L+yFhkq+jj+fdCJzkhzturXGB+OWE6FomYdiD8MYo6LPDyGpfuE8zHe5JoKPFzvp3pWPwxYn5UpnvRVwoOVXviLY2CQOMVLCpxkjXC0BQlrZ7377iK5HtByix3XosgFTKsVppHbl0RdE5iWZVm5lrHwDWctVdM1iB/+tsRrwUpXMUGWYeLvUSVx9b7cJdT87st9oQ6rAlcRyjeTqam5QFb/B8Vukl73nWFLQf4UJTFQyjEGTfvF306mXzZLoRkaeMZN1irqzHCHuS7d9c0=","layer_level":3},{"id":"6b359be4-c5e6-4db1-ad43-abf632c4e050","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Snapshot Plugin System","description":"snapshot-plugin","parent_id":"ad096386-ea33-44d1-b9f2-261f11fb24d5","order":1,"progress_status":"completed","dependent_files":"plugins/snapshot/plugin.cpp,plugins/chain/plugin.cpp,documentation/snapshot-plugin.md,plugins/p2p/p2p_plugin.cpp,libraries/chain/database.cpp,share/vizd/config/config.ini,share/vizd/config/config_witness.ini,libraries/chain/fork_database.cpp,plugins/snapshot/include/graphene/plugins/snapshot/plugin.hpp,plugins/snapshot/CMakeLists.txt,plugins/snapshot/plugin.hpp,libraries/chain/dlt_block_log.cpp,libraries/chain/include/graphene/chain/dlt_block_log.hpp","gmt_create":"2026-04-13T15:59:14+04:00","gmt_modified":"2026-04-30T13:09:00.7660159+04:00","raw_data":"WikiEncrypted:aMBX4tyQy9CspId6SOjUsPjDbWaE0XwjiYFfJC+6JmpoDChB3ZowO5dYf5bnEbW/owWEY1csO33LOVGSLpEpLAsElEIuL6651OxIlbI6Jx4VJMJygyPsMEb3u2618Hv1nZRF8bM+TfiU1NGhj29Hy5By84gyGPEtmnom6gs62R7BlGX/O3S/Amvl/cCWu49KNtB/LRTrl3hRCySiJMTOgbB6kvhyWuhovDff8CXD12Li/yJPDsjaADY4REhlykVtmyLSUnHzKSo17aeqeAVjAjbYuyReEFLWIjy77IO02dKYT4gasIrxJYXx+MZ5UXisi47XRTsja5REt+XzLuMLTwOomLSe4m6RP24YJSWgzalMhDUC1/aeiACHRsAKaO9bSOLlwcAMBVQh6CsC8RUSC/r3yvMLfGZfNglrtQCsmR+EESeI/eacqO4UGUsfdW2x2+BuT4AgLGOLZtsNbx9oIhJv2bjL+0mYbdUqhSPYU7grkHE8Am3tlTggc5QGhANkSYk4y+E2X7ii5BLnTPa5uAuFedqPreKFE/X99oDM/Tgthjgb9ik6NUy6rlfjuJY5sqJp/GZydiK6kiCiH31g/L6cCwlXpbnGfoMOBVuQhSwBErR29TYQIccdjyohnWflxPYlTHo3Zr97zt8x9WcbL7lf+54/lqEt2qWimY3IVTMDqqrJnaDEbKurS87gvhwbKjINIVVG81/oFZlQqcY1SxlQ5DfY2i+LN4Lr3xLdiXdXVAGUcJJng5SJz05tWIPZ/fvvlqPwS9Pwul340LmEp8BiRBRdIjU5A2E3q03m6e5fYuihH/OFGUPbqC27rVgE","layer_level":1},{"id":"6f970632-4b1c-4a78-a129-89269ed82d82","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"DLT Rolling Block Log","description":"dlt-block-log","parent_id":"eb3415ba-4213-4e37-931c-49f45d7ebe37","order":1,"progress_status":"completed","dependent_files":"libraries/chain/dlt_block_log.cpp,libraries/chain/dlt_block_log.hpp,libraries/chain/include/graphene/chain/dlt_block_log.hpp,libraries/chain/database.cpp,libraries/chain/include/graphene/chain/database.hpp,plugins/p2p/p2p_plugin.cpp,libraries/network/node.cpp,libraries/chain/fork_database.cpp","gmt_create":"2026-04-13T16:01:33+04:00","gmt_modified":"2026-04-30T11:11:44.2224692+04:00","raw_data":"WikiEncrypted:s2jjuqSQeKwD1hNHHJ9DR2MPb35AgwzTacHpcPL0OtJB0zaRNLYJ+orR6pmHUkGhks1yVrOPHhwOHdr0evYd0xEi282qASpCMeLKGxgeabO4wWJCefkdwW+00NAyLKPpF5TRyYZ+UwGTHAheIXwbFWqT9C+s+LA3IYd0iPIRaYCeY+tvrYiaAMfMpOXQ6mueHbBChXQUtf9afyep5nwma8mCls9B3VEMXM69LZTRrQ2Uz7Xb6bG9yUgk7Vp4e1w72vxSN+A+N2UdaEXPf1w0sg+V1f+hOJTnNjjhoZMwd2BthVt37JoE6cHYEPh7yhI80vRAy1+br9nfuqCiwsW0vyiwpiVl2LJnfUg+8zs2OpgRsl56vcP7iG1U8SLUORFlxsm/MhBRLnLYQkd1ROnZmcfk28geae5dxHFWL9rwGL4rNBxQP/MClDScksxK0CHNAKGDrzaT9LKv9Ikn818QkXDkhJDogFubViQQh+KldJvpMG5JM2rC0wtXKLx9113ln64pkHDL3q+RPVC2pW+cEFna8mtVtICAFFr3pyZqdr42u2f83GGklmkIBIK2vcRdH6WOC82MYiRl7wioDnJOmQ==","layer_level":4},{"id":"d93a647d-d325-4dd2-96a5-703494dd5d12","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Emergency Consensus System","description":"emergency-consensus-system","parent_id":"7e383bdb-11dd-48d6-bd47-4d350e2df438","order":1,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/protocol/include/graphene/protocol/config.hpp,plugins/witness/witness.cpp,libraries/chain/fork_database.cpp,plugins/chain/plugin.cpp,share/vizd/config/config_debug.ini,share/vizd/config/config_mongo.ini,share/vizd/config/config_stock_exchange.ini,share/vizd/config/config_testnet.ini,share/vizd/config/config_witness.ini,libraries/chain/include/graphene/chain/database.hpp,libraries/protocol/include/graphene/protocol/config_testnet.hpp,libraries/network/node.cpp","gmt_create":"2026-04-20T06:57:07+04:00","gmt_modified":"2026-04-30T12:35:27.5354397+04:00","raw_data":"WikiEncrypted:yCC4O4QQiwfuc1LsaLvGZSv7iyGIp30QuTXuQp4YbjBPkP2yi2DSamCQ0erkARNQdFUVyIGCSLZc9P70aEvXU2XDlPi9dn8dxZ/3E7hfD7l8VSySXrg3ONRMw5gixEiS2Is5tNiGzsUuDhqPSmzvhN5QQPsvkDBdKT78rnUi7cRfVOHAqbx5rGtRz+Mx1t+4rzvcqmk5ZcBktnKa/RII3dRG86YHy2qgDjLm1p8D6C2P3NuzpmpRUMJ5H8vuTY9822u/fcASmS6VGPcMcclNEp6PLsBsUMJGY1nTCF9CbtK1WAa0JGnIkEWt1DWsEYTRVmwxexNfR8KVp3Lvxveagio8D6uyPikogm3VJy2SOG8TB0eQkQPMJKiAIYNrfPMq7NbipuOlDDgYCspRIWjmzesfjR42Br7Pr5KnkNlJx0TQRoFGDR8Lz187YJ2kGzaJ3stBnxfooluXtnqX/svl8qYnWPqXUp69rN3ec4uIpt3nrZdnr6osSr6xrzlMII2LuB0BhjpWSymNEnxAReJ/rrS/JWolGuor1Jb+vHER3rwo0ACrHdId5i2a7XZ/4dAI1kMUardPM/7wC0qUz4jdtQzxlk9xNmQvNkNTTyrpUPZVpSzfPFJX9PIqUSNcJoTcSgkF1Q62OnE4ckqJ2mzbbTT5gHa8NVimBS8y03MhL7HekBJanMWwV2t464ROQjc2diWqA5t0RErX7DirXWTPjdj8IIzvgdOQzKaiHe7BLj+Gw4E+HupBBOG5ylZzzJSGslmzNLEUiIRvmWfRcKzyx2N+GWcooVvgsRmT3Ffz0PI5HB2kr3i3Jv+qK7nTdM/Cup17wzrdYDIPXKK8G3/+f9VWHM5lVE87UM/oQyTB9NfANthOx5aHNTYIOc6a6bvfKZdR/+01FMh7xTEzzmQETg==","layer_level":1},{"id":"8aeac580-587b-43f3-9292-e62e4d3781f7","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Architecture Overview","description":"architecture","prompt":"Create architectural documentation for the VIZ CPP Node system. Describe the high-level design showing the relationship between the main vizd process, core libraries (chain, protocol, network, wallet), plugin system, and external dependencies. Document the modular plugin-based architecture that allows for flexible feature addition and removal. Explain component interactions including data flow from JSON-RPC requests through plugins to database operations, and the observer pattern used for event-driven architecture. Include system boundaries showing how the node communicates with peers, handles API requests, and manages persistent state. Document technical decisions like the choice of C++ for performance, Boost.Signals2 for event handling, and the separation of concerns between different library layers. Address cross-cutting concerns like security, monitoring, and performance optimization. Provide system context diagrams and component breakdowns showing how all parts work together to form a complete blockchain node.","order":2,"progress_status":"completed","dependent_files":"programs/vizd/main.cpp,plugins/chain/include/graphene/plugins/chain/plugin.hpp,libraries/chain/include/graphene/chain/database.hpp,libraries/protocol/include/graphene/protocol/operations.hpp","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:32:30+04:00","raw_data":"WikiEncrypted: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"},{"id":"139b0217-0190-433f-b41d-60fa08c9ee5f","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Core Libraries","description":"core-libraries","prompt":"Create comprehensive content for the core libraries section. Explain the four fundamental library layers: chain library for blockchain state management and validation, protocol library for operation definitions and transaction processing, network library for peer-to-peer communication, and wallet library for transaction signing and key management. Document the relationships between these libraries and how they work together to provide complete blockchain functionality. Include architectural patterns used in each library, such as the observer pattern for event handling and factory patterns for object creation. Explain the separation of concerns between libraries and how they maintain loose coupling while enabling tight integration. Address the design decisions behind choosing C++ for performance and the specific technologies used in each library layer.","parent_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","order":2,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/database.hpp,libraries/protocol/include/graphene/protocol/operations.hpp,libraries/network/include/graphene/network/node.hpp,libraries/wallet/include/graphene/wallet/wallet.hpp","gmt_create":"2026-03-03T07:28:18+04:00","gmt_modified":"2026-03-03T07:46:01+04:00","raw_data":"WikiEncrypted:rjW6ih7twxOwUWSEZRQSjMx3LD6abD8HmUkKFFPrE6+YNvBCO9jnmcKRUqOnqTvQ77Bp7GpSqu3EnejZfaQk6gcLDZjPBL3ooAdK0NnUt/cvyt44w29ZLzQUR7fLyl/EaaM8PD3EHmh5KbEHPdM5Qv/UhCU1HJOaXqKjbkSB9anJwMgXMqI4TXjPfJG1CBW0odtrTRP6vuQoizHae9B8wRbH9z6wx1wO2bCKdGc/AAsousfd9W8rU6gsYKhBoOnOv2jT8TLg1UD99DHqMj7+HwMWbj0A/Ko1LLN+NDUfPJzvkAtLAb0+1n29Jjw2mHmsziaJpfy8XwLanCcoQbpA3r1+Legz+qo1Q96PdTMjz5eII9Hih4Qq8187zY++HOXJj5M2dzTsCG/s9FukLTFrRmS0kSNJThGJdVEnpmeOceOgtyObzdMtxrvXHoHoxqU52gLxnO17rdpvToLMOjvJQ0yb+dvaswKB/ArrWU+hs8NBbYhFsfFNDqI+0Essz2/AYR9WwfXyYXdyNLEyej9YEaUtmNen/pU7ln6iOfj2OFj1+JDk8AJHIUsox+2IIaXvYzsaKgv6307xonngMoGPlzCsATItgH73r3wzb5n5ZvPMwRndyNpclDgWPuzZusKvOOwtKpdwpJvVBqnr2RMotAsRCV/lB2iyuUvA5mKoiBcfIZT8FYsFzyI1F2/wLe+7Gw6LMvnjD2fTAtqfdan9NALAL5bRxUjWMKNCCVVAiXV5JbQaeb7FWgNEddvKexsr7f7KCvQ8ayDOLy0YjZgLL8zgyF7QaLzDIm6RyFnmW5n3ME52gkzV6K5RLvmbrW6fPkR8iswWGXIwGVt2nQzyNR7XGDCQIEVdLGBFHmzimOKr0UvJmEkY7SRjDClRvnr/6/wQBj+ZGdAqqEYIA3WCsDvl5aw1lzQBs23xS7A3LVYE8Ynsl++ybKRXzpkTmP6+GP1D9lgV/Y4ID4C568ayZvlSnWh8skGPirHby0ecdMI+Rw/Sk3HMhgd5Rf0rZAnGI4SBL59LsChXvzb+jtgSbzTRbH044gVjDDGvObrwB5N91KqU3jodTugmPGMe9z73My0mt2qudqsPC1Cibe3q7KDDxO0WUBtR38BxhSnx0WoSfYtQ0vB1cGC92uBwe4DundhZEOKNDPAQAumQXB300lg9Po7YHs3T8ytJ6//ifaNLeN1K455rd16UpEqKmS/1onHFH3JsDNSH+u3VAgp67NekBTzIX4E8D0CViyiT+aW6CbffItnYVPDviYXrEuCxWXW9lHvgJf1qt3snbPE5SYt1z0iaeGwOQ2RTF8LE6Dr23K0Ic950Pzc+ZutY3HI+SVPGv49IqdJEMb53nwQ98DKDwAMpF0OKkp3UI15weMXgTmdbFtsM3J2WFhSutvotj403H6b+ljUMWnpKwCwPifYfbo8grlTYUeZan7HtL40qr5Kk0Vr9YSDXQ/aIKUaYSIHZbs2xlF2XwGI5ewXPsHXfxFNbVt9swe32TRtOZyxTHRV32YEJlh2sl7knGDRIt+dEtYp1xMU8MmdF3Av1NRQjVYV6j1uRdGCI87hMor8bSdRwPcGqY4DYzA9vAndVh6nO6SeORd82GeBmlC5dRJte0PiupccTnQaii/mYH137g27DXkrh4BW2GyCWa7M/JkK1euRE8FbSaffj7bwXMoe7rVUJVQFSG7gD/CrqxaHEyTemqqRoLKDZ1pxRvzeSztF2Az9dO5gBoOPJA2CXTKQaXYol+IBakFkIRb4i1Q40KxINQCJ1IRqGf0pbUpgnR90yLZTWsclfAd4wUFmoRHgBsAeBD93sQMCiY/9qdGgYqdHLwavsrqbUMKADxmqXyPxzCXsdjhU9JgjOOxsqy+9zpFSou6qw783eYAr/O5VEqHitZFjeIkqHQ9JNOafdsGKAOvOl3Y0Qb6/yGwjSItxnmRrd0rJSjXQSzYUkHOrCROKnASJPfnvSlzBHkOYtSy/VfLETi7FSfPwvjV1Evw==","layer_level":1},{"id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Debugging Tools","description":"debugging-tools","prompt":"Create comprehensive debugging tools documentation for VIZ CPP Node. Document the debug node plugin functionality including state inspection, transaction tracing, and blockchain state visualization. Cover transaction serialization utilities including sign_transaction and sign_digest tools for debugging transaction signing issues. Explain network debugging capabilities and peer connection monitoring. Document performance profiling tools and memory analysis utilities. Include practical examples of common debugging scenarios such as transaction validation failures, consensus issues, and network connectivity problems. Address log analysis techniques, error message interpretation, and systematic debugging approaches. Document integration with external debugging tools and IDE integration. Explain debugging workflows for different development phases from unit testing to production troubleshooting.","parent_id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","order":2,"progress_status":"completed","dependent_files":"plugins/p2p/p2p_plugin.cpp,plugins/debug_node/,programs/util/sign_transaction.cpp,programs/util/sign_digest.cpp,programs/util/inflation_plot.py","gmt_create":"2026-03-03T07:28:48+04:00","gmt_modified":"2026-04-28T19:48:38.9116038+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"9d487fbd-32f6-4e37-acf4-e314d7f75019","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Docker Configuration","description":"docker-configuration","prompt":"Create comprehensive Docker configuration documentation for VIZ CPP Node containerized deployment. Document all available Docker images including production, testnet, low-memory, and MongoDB variants. Explain container environment variables, volume mounting strategies for persistent data storage, and network configuration. Cover Docker Compose configurations, container orchestration patterns, and multi-container deployment scenarios. Document image customization options, base image selection, and security considerations for containerized deployments. Include practical examples of common Docker deployment patterns such as standalone containers, cluster deployments, and development environments. Address container monitoring, logging configuration, and troubleshooting containerized node operations. Provide guidance on Docker registry usage, image versioning, and update procedures.","parent_id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","order":2,"progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-production,share/vizd/docker/Dockerfile-testnet,share/vizd/docker/Dockerfile-lowmem,share/vizd/docker/Dockerfile-mongo,share/vizd/vizd.sh","gmt_create":"2026-03-03T07:28:57+04:00","gmt_modified":"2026-04-17T17:31:31+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"3834864b-3db0-4e65-a23c-0fcd2d2759ec","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Cloud and Infrastructure","description":"cloud-infrastructure","prompt":"Create comprehensive cloud and infrastructure deployment documentation for VIZ CPP Node. Document cloud provider deployment strategies for AWS, Google Cloud, Azure, and other major platforms including instance selection, storage configuration, and networking setup. Cover infrastructure-as-code approaches using Terraform, CloudFormation, and other IaC tools. Explain load balancing configurations, auto-scaling policies, and high availability setups. Document CDN integration, SSL/TLS certificate management, and security group configurations. Include monitoring and alerting setup with cloud-native tools, log aggregation, and performance metrics collection. Address cost optimization strategies, reserved instances, and spot instance usage. Provide disaster recovery planning, backup strategies, and multi-region deployment patterns. Document migration procedures, blue-green deployments, and rolling upgrade strategies.","parent_id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","order":2,"progress_status":"completed","dependent_files":"share/vizd/docker/,share/vizd/config/config.ini,documentation/building.md","gmt_create":"2026-03-03T07:29:04+04:00","gmt_modified":"2026-03-03T07:46:55+04:00","raw_data":"WikiEncrypted:42GucIVlAI9L6q+fifwcxVAbKGavmbcykvSdpgqxh0TAH0q+Ha/IQo6kdv/t6QkMYWTMvXuFMKqUZoM0bohLDe8W53czaDR4WlM3erwcKXxehRt1aXbXJnaLRx5p6tp0sSc3yVRNCnBeosg2oZgzfAsdiQ3vsqyvdatYm2IdxMRvRrTvAQAf3EXi5NkleukIMVj7pJFg0FmHLSHCPJTCylyT3QWXnGfziYXeWW2khY7v+8Us5ezMGnf6jtPNvnCovh/W0Jwz5nDLCQ5GiXfdUoXkTp6R3Z9R7G3NIamJO/Ts5mUoKGPsj0vYelpUO3aFT4BWbQIQZDITxYj3gU7DBEOBZ8IPxtwv3GMfISKYxgJB3CrVK/bgqpF4RcYKOBamAjpUpf952aLyaogtOs8q/aJDYZDdTHmp56r9jxJbD8nWY9ok3JaIMdKXprcr5SFRbixvMChg0uV0c8/AWq+4+127b2zJSSY1ec2oFownTPZzPIvvwBxf6m830cdR3QzEHjOjzWqe+CfN6b/fWarCrOPng0F9P0fy0XUu/xB1RcIdC9BpRf0FpxTlwhT5dS6xUWBR2w2I/WfJ/ptaaU8FSHbqcMMng9SVWw6sj9AtJ7sXIg7Ho/HrYpDiQo95kLZQ/c8BrEQbYoxVhgRJlg3ryjdRmJa7PzpkjCSVvJQbDBTWmzT9tCTl988jdhrgTRyq/7Bpq7IZdM+gxUW81NrGi+pwi4vZaBOPbByVWy0mxWrtAm3i/xUTuH/kn/O+Y757em0jpxyfQj2IKjDhlBeZalbF7nYa/gMUWUrbH96TqX1OoKco40wP/4ASi42IAI3ceorAWVWNhtRIPzj2JeYbBd/FU0nr5zbJs2NZ6K2EFiOiavlntE6Om2m0FdBC6FZM1Low/kPL6IjYMLndUv4NYL1r3vWi1rP/WSUzut3bDNlHXT5Ob6ylkSOHZbbtZfxXb+0fEuPTiZ3gUXv65HQj8jqQZMuX7A5P5iCdB95cW7K1AGYhCOMvHZas2bKXnYq3QQ5/CvoUMsR7WbClJfnL+FhsDbFMZQC1c5KYlcnAZeL2D1bWkdFvE/MwqyHUeWYT909jQ5eeHzlx4Qy6caZn/Yyfc7rIc7m0ybcWTCfNwAPVPvvIVQuKV2ydlb4mMtxWDjpZaweNbeCKl0csc1ROfMo3Mfvj1zeOByo1x8J6HXtYUrbHrhn9uyTDxfTisI+mQ5AUDt9jEiQS4DhAZ+F/JAVmogZCpOT0/790jKv2wdvFu/4gxR+vRFIFMeHIJOcHvGD9ntdcMvcQu/hShba4KWIyIYWviX5676XmJ0RYo2JJDPyxZRrMddWxVh9vjz5JkLNLfGmxVSYNZVOYiX6tAo/g1C6a63Wn+72bzFXcoVOfsDxd/2nk2yHKRcdkPVJk4hqwdHL0d5YVN/lLz//BIs8p98fiLnGwtJnDbQtiHTu0PD60+Dh44NneEPi6jcosEJbYOYqqlcWLEpw4Qsmn+9NsA5sdDTw6rCBb7+OX9+mLnfOb8k9OZfYW+i91xz2h7uAheSkmbiNtBSgptexuaeDDBXsOnet3A/tj5RkDfkK5AF/hgfn5KnBNvY0cr8gy5rF4J/DBD5nwSpmmgiDITXoZ639w/tXh/uf3Op0lhH52Xs/Glyf3ZtkyS5iHN6Bf2otdwJW0rjt3+xuetuP+uB+V4oFQDk/5ZoFdFk7TPu95ExV/OMXnmVsyici/qYdAeAuyng48BNsXyc9wQT4N7dRJmESPRwtj5sMmkloB8nE7m2MXIoOPZIspjk97jxf8ju05sCOtU3ByqzcSrMLpLe5w+5Nl7bWVPX8zxYMryrZpovHuNJOyygUwTF+BS2z8o89Bi8KQ540RBAJXHsG4NQieAMubqajWjhrlsPbRvvExmpibr/H+zdVg0meSoMf5FBswqZoR7VOmVY31HklSvz7wIlpsbEpmELYP3Lvv1TQ9wPXt10Cm6Ta/VLX4GTsITlswbcqVyrb+gEqqhxnnBXPxzwf76dK5+PtaJ2rdyfuoZ5yrC+QfKM9dL2Fj+vS/xou0zgDkXkxIX9KWMtWXcgHoR2IJIKt0dR8FKf7RDmgFj9ZHAfouXri7F+X0cdMh3fOkObWXHdAVMp5wsgluVMLfY1hs1e3nJzS0Lwvhg0ElMIPS4uTrGg9S8I66U9mw","layer_level":1},{"id":"fb7f5918-6ff3-4fba-89b3-37eef3bf402f","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Custom Plugin Development","description":"custom-plugin-development","prompt":"Create comprehensive content for developing custom plugins from scratch. Document the plugin template system created by newplugin.py and how to generate boilerplate code for new plugins. Explain the plugin class structure, required methods, and interface implementation patterns. Include step-by-step tutorials for creating different types of plugins: API plugins, database plugins, and network plugins. Detail the plugin development workflow from template generation to deployment and testing. Document plugin configuration options, command-line parameter handling, and integration with the main application. Address plugin testing strategies, unit testing patterns, and integration testing approaches. Include practical examples of common plugin patterns and anti-patterns. Provide guidelines for plugin packaging, distribution, and version management. Document debugging techniques and common development issues.","parent_id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","order":2,"progress_status":"completed","dependent_files":"programs/util/newplugin.py,plugins/chain/include/graphene/plugins/chain/plugin.hpp,plugins/chain/plugin.cpp","gmt_create":"2026-03-03T07:29:09+04:00","gmt_modified":"2026-03-03T08:00:21+04:00","raw_data":"WikiEncrypted:VrTOMK0P24YINQ3w81YokeSPoB5X9Zo/YG1ok/2a/9ryYLsqc1VARxnFCL4h0y80V3hdIQYc2nWoxIlKRpkvalc7lk5z+JlJ/h/qV4B6VpDkk+7D+iI3Z4iiJ+aP+fnnzj9U/9miQtCCYqlIsgWw+M9ctNXxnyPRWq6ZFHOXO8ReBDq830QA0iedXPe15iArFJ0CpRhfTLTTh9ALhUWxyPZRIZcV2qFU6q+pSX3xNlG5GtLnDcpg9SthmqU/6DxfF0a/GwjHlA0Qm5Xf+F+i4Bdbvby/N9F61bsAtP6CIYEEHZLpvZ7bUxWipx6BT4CGRgByiPmQ39OAPt4yyHIaljAbblr55afTAwZrUbm/zWPAE/pOToMuqYS73Q6aDy9pnGPyS7rCRF9EkKJFcUNHl5hDCnShN+8gSxwHBbKCQS/XR3jbcnxP31XcNG3EM+iT2BUM0KL5nyDV7vLfXXzCeX5cVikVB4Xvdd+GxWgmynOSqmhniOSVBSDu72nUH5kJrVNHoq4Xz1GhNe2cJFUTNkj4PTWcJssbQpwkn+9d9n7cvrMZO3AXrXCluG87yDMzBWORt2Ea0c8YkAiIjgVQlJJwhagve5TCBW7UzjSk6V41rVhKTEM7lCXWLy/yp7YpGIfakUS7Lo/hCeMT/WyMLWXmqKUvfEnAGQUp6mO3rRRUZBCbNkG48j5RTa3tfd0ak0RCGAgJNjiGRso9vwW3Jcy2MDZmKhQmBrhDQU+VTIrOkUnE6BBsC19VAj5nax9ACH+hFBfL7DVYoQIGZQWp1UCDJ8KlWyhVOtYYCq4P4NYjpZTqjd1Vm4RASVSfB0H+7fXJHEKaB9G/eXLp3jG1nbt1IKwDLbT9PpTNnIeF5JChqi049/67JCP4z0rbSq8QP5NrL75g2vXzybKuUtBIRlltbRFisNBnLGabdSJSFZ1IhgJOrOeLMYi2QlJho/MC0Wj47wyZwfdQDYqPaKXRBXQf8g0cukIk1nsIzfdnkDFylPauDWhPeJzDDoj+Xjur1CqrVQgeqxTZl7F5qLt9zHcYMBKkKTGe7HXcBOPiBNyiqDaBxvSLGres01tOjl9CLdct1U01YH4NADG9O0zSpORIsSwTPiucTKNwtQK3KhLpXkhbBHtNc45Yqx96Ok8aKTjwFe7xsSBzPFPdzKDgYzK2O0wbdd5cXeoKtUIn2wloznUviwRJIA9vBh7DtFIUZZgubozRwhs7h3AQ20bM/3F74UthcMhn3AWW3KvV6lwe2ZAUufnBvtPcNQJaJuIk2JPwxkm6TgWeb9GjBtMUaFWYRbw5a5qPyku889Fa6+eB0DrWaDsAPZC01H6k847c3XKGxo/2lCbVnGbNeQC4oAmm677HgDhYaI/Igx75b19V1tEOkUDrxbKeMW+zH+M2XVjD0XvnmpZXJORM9byRnixT9WBsPniMEfMc4Wz6cl/LWi+j1zTYfIB3EVLEJAkZwwtMmwaUvaE/3QeeOrNl6PeYpaFmom2Jduvh1TrvsgC7qp4ii/vL6o76+31OePjzmCIY6ELli+eSVt8H4nqRSlcT541ZYf8jchQUrKXuMk1mtV1oLUgZeW0RZkQx6UN/3aqbbeTypZmueX5+evi4WFejrIPWU7EN0NFHUkZlAql1SXbK3nQ+aFAFVOXeafevdvZpRjQaS0j1idhirFDc/N+POguzTwbVsiJ4x1WByRcs4EuuSUTgWZeIxZLyQ5xd","layer_level":2},{"id":"28bb2a2e-23c2-4009-8847-35e8fac1f151","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Security Implementation","description":"security-implementation","prompt":"Create comprehensive security implementation documentation for VIZ CPP Node. Document the cryptographic security implementation including digital signature verification, key management, and secure communication protocols. Explain the authority system including multi-signature requirements, threshold calculations, and permission validation. Cover API authentication and authorization mechanisms including token-based authentication, rate limiting, and access control. Detail network security measures including peer authentication, secure connections, and protection against various attack vectors. Document vulnerability assessment procedures including common security risks, penetration testing approaches, and security audit methodologies. Address security best practices for plugin development including input validation, secure coding patterns, and threat modeling. Include practical examples of implementing security features in custom plugins and extensions. Provide guidance on security monitoring, incident response, and security update procedures.","parent_id":"7a20b53f-0b97-40ec-a630-7e9171a04006","order":2,"progress_status":"completed","dependent_files":"libraries/protocol/authority.cpp,libraries/protocol/sign_state.cpp,libraries/chain/database.cpp","gmt_create":"2026-03-03T07:29:10+04:00","gmt_modified":"2026-03-03T07:47:20+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"0ffb65de-cf29-46a1-a84e-5b7531aaa9cf","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"API Request Processing","description":"api-request-handling","prompt":"Create detailed documentation for API request processing from receipt to response generation. Explain the JSON-RPC request parsing, method routing, and parameter validation. Document the database query execution and result formatting for different API endpoints. Detail the webserver plugin's role in HTTP/WS request handling and response serialization. Explain authentication mechanisms and rate limiting for API access. Include error handling strategies, exception propagation, and response formatting standards. Document performance monitoring and optimization techniques for API request processing under load.","parent_id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","order":2,"progress_status":"completed","dependent_files":"plugins/database_api/api.cpp,plugins/json_rpc/plugin.cpp,plugins/webserver/webserver_plugin.cpp,libraries/wallet/wallet.cpp","gmt_create":"2026-03-03T07:29:21+04:00","gmt_modified":"2026-03-03T08:01:46+04:00","raw_data":"WikiEncrypted:C34GewOyK1SlumqKiPsSg1JYzeCsCQE5DuJT41k9RTGrPgA2abBsNlRj9b4XM+jkw4/9NpaPKF6EJT5TeM3pEGtAXs6fmJFpD/ClSCokjO5iH688bbQoqGmQTvYhz6YFrqi2ZwZCgLZqxXjeQ+3tTxBnymCnZxB8FG4ZCYnO/aM7mVFF+wX7cs8cHpaPsXcOfr6Hd4fzmo068z3DM7cGFEXM5A9ls1NnArh155cTf2tueq9UMQkcnntwWzMc3neifSA8s7zCMMuRSbFSClMbY6V9dfVNk5WdOY7cmVE3DUCVinPejJUo5YqsnmY9dctLkvnCjD6r/kkmzQGUdQwKWL//akcURyfe4GYPSjtIZ44ZT/CLrBfKXTw7lan46TCZC7F6qfHQ9aadN3F4TnU5H1ujcRcpThzxdMPsuZ5BEQn14HqOBg4t1kbtlKTeiELTT55CEJBjW2rFbl+U9FB08CuygiPBZllXzpMe0RU4PDD9z79SDJBWHgOSd5WGX1YGQkYKq8L4nuJtoWQlrZ0BPAWIbvneiGiA3oNibLVvbq9BAn3NLuJI+AHJ3loWhzJGAZn6YE/6InN+lcFAd947H4Pe35OluAh6wFSB+XAcNyhKupdb5VKxOSe3opO5Qc8am/tofA8ZU9WYaCGGUEqT+/e6sSfhJsMLLmmY4CNJDdej/QfScNXvrkwcxc2LiYr0NgtIOrzGpsQCuhUVJMPO5LTXSgIqFPE6My9mOIRFinxm2t95cIsVXW4w9PLc3nX8s4sDtfXKxBJNNVzoPQqh4ovzWp8W0I3tY9AJTzVwJpyS3nRWg617dFDa4qGd2+4E1erMFsGEK8BgcY49CVHEMFf9sT45cISssrcMnGi02O6q0dnjHEEeAAY/0T9S4FTN7i80L4k4ZmYEqxKSZLyvrD0737gx9ST0tKa6JpoLG9tT9P1uZnS53sE9aD3HmZkiyLupKeDDv+qpXFpKQoFnkXRndxAB3otewfQhgjJBiHkvHJOUCcGwu7oUTksIx2X+p/HOUVm/a/YaOLOlZg30lXvoq/NBVfV6OXioS0MhhybUF1ZIFv7bCJjXmKAjJ8RzXFBIteGan7GbAqfpCj7QXfNKDIbLTzTS8Tcc3xAX5SftkaJP0F1zb/wPjohfgyOydr9/jfRh6sukEK9rzTfSOuFC2Fbbo/6WmxuoHaivcCwy0lnYP6CZSdGlum5moeyIrqTQBKfgud7vvmpVu7KYrWXaidCLR8KPdODZbPhMACrFawOh3JYjSLEpfTMgtfWikcDOVPjVG52gBOdZNLUQlkJi/ZOAXSmAlMebJ4m1bVS5tnVK9x2Xb3MMwNNJrrlh8aX4ugvzgu71ryH9sfQkOi0JNkbmRqzITStS4cC3qdTs9C75L7Vl5oaVmuz5yGSn","layer_level":2},{"id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Network Library","description":"network-library","prompt":"Create comprehensive content for the Network Library that handles peer-to-peer communication and network protocol implementation. Document the node.hpp implementation for network node management, peer discovery, and connection orchestration. Explain the peer_connection.hpp for individual peer communication, message handling, and connection lifecycle management. Detail the core_messages.hpp for standard network messages including block propagation, transaction broadcasting, and handshake protocols. Cover the stcp_socket.hpp implementation for secure TCP socket communication and network transport layer. Document the peer_database.hpp for peer address management, connection tracking, and network topology maintenance. Include the message.hpp structure for message serialization, deserialization, and protocol compliance. Provide examples of peer connection establishment, message exchange patterns, and network synchronization. Address network security considerations, connection pooling, and performance optimization techniques.","parent_id":"139b0217-0190-433f-b41d-60fa08c9ee5f","order":2,"progress_status":"completed","dependent_files":"libraries/network/node.cpp,libraries/network/include/graphene/network/node.hpp,plugins/p2p/p2p_plugin.cpp,libraries/network/include/graphene/network/peer_connection.hpp,libraries/network/peer_connection.cpp,libraries/network/include/graphene/network/core_messages.hpp,libraries/network/core_messages.cpp,libraries/network/include/graphene/network/message.hpp,libraries/network/include/graphene/network/stcp_socket.hpp,libraries/network/stcp_socket.cpp,libraries/network/include/graphene/network/peer_database.hpp,libraries/network/peer_database.cpp","gmt_create":"2026-03-03T07:29:24+04:00","gmt_modified":"2026-04-28T21:31:00.4625046+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"3789801b-aaa1-4c34-a35a-c5b48338520a","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Docker Integration","description":"docker-integration","prompt":"Create comprehensive Docker integration documentation for VIZ CPP Node development and production environments. Document the multi-stage Dockerfile variants including production, testnet, low-memory, and MongoDB-enabled builds. Explain the GitHub Actions CI/CD pipeline configuration for automated Docker builds and testing. Cover container orchestration patterns, volume mounting for persistent data, network configuration for node connectivity, and environment variable setup. Include practical examples of running development containers, connecting to test networks, and deploying production nodes. Address Docker-specific build optimization, image size reduction techniques, security considerations for blockchain node containers, and troubleshooting container-related issues. Document the relationship between Docker configurations and CMake build options.","parent_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","order":2,"progress_status":"completed","dependent_files":".github/workflows/docker-main.yml,.github/workflows/docker-pr-build.yml,share/vizd/docker/Dockerfile-production,share/vizd/docker/Dockerfile-testnet,share/vizd/docker/Dockerfile-lowmem,share/vizd/docker/Dockerfile-mongo","gmt_create":"2026-03-03T07:29:30+04:00","gmt_modified":"2026-04-17T10:15:28+04:00","raw_data":"WikiEncrypted:CMPQKjsWj44q+b7DSXFoBXMIGf3GaM3SGkmd3tknFiEqzTeBe3V3x4Rl6LRWK8ucLbbUzS3JInyHtCKQF0ZtTRFsUM2pHuNQBR/McP7zrp8kqpYHwp5RGHgFScAIJwhQeXMWt06bLnmVd5jsAHbioGS3UmhZLSzkbyFrOFeAaGEXV1hChm+rrU6fiW6cWeDh/zmPZpRLLe9VMrpkoEeRdFbzZT3WClOHLOc21Q2QZIyRj/POcXUEOYFj7lriSL6UWS5n1a2f0990pasHQZrSROtt5Xmal47gweop/quaPDZwrVU6s1NnlXmCs6rEr4dJA5PRzeRuwA+IdaxWwk3Zb80SobupVgM5K8g0YWDexoK15CgzQujFwTMO2ERL8laZv5KLrIl5W8f5jaoBbQJ/lpn3NzJ7j8V5G2HV/Pxd0mQTNJQnaMEexQshyUq8A92SpD1Gs6HK1JIdhUlzhsRe1GRGoJuuPM8iA4tSta7F+VdgOw1OQR8qMP1qqr/fGPBLGlIv+hJiRrCjjNH7qpZbCcJ+PKj6aYiSpYSoEc9nvZtyH2+YnA2QhNmN4hBmJ6cg7dQo0aeXxovS/SXyorpTTYYDRllJmEvXUA5rZVLd9m4JHDlnClDCncfys3IV4iX9C+0Ah1xl89YcyJQl8XkY/g/I8pqvKkNxvEtpYL/TgSqROPQOwHOJpgfns8EsUoUrXC/j5oCa84HkdfonOoxNcSpP3tZ2DEj/grMQcCXy9p6atU/zKxVo34A94/vTRp+1ipz5l85OxMoNLshI/I3p4+dAn7iuK/aEe33cSFaI+8Inb5ihmdHlttjs5r/LOqmR+MT1od9da+q+eAkI2NU2wMeDjjQrohsBGZiCCc4fTm99YkcmaekEa1pKCELRIAb1HQKR8nJ6Lvcl3fXj/EddyME3X+v51draQWrzB84H0iqVHKBhvctVPQqp8F7UTzC9ZV97vjpmMpCKOUatXSiXCEA4U/zUEZkSXx+Om7XEhUGJjvZ6UOcd2JW17WKykU5RkzualU11W9DGXaQwMkZI2AY8ipfR1C0R7ZBmg1v3m5Ae8vCCzwjnIP1mkLI+YbifLz+WQNRyyx529VyDi+bndgCEnArzpZePLaLaIOTGwU+fupkPjyLtgO0Mkpjhg8Vjrr2boJhLj4YpFopCDcD23akpBgMUjtnkleOZIaM0c/CSz3r84qmWigf5JNU6vxgBsuosmE1RIbj3ql1+qtCEhfGozSOYcyiw9lR0rNCq2UzWi0fNGU8Yu36iNXw0nld+PFDTSNPLb4Ed+KkqeMzyIIMaPjx/FAGy7UnpG9ZlfLGR4lxxGVY2cOCPGYj65fMeBBL6AUWw4J+SxapwO/E+8gfdYpgThk25UybTF2EpYO4Gpn86aa93NSggOT18LsOWm74ys84v2mxBJ6ds1Fbizl3EJX4jLUG0bJBR6kpEMOwkYEgs5tIby0stgF8anPgJC/Npttwf4iGkZ9WrL9fDElVv70dYw61rXyzQV7NyplySti9UNFqHPqNYeW3PW1VdlXOAWcJx6ic4QFCQPHeX/42x3lcgwDmgUBFNuVBMzgHu+ErwRngOCG+eaBoN1RtIFoDrFTAuf17hiDRMN5yE5hIx9xbtb9LKoVnMnBRGHVt7zMpPE8bkGlFDyYfs/0j7xtso4DtUkFY7kOZcgB3HWnJfMXPQmCMahTDHo1bnk5cwa8WtJRLE7Ns87Wt4DgTeN8/JZnRxmY4uEOzAnehwmcb7I2OUEVk0ucosgNmJk56x2PxTuFbfLAgr7ZXznOt5zxJLOKhaRiqoY+T6fbdwdr5dDazRxSqhLEF5KYJbuFEoPvfILO04KeaXNdPZ0GzZXRHUJ+saTGDDDSJDjI/woJxYnpPrA/ejN0UIER/hnmJ4H2GlP6kgjCqt/X6f1ybak0FEPX+1HEModDzw/Cy3tw+ZyEROrOBk8q1iE1FyAoE=","layer_level":2},{"id":"be25befd-151b-41db-97bd-3bc570e2cf2d","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Network Debugging Capabilities","description":"network-debugging-capabilities","prompt":"Create comprehensive documentation for network debugging capabilities in VIZ CPP Node. Document peer connection monitoring and debugging techniques including connection establishment issues, handshake failures, and network protocol problems. Explain message propagation debugging for understanding block and transaction distribution across the network. Cover network performance monitoring and latency analysis tools. Document peer database inspection for diagnosing network topology issues and connection quality problems. Include practical examples of common network debugging scenarios such as peer discovery failures, block propagation delays, and network partition detection. Address logging configuration for network debugging, connection state monitoring, and network traffic analysis. Provide troubleshooting guides for network connectivity issues and performance optimization techniques.","parent_id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","order":2,"progress_status":"completed","dependent_files":"libraries/network/include/graphene/network/node.hpp,libraries/network/include/graphene/network/peer_connection.hpp,libraries/network/node.cpp,libraries/network/peer_connection.cpp","gmt_create":"2026-03-03T07:29:38+04:00","gmt_modified":"2026-03-03T08:04:07+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"5bb14590-6784-4cf5-b371-7c3778519d8e","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Service Integration","description":"service-integration","prompt":"Create comprehensive service integration documentation for VIZ CPP Node deployment. Document systemd service configuration for Linux environments including service files, startup scripts, and process management. Cover Windows service installation and management procedures. Explain integration with reverse proxies, load balancers, and API gateways. Document monitoring integration including health checks, metrics collection, and alerting setup. Address log rotation, centralized logging, and log aggregation strategies. Include integration with cloud platforms, container orchestration systems, and automated deployment pipelines. Document backup and recovery procedures, disaster recovery planning, and high availability configurations. Provide integration examples with popular monitoring tools, logging systems, and infrastructure management platforms.","parent_id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","order":2,"progress_status":"completed","dependent_files":"share/vizd/vizd.sh,programs/vizd/main.cpp,share/vizd/config/config.ini,plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp","gmt_create":"2026-03-03T07:29:47+04:00","gmt_modified":"2026-03-03T08:03:49+04:00","raw_data":"WikiEncrypted:vMsgMax61wW2sTWhXd8DH8qAw9CtLog8cZ1tiD2BFP+U0bXW3hqFYf3RL9xyiBC/9b4sFP+QmOk2wmA/qm9hf0gT3h2Jws99nvB34YCyl5dFaIRl84rx/o3Zykg3tatTYFluDC7sbSvs1O0o8gMlPHhUonDd9S0Wby8VPQZNvmSEJ/WgHJJygKImU3JR6hCKaVPIJYXeKFOu2MMIoj0sshp9BQnlc1PmbUL9S4on4eMkB10USK/Ro+RgIaYSkS55t21sHWbLTo0AlxIYQ+u0KpIzryme9wNUHxNVv1/IR7MrAd/lUW5ytYLeeT+8Vl87eR7Z3oPoyjsZ3ZbIID+QIAzdNu2832ZZA7xUUgZJBC5mMJz9XR+Ufm671kMd/tgGWmWR36CAQ6tg5WVoTK7FLLOP7NJr8n8JYqcBpGXHRoFWOzLaYd/eBTgigAT2//TsubTjnTst0Xr5wCwHMEizXHcho4YT8rdM97WryHG0LqDXPXpKfJdorLOlz48JKDaCjVGeE0oO77OerszQWRaaHz6Otzq3+Suf167Tp6EQB6ErQpC3x79NVUEBJkgeltwq8BZzB7mT8WjiD8dzA0ouZxOkfye1tPTKgdN9llQJQM8YmsxV7dzAJ9Zk4fQR32f2I+8aMONsLHq8Ye0GRjHmVjSP/I59+8qzq9/vTKE1DLsRm4ATPJm6qpIKnbhA0L/QUgRkjpOOiUiBlYcKuzkNtxwYGT3Kl2H16TVZv92wuUs9Q0igRFhOuMXtMF9dOAD+8d1kAMc7s4bQJGqb03MNS52ZDa2NIjyeDjP0N/ZIVSlCLqlIXeF6nFzlI1+2RLWMSqlSXt6WiZXkhtgnbBXQJLp4ZBaKnDBezrJI1PXBohf13XZ2y6AXkuGKjJwe2fxE0A8vynkyIyTeAHBpfoXcdDVI4GhaTQMaGsASUAJuQjOCFcSj01Z9IjxjFv9fddpSlR6KvnOhqrbnZhltVnNCS1CwWaGGvp6fakDvnZR8lnmI1mukzzde0zZ2GwMrypQo4wuGW5bUH/XJpG/r2UwS31ArKbP6E5Mfq60OymRDINMWSJD016iwBtvaEo1S0F1Vjf4P+4v/qFKApG9mMaDKbbKoS/PxvkW7YxbBhXqSws/TlykHsuEDeoVK2qNyZnn16LP+XaIog+yFNJBrS2FuZVo7pO6c/qdLfuiO550zmM/y3Iq9vfDEywnwrMah00LPAPrIw/Dmqwzn+PZdfz/GeSJifvAvbHN6iqVbUV9Est6nDFcNVqxGylGlPui1mJ3eFg0/wFAKf61Q4yzylgEf9LWqzN8hl6GDzQvN2IY7J0GbIzEPoh3fayxchmU1Zeom4xwtv56vCZFnrdKwgAQ4b3HBzBT75pYKEeNtPfI0y8BJNbfYdA6jocqZP0rnE2GTTX/2LIi+d5ftnKdahlv0oDtGTzHUEnh+q+ymfrrslIS1YjUiWsYi6g2LlRAmZ8gzhK76DQ7/dM8k7Q3SoCRk5z/kcLrgy4Z+lSLqasmUGhewoVBLdudC/Eam77SJ15s/5T58WIE3NT1UOw8h5O5j7YSWM6ErjZC3uTvEVtmRhBi3To4FqO7dWQW2Da8QJewcor/ldmjaEGpFSBFc/6ROzdHI34DTjOHmfroIsfx4/UVKbxb3RgViP4DVjAQj5jnLvHM5mdVIuI6vaHF1UAJZTsyAfcqHB6ryb9xGYZ22mWk11OakmTv73w0PCQRHAR3mqVUfiFG79eu7OLe/5+f4VbaxwegE0DGd9+WbkQl2tWc6wwm700mXO+ZWAB7RbkXEujlUF7HZ6lFfvT6nDQxEnb6riuw/0+d8RHlIWR93YaCmx/7UV+HhspCPHD1G7vaG2lFLfLaEMR1FucZeJsNLzzYDyqTfS7YNjOWpfjCSmzjS7qzViO7leJGrPVv47n//","layer_level":2},{"id":"75eb3c5e-02de-4177-8680-a24fd13d2590","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Authority Management","description":"authority-management","prompt":"Develop detailed content for Authority Management covering permission systems and access control. Document the authority.hpp implementation including authority structures, weight calculations, and threshold validation. Explain multi-signature authority requirements and permission hierarchies. Detail the sign_state.hpp functionality for signature validation and authority checking during transaction processing. Cover authority inheritance patterns, custom authority types, and permission delegation mechanisms. Include examples of authority configuration, signature verification workflows, and permission validation scenarios. Document the relationship between authorities and operations requiring specific permissions.","parent_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","order":2,"progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/authority.hpp,libraries/protocol/authority.cpp,libraries/protocol/include/graphene/protocol/sign_state.hpp","gmt_create":"2026-03-03T07:29:54+04:00","gmt_modified":"2026-03-03T08:17:58+04:00","raw_data":"WikiEncrypted:Jgq9fCpm/NkqSNIWYhs+n4jiUARsKF/Jd4ydE+1m2zwQwWHJGmtOerLGG8TW7XbS4S/T35fVYB/yJZzgovCH718BLdmouX/kTxDmd8tNbBdrrta+doQxNGDkod8z/WaaQYLVb4IxX7U/EjoAr7/P+66vrhi6RqYj5fBPtrSgLJUW/RR9MCpaEUYd7pGcSU6JWeCOU2QyjuuYk1SyjFg+g1rcuLzhrRhHI9zKfjN872ae11+XxxBNxki1ElyJsf3BevyOBdOTFNxxS363QkNd/vpvy4NvNUs1OpK8DvQeMiVwEtO8/HAwIm2nwoQnxz0E3q+QPoaUTGSDd7BN9thcQWqlBd1D6lTayxEUnWl33CQOWEqRTocDEicRTnxYYEwujQCeNI8NVyTgieqInU4N2L/J58a02Wz8RQi6AJXBFQ6f1btOEF/VJS5xkGYxJDnigIiZctgWc5R/uQ+g2s9733TZBWZBG5jaZK8dp6ZIH1hX31+DnMRzJnO0xqnFq1JGcThh3FXCYiazMyDvVG4xlJVCLM9Jg61r4bStfBEfdQofNXQXURMWrAWgVRjgBpvKKSIsaJzo/m/mwupcs6A5ROCTsUktizLhzKbWqTUCOhya+jnqDYc966T4LKBkbRgz2G2viJ4xn0ApRwTxKB8eYeMeTPYlpmHdYAOGVqe3dAPJ9kXect7UPNO49edXXDW8c59l+VwSAGXSRIPWC1vBp/hFyYfOI2oO1qF0XiloGQrv69txOEG2PmXtvgz8Wj4UVm6zpeKhwcw/kdmqNBV6EAd4wu7ri2GlggsPU3vp85an6T0UVHXL/OxtJiLQWwrTpGOjaEAo7uCVA6F4KL8kKpsAIC/EPq3CBO2XJkylhWGGK+vbLH1QSzROeOoJQN/RmOUXveFYAkQxysQJi36XfXtBEcI0swK/nJPGsjje8+b8vZpoBlN98dW8t0Ns5PRfjyRuhRbCHYvN9Vvg6/5yuRQFHQPY0GArydv24Du0b4F4jYEfq1U/U0SqxKU2uOBEONQjr873NJVAjWVmM/TChAhjIgGPuIf1anSvWe/+3rCjs9E+YgrTU6fW9XKVinf/wF229mjENAXVsUPeekDSua6JWR3GoZ4n6L08jD57Z1GJDYvZpQC6OmiFbkwl0jZ1LVjqHPMMDtKd+gzj2TOLDHjEewcQLtTUws+fE0Z0A1j2oJOWR7ffPuRW86eGL7eT5croRguM1miNpTx3b7XjIY05QBx+cZfEW3dwauyynARfon3eYMJ1ywVqc+NeZ0uqVxtRhlXc+RD7Qt0rIu2irReEDQaz6Ruvi5GSWsNZSiAsJgNSMoBc6vIcU3vu0nUVZRIxQTZ2E6URcuRuWHR7xxtTZGl0FW7qPWYddIon/o93Y1kOj1tqKyGP3s1OghTd9vzmGKrbovd810tZXWyLrz4s1G3xf/GU9K7mYwUoXKtAOkbj26gosy2d7zXTU7ucfwn1XhZBThySCG6CjiRoCU7dPOBNwN3hcOcpagEr7UrxQQbiFwrVLSa5uy5t823DFb9iMAGkJ2H/IJZ05LeVDBC8cvgklwS7BEkMrU1nIcH0qUOhDN+PiCz74ePlbsdDCXpJ2XcfTk24dkzl05ZzDA==","layer_level":3},{"id":"d7a25826-a156-4b8d-b236-8414ec49a67d","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Fork Resolution and Consensus","description":"fork-resolution","prompt":"Develop detailed content for the Fork Resolution and Consensus system that maintains blockchain integrity and handles network partitions. Document the fork_database.hpp implementation including fork chain management, branch selection algorithms, and irreversible block determination. Explain the fork traversal mechanisms, common ancestor detection, and chain reorganization processes. Detail the block ID tracking, fork chain construction, and conflict resolution strategies. Cover the witness scheduling integration and how fork resolution affects block production. Document the API methods for fork detection, chain validation, and state recovery. Include examples of fork scenarios, resolution processes, and consensus mechanisms. Explain the relationship with the blockchain log and how forks are persisted and recovered. Address performance considerations for large fork chains and optimization strategies.","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":2,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/fork_database.hpp,libraries/chain/database.cpp,libraries/chain/fork_database.cpp,libraries/chain/include/graphene/chain/database.hpp,libraries/chain/hardfork.d/12.hf","gmt_create":"2026-03-03T07:29:58+04:00","gmt_modified":"2026-04-30T07:19:20.4603602+04:00","raw_data":"WikiEncrypted:LF5XH+WZjZXH77Oahqhu33D8kMc2V5EyZ5sCQJaB6AbkaftNweUtSuIUOV/O1ju0L84BXRl/rB6mkbN9lJNCBp8gKu1Js50cynDLXNwHl9v3CFjgeOELp0KEyNk7HrPoblpscxDGsnAxbjU6uksUs7O0u7cTueUtpnsEhZYzj9r8lfaBwvcIcwsEB01RRvdhbPL8qluO1DonMjYGtl/u/z+VLRoiv5ZgLMwPnvU4vbwacw4Nl4nBQckEhTWyx8PX4rDQbuccQQ4SXKLqidYPi4B4aeRXfSy+WFUfPBEwabGu6wVVdmAalq7QGFs5G+ZaOoCumfG8JuRmenUNe7txszLy+G3PmfSd2EFhv1fPAsgxkEoUXUhyP+z7mm4ZqZHngO6WzuankZHLSspID5TYCXK2ChsJXZ++8FElt7o7HDjd37v1fFddC0lfsoLHBo2wCqgork3ZG9kruihKJN9BwbnaWIb+n1+SMmDOqHTTn453SvDMygUtsCOUSqEa1AhSJk0jWGFDWYSGpQ7EU7XWK7FetNZJ+qZidr8PgtgwfY98yoTZ411hHRRarvmZEMRkUTDnN9IrC9No2dlAG/yvx5NsfeIBHnCn/U7Qct07ypbU9/Vc56PfP5052v9jhw5uDTosqJJi8eWJRYoZV98PnI+xoU49yM92VJVWYxQ6HJnRLAPWJxDEk5c2LVDjYGPDfurStuNYbY9IJoJh/BaYzQCCLMb4zcXk5eIeYMn7IWzZK2v7wdMGFeG1CcIFBYBaiqxNl5OLQT5u2w7HXFuPIEzcR1hEhhCdj8GQPCpxdn3RgNR1WJOHgJMyuW5jh3mnx9RvL1xvrXBwBnoR3gA6I3Stzg5XyQ7zXz7gfskdj6HhX3V+LMVWc6AlOk74vJQkl1myiZtzunWssa0DH37qbuf4+nzYxAnPGfza3YJoZ/GqFd5YIeIPGMLywZKEx2+VvXHpyuq2ScgROy3pjQmmJsm9Dg26FwlrjeOJ1fb7rKnJL7j6reeSTeBc7ZTcSXEnXZ8HjIWwkVj99LZny7So+qjVDhgPOS6OBiemWQ/g2e8/W50hkhBP6t2ABzLW1HOULcuXCZXDs9guIa4Sf4XMof+lgva60Oz+kyDOpoaqv/EPb5sQsWkexNIYBbKl1NAzTSa1r9zyXX2sCh0dOXq3oXndhsHwVxQXiQ9NwfJTv6d3pqPLe+DBvTRvbTz+32u7RyIBS2F+RU6rHxONYEp7nJhIzKy0TImWHvG4iHhpYG4hvzrpDelalgWFx853AUPJKMMx4zK98Wiuf2NaJTF7rNSQVvKWHaaplCqWXe1A0MmMj5fM/5wO3JXYJRuun2mfe3IFsT7/iG7Q//tOvdVOI8/jv4UES5afZD5xHcoQe82ZVIWWx21OOj23t4A2p12hkuMo6DpKhWf7jtKx7mCTnscAl6RgaLYhgPXPbiMnNKOqISmH5GMQ/1ILnpOv6Jpv4RFkpbSD4EfmRu29FRGRBe9dx7BhuN/Wz2s/330nfzmXKbqQl7Wb8Qw5XJHqzUbJTrpav5fF6MJS/DgPUBCwDvJXmylzy5D6wm5cMazm8qA34DJ693JnIZqLCcBSjsNXsH6kqMDU34FcaY4dny6gfvaL+ENE4gsnDFK6yBxMgii5o8O3N1e2trGlTb/XpbBhD/jKD/wWVawl5uXKu4NCTAJF58QsjWzcnfBjA2RdYbX+oKGlIULRwwNDb9mxuXV41Urm5L3JVcu/XH+3p/hJJBbfLA1FEHOfLJ/Mqsqx1MA/tYKRczvEjUoogvl+pF5S2ZnGmI9f+GzZjKfqG+dQKh/LvXSOsNm+oOTbeVR+0YfE4Gjs/h2zsxspTmJnuRjJIWEVAer2EDIONMeggSrN03WbpB/aEQxyCBF9/4ZbZlagUVsdBES+FAo29yFRsZZroH0N6p/NDFgdcYOM6i21E2pbBy8ndUcggR4zRwImib0vMDf3YLLqA1aRgLxNcIql","layer_level":3},{"id":"853c4d2b-809f-4ae0-9735-c14d174538d3","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Message Handling and Protocol","description":"message-handling","prompt":"Develop detailed content for Message Handling and Protocol that defines network communication standards and message processing. Document the core_messages.hpp implementation covering standard network message types including block_message, trx_message, and item_id structures. Explain message serialization, deserialization, and protocol compliance validation. Cover message routing, delivery guarantees, and message ordering mechanisms. Detail the message.hpp structure for generic message handling, payload encoding, and protocol versioning. Document message propagation tracking, duplicate detection, and message validation workflows. Include examples of message creation, transmission, and processing patterns. Address message compression, fragmentation handling, and protocol upgrade mechanisms. Provide guidance on implementing custom message types, message validation rules, and protocol extension points.","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","order":2,"progress_status":"completed","dependent_files":"libraries/network/include/graphene/network/core_messages.hpp,libraries/network/core_messages.cpp,libraries/network/include/graphene/network/message.hpp","gmt_create":"2026-03-03T07:30:03+04:00","gmt_modified":"2026-03-03T08:20:04+04:00","raw_data":"WikiEncrypted:IaaHBhg4aKVK2Z27STIpf61hPTwuvjJw00wghNRz0dqXZFnsx3+KXuJLymQNNBhm+4HmlhfiPgft+nBCx8lK4ljvr9u1N7eyZnhnwrufcfJWtCJmJAYdT6I/MbNWHUQIKT842G2JFoDfikSnGXpefzkqbmJ9h4HkLavoFO8GveAAfrmDKT8BrkB45sEUfJuABljdMo1Z4Po59a0a4om8B5rJ8OUxvmIemXI2d5efoKGKw5+cKGNGgMwYtApsVIFedpjM4uFtQnlachraAR2ooVuqRRO80ib4jrTSv6yeZ7H51ge5rgRDeYcFxsrJCoVdwdGWygXe8okjzamm+iH8qIoCmIeWbmGhMXfFlxEK/xb+wwY52MBM4YD0HCpQKrh+FO+ELHik/d6lsYRY9gPA/rOwZAD/lHaoyAvRfwGwxZBnI9v1hKYnBr3jkgYNLd2b4C+SN6V0q1D/J5y5JrGIEDD0UDlw9LcEozUbvr8SxlE/c3ssjyO70AP9AkWHy0n/edPKa7I1P8a5PI/LkoGgkbZsgmU2eWdzzRHPD+SAnRdp/wbF747R4uXmCN4zeoRvcIx7OcXyzlai1574JHXrHUXVa2PHa0w8B8126wMxdEQWP7//PnhsaFyMCTJtgGzzl4Z9itYmtAjL63fZhJ4/ulTh6nSVcAaG5zFsedHUkFowgbseLtQe/VZ/cnva8HtoTWZN1mFJ+RqQ9jfwt6LYrzEd2q3MirnV2jaYHYkcstr51bztnhXvUgkhWL+e3AELp6mphweylQexxr7cElbJkAXJKfxSoGgi6yrwn8HZrCLHucOZYM2oPk5hxPtgYidAWjD39B7q9sD5fd5HTpIbtXghy+Y0n03NfM1FVHHCxxjzfqjT2zJHMmFpwEg7TMxgVKXNzsaoXhfOVluWDB6boDg9qics2SnUgCnPjCrCaUfOL/+/3CYa+UyWEEKgG7CyS5/Y82EKHbZzSus9o4j4gANndEAiosEL3j2nl89R6zEhtRLCWEcaj2rvM5aHgTjhKovqUJXkKsmixnyt5qMgzbo5nsmiBjpOUlvVKwEBSXsLxENv+jTt+kgzsIbzy1Jp5xtzSiQhvHOoLZ30UfUSrf3lMZ6XwJ/uVJbfRPnkQxayMicktwKeQtCn4FChxyYZEp76MNcO23bGr0HXdcFwVB+V+6sOw35crzsrOX0G3Y5zxdwwg9AKekR1gVUEilUZk9axa+YC+9LJy7dzNX1rkOd7bVXWcUs1ZrGXwQEKkB1BPYhOsWZG44+DyxwIxnRp+jOUXNaPqE5EejlZDlomg7S1cOn4gOqSktzaWJjoGTILesnSEh2cL6x8Wy3fBDjYFWKF3L+PuCNh+pD4ChQBrf7ypQp+hBk8SvwZS7dp1cjzmzJZxVoJMDfb/TM4Earm3H0uHtPgyNB9Vtphl05jPHAf0f8vYuQ+s7cTaTyab/jpEqRdDzl6/cALbcywQ1V2aRNc0kPxcV2Zaopfp2UHzxC77e6+R15VG0KlBuF3PObzKl8w+w5wkN8x/18+NiQGljAIYuoslW70VeMMwUwo4fuB0U7f0r1Q9yeYVdIdFTT9y2SoL7yQgFs0wpWrAT5vjflJ7nPeIj9yMdKSOh6orsFq+PRqcVGaZPd+qVoghULPAqhBhvKqEe+2fuMItfkb1t/1K1HkFcu0s9KC8xYkZFFbClqzym72hHLhRXCU+9mTwqhkMHujFNlXu11k6j8K1Ep2jNU5J2M9v5RO91IEa0hRaKxJLDF8/SuYNgZoWdOIjPZxsoZyg1dmtaVoVp53","layer_level":3},{"id":"c8b8f71a-3ba6-4723-8e51-78c701b5b4ab","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Dependency Management","description":"dependency-management","prompt":"Create detailed dependency management documentation for VIZ CPP Node CMake configuration. Document Boost library configuration including required components (thread, date_time, system, filesystem, program_options, signals, serialization, chrono, unit_test_framework, context, locale, coroutine), static vs dynamic linking options, and version requirements (1.57+). Explain third-party dependency integration through subdirectories (appbase, chainbase, fc), OpenSSL configuration, and optional dependencies like MongoDB. Detail dependency resolution strategies, version compatibility matrices, and troubleshooting missing or incompatible dependencies. Include guidance for customizing dependency locations, handling corporate firewalls, and managing dependency updates across different platforms.","parent_id":"317287b2-3937-4876-97d0-a8c96007d95c","order":2,"progress_status":"completed","dependent_files":"CMakeLists.txt,plugins/mongo_db/include/graphene/plugins/mongo_db/mongo_db_types.hpp,plugins/witness_api/include/graphene/plugins/witness_api/plugin.hpp,thirdparty/CMakeLists.txt","gmt_create":"2026-03-03T07:30:07+04:00","gmt_modified":"2026-04-19T22:00:10+04:00","raw_data":"WikiEncrypted:Plae3AeD8kzvx5cS0SI01VxUgqb4buHXTzzTWj4gTygU7IDKBYr41L3/hTrS44leIMVa8ywMUh248ZyPirs+eIVofLm7+N0WlOX6fg0khoNhXtfGI1JGQ9weIgIVyjznsmVNtjh2fiQQu82cjIL5lPsNVUenQmG4sEvbSS9dpwJ3rEyNbj0zNlca/sosLrYifdoLBf6wi9rVRkw0R2HPbVqv1K62V8d2h1xVxhoD+mzciX08y+Y626vWX3TQ55XUKWPPezNHVOIkuhKKK/FvzNNEOWkkvBod7s12N1y5zsBJ7OnVtQ+te+Oraj1mZvD3yQNlf7OoLG+dWkEdXHOvf5CZFFffTB/IVrar9FXThN/I7Fc5spsivRhxmS2EtHqcjzaJttxdCdRQQ/BCFLgiPZjRjOfDJSF+XwX5s/wgAZIzXU8Fs+Q5CU2VClMl0ZBUMCFhbGkGobGoibrJW0gv+xCNWo9dvQy90S9DVkg2JHDWq6NQLU9/Ck03b6pCkb4oUVBlX+E2FjRHbbZRNMSRaaKp/+A0F3LfmijkIZtUidn2Ud5ssgcgnZ0xWqxULF0L7nK0uOpChFpQE37ofSZGu0ZYcgLBqoAqGM3z7FWLOT9QNFB2J2ghVFeM8ctDl15x5agpJ6c/n20KeYIQQ3YbyR1w7lEJ2DmAIJ115iDZOxh6T+la0Dxl1e6Z6gGg4R0x1BnYlD1RaeyHxnbcJpmmd25fYpjV0bwt8FMkic75TZmS6y1j4LbrrxRqsSAoq4YRuvS6ry5PgQBOPti5pLq1FtNs7nMTUGfERuRBF77QhfGS4zi95OM0MqSDSW1NNeL7hTmzhlbVNJzyRvgd/6gkuSoyWoccHQGp8IpMeJglYMcUS/1agV1WnMfkJO0IgyiMq03NBKaIDDyvY75Al1xdsUXFFSwS5PytKsQEt1WFbqNBe1dxZTAtRspq5I8JD5AAdK7DQWcjEZdeYgr305oWce1+VxuCkOHk7GIs2j/mFf2bY7c8pzqUhVQNYXfZFHuKet+VgRnEPP/FGnsPmbto4yg4y8H7RWaOD8tyi+e93Di9ifGP6c9XBzLRXZNceCcgqhEQP39gDKqBNFgCfEwmTexbqkDzoAB+uSkFe1g4ABb7klM7h/um1faCYTTD05mQgAcjQlUGu6Kig0OuvO20D/u2w+DkhZticFB7WdkEAMnzEA0J34GWtQjN08T/5j3K1NnlDCxAZQ7sS5MADnsU5FA5/ccz5ZPmHPTsUPPNcH+YLNVERxwyESTIBAfTgEhI0GVthOsevmZIAgvtZGLeT/vIFMhv5bywfq6/Ecu4Ns/AHG+gT0UXUg8r4Nqg8wgE94TVKAkBcthaCrkMgzh+dpgtkgf8dvur67TXqpUHdhuStZpvRlPhfA22RJm9XYNB7NZ+OLWCVxzmEwyncrvdieFuAP5kZs0IY6Fa7kvZ8E6kLTRwHvZU7BuMutV/73vTY4TiA15o0Z09KIRrbYRie/XkiK7Mo4Pe/2qhFQ/hqUvC0GpmyT3uQpk87+6XQO6TUzYuZvzO7fx8glSmEmJOBlIakoCXqY+heH5XcP4uAK0CrcjKNQt3n3/l3JDhZLXGtR4FSzfj7SswLAg5iSUJBG6KST3hab6DYHGqSrrJOHF7p6JnrWx6i2y6epIIluQQltuf6CtUp6ppPR+vZF+V2tnYisy6JXWohcO3wFw1jHbDq5UrBHWcXrEQaJCOA/OV","layer_level":3},{"id":"c387583c-6834-478f-acef-629c155068d6","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Low-Memory Dockerfile","description":"low-memory-dockerfile","prompt":"Create detailed documentation for the low-memory Dockerfile optimized for resource-constrained environments. Explain the LOW_MEMORY_NODE build option impact on memory usage, reduced functionality, and performance trade-offs. Document the minimal dependency requirements, optimized build process, and reduced feature set compared to production builds. Cover use cases for low-memory deployments including lightweight nodes, development environments, and edge computing scenarios. Include practical examples of building low-memory containers, resource monitoring, and performance optimization techniques. Address limitations of low-memory mode, supported operations, and migration paths to full-featured builds when resources allow.","parent_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","order":2,"progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-lowmem","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:20:43+04:00","raw_data":"WikiEncrypted:fKjMku8Fpv/b9ZP4Ul2Tm7Zca1h5FLirNykTI/AA7d47CnKOVNgTfrsa18b5sEdeunts328aDl/rj1iuGdoZlRmNliSHTyno4JbtoRql9rKHpIYLsGWMX9G2LUkeMbg5FlADbz3moUepTMX3AczHxUqbYB4AFqFyRp9NfIt2CAJxj+V+xIYQZNJxkd++ojQvXSYZIG5JstNLMOPkzDOBBMSmIkHlovPB1lMrLLJwFhzUpC1xCa+ND63Q5gMlN0G3yfjAIqOGUgrdT+ScVEXVikgbsMs2FR+Yf21LW0JY5SWTiW9asZnrbARtm1I0PBi1SwOnynvG4O70EZX9LRN9utgNzEKbQ/qb7A8SfVmVJ/5d2HzbGUMSHrkrOIOfbq7x+m5zQ+xeVa3ivGOz0zfrx0YS8ylBBcoxuQpJaKppYNws9zDTzNPyPKF6F8R0f1xEekSn/JYo8L8cTTlwORrSEVBL7LFIRgEWWaDNsVi/1O8gCAip4DBDZBQ2LPfC6P1QsUKasNlSO1mVC86ULrnACvyOlzdu4LgiRoNEiae/X7YYeJ27qk6miFPwfkqI74vrZqcB1SJtN1oM7wrhwKFiRe9nBzycLbwqgkO0CcPCTjuD4ODtK8fSqy3BoOB3//ZSvhyZGyn0R8gSDuAPdm+kh0/VZkaih+mXej8gh4sIMDIrJ2wnLHPiSUo0fHeGe7xvqvxBGfsukAs4x/6YobQGQrAcK8lvIiqbuv/zcWei0mxwkL+vtvgCGdgWdZNzVGlKpi+l0uM4+PmlnnUtI6E2ft7hMLxSRFFE0JCZJZibOiVittplbnVeb/JCKsBfBqhKT5ffxVvmAWmmz4FggTt3s6WiYfzMLbT5gs0JbLKyZw2fyzMJinM86Lsg4JoVDV2tEjnC5K+hG0CYL+/Hmdc06IdnAhagszBwJdg6UcIJmPbvVOGO5/yXMYF/PHJb4YEX0bYPFjmlxEiX2VH9mauNLPpt1jyCPGWgnZhyUwTWiQRTInuPux3MmvCBFIdhvbSqewELe+RCUR4kKk9YJS5GXYeZdik3EX7M9JK4p5q0/MxMgt4QtVQ/rYH/5oOzinNpJ6a6qM5G1yQe+AJJiNnMmCPHHNOzcC312TKra6dD7p85Thyog4vHQujObntWLiTnTOyNOJ4xY0pNqOZCXC/Q5ZorjBo1XHSB1Lp0wSdJAtzg644h4eKUjh85lW+FjpNYTVSH3dYhbW8ZQbhBhB1LSTXLsLYMDwhUlV29PLoAS5L+j2tTI5azUAjxI33HBbuYkzHJcOVoz9ZwiNPX/8aOHvoacoHQ3sNu0ZTYwXCfQcn/qQWFY79o04+IJ6ojQPjfOL9PxdOR+3+FXk7ksofNnnVe5/+jF7ZkrgbI13Bg2V2aDwse9dsZ8pT2WIlIDimfa+o8woVUK9ZsEODSEH7BfQ==","layer_level":3},{"id":"85a56025-1d98-4b60-bea6-dc4fe9dd9336","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Plugin Development Tools","description":"plugin-development-tools","prompt":"Create comprehensive documentation for the VIZ CPP Node plugin development tool (newplugin.py). Document the template system for generating custom plugin boilerplate code, including directory structure generation, header file creation, and implementation skeleton templates. Explain the plugin naming conventions, file organization patterns, and integration requirements. Include step-by-step examples of creating new plugins using the template system, modifying generated code, and integrating plugins into the main application. Cover command-line options, customization parameters, and best practices for plugin development. Address common plugin development pitfalls, testing strategies, and deployment considerations.","parent_id":"d54afe72-4975-48c8-b825-ab792ce92a46","order":2,"progress_status":"completed","dependent_files":"programs/build_helpers/newplugin.py","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:21:29+04:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BNh0I4BWUQUUZnzOP1DB+1vlRoA2DnNNT/bHeFbdtIQSXyk7bUmdFD+AFhUw6F/GhxiiRn+hzkKtze7IIl7cKG/KiTWWAdasY0S/sUREmQTHx6fByz16NvdAO9bhp/o5Zn/mUi/wb3p4250DKByWWZfNOfNXVv2JlV04ypM3wlrlGWlbJ7X8Fy6U0pHiMDV7TSm1MqZ7jRntlHQPGcOntBT/sCsvcMG+2Tz+AhYuUPl5S8hp4VL5aF0Bldz2wMa/U1pJc7TfQFlMxB86sCIBeKzByisy5hcvzrvj4EnFi6GPdH6XeSu/FRtSiNKuU/+BLK4e+xVb299e30vgCpN+yGzMnQSwF6Hl+jcihMZsXvgHDNEI/RrCXZvssPbZrT7sDQLng4yvFg/DbS5ctr/s3st4H4yLiUYjxEqDeeDZJmUsl/gOzg5Npf6VYtyLMLyH9njN3FYygMBEItIWHS/ZMH1W3KPMaE+jELwWFWfW6x3luX1FV+5NfTiGDUZFr5zbOv1nTesTTLLSp0JnpHFC0GvbajAQrZqALmujKNhlB5TCYT05Flf0GcmXhPEou3sfRmVyejF6URcCf/d5kBLMvqRSdfpnl/N03KHaPxYZINuPHBIAvP6NhDUCR/fUp24M1VUaRdEYxuTA0xVGT4B/mJFB1GcM4+9oL3v5BAIoblxDFG0ot39YIWDKAEZJP+FvRnZW7pXYJeHiWSk0qtIKgtaISPvLuJjnsI/dT0oSS3xkL0kd2kYI0vsYF4O+AsB9t2ee1KQCgIm5wS/fpF5ZD6AzqEaVt4Bz7TefBcReXAJpcG3vuPU+gLWvuzjT41eG5LOaY9P3Xn7wAvALCYsFE0vfSh8VR6967R/tPj5malqd3ZlHC0dxWpbxK5zylOGQO4uxR11qWEo2wh0pDE9wImO0X1phGa0q8u9QH0mjXEQ/tKnVJMfCy44Ur4SoVgKhfwCVtzuOaQWJzffT2DQN0zbuTBYBWTCrq9HAR6vNZmH2Z3sEpQgc/+ZJvLWTGHYGzSkGBjeIvPAFT7j3+lGMmHjVnT2E1QbymYUm4bNV6N4jm82YWThsJ9rkZtizBTQnTkbtEeW/TDXtJESiADfebLTnRZTZl7I7WM5mLPsPhlwYWa5D4Ll1vbKBq3TOCFjt7mBHIGiV3sS8VL+r86dHiM5y9zVYhoVkQ6dZnGqT8NcjOrRqF4ysAeIFLlMfihEvI3KCXAR61jbN/0bv2w9K/DcKSf6l2e7fFEfrdNx9kXLwfiDmsII0LnZpIxwKudn1vbk74LhTEW8Cuq4YGMH2AKTpMPt3FKdP/7CGNTpSK6QxHL6TtvmZv+gP7Z3wdC5jd0QjQlu4NnBFMWzpn/9HWmVn0GOavzxl77UxMoNg+Zc3VHivV1ARsjNAEidCVxhg4Mnb7xQ2/trOZlh0kCHFa/M=","layer_level":3},{"id":"63eb59b9-96cb-4c76-82c1-93eb29f163f1","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"NTP Synchronization System","description":"ntp-synchronization-system","parent_id":"7e383bdb-11dd-48d6-bd47-4d350e2df438","order":2,"progress_status":"completed","dependent_files":"libraries/time/time.cpp,libraries/time/include/graphene/time/time.hpp,plugins/witness/witness.cpp","gmt_create":"2026-04-21T15:57:29+04:00","gmt_modified":"2026-04-21T16:27:59+04:00","raw_data":"WikiEncrypted:kk2p6A+hTfq/j31wt7MAgu7PjcLqcqeJIlT11ZAX6rG6RFTstxzezqPewwuq7KJcZnmxN+1kb78oCoyll71+CuHlqFqb2IInJOarRp3GUu1hTuhP5Ph9c12xZHHA3N9Y6gkfFTURztr6jAT6LxmiaTH7GJAiS5z7eF8RNHQWKef/m7HHGsZr01TaIMaqh33KDw6kzrqzxNeZDzLMbyh/x9737bQIhT5RB3tSN8g6hBmfRWfk8EkMtWVf4AcsDkhJOGA2ZXZbKc+Ey4I2k6wZGpgW1sM4jfqwCC5VX8Nk9VocnoDSGLfxgLh/xYV2SF27P7AOCsOaBBGjXqSvStzw1Q==","layer_level":1},{"id":"024bd7a9-84dc-4534-95b8-96539a35367f","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Witness Guard Plugin","description":"witness-guard-plugin","parent_id":"ad096386-ea33-44d1-b9f2-261f11fb24d5","order":2,"progress_status":"completed","dependent_files":"plugins/witness_guard/witness_guard.cpp,plugins/witness_guard/include/graphene/plugins/witness_guard/witness_guard.hpp,plugins/witness_guard/CMakeLists.txt","gmt_create":"2026-04-28T10:02:33.2744641+04:00","gmt_modified":"2026-04-28T10:05:06.7184647+04:00","raw_data":"WikiEncrypted:JeTXIs+pfWQp8HpBYqSHUv6FCVRIRaRMz3xNyEW8d7EhJ4Yb9uJTUDwZy779+JnAHj6NWz8b3Oo5/W9JMIZSMgRD5r6w4EIzwRavY8e4kc1XIH0/yLqyECkYwILkFMHI6V10KB1Xjt96X5Zn/owwRdxlFryES/SODzx2FYuKNSOxkz61rrs8q6Bf2bO4pyez/nGB2SjYTQ0sovrctzO9ILXRIu2ubT2B3BO/ZNolrExOtyi+g6pNHHCc+XRtdL5oNM/GlH21Guyo9bb6wJCyeb88zRhRrD1IyzVpjB9sRliZPsCuVxOEd8G6iJ0lmAq5X/k3RcDg/u/W0yo7Z+MelrFVPO6wsgdDN6w43cTegfCA4phNf9uFNCL4ym6V2JCrbx89vANIrBfGDu8lobaaew==","layer_level":1},{"id":"7e383bdb-11dd-48d6-bd47-4d350e2df438","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Core Libraries","description":"core-libraries","prompt":"Create comprehensive documentation for the VIZ CPP Node core libraries section. Explain the purpose and relationships between the four main library categories: chain library for blockchain state management and validation, protocol library for transaction and operation definitions, network library for peer-to-peer communication, and wallet library for transaction signing and key management. Document how these libraries interact to form the foundation of the blockchain node. Include both conceptual overviews for beginners understanding blockchain architecture and technical implementation details for experienced developers working with the codebase. Use terminology consistent with the VIZ codebase. Provide practical examples demonstrating how different library components work together in typical blockchain operations like transaction processing and block validation. Document public interfaces, key classes, and their responsibilities within the overall system architecture.","order":3,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/network/node.cpp,libraries/network/include/graphene/network/peer_connection.hpp,libraries/chain/include/graphene/chain/db_with.hpp,libraries/wallet/include/graphene/wallet/wallet.hpp,libraries/wallet/wallet.cpp,libraries/chain/,libraries/protocol/,libraries/network/,libraries/wallet/,libraries/api/","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-04-19T22:31:11+04:00","raw_data":"WikiEncrypted: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"},{"id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Data Flow and Processing","description":"data-flow","prompt":"Create detailed documentation for data flow and processing patterns throughout the VIZ node. Explain the complete data flow from incoming JSON-RPC requests through plugin validation, operation processing, state application, and response generation. Document the transaction processing pipeline including validation, authority checking, state application, and fork resolution. Include block processing flow showing how blocks are validated, processed, and integrated into the blockchain. Explain the observer pattern implementation for event-driven architecture and how signals/slots enable decoupled communication between components. Document the data persistence mechanisms, including how state changes are applied to the database and how fork resolution works. Address performance considerations, caching strategies, and optimization techniques used throughout the data processing pipeline.","parent_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","order":3,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/protocol/transaction.cpp,plugins/database_api/api.cpp,libraries/network/node.cpp","gmt_create":"2026-03-03T07:28:18+04:00","gmt_modified":"2026-03-03T07:48:50+04:00","raw_data":"WikiEncrypted:PGdHQOrMWxh6s6galmzx60G4c66k6IPhWJyX8d8v0xn2Sl7SJvUGzCeuElhJ4SjnW1f5q1x3OM20oMAyLozbgKnw1geq3fLXvsMfIZaJytjp20ZVI2wKYo7M9ca6xvMqmvLCoFjV2Z0kELRuZLvDkmrlYmvgiiF44ET+JaQD3Tg6UnMB2AfY+GkjGaMezQa+OwIe8+/2009s6DSnQ122sSDAASlZ4rQAQgkeL7LK6gVM4lYmwTx7H0FRKgvN56jg92nJt8Q9ssKuyC3PnuMRtdmLRDD9GHl1UjneLNj58vnJAWszzHCQBtNk3VjHNP0deezRuhtgxwC+tewqd/JQSDdmqyXoyJE348rcbGaYl3xaUS1p7UrDoI32vDeIvbkTHgU7k5h+7g9gk3haKfN9RTzmsbqoL4b717U38BLqEOT3exi9WZkIorQW0NF5G6m0x9Q0Tj3SFO79eAxNuomk15MhXHBdLOea8nqT47FcO/+tqaorLLAUsGEH+NKXmbsnYD8mN6BS9AiVn3+3XJh5WvCSNOMqv2BkONJycxEao4fPiJe3Skv/lMqF2C5EGRNx5VUDJCHu5QSu7iNcehn6sFKJz7hJ1MvCwwEmlcnZTHZdCnSBWIGwj45ejQABCG69LOiZAmidK5KSRBFFqPcIEBWLz8Gjz8nSvvj/YOWHvnBGrJhJx7RWwwBisYRsAy8Z5cW61f+KRnOeiEN/pAz0CVwH/qCZ82Xoa3zbJhxDnVobI/YZxB38kzyIhZzD5f3TmRsWdYpru9hzJFPh4gEZUpsJG6MybcNpBh1TM2pH6c74FIjPfAU7ZiWVr0OrgabTZ7XlHJ7+uB2xNr3k8VzkQVf/V1AHJd8L5ZyI0pt4Dp9E0Op0q76xdp5vQHjmpfTZlnsM9Rjo/49Hsvs8G6a3fnlXts9G3Z+xo853HjLZVtYt2WD+9vjO7shN4ANJp6vwD1LpJWWEZMsRZT78kU0yIH7hAENi2GDclKPltKOA6xqDqNuz9cCyWGu/8JeX+SH00trq7Usn6zm+KCEs27c/T/YH/t93FMy7TOSXt3czenAk2eo5Y0Dwkfg76ikGVoLpj3QrHxmeFx/MCun8RXKjooErmweSQ0xhlAfNLUGdhsWcjsQQoA/g6jyIIfyVzl2FxuT86yu0Lyx13sc7HSif55cl1n3VweLstcitlhCQxCXHY1XnzOEuvylz+3+gqE81pk+e/EtYVpCOAnImJV56kOfkVIPHWVXQT/GazHgAtiW8XjD6WTHkeY/+kVBRMra0MvIz57qKdAw+zFgMJ3LXK+SybRY5ANWjt5RA4Un4tPdsOSE8XBkhZz1UFPkW8dtXySJd9Byr1XKqgUI1u/e7477TafcC/BWJNjeUIcIs4Kcjn+tzA1/wqJ4ImMm97/9cgv4QoDcxTPvZMEWmAKgYbjCsq5JuTsGWZeUd4gLTRYNdZMfeywZ1gARhSkt/BswMFAZFgL7DVbDgy7m3lvEz9l/U2i5ea7PWJv/KkYnXxer6DthsXvkHn+CEoQ7h1S9z3RNXMYEE8kZ+GOhOJib9twOdHelHqFefxCAoJQz7dJL8o9cmHq0Fr2WSTuKvcAvfX8iUnrtB1ur55PFh1Ub21t5HcA+Ofm44YsMlcT+G2k6lZsQpZP0Shrhe2kxei7508e065lBusZAeDpXsqIBC1BdRcJ3quwypSsS4SJyHeLaz4PHY9ubLEL+opj3D8JWdurRx8fFnB2+u1EiFth365AXKQR4baz4MaYaGxaJ4bBc/KzURVnTSI1Ysbh5eQQKGjFu4a7r/0sEw0E8tlDp5iw==","layer_level":1},{"id":"9091fce8-eb05-4150-ae9b-eaeb0c47be15","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Development Workflow","description":"development-workflow","prompt":"Create detailed development workflow documentation for VIZ CPP Node contributors. Document the complete development lifecycle including code style guidelines, commit conventions, and pull request processes. Explain the plugin development workflow with step-by-step instructions for creating new plugins using newplugin.py template. Cover the continuous integration pipeline including GitHub Actions workflows for Docker builds and PR validation. Document code review processes, testing requirements, and merge criteria. Include practical examples of common development tasks such as implementing new features, fixing bugs, and contributing to existing plugins. Address collaboration workflows, issue tracking, and community contribution guidelines. Explain the relationship between development workflow and project quality assurance processes.","parent_id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","order":3,"progress_status":"completed","dependent_files":"documentation/git_guildelines.md,documentation/plugin.md,programs/util/newplugin.py,.github/workflows/","gmt_create":"2026-03-03T07:28:48+04:00","gmt_modified":"2026-03-03T07:48:38+04:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9Czfqaqo1gAmvHQcnSrNK3einUABLsSCloeGqrP6SdFS0zUakxLmRPUL6anlMllMDgmHCVMwT8sIbysAIHx8JwrceyMEVF9jQwUjTwXD4s9NR4xgxKzXDc6kzbarmc9U+I7QQ6PZsut89UqaRJ7ar623bftYj5EwgQxqvsLRcwVfKV/GDfEbJvOx2RY0h10Nbi1ODoLjCS1a617p4rv2Iuw+QlFBTN3bmkQ9FyJFFXkeU6zioiIpZbTVr39I8w+pf7id6L62D5ahg3Sxu5w3gY0HAQQGF9oVGSLzbV+dZEmr1joErJDxyHbfMpfuezubZWCOgDG49Aof5eboZkk/SPpgjRi4M0a/mzKg/BRs7MpKzy/seiCgyAEt7WFrQBP8po2VCMsE8tmwdkEYqZhwOFfazX1BfT2MEuTraZqrmlBor5pAQBdGGNQBVYQZ5F9b7p1mOQi96BKtAJzwIF4yQbDWsMLjyOqNW1VbY+AEdzGIdpOtJcZ/ezOewZFB0CAxzTZn9jedFm4R0/EaGgUKtagaFLpsZVWMpLLJFKJL94sSD90ZgUL6pvllyCBGwJF5ZAc6C5RJItknfvpDXf8P//GfNSBU3cIekE6P9WvnDJ7vNbiiaebgB9yzvndzyfErDJYAfRS3pTWc10SMJgiCgJit91QYWrHn2YbE0TIJPscpsJlY9ZDlEgVddWTwDN0CILLrVgeo0dHqTmuZ8JCRzhPnmKCf3r7hhS4UygeyVVCiF7sipxKs7+UW1Ey6q/i9WsoMfxYKPq63OQvAHrC5JmwqPlsy/Gq3QRC6mUrV4VHLn9g0Pb3wCJ2mU2OMpeREGJYLG7Zil6byLQnUaizfbcHKvFHDttTZUv2WfTgR6bLn9YmUZSFJSa+TBeZwAlo4hG+6MGG/VFIjxefd2g2n++kcYYStotMRc6zes+8ETT24eEE9KnOIgVA7rJHZmNINWkVe7GcxVS2FyXSlUKpqUcNJuYSFAncE/z3hBt4KjtCR8G/CFD4TX3Qt8p+jf5Ad/3gWDzSc0muCo3MSPPdKzqHctqlAyCEre8hKBkeDfiIlYmWJydUB4T8W0aidx3rH16Hs+ALMWQbzbcBDzqsTHmX33HJ0XHIsJNU2YLv+tM1H9CINXNugBwsZVPtXNXQtMimhOR8IWZw3eclJFGlj23v4ySOWPaRPZ4WjElIyX6qr8bWJOWUdqS3wQ2Kw5YktLlPIzYysaSz4gOrSQ6e2kDUoxWzVBnCCUKXdCEfz+AGX9lSZ76q3xDqR6guzHVn+UXNeJnsmIfpMojA5pRRlfBI3VVQYAG97vcP8526sIxC22bje3znqoS9qGoIkRvUE/0by54fSl5XDvrTL8N7W/ON6kSF1NrBtVdbub5iOzEa68DQ6OLb+jrYG08YJxKCFScRgMyPjf6j87PPUCNyD62IUxlpWHRGbGgbPgmvcBvXCaQYbDpSRbHJrZv8uU3k61iYKBXRKJJ+XuK/vo72kwYD3Pj9g4xbFg4rew7d45+7HcQ+4DVdreCL0nS5Jw6tg8B0vDBUcd1yK+AY5X3FjSzRcOWMgBuxhJHSNMfscJaNhaCo9FMJxPI0KzO7jb6tA2GYmGb0LBkC2CcYsC6RGvbRz8k7DfoZxCuYsKhk9O/9G7Rx25G53/ucfGAGAQPEwbnNKoI9+Cww5kGlGFpFH1LMbp+ocM8gY6L6QCNn1lbmq8d04vYBAIS2u8GpBrclT6KmzCaEt2ITFE/OynfHFEcSSVPfpJcdOt9uqhZoJxDKFpMmYeygJKvUZ/2shGth4vwCgZdNxWmqAbsuQfehG26Wky1OM+HLWqoJ1DD8EMex2O11DLlfy/DgKt2GHmnTNVsEGzKKdVClEbTg/Uyz2iVX0ZpjcVeWls+x+ARJo/dDtomMmVxdkV8LGrM34LL8mplho4RDDmZqdbvHWQTWRY0tJoxHIEOEGtZZmsfPSfy7GyQh+5mYMG7NrCZN5p91ySgs4/CxMg+pEypi+0XZF0hfXhNkSqvc/qIfI0xsbCv/h6xs00c8s1cWeObSWfAfnsh87fVBy/x/dt9LAtINtEjdJOofVFxKHXKCD0WH0MJixAFe87/fdaQ5qT/A6ZYiO5uWaYT7wW/rPqC5dHo5x3RJE91YAkHlVUVNTK+MMs2bk7","layer_level":1},{"id":"b52a3e7c-7bc9-46ea-afb3-610c7430eb21","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Network Configuration","description":"network-configuration","prompt":"Create detailed network configuration documentation for VIZ CPP Node peer-to-peer networking. Document peer connection settings, seed node configuration, and network discovery mechanisms. Explain listen address configuration, port settings, and firewall requirements for different deployment scenarios. Cover network security settings including TLS configuration, authentication requirements, and connection limits. Document network performance tuning parameters, bandwidth management, and connection quality metrics. Include practical examples of network setup for different environments including private networks, testnets, and public mainnet deployments. Address network troubleshooting including connection issues, latency problems, and peer discovery failures. Provide guidance on network monitoring, bandwidth optimization, and scaling considerations for high-traffic deployments.","parent_id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","order":3,"progress_status":"completed","dependent_files":"share/vizd/config/config.ini,share/vizd/config/config_debug.ini,share/vizd/config/config_mongo.ini,share/vizd/config/config_stock_exchange.ini,share/vizd/config/config_testnet.ini,share/vizd/config/config_witness.ini,plugins/chain/plugin.cpp,plugins/snapshot/plugin.cpp,share/vizd/vizd.sh,share/vizd/seednodes,share/vizd/seednodes_empty,libraries/network/include/graphene/network/config.hpp","gmt_create":"2026-03-03T07:28:57+04:00","gmt_modified":"2026-04-23T12:16:49+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"bf5ec7d7-d376-4b39-8781-5b76b3e90e2b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Monitoring and Maintenance","description":"monitoring-maintenance","prompt":"Create comprehensive monitoring and maintenance documentation for VIZ CPP Node operations. Document health check endpoints, performance metrics collection, and system monitoring integration with tools like Prometheus, Grafana, and ELK stack. Cover log management strategies, log rotation, centralized logging, and log analysis procedures. Explain database maintenance tasks including compaction, optimization, and backup verification procedures. Document performance monitoring including CPU, memory, disk I/O, and network utilization tracking. Include proactive maintenance procedures such as regular updates, security patches, and configuration audits. Address incident response procedures, troubleshooting methodologies, and escalation workflows. Document capacity planning, growth forecasting, and resource optimization strategies. Provide automated maintenance scripts, monitoring dashboards, and alerting configurations for operational efficiency.","parent_id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","order":3,"progress_status":"completed","dependent_files":"plugins/p2p/p2p_plugin.cpp,share/vizd/config/config.ini,plugins/debug_node/,documentation/debug_node_plugin.md","gmt_create":"2026-03-03T07:29:04+04:00","gmt_modified":"2026-04-21T15:57:29+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"95b482d0-a7d5-4c95-92a5-19cfbe2967d6","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Plugin API Design Patterns","description":"plugin-api-patterns","prompt":"Develop detailed content for plugin API design patterns and best practices. Thoroughly explain how plugins access and interact with the blockchain database through the chainbase framework. Document the database access patterns including find, get, and index operations demonstrated in the chain plugin API. Include concrete examples of how plugins implement CRUD operations on blockchain objects. Explain the plugin API surface design principles and how to create clean, maintainable plugin interfaces. Detail the template-based database access patterns used throughout the codebase for type-safe object operations. Document error handling strategies, exception management, and data validation within plugin APIs. Address performance considerations in plugin database access and optimization techniques. Include practical examples of plugin API usage patterns and integration with other system components.","parent_id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","order":3,"progress_status":"completed","dependent_files":"plugins/chain/include/graphene/plugins/chain/plugin.hpp,plugins/database_api/include/graphene/plugins/database_api/plugin.hpp,libraries/chain/include/graphene/chain/database.hpp","gmt_create":"2026-03-03T07:29:09+04:00","gmt_modified":"2026-03-03T08:05:51+04:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BLgnn7JYGqI+7BDGQTVnjuRHRVrSL6tQDGezspM53gdtUsm79POkhFGbMKDAc/J73KOr8fv9yxwFP0VoRuKhzfwxYc3cuTurCXWgzU9qD33UyKcWZq5jbu8gui6I3BI09h3x8uoako0lZEJvMc987YbO8DFIAMI186UTX0GSkXJAiB+0tTnW0lK7Q7CyvzRlnJ4uvexA1xc+EZhQapFn0hFfn3BkqPvnFiPnhpszja3qVmCu0yxr5AX+OzkI9YrEHhMjnuc8KfaQdW9VHAia2WrQVVakOkiPAtBRLXw1SRpQtkxf6KrABOJaLawhkAo48bB2LOZHqAGu3tOxNEc72vQZfevNODQw/4xudcgAahRGx6P8V5QbfRG+7ZOzoOWphjKBaflPa3rNxq8WGsAT/7iITXZlKmwpq3pzl7blf9ohNDJ10/MGhxEznX6QxuFW4DthLR5kVo5FMpMbegc2qceJcr7rDsOVLLMyn4iJu3UaiybcuK+TNOvl/9FepZrihUrm7Rs1ztzDJ4QcscsNs+neY94/12m5K8AL6Mu2NzlcGwModzUdwsbItYtpPbN3vRWm+Nz4rmPUAYuKtui4c9vNm4avqaez3/tk9hTuof0mO/Pm7zStNDgQyzxVojbY3EL8rrMEPcI/D3OSAaUkUGRG2fLtZsmL+d/ZPTlIBTsNmlndMfEYTDrKr5E+W+3IRTPIKlzPWVBGmWGxi7haFJl2kgSpHJNyeh0Eo+8iETSeKxxu2TDgSHUkuYIg3HEGgdvgYIr1qGaupyRUtoY/q5EFKf5BRPbM5yv+gz+JC83OqEu+q80SULYKezoBiEdC5INZXHTv6NQVWGEl+8cCqdbUhMXEry7NmKGDeMJk5zVvI7BNCOTSguxS0P3q8tOjLfGnCxbOsLD8pxYvoN/z/twkUIVYuDYD322POm0xjzJ4AlPQArTp0rc4KlmH4w85aBBZ/nQ+fE49ONoyT3SW+Cp0lP0zVFHQPxLCqiO0CyKyNngE9HLAHdlN06IdGeLydDYg6DPV12HBIEV76AMcRaUL/CEr8dMWl2JhqmOYzIcZ54x/28IVV6uLzeZqSeBF86UMoiqp9mlO53qdRZ389i6a43ExR/fsho0biQmT1pYOg2z+Bs4JH/7havhY3tRk5/juh8+qSjyoYYJPDsqohP+9mGFBGc1L7BHbT6vyiZ9TjHmRwy+EnJSkDz/glriYfUpFIaSLN57bLnu+/sljxE/9WpEvw78No8/Rg/u5o0zhUxaSohbQRyrtjDWxh+2oFpvfLxStjsxVLZN+WS79BCIEnYef+pRZS/FzWgoaufxJaHm59yNZZYUdUB5rqxr8ex2ShwGoxeOaNmHsdrwGJ8/1m+Vg3BIlGtSTACH+Yt91iRdU2djDMu3OjKI7UKic90Ym6lDwCsnSjtgRZFxOa2+iYkqh87X0eA2XH4fcVs5dZv1zzPVTLYPu7ASfJWHRQQnPxabds2CqBynETnz4ROkyvaSshSNuqU3j0juF0GxFpyUNzVeHf5innJ7jt+muwMjOeff+m8cKbx//GFVgPhrp+2SM89QoZShNDkyyy9BlP71G4v5udRQgl7xC4qFX3ukbL1gg7nD9AT9bEcj4e4FwzePHvt633V7icBSGr0pCiDbBVwZEsmQvAuR8I+Pk8cIPh9trrznEmV1qLVkcEN/a1Rd3RANeS1yOnW2kVHHkpx+vQQWHnTzGpWTeMe7iVK02bsiYRcPro0nLDjwy+huJfeJA0v6pQciFTorypRWxbHa44CcnT9pJNzwdIwj6Qw==","layer_level":2},{"id":"30dbc846-1f3e-44d5-a93a-988c973d064f","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Advanced Plugin Development","description":"advanced-plugin-development","prompt":"Create advanced plugin development documentation for VIZ CPP Node. Document custom plugin creation workflows including plugin architecture patterns, lifecycle management, and integration with the core system. Explain advanced plugin development techniques including custom evaluators, database object extensions, and inter-plugin communication patterns. Cover the plugin testing framework including unit testing strategies, integration testing approaches, and automated testing procedures. Detail advanced plugin features including custom API endpoints, real-time event handling, and asynchronous processing. Document plugin performance optimization techniques including memory management, caching strategies, and resource utilization. Include practical examples of developing complex plugins such as custom validators, specialized APIs, and system integrations. Address plugin deployment and distribution including packaging, installation procedures, and dependency management. Provide guidance on plugin debugging, profiling, and troubleshooting advanced issues.","parent_id":"7a20b53f-0b97-40ec-a630-7e9171a04006","order":3,"progress_status":"completed","dependent_files":"plugins/test_api/,documentation/plugin.md,plugins/chain/include/graphene/plugins/chain/plugin.hpp","gmt_create":"2026-03-03T07:29:10+04:00","gmt_modified":"2026-03-03T07:50:18+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"e61981dc-5f45-433d-aff8-b4a293795e7e","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Event-Driven Communication Patterns","description":"event-driven-architecture","prompt":"Document the event-driven architecture and observer pattern implementation throughout the VIZ node. Explain how signals/slots enable decoupled communication between plugins and components. Detail the operation notification system and how state changes trigger event propagation. Document the plugin communication mechanisms and inter-component messaging patterns. Explain the role of Boost.Signals2 in managing event subscriptions and callback registration. Include examples of common event patterns like account updates, transaction confirmations, and block notifications. Address performance implications of event-driven architecture and optimization strategies for high-frequency events.","parent_id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","order":3,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/chain/operation_notification.cpp,libraries/network/node.cpp,plugins/database_api/state.cpp","gmt_create":"2026-03-03T07:29:21+04:00","gmt_modified":"2026-03-03T08:05:24+04:00","raw_data":"WikiEncrypted:W27BoG2tWSBKbrlfVNVQ+n30XbiFQ0QQI5a6lxogiBPjTg0DvvbBFVxLISoEha9gga8YkbF6lz5DhmIKlkxVqSrOPfvwP98GUOj8LffovPN0x6FVjem0YCS83Npx+6Ibzq2LUJxesBU+qAtPQEe1+kgERFazI8jpVPIEA5SAQs6E+tVyMbrp+izzDgE1An3BkZcmd8WlOiKBTXmO+BX9+gxzlWar87g9CugYmsBzcZwUUzG+TnbkVV8m9VyiERgc7YdTtwBSORP6zbFpLpqimwCl1WGfM2iPx3fmKl9ID7Vqcg9sjWHFHETcAef3vIQcCHn5ZwelrdlGWmjuugEqhEclWt6FQ+85c+7FlrVA/SJEkPHl21tbyLcXRo59nelJ479auS1kaMRkIAbbLLJFA89pTxBHLTh6UpmQfi/PnJX0FHKAQG4cCXDLpbng3u9V4jiScS+kPZDrvwbi0pxVlN3BoDGiYiup5naQqix6syTGND3DBn7DrrN97NOWB6As3M2nXHR2NvXMUoEN1DnpOIMbilF3IRve9B+8ZJCp0RU5fbFQjy1qD+s++dLoQP21N1/cjEFHD1iF0WYvAaqrRk/uDYDHno+tqeQ/mx+ZPbJqVfsvxIMdcTs+jDXnczvtHH+oOzAEz+66ridRpqISPDgcfO2cbHbD8yChkTSvPCRZdWYhTuPGD9FMpDyd0jIjtOB3xxYvHoZkAxGV+nMX9hasGMIF7kwGkhH9rmrYSGjPP7cDfNwTwu/FBc32a47b3jkk6hpJjVqUgKaUQwVLAljvp0rQBygK/1ZzcxVW+BIMsTioFS1YT3txI6Yht/fkrclLUxfXo4emNwybErlc27SOgQsen8u8XVq6ec0ymghCmX2GNpzdyBcoGHndxCnjXNjuytqWC148K/gEYnD8uMDDFR/FDCpTamlo9TnjmLOonJ+/0ajAF3YrxiqACGbHvCrJ4G+yuWD0h8hICR+5PP8s+bFUs/yKn7d9kaDv15PD1TKsDYh9+8aUEFoagYbWqdVUqdoaRVqqeuMH776Y5FkUXnii32wBY7HhXZLhzZSyp1xuekmM7J84yOOK2tBopwNQRS686YPC8+JftwhlJCmWcc0+mYaWoDpSZu4qYzYc84zrabiZWOKq7wECSRjNq1So/eOnTsS8aflZfO3NPSmfrPeog/Q5TzrA9SAmy+fQSmJFuZG2EpQmwndvbB6e6NcyddF6eHMQSXFsIQmzRkclcjFw5DWeX1BZU8uYADfXYb9MLMIiQFqfi7uQoiSiLvJ1KCqNhvLB6OVclq+W/oceE/acm/1XZZ8ivi1Qou4VtLQe1CWJECh3sTOOdIZyP0UWlmqWmT9BUQBQ1G6l5wGdjTmUEhh/r1xHfJHHYuzX2Wgc+JRQIS8LKGWlyVGcRi8l44kHDiM9Clhn2uGn4nL7baAM0wRSOGz/zGx0WsDBvGqL0nVkDgCZJdy0t2Y8WCG0Dfft57uM5GvoSFZ6MOzhOe0koPbRUZA9gA8yNzup8ltl7rocXAO12CAW7XD3rCUxhffjjXddeBpSijY8cpDxEylvPQnGr4rJuIbCjuM=","layer_level":2},{"id":"48f0ee63-f542-40b7-bddc-5746b9b949c8","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Wallet Library","description":"wallet-library","prompt":"Create comprehensive content for the Wallet Library that provides transaction signing capabilities and wallet management functionality. Document the wallet.hpp implementation for wallet state management, key storage, and transaction building. Explain the remote_node_api.hpp for connecting to remote blockchain nodes and delegating transaction signing. Detail the API documentation system for exposing wallet functionality through JSON-RPC interfaces. Cover the reflection utilities for dynamic API generation and type introspection. Include wallet encryption, key derivation, and security best practices. Document transaction construction, signature aggregation, and broadcast mechanisms. Provide examples of wallet creation, key import/export, transaction signing workflows, and remote node integration. Address wallet backup strategies, recovery procedures, and security considerations for key management.","parent_id":"139b0217-0190-433f-b41d-60fa08c9ee5f","order":3,"progress_status":"completed","dependent_files":"libraries/wallet/include/graphene/wallet/wallet.hpp,libraries/wallet/wallet.cpp,libraries/wallet/include/graphene/wallet/remote_node_api.hpp,libraries/wallet/include/graphene/wallet/api_documentation.hpp,libraries/wallet/include/graphene/wallet/reflect_util.hpp","gmt_create":"2026-03-03T07:29:24+04:00","gmt_modified":"2026-03-07T21:45:11+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"19f906f3-0605-4d92-8d4b-7052dddc5ee7","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Cross-Platform Compilation","description":"cross-platform-compilation","prompt":"Develop detailed cross-platform compilation documentation for VIZ CPP Node. Document platform-specific build configurations for Windows (MSVC and MinGW), macOS (Xcode), and Linux distributions. Explain compiler requirements, dependency installation procedures, and platform-specific optimization flags. Cover static vs dynamic linking considerations, library path configurations, and platform-specific build artifacts. Include step-by-step compilation instructions for each supported platform, common compilation errors and their solutions, and performance optimization techniques. Address cross-compilation scenarios, continuous integration setup, and automated build pipelines. Document the relationship between platform choices and runtime performance characteristics.","parent_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","order":3,"progress_status":"completed","dependent_files":"CMakeLists.txt,programs/build_helpers/configure_build.py,share/vizd/config/config.ini","gmt_create":"2026-03-03T07:29:30+04:00","gmt_modified":"2026-03-03T08:06:47+04:00","raw_data":"WikiEncrypted:2GoRefXUXXQ3Xwp7OyY9nlon887ydNfpOl/itiNfh/4iWIxC9TaxKDiFwjOVFwQTPZYi+aDZcmdacy3T3sTlNOPDniBKjwz+vMIh3cB1plVH4KYwPt2TZXc/+ujGFDRr35exKHL5nJjwwQ0ZMNpW/UibupcGN0tcn8JuX3NpL4WLBra3PxQ3XTSuZYZPVzLj82+fwHHCLPcEK+78OX8e1RcVEklR+N1UsgtET9kO0/b+T0OBqa5ERNN3IEYqcp0mY5DL4MgmhZ5ELHFmyDcLeXPGbENuTTr/wv73OYFptwxgOC7zfdnxEof+OJt7oFB1H14TF9NkYiMrMg21KMYZ7SpknlH2jxvpqfrAZCvqdyxgE59BG/VXVZPBrsUVrClVTeHDodIoKQCzDVpuGZCDEUcM4ywm7n0JaWJSvA5QqTFe6FlcGrO4kJP0nIgvoYFjCNa6wMEbFOKpK082OTtsHnoZAn7Ygz/SktuD3sxaFQutzYzGUpESMp+7KK6ArmF3MZD1kHYrkbx8S1r3t7TRMBIPvNVbc8GJDepR8ER6t3haV1sBwAGTuVTiBApkEg1+z2snamjx/DMbTOTZC0t9VeDuyQmejRJ2nfbysv6hUkQPWiiVsQjp/J+k69s9+Ux7cnj9DlnC7yP61FjH09kWx24MLREOQlg4aqdv02Yaf/0NhCugHWGlzPlZRo9Rcm7A/fYVCWIdyBicPqoNenizmIRw/+0ZUncKEzrvzurMeUV+p6by+Wl4x/LuusxxAJNHAjzKBMDLPygjAixvqHVGme7S3iJkX6GEWMaATXOA58szwt0/m65fztGuJ6QnWZOGheD2ELMTHbAgxv9IgkRcqpDmLp2VaP7YYU4hq0gze2HaeR6u4tAs0fHJZX1HORBQV6m/1mzw/VUtnolpwqE/TDgNPDjy6eYc/8e8OPu/PHoavvf4IzJOMbuw9Jab/F5w158jHfEt9txnl5+n9JhFtPecLcLLIKgnb8rnsbOKzT4D5ggU6rqH4FkXNb3bwpNtX3vMcfTGxzXmertP2Lb88uXGxhfMWPiAvWdUrJtNxnCQIUWII2pyHmrr1hLGTBSzE0qEj2a1Y4kVgfkKUkeDNwNCf97ufWnDMqThJcy6zqCMYqHJIq/hc32CjSkIzzDOQouvmIOPaVwL6fpE699lSOwB+RKRrfZy4TBjrmA++IxZO00dgzzHFOHnN2m7tOKpsMnGukeWgOno6BUIexnY0lI9oY3VNKLjBq1WOxOBwi2qClZoCoD+7QkbJHk9gFUvcuZdAG8QeMQcgeeReC8hK9BHD4hZPTReh0bkSF1wEfAbM6TrdmuRtEECtHx8ccNSDmA0dl9OIyKfqRhsIsVF8knLOjcFBsaRt57n5d82KEfGVC68CqLC53zlhwC0f+83i16CySJnkLCgNBbd15ULQvB0CplndMfsziHgwpuJqtovu8ylKTtPg/wamM1QLvqMB5t4DVEbc90jw7qwR8T2SBAu+WoLfmaD20wd01rLkYH4tYuEUmmUq0XbGQtgOi+rUF1mBwHDdrHFW/gr7FuEdUWCclH5mbo1cA7ExHaHxPYDAxlKWN7m2zuym9yZ+Gf5h3jBjwldO1bHH58e5oSV8DQciXvAjBNDP9wIfpcfNEKgnr17F/GNHOBuQBfTDOUGLSGiAqCT5hu+QpkcGRq4U52dOsMI7FjTQau2lMxTyaQ=","layer_level":2},{"id":"3c3c0db5-9be5-46ca-999c-68f9e09ed1b7","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Performance Profiling Utilities","description":"performance-profiling-utilities","prompt":"Document performance profiling and analysis utilities available in VIZ CPP Node. Explain the inflation_plot.py script for analyzing blockchain economic metrics and inflation patterns. Cover the size_checker utility for examining memory usage and object sizing within the blockchain database. Document test utilities including test_block_log and test_shared_mem for performance benchmarking and memory testing. Include practical examples of performance analysis workflows such as identifying memory bottlenecks, measuring transaction processing throughput, and analyzing database performance. Address profiling techniques for different system components including blockchain processing, network operations, and database performance. Provide guidance on interpreting performance metrics and identifying optimization opportunities. Document integration with external profiling tools and system monitoring approaches.","parent_id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","order":3,"progress_status":"completed","dependent_files":"programs/util/inflation_plot.py,programs/util/size_checker/main.cpp,programs/util/test_block_log.cpp,programs/util/test_shared_mem.cpp","gmt_create":"2026-03-03T07:29:38+04:00","gmt_modified":"2026-03-03T08:08:06+04:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3WmwBot9Y9OBVOHncLlXn0pdKKz1WUfKsVGytPJZVkVzn1jhn09V8HprJdLgPvTqNIW9nck+Y9UzRqIVeizYwkrs8AvalbIdraMHq26xqQNyaXClx6ky2D2pEEVHlOEfHbZjrgf1Sm8DUdhe8EAYWNolPrJ6GqK3+K+xRCT/9X1x4CCodn3UdEwfLCSQsSRgWgK4QGymNKjWkyJOfHDjYb1VC6o8ANBDlpadKkYtA3V59/TdHAbqDX+QexB87xQmz4cirNA+ioLb0jI786Iu/Pb5XVXjcU+dx4ul5SbBkZl5pvvMHjJULCva4tmVSEDjIadV43PUVWuYE0gKYI8w1E7NpTBXPuc0iI5914LhVsQmBFsmnTxKevtgAsctmBkSdvi6UwOfc229QQs9xksRdNEZ8MSd7P8QFG0pUDELq6ZGFB2/BLvzRQgmp/Ka2k/yDuCvwHuAGmcYWVQactY38XI1FjB/ygv5yTWY6mW9yyelLdBGB1iczQuifZmWaQ5T869INDRQX6L+nbHwUb12+ywi0wwPZy8ZImXWhvicEjKccDf3bSENeJnoVRy4nMrdaD9HRGdn6eZMyF21Eh15z4RgMw7wLGdRaT2ogCc0iLq3giWRF6gr1BxS5oy+BT0nFGs0TXZS+L0D89koEz8XOFlKX8UScpNrTq2e4cwORQSYu7q3JTlOtZkg90S62Jp0XKjYujasx8/siMBbWbYfEX0ZlbBIk0YEtNeFXOrJ0YFMjVq2OasTou5uu7q4V791sn3cWwdWnVWnRd90OZESlsL1qjs5Hp5gtKHRkiiyKulzW4QNK8KI+PxATcdwdnPuW3PeWY/Fj3mtZkknuKTrrjHg/MOo/5KXKdPIxYpyHfjopL8DmusCaVmebPmbg+6o+DzlqVWwjynSup9LptgE6TZx5j9KZibKOIWA9jlMt15ndk4hiw5cGCUYSfOivLJJOW/Y/D5mApY53YY1x+NA75hGruZzFHH6M/vxsfaglc8Q9aWBLM9PVULOfKzoLXe1HZsqoVDNrqkQap6BXmm6qU8VQZnUkUkfb1TBkrsGsxw2w4oxVxo01P+OLg/XKct6Y/69IeApxBiLcDX/Jv2SaCyaBYM9O8p1K0XFb5Us6LWy1cqPbeoBf12EwWsv9o+1TG1a0zG5W1ecQTKeyVT6Rye8JwvZ6rlzN2Vgn/5YXtaK2RuwBZYLtFmn6lXQmbxB0E2+OY/BdmKtg1BKas7eEr3BxOZWhB3nw2InQL/Rxk/uLJfr0nwgZM2heGgx6ZncDhiQLNLptKiuRclBqRA31Rxk0ZKWAsF6VvLKt3qTTw6ZAeXs/P459LEX8PFz0kL4+lrFKfRH2mYWGoY7R84LubC6DIgSFA8kVz9XF8IKYzkglc8D4VQHfO5Tlr1/FqtV7ao2vtDwAesZ5GiTh6OQOPlh5fG5iPqKj5W4FcKJ7un/jimNAw1TvifsLS+ZbpWKpjfSQ1sCSCSKA4wI1URjJF6GALXRnRL3QqzaNVEopvxLkcbw9H4xT6T4x+csQ3o3cMngf0CL/z9nVwnMXoWgO4AcduUTZKrU6QrFGk8mxvbfiYJnC4/nKcKb7HjGX3xHw5BAv9I4eCxeGi2rNdH2SbnKuwl1okQXCzEemNTozhwCSgC/Sz39fanksRKmd6tBfcs2TSqH5HI6g0Y14lC2t/RICk1kiO2q/LpLBolUQJYWnVnTc19Ie10b6N6qc5NoltlrOW855LCnSQsgb/kcB/AJhLp+aw+LALJDIQj0ddrgQwxkfJZtRYs924eU1qeBS8y1cKQBY7tZawDIiNceLg7elc3tN6MfOwinrZU3zg24mEFunCge691ZTdA9oUS+k5tVFYucvH3zNAaBai3rmjp3yTUR8BZTna4lfXx/w1Q36GMSMrim2V0wzKeekrYSPgelthR/gZK4pMjNMFU2LxK9XPfZitValaN8XVEf18r0QwuseoCAAtHj0hok66wYT+LuMdp5v4px/oPftoRJTCSBYBWEEdTO3BcGqHSRFc54xZ3QbZeH8I+/6H5bFkyHTLaEc+XSMCF9FeEa2XytZsumZT3daRrD8vWEdAALfOaaS0O4LVdaqoAizqQC3Ag5Pve1jiNlG6+E+3dkQAPfMHmfzSPedsihSPwQTAeFXeU8rtBG8pBu0BhQIttnPS9NR6yenSZYzfdgZvLyb2SHdBabM=","layer_level":2},{"id":"9e84e0cf-c0e7-4a82-9101-9152b572c82a","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Security Hardening","description":"security-hardening","prompt":"Create comprehensive security hardening documentation for VIZ CPP Node deployments. Document network security configuration including firewall rules, port management, and network isolation procedures. Cover API security including authentication mechanisms, rate limiting, and access control implementation. Explain cryptographic security measures including key management, certificate handling, and secure communication protocols. Document system-level security including user permissions, file system security, and process isolation. Address security monitoring and threat detection including intrusion detection, anomaly monitoring, and security event logging. Include vulnerability assessment procedures, security update management, and incident response protocols. Document compliance considerations, audit logging, and security best practices for different deployment environments from development to production.","parent_id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","order":3,"progress_status":"completed","dependent_files":"share/vizd/config/config.ini,share/vizd/config/config_debug.ini,libraries/protocol/include/graphene/protocol/authority.hpp,libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-03-03T07:29:47+04:00","gmt_modified":"2026-03-03T08:08:09+04:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"8774fe5b-dc3c-4a02-b907-d2a16b1df420","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Block Structures","description":"block-structures","prompt":"Create comprehensive content for Block Structures covering blockchain block format and consensus mechanisms. Document the block.hpp implementation including block header structure, transaction inclusion, and block metadata. Explain the block_header.hpp specification covering block hash computation, timestamp validation, and witness signatures. Detail block validation rules including Merkle root verification, witness validation, and fork resolution criteria. Cover block production workflows, block propagation mechanisms, and consensus participation. Include examples of block construction, validation scenarios, and network synchronization. Document the relationship between blocks and blockchain state progression.","parent_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","order":3,"progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/block.hpp,libraries/protocol/block.cpp,libraries/protocol/include/graphene/protocol/block_header.hpp,libraries/protocol/block_header.cpp","gmt_create":"2026-03-03T07:29:54+04:00","gmt_modified":"2026-03-03T08:21:50+04:00","raw_data":"WikiEncrypted:boPmx5CcA0j/DyoZ7HyhKvDO0uY4WRRkzNPlVPFfuYd8x5dUCvXHd/9oi/DxEkfTxFYD6bAblx+fQQtuLzg3sNwWhDQfuhCUPU0fy858bISDVVeq0bZ9kOv+N1cQafYJexYNmmOXHAtODv6aTvln0mZMaSSdpskonjRSiVDR2JFQ1c3ihfXZ9aWKOJzr9HkollwT6o0GKJ8eorPz1iLxLjuuquHSqCI3XT9AEmwcOaNnQShyTG0htuDWIltom40CsZcu7Cy8U/5nQzjC0xDOrC250aMy5seipxo8FAkVVpMX1XNBS38rhNMjRx2OKCppowA7cIOi2FHW6V4Q5vbu+mU6FUxquGMY6lbq3yu8TbvoMAD/QHS8UL7YYUa+4otdwFZ9QSkbvu5GvmAg2jjbbBzHknhWswLPV2t16urDqHkTqrEYUcmJNobdpZwC6FMjh8IS60obeoHCmUMLWxbZKLs/at3r+7JaWiPt+7xh26AoOr2jvjva8YYv6aSKWGoTMW3H2qpeMDiwUqtqWS0L/REzV01evXpTy69qkgUnRQcWi+FkXRKAwQ4p5veRT8OF23DmlIPRBd9CX73BxgYX+wQmYU/ki8y2bDeb1P+++vOAPh+61ADmkl1O1DMHisuDnaDiCFOfYhQoUbJ8x19MSmRVDwe4AU6+EZrxp8RKz8/a9GwAtETrMQ+90BijOC54NEEGnoN4nI7onVLXrah4q7IPCn7ZsDwfiTROpju69VldR0fx5W3mcW5cR5QkvQ2GxhzLhsLECXMlAfQ8rmumlR3p2VeIdW8e/P/S/ozfNjWZzTfhrhDfu0Vh0Y7Vl6w8M+CVXnOs/tC7MadUAhjrh+JQyC+HMohGmdO7/z9++33J1xvTFJVyMw0GFOMSQFY6Ep07yumrY1mvZl7qZS05ItAmaINydqZu3p6K+KExgwoNhGWchPC4vfZ8xBQ0VJoT+F8Faidd+o4SynyU1Oa9a4nDGc4as1CSHvJdKS7A/xthytbfgo5QJNtZqwsgpqQiSBar6Jt5wb0v34osxOvwjhLvuvDRZ9fuSDvIlOiFT7/h1jeTg77hn49LMeK3SSge8uSY1mhYSX0wFFmSTZ09o0BBULQWJpqNi47MKUitiopByHGADdj6vHInz2cTcAegHNkmJElDw3ojdlDsbQibKm8vkNBNR/J43aDniBItv5XH9lShNCczTfl0ZYuawpqhiTDLOq8QJy8wCli16PSF3Wwq61hM7hq6qXdL1rZfvRsnYBW5GhCSL7weKEaqDTpsk+IxRFFdhwJ1ncnSZGEOLXXOeudTkfZHk8r+YxgLkt0NzpdB6t3M6r975QZs+Tj+4ReU8QJzH2lETRvs5l///xaT2cUdzYBloc/E60aX4zonk7ZyYs3KJwXniHXQefJRk+RsmN1DbuKpwaEFPVI1OiUgtuetyAT05BDA7lh2VSvtej7xZtkMI0FejtchcpCcvJFuH1BgjPfECJKdDQlWhRzLDP+YDKXAP8z5AFFA2tzEw7DXGyBxKo8/9vajdN/f2CiX1x1ryNzep77p2dM5fyk5ZvgmBvQlK5wEf4+BZgjSp+c9B8mojotd6/I5mRMJ6pUqqe92PePdrcW+I4qiFA==","layer_level":3},{"id":"6f3f9c87-cd58-45c0-b90e-7c01d39d3188","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Block Processing and Validation","description":"Block Processing and Validation","prompt":"Create comprehensive content for the Block Processing and Validation system that handles incoming blocks and maintains blockchain consistency. Document the block_log.hpp implementation for efficient block storage, retrieval, and replay functionality. Explain the block validation pipeline including header validation, transaction validation, and state application. Detail the push_block() and validate_block() methods, their validation steps, and error handling mechanisms. Cover the block summary object creation, witness participation tracking, and block production scheduling. Document the block replay mechanisms for node synchronization and state reconstruction. Include examples of block processing workflows, validation scenarios, and performance optimization techniques. Explain the integration with fork database, witness scheduling, and state persistence. Address block size limits, transaction ordering, and consensus enforcement mechanisms.","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":3,"progress_status":"completed","dependent_files":"libraries/chain/database.cpp,libraries/chain/include/graphene/chain/block_log.hpp,libraries/chain/block_log.cpp,libraries/chain/include/graphene/chain/block_summary_object.hpp","gmt_create":"2026-03-03T07:29:58+04:00","gmt_modified":"2026-04-28T21:03:48.5839966+04:00","raw_data":"WikiEncrypted:R9i/29qd1Uv5xEgS1tKQyKa0Xuqqfm5cq0GV9nRcndmrxsHsnYwJpAewisCUpG2ti9GxrCpxWosUOZaN9wIJ7/8/157xbaOnn2BOhyeyJDPEjOCeYSYjSjv1dxVt5lXdexGoI1KQL06BJsml/tJH8IGm3rSrWyMIJMVaaR4ggiX6+4EVB5GRcduKv4h7YPDYp3XIn5/mXxo9OTYPUOtsoVOv7rHyTlUbejkiXURwQve9fLOeUlvOIkZF4R06e8IAaiKcWGIvFXcY2VrH3QcxUFJsp4kJhDzGK2FUcgBnx3qjBwarMUwBpmjy4qxtg9mcgmICpt9DkXV/Qj7CgjGXDq0ch298hK9VXiT1gmCEUwmXar2PNH/y9g8c8RiIUMVAxrUCV6mO2cnruxbtn4bQRHyC6sk4Ob2Xl2kVvZuIDBbT66aj/kOiD69bs6LpzdWsztvVvmOAFqak3DVJANV/su1oWfc4dZHy1TVF86Ri31HD6HaOPhqNpMApI4ZuTGA6AuOth9U/yvJQNw9eJa2uqHSJLovcqephYqd/UVvPQUwwoQmeMyQpQGIgDu02ksU/4/umYthxfnKr9BCJZueLWKne0Ib/cxoDN+QlTPByFNxCIyaHLleav2nztHstwhM3KkUtSO48JMcEIF4KuBSW8rzzIVZSm8sfhQ+Z18r/cGnez0cCvKI8I6dIkLNeFeMz/WwUgYBbFFnw9LMJ0u7OulBWbJ6hXLwmS9uQEAywjdogAEWO7ff6hfllQ5ZJjUMBmDO4drvylBiNbQFRrwKjyqKxSoR2js37uA4O0CBA/JESRC6UsjfeRfGNWa1l/rXrdgoGwwBrE8hT7iNKOAgU2x/xiS81GBLWaUdxUtzTAK4j0jIgecLdmg9DWIxP35A4grHki8nATuqPuMzK/XD82HPaERxvdoyjYE/kyUsP/mUfCwD/JXekHhftIDxZUJSqV7l/fDYPQ5ipe2jBnJIy7Nh4rpvA2BW9RJhI41asIZjiphshvPGZWGOF2GAyVwTANhAoRWizBv+itY1p/2WOckumF9RlmFiXVuFJzkCrNMyvjdvkdCYcu003ud8rO4xtpyb+J6jN5TNAoQUSO5fOhVvcHght5e6GzQlmQqJsmhjwCIcHq0OfStaGzE49mWjAcY3UjQhLQluW7CXA6G0qGQ7XoDVDML/QxP22XB8y8Ag/eDa38ZbtVYhXNIhVy9pWH8EeWIPbbGJv1UMvE6KF89Ybpgi9DmWvsZz6grqkqVw7Kig7sPtS0YJOHjCaHQ7LJmHCCudaZuZ2MF2TuMAkYW5yaytTWIhz0H77S/dQmzQmMbytfA1mqlMnBDDXtlT22T3++L+II8JkaX+0jTi1DTG6QXHTBQ7GcRuJfIF8CXjnJPbDSyUgXNRdvY1/Mn9CbPL4uVjXu90DzGhoKrvUGDXTTIzcHERZKN2/WCYDuD2A/kt/ky+a4Ifw0xSaifi271XU3geXOUUbdpVlCcV9aORTRkhN252B0skqL0oEnWgTxGYxoqA7NSU0021Y5Bd8/1cnNsVTN2vGh0YqLujdAfT3t+xV4modisvpwYxQ50Aj0ZJpcYBstxuDpOaAhEkLR5hr5XLkyAkl1niPitqs2+wSSsmDR9AUBpEY9FszPwk0pJOauEP8Jfr1d5BLOVVyTx33OYPcaq7OSFBB+BVeb2PdBWIQ3rXPJh4/C4vFb2Dm7ANtijqKL05LFes9n4IA9RpbvGA4TKXkeuQ29BEmtOSBPphfzyG9SQXOvTw7hmw5S3Kynu9fQaK77qhLq8/bZnW5czbIhiCfmycKKVJJWKkhDVDc/QGJZkuISswBtvOZqyJEogCnVHh20eVcvsGuV4ki3KHOcPx4rUhjTjXNpaaFzlwE8XrbFLZ8u2B/jB+4toP9H8MuRsWry/rKhQmFlz+dl20Ow/ic6jWDvlTRVljvVsPFvB3bDy4T8IKvzVoVtpm8QJHxIkeEhA7FGrf3","layer_level":3},{"id":"7b4370bd-7440-4196-bd4c-e441e1f693d8","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Transport Layer and Sockets","description":"transport-layer","prompt":"Create comprehensive content for Transport Layer and Sockets that implements secure TCP communication for network transport. Document the stcp_socket.hpp implementation for secure socket communication, including TLS/SSL encryption, certificate management, and secure connection establishment. Explain socket lifecycle management, connection pooling, and resource cleanup procedures. Cover transport security features including encryption negotiation, authentication verification, and secure channel establishment. Detail socket configuration options, buffer management, and performance optimization settings. Document error handling, connection recovery, and fault tolerance mechanisms. Include examples of secure socket setup, encrypted communication patterns, and transport layer debugging. Address network security considerations, vulnerability mitigation, and secure communication best practices. Provide guidance on socket monitoring, performance tuning, and troubleshooting transport layer issues.","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","order":3,"progress_status":"completed","dependent_files":"libraries/network/include/graphene/network/stcp_socket.hpp,libraries/network/stcp_socket.cpp","gmt_create":"2026-03-03T07:30:03+04:00","gmt_modified":"2026-03-03T08:24:00+04:00","raw_data":"WikiEncrypted:dkYJ53aRvrNDaS+3NsNNs6w5If3uzOgs0Hbe29DiBx3mo/yRmSwkQRnMBRPnzoWGqPZ92OwU/caHUIgxDw3SIzF6G+l+ERyUQeM+5k8nlB13TwLGj0fVp686VLtYOr41/lerWMRI7r1nkNr74ZsTI//FSbi2G9SrvyKZ61XeHQG52M/cayN69rlGN09zTApYx4BVQSWb2i6BxxSytcKaDWb1J20q6BHyKneNmvNVZgCaF0rwcMeSSoByQylXwRDtVsY/0BwBP4rfWpBp67hPXAduIM1/AM21CdQgxh2c6knORVht0g0QmQsZw0NWcx4YL9Y1nzZyFpQ70i7h6ipwiSBFydgbOJPVkWTCSkMboLQVC+JReq+N76UfDkZcuNeooMsYPKVmR21KRI53d1ksrMsqJKpk8m/l2Gx1mYC8RPnt8hA5HK7RK35cQcnLx+tHRlGouJ37O/Ho3ZjGeYnuXO06taOqh4oHKNhC0CuTM7j5briN+qDNziKL3qrEagkw8MQ2Flhw2Ut609zD4HJIE4DiH/98snKwoFEIvo3HIZ3XOuQrGA8tqN7EGe7F3pG0++qZeOZ7cUJhnNWxqTeXGsLDH7yxQWtZyBLyvjGQX1xr/juOFCZx4bAzdWoycAfVlvjr2uxkBo6EYFbTo/IyJrXg5VPan51QhuxjTDEzVNWlSwt1lnBCnuOCKwHgBdzcSJgJH56iYdia5kRnlRiLeBRmHyIE169xvgvBxxlrH1JndEb33mw9trClKcuQpM2pPzVA56qCbcbiM2Z44kdqKDr4CSG8ooHl6voaTHVMpIhfDUSmE67NTSyHYiI1dd/85iVQ+9FfNfoASUtTAXELUUYQYvzHMPJiU3MEaD2YcNWgsKvzjxN3VN4FTcmw8L40grY9Y82P4hOZiWDDUlAMLciKeF6y2t266s4DZ8JCnab8osDj8QF+6KTb6kkeqFJ3cCCGI0txYTS54YjlXZcPpiqHCPE0t9FvIT5upocG+rYGTWehyi1JYLJWC274vsGtm5GxLvRg6mbSqE7tBd1v8Zer9fNpXLEm4Vbddd/Rl6Eh0qbzB1Tsoq6fYyLBGLyV2fbQav8S8id2khKvjPBzrSRYlKUt4MIeJoj1OPBsETpBlksb/sBe6zXuWQl1xdv1gj9XrQNqLeVVV6nMW0llZzTx7hDht3JryMwsQg1tnfcOHSIT8O7jb/KR3IsyPyzBwErQdZ401BUyu+fG/uzA7BXgy7/APjoVyikPtgFONSsd2LohWJ/+o/xmuwCFIM3eNoMIwhCsFA98lztBOiM9foR5bXUo85+w7OvJTct69ak8sO+4KO5AH5/Tz7uFF7T77SRhUeDI7YjpD+Ik9HLNsoGKRyr8cbNLyac/UxKH1U4TKLDk4AXTIImmwF5rK8DJ0f5l1TNZgMaUZ8DFXO5vQClOfyqFxZWCt6klaU44p54Zp3LCMzEJnexfBmjaSv0DcVFHG8qLi18z3+qLjoEnRpsnnMHegrThAgDc/30MLr7k4e6iUcffJUilYu4Pu1Sc42USdHD2FfKrNDoUSfokki3E/ZKIrFVGQvC8gnoSqAwuh0ioo3iHGiJW1O3Hth8vbhUnFatBI/jLrXyzAFrOTkVzWwxQemSuJIF6jvWcGkgiAogUGWvRS60wJBSFfLyUdAMPIXDDve4qPvZ3uNGSNHXFN5w5oxjkJr9zWEXTyWOpAcb+j7G2l3FtGxwEAfgiPCl3sCAHm/4tpKr2gTx99oBrasStExD6+BpcjkMiFvcLVuwDnAuknrACPbPJ8vXTbEJ3TxUxzy5/jBlGmaFsNKC9zcFZfTn5AJGPPUGUziylI2Tr54IzA7ULa2tuHRctvQB9pah5y+GJCs/E0wSrqA==","layer_level":3},{"id":"7045a421-d36d-4058-b1f7-1eade1482cdf","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Build Targets","description":"build-targets","prompt":"Create comprehensive build targets documentation for VIZ CPP Node CMake configuration. Document the main build targets including vizd (full node executable), cli_wallet (command-line wallet), js_operation_serializer (operation serialization tool), and various utility programs. Explain library targets (libraries/*) and plugin targets (plugins/*) with their dependencies and interconnections. Detail static vs shared library compilation options, test target configuration, and installation targets. Include examples of building specific components, skipping unnecessary targets, and customizing build scope for development workflows. Document target-specific compiler flags, linking requirements, and platform-specific considerations for each build target.","parent_id":"317287b2-3937-4876-97d0-a8c96007d95c","order":3,"progress_status":"completed","dependent_files":"CMakeLists.txt,programs/CMakeLists.txt,libraries/CMakeLists.txt,plugins/CMakeLists.txt","gmt_create":"2026-03-03T07:30:07+04:00","gmt_modified":"2026-03-03T08:23:32+04:00","raw_data":"WikiEncrypted:ZHd6gDb1oAMJeik+Vv5fPmYm+3RvozY/gdL9KOhG1Gzli6r3m1Qs+ajLMwPD/vJq3bXqoW1huXFI4mNN8ySzLIQHLUimXSbYEWathKED4BP6kZB18cGiRNQidMb8cyrDV5Iuqrq7w4IXFOrP49KX1Fj+mOjkDg3HSykKn6cAceQlzfAz0DrSk7eNO5hzUQqSiElf3OV0v7+fK9Cm4IQq0058KWBtgI5xr1ykHT0HpoUy3JFULOqohFCF27f5ON1OWmLfAvFSCDxaw0Cl+BhogR6z4GT18ewS7uuTNy2PkJ1ia0uNOXkxMjsSSmmup5HxBMXdZkQpdPZNEoZL7fDXqwhfd98C+eejOh3Z4tyNJtppazTRl06TCmo9zBZKQAczNueGCUBgz5MmxlMxulgT+9hXgu1cWG4XA3eJ96P6ZBxnW25xp7PSSH9JRkMlDmOcuC46lfmCQWt0aTtIS2ozbWrcE0ww96p2VsQ45j2rNdqMIpi1ulIJUOotFpc/CddsAlKtEVpExeGMLcSkX76K3NIA90qoVwWSndANNc4MJ/8bh9ulFe2+uzoBBu3xinjVvUlbOCjyNGqFd1jnMZtnt3L7/t7PH0V9q2SOflN+SgM9jVRVitER45lZFxsqr/tav2KGrocQE/xxUOIjQIC5CMvx2HWPNHn7xRZU9XceW974jpXKFvL5kBh7vnmnsKJupnB9t42ya5cABJD3AQu6Z0j6CKGPS2/l4uzkYiQ89k5SPmbyPik64SWmpi1um5U9Kj7wI4cWS/oflhQlCNAmvw4uvDwwljAA6qj+M6gLAanR65d03Q9aDTAjBYMVwGmOo4abkQv3nf9TCwKxKDVFAs5ZcueELmtGXDiVHfj+aZxEo+t86mMMQ8g7u+kNm84EszGt09RKbBsjXslT7yQIutKSMsZJpE3XeEFYyhNtdvcx4MZ0/0C07WBxke/L+xeuddZajpKMJ3dJJCBkwNkDH9y1gQCS0cFOpuuviGp6SNKtCxcvsgaWS7wBAW+uPcsoMQE0llh0xjKnOnATbn9DIx0tfuUk7ESBuGr0VaKB9nfzTlBLkjl4PToRWCsnt84L3d+ueb44ND8vu7KMItz8QOKO4zuDAQv3ATK+TZjQcFqFxXPqpOu6tx2+SzU9U0Tm1N/U3VMkQgn+Uz1EBAQjxtp0HMRc8ziGnewPSGizlOykM6jUEZhJPFrMxDefENfoQxGLA+l6IrDKlL/lo86+eCXm4vFSHWEalAjeApSnERSF0wPuU6fm9QJcUdlhu7YfBgb2KoEhKQv99o5kzzGAwEO48dvnbGMlT5tg4Wy00FCskJlqYfDQBVxLTL24kNHfDTz7VM3JENKxyK0FPq8e+xgEtZrVx5vIEPzsppJ7Tm2JvwMNsgBNzTTVrWdB6GFc+ykwf9X+NihR8xU80Of6zgl/EQLw4MGr687/twMImC5bbwRa0EN4Pnpm+wfGnxag1dAxyCl7pFPa00FsMWfFsRJfEMTsBtYzA4fj+y8wFZji35gM1dsWtMer8ZNiTk+A","layer_level":3},{"id":"939d7089-2486-4f03-bd3f-c35c98d5a1db","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"MongoDB Integration Dockerfile","description":"mongo-dockerfile","prompt":"Create comprehensive documentation for the MongoDB-enabled Dockerfile variant that integrates VIZ CPP Node with MongoDB for enhanced indexing and query capabilities. Explain the ENABLE_MONGO_PLUGIN CMake option and its impact on build configuration and dependencies. Document the MongoDB plugin architecture, data synchronization mechanisms, and performance benefits of secondary indexing. Cover the MongoDB container setup, connection configuration, and data persistence strategies. Include practical examples of enabling MongoDB integration, configuring replica sets, and optimizing query performance. Address the trade-offs between traditional SQLite-based storage and MongoDB integration, including storage requirements, backup strategies, and migration procedures.","parent_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","order":3,"progress_status":"completed","dependent_files":"share/vizd/docker/Dockerfile-mongo","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:24:06+04:00","raw_data":"WikiEncrypted:1goLeoGXOcr+JMF7YkmJQ4CA5GfPsgr9AOqxshcHKh0QXHY1oeNCF9v12XmDZHZdXhCy259YG0ezOu7wCXExHWK8rq0XwOg0suG4Rru7URghgXoS9VEljbRd1sl6vaFJhSLystxSvjxxzzlFJvD2tYkg8LaFtAmMvb8rZV8Ez/vZCMyxbPhKJ/eYVSciU7pmsK5xcHztFCn50vpB2r+Tj7t3gDP8WGYotYg9Jf5I0fqC3CInBw+7+Fy7HWpLVUIBIaIjozAoDMsShFMBja8RpTufBS28/UhItMRKddABKXVEZXD7SGIpEsoJoSREJ6yiSO+EmTw7r4tt0ORzmnJhtT97Bxk6r9hcgLBH9wNaggWiZSGB0X7RZSbzLF4qGNJ8kk/Dku4q/6vMsh1tZlnNTz+xeJ9Qdd4d6UNqdaS1i0rQHV/TauwScbWmVjrmaU3qQS5CwPasVE25WCIbXplFghy90JNbFQvZqI1Et3VDOQTiGhrW4WEULb81StceIyHZHPYG0KEkZ7RSnXUbIn1DARL6HzgoHsunnU1r15BIcy9NKrxjvCIQVJHpNSkt3Gj2AKDIAd1VCYM7KU4prw0cF23fcCABWMrCPPFmkFxsp0G/1NATKnFi56Km0ARP9qM78401kh9C5AVW7pDJ3akRvievrgrCd8ffmyrxqPThxJ4FWDo85X5RFbaaRiNj9qln0BKGqrR9t2JF2OHebqvlzwoROLwdN5DaJazsk9B6QVquqRJZLV+jBuJ59vK9g1rpdU1oBluHRJLvB4PZypWLlTVg5Pf/v5jCH0gnPTpCMxPwfPJlxUc2m5hojJE32fkJeAkFXJ8Q2j9mbQAvuDxUCH1844Bhwc+O8q0ZzPHADKs8yp2RPbPIU9cDsrHP8I3rkRdRHQkSpzW1Ja7wDnR7rHFtaV81Ygr5h0DDQqEGeJRycLYDrvbgXJ++N8yk2pMI3NdVp82G4v97ldxc7pmOoyCtSxLmM2L0AVmLCiJfEIIelQtOfafD8S/dXBowqYXgsFsj7pHzEfLu685kww+S0Hi2Ma58ydkYzot32TR3SBK6Euo5mDirRCGoi66xck8Ao84maWlxOIZR4/27ZoQsTCnnRPuONwNxwf4IArp+RpIyq6y8pMDvJS6D9+NUNajJvmdC3ripFYOzzg6AoGuxRkUKXPGkJJeUxIU0YUv6UUx3/Ceh5rSpXlBoWnIrnMvY57waMMR24d54ElfvPd61lvpdCD6zkMGQFpKPL2fuhcyOZXVUzBhG0iHARrL5sDw/qpkjwUp6pMY8lWFvqInaAAfRcYJqSSxcTf5lSDQncMV16JPUH71IzFKM75zM6dxgi5dX1EbdZHeDSFX4sBwGdR6tMxyw7x2Tr59DU2XjpNklRUYK+t81jNTVBFghVIAHiZbZh0iA26/Pgy/WrWoID8+MBc/XNy4wtzJXPUzsy1notTsYCLr/sK9uptZZRYnp","layer_level":3},{"id":"75c2d99d-2330-4db2-a9d0-f4a9fdb902bc","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Schema Generation Tools","description":"schema-generation-tools","prompt":"Develop detailed documentation for VIZ CPP Node schema generation and validation tools. Document the pretty_schema.py utility for generating formatted schema representations and documentation from blockchain object definitions. Explain the schema_test.cpp utility for validating database schemas and object relationships. Cover the schema generation process, formatting options, and output customization. Include practical examples of using these tools for documentation generation, schema validation, and development workflow integration. Address schema evolution patterns, backward compatibility considerations, and automated schema testing approaches. Provide guidance on interpreting schema validation results and resolving schema conflicts.","parent_id":"d54afe72-4975-48c8-b825-ab792ce92a46","order":3,"progress_status":"completed","dependent_files":"programs/build_helpers/pretty_schema.py,programs/util/schema_test.cpp","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:24:57+04:00","raw_data":"WikiEncrypted:7b0rATEHF8+R+XhpZF8awJS9ucITjIW8AZ92lNvy3q9A2A2uvYfv6YpvR0BnMFsd4Q0ovn849WEZySYF9U7MEsIS00oTyk5KL6C0n6FXddBjWTUR5PTJ3ztnl9XxWJzEUhzMMtIdmAd1KyvimpOCYwQ21QpwY5paukgVnjbsw/0pQ82INNTEiOIwF7BlzTf1HYfL7szXIL0WkJpLMdLxt2h9C2FHgQFy60+AKUZg1pt5Jd3K/aBQWV81VNnDXW/LnOx1FPSPwkGkzssRmbbAg0nFhMWsx5SMLXwbx+0OxsTzcsEom77ZZm1yybS/5zIQUFiRjQfIYwJuzu6N5Z2LWfsWSHYqLWmQF3c6umAOf3r1wW2ZNrCeX9orBn5VMOJZ7l8GTVOJXCDCFxdnr1WXweN5VGwCS0Odt+Ron1uBfAzu1GAw58ablMKRKv9VS4SXuxnr2wY/CQOMRjsWbRtvI71HuFhd2RJZIc3eVAsDc1GU1cmrTeTbUnOpZCUhW1oFgJZ7zk11j0lDuC7R2fp03fFJsHDnTeTn+KjHQ8dMIpWtQ8Nit6XrZb6D7tvpAC0SvTT6/p2f7HZgovIfTijfj1y1hPiIdc1d3NgzyEntYVppm5pepIF06TVVx7zfhhiuG9b6HE5hLuEvMq3DS/4XMm90Cnv4sZnjEyT3TEj5mX4J7N5cBAgYCSGgcNeI43T1C15pXX4uGLqfoOPXXnB/SCpxe9nWbiABMh2oto/9Xz2rUuQGDrsSrvRXL3iFGHAh+0c6m//cPkbqieTn8V+jGVQl6W0JlrLbKYhtiihZ2TDx24go8d7f8PL0ejj90ChkWSBVvmztGtG5cLsTAM5lB21FF4PXM72PfYtGrOCtfIOOHZfaXn/3vJKykmXqi9G01zdxiUzn5JV9g4bjIq2pAeYD9x8XC/bIO81rmTigEbB4nnLKa1ElZBsSM0/70h8jS+5z7IliXyuhB5FqyvZwwW0xVyIOUAzLtk33DyepAdhyg5fBwgApQ/HT48joEV2rTs8N48kN92Kxy2Ye79DVSUvQzIQPTLZoQkDnUqCOageMGKRgFzb6cqmHCuPViGnEMOQf0++miVciKXzhicWHaoLzp+sFjN3yGJMY6tZVI1oh/UiPejOTqvAQz8SMLfS229ZyyilSHYo4cKKzCuR9NlRx1X211iyYLzcNfOdkZwdM4CwTPQMSl3VtUnvqTSZHwYv1ZCeN76rrKV5GhJGX/NxT335dN0vycUHuJLIn/NlfOsFxQG5XodPVwtnxZp7S6TnnU1KVuZrm2ftDmexkuoC+050w+4hBvFdc/wjSpNOWgIx5HxbDS9wWBlmnw0TDrlXh3YEqotm+U3Crr7DxCF+D4IgTMGhdtmJ1R1jLTzSqu6SKtryd32ymbDmRgf1/8MZIIPbWljiJyYH5UNsPbK4WhW9WLV2g+eXlh+1UAwBgpyWvaeXm/t1ctPrjmfXsAnoJTYnhyJ6upeg8GnfHo7Z9UDfIJ3pyR/8d0SUQ7usL8Nb9HXxpWxddOk9Evqn5","layer_level":3},{"id":"8fa79728-580d-4d6c-bed4-5ac9ef3ae8d7","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Witness Guard Plugin","description":"witness-guard-plugin","parent_id":"ad096386-ea33-44d1-b9f2-261f11fb24d5","order":3,"progress_status":"completed","dependent_files":"plugins/witness_guard/witness_guard.cpp,plugins/witness_guard/witness_guard.hpp","gmt_create":"2026-04-30T12:39:24.257028+04:00","gmt_modified":"2026-04-30T12:41:43.2873164+04:00","raw_data":"WikiEncrypted:JeTXIs+pfWQp8HpBYqSHUv6FCVRIRaRMz3xNyEW8d7EhJ4Yb9uJTUDwZy779+JnAHj6NWz8b3Oo5/W9JMIZSMgRD5r6w4EIzwRavY8e4kc1XIH0/yLqyECkYwILkFMHI6V10KB1Xjt96X5Zn/owwRdxlFryES/SODzx2FYuKNSOxkz61rrs8q6Bf2bO4pyez7gm8bWEf+++ptw5UQP1jcW0btibEljT/0SoZBuM1AxjryuZZZOPzzWNJtJDVCcWv1YBUW4p7Rqws38KwhEh7rDWU7mvUFwc/NQhS4bLJ3+I=","layer_level":1},{"id":"ad096386-ea33-44d1-b9f2-261f11fb24d5","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Plugin System","description":"plugin-system","prompt":"Create comprehensive documentation for the VIZ CPP Node plugin system architecture. Explain the plugin framework's role in enabling modular functionality, the plugin lifecycle from registration to shutdown, and inter-plugin communication patterns. Document the 40+ built-in plugins covering everything from core blockchain functionality to specialized APIs and integrations. Include both conceptual overviews for beginners understanding the plugin concept and detailed technical implementation for experienced developers creating custom plugins. Use terminology consistent with the appbase framework and VIZ codebase. Provide practical examples demonstrating plugin registration, API endpoint creation, and plugin interaction patterns. Document the plugin development workflow including the template-based creation tool, testing strategies, and deployment considerations. Address plugin configuration, dependency management, and performance implications.","order":4,"progress_status":"completed","dependent_files":"plugins/p2p/CMakeLists.txt,plugins/p2p/p2p_plugin.cpp,documentation/plugin.md,plugins/,plugins/chain/,plugins/webserver/,plugins/database_api/,programs/util/newplugin.py","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-04-23T09:46:06+04:00","raw_data":"WikiEncrypted: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"},{"id":"c5e155d7-00b2-4e55-811e-cffb5860ac55","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Design Patterns and Architectural Decisions","description":"design-patterns","prompt":"Develop comprehensive content for design patterns and architectural decisions section. Document the key architectural patterns used throughout the system including MVC-like separation between data (database), control (plugins), and view (APIs), event-driven architecture using Boost.Signals2, factory pattern for object creation, and strategy pattern for different evaluation strategies. Explain the technical decisions behind major architectural choices such as using C++ for performance, choosing appbase for application framework, and implementing a plugin-based architecture. Include trade-offs analysis for different design approaches and how they impact system performance, maintainability, and extensibility. Document cross-cutting concerns like security implementation, monitoring capabilities, and error handling strategies. Address scalability considerations and how the architecture supports horizontal and vertical scaling.","parent_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","order":4,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/database.hpp,libraries/chain/include/graphene/chain/index.hpp,libraries/chain/include/graphene/chain/evaluator.hpp,libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-03-03T07:28:18+04:00","gmt_modified":"2026-03-03T07:52:04+04:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"f6b80222-aff8-4f40-9721-fcb497d3cf84","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Data Types and Serialization","description":"data-types-serialization","prompt":"Develop detailed content for Data Types and Serialization covering blockchain data structures and encoding formats. Document the types.hpp definitions including basic data types, smart contracts types, and specialized blockchain types. Explain serialization mechanisms for operations, transactions, and blockchain objects. Detail the operation_util.hpp functionality for operation utilities and helper functions. Cover variant serialization, enum handling, and custom type serialization patterns. Include examples of data type usage, serialization scenarios, and deserialization workflows. Document the relationship between data types and protocol versioning.","parent_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","order":4,"progress_status":"completed","dependent_files":"libraries/protocol/include/graphene/protocol/types.hpp,libraries/protocol/types.cpp,libraries/protocol/include/graphene/protocol/operation_util.hpp,libraries/protocol/operation_util_impl.cpp","gmt_create":"2026-03-03T07:29:54+04:00","gmt_modified":"2026-03-03T08:25:53+04:00","raw_data":"WikiEncrypted:4o0MsTZSJF8izk/4K4S0sgel0pL3GjUBgmfU2Jyx8LAEeqHSwBDIqrwqYaLa7vz0dZklAexiBrcyBPoGl0UL8BLUGv1A6Pm6qrXwLUFQaxQ3uw6aYd84Czg+l1rsyFCtZkGqcNdvR7IzXAukFAEoBdxczKyxinARYsusL7HRvAfVzJVoHceBpQQ3T8jYuUKHR7KxqUNsY1I1N4cKmpYRNuONQUbY3FaLt836Lwat+eczNxHuemF2h54DgyLIYFx7jGWD64tBO5H18dfTY45jnQWyvHaLi9b34BxaNrhm+fGKARUr4lS123jCX8Ogd6cROYLNUcfKWIV71Lza7SLjR3oy2fJHN2RTB7aek7eUs7BZ29A+DVGyDmeK8uCBtgTPDzclEAp6WftsK75zwen2vDxgiOSXFpRMVMEAOHAwj1IuDC7RNL+ffoS7VdEA68fjVq126qs32YF+sBGMUkEKyWEWX+gkggDLcEHsn/7+jSvzHtKBYqvBHDb4T0RhQ33cQm8MOsWmMxNa/cVQmnkVvOXkGhgMzkTo2aWzaU5vJ/1gxMrhMc+G6+zypIGtUI9UjmYZslWZiPNHcOTa2Fe+62p2Finm8c8m8ItRnKBSpvWLSmz+nIWazm7UWfByDY1S1v1wNfnY2PcdeEAjKCyxthZ5Cky9zotWIT+qrIOpc/qC26r4ZBiQR0j9E1GWg4iNMJxrVhTp02hdLeaTOL2pfLR0G4X7IcxRwvHRz0hH8trmEJpknID6V2HoDQ3xJPAyk7MoVzWBkP0ginPs2PFFCPTQKuJCx9YICn7OxOH8KNNGT8dqz2jLx+oipdS5PkG++aRBaQhBx/3XcXUJu1RLEc5ow1BZ5FfwwFI1SawDt2JI+TJwDy5UvAJg3NVZlw2VZNOWvlMSWjzRd1JXWKRnZ3ttaAdOh8Rnq8018rPe3hTKusOw0H7x6Qutwzuy861i00sXA1EpBOM+h4qwdylwOpck0nF6stCsQKPPthaeVkTF54qbg6oJiJisfp0I9QfmilymYVDuLFzflAylAFe8YSWyBHptb61CK4Ak5snS3b+69+zTp8vXayv56nEDuQ8gn7gtbYOmYf7PpkfCmWz5gUtos9IbU02Fw4OnqLWIyYUH6qOhbS87wfcuSqUp+1WKMYHFNxzTmXG7UQvt/7Ir6SJvZbS6l6YykQlv2yMFV7+LDWkQyA2o7PPDUcTjmV4IQVtY2pd2QEkdQlBFF7doTRILVr7moooL82uAYJK1aSAfGLpPLQ00ZG8qg6d0Wx3YVH00HTPF7xHCvt9YOJwKwPZ/uF5ycShlwxUNsN2qj6QIXK9CdnDV5a5JDGhP/JmICPhmAG/S7PUAL4d5+EE6xxFA4iwcsWyZm1i76v4W5l/+U3wz/4cREOAone0UPOTGBFFvTvrgLgt2iwBpoWCUJJs1T6w3dwWMyZRG1Sy4dJY6reScRpuOoPdBmKELw8zB4hBipR8Tlj5DA517ISX2rXS4QjE53Vk0mEbFdVha4CsZ33/5Ytms3zPrGhiUM2/KFGnEQMevHWbR+98FTktgxyxdpcmc3q9fByqAP2kYSvyRFDeX8oG+KsE+DdUEqk6u","layer_level":3},{"id":"db232a1e-1458-4825-ab19-14e5658aa89b","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Transaction Processing","description":"transaction-processing","prompt":"Develop detailed content for the Transaction Processing system that validates and executes blockchain operations. Document the transaction_object.hpp implementation including transaction metadata, status tracking, and fee calculation. Explain the evaluator system including the evaluator base class, evaluator_registry for operation dispatch, and custom operation interpreters. Detail the transaction validation pipeline including signature verification, authority checks, and operation validation. Cover the apply_transaction() and _apply_transaction() methods, their execution context, and rollback mechanisms. Document the pending transaction management, transaction pool operations, and broadcast mechanisms. Include examples of transaction processing workflows, operation evaluation, and error handling. Explain the relationship with the witness scheduling, fee markets, and state transitions. Address transaction size limits, priority handling, and performance optimization strategies.","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":4,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/transaction_object.hpp,libraries/chain/transaction_object.cpp,libraries/chain/include/graphene/chain/evaluator.hpp,libraries/chain/include/graphene/chain/evaluator_registry.hpp,libraries/chain/chain_evaluator.cpp","gmt_create":"2026-03-03T07:29:58+04:00","gmt_modified":"2026-03-03T08:26:05+04:00","raw_data":"WikiEncrypted:pze/wTPA8hT9dADtWGlHVecGIju168riPHUw4TY8/AOhja4aeOzUlmfgdY/KTiokGkE0pwevgTXyU4//H92NNz2DvJDyylHUIIAgFa19IOTfSKVBOXJcKVULz6LIPtQwZ5+I/d2HQnvXu0GFtUcT9kmgOyRNKQ4GRUnmvneTMJmrQG5Vslg7JhN7/mNg4IJK0Dk3ThrdEunekVIeXQSA2yDfb4/F1psaKryHcISCqIr7tbvJqmxP3i0fMkwopqTPf6ajp8rGC+GRxqBpF/y0kdkBEjwiXnv31iUBzGXZv9OERg5CxwIga1U4y815sa7uz4/XLIarRrSrSkkH4jJSsb9nbsr6BCqGCpFm7yR/coQc1kz0fH3MHId8ozmrx+i4rF2oiNooGCXUoFpRo5UOz+bI2wbNAThGLFxtBDW16GYIOREvz/ia71sBMJtLkKcCTiXrIjhAsvYJXiiV25TiudXMeYIFBR7YTIFR78P8IxlDu+ps95nF9d2z0mGvlqv5ZeMVjmsWWFhijJz+dLCLDWiSOITgiWobkEqX0dAF9rWNUuNaBp0PO6V6+5bPhVNgMxxD2X4Bj8yCQCifDIGn63I6qufXUScVoVh2Q2QiOQi6/vSnd1zvdRAnUYSvSBNDTRdjj5nk+0gf5Y2JWwfQomwHvObp9Ix+j4O8MS4WmDIurqJkl/qQPWZOyO7Ovbesa1ya4WyodKNTWL2p10rOs/VBSyyeaUHdzlTRg2MjBqxucn+tRMrZRmSbHSEKJOR0BBBVhhduq7lgyhZIXMZoycnIN+WgDyn6XMvGxIQqniDtskHa980w9GnNIBwCbIxJnxjQv+lpaxJE3IOOwCW23ndsn75pybH3Seyqv6OuQhad56v9DwC0BxyYBqsIaXmGNoNllAeQeVZUQH175v0BgIK1c3n9RGtUgHLfdZsNsHzC8mgChqLbRC6DsWirecPKWLpjZf4xET+zOq2jUSQEdw18YGi5NJ3PvicRdQhS4yUaotOwkHeEdgitV6BOcGN2jFhWSrCwIGw+lsfV+iltczCyEO+QcDb4ejHfTFbTQw1XmXSFa47nMho7GKph2QF2+GQJ+nbone7OFVC8m/xQn4jr8lI3/+OLGwczf0GkZ4XuK8zLmQ0V2UndN061/mzWtLFJ69hxHBwUNYfeKoP4EDRl0a/fxRwCciErr4Jq57BKpxaUDoRIuUK4KtpJ/NJLSFitBqXFX/ofVjEuwdj0sGoUuhCzOollA8quac36d7TLQxLf8Q77OlVo85VmNjQw8utru/9UvqcaiC5AayGoP+uVvudNUxgYpWxPIzafzZYM1ayP9xLHmw9R4ex0u/EOkwZqeiLEEF4W90swZcJH6wfviFYzP21bySNNBZX1tfveoWOmloolbNne80gy6jOmIVM5MwhYZN+uyyQwTqFDiX9RgUP/XJC1lsAnDcoC4nqThnSjpMx4ewPkHRH238VIddAgBFBD9t7tpYIVjIAoDe+w3LMGfh8lQipF0uhap2iJABfmTI2DHZpCrsKPJMVy+mbP2zgoV6a+mEbf64RjM0yFN0CXOGNTed5itxXtfXATiEvKUNOHBFufW7TX8AdKdJc1Co1UJERgDaHTvakQj4pVvENgDIDjvQGeU91LZGahPDPY9RYmT4lLzT+8LPt1ts3MOxQR2eJT+yCsqaeJ+eKNGItw4mdvVyactSFV5wDElXPsYw4Czyi+ku7OZQ6kXuBox1TwmrZYbQ6dATa2jlDt5nWXBokmI2epBSyVyvVpPvNlbJdA1cdmy60QeZIHxRBEsPsT+Wzmq1eJMOhnh/eFDPUoyGC8Jt4UbbMFczwn3JPc5wWzSLNSxjq5Fj3ZD6fLt/aCo9qYTs1anapyWkXQ0M8GRNFWnj8EzlazdLXo1S5b2tlmlboOVeQB5xEj8sqNuMZMb5VWilnFlKauw3ArBD1uGCOa/kiqgAPJOhxcWYHNbCOtydn6sKPMLpZ2s1yMkcZXOk7ViNGtwi/d2zE+QjYkdo4tlUJ6cy2O5TwI9nWtnNkHqnOeaGpFujYQNWVjWfUDWVXpUQYRRqI7Z+qQFvqTi4z1UXxBPpXWYyU5BU9deuRDlsYqHvXP9V4xhyKN1fQudyyBBSg2vPnd8JTq9lnv3dZDAOZ6LH4PAb4F7NNauTxZ+BXpHyFqp1lR","layer_level":3},{"id":"f53aa7de-1f1e-46ef-8b89-75ca11a2de22","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Peer Database and Discovery","description":"peer-database","prompt":"Develop detailed content for Peer Database and Discovery that manages peer address storage, discovery mechanisms, and network topology maintenance. Document the peer_database.hpp implementation for persistent peer address storage, connection history tracking, and peer reputation management. Explain peer discovery algorithms, bootstrap node configuration, and network seeding procedures. Cover peer address validation, geographic distribution optimization, and connection diversity strategies. Detail database schema for peer records, connection statistics, and peer scoring mechanisms. Document peer pruning policies, stale peer removal, and database maintenance procedures. Include examples of peer database initialization, peer lookup operations, and network discovery workflows. Address peer selection strategies, load balancing across peers, and network partition recovery. Provide guidance on peer database backup, migration procedures, and performance optimization techniques.","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","order":4,"progress_status":"completed","dependent_files":"libraries/network/include/graphene/network/peer_database.hpp,libraries/network/peer_database.cpp","gmt_create":"2026-03-03T07:30:03+04:00","gmt_modified":"2026-03-03T08:27:29+04:00","raw_data":"WikiEncrypted:XiRbxJCvY27UULqlncgSjGeAt+SntVKp6XLlW8ZptMe3cQN5ElOvYsLW2S/yrn5Pm/gdCGXs1y2Piedj9v33wLVOwOus1E+E5H9jI71bXJ8uMEB/sz5NkYwU8/6WNzkQEHsACzMBDHuIu68ikPcAtR/8PnomAHUeME5ZfrZrVhoViH3TDu6y2YrDMdFxjmqinq0fSJUCDY+ReIEVe0DvsdamrkwIGLGY5bVT2dG4wA72SkOilgWxqZTHkxb6lHymUVytk9eYkF++9M1xy+eMmJxQD+TE2u5KZxVCvqgn2YADlbSX3hWCGnZjEjZFVlyDxQaAO1QnQ8yUy2iYYhwwWm7CeMqOc9byb+cFu+/OcEVm+e8BFvLtlLhxtP3eh+6O2Vs973N6W5ysyb0JygjHnJ8nudjMyaHNw8RyMvqSOSLT9U6UwXVTEaUotwIWIKzszrlF5uOiVOgjVs4Vuhd/uYnYqPY7yg1U9Gupcuxvia0BPTymFFSR0GDBDuozAVK3y45LRyXz9WHPutVVQWh88qMX+jfAGvGLPWgoIINUN7qxj7vx/kvAhe+zqVIba7395/OXZF6206+vXtoOr52yCARo1CLxoOxdGiOKHHIbYfGb5rQTXcMLT47TM1pJW77qF2ZR5g5GHIJIMydfYlnCTELuUPbwEQv+04i9jOdcmqTvtikO6WoduzLSRan9imvV39bTHESYJcjmUlckudSYPQtozz7k9e+CM8MImvuLr9XjkYGT1eUYbvc+w1RPzIdkX0510bTwxzf+aDCpoCvs8EQsEWVi7mp9dM2qBWQEdpkW8TIno+0mFwoo9mNRZDjG3uDxVroN5n9AgEtgWwXkrXHOFMpY2E1AIKhxOYjZ1Vy5KzxBMdh2cinDqfAb6ll0vpu9cElmA+zv7ttinHxgQjFyClOod38iDnt5ZR+0FGhcIcs4P74nKN67g708KKvGVd4lwx6dtmZrc24PynmKHwA2TBmrLBNM5ayRIe9uGx7fwf2GBSg2dPNCXEUtOTsDs7IGGa0B9w4wa5CKCIuoB9SoV70Lq1n/P6BwSKUmhNygSrebiD43uHUQ5cOIYPv9jDBgaTNBoQM4TnTC7fjNg5xBcDw0vlGHTq9FwedyYAG47EgYdNoSbNf8YT/GbFLjGaspoWg/aJJfrOiArUoo6Wg4ojQP3O0OGKlX4X0H/+9dL+4J9PwFjIvx/ESPb/xBDznza0ed4IZr+4fZ7TaSScM5euZl2jk16NwcujBriKnp6ABz12CC3fd5IXOG8S/P/iIbQseHgBo7JfDWjLYX20Cap8snp6zDAuJPznfy5geMKJ/JacoOzCglJsV+R03yLHv9QFHCjeSziCtcx+9azEC8MvUzgqr6CzcAI4nkh5GhDwnkmJ7JfJU22HTpajb16qZcHJBnGZWHiG3KZdD8jKV5qSo2fwd+92rHO4mrCEXisYVNImPxfi8jA1nSAp6Y2NXk6bFa02t0jO15651DfABmgqeJxXvGGgN5MrRLKGu6rb3deqKo+dcjh1F7OffKbsMAZH+mQOCdYVTsnEyCJupKzMvhxEqC/LIXyStFyD8xXNLXXMILU+BGDP5Ot99lNtc1tavX26Wadj+ngWdtm1fw3m6GQ9+HUEY2O8NQNTNdGyhn7l58zZA6wDYY3LgzZzzq3DBddqX0/Hlrr2wcjnqsfapDRrVhDfTM5Y5WjHfvmtO2n0v4Wv6ZgGL4pTCzDtXzl0is4FdsexfPlZVbHL2kFxVm7iXsRfmCY7F74GkQUrSNaKjisSho8S7eR3XxH26Kbkww49FudqO3YTCQO2q969KjbtwNxa2MS3UjOh4=","layer_level":3},{"id":"534cfa3d-aef9-406f-b4b2-b732746e7f7a","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"GitHub Actions CI/CD Pipeline","description":"github-actions-ci","prompt":"Create detailed documentation for the GitHub Actions CI/CD pipeline configuration that automates Docker image builds and testing for VIZ CPP Node. Explain the workflow triggers for main branch pushes and pull requests, including build matrix configurations for different Docker variants. Document the automated testing processes, code quality checks, and security scanning integrated into the pipeline. Cover the artifact management, Docker image publishing to registries, and deployment automation workflows. Include practical examples of modifying workflow configurations, adding new build stages, and troubleshooting pipeline failures. Address best practices for CI/CD in blockchain development, including reproducible builds, security considerations, and performance optimization of automated workflows.","parent_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","order":4,"progress_status":"completed","dependent_files":".github/workflows/docker-main.yml,.github/workflows/docker-pr-build.yml","gmt_create":"2026-03-03T07:30:16+04:00","gmt_modified":"2026-03-03T08:27:16+04:00","raw_data":"WikiEncrypted:xtifkbs/d6wNgYxQA0eu1rJ2oLOxPwih+xivji5z+tk4TDdFMY/p/WvAfD0LFZfeJ+Eax8x67PbVPoq2NW8j2tIHrBfX9wrvkZxoA9QdrNVjiLVdVfe6Y1r0ibktm0Avg6vXYAS0SaYo67e5rpbS5THtPtI5Epz3s9cYAf9VR4Ht6UclEB5iAnTvfl+NiNqfwqwXiOspjLPQiRG8p3RfJBmILD7fF74upqMQMTZNR3dX1RyKYAlf52Fl8pvi8nswFcV11CJbcJFMlHuyqv8r1x7sF93nPiITCDAY4YEDZWPtv0HPZbO5ySbZHW9xbssULeAkFufQZ/thD6DxJCi7VRJYes9hYACZbo0sGXne5XDS5Yx/46CVqDbse/jkgCrx32z0z79xufyr+ot9vUQkNIk0/AR44Xp8Jcrmr/X8f1lhsB62/1x3o1O1KJjW9HRPHhR9E8qwNbu3fJzjGJ2T5YyRodDBh1WIsRecGD2oc/aHfbYTLleUIkaF4ywe9XotnNdXE+2AIDZUIu6n4c/5FEPwDpUueJ4Tp9k8+0OWRmWMKDI4nBMsQl78/UW5ztdVu/cLE9zt7D3HhyQEhqD9i5hVXxOIkTI0U//nf+BZWPBGkwxAujRCgHUo83KHF2/rtvvaHVaeLCtDI3KHBfgR3IYbBZfOSKN9t7Pt/SyFiuO+OXYDMzpDJxjLHxbBHQDtDt2r5p3Gm8nG3WssxSuRpEBus11wtbcjXlF2mXLsAl1wCMvARg12hIujsTyX93eiDPM9fBMzi/vFbFUOpWiA1wr9v/dDH7eMYbYiSIg4yl/RGFtCLvn6HbxwUkiYKS3TCv/o3gjbNRpr6fx9S+slOi3AgEtxdTTwarmmGxIW3MIC1ttWgDOIDKCR5UKIW49MPA9YXncu1oMKGb8O5oegsXc/GYpBkBlJQcoCzYKXZweonUUybw20/ubLULaB7u4MKBsN2b+StKx+79GvhVXFstIGp5avC1FRLQzt0TnQq9mYErtlpdZptJP8ICL6VD9ixgiWv9h7xNkCODRVkl3iMLjqfEW2qAZEvHHFMqRPP0ahgx7pp+hgFZPwKU0mjPKeUXl8krbNPXMeEIIKU4IHI0x3mpIfJqIYGm8frGZkdEgeHdiebGnPkRSMwQS5nPieC6CCoi0njCZkSNzttDzq606Hg+uAeO6k8sdlYJMnnVChv1lV5PjJPeHCPiWzQ5OjVeB2Eev+ZRsYt9H3ki7ze7YVwsVr0uI9Oq4T2F71RffnMEi85KedLxjLysvnZX2sUg1vhKCdBfIGsAD2WknQG+UifpDs+lBI4+lxP+BreYfl0r/B83QtGC43dNsT6U/tlrhi6AlVMRXn4PtnpTty596UHw/q7nIST+ypHUfADM1CFQJTqpQG5UbAOH9Nx+mz32w0nG+e/owYNzindwUlSLihC1265vOzGpP3xZFwPKHT15sdqcruYTTkrbWxzpsoOrjyZb4iobm6VNhIB2RPlTwGjUMtx1uUnum0VzuS7x7xpo8CjYM6HuyYfu/jacSvKPqPn1A2TrS2CmIxl4Nb59/V9OjhS75lWzk5rUXo7SLHSmTnwBMg77E4cxSlfVHeRvxSDXS4KdCgvq3owWlaIw==","layer_level":3},{"id":"a4a4d47c-bb91-469b-9531-67491f9f186f","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Build Helper Scripts","description":"build-helpers","parent_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","order":4,"progress_status":"completed","dependent_files":"build-linux.sh,build-mac.sh,build-mingw.bat,build-msvc.bat","gmt_create":"2026-04-19T22:01:25+04:00","gmt_modified":"2026-04-19T22:03:11+04:00","raw_data":"WikiEncrypted:zhwwHcEGfkuzROuyPGwGZD/0WI/CTybfsgnvf0a+/fBPmrYtLd5NuaTqipWJR9I45kt0KlRWyKnQXBlUGFuKVXIWHd8zpK1bD/dws3Y+0y5bmVLWHKp6dzQZhaCQ8PqdbqH6Ef6BOExueeAKMrg3VG4nGQ4qnkwQuwN3IYhGJSf0t1yOpT1aqpbR+u9hEgg+mf/t+np2afE7VAT75QUC3xAJ/6WmRABeDId8fKJ8AJi2YCHWLM/x6M/vbZTtQNbB3k8sTMjZxrWdv7Jdh1CgCg==","layer_level":2},{"id":"77fc8335-bca5-4260-9f79-76df553d0950","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"API Reference","description":"api-reference","prompt":"Create comprehensive API documentation for the VIZ CPP Node JSON-RPC API system. Document all public API endpoints organized by functional categories including database API for blockchain state queries, social network APIs for content and user interactions, governance APIs for committee and proposal management, and custom protocol APIs for specialized business logic. For each API group, document HTTP methods, URL patterns, request/response schemas, authentication requirements, and error handling. Include practical examples showing common API usage patterns, parameter specifications, and response interpretations. Document WebSocket endpoints for real-time data streaming and subscription management. Address rate limiting, security considerations, and performance optimization. Provide client implementation guidelines and common integration patterns. Include migration guides for API changes and backwards compatibility notes where applicable.","order":5,"progress_status":"completed","dependent_files":"plugins/database_api/,plugins/social_network/,plugins/committee_api/,plugins/custom_protocol_api/,libraries/api/","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T11:26:06+04:00","raw_data":"WikiEncrypted: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"},{"id":"29346336-4f9c-4ae7-9233-d7d4ccef1e6e","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Block Log Reader Module","description":"block-log-reader-module","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":5,"progress_status":"completed","dependent_files":"libraries/chain/include/graphene/chain/block_log.hpp,libraries/chain/include/graphene/chain/dlt_block_log.hpp,libraries/chain/block_log.cpp,libraries/chain/dlt_block_log.cpp","gmt_create":"2026-04-14T14:39:36+04:00","gmt_modified":"2026-04-14T14:41:40+04:00","raw_data":"WikiEncrypted:R9i/29qd1Uv5xEgS1tKQyI1I0rpdsO9IumbhMrSZOSV7pWU+H3/REFsGh6aDTot4hNxJPS2VAN0rfbzcg4VekaBmG/Alt/nqGifIFlLhScM8FHHmLRuS2zB0uFzQkJdXUBV23GOZdcOPSusr1YBSe5C1pBy92GXe11lEhG++DJeD7uDwx/BwFgme27p7RN3ShHGpOKO6KZLVq4NtrBbRqXBgj+BPN896vHdpQsGPy1Z9xdzm3DDw7+wmkNL+5lwLXW+0miCGz0DCrZ8PWFoJJhE3W1JhA/46ieUfQOPY78J4877vX/mqkUnYqvTQFp7WP5nOGjPH/csixyLK1BUw6K2TEcBagf+in3k6twTXnVUyf1ZZPU/VpryPBLYtnWHcOZgglvMtupZVMfciEg1Ziasrbccx96hkUHVxE6c59taZWMVDyPuepIVEIVVoBJZJ","layer_level":3},{"id":"1c7c44d6-22c3-42c5-953f-357d54ffc8ad","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Originating Peer Tracking","description":"originating-peer-tracking","parent_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","order":5,"progress_status":"completed","dependent_files":"libraries/network/node.cpp,plugins/p2p/p2p_plugin.cpp,libraries/network/include/graphene/network/node.hpp","gmt_create":"2026-04-28T22:31:26.0072844+04:00","gmt_modified":"2026-04-28T22:34:00.325344+04:00","raw_data":"WikiEncrypted:Vf/2EfYbH0IRFc1VwBfj5SHqpGLD7tVUjbXPvqCoV3C7/EOAaOOTRP35BEvVpaDiiCmbSBwF+8d00H2lYCKAr6IKI5OcjZmUTqgeVF/tPsb3pOh/sfmhgjTy0ddmB054gPxFO7LYEZYupbH1TmEn7wSlT9F8WQ+4ootXTjq2gHlpPMRfgqhQT1xQuFmlCszmkkhoWj1O5J/tRs99K9vXv9SNvRkG/Kawaa98SdVnHbA/jkdcb1EhIeiGsKbgG41pT3RJw6V0LyOoBYSfXjtXzpHRzaGp60neB1cDUM6erdvqtjYCL7nlmeDXeDAuI2GHifn3VUcwsfWVyjpO9U534g==","layer_level":3},{"id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Configuration Management","description":"configuration-management","prompt":"Create comprehensive configuration management documentation for VIZ CPP Node. Document the complete configuration system including configuration file structure, runtime parameters, and environment variable overrides. Explain different node types (full node, witness node, low-memory node) and their specific configuration requirements. Cover network configuration including seed nodes, listen addresses, and peer connectivity settings. Document plugin activation and configuration, performance tuning parameters, and logging configuration. Include practical examples of common configuration scenarios such as production deployments, testnet setups, and development environments. Address Docker-specific configuration, container environment variables, and volume mounting for persistent data. Document build-time configuration options, compiler flags, and feature toggles. Provide troubleshooting guidance for common configuration issues and validation techniques.","order":6,"progress_status":"completed","dependent_files":"plugins/chain/plugin.cpp,plugins/snapshot/plugin.cpp,plugins/witness/witness.cpp,share/vizd/config/,CMakeLists.txt,share/vizd/docker/,documentation/building.md","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-04-23T11:18:10+04:00","raw_data":"WikiEncrypted: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"},{"id":"612848bb-0178-4a56-b82c-aefc05b2cae9","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Memory Management System","description":"memory-management-system","parent_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","order":6,"progress_status":"completed","dependent_files":"thirdparty/chainbase/include/chainbase/chainbase.hpp,thirdparty/chainbase/src/chainbase.cpp,libraries/chain/database.cpp,plugins/p2p/p2p_plugin.cpp,plugins/witness/witness.cpp,libraries/network/node.cpp,libraries/chain/include/graphene/chain/database_exceptions.hpp,libraries/network/include/graphene/network/exceptions.hpp","gmt_create":"2026-04-23T07:21:32+04:00","gmt_modified":"2026-04-29T06:53:57.1834315+04:00","raw_data":"WikiEncrypted:4UGnUWsfWDZbqjKXeP7l3nIFoUg1QR8mX7Mg3xz3Yqw2RQAhFYQlnJrNzDWK62g0p28n0x68xCnCqGl889LahGm2SmDbdbatAKMUU6rWXYBKNn6+N3eH9m9gUn1MBPeGPJPHmyJDQng37bgqLvcdCCzuu17Ub3i4B1eusNKAczpEh9B4otX++juvK+SOqz4uuxqM+jzfKiGwBdlUp7esUiYKYKGCt6g83LkJ2qX2/Eepyk6bKUccX8yqa6TEzS2DkYADCyD6mz1pYmB0HSgQblgT20mPlTcQGuVPirNpZgO4k28aUJ1k0m2W0gcvQKSw5XQhaXeeebb314Q2scMUuIIxLxSgDeuvMdtW3X9EWgR0yuwws3QZ4t7i2epJi2VEAkCbAs6ZamIEz9GQ7Fivc2eik/s8ZVu+IAX2PTccFCouIF8NvsF1vrXJdxOXB/g60KZhuX2xSIqxpycKaDTmDYuh1PdJ4hWqJ2Zqn+of7Si6aSYTBsPnYniYIMfVfmkcruGyBHiznC3j15v0K/FUy1oust+OSkYN4epr7dy/wyzutivgrdWNvNccR8EGkbvg5kDeGJBwZXZVt4sFFZUWLOByQS7SO1jgVOE4xR4d3iQgM2MhIZ2Jl5AfgU+tbtNXv1q7vJNiYhuNTl1Sr8QcBA==","layer_level":3},{"id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Development Tools","description":"development-tools","prompt":"Create comprehensive development tools documentation for VIZ CPP Node. Document the complete development toolkit including the CMake build system, cross-platform compilation instructions, and Docker-based development environments. Cover the testing framework with unit tests, integration tests, and performance benchmarks. Document debugging tools including the debug node plugin, transaction serialization utilities, and network debugging capabilities. Explain the development workflow including code style guidelines, pull request processes, and continuous integration. Include practical examples of common development tasks such as building custom plugins, running tests, and profiling performance. Address code generation tools, schema validation utilities, and development environment setup. Document the relationship between development tools and the overall project structure, making it accessible to contributors while providing sufficient technical depth for advanced development tasks.","order":7,"progress_status":"completed","dependent_files":"programs/,documentation/testing.md,programs/util/,.github/workflows/","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:35:27+04:00","raw_data":"WikiEncrypted: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"},{"id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Deployment and Operations","description":"deployment-operations","prompt":"Create comprehensive deployment and operations documentation for VIZ CPP Node. Document production deployment strategies including hardware requirements, security hardening, and performance optimization. Cover Docker containerization with different image types (production, testnet, low-memory) and orchestration options. Explain cloud deployment options, load balancing considerations, and high availability configurations. Document node types including full nodes, witness nodes, and seed nodes with their specific requirements and operational procedures. Include monitoring and maintenance procedures such as log management, health checks, database maintenance, and performance optimization. Address security considerations including firewall configuration, SSL/TLS setup, and access control. Provide troubleshooting guidance for common operational issues, performance bottlenecks, and recovery procedures. Document backup and disaster recovery strategies.","order":8,"progress_status":"completed","dependent_files":"share/vizd/docker/,share/vizd/vizd.sh,share/vizd/config/config.ini,documentation/testnet.md","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:36:27+04:00","raw_data":"WikiEncrypted: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"},{"id":"7a20b53f-0b97-40ec-a630-7e9171a04006","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Advanced Topics","description":"advanced-topics","prompt":"Create comprehensive advanced topics documentation for VIZ CPP Node. Cover complex subjects including hardfork implementation and management, database schema design and optimization, security considerations and vulnerability assessment, and advanced plugin development patterns. Document the hardfork system including version management, migration procedures, and backward compatibility handling. Explain database design patterns including object persistence strategies, index optimization, and fork database implementation. Address security topics including cryptographic implementation, API authentication, network security, and vulnerability mitigation. Cover advanced plugin development including custom evaluators, database object extensions, and inter-plugin communication patterns. Include performance optimization techniques, memory management, and scalability considerations. Provide expert-level guidance on extending the core functionality and integrating with external systems.","order":9,"progress_status":"completed","dependent_files":"libraries/chain/hardfork.d/,libraries/chain/include/graphene/chain/chain_object_types.hpp,plugins/test_api/,documentation/plugin.md","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:37:26+04:00","raw_data":"WikiEncrypted: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"},{"id":"827bb973-d548-4605-9a5b-103c1b308c31","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Troubleshooting and FAQ","description":"troubleshooting-faq","prompt":"Create comprehensive troubleshooting and FAQ documentation for VIZ CPP Node. Document common build issues and their solutions including dependency problems, compilation errors, and platform-specific issues. Cover network connectivity problems such as peer discovery failures, sync issues, and firewall configuration. Address performance optimization including memory usage, CPU utilization, and disk I/O optimization. Document error message interpretation and diagnostic procedures for various failure scenarios. Include frequently asked questions about node operation, API usage, plugin development, and integration challenges. Provide systematic debugging approaches using the debug node plugin, log analysis techniques, and diagnostic tools. Address recovery procedures for common failure scenarios including database corruption, sync desynchronization, and configuration errors. Include community resources, support channels, and escalation procedures for complex issues.","order":10,"progress_status":"completed","dependent_files":"documentation/building.md,documentation/debug_node_plugin.md,documentation/testnet.md,share/vizd/config/config.ini","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:37:39+04:00","raw_data":"WikiEncrypted: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"},{"id":"0e7eda4e-d736-4dea-834b-eb08eb84d4d9","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Contributing and Development","description":"contributing-development","prompt":"Create comprehensive contributing and development documentation for VIZ CPP Node. Document the development workflow including code style guidelines, commit message conventions, and review processes. Explain the contribution process from issue identification through pull request submission and merge. Cover code quality standards including testing requirements, documentation expectations, and performance criteria. Document the plugin development contribution process including template usage, testing requirements, and integration guidelines. Address community contribution opportunities including bug reporting, feature requests, and documentation improvements. Include practical examples of common contribution scenarios such as fixing bugs, adding features, and improving documentation. Document the relationship between contributions and the overall project governance, licensing requirements, and intellectual property considerations. Provide guidance for new contributors on getting started with development and finding suitable projects to contribute to.","order":11,"progress_status":"completed","dependent_files":"documentation/git_guildelines.md,documentation/plugin.md,documentation/api_notes.md,programs/util/newplugin.py","gmt_create":"2026-03-03T07:27:58+04:00","gmt_modified":"2026-03-03T07:37:44+04:00","raw_data":"WikiEncrypted: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"},{"id":"a85aa407-665b-425b-b5e1-fc693d469cd7","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Witness","description":"witness","order":12,"progress_status":"completed","dependent_files":"plugins/witness_guard/witness_guard.cpp,libraries/chain/database.cpp,plugins/witness/witness.cpp,plugins/witness/include/graphene/plugins/witness/witness.hpp","gmt_create":"2026-04-13T21:23:28+04:00","gmt_modified":"2026-04-30T12:39:24.2387906+04:00","raw_data":"WikiEncrypted:JeTXIs+pfWQp8HpBYqSHUt9pgs+Z3ta6nCRipvtinj2ZibPEEeHHjj4s1YQflAL5kw0thomwlF/m298PbgVpHcMYZUHRQqAsMYtr07dfBLOo+zFv+W+D15w/E/4EN0I18VG1kogm2C52/pqntBpMHHQWi2HWNMI83JaiO1F0VurwzKmQ65PYBSw4dXAs+l4jeUjO8SswzVE6OFsp8RNPdj0h5kBtGKesfwW3SOqa0AxZmIqU3jg38nTzAw9BnYUr83UhDetPgX8JPXzWIjalYZ3vcjLVMNl7bpTm957vtBwxp1CmZoONclppVImQSxAI3YqFVGGTJbkeptK6yWB2GNGwOs1o0276HfIKxOMC37BlJ44emeXqvsTqlYCdSu5b"},{"id":"336017d8-00e0-43f8-afef-4d3d4a2e5ccb","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Webserver Plugin","description":"webserver-plugin","order":13,"progress_status":"completed","dependent_files":"plugins/json_rpc/plugin.cpp,plugins/webserver/webserver_plugin.cpp,documentation/webserver-plugin.md","gmt_create":"2026-04-14T09:27:36+04:00","gmt_modified":"2026-04-23T15:42:30+04:00","raw_data":"WikiEncrypted:DVkoReQyyhdwnmC6pD+XJl1726hWlyrdb/kexi9P3mlDxrXesxG0TGa6cLaC0YXste3eGQsJLCuBJsmN7jS41YrtOzDmXjZ20dpluGZh7TF8d5Ih/dkUyBAv83zgG5dT5X/GX2Xf8jjsJPRMiH5sknmR3OG8wocD5A9ncHBEVFRyBp0HihXukxhHlpTsrCQUq/zYGQhCvSGL3yzBUH/lFvEHVNY6wumep+VY9J36gqSbAsRpvnsVgmmROXkXabCmVhKGXF5QLsRelkbIqbSqDh/TeX+yd1kbbAhQ4VkC2JqtmnY6UJeSCFsR3Ul9lwh/"},{"id":"cff6b813-9c5a-4ab6-a45c-f9382c25ff61","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Chain Plugin","description":"chain-plugin","order":14,"progress_status":"completed","dependent_files":"plugins/chain/plugin.cpp,plugins/chain/include/graphene/plugins/chain/plugin.hpp,libraries/chain/database.cpp,libraries/chain/include/graphene/chain/database.hpp,share/vizd/config/config.ini,share/vizd/config/config_witness.ini","gmt_create":"2026-04-20T08:54:36+04:00","gmt_modified":"2026-04-29T06:59:11.3226702+04:00","raw_data":"WikiEncrypted:2nxDQCjwbtJzhDuGjsVF7mHsV7DvjvnRRbUVGKq7sKBjc03f9mwX6sCrl1O98+zpUP3CrZGNY7+od97OqysKwp6V8pyGSudE2hJ3DdykrmiIDKhcn3MAes8dpg0JRzFtSSQgwpIZiOnespKZn4hpTLOyeq4hVG5hqc6ABc/sw/nvfHWfqyo65GeakfCQ+gpaGSQjBupzQlsscQ+/o/hMvQU/XNc8xpL81ukyIZXuDZfJKuk7FwaGm3cFsv9MqXrj+A7BEF1Xq4aPataHskdRoX8p40Ykjyeal642bhpYLpWd+dPPT9HsVOna+wKQS7r/ZgGRsPVLIOqyAXu8QV79wV+K4ht4iIZXx/61hOyRV3r2ukL9YPAtUVPy5ihSo50NJ7lXFfJ/fZ1JeC9T7rG7WMnAehMmhvxLQFtaeZuwB8rT1TE591uoSHLFcc23qiBrZ7f5w8wUp2DgWU6LKwjhfjDS+ELv3bx6bsW4SFi3/2k="},{"id":"766a7066-9703-4342-a54b-f827e0e13757","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"P2p Plugin","description":"p2p-plugin","order":15,"progress_status":"completed","dependent_files":"plugins/p2p/p2p_plugin.cpp,plugins/p2p/p2p_plugin.hpp,plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp","gmt_create":"2026-04-23T11:49:52+04:00","gmt_modified":"2026-04-30T11:12:37.5129528+04:00","raw_data":"WikiEncrypted:LjUwH/yUcbWfnBumtHMxuKISe72JbF8T+AYe9w/08E+XtSR36PLbVQBinOspVDlWetMPFkhRiTMoRAUUG8lGn0m5x7RHi+E+u8xLwer77SCrno3g0kQXsOkD1Q1KBhNs+BVWEhWp1jKV61HpFgn7Ii2DSYcoPqruBnuf9DUj0GmPTp6uczQEOm0dKxUy+TvURdnCFU8uhpNAss/Dq1MH66dQNLpms7Ha1KR1P26a88f2fsbRkeCIp8bKCrmbV/B/wyJvUzBcFMNlqsuwBDC3tpY6mVYiEpVoupNHqujr0CG2ziqC/HV+tso3ofU/UAGu"},{"id":"e09223c9-c6d0-4de2-bc9e-e71b821821e9","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"Logging System","description":"logging-system","order":16,"progress_status":"completed","gmt_create":"2026-04-28T22:07:50.137316+04:00","gmt_modified":"2026-04-28T22:09:11.9888453+04:00","raw_data":"WikiEncrypted:yXtkOK/klHQ6fg8DXtAtTgXcdJlvAxws0gHlGuZdj1Nq0qCgdW36gO4KWZvggEHP3mw5DUw7tq468fzgZ4wHWUCLlo4HtkDTFqTWGh+xHCjmGARpn3yWzRgRrE9LGGpCxnS4z/0db4/mvocXTFSTmz6AFUcRoyFLbPag4UL5FZc="}],"wiki_items":[{"catalog_id":"cb549eb1-0a24-4153-9474-eae1ed48e8e1","title":"Getting Started","description":"getting-started","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"7803d50e-ee66-4670-83ec-32f2c6719409","gmt_create":"2026-03-03T07:31:32+04:00","gmt_modified":"2026-03-03T07:31:32+04:00"},{"catalog_id":"80d9e7dd-fa35-469c-bd78-95cb6616e64c","title":"Project Overview","description":"overview","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"299812b4-7d0c-42f7-b530-6d057ba096bb","gmt_create":"2026-03-03T07:31:56+04:00","gmt_modified":"2026-03-03T07:31:56+04:00"},{"catalog_id":"8aeac580-587b-43f3-9292-e62e4d3781f7","title":"Architecture Overview","description":"architecture","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"419b0fb1-31a5-4b4b-87f1-7adba3743630","gmt_create":"2026-03-03T07:32:30+04:00","gmt_modified":"2026-03-03T07:32:30+04:00"},{"catalog_id":"77fc8335-bca5-4260-9f79-76df553d0950","title":"API Reference","description":"api-reference","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"4c1475f4-4dd1-4888-8a4e-dde1e0cec83c","gmt_create":"2026-03-03T07:33:49+04:00","gmt_modified":"2026-03-03T11:26:06+04:00"},{"catalog_id":"ad096386-ea33-44d1-b9f2-261f11fb24d5","title":"Plugin System","description":"plugin-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"f5eb1fa5-a4ca-4e54-b68b-b234545fb8ce","gmt_create":"2026-03-03T07:33:58+04:00","gmt_modified":"2026-04-23T09:46:06+04:00"},{"catalog_id":"7e383bdb-11dd-48d6-bd47-4d350e2df438","title":"Core Libraries","description":"core-libraries","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"ecd87c29-4938-4318-9bbb-b3c2a87a2d22","gmt_create":"2026-03-03T07:34:30+04:00","gmt_modified":"2026-04-19T22:31:11+04:00"},{"catalog_id":"d896ebd6-7a89-4c1c-a16d-8acb2a61bb9c","title":"Development Tools","description":"development-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"4493b728-953f-4c7d-9b30-89aa33255a3b","gmt_create":"2026-03-03T07:35:27+04:00","gmt_modified":"2026-03-03T07:35:27+04:00"},{"catalog_id":"6ca6368d-78f2-436a-89d8-8e2fa9c3d925","title":"Configuration Management","description":"configuration-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"e885f837-dcb8-4f4a-b0ff-5c620c375d5e","gmt_create":"2026-03-03T07:35:41+04:00","gmt_modified":"2026-04-23T11:18:10+04:00"},{"catalog_id":"ea5be69a-46ea-4304-9d86-597c6f7fc254","title":"Deployment and Operations","description":"deployment-operations","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"cafaced8-cceb-47ca-9052-70e14192d570","gmt_create":"2026-03-03T07:36:27+04:00","gmt_modified":"2026-03-03T07:36:27+04:00"},{"catalog_id":"7a20b53f-0b97-40ec-a630-7e9171a04006","title":"Advanced Topics","description":"advanced-topics","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"43570872-cdce-4428-b8dd-dd01164aa9b3","gmt_create":"2026-03-03T07:37:26+04:00","gmt_modified":"2026-03-03T07:37:26+04:00"},{"catalog_id":"827bb973-d548-4605-9a5b-103c1b308c31","title":"Troubleshooting and FAQ","description":"troubleshooting-faq","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"63ed2c61-53af-4c7c-aaf3-7d8586a249e8","gmt_create":"2026-03-03T07:37:39+04:00","gmt_modified":"2026-03-03T07:37:39+04:00"},{"catalog_id":"0e7eda4e-d736-4dea-834b-eb08eb84d4d9","title":"Contributing and Development","description":"contributing-development","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"aa5583cd-5e97-4e63-b478-467c9d34674e","gmt_create":"2026-03-03T07:37:44+04:00","gmt_modified":"2026-03-03T07:37:44+04:00"},{"catalog_id":"86d4d313-8f5e-4334-b5d1-220ec01d0971","title":"System Overview","description":"system-overview","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"fec1e146-3e5c-4c90-9824-44c18fd37d36","gmt_create":"2026-03-03T07:39:03+04:00","gmt_modified":"2026-03-03T07:39:03+04:00"},{"catalog_id":"9cfa64b0-5249-4b35-ae4c-c94b4ab1b246","title":"Build System","description":"build-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c4b8579d-6410-4a31-8523-e38a9b1d69d3","gmt_create":"2026-03-03T07:39:35+04:00","gmt_modified":"2026-04-21T16:26:53+04:00"},{"catalog_id":"4b6cb85a-4799-425e-9f98-9cd149c004ec","title":"Node Deployment","description":"node-deployment","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"101024ac-5da4-4315-80c7-0cd7955ea4f8","gmt_create":"2026-03-03T07:40:48+04:00","gmt_modified":"2026-03-03T07:40:48+04:00"},{"catalog_id":"61febd56-5be6-448d-b2a2-26975fe33d8d","title":"Node Configuration","description":"node-configuration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0fc8c6be-5e2e-4d16-aa17-5e6b88335450","gmt_create":"2026-03-03T07:40:51+04:00","gmt_modified":"2026-03-03T07:40:51+04:00"},{"catalog_id":"56a9c3df-f2c3-4f59-8729-1fed0fcdb9d2","title":"Hardfork Management","description":"hardfork-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"d992f398-cce4-49e2-a21a-44ff13893da3","gmt_create":"2026-03-03T07:41:25+04:00","gmt_modified":"2026-04-20T11:24:22+04:00"},{"catalog_id":"cbaaeab2-9ed7-42e0-888e-58f1dff3747b","title":"Testing Framework","description":"testing-framework","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0cb251fd-c588-4acc-8c03-1b2980db606b","gmt_create":"2026-03-03T07:41:49+04:00","gmt_modified":"2026-03-03T07:41:49+04:00"},{"catalog_id":"2c57cd51-91bf-4148-bbc4-53fda0ff7ec3","title":"Build Configuration","description":"build-configuration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"efbfc523-380a-4c5c-89b1-b1b22375fdd1","gmt_create":"2026-03-03T07:42:49+04:00","gmt_modified":"2026-04-23T06:46:47+04:00"},{"catalog_id":"7c381449-9427-4fc2-ab03-1a1301da306b","title":"Containerization and Docker","description":"containerization-docker","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"46914ef3-870f-4299-b0b1-9b5d299c5cad","gmt_create":"2026-03-03T07:43:26+04:00","gmt_modified":"2026-03-03T07:43:26+04:00"},{"catalog_id":"64b99394-2424-4a81-ab2a-f41d1b9e973c","title":"Plugin Architecture","description":"plugin-architecture","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c6931d42-c58d-4696-88f0-c17996821ffa","gmt_create":"2026-03-03T07:43:34+04:00","gmt_modified":"2026-04-15T13:00:48+04:00"},{"catalog_id":"ac1c2473-448f-4372-9f6e-3715d530d978","title":"Database Schema Design","description":"database-schema-design","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c9cc2572-d693-45ec-a7b0-6a1fa0a3d47e","gmt_create":"2026-03-03T07:45:31+04:00","gmt_modified":"2026-03-03T07:45:31+04:00"},{"catalog_id":"614f1169-202f-4dd4-aaa5-360a10ad6bd8","title":"Debugging Tools","description":"debugging-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"3db3b667-c9b0-4ef0-bdbd-1e4638995b5c","gmt_create":"2026-03-03T07:45:42+04:00","gmt_modified":"2026-04-28T19:48:38.9116038+04:00"},{"catalog_id":"139b0217-0190-433f-b41d-60fa08c9ee5f","title":"Core Libraries","description":"core-libraries","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"724010bf-a048-4a08-bf63-fc4bcac656b4","gmt_create":"2026-03-03T07:46:01+04:00","gmt_modified":"2026-03-03T07:46:01+04:00"},{"catalog_id":"3834864b-3db0-4e65-a23c-0fcd2d2759ec","title":"Cloud and Infrastructure","description":"cloud-infrastructure","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"760f37d6-5fcd-49a4-ac1d-f5e886377331","gmt_create":"2026-03-03T07:46:55+04:00","gmt_modified":"2026-03-03T07:46:55+04:00"},{"catalog_id":"28bb2a2e-23c2-4009-8847-35e8fac1f151","title":"Security Implementation","description":"security-implementation","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"4f51c881-94ed-4e49-b8cf-e3b1fab21e0e","gmt_create":"2026-03-03T07:47:20+04:00","gmt_modified":"2026-03-03T07:47:20+04:00"},{"catalog_id":"9d487fbd-32f6-4e37-acf4-e314d7f75019","title":"Docker Configuration","description":"docker-configuration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"ecdb8c95-8cbb-4c16-b315-822594095634","gmt_create":"2026-03-03T07:48:32+04:00","gmt_modified":"2026-04-17T17:31:31+04:00"},{"catalog_id":"9091fce8-eb05-4150-ae9b-eaeb0c47be15","title":"Development Workflow","description":"development-workflow","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"be44fe88-0512-4e4b-a4b8-9e082214a604","gmt_create":"2026-03-03T07:48:38+04:00","gmt_modified":"2026-03-03T07:48:38+04:00"},{"catalog_id":"a486a2be-4bcb-4205-83fd-2ab48f89829b","title":"Data Flow and Processing","description":"data-flow","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"9e5f8d60-bebb-4161-a630-0880704f9f81","gmt_create":"2026-03-03T07:48:50+04:00","gmt_modified":"2026-03-03T07:48:50+04:00"},{"catalog_id":"30dbc846-1f3e-44d5-a93a-988c973d064f","title":"Advanced Plugin Development","description":"advanced-plugin-development","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"09728486-f6d3-4cf1-bb8b-b5b404117331","gmt_create":"2026-03-03T07:50:18+04:00","gmt_modified":"2026-03-03T07:50:18+04:00"},{"catalog_id":"b52a3e7c-7bc9-46ea-afb3-610c7430eb21","title":"Network Configuration","description":"network-configuration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"52d914f6-5cef-4a53-bd37-4c7c074ddcb2","gmt_create":"2026-03-03T07:50:58+04:00","gmt_modified":"2026-04-23T12:16:49+04:00"},{"catalog_id":"c5e155d7-00b2-4e55-811e-cffb5860ac55","title":"Design Patterns and Architectural Decisions","description":"design-patterns","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"06bc216a-07e4-48fb-bdff-38335db957cc","gmt_create":"2026-03-03T07:52:04+04:00","gmt_modified":"2026-03-03T07:52:04+04:00"},{"catalog_id":"bcdd0730-3bcf-4e55-aeac-7cc0a351046b","title":"Plugin Lifecycle and Registration","description":"plugin-lifecycle-registration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"cc17934e-5862-4f4b-99a7-0ed4fd1c2e2a","gmt_create":"2026-03-03T07:52:10+04:00","gmt_modified":"2026-04-20T10:26:06+04:00"},{"catalog_id":"bf5ec7d7-d376-4b39-8781-5b76b3e90e2b","title":"Monitoring and Maintenance","description":"monitoring-maintenance","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"a3afccb6-22df-4d5b-bb93-2f591af782bf","gmt_create":"2026-03-03T07:52:29+04:00","gmt_modified":"2026-04-21T15:57:29+04:00"},{"catalog_id":"08c2583a-92f0-4c14-aa9d-736878711ba1","title":"Transaction Processing Pipeline","description":"transaction-processing","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"28f563ee-bb1b-42be-8243-e7bfa17eb793","gmt_create":"2026-03-03T07:53:30+04:00","gmt_modified":"2026-03-03T07:53:30+04:00"},{"catalog_id":"317287b2-3937-4876-97d0-a8c96007d95c","title":"CMake Configuration","description":"cmake-configuration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"e9540698-3e7d-4a1c-bdaa-0d96c8be0745","gmt_create":"2026-03-03T07:53:46+04:00","gmt_modified":"2026-03-03T07:53:46+04:00"},{"catalog_id":"3690c93b-e823-4c69-8ec9-862feb3c3549","title":"Unit Testing Infrastructure","description":"unit-testing-infrastructure","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c08ac7ca-a94d-4e15-8e9e-3dae3b1a5752","gmt_create":"2026-03-03T07:54:54+04:00","gmt_modified":"2026-03-03T07:54:54+04:00"},{"catalog_id":"ff9d9cb4-10d6-40dd-a6c6-47f4665aee8b","title":"Debug Node Plugin","description":"debug-node-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"589f3f8e-0048-4b0d-befe-693f063b0ce4","gmt_create":"2026-03-03T07:55:19+04:00","gmt_modified":"2026-03-03T07:55:19+04:00"},{"catalog_id":"e02c38ec-2618-428e-b338-f93cfe94dc72","title":"Chain Library","description":"chain-library","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"4f950ad3-7c9b-4d85-8ae3-b1b342b6ce31","gmt_create":"2026-03-03T07:55:53+04:00","gmt_modified":"2026-04-23T11:18:36+04:00"},{"catalog_id":"a4025412-2ce8-4c57-91cb-0f16dac0132c","title":"Installation and Setup","description":"installation-setup","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"f7e77aea-7354-410f-a8b6-ad12fbed8361","gmt_create":"2026-03-03T07:56:01+04:00","gmt_modified":"2026-03-03T07:56:01+04:00"},{"catalog_id":"30dc8338-1212-4946-a037-0fcb2222ca44","title":"Inter-Plugin Communication","description":"inter-plugin-communication","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"6ff3d5ed-5a93-44e9-b8fc-ee03618c7b1c","gmt_create":"2026-03-03T07:57:09+04:00","gmt_modified":"2026-03-03T11:26:31+04:00"},{"catalog_id":"4e47c09b-f1e5-4405-8940-c9714fcf5965","title":"Protocol Library","description":"protocol-library","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"b52202cc-02f2-44ed-bba8-d9428b217809","gmt_create":"2026-03-03T07:57:42+04:00","gmt_modified":"2026-03-03T07:57:42+04:00"},{"catalog_id":"0b0666c8-2764-44f1-b24f-7a1cb2afaf30","title":"Block Processing and Validation","description":"block-processing","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"885ce864-d616-4f9f-8a3e-6198a88feda6","gmt_create":"2026-03-03T07:57:58+04:00","gmt_modified":"2026-04-28T12:54:08.1046315+04:00"},{"catalog_id":"afe12b98-5441-4e08-9bd0-d8c604b2dbaa","title":"Code Coverage Analysis","description":"code-coverage-analysis","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"36300f0a-f814-4ee7-8fea-443822b5ee7e","gmt_create":"2026-03-03T07:58:43+04:00","gmt_modified":"2026-03-03T07:58:43+04:00"},{"catalog_id":"d54afe72-4975-48c8-b825-ab792ce92a46","title":"Build Helper Tools","description":"build-helpers","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"18a3eced-7204-4ae6-ace6-9325629f7540","gmt_create":"2026-03-03T07:58:47+04:00","gmt_modified":"2026-04-21T16:26:14+04:00"},{"catalog_id":"514b44cf-1ee9-477f-afb6-86b4f8c17ee2","title":"Transaction Debugging Tools","description":"transaction-debugging-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"3c6c03d8-c73c-48e4-8076-4deaff61fc83","gmt_create":"2026-03-03T07:59:59+04:00","gmt_modified":"2026-03-03T07:59:59+04:00"},{"catalog_id":"eb3e00ca-26ca-455a-8670-e309bca1ae7d","title":"Node Types and Configurations","description":"node-types-configurations","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"7e78b6cc-7d2d-4326-820e-37969b08647b","gmt_create":"2026-03-03T08:00:19+04:00","gmt_modified":"2026-04-21T15:32:31+04:00"},{"catalog_id":"fb7f5918-6ff3-4fba-89b3-37eef3bf402f","title":"Custom Plugin Development","description":"custom-plugin-development","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"20e80b63-adb3-4fae-a0ff-7b4553335673","gmt_create":"2026-03-03T08:00:20+04:00","gmt_modified":"2026-03-03T08:00:21+04:00"},{"catalog_id":"0ffb65de-cf29-46a1-a84e-5b7531aaa9cf","title":"API Request Processing","description":"api-request-handling","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"f8aac207-e623-4724-8003-ced4b4d90bf8","gmt_create":"2026-03-03T08:01:46+04:00","gmt_modified":"2026-03-03T08:01:46+04:00"},{"catalog_id":"3789801b-aaa1-4c34-a35a-c5b48338520a","title":"Docker Integration","description":"docker-integration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"bf24a62f-5138-4dfb-9ecb-9d4133953010","gmt_create":"2026-03-03T08:02:06+04:00","gmt_modified":"2026-04-17T10:15:28+04:00"},{"catalog_id":"5bb14590-6784-4cf5-b371-7c3778519d8e","title":"Service Integration","description":"service-integration","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"3b02cb64-064b-4b4c-804e-62b2ba00d9ad","gmt_create":"2026-03-03T08:03:49+04:00","gmt_modified":"2026-03-03T08:03:49+04:00"},{"catalog_id":"02937d37-0e8d-4e1e-8464-7e8c7717aaea","title":"Network Library","description":"network-library","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"ed702015-695e-4ef5-87fc-be4645f73987","gmt_create":"2026-03-03T08:03:52+04:00","gmt_modified":"2026-04-28T21:31:00.4625046+04:00"},{"catalog_id":"be25befd-151b-41db-97bd-3bc570e2cf2d","title":"Network Debugging Capabilities","description":"network-debugging-capabilities","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"7e6094b6-9310-43af-993d-e3bebf0c7ee7","gmt_create":"2026-03-03T08:04:07+04:00","gmt_modified":"2026-03-03T08:04:07+04:00"},{"catalog_id":"e61981dc-5f45-433d-aff8-b4a293795e7e","title":"Event-Driven Communication Patterns","description":"event-driven-architecture","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"aedcc69e-d00f-471d-a338-b290a71a8310","gmt_create":"2026-03-03T08:05:24+04:00","gmt_modified":"2026-03-03T08:05:24+04:00"},{"catalog_id":"95b482d0-a7d5-4c95-92a5-19cfbe2967d6","title":"Plugin API Design Patterns","description":"plugin-api-patterns","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"faf4c29b-a303-4f0e-b3de-f9679789aa09","gmt_create":"2026-03-03T08:05:51+04:00","gmt_modified":"2026-03-03T08:05:51+04:00"},{"catalog_id":"19f906f3-0605-4d92-8d4b-7052dddc5ee7","title":"Cross-Platform Compilation","description":"cross-platform-compilation","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"85f42623-d6f4-4a64-9df9-84d74edb3ff8","gmt_create":"2026-03-03T08:06:47+04:00","gmt_modified":"2026-03-03T08:06:47+04:00"},{"catalog_id":"48f0ee63-f542-40b7-bddc-5746b9b949c8","title":"Wallet Library","description":"wallet-library","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"32f6a790-8183-436f-a550-04552fa6b462","gmt_create":"2026-03-03T08:07:16+04:00","gmt_modified":"2026-03-07T21:45:11+04:00"},{"catalog_id":"3c3c0db5-9be5-46ca-999c-68f9e09ed1b7","title":"Performance Profiling Utilities","description":"performance-profiling-utilities","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"40c4f036-b025-4e82-846a-a71cf89d5e5a","gmt_create":"2026-03-03T08:08:06+04:00","gmt_modified":"2026-03-03T08:08:06+04:00"},{"catalog_id":"9e84e0cf-c0e7-4a82-9101-9152b572c82a","title":"Security Hardening","description":"security-hardening","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"64d83c3f-4775-41fd-9d42-d6c12ca8054b","gmt_create":"2026-03-03T08:08:09+04:00","gmt_modified":"2026-03-03T08:08:09+04:00"},{"catalog_id":"c634ee15-c5d1-4600-8f5b-96016ecb0773","title":"Core Build Options","description":"core-build-options","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"371d43b9-4b79-40d6-a740-d0e09043a493","gmt_create":"2026-03-03T08:11:41+04:00","gmt_modified":"2026-03-03T08:11:41+04:00"},{"catalog_id":"843bdf5b-2dea-4e14-97c9-d8ddaf902f92","title":"Node Management","description":"node-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"9dfed239-6d34-405d-a774-0a99f673e816","gmt_create":"2026-03-03T08:11:43+04:00","gmt_modified":"2026-04-30T07:20:23.8239769+04:00"},{"catalog_id":"eb3415ba-4213-4e37-931c-49f45d7ebe37","title":"Database Management","description":"database-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"295c418f-33b4-4c06-80cf-224d6b633a76","gmt_create":"2026-03-03T08:12:40+04:00","gmt_modified":"2026-04-30T08:00:09.9789246+04:00"},{"catalog_id":"d0aa68e6-4e49-421c-8bfa-6ef641cd6656","title":"Code Assembly Tools","description":"code-assembly-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"6173e746-57a9-469a-ac23-90061ef56ab6","gmt_create":"2026-03-03T08:13:01+04:00","gmt_modified":"2026-03-03T08:13:01+04:00"},{"catalog_id":"85611a9f-1537-4247-b45d-a6a5bcb6a4ca","title":"Production Dockerfile","description":"production-dockerfile","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"9c3a79b2-0a34-4da6-8159-eb775b084846","gmt_create":"2026-03-03T08:13:22+04:00","gmt_modified":"2026-03-03T08:13:22+04:00"},{"catalog_id":"6ab3219a-8693-407a-b403-239fa721b5a2","title":"Transaction Processing","description":"transaction-processing","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"83f9e213-4dbf-4d44-8484-71f9339f5ed7","gmt_create":"2026-03-03T08:14:41+04:00","gmt_modified":"2026-03-03T08:14:41+04:00"},{"catalog_id":"a8c1e706-27c9-4798-b664-a842a70058b4","title":"Object Model and Persistence","description":"object-model","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"81bc0ef1-cb71-44d4-a313-c0adacd3b67b","gmt_create":"2026-03-03T08:15:23+04:00","gmt_modified":"2026-03-03T08:15:23+04:00"},{"catalog_id":"b47bb56b-832d-4e6d-8045-bdbee53d703a","title":"Peer Connection Management","description":"peer-connection","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0505088e-5f10-4252-bc3b-307363fee60d","gmt_create":"2026-03-03T08:16:05+04:00","gmt_modified":"2026-04-30T13:09:18.8212712+04:00"},{"catalog_id":"1ec7edf8-46f7-4e71-ba54-bc1cc3533453","title":"Platform Configurations","description":"platform-configurations","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"818151df-a208-4937-9c96-909884f6bbb8","gmt_create":"2026-03-03T08:16:10+04:00","gmt_modified":"2026-04-17T10:42:56+04:00"},{"catalog_id":"7b9a46a1-f3d0-4034-a4c5-aec28be05f18","title":"Testnet Dockerfile","description":"testnet-dockerfile","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"58e53605-3c83-4017-8c41-9a5919796003","gmt_create":"2026-03-03T08:17:07+04:00","gmt_modified":"2026-03-03T08:17:07+04:00"},{"catalog_id":"180359d7-c289-42ff-9805-28e742c9f10d","title":"Reflection Validation Tools","description":"reflection-validation","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"cbe0e279-74ff-4c6f-bc5d-ac88e9bcc6ac","gmt_create":"2026-03-03T08:17:31+04:00","gmt_modified":"2026-03-03T08:17:31+04:00"},{"catalog_id":"75eb3c5e-02de-4177-8680-a24fd13d2590","title":"Authority Management","description":"authority-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c911bbfb-6d46-458b-ac1c-dbba112490e9","gmt_create":"2026-03-03T08:17:58+04:00","gmt_modified":"2026-03-03T08:17:58+04:00"},{"catalog_id":"c8b8f71a-3ba6-4723-8e51-78c701b5b4ab","title":"Dependency Management","description":"dependency-management","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"93891608-7b30-4aca-9ab2-5d88a2e3225f","gmt_create":"2026-03-03T08:19:13+04:00","gmt_modified":"2026-04-19T22:00:10+04:00"},{"catalog_id":"d7a25826-a156-4b8d-b236-8414ec49a67d","title":"Fork Resolution and Consensus","description":"fork-resolution","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0227cdb3-c369-47eb-9251-d897b9181340","gmt_create":"2026-03-03T08:19:55+04:00","gmt_modified":"2026-04-30T07:19:20.4603602+04:00"},{"catalog_id":"853c4d2b-809f-4ae0-9735-c14d174538d3","title":"Message Handling and Protocol","description":"message-handling","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"8908ad91-79b1-4190-aa7c-9a512f259dcb","gmt_create":"2026-03-03T08:20:04+04:00","gmt_modified":"2026-03-03T08:20:04+04:00"},{"catalog_id":"c387583c-6834-478f-acef-629c155068d6","title":"Low-Memory Dockerfile","description":"low-memory-dockerfile","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"2d5de852-4c30-4e77-8e31-3963f875ae85","gmt_create":"2026-03-03T08:20:43+04:00","gmt_modified":"2026-03-03T08:20:43+04:00"},{"catalog_id":"85a56025-1d98-4b60-bea6-dc4fe9dd9336","title":"Plugin Development Tools","description":"plugin-development-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"43b1b513-1146-4508-9929-bfca0e7bc21d","gmt_create":"2026-03-03T08:21:29+04:00","gmt_modified":"2026-03-03T08:21:29+04:00"},{"catalog_id":"8774fe5b-dc3c-4a02-b907-d2a16b1df420","title":"Block Structures","description":"block-structures","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0f6511c5-05bc-4ef7-8e04-442a302db49c","gmt_create":"2026-03-03T08:21:50+04:00","gmt_modified":"2026-03-03T08:21:50+04:00"},{"catalog_id":"6f3f9c87-cd58-45c0-b90e-7c01d39d3188","title":"Block Processing and Validation","description":"block-processing","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"868816de-43fc-4fe0-9cf9-0e89f661447c","gmt_create":"2026-03-03T08:22:26+04:00","gmt_modified":"2026-04-28T21:03:48.5839966+04:00"},{"catalog_id":"7045a421-d36d-4058-b1f7-1eade1482cdf","title":"Build Targets","description":"build-targets","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"3e146dd5-1515-4f08-a766-7c555069570d","gmt_create":"2026-03-03T08:23:32+04:00","gmt_modified":"2026-03-03T08:23:32+04:00"},{"catalog_id":"7b4370bd-7440-4196-bd4c-e441e1f693d8","title":"Transport Layer and Sockets","description":"transport-layer","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"446c4151-6374-4826-9947-cf5133b470cd","gmt_create":"2026-03-03T08:24:00+04:00","gmt_modified":"2026-03-03T08:24:00+04:00"},{"catalog_id":"939d7089-2486-4f03-bd3f-c35c98d5a1db","title":"MongoDB Integration Dockerfile","description":"mongo-dockerfile","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"e2b16877-3e41-4465-91f2-48e5dacfd2ad","gmt_create":"2026-03-03T08:24:06+04:00","gmt_modified":"2026-03-03T08:24:06+04:00"},{"catalog_id":"75c2d99d-2330-4db2-a9d0-f4a9fdb902bc","title":"Schema Generation Tools","description":"schema-generation-tools","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"75c788ef-0d7a-4a59-a02a-d56403aa3459","gmt_create":"2026-03-03T08:24:57+04:00","gmt_modified":"2026-03-03T08:24:57+04:00"},{"catalog_id":"f6b80222-aff8-4f40-9721-fcb497d3cf84","title":"Data Types and Serialization","description":"data-types-serialization","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"d7562df5-2f68-4c8b-9b1b-1aff56d025ab","gmt_create":"2026-03-03T08:25:53+04:00","gmt_modified":"2026-03-03T08:25:53+04:00"},{"catalog_id":"db232a1e-1458-4825-ab19-14e5658aa89b","title":"Transaction Processing","description":"transaction-processing","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0c2a4f4d-a142-41b8-81d4-a4c72022cd6d","gmt_create":"2026-03-03T08:26:05+04:00","gmt_modified":"2026-03-03T08:26:05+04:00"},{"catalog_id":"534cfa3d-aef9-406f-b4b2-b732746e7f7a","title":"GitHub Actions CI/CD Pipeline","description":"github-actions-ci","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"44884ed2-2c27-4d94-af1e-c939b85e2dba","gmt_create":"2026-03-03T08:27:16+04:00","gmt_modified":"2026-03-03T08:27:16+04:00"},{"catalog_id":"f53aa7de-1f1e-46ef-8b89-75ca11a2de22","title":"Peer Database and Discovery","description":"peer-database","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"14f4dc36-feae-4d78-a12c-32f851999890","gmt_create":"2026-03-03T08:27:29+04:00","gmt_modified":"2026-03-03T08:27:29+04:00"},{"catalog_id":"5e42d05e-3b67-477e-8c56-8aa25b98889b","title":"Operations Definition","description":"operations-definition","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"52188625-f997-45b2-ab6a-1b01391bde00","gmt_create":"2026-03-03T08:29:14+04:00","gmt_modified":"2026-03-03T08:29:14+04:00"},{"catalog_id":"6b359be4-c5e6-4db1-ad43-abf632c4e050","title":"Snapshot Plugin System","description":"snapshot-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"4d58ea88-1cbb-46a1-9bb9-477c8e3d9846","gmt_create":"2026-04-13T16:01:32+04:00","gmt_modified":"2026-04-30T13:09:00.7660159+04:00"},{"catalog_id":"6f970632-4b1c-4a78-a129-89269ed82d82","title":"DLT Rolling Block Log","description":"dlt-block-log","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"cb4b06a3-d41b-4c45-b1c6-e1b6306eff9f","gmt_create":"2026-04-13T16:03:19+04:00","gmt_modified":"2026-04-30T11:11:44.2224692+04:00"},{"catalog_id":"a85aa407-665b-425b-b5e1-fc693d469cd7","title":"Witness","description":"witness","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"c93fa44d-294e-4802-9676-e73b1a162b2b","gmt_create":"2026-04-13T21:25:30+04:00","gmt_modified":"2026-04-30T12:39:24.2387906+04:00"},{"catalog_id":"336017d8-00e0-43f8-afef-4d3d4a2e5ccb","title":"Webserver Plugin","description":"webserver-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"cfbf2561-8dc1-4657-9990-87f4d9de95ae","gmt_create":"2026-04-14T09:29:12+04:00","gmt_modified":"2026-04-23T15:42:30+04:00"},{"catalog_id":"29346336-4f9c-4ae7-9233-d7d4ccef1e6e","title":"Block Log Reader Module","description":"block-log-reader-module","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"03ac3143-5983-4c15-be9a-0e032445a800","gmt_create":"2026-04-14T14:41:40+04:00","gmt_modified":"2026-04-14T14:41:40+04:00"},{"catalog_id":"6b359be4-c5e6-4db1-ad43-abf632c4e050","title":"Snapshot Plugin System","description":"snapshot-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0a955b97-eb9d-434a-80a4-9bf1bf937dfb","gmt_create":"2026-04-16T12:35:54+04:00","gmt_modified":"2026-04-30T13:09:00.7660159+04:00"},{"catalog_id":"a4a4d47c-bb91-469b-9531-67491f9f186f","title":"Build Helper Scripts","description":"build-helpers","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"f1d8e320-e614-4981-b139-99ffa4534e71","gmt_create":"2026-04-19T22:03:11+04:00","gmt_modified":"2026-04-19T22:03:11+04:00"},{"catalog_id":"d93a647d-d325-4dd2-96a5-703494dd5d12","title":"Emergency Consensus System","description":"emergency-consensus-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"61b10976-8eeb-45d9-a3fa-3b71c7d30939","gmt_create":"2026-04-20T06:59:08+04:00","gmt_modified":"2026-04-30T12:35:27.5354397+04:00"},{"catalog_id":"cff6b813-9c5a-4ab6-a45c-f9382c25ff61","title":"Chain Plugin","description":"chain-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"b12a10e1-437e-49c8-ad45-2322fee38c9b","gmt_create":"2026-04-20T08:56:19+04:00","gmt_modified":"2026-04-29T06:59:11.3226702+04:00"},{"catalog_id":"63eb59b9-96cb-4c76-82c1-93eb29f163f1","title":"NTP Synchronization System","description":"ntp-synchronization-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"0be54f9c-0831-4de9-a839-fe492741178a","gmt_create":"2026-04-21T15:59:39+04:00","gmt_modified":"2026-04-21T16:27:59+04:00"},{"catalog_id":"612848bb-0178-4a56-b82c-aefc05b2cae9","title":"Memory Management System","description":"memory-management-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"d21997e6-71b9-44d6-b43f-85770fe1e9dd","gmt_create":"2026-04-23T07:24:03+04:00","gmt_modified":"2026-04-29T06:53:57.1824317+04:00"},{"catalog_id":"766a7066-9703-4342-a54b-f827e0e13757","title":"P2p Plugin","description":"p2p-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"6c14d115-1e64-4774-9d11-4861953aec78","gmt_create":"2026-04-23T11:53:01+04:00","gmt_modified":"2026-04-30T11:12:37.5129528+04:00"},{"catalog_id":"024bd7a9-84dc-4534-95b8-96539a35367f","title":"Witness Guard Plugin","description":"witness-guard-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"24d2e14a-472d-4051-8c51-776999cfe4cc","gmt_create":"2026-04-28T10:05:06.7179502+04:00","gmt_modified":"2026-04-28T10:05:06.7184647+04:00"},{"catalog_id":"e09223c9-c6d0-4de2-bc9e-e71b821821e9","title":"Logging System","description":"logging-system","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"9b86b8a5-506c-4454-a574-0aff36f0faf2","gmt_create":"2026-04-28T22:09:11.9818468+04:00","gmt_modified":"2026-04-28T22:09:11.9888453+04:00"},{"catalog_id":"1c7c44d6-22c3-42c5-953f-357d54ffc8ad","title":"Originating Peer Tracking","description":"originating-peer-tracking","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"ba976b2f-ad3f-4c9c-bbde-af6e23216dbe","gmt_create":"2026-04-28T22:34:00.3243045+04:00","gmt_modified":"2026-04-28T22:34:00.325344+04:00"},{"catalog_id":"8fa79728-580d-4d6c-bed4-5ac9ef3ae8d7","title":"Witness Guard Plugin","description":"witness-guard-plugin","extend":"{}","progress_status":"completed","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","id":"6ae7ebac-bb25-4499-8364-0f2f7ac99d8a","gmt_create":"2026-04-30T12:41:43.2858749+04:00","gmt_modified":"2026-04-30T12:41:43.2873164+04:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n\n# VIZ CPP Node - Comprehensive Project Analysis\n\n## 1. Project Introduction\n\n### Purpose Statement\nVIZ is a C++ implementation of a decentralized blockchain node designed for the VIZ World platform. It serves as a full consensus node that validates transactions, maintains the blockchain state, and provides APIs for interacting with the distributed ledger system.\n\n### Core Goals and Objectives\n- **Consensus Validation**: Maintain blockchain integrity through cryptographic verification and consensus mechanisms\n- **Network Participation**: Act as a peer-to-peer node in the VIZ network infrastructure\n- **API Provision**: Expose comprehensive JSON-RPC APIs for external applications and wallets\n- **Extensibility**: Support modular plugin architecture for specialized functionality\n- **Performance**: Optimize for both full node operations and lightweight consensus-only modes\n\n### Target Audience\n- Blockchain developers building applications on VIZ\n- Node operators running full nodes or witness nodes\n- Wallet developers integrating with VIZ blockchain\n- Researchers studying blockchain consensus mechanisms\n\n## 2. Technical Architecture\n\n### Component Breakdown\n\nThe VIZ project follows a modular architecture built on the appbase framework:\n\n```mermaid\ngraph TD\n A[VIZ Node] --\u003e B[Core Libraries]\n A --\u003e C[Plugins]\n A --\u003e D[Programs]\n \n B --\u003e E[Chain Library]\n B --\u003e F[Protocol Library]\n B --\u003e G[Network Library]\n B --\u003e H[Wallet Library]\n \n C --\u003e I[Chain Plugin]\n C --\u003e J[P2P Plugin]\n C --\u003e K[Webserver Plugin]\n C --\u003e L[Database API Plugin]\n C --\u003e M[JSON-RPC Plugin]\n \n D --\u003e N[vizd - Full Node]\n D --\u003e O[cli_wallet - CLI Wallet]\n D --\u003e P[js_operation_serializer - Tools]\n```\n\n### Design Patterns\n\n**Plugin Architecture**: The project extensively uses the appbase plugin system, allowing modular functionality through independent plugins that can be enabled/disabled at runtime.\n\n**Database Pattern**: Chainbase provides an object-oriented database abstraction layer, enabling efficient blockchain state management.\n\n**Observer Pattern**: Event-driven architecture through Boost.Signals2 for handling blockchain events and state changes.\n\n### System Relationships\n\n```mermaid\nsequenceDiagram\n participant Client\n participant Webserver\n participant JSON_RPC\n participant Chain\n participant Database\n \n Client-\u003e\u003e+Webserver: HTTP Request\n Webserver-\u003e\u003e+JSON_RPC: Parse JSON-RPC\n JSON_RPC-\u003e\u003e+Chain: Validate Operation\n Chain-\u003e\u003e+Database: Query State\n Database--\u003e\u003e-Chain: Return Data\n Chain--\u003e\u003e-JSON_RPC: Process Result\n JSON_RPC--\u003e\u003e-Webserver: JSON Response\n Webserver--\u003e\u003e-Client: HTTP Response\n```\n\n### Data Flow Diagrams\n\n```mermaid\nflowchart TD\n A[Transaction Input] --\u003e B[JSON-RPC Parser]\n B --\u003e C[Operation Validation]\n C --\u003e D[Authority Verification]\n D --\u003e E[State Application]\n E --\u003e F[Block Production]\n F --\u003e G[P2P Broadcasting]\n \n H[Block Input] --\u003e I[Block Validation]\n I --\u003e J[Fork Resolution]\n J --\u003e K[State Commit]\n K --\u003e L[Peer Sync]\n```\n\n## 3. Key Implementation\n\n### Main Entry Points\n\n**Primary Node Entry Point**: `programs/vizd/main.cpp`\n- Initializes the application with core plugins\n- Configures logging and command-line options\n- Manages plugin lifecycle and startup sequence\n\n**Configuration Management**: `share/vizd/config/config.ini`\n- Network settings (P2P endpoints, webserver ports)\n- Plugin activation and configuration\n- Performance tuning parameters\n- Logging configuration sections\n\n### Core Modules\n\n**Database Layer**: `libraries/chain/include/graphene/chain/database.hpp`\n- Blockchain state management\n- Object persistence and retrieval\n- Fork database handling\n- Transaction validation pipeline\n\n**Protocol Definitions**: `libraries/protocol/include/graphene/protocol/operations.hpp`\n- Complete operation type definitions\n- Transaction structure validation\n- Authority requirement calculation\n- Virtual operation handling\n\n**Plugin System**: `plugins/chain/include/graphene/plugins/chain/plugin.hpp`\n- Core blockchain functionality\n- Block acceptance and validation\n- Transaction processing\n- Index management\n\n### Configuration Approach\n\n**Build Configuration**: `CMakeLists.txt`\n- Cross-platform compilation support\n- Compiler-specific optimizations\n- Feature toggles (testnet, low-memory)\n- Dependency management\n\n**Runtime Configuration**: `share/vizd/config/config.ini`\n- Plugin enable/disable directives\n- Network connectivity settings\n- Performance tuning parameters\n- Logging configuration sections\n\n### External Dependencies\n\n**Third-party Libraries**: `thirdparty/CMakeLists.txt`\n- appbase: Application framework foundation\n- fc: Fast Crypto library for networking and cryptography\n- chainbase: High-performance object database\n\n**Build Dependencies**:\n- Boost 1.57+: Core C++ utilities\n- OpenSSL: Cryptographic operations\n- CMake: Build system\n- Platform-specific toolchains\n\n### Integration Points\n\n**P2P Network**: `plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp`\n- Peer discovery and connection management\n- Block and transaction propagation\n- Network protocol compliance\n\n**Web API**: `plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp`\n- HTTP/HTTPS server implementation\n- WebSocket support for real-time updates\n- JSON-RPC 2.0 compliance\n\n**Database API**: `plugins/database_api/include/graphene/plugins/database_api/plugin.hpp`\n- Comprehensive blockchain state queries\n- Account and transaction history\n- Market data and governance information\n\n### Component Relationship Diagrams\n\n```mermaid\ngraph LR\n A[Chain Plugin] --\u003e B[Database Layer]\n A --\u003e C[P2P Plugin]\n D[Webserver Plugin] --\u003e E[JSON-RPC Plugin]\n E --\u003e A\n F[Database API Plugin] --\u003e A\n G[Account History Plugin] --\u003e A\n H[Tags Plugin] --\u003e A\n I[Follow Plugin] --\u003e A\n```\n\n## 4. Key Features\n\n### Functionality Overview\n\n**Blockchain Consensus**: Full validation of blocks and transactions according to VIZ protocol rules\n**Network Participation**: Active participation in the peer-to-peer network with configurable connectivity\n**API Exposure**: Comprehensive JSON-RPC APIs covering all blockchain functionality\n**Plugin Extensibility**: Modular architecture supporting specialized functionality through plugins\n**Performance Optimization**: Configurable memory usage and processing modes for different node types\n\n### Implementation Highlights\n\n**Modular Plugin System**: `plugins/*/include/graphene/plugins/*/plugin.hpp`\n- Independent plugin development and deployment\n- Runtime plugin loading/unloading\n- Inter-plugin communication through appbase framework\n\n**High-performance Database**: `libraries/chain/database.cpp`\n- Optimized object storage and retrieval\n- Efficient fork resolution algorithms\n- Memory-mapped file support for large datasets\n\n**Comprehensive API Coverage**: `plugins/database_api/api.cpp`\n- Complete blockchain state queries\n- Historical data access\n- Real-time event streaming\n\n### Feature Architecture Diagrams\n\n```mermaid\nstateDiagram-v2\n [*] --\u003e Initializing\n Initializing --\u003e Syncing: Start Node\n Syncing --\u003e Live: Catch Up Complete\n Live --\u003e Producing: Witness Enabled\n Live --\u003e Listening: Normal Mode\n Producing --\u003e Live: Block Production\n Listening --\u003e Live: New Blocks\n Live --\u003e [*]: Shutdown\n \n Syncing --\u003e [*]: Error\n Live --\u003e [*]: Error\n```\n\n**Development Workflow**: `documentation/building.md`\n- Cross-platform build system\n- Docker containerization support\n- Automated testing and CI/CD integration\n- Release packaging and distribution\n\n**Testing Infrastructure**: `documentation/testing.md`\n- Unit test framework integration\n- Integration testing capabilities\n- Performance benchmarking tools\n- Continuous integration workflows\n\n## 5. Conclusion and Recommendations\n\n### Project Architecture Summary\n\nThe VIZ CPP Node demonstrates a well-architected blockchain implementation with several key strengths:\n\n- **Modular Design**: Clean separation of concerns through the plugin architecture enables easy maintenance and feature development\n- **Performance Focus**: Multiple optimization modes (full node vs. low-memory) accommodate diverse deployment scenarios\n- **Comprehensive API**: Broad coverage of blockchain functionality through standardized JSON-RPC interfaces\n- **Cross-platform Compatibility**: Robust build system supporting multiple operating systems and compilers\n\n### Architectural Strengths\n\n1. **Scalability**: Plugin-based architecture allows selective feature activation based on node requirements\n2. **Maintainability**: Clear module boundaries facilitate independent development and testing\n3. **Interoperability**: Standardized JSON-RPC interface enables seamless integration with external applications\n4. **Reliability**: Comprehensive error handling and logging throughout the system\n\n### Potential Improvement Areas\n\n1. **Documentation**: Enhanced inline documentation would improve code maintainability\n2. **Testing Coverage**: Expanded unit and integration test suites would increase confidence in changes\n3. **Monitoring**: Additional metrics and health check endpoints would improve operational visibility\n4. **Security**: Regular security audits and vulnerability assessments should be integrated into the development process\n\n### Actionable Recommendations\n\n1. **Implement Comprehensive Logging**: Add structured logging with correlation IDs for better debugging\n2. **Enhance Test Coverage**: Target 80%+ code coverage across all modules\n3. **Performance Monitoring**: Integrate metrics collection for key performance indicators\n4. **Security Hardening**: Implement regular security assessments and dependency updates\n5. **Developer Experience**: Create comprehensive developer guides and example applications\n\n### Next Steps for Project Evolution\n\n1. **Microservices Migration**: Consider breaking down monolithic components into microservices for better scalability\n2. **Cloud-native Deployment**: Enhance Kubernetes support and cloud-native features\n3. **Advanced Analytics**: Implement real-time analytics and reporting capabilities\n4. **Mobile Integration**: Develop mobile SDKs for broader ecosystem adoption\n5. **Community Development**: Establish contributor guidelines and development workflows\n\n---\n\n**Sources:**\n- [CMakeLists.txt](CMakeLists.txt)\n- [main.cpp](programs/vizd/main.cpp)\n- [database.hpp](libraries/chain/include/graphene/chain/database.hpp)\n- [operations.hpp](libraries/protocol/include/graphene/protocol/operations.hpp)\n- [plugin.hpp](plugins/chain/include/graphene/plugins/chain/plugin.hpp)\n- [config.ini](share/vizd/config/config.ini)\n- [building.md](documentation/building.md)\n- [plugin.hpp](plugins/database_api/include/graphene/plugins/database_api/plugin.hpp)\n- [p2p_plugin.hpp](plugins/p2p/include/graphene/plugins/p2p/p2p_plugin.hpp)\n- [webserver_plugin.hpp](plugins/webserver/include/graphene/plugins/webserver/webserver_plugin.hpp)\n- [CMakeLists.txt](thirdparty/CMakeLists.txt)\n\n\u003c/blog\u003e","gmt_create":"2026-03-03T07:24:05+04:00","gmt_modified":"2026-03-03T07:24:05+04:00","id":"825a060f-64a6-4072-8338-e1ab100bb1b0","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6"},"wiki_readme":{"content":"No readme file","gmt_create":"2026-03-03T07:22:14+04:00","gmt_modified":"2026-03-03T07:22:14+04:00","id":"2c1da76b-6fd5-4e91-b0e1-3dcd4e769a29","repo_id":"1eebf745-cdbd-49c6-992c-a603f46f10d6"},"wiki_repo":{"id":"1eebf745-cdbd-49c6-992c-a603f46f10d6","name":"viz-cpp-node","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── .github\\\\workflows\\\\\\n│ ├── docker-main.yml\\n│ └── docker-pr-build.yml\\n├── .qoder\\\\\\n│ ├── agents\\\\\\n│ └── skills\\\\\\n├── documentation\\\\\\n│ ├── doxygen\\\\\\n│ │ ├── images\\\\\\n│ │ │ └── viz.png\\n│ │ ├── DoxygenLayout.xml\\n│ │ ├── customdoxygen.css\\n│ │ ├── footer.html\\n│ │ └── header.html\\n│ ├── api_notes.md\\n│ ├── building.md\\n│ ├── debug_node_plugin.md\\n│ ├── git_guildelines.md\\n│ ├── plugin.md\\n│ ├── testing.md\\n│ └── testnet.md\\n├── libraries\\\\\\n│ ├── api\\\\\\n│ │ ├── include\\\\graphene\\\\api\\\\\\n│ │ │ ├── account_api_object.hpp\\n│ │ │ ├── account_vote.hpp\\n│ │ │ ├── chain_api_properties.hpp\\n│ │ │ ├── committee_api_object.hpp\\n│ │ │ ├── content_api_object.hpp\\n│ │ │ ├── discussion.hpp\\n│ │ │ ├── discussion_helper.hpp\\n│ │ │ ├── invite_api_object.hpp\\n│ │ │ ├── paid_subscription_api_object.hpp\\n│ │ │ ├── vote_state.hpp\\n│ │ │ └── witness_api_object.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── account_api_object.cpp\\n│ │ ├── chain_api_properties.cpp\\n│ │ ├── committee_api_object.cpp\\n│ │ ├── content_api_object.cpp\\n│ │ ├── discussion_helper.cpp\\n│ │ ├── invite_api_object.cpp\\n│ │ ├── paid_subscription_api_object.cpp\\n│ │ └── witness_api_object.cpp\\n│ ├── chain\\\\\\n│ │ ├── hardfork.d\\\\\\n│ │ │ ├── 0-preamble.hf\\n│ │ │ ├── 1.hf\\n│ │ │ ├── 10.hf\\n│ │ │ ├── 11.hf\\n│ │ │ ├── 2.hf\\n│ │ │ ├── 3.hf\\n│ │ │ ├── 4.hf\\n│ │ │ ├── 5.hf\\n│ │ │ ├── 6.hf\\n│ │ │ ├── 7.hf\\n│ │ │ ├── 8.hf\\n│ │ │ └── 9.hf\\n│ │ ├── include\\\\graphene\\\\chain\\\\\\n│ │ │ ├── account_object.hpp\\n│ │ │ ├── block_log.hpp\\n│ │ │ ├── block_summary_object.hpp\\n│ │ │ ├── chain_evaluator.hpp\\n│ │ │ ├── chain_object_types.hpp\\n│ │ │ ├── chain_objects.hpp\\n│ │ │ ├── committee_objects.hpp\\n│ │ │ ├── compound.hpp\\n│ │ │ ├── content_object.hpp\\n│ │ │ ├── custom_operation_interpreter.hpp\\n│ │ │ ├── database.hpp\\n│ │ │ ├── database_exceptions.hpp\\n│ │ │ ├── db_with.hpp\\n│ │ │ ├── evaluator.hpp\\n│ │ │ ├── evaluator_registry.hpp\\n│ │ │ ├── fork_database.hpp\\n│ │ │ ├── generic_custom_operation_interpreter.hpp\\n│ │ │ ├── global_property_object.hpp\\n│ │ │ ├── immutable_chain_parameters.hpp\\n│ │ │ ├── index.hpp\\n│ │ │ ├── invite_objects.hpp\\n│ │ │ ├── node_property_object.hpp\\n│ │ │ ├── operation_notification.hpp\\n│ │ │ ├── paid_subscription_objects.hpp\\n│ │ │ ├── proposal_object.hpp\\n│ │ │ ├── shared_authority.hpp\\n│ │ │ ├── shared_db_merkle.hpp\\n│ │ │ ├── transaction_object.hpp\\n│ │ │ └── witness_objects.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── block_log.cpp\\n│ │ ├── chain_evaluator.cpp\\n│ │ ├── chain_objects.cpp\\n│ │ ├── chain_properties_evaluators.cpp\\n│ │ ├── committee_evaluator.cpp\\n│ │ ├── database.cpp\\n│ │ ├── database_proposal_object.cpp\\n│ │ ├── fork_database.cpp\\n│ │ ├── invite_evaluator.cpp\\n│ │ ├── paid_subscription_evaluator.cpp\\n│ │ ├── proposal_evaluator.cpp\\n│ │ ├── proposal_object.cpp\\n│ │ ├── shared_authority.cpp\\n│ │ └── transaction_object.cpp\\n│ ├── network\\\\\\n│ │ ├── include\\\\graphene\\\\network\\\\\\n│ │ │ ├── config.hpp\\n│ │ │ ├── core_messages.hpp\\n│ │ │ ├── exceptions.hpp\\n│ │ │ ├── message.hpp\\n│ │ │ ├── message_oriented_connection.hpp\\n│ │ │ ├── node.hpp\\n│ │ │ ├── peer_connection.hpp\\n│ │ │ ├── peer_database.hpp\\n│ │ │ └── stcp_socket.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── core_messages.cpp\\n│ │ ├── message_oriented_connection.cpp\\n│ │ ├── node.cpp\\n│ │ ├── peer_connection.cpp\\n│ │ ├── peer_database.cpp\\n│ │ └── stcp_socket.cpp\\n│ ├── protocol\\\\\\n│ │ ├── include\\\\graphene\\\\protocol\\\\\\n│ │ │ ├── README.md\\n│ │ │ ├── asset.hpp\\n│ │ │ ├── authority.hpp\\n│ │ │ ├── base.hpp\\n│ │ │ ├── block.hpp\\n│ │ │ ├── block_header.hpp\\n│ │ │ ├── chain_operations.hpp\\n│ │ │ ├── chain_virtual_operations.hpp\\n│ │ │ ├── config.hpp\\n│ │ │ ├── config_testnet.hpp\\n│ │ │ ├── exceptions.hpp\\n│ │ │ ├── get_config.hpp\\n│ │ │ ├── operation_util.hpp\\n│ │ │ ├── operation_util_impl.hpp\\n│ │ │ ├── operations.hpp\\n│ │ │ ├── proposal_operations.hpp\\n│ │ │ ├── protocol.hpp\\n│ │ │ ├── sign_state.hpp\\n│ │ │ ├── transaction.hpp\\n│ │ │ ├── types.hpp\\n│ │ │ └── version.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── asset.cpp\\n│ │ ├── authority.cpp\\n│ │ ├── block.cpp\\n│ │ ├── chain_operations.cpp\\n│ │ ├── get_config.cpp\\n│ │ ├── operation_util_impl.cpp\\n│ │ ├── operations.cpp\\n│ │ ├── proposal_operations.cpp\\n│ │ ├── sign_state.cpp\\n│ │ ├── transaction.cpp\\n│ │ ├── types.cpp\\n│ │ └── version.cpp\\n│ ├── time\\\\\\n│ │ ├── include\\\\graphene\\\\time\\\\\\n│ │ │ └── time.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── time.cpp\\n│ ├── utilities\\\\\\n│ │ ├── include\\\\graphene\\\\utilities\\\\\\n│ │ │ ├── git_revision.hpp\\n│ │ │ ├── key_conversion.hpp\\n│ │ │ ├── padding_ostream.hpp\\n│ │ │ ├── string_escape.hpp\\n│ │ │ ├── tempdir.hpp\\n│ │ │ └── words.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── git_revision.cpp.in\\n│ │ ├── key_conversion.cpp\\n│ │ ├── string_escape.cpp\\n│ │ ├── tempdir.cpp\\n│ │ └── words.cpp\\n│ ├── wallet\\\\\\n│ │ ├── include\\\\graphene\\\\wallet\\\\\\n│ │ │ ├── api_documentation.hpp\\n│ │ │ ├── reflect_util.hpp\\n│ │ │ ├── remote_node_api.hpp\\n│ │ │ └── wallet.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── Doxyfile.in\\n│ │ ├── api_documentation_standin.cpp\\n│ │ ├── generate_api_documentation.pl\\n│ │ └── wallet.cpp\\n│ └── CMakeLists.txt\\n├── plugins\\\\\\n│ ├── account_by_key\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\account_by_key\\\\\\n│ │ │ ├── account_by_key_objects.hpp\\n│ │ │ └── account_by_key_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── account_by_key_plugin.cpp\\n│ ├── account_history\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\account_history\\\\\\n│ │ │ ├── history_object.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── auth_util\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\auth_util\\\\\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── block_info\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\block_info\\\\\\n│ │ │ ├── block_info.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── chain\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\chain\\\\\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── committee_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\committee_api\\\\\\n│ │ │ └── committee_api.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── committee_api.cpp\\n│ ├── custom_protocol_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\custom_protocol_api\\\\\\n│ │ │ ├── custom_protocol_api.hpp\\n│ │ │ ├── custom_protocol_api_object.hpp\\n│ │ │ └── custom_protocol_api_visitor.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── custom_protocol_api.cpp\\n│ │ └── custom_protocol_api_visitor.cpp\\n│ ├── database_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\database_api\\\\\\n│ │ │ ├── api_objects\\\\\\n│ │ │ │ ├── account_recovery_request_api_object.hpp\\n│ │ │ │ ├── master_authority_history_api_object.hpp\\n│ │ │ │ └── proposal_api_object.hpp\\n│ │ │ ├── forward.hpp\\n│ │ │ ├── plugin.hpp\\n│ │ │ └── state.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── api.cpp\\n│ │ └── proposal_api_object.cpp\\n│ ├── debug_node\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\debug_node\\\\\\n│ │ │ ├── api_helper.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── follow\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\follow\\\\\\n│ │ │ ├── follow_api_object.hpp\\n│ │ │ ├── follow_evaluators.hpp\\n│ │ │ ├── follow_forward.hpp\\n│ │ │ ├── follow_objects.hpp\\n│ │ │ ├── follow_operations.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── follow_evaluators.cpp\\n│ │ ├── follow_operations.cpp\\n│ │ └── plugin.cpp\\n│ ├── invite_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\invite_api\\\\\\n│ │ │ └── invite_api.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── invite_api.cpp\\n│ ├── json_rpc\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\json_rpc\\\\\\n│ │ │ ├── plugin.hpp\\n│ │ │ └── utility.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── mongo_db\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\mongo_db\\\\\\n│ │ │ ├── mongo_db_operations.hpp\\n│ │ │ ├── mongo_db_plugin.hpp\\n│ │ │ ├── mongo_db_state.hpp\\n│ │ │ ├── mongo_db_types.hpp\\n│ │ │ └── mongo_db_writer.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── mongo_db_operations.cpp\\n│ │ ├── mongo_db_plugin.cpp\\n│ │ ├── mongo_db_state.cpp\\n│ │ ├── mongo_db_types.cpp\\n│ │ └── mongo_db_writer.cpp\\n│ ├── network_broadcast_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\network_broadcast_api\\\\\\n│ │ │ └── network_broadcast_api_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── network_broadcast_api.cpp\\n│ ├── operation_history\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\operation_history\\\\\\n│ │ │ ├── applied_operation.hpp\\n│ │ │ ├── history_object.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── applied_operation.cpp\\n│ │ └── plugin.cpp\\n│ ├── p2p\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\p2p\\\\\\n│ │ │ └── p2p_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── p2p_plugin.cpp\\n│ ├── paid_subscription_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\paid_subscription_api\\\\\\n│ │ │ └── paid_subscription_api.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── paid_subscription_api.cpp\\n│ ├── private_message\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\private_message\\\\\\n│ │ │ ├── private_message_evaluators.hpp\\n│ │ │ ├── private_message_objects.hpp\\n│ │ │ └── private_message_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── private_message_objects.cpp\\n│ │ └── private_message_plugin.cpp\\n│ ├── raw_block\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\raw_block\\\\\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ ├── social_network\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\social_network\\\\\\n│ │ │ └── social_network.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── social_network.cpp\\n│ ├── tags\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\tags\\\\\\n│ │ │ ├── discussion_query.hpp\\n│ │ │ ├── plugin.hpp\\n│ │ │ ├── tag_api_object.hpp\\n│ │ │ ├── tag_visitor.hpp\\n│ │ │ ├── tags_object.hpp\\n│ │ │ └── tags_sort.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ ├── discussion_query.cpp\\n│ │ ├── plugin.cpp\\n│ │ └── tag_visitor.cpp\\n│ ├── test_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\test_api\\\\\\n│ │ │ └── test_api_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── test_api_plugin.cpp\\n│ ├── webserver\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\webserver\\\\\\n│ │ │ └── webserver_plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── webserver_plugin.cpp\\n│ ├── witness\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\witness\\\\\\n│ │ │ └── witness.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── witness.cpp\\n│ ├── witness_api\\\\\\n│ │ ├── include\\\\graphene\\\\plugins\\\\witness_api\\\\\\n│ │ │ ├── api_objects\\\\\\n│ │ │ │ ├── feed_history_api_object.hpp\\n│ │ │ │ └── witness_api_object.hpp\\n│ │ │ └── plugin.hpp\\n│ │ ├── CMakeLists.txt\\n│ │ └── plugin.cpp\\n│ └── CMakeLists.txt\\n├── programs\\\\\\n│ ├── build_helpers\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ ├── cat-parts.cpp\\n│ │ ├── cat_parts.py\\n│ │ ├── check_reflect.py\\n│ │ └── configure_build.py\\n│ ├── cli_wallet\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ └── main.cpp\\n│ ├── js_operation_serializer\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ └── main.cpp\\n│ ├── size_checker\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ └── main.cpp\\n│ ├── util\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ ├── get_dev_key.cpp\\n│ │ ├── inflation_plot.py\\n│ │ ├── newplugin.py\\n│ │ ├── pretty_schema.py\\n│ │ ├── saltpass.py\\n│ │ ├── schema_test.cpp\\n│ │ ├── sign_digest.cpp\\n│ │ ├── sign_transaction.cpp\\n│ │ ├── test_block_log.cpp\\n│ │ └── test_shared_mem.cpp\\n│ ├── vizd\\\\\\n│ │ ├── CMakeLists.txt\\n│ │ └── main.cpp\\n│ └── CMakeLists.txt\\n├── share\\\\vizd\\\\\\n│ ├── config\\\\\\n│ │ ├── config.ini\\n│ │ ├── config_debug.ini\\n│ │ ├── config_debug_mongo.ini\\n│ │ ├── config_mongo.ini\\n│ │ ├── config_stock_exchange.ini\\n│ │ ├── config_testnet.ini\\n│ │ └── config_witness.ini\\n│ ├── docker\\\\\\n│ │ ├── Dockerfile-lowmem\\n│ │ ├── Dockerfile-mongo\\n│ │ ├── Dockerfile-production\\n│ │ └── Dockerfile-testnet\\n│ ├── seednodes\\n│ ├── seednodes_empty\\n│ ├── snapshot-testnet.json\\n│ ├── snapshot.json\\n│ └── vizd.sh\\n├── thirdparty\\\\\\n│ ├── appbase\\\\\\n│ ├── chainbase\\\\\\n│ ├── fc\\\\\\n│ └── CMakeLists.txt\\n├── .gitignore\\n├── .gitmodules\\n├── .travis.yml\\n├── CMakeLists.txt\\n├── Doxyfile\\n├── LICENSE.md\\n└── README.md\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted: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","recovery_checkpoint":"incremental_processing","last_commit_id":"93ce9f3e0908c4e1445a502330f0e3e6a70f0c81","last_commit_update":"2026-04-30T13:09:19.4616936+04:00","gmt_create":"2026-03-03T06:42:09+04:00","gmt_modified":"2026-04-30T13:09:19.4616936+04:00","extend_info":"{\"language\":\"en\",\"active\":true,\"branch\":\"fix-witness\",\"shareStatus\":\"\",\"server_error_code\":\"\",\"cosy_version\":\"0.8.2\"}"}} \ No newline at end of file diff --git a/.qoder/research/consensus-emergency-recovery.md b/.qoder/research/consensus-emergency-recovery.md deleted file mode 100644 index 97577e8a79..0000000000 --- a/.qoder/research/consensus-emergency-recovery.md +++ /dev/null @@ -1,1513 +0,0 @@ -# Research: Consensus Emergency Recovery & Micro-Fork Prevention - -## Status: Research + Proposal - -## Problem Statement - -When a significant portion of VIZ witnesses go offline, the network stalls. The current recovery procedure requires operators to manually set `enable-stale-production = true` and `required-participation = 0`, but: - -1. **Operators forget to revert** these settings after recovery, causing micro-forks during subsequent network partitions -2. **fork_db depth = 1024 blocks (~51 min)** means if a partitioned witness produces blocks alone for >51 min, fork resolution fails -3. **No automatic detection or recovery** exists — everything depends on manual operator intervention -4. **Witness shutdown after 200 missed blocks (~10 min)** ([config.hpp:32](../../libraries/protocol/include/graphene/protocol/config.hpp#L32)) removes witnesses from the schedule, making recovery even harder -5. **Penalties accumulate** during the stall, further reducing witness `counted_votes` and their scheduling priority - ---- - -## Current Mechanism Analysis - -### 1. Block Production Safeguards (witness.cpp) - -Two safeguards prevent isolated block production: - -| Safeguard | Check | Condition | Effect | -|---|---|---|---| -| Stale check | `_production_enabled` | `get_slot_time(1) >= now` | Stops production if node hasn't received recent blocks | -| Participation check | `prate < _required_witness_participation` | 33% default threshold | Stops production if < 33% of slots are filled | - -Source: [witness.cpp:333-339](../../plugins/witness/witness.cpp#L333), [witness.cpp:436-439](../../plugins/witness/witness.cpp#L436) - -Both are **bypassed** by emergency settings. There is no time-based automatic re-enablement of these safeguards. - -### 2. Witness Shutdown Mechanism (database.cpp:4046-4051) - -```cpp -if (head_block_num() - w.last_confirmed_block_num > CHAIN_MAX_WITNESS_MISSED_BLOCKS) { - w.signing_key = public_key_type(); // Zero key = disabled - push_virtual_operation(shutdown_witness_operation(w.owner)); -} -``` - -`CHAIN_MAX_WITNESS_MISSED_BLOCKS = 200` (~10 min). After a witness misses 200 blocks, their `signing_key` is set to null, removing them from the schedule. This is **irreversible on-chain** — the witness must submit a new `witness_update_operation` to re-enable their key. - -**Problem during stall**: If the network stalls for >10 min, ALL witnesses get shut down. Recovery then requires external intervention (CLI wallet) to re-register all witness keys. - -### 3. Penalty Accumulation (database.cpp:4035-4043) - -During any gap, missed blocks trigger penalties: - -```cpp -w.penalty_percent += consensus.median_props.witness_miss_penalty_percent; // 1% -// penalty expires after witness_miss_penalty_duration (1 day) -``` - -During a prolonged stall, penalties accumulate massively. Even after recovery, witnesses are penalized for blocks they couldn't possibly produce — their `counted_votes` drops, affecting schedule position. - -### 4. Fork Database Depth (fork_database.hpp:117) - -```cpp -uint32_t _max_size = 1024; // ~51 minutes at 3s intervals -``` - -The fork_db dynamically resizes to `head - LIB + 1` during normal operation. But during solo production: -- LIB doesn't advance (no 75% witness validation possible) -- fork_db stays at 1024 -- After 1024 blocks of solo production, older blocks are pruned -- Reconnection with the main chain becomes impossible without full replay - -### 5. Last Irreversible Block (LIB) Advancement - -LIB advances via two mechanisms: -1. **`update_last_irreversible_block()`** — uses `nth_element` of `last_supported_block_num` at 75% threshold -2. **Block post-validation** — requires 75% of `num_scheduled_witnesses` to sign off - -During a stall or solo production, neither mechanism works. LIB freezes at the last block where 75% of witnesses were participating. - -### 6. Witness Scheduling - -```cpp -account_name_type database::get_scheduled_witness(uint32_t slot_num) const { - uint64_t current_aslot = dpo.current_aslot + slot_num; - return wso.current_shuffled_witnesses[current_aslot % wso.num_scheduled_witnesses]; -} -``` - -The schedule is deterministic — `current_aslot % num_scheduled_witnesses`. With fewer witnesses (after shutdowns), the schedule wraps faster, but only among remaining active witnesses. - -### 7. Current Emergency Procedure (Manual) - -| Step | Action | Risk | -|---|---|---| -| 1 | Set `enable-stale-production = true` | Bypasses sync check permanently | -| 2 | Set `required-participation = 0` | Removes participation safeguard permanently | -| 3 | Restart node | Node produces blocks even if isolated | -| 4 | Re-register shut-down witnesses via CLI | Manual, error-prone | -| 5 | **FORGET to revert settings** | **Micro-forks on next partition** | - ---- - -## Root Cause Analysis - -The fundamental problem is that **safeguards are binary and manual**: - -1. `enable-stale-production` is either `true` or `false` — no time-based auto-revert -2. `required-participation` has no automatic adjustment based on network conditions -3. Witness shutdown (`signing_key = null`) is permanent on-chain — no automatic recovery -4. No on-chain concept of "emergency mode" — all recovery is off-chain configuration - -### The Micro-Fork Chain of Events - -``` -Network Stall - │ - ├─ Witnesses miss blocks → penalties accumulate - ├─ After 200 missed blocks → signing_key = null (shutdown) - ├─ Participation rate → 0% → production stops - │ - ├─ Operator manually sets enable-stale=true, required-participation=0 - ├─ One witness starts producing alone - ├─ Other witnesses re-register via CLI, rejoin - ├─ Network recovers, operator FORGETS to revert settings - │ - ├─ Later: network partition - ├─ Isolated witness: enable-stale=true → keeps producing - ├─ Isolated witness: required-participation=0 → never stops - ├─ Isolated witness: skip_undo_history_check → no LIB gap limit - │ - ├─ After 51 min (1024 blocks): fork_db prunes old blocks - ├─ Reconnection: fork resolution FAILS - └─ Full replay required → extended downtime -``` - ---- - -## Proposal: On-Chain Emergency Consensus Mode - -### Core Concept - -Add a **consensus-level emergency mode** that activates automatically when the network has been unable to produce blocks for a configurable duration. In emergency mode, a single well-known committee key becomes the sole block producer, ensuring chain continuity without requiring operators to disable safety checks. - -### Design Principles - -1. **Automatic activation** — no manual intervention needed to enter emergency mode -2. **Automatic deactivation** — emergency mode exits when normal witnesses resume -3. **No permanent safety bypass** — `enable-stale-production` and `required-participation` remain at safe values -4. **Deterministic committee key** — all nodes agree on who produces blocks during emergency -5. **Minimal consensus changes** — smallest possible diff to existing objects - ---- - -### Change 1: New Constants (config.hpp) - -```cpp -/// Emergency consensus mode: activates when no block has been produced for -/// this many seconds since the last irreversible block. -#define CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC 3600 // 1 hour - -/// The witness account name that produces blocks during emergency mode -#define CHAIN_EMERGENCY_WITNESS_ACCOUNT CHAIN_COMMITTEE_ACCOUNT // "committee" - -/// The public key used to sign blocks during emergency mode -#define CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY_STR "VIZ75CRHVHPwYiUESy1bgN3KhVFbZCQQRA9jT6TnpzKAmpxMPD6Xv" -#define CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY (graphene::protocol::public_key_type(CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY_STR)) - -/// Number of consecutive blocks produced by the emergency witness that -/// triggers automatic exit from emergency mode (witnesses have rejoined). -#define CHAIN_EMERGENCY_EXIT_NORMAL_BLOCKS 21 // 1 full round of 21 witnesses -``` - -### Change 2: Emergency Mode Flag in dynamic_global_property_object (Breaking) - -Add a new field to track emergency state: - -```cpp -// In global_property_object.hpp, inside dynamic_global_property_object: -bool emergency_consensus_active = false; - -/// Block number at which emergency consensus mode was activated. -/// Zero if never activated. Used to compute duration and for logging. -uint32_t emergency_consensus_start_block = 0; -``` - -**FC_REFLECT update** (breaking change — requires hardfork): - -```cpp -FC_REFLECT((graphene::chain::dynamic_global_property_object), - // ... existing fields ... - (emergency_consensus_active) - (emergency_consensus_start_block) -) -``` - -### Change 3: Emergency Mode Detection — Consensus-Level (database.cpp) - -In `update_global_dynamic_data()`, after the existing missed-blocks logic: - -```cpp -// After the existing participation/missed-blocks update logic: - -const dynamic_global_property_object &dgp = get_dynamic_global_properties(); - -if (!dgp.emergency_consensus_active) { - // Check if we should enter emergency mode: - // No block has been produced by a normal witness since LIB, - // and more than CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC has elapsed. - fc::time_point_sec lib_time = get_block_time(dgp.last_irreversible_block_num); - uint32_t seconds_since_lib = (b.timestamp - lib_time).to_seconds(); - - if (seconds_since_lib >= CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC) { - // Enter emergency consensus mode - modify(dgp, [&](dynamic_global_property_object &_dgp) { - _dgp.emergency_consensus_active = true; - _dgp.emergency_consensus_start_block = b.block_num(); - }); - - // Override witness schedule to single emergency witness - const witness_schedule_object &wso = get_witness_schedule_object(); - modify(wso, [&](witness_schedule_object &_wso) { - for (int i = 0; i < _wso.num_scheduled_witnesses; i++) { - _wso.current_shuffled_witnesses[i] = CHAIN_EMERGENCY_WITNESS_ACCOUNT; - } - // Keep num_scheduled_witnesses unchanged to preserve schedule rhythm - }); - - ilog("EMERGENCY CONSENSUS MODE activated at block ${b}. " - "No blocks for ${sec} seconds since LIB ${lib}. " - "Emergency witness: ${w}", - ("b", b.block_num())("sec", seconds_since_lib) - ("lib", dgp.last_irreversible_block_num) - ("w", CHAIN_EMERGENCY_WITNESS_ACCOUNT)); - } -} -``` - -### Change 4: Emergency Block Production — Witness Plugin (witness.cpp) - -In `maybe_produce_block()`, add emergency mode awareness: - -```cpp -// After the _production_enabled check, add: - -auto &db = database(); -const auto &dgp = db.get_dynamic_global_properties(); - -if (dgp.emergency_consensus_active) { - // In emergency mode, any node with the emergency private key - // can produce blocks. The schedule only contains the emergency witness. - // - // The emergency key must be configured in the node's config: - // emergency-private-key = 5JPYE8UhnxDgURG7mFDcSPQaNjwT5VmCrq3L4QQ2sZSQhbTUZkZ - // - // This is safe because: - // 1. The key is only used during emergency mode - // 2. Any number of nodes can have this key (only one produces per slot) - // 3. Emergency mode auto-exits when normal witnesses return -} -``` - -Also add a new program option: - -```cpp -// In set_program_options: -("emergency-private-key", bpo::value>()->composing()->multitoken(), - "WIF PRIVATE KEY for emergency consensus block production") -``` - -And in `plugin_initialize`, load the emergency key alongside existing witness keys: - -```cpp -if (options.count("emergency-private-key")) { - const std::vector keys = options["emergency-private-key"].as>(); - for (const std::string &wif_key : keys) { - fc::optional private_key = graphene::utilities::wif_to_key(wif_key); - FC_ASSERT(private_key.valid(), "unable to parse emergency private key"); - pimpl->_private_keys[private_key->get_public_key()] = *private_key; - } -} -``` - -### Change 5: Emergency Witness Object — On-Chain (database.cpp) - -When entering emergency mode, ensure the emergency witness account exists in the witness index with the correct signing key: - -```cpp -// When entering emergency mode: -const auto &witness_by_name = get_index().indices().get(); -auto wit_itr = witness_by_name.find(CHAIN_EMERGENCY_WITNESS_ACCOUNT); - -if (wit_itr == witness_by_name.end()) { - // Create emergency witness object if it doesn't exist - create([&](witness_object &w) { - w.owner = CHAIN_EMERGENCY_WITNESS_ACCOUNT; - w.signing_key = CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY; - w.created = head_block_time(); - w.schedule = witness_object::top; - }); -} else { - // Ensure existing emergency witness has the correct key - modify(*wit_itr, [&](witness_object &w) { - w.signing_key = CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY; - w.schedule = witness_object::top; - }); -} -``` - -### Change 6: Emergency Mode Exit — Hybrid Schedule Transition (database.cpp) - -**Problem with the naive exit approach**: During full emergency, ALL schedule slots = "committee". Normal witnesses can't produce blocks → `last_confirmed_block_num` never updates → the exit condition `head_block_num() - w.last_confirmed_block_num < CHAIN_MAX_WITNESS_MISSED_BLOCKS` is always FALSE → **emergency never exits**. - -**Solution: Hybrid schedule** — instead of all-committee or all-real, the emergency schedule is a **mix**. Normal `update_witness_schedule()` runs, and real witnesses get their slots. Committee fills **only** the remaining slots where no real witness is assigned. - -This way: -- Witnesses that are online naturally produce at their assigned slots -- Committee covers slots where witnesses are still offline -- No special re-registration or signaling required -- The system **observes** who is actually producing - -**LIB advancement** is the natural exit signal: -- `update_last_irreversible_block()` needs 75% (16 of 21) witnesses with recent `last_supported_block_num` -- 11 witnesses producing = 52% → LIB stays frozen -- 16 witnesses producing = 76% → LIB starts moving → emergency exits - -In `update_witness_schedule()`, after recalculating the witness schedule: - -```cpp -// After normal schedule update, check emergency mode: -const dynamic_global_property_object &dgp = get_dynamic_global_properties(); - -if (dgp.emergency_consensus_active && has_hardfork(CHAIN_HARDFORK_12)) { - const witness_schedule_object &wso = get_witness_schedule_object(); - - // HYBRID SCHEDULE: Keep the normal computed schedule, but replace - // slots for witnesses that appear offline with committee. - // A witness is considered "potentially offline" if: - // - signing_key is null (disabled), OR - // - no confirmed block since emergency started - // (they haven't produced since we entered emergency) - // - // Witnesses that ARE online will produce at their assigned slots. - // Committee fills only the gaps. - - modify(wso, [&](witness_schedule_object &_wso) { - uint32_t real_witness_slots = 0; - - for (int i = 0; i < _wso.num_scheduled_witnesses; - i += CHAIN_BLOCK_WITNESS_REPEAT) { - const auto &wname = _wso.current_shuffled_witnesses[i]; - if (wname == account_name_type()) { - // Empty slot → assign committee - for (int j = 0; j < CHAIN_BLOCK_WITNESS_REPEAT && - (i+j) < _wso.num_scheduled_witnesses; ++j) { - _wso.current_shuffled_witnesses[i+j] = - CHAIN_EMERGENCY_WITNESS_ACCOUNT; - } - continue; - } - - const auto *w = find_witness(wname); - bool witness_available = w && - w->signing_key != public_key_type() && - // Has the witness produced since emergency started? - // If they have, keep their slot. - // If not, give them the slot anyway — they might be - // coming back. If they miss, it's a normal miss. - // The penalty system handles it. - true; // Always give real witnesses their slots - - if (!witness_available) { - for (int j = 0; j < CHAIN_BLOCK_WITNESS_REPEAT && - (i+j) < _wso.num_scheduled_witnesses; ++j) { - _wso.current_shuffled_witnesses[i+j] = - CHAIN_EMERGENCY_WITNESS_ACCOUNT; - } - } else { - real_witness_slots++; - } - } - - ilog("Emergency hybrid schedule: ${r} real witness slots, " - "${c} committee slots", - ("r", real_witness_slots) - ("c", CHAIN_MAX_WITNESSES - real_witness_slots)); - }); - - // EXIT CONDITION: LIB is advancing again. - // When LIB unfreezes (Change 12), it means 75% of scheduled witnesses - // are producing consistently. That's the strongest possible signal - // that the network has recovered. - // - // We check: has LIB moved past emergency_consensus_start_block? - // If yes → enough witnesses are back → exit emergency. - uint32_t current_lib = dgp.last_irreversible_block_num; - if (current_lib > dgp.emergency_consensus_start_block) { - modify(dgp, [&](dynamic_global_property_object &_dgp) { - _dgp.emergency_consensus_active = false; - }); - - ilog("EMERGENCY CONSENSUS MODE deactivated at block ${b}. " - "LIB has advanced to ${lib}, past emergency start ${start}.", - ("b", head_block_num()) - ("lib", current_lib) - ("start", dgp.emergency_consensus_start_block)); - } -} -``` - -**How the hybrid schedule works step by step**: - -``` -Step 1: Emergency activates (hour 0) - - Penalties reset (Change 7) - - update_witness_schedule() runs normally: top 11 + 10 support - - BUT all 21 witnesses are offline → all miss their slots - - Hybrid: committee fills all 21 slots - - Result: [committee × 21] — same as before - -Step 2: 5 witnesses come back online (hour 1.5) - - update_witness_schedule() computes: top 11 + 10 support - - 5 of these are online, 16 are still offline - - Hybrid: 5 get their real slots, 16 = committee - - Result: [wit1, wit2, wit3, wit4, wit5, committee × 16] - - Those 5 produce real blocks → their last_confirmed_block_num updates - - Committee produces the other 16 slots → chain continues - - LIB: only 5/21 = 24% producing → LIB stays frozen - -Step 3: 16 witnesses back (hour 3) - - Hybrid: 16 real slots + 5 committee - - 16/21 = 76% > 75% threshold - - LIB unfreezes → starts advancing - - LIB passes emergency_consensus_start_block - - Emergency mode exits! - -Step 4: All 21 witnesses back - - Normal operation, all committee slots replaced - - Schedule is 100% real witnesses -``` - -**Key insight**: The witness doesn't need to "re-register" — their `signing_key` is still set from before the emergency. They just need their node to be running and connected to P2P. The hybrid schedule gives them their slot; if they're online, they produce; if not, committee covers. - -### Change 7: Penalty Reset on Emergency Activation - -When entering emergency mode, reset all witness penalties and re-enable shut-down witnesses: - -```cpp -// When entering emergency mode: -const auto &witness_idx = get_index().indices().get(); -for (auto wit_itr = witness_idx.begin(); wit_itr != witness_idx.end(); ++wit_itr) { - modify(*wit_itr, [&](witness_object &w) { - // Re-enable witness if shut down - if (w.signing_key == public_key_type()) { - // The witness must be re-registered with their key via - // witness_update_operation. We cannot restore the key because - // we don't know it. However, we can reset penalties so that - // when they do re-register, they aren't heavily penalized. - } - // Reset all penalties - w.penalty_percent = 0; - w.counted_votes = w.votes; - // Reset miss counters - w.current_run = 0; - }); -} - -// Remove all pending penalty expiration objects -const auto &penalty_idx = get_index().indices().get(); -auto pen_itr = penalty_idx.begin(); -while (pen_itr != penalty_idx.end()) { - const auto ¤t = *pen_itr; - ++pen_itr; - remove(current); -} -``` - -### Change 8: Emergency Key Configuration in config.ini - -```ini -# WIF PRIVATE KEY for emergency consensus block production. -# This key is only used when the network enters emergency consensus mode -# (no blocks for >1 hour since last irreversible block). -# Multiple nodes can safely have this key — only one produces per slot. -# Private key: 5JPYE8UhnxDgURG7mFDcSPQaNjwT5VmCrq3L4QQ2sZSQhbTUZkZ -# Public key: VIZ75CRHVHPwYiUESy1bgN3KhVFbZCQQRA9jT6TnpzKAmpxMPD6Xv -# emergency-private-key = 5JPYE8UhnxDgURG7mFDcSPQaNjwT5VmCrq3L4QQ2sZSQhbTUZkZ -``` - -### Change 9: Automatic Safety Enforcement — Remove Human Factor (witness.cpp) - -**Problem**: Operators set `enable-stale-production=true` and `required-participation=0` to recover the network, then forget to revert. This is the #1 cause of micro-forks. - -**Solution**: After hardfork 12, the witness plugin **automatically enforces safe defaults** when the network is healthy, regardless of what the operator configured. The config values `enable-stale-production` and `required-participation` become irrelevant — the consensus layer decides. - -In `maybe_produce_block()`, replace the existing stale/participation checks with: - -```cpp -// === AUTOMATIC SAFETY ENFORCEMENT (Hardfork 12+) === -// Remove the human factor: when the network is healthy, enforce safe -// defaults regardless of operator config. Operators no longer need to -// manage enable-stale-production or required-participation manually. - -auto &db = database(); -const auto &dgp = db.get_dynamic_global_properties(); - -if (has_hardfork(CHAIN_HARDFORK_12)) { - if (!dgp.emergency_consensus_active) { - // NORMAL MODE: Always enforce safe defaults. - // - Stale check is ALWAYS active (equivalent to enable-stale-production=false) - // - Participation threshold is ALWAYS 33% (required-participation=3300) - // - // This completely removes the human factor. Even if an operator - // has enable-stale-production=true in their config, it's ignored. - - if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; - } else { - return block_production_condition::not_synced; - } - } - - uint32_t prate = db.witness_participation_rate(); - if (prate < 33 * CHAIN_1_PERCENT) { // Hardcoded 33% — not configurable - capture("pct", uint32_t(prate / CHAIN_1_PERCENT)); - return block_production_condition::low_participation; - } - } else { - // EMERGENCY MODE: Bypass both checks. - // The consensus layer has determined that emergency mode is needed. - // The witness plugin trusts the consensus-level decision and - // produces blocks without the stale/participation checks. - // No manual enable-stale-production=true needed. - _production_enabled = true; - } -} else { - // Pre-hardfork 12: use legacy behavior with config-based overrides - // (existing code for enable-stale-production and required-participation) - if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; - } else { - return block_production_condition::not_synced; - } - } - uint32_t prate = db.witness_participation_rate(); - if (prate < _required_witness_participation) { - capture("pct", uint32_t(prate / CHAIN_1_PERCENT)); - return block_production_condition::low_participation; - } -} -``` - -**Effect**: After hardfork 12, the lifecycle is fully automatic: - -| Network State | Stale Check | Participation Check | Manual Config Effect | -|---|---|---|---| -| Normal (21 witnesses healthy) | **Always ON** | **Always 33%** | Ignored | -| Emergency mode (LIB timeout) | **Auto-bypassed** | **Auto-bypassed** | Ignored | -| Pre-hardfork 12 | Config-based | Config-based | Honored (legacy) | - -Operators **never** need to touch `enable-stale-production` or `required-participation` again. - -### Change 10: Emergency Multi-Producer Collision Resolution (fork_database.cpp) - -**Problem**: When 5 nodes have the emergency key, ALL of them produce a block for the same slot simultaneously. This creates 5 competing blocks at the same height with different transactions. - -**Root cause analysis**: - -1. **Fork collision check is blind during emergency** — [witness.cpp:457](../../plugins/witness/witness.cpp#L457) checks `eb->data.witness != scheduled_witness`, but during emergency ALL blocks have `witness = "committee"`, so the condition is always `false`. The check never triggers. - -2. **fork_database uses first-seen-wins** — [fork_database.cpp:77](../../libraries/chain/fork_database.cpp#L77): `if (item->num > _head->num)` means same-height blocks don't replace head. Different nodes see different blocks first → persistent parallel chains. - -3. **Timing**: All 5 nodes wake up within milliseconds of slot boundary, check fork_db (empty), produce, broadcast. By the time P2P propagates, all 5 blocks exist. - -**Solution: Deterministic hash-based tie-breaking** - -When two blocks compete at the same height, compare their `block_id` (hash). The block with the **lower hash wins**. Since `block_id` is deterministic (hash of block content), ALL nodes converge to the same winner regardless of P2P arrival order. - -In `fork_database::_push_block()`: - -```cpp -_index.insert(item); -if (!_head || item->num > _head->num) { - _head = item; -} -// CHANGE 10: During emergency mode, deterministic hash tie-breaking. -// When two blocks compete at the same height (multiple emergency -// producers), prefer the lower block_id hash. This ensures all -// nodes converge regardless of P2P arrival order. -// Only applies during emergency — normal mode uses slot-based resolution. -else if (item->num == _head->num && item->id < _head->id && - _emergency_consensus_active) { - _head = item; -} -``` - -> Note: `_emergency_consensus_active` is a flag passed to fork_database (e.g., via `set_emergency_mode(bool)`) from `database` when emergency mode changes state. - -**Why this works**: - -``` -Slot N: 5 nodes produce blocks B1..B5 at height H - │ - ├─ Each block has a unique block_id (hash of content) - ├─ Node A receives: B1, B3, B5, B2, B4 (arrival order varies) - ├─ Node B receives: B3, B1, B4, B5, B2 - ├─ Node C receives: B2, B5, B1, B3, B4 - │ - ├─ All nodes compare hashes: min(B1.id, B2.id, B3.id, B4.id, B5.id) - ├─ All nodes converge to the SAME winner (e.g., B2 has lowest hash) - │ - └─ Result: deterministic convergence within one P2P round - -Slot N+1: fork collision check (updated below) detects the winning - block and prevents redundant production on most nodes. -``` - -**Transactions from losing blocks** (B1, B3, B4, B5) remain in each node's `_pending_tx` pool and are included in subsequent blocks. No transactions are lost. - -### Change 11: Fix Fork Collision Check for Emergency Mode (witness.cpp) - -The existing fork collision check at [witness.cpp:447-471](../../plugins/witness/witness.cpp#L447) doesn't detect emergency-mode collisions because it requires `witness != scheduled_witness`. During emergency, all blocks are from "committee". - -**Fix**: During emergency mode, ANY existing block at the target height is a competing block: - -```cpp -// Check if a competing block already exists in fork_db for this height. -{ - auto existing_blocks = db.get_fork_db().fetch_block_by_number(db.head_block_num() + 1); - if (existing_blocks.size() > 0) { - bool has_competing_block = false; - - if (dgp.emergency_consensus_active) { - // During emergency mode: ANY block at this height is competing. - // Multiple nodes with the emergency key may have produced. - // Defer to the deterministic hash-based resolution in fork_db. - has_competing_block = true; - } else { - // Normal mode: only count blocks from different witnesses - // on different parents as competing (existing logic) - for (const auto &eb : existing_blocks) { - if (eb->data.witness != scheduled_witness && - eb->data.previous != db.head_block_id()) { - has_competing_block = true; - break; - } - } - } - - if (has_competing_block) { - capture("height", db.head_block_num() + 1)("scheduled_witness", scheduled_witness); - wlog("Skipping block production at height ${h} due to existing competing block " - "in fork database (witness ${w} deferring to allow fork resolution)", - ("h", db.head_block_num() + 1)("w", scheduled_witness)); - return block_production_condition::fork_collision; - } - } -} -``` - -**Combined effect of Changes 10 + 11**: - -| Slot | What happens | Competing blocks | -|---|---|---| -| 1st emergency slot | All 5 nodes produce simultaneously (unavoidable) | 5 blocks | -| Hash resolution | All nodes converge to lowest-hash block | 1 winner | -| 2nd emergency slot | Fork collision check fires on nodes that received a block | 1-2 blocks | -| 3rd+ emergency slots | Only 1 node produces (others see block in fork_db first) | 1 block | - -The collision is a **transient startup artifact** that self-resolves within 1-2 slots (~3-6 seconds). - -### Change 12: LIB Freeze During Emergency — Partition Safety (database.cpp) - -**Problem: Competing irreversible emergency chains** - -If the network splits into 3 partitions (e.g., US, EU, Asia), each partition independently activates emergency mode after 1 hour. Each partition produces its own emergency chain with the committee key. The critical flaw: - -`update_last_irreversible_block()` ([database.cpp:4494-4631](../../libraries/chain/database.cpp#L4494)) iterates `wso.current_shuffled_witnesses`, gets each witness's `last_supported_block_num`, and uses `nth_element` at the 75% threshold. During emergency, ALL schedule slots = "committee", so the committee witness's `last_supported_block_num` dominates → **LIB advances on each partition independently**. - -This makes each partition's emergency blocks **irreversible**. When partitions reconnect via P2P, they have irreconcilable chains — the exact same problem we're trying to solve. - -``` -Partition A: blocks 1000→2200 (LIB advanced to 2180) — IRREVERSIBLE -Partition B: blocks 1000→2100 (LIB advanced to 2080) — IRREVERSIBLE -Partition C: blocks 1000→1500 (LIB advanced to 1480) — IRREVERSIBLE - ↑ - P2P reconnects — fork resolution IMPOSSIBLE - All three chains are irreversible past fork point -``` - -**Solution: Freeze LIB during emergency mode** - -Emergency blocks should NEVER become irreversible. They are temporary and must be reversible so that when partitions merge, the losing chain can be unwound. - -In `update_last_irreversible_block()`: - -```cpp -void database::update_last_irreversible_block(uint32_t skip) { - try { - const dynamic_global_property_object &dpo = get_dynamic_global_properties(); - - // === CHANGE 12: EMERGENCY LIB COMPUTATION === - // During emergency mode, compute LIB using ONLY real witnesses - // (exclude committee). This solves two problems: - // - // 1. PARTITION SAFETY: If only committee is producing, LIB stays - // frozen → all emergency blocks remain reversible → partitions - // can merge. - // - // 2. GRADUAL RECOVERY: As real witnesses return via the hybrid - // schedule (Change 6), their last_supported_block_num updates. - // When 75% of real witnesses are producing, LIB advances - // naturally → emergency exits. - // - // Without this, committee's last_supported_block_num would - // dominate, advancing LIB on each partition independently. - if (has_hardfork(CHAIN_HARDFORK_12) && dpo.emergency_consensus_active) { - const witness_schedule_object &wso = get_witness_schedule_object(); - - // Collect ONLY real (non-committee) witnesses from schedule - vector real_wit_objs; - for (int i = 0; i < wso.num_scheduled_witnesses; - i += CHAIN_BLOCK_WITNESS_REPEAT) { - const auto &wname = wso.current_shuffled_witnesses[i]; - if (wname != CHAIN_EMERGENCY_WITNESS_ACCOUNT && - wname != account_name_type()) { - real_wit_objs.push_back( - &get_witness(wname)); - } - } - - if (real_wit_objs.empty()) { - // All committee — LIB stays frozen - // Expand fork_db to accommodate emergency blocks - uint32_t emergency_fork_db_size = std::min( - dpo.head_block_number - - dpo.last_irreversible_block_num + 1, - uint32_t(CHAIN_MAX_UNDO_HISTORY)); - _fork_db.set_max_size(emergency_fork_db_size); - return; - } - - // Compute LIB using real witnesses only. - // Threshold: 75% of REAL witnesses (not total schedule). - // E.g., 16 real witnesses in schedule → need 12 (75% of 16) - // producing consistently for LIB to advance. - size_t offset = - ((CHAIN_100_PERCENT - CHAIN_IRREVERSIBLE_THRESHOLD) * - real_wit_objs.size() / CHAIN_100_PERCENT); - - std::nth_element( - real_wit_objs.begin(), - real_wit_objs.begin() + offset, - real_wit_objs.end(), - [](const witness_object *a, const witness_object *b) { - return a->last_supported_block_num < - b->last_supported_block_num; - }); - - uint32_t new_lib = - real_wit_objs[offset]->last_supported_block_num; - - if (new_lib > dpo.last_irreversible_block_num) { - // Real witnesses have advanced LIB! - // Apply the new LIB and continue with normal commit logic. - ilog("Emergency LIB advance: ${old} → ${new} " - "(${n} real witnesses producing)", - ("old", dpo.last_irreversible_block_num) - ("new", new_lib) - ("n", real_wit_objs.size())); - // ... fall through to normal LIB commit logic with new_lib ... - } else { - // Not enough real witnesses yet — keep LIB frozen - uint32_t emergency_fork_db_size = std::min( - dpo.head_block_number - - dpo.last_irreversible_block_num + 1, - uint32_t(CHAIN_MAX_UNDO_HISTORY)); - _fork_db.set_max_size(emergency_fork_db_size); - return; - } - } - - // ... existing LIB advancement logic ... -``` - -**How LIB recovery works with the hybrid schedule**: - -``` -Hour 0: Emergency activates - Schedule: [committee × 21] - Real witnesses in LIB calc: 0 - LIB: FROZEN (no real witnesses) - -Hour 1.5: 5 witnesses return - Schedule: [wit1..wit5, committee × 16] - Real witnesses: 5, threshold 75% of 5 = 4 - wit1..wit5 producing → last_supported_block_num updates - 4+ witnesses meet threshold → LIB advances for the first time! - But LIB may not yet pass emergency_consensus_start_block... - -Hour 2: 16 witnesses return - Schedule: [wit1..wit16, committee × 5] - Real witnesses: 16, threshold 75% of 16 = 12 - LIB advancing steadily - LIB passes emergency_consensus_start_block → EMERGENCY EXITS - -Hour 2+: Normal operation - Schedule: [wit1..wit21] - Standard LIB computation -``` - -Also freeze LIB in `apply_block_post_validation()` ([database.cpp:4260](../../libraries/chain/database.cpp#L4260)): - -```cpp -void database::apply_block_post_validation(block_id_type block_id, - const account_name_type &witness_account) { - try { - const dynamic_global_property_object &dpo = get_dynamic_global_properties(); - - // Don't advance LIB via post-validation during emergency mode - if (has_hardfork(CHAIN_HARDFORK_12) && dpo.emergency_consensus_active) { - return; - } - // ... existing post-validation logic ... -``` - -**How partition merge works with frozen LIB**: - -**CRITICAL PROBLEM: Different LIBs at partition time** - -The original diagram assumed all partitions have the same LIB. In reality, partitions have **different LIBs** because one partition may have had enough witnesses (75%) to advance LIB further before stalling: - -``` -Partition A: LIB=1000 emergency blocks [1001..2200] (1200 reversible) -Partition B: LIB=1010 real blocks [1001..1010] committed + emergency [1011..2100] -Partition C: LIB=1100 real blocks [1001..1100] committed + emergency [1101..1500] -``` - -The fork switching logic ([database.cpp:1096](../../libraries/chain/database.cpp#L1096)) uses **longest chain wins**: `new_head->data.block_num() > head_block_num()`. This creates a deadlock: - -``` -A receives C's chain: - C's total from fork point (1000): 500 blocks - A's total from fork point (1000): 1200 blocks - A is LONGER → WON'T SWITCH - (even though C has 100 REAL consensus blocks!) - -C receives A's chain: - Fork point: block 1000 - C's LIB = 1100 → can't pop past 1100 (undo data committed) - A's chain diverges at 1001 (before C's LIB) - C CANNOT SWITCH → undo data for blocks 1001-1100 is gone - -RESULT: DEADLOCK — both stay on their own chain -``` - -**Root cause**: Emergency blocks (meaningless filler from committee key) have **equal weight** to real-witness blocks (confirmed by 75% of actual witnesses) in the chain comparison. - -### Change 14: Vote-Weighted Chain Comparison (database.cpp) - -**Problem with simple block counting**: - -Counting "real" (non-emergency) blocks is insufficient. Consider: - -``` -Partition A: 11 top witnesses (big votes, e.g., 100K each) - → Only 11 witnesses, below 75% threshold - → LIB stalls, enters emergency eventually - → 11 real blocks per round + emergency blocks - -Partition B: 30 support witnesses (small votes, e.g., 1K each) - → Enough witnesses to keep producing (>21) - → Penalty system kicks in: missing top witnesses get penalized - → Support witnesses promoted to top 21 - → NO emergency mode → produces a normal longer chain - → 30 real blocks per round - -Block count comparison: B(30) > A(11) → B wins ✘ -But A has 11×100K = 1.1M total stake, B has 30×1K = 30K total stake -A represents FAR more consensus! -``` - -Also vulnerable to **Sybil attack**: one operator registers 10 support witnesses with tiny votes. During a partition, these 10 produce "real" blocks cheaply, inflating the block count. - -**Rule: Use cumulative `votes` (raw, unpenalized stake weight) of unique witnesses per branch.** - -Key design decisions: -- Use `votes` NOT `counted_votes` — because `counted_votes` is affected by penalties accumulated *during* the partition (a partition artifact, not real consensus signal) -- Count each **unique witness once** — prevents a single witness from inflating weight by producing many blocks -- Emergency blocks (`committee` witness) have `votes = 0` — naturally lowest priority - -In `push_block()` ([database.cpp:1089-1161](../../libraries/chain/database.cpp#L1089)): - -```cpp -if (!(skip & skip_fork_db)) { - shared_ptr new_head = _fork_db.push_block(new_block); - _maybe_warn_multiple_production(new_head->num); - - if (new_head->data.previous != head_block_id()) { - bool should_switch = false; - - if (new_head->data.block_num() > head_block_num()) { - should_switch = true; - } - - // === CHANGE 14: VOTE-WEIGHTED CHAIN COMPARISON === - // Use the sum of unique witness votes as the primary fork - // resolution criterion. Applies UNIVERSALLY (not just emergency). - // - // This handles: - // 1. Emergency vs real: committee has 0 votes → always loses - // 2. Top vs support witnesses: top have more votes → their chain wins - // 3. Sybil attack: 10 fake witnesses with tiny votes can't outweigh - // real top witnesses - // 4. Penalty manipulation: uses raw `votes` not `counted_votes`, - // so partition-induced penalties don't affect comparison - if (has_hardfork(CHAIN_HARDFORK_12)) { - auto branches = _fork_db.fetch_branch_from( - new_head->data.id(), head_block_id()); - - // Compute vote weight for each branch: - // Sum raw `votes` of UNIQUE witnesses (each counted once) - auto compute_branch_weight = [&](const branch_type &branch) - -> share_type - { - flat_set seen_witnesses; - share_type total_weight = 0; - - for (const auto &item : branch) { - const auto &witness_name = item->data.witness; - - // Skip emergency witness (votes = 0 anyway) - if (witness_name == CHAIN_EMERGENCY_WITNESS_ACCOUNT) - continue; - - // Count each witness only once - if (seen_witnesses.count(witness_name)) - continue; - seen_witnesses.insert(witness_name); - - // Use raw `votes` — not `counted_votes` — - // to ignore partition-induced penalties - const auto *w = find_witness(witness_name); - if (w) { - total_weight += w->votes; - } - } - return total_weight; - }; - - share_type new_weight = compute_branch_weight(branches.first); - share_type old_weight = compute_branch_weight(branches.second); - - if (new_weight != old_weight) { - // Primary: prefer chain with higher vote weight - should_switch = (new_weight > old_weight); - } else { - // Secondary: same vote weight → prefer longer chain - should_switch = - (new_head->data.block_num() > head_block_num()); - // Tertiary: same length → hash tie-breaking (Change 10) - } - - ilog("Vote-weighted fork comparison: " - "new_weight=${nw} (${nc} witnesses) vs " - "old_weight=${ow} (${oc} witnesses), " - "switch=${s}", - ("nw", new_weight)("nc", branches.first.size()) - ("ow", old_weight)("oc", branches.second.size()) - ("s", should_switch)); - } - - if (should_switch) { - // ... existing fork switching logic (pop + push) ... -``` - -**How this resolves ALL partition scenarios**: - -**Scenario 1: Emergency vs real (different LIBs)** -``` -Partition A (LIB=1000): committee blocks only - unique witnesses: {committee} → votes = 0 - -Partition C (LIB=1100): 11 top witnesses + committee - unique witnesses: {wit1..wit11} → votes = 11 × 100K = 1.1M - -Vote weight: C(1.1M) >> A(0) → C wins ✓ -``` - -**Scenario 2: Top witnesses vs support witnesses (no emergency on B)** -``` -Partition A: 11 top witnesses (100K votes each), enters emergency - unique witnesses: {top1..top11} → votes = 1.1M - -Partition B: 30 support witnesses (1K votes each), NO emergency - unique witnesses: {sup1..sup30} → votes = 30K - (penalty system promoted them to top, but raw votes still small) - -Vote weight: A(1.1M) >> B(30K) → A wins ✓ -Even though B has more blocks and no emergency mode! -``` - -**Scenario 3: Sybil attack (1 operator, 10 witnesses)** -``` -Partition A: 11 top witnesses (100K votes each) - unique witnesses: {top1..top11} → votes = 1.1M - -Partition B: 10 sybil witnesses (500 votes each) + 5 support (2K each) - unique witnesses: {sybil1..sybil10, sup1..sup5} → votes = 15K - -Vote weight: A(1.1M) >> B(15K) → A wins ✓ -Sybil can't manufacture vote weight! -``` - -**Scenario 4: Both partitions have similar vote weight** -``` -Partition A: 11 top witnesses (100K votes each) → 1.1M -Partition B: 10 top witnesses (100K each) + 5 support (20K each) → 1.1M - -Vote weight: A(1.1M) ≈ B(1.1M) → fall through to chain length -Longer chain wins → fall through to hash tie-breaking -``` - -**Why `votes` not `counted_votes`**: -``` -Partition B has 30 support witnesses. After partition: - - Missing top witnesses get penalized (penalty_percent increases) - - Their counted_votes drops - - Support witnesses' counted_votes relatively increases - - This is a PARTITION ARTIFACT, not real consensus - -Using raw `votes` ignores partition-induced penalties: - - top1.votes = 100K (unchanged regardless of penalties) - - sup1.votes = 1K (unchanged regardless of promotions) - - The comparison reflects REAL stake support, not temporary schedule -``` - ---- - -**Updated partition merge diagram**: - -``` -Before merge (3 partitions with DIFFERENT LIBs): - -Partition A: LIB=1000 head=2200 [0 vote weight + emergency blocks] -Partition B: LIB=1010 head=2100 [30K vote weight (support witnesses)] -Partition C: LIB=1100 head=1500 [1.1M vote weight (top witnesses)] - -P2P reconnects: - ├─ Nodes exchange blocks via P2P - ├─ Vote-weighted comparison (Change 14): - │ Primary criterion: sum of unique witness votes - │ C(1.1M) >> B(30K) >> A(0) - ├─ All nodes converge to Partition C's chain - ├─ A unwinds emergency blocks (all reversible, LIB=1000) - ├─ B unwinds its chain past LIB=1010 - ├─ Transactions from A and B return to pending pool - │ - ├─ Normal witnesses reconnect and re-register - ├─ Emergency mode exits (Change 6) - ├─ LIB unfreezes and starts advancing normally - └─ fork_db shrinks back to normal size -``` - -**Emergency duration limit**: With `CHAIN_MAX_UNDO_HISTORY = 10000` blocks and 3-second intervals, emergency mode can sustain ~8.3 hours of frozen LIB before fork_db overflow. If emergency lasts longer, the oldest reversible blocks get pruned and fork resolution scope shrinks. This is acceptable — if the network hasn't recovered after 8+ hours, manual intervention is expected. - -### Change 15: P2P Anti-Spam for Rejected Forks (node.cpp) - -**Problem**: After vote-weighted comparison rejects a peer's fork, the peer continues sending blocks from their losing chain. This wastes bandwidth and processing time, especially after partition merges when many nodes may still be on the old fork. - -**Current behavior** ([node.cpp:3253-3271](../../libraries/network/node.cpp#L3253)): -- `block_older_than_undo_history` → `peer->inhibit_fetching_sync_blocks = true` -- Invalid block → full `disconnect_from_peer()` - -**New behavior**: Add a "soft ban" for peers whose fork loses vote-weighted comparison. Instead of full disconnect, temporarily stop processing blocks from that peer for 1 hour. This allows them to eventually switch to the correct chain and reconnect. - -```cpp -// In send_sync_block_to_node_delegate() and process_block_message(): -// When push_block() rejects a block due to vote-weighted comparison: -catch (const fork_rejected_by_vote_weight &e) { - // Peer is on a losing fork. Don't disconnect fully — - // they might switch to the correct chain soon. - // Instead, temporarily ignore their blocks. - fc_wlog(fc::logger::get("sync"), - "Peer ${peer} sent block from fork rejected by " - "vote-weighted comparison. Ignoring for 1 hour.", - ("peer", originating_peer->get_remote_endpoint())); - - originating_peer->fork_rejected_until = - fc::time_point::now() + fc::seconds(3600); - originating_peer->inhibit_fetching_sync_blocks = true; -} -``` - -In `peer_connection`, add: -```cpp -fc::time_point fork_rejected_until; // soft ban expiry -``` - -In `process_block_message()` and `send_sync_block_to_node_delegate()`, check: -```cpp -if (originating_peer->fork_rejected_until > fc::time_point::now()) { - // Still soft-banned — silently discard block - return; -} -``` - -**Also increase standard `fork_db` max size**: -```cpp -// In fork_database.hpp: -static const uint32_t MAX_BLOCK_REORDERING = 2400; // was 1024 -// ~2 hours at 3s/block, enough for vote-weighted resolution -``` - -This gives the universal vote-weighted comparison enough room to operate in normal mode without emergency fork_db expansion. - -### Change 13: Keep `enable-stale-production` / `required-participation` as Manual Overrides - -Update to Change 9: the config options are NOT deprecated. They remain available as **manual overrides** for operators who want to intervene faster than the 1-hour emergency timeout. - -The auto-enforcement logic (Change 9) applies only when: -- Hardfork 12 is active AND -- The network is healthy (participation ≥ 33%, emergency mode not active) - -When the network is in distress but hasn't yet hit the 1-hour emergency threshold, operators can still manually set `enable-stale-production=true` and `required-participation=0` to accelerate recovery. The difference from the current system: once the network is healthy again, the witness plugin **automatically reverts** to safe defaults, regardless of config. - -```cpp -// Updated Change 9 logic: -if (has_hardfork(CHAIN_HARDFORK_12)) { - if (dgp.emergency_consensus_active) { - // EMERGENCY MODE: auto-bypass (no manual config needed) - _production_enabled = true; - } else { - uint32_t prate = db.witness_participation_rate(); - if (prate >= 33 * CHAIN_1_PERCENT) { - // HEALTHY NETWORK: enforce safe defaults automatically - // Even if operator has enable-stale-production=true in config, - // it's overridden because the network doesn't need it. - if (!_production_enabled) { - if (db.get_slot_time(1) >= now) { - _production_enabled = true; - } else { - return block_production_condition::not_synced; - } - } - if (prate < 33 * CHAIN_1_PERCENT) { - capture("pct", uint32_t(prate / CHAIN_1_PERCENT)); - return block_production_condition::low_participation; - } - } else { - // DISTRESSED NETWORK (participation < 33%, not yet emergency): - // Honor manual config overrides — operator may be trying to - // accelerate recovery before the 1-hour timeout. - // Fall through to legacy enable-stale-production / - // required-participation config-based behavior. - if (!_production_enabled) { - if (_production_skip_flags & database::skip_undo_history_check) { - // enable-stale-production=true → skip sync check - _production_enabled = true; - } else if (db.get_slot_time(1) >= now) { - _production_enabled = true; - } else { - return block_production_condition::not_synced; - } - } - if (prate < _required_witness_participation) { - capture("pct", uint32_t(prate / CHAIN_1_PERCENT)); - return block_production_condition::low_participation; - } - } - } -} -``` - -**Three-state behavior after HF12**: - -| Network State | Participation | `enable-stale-production` | `required-participation` | -|---|---|---|---| -| Healthy | ≥ 33% | **Ignored** (always safe) | **Ignored** (always 33%) | -| Distressed (pre-emergency) | < 33% | **Honored** (manual override) | **Honored** (manual override) | -| Emergency (auto, 1hr+ since LIB) | N/A | **Auto-bypassed** | **Auto-bypassed** | - -This preserves operator agency during the gap between "network struggling" and "full emergency activation", while still auto-reverting when the network recovers. - ---- - -## Emergency Mode Lifecycle - -### Activation - -``` -Normal Operation - │ - ├─ Witnesses start going offline - ├─ Missed blocks accumulate - ├─ Participation rate drops below 33% - ├─ Block production stops - ├─ Witnesses get shut down (signing_key = null after 200 missed blocks) - │ - ├─ 1 hour passes since last irreversible block - │ - └─ EMERGENCY MODE ACTIVATES - ├─ emergency_consensus_active = true - ├─ Witness schedule overridden: all slots → "committee" - ├─ All penalties reset to 0 - ├─ All penalty expiration objects removed - ├─ Nodes with emergency-private-key start producing blocks - └─ LIB frozen (Change 12) — all emergency blocks are reversible -``` - -### Emergency Operation - -``` -Emergency Mode Active - │ - ├─ Only "committee" witness produces blocks - ├─ Blocks signed with CHAIN_EMERGENCY_WITNESS_PUBLIC_KEY - ├─ Any node with the emergency key can produce (only one per slot) - ├─ LIB is FROZEN (Change 12) — all emergency blocks are reversible - ├─ fork_db expanded to CHAIN_MAX_UNDO_HISTORY (10000 blocks ≈ 8.3 hrs) - ├─ Multi-producer collisions resolved by hash tie-breaking (Change 10) - │ - ├─ If network is partitioned: - │ ├─ Each partition produces its own emergency chain - │ ├─ All chains remain reversible (LIB frozen) - │ └─ On reconnection: longest chain wins, losing chains unwind - │ - ├─ Operators re-register their witnesses via CLI: - │ witness_update "account" "url" {"signing_key": "VIZ..."} true - │ - ├─ Witnesses rejoin and start confirming blocks - └─ update_witness_schedule() detects normal witnesses -``` - -### Deactivation - -``` -Normal Witnesses Rejoining - │ - ├─ update_witness_schedule() runs - ├─ Detects non-emergency witnesses with valid signing keys - ├─ Emergency mode deactivates: - │ ├─ emergency_consensus_active = false - │ └─ Normal witness schedule restored - │ - └─ Normal Operation Resumes - ├─ No need to change enable-stale-production - ├─ No need to change required-participation - └─ No micro-fork risk from forgotten emergency settings -``` - ---- - -## Key Advantages Over Current Approach - -| Problem | Current Approach | Emergency Consensus Mode | -|---|---|---| -| Network stalls | Manual `enable-stale-production=true` | Automatic after 1 hour timeout | -| Low participation | Manual `required-participation=0` | Schedule override (all committee) | -| Safety bypass forgotten | Operators forget to revert → micro-forks | Auto-exits when witnesses return | -| Witness shutdown | Manual re-registration via CLI | Penalty reset; still need re-registration | -| Fork_db overflow | Solo production exceeds 1024 blocks | fork_db expanded to 10000 during emergency | -| Multiple producers | Any witness can fork | Single deterministic producer | -| Forgotten settings | enable-stale=true stays forever → micro-forks | Config ignored after HF12 (Change 9) | -| Multi-node emergency | N/A | Hash tie-breaking + collision check + vote-weighted fork comparison (Changes 10+11+14) | - ---- - -## Security Analysis - -### Emergency Private Key Security - -The emergency private key (`5JPYE8UhnxDgURG7mFDcSPQaNjwT5VmCrq3L4QQ2sZSQhbTUZkZ`) is shared among multiple nodes. This is safe because: - -1. **Only used during emergency** — the key is meaningless during normal operation -2. **Deterministic schedule** — only one node produces per slot (based on timing) -3. **Multiple nodes prevent single point of failure** — if one emergency node goes down, another takes the next slot -4. **Short duration** — emergency mode should last minutes to hours, not days -5. **Blocks are validated** — other nodes still validate blocks against consensus rules -6. **Auto-exit** — the more nodes have the key, the faster production resumes, and the faster normal witnesses can rejoin - -### Multi-Producer Collision Safety - -When N nodes have the emergency key, the first emergency slot produces N competing blocks. This is handled by a **three-layer defense**: - -1. **Deterministic hash tie-breaking** (Change 10) — `fork_database::_push_block()` compares `block_id` hashes at the same height: lower hash wins. ALL nodes converge to the same block regardless of P2P arrival order. No transactions are lost — losing blocks' txs stay in `_pending_tx`. - -2. **Emergency-aware fork collision check** (Change 11) — after the first slot, nodes that received any block at the target height skip production entirely, deferring to the hash-based winner. - -3. **Self-resolving** — collision only affects the 1st emergency slot (5 blocks), drops to 1-2 blocks by slot 2, and reaches 1 block by slot 3+. Total extra overhead: ~5 blocks in the first 3-6 seconds. - -### Automatic Safety Enforcement - -After hardfork 12, `enable-stale-production` and `required-participation` config options are **context-dependent** (Change 9 + Change 13): -- **Healthy network** (≥ 33% participation): config ignored, safe defaults enforced automatically -- **Distressed network** (< 33%, not yet emergency): config honored as manual overrides -- **Emergency mode**: auto-bypassed, no config needed - -This eliminates the most common cause of micro-forks (forgotten emergency settings) while preserving operator agency during the pre-emergency window. - -### Attack Vectors - -| Attack | Mitigation | -|---|---| -| Malicious actor with emergency key produces invalid blocks | Consensus validation still applies; invalid blocks are rejected | -| Emergency mode activated during normal operation (time attack) | Only activates if LIB timestamp is >1 hour old; during normal ops, LIB advances every few seconds | -| Emergency key holder censors transactions | Emergency mode is temporary; all transactions are public and will be included when normal witnesses return | -| Emergency mode never exits | Exits automatically when any normal witness with valid key produces a block | -| 5 nodes produce competing emergency blocks | Hash-based tie-breaking ensures deterministic convergence within 1 P2P round; fork collision check reduces to 1 producer by slot 3 | -| Operator forgets to revert enable-stale-production | After HF12, config is ignored in healthy mode — consensus layer controls bypass automatically | -| Partitions with different LIBs enter emergency independently | Vote-weighted chain comparison (Change 14) sums unique witness `votes` per branch; chain with more stake-weighted consensus wins regardless of length | - ---- - -## Implementation Plan - -### Phase 1: Non-Breaking Changes (No Hardfork Required) - -These can be deployed immediately without network-wide upgrade: - -| Change | File | Description | -|---|---|---| -| Emergency private key option | `witness.cpp` | Add `emergency-private-key` config option | -| Emergency key loaded into key map | `witness.cpp` | Load emergency key alongside witness keys | -| Emergency mode logging | `witness.cpp` | Log when emergency witness is scheduled | - -### Phase 2: Hardfork 12 (Requires Network-Wide Upgrade) - -| Change | Breaking | Files Modified | -|---|---|---| -| `emergency_consensus_active` field in DGP | Yes (serialized object) | `global_property_object.hpp`, `database.cpp`, `snapshot/plugin.cpp` | -| `emergency_consensus_start_block` field in DGP | Yes (serialized object) | `global_property_object.hpp`, `database.cpp`, `snapshot/plugin.cpp` | -| Emergency mode activation logic | Yes (consensus behavior) | `database.cpp` `update_global_dynamic_data()` | -| Emergency mode exit logic | Yes (consensus behavior) | `database.cpp` `update_witness_schedule()` | -| Schedule override during emergency | Yes (consensus behavior) | `database.cpp` `update_witness_schedule()` | -| Penalty reset on emergency activation | Yes (consensus behavior) | `database.cpp` | -| Emergency witness object creation | Yes (consensus behavior) | `database.cpp` | -| FC_REFLECT update for DGP | Yes (serialization) | `global_property_object.hpp` | -| Snapshot export/import update | Yes (new fields) | `plugins/snapshot/plugin.cpp` | -| config.ini template update | No | `share/vizd/config/` | -| Auto safety enforcement in witness plugin | Yes (consensus behavior) | `witness.cpp` `maybe_produce_block()` | -| Deterministic hash tie-breaking in fork_db | Yes (fork resolution) | `fork_database.cpp` `_push_block()` | -| LIB freeze + fork_db expansion during emergency | Yes (consensus behavior) | `database.cpp` `update_last_irreversible_block()`, `apply_block_post_validation()` | -| Manual override preservation (enable-stale/required-participation) | No (witness plugin) | `witness.cpp` | -| Emergency-aware chain comparison | Yes (fork resolution) | `database.cpp` `push_block()` — vote-weighted using `witness.votes` (universal) | -| P2P anti-spam for rejected forks | No (P2P layer) | `node.cpp` — soft-ban peers on losing forks for 1 hour | -| fork_db standard size increase to 2400 | Yes (fork resolution) | `fork_database.hpp` `MAX_BLOCK_REORDERING = 2400` | - -### Hardfork 12 Definition - -**File**: `libraries/chain/hardfork.d/12.hf` - -```cpp -// 12 Hardfork — Emergency Consensus Recovery -#ifndef CHAIN_HARDFORK_12 -#define CHAIN_HARDFORK_12 12 -#define CHAIN_HARDFORK_12_TIME // To be determined by witness vote -#define CHAIN_HARDFORK_12_VERSION hardfork_version( version(3, 1, 0) ) -#endif -``` - -All emergency consensus logic should be gated behind: - -```cpp -if (has_hardfork(CHAIN_HARDFORK_12)) { - // Emergency consensus mode logic -} -``` - ---- - -## Alternative Approaches Considered - -### Alternative A: Time-Based Auto-Revert of Emergency Settings - -Instead of on-chain emergency mode, add a timeout to `enable-stale-production` and `required-participation`: - -```ini -enable-stale-production = true -enable-stale-production-timeout = 3600 # Auto-revert after 1 hour -required-participation = 0 -required-participation-timeout = 3600 # Auto-revert after 1 hour -``` - -**Rejected because**: -- Still requires manual activation (operators must set emergency values) -- Auto-revert timing is hard to get right — too short and recovery fails, too long and micro-forks happen -- Doesn't address witness shutdown/penalty issues -- fork_db overflow still possible if revert happens while isolated - -### Alternative B: Increased fork_db Size - -Increase `_max_size` from 1024 to a larger value (e.g., 10000 blocks ≈ 8.3 hours). - -**Rejected because**: -- Only delays the problem, doesn't solve it -- Increases memory usage significantly -- Still doesn't prevent micro-forks from happening -- Doesn't address the root cause (solo production on isolated fork) - -### Alternative C: P2P-Level Fork Detection - -Add P2P-level fork detection where nodes gossip about fork depth and automatically prefer the chain with more witness participation. - -**Rejected because**: -- Complex P2P protocol changes -- Vulnerable to Sybil attacks (fake participation claims) -- Doesn't help if witnesses are genuinely offline -- Doesn't address the need for actual block production during a stall - -### Alternative D: BFT-Style Fallback to Committee Multisig - -Require M-of-N committee signatures for emergency blocks instead of a single key. - -**Rejected because**: -- More complex implementation -- Requires committee members to be online during emergency (defeats the purpose) -- Single-key emergency is simpler and the key is only used during emergencies -- Can be upgraded to multisig later if needed - ---- - -## Test Scenarios - -### Scenario 1: Normal Emergency Activation and Recovery - -1. Start network with 21 witnesses -2. Shut down 15 witnesses (leaving 6 — below 33% participation) -3. Wait for network to stall -4. Wait 1 hour → emergency mode activates -5. Emergency committee produces blocks -6. Restart 15 witnesses, re-register their keys -7. Emergency mode exits → normal production resumes - -**Expected**: No manual intervention beyond restarting witness nodes - -### Scenario 2: Network Partition (Micro-Fork Prevention) - -1. Normal network operation (no emergency settings active) -2. Network partition isolates 5 witnesses from 16 -3. Both sides see participation drop -4. Minority side (5): participation < 33% → production stops -5. Majority side (16): participation still > 33% → continues -6. Partition resolves → minority side syncs from majority - -**Expected**: No micro-forks because emergency settings were never manually activated - -### Scenario 3: Complete Network Stall + Recovery - -1. All 21 witnesses go offline (e.g., datacenter power failure) -2. After 1 hour → emergency mode activates on all nodes with emergency key -3. One node produces blocks with committee key -4. Witnesses come back online one by one -5. Each witness re-registers via CLI -6. After enough witnesses are active → emergency mode exits - -**Expected**: Chain continues without full stall; LIB frozen during emergency, unfreezes when witnesses return - -### Scenario 4: Network Partition During Emergency - -1. All 21 witnesses go offline -2. After 1 hour → emergency mode activates on all partitions independently -3. Network is split into 3 partitions (US, EU, Asia) -4. Each partition produces emergency blocks with committee key -5. LIB is frozen on all partitions (Change 12) -6. After 2 hours, P2P connectivity restores between partitions -7. Longest chain wins, losing partitions unwind -8. Normal witnesses re-register, emergency mode exits - -**Expected**: Partition merge succeeds because all emergency blocks are reversible. No manual intervention needed beyond witness re-registration. - ---- - -## Open Questions - -1. **Should the emergency timeout be configurable on-chain?** **RESOLVED**: No. Keep it hardcoded at 1 hour (`CHAIN_EMERGENCY_CONSENSUS_TIMEOUT_SEC = 3600`). One hour is human-friendly and predictable. Making it on-chain configurable adds complexity without benefit — the timeout is a safety constant, not a tunable parameter. Emergency mode only applies to nodes running the witness plugin. - -2. **Should the emergency witness produce blocks with empty transactions?** **RESOLVED**: Emergency blocks **CAN** be empty but **not forced empty**. Transactions must still be processable because witnesses may need to broadcast `witness_update_operation` to re-register their signing key during the hybrid schedule transition (Change 6). If emergency blocks were forced empty, witnesses couldn't re-activate — creating a deadlock where emergency never exits. In practice, most emergency blocks will be empty (low tx volume during a stall), but the mechanism must not prohibit transactions. - -3. ~~**What happens if multiple nodes with the emergency key produce blocks simultaneously?**~~ **RESOLVED** (Changes 10+11): Deterministic hash tie-breaking in `fork_database::_push_block()` ensures all nodes converge to the same block (lowest `block_id` wins). Emergency-aware fork collision check prevents redundant production after the first slot. Multi-producer collision is a transient 1-2 slot artifact. - -4. **Should the emergency private key be rotated?** **RESOLVED**: No. There's no reason to rotate. The `committee` system account signs emergency blocks only when emergency mode is active. Nodes without the emergency key simply don't produce during emergency — they still validate and accept emergency blocks from peers. The key has no value outside emergency mode, and rotating it would require a hardfork for zero security benefit. - -5. **Should emergency blocks have special extensions?** **RESOLVED**: No. Emergency blocks are already identifiable by `witness = "committee"` (the system account). No additional header extension needed — monitoring tools can simply filter by witness name. - -6. **What is the minimum number of normal witnesses required to exit emergency mode?** **RESOLVED** (Change 6): Emergency exits when **LIB advances past `emergency_consensus_start_block`**. LIB advancement requires 75% (16 of 21) witnesses producing consistently (`CHAIN_IRREVERSIBLE_THRESHOLD = 7500`). So effectively: **16 witnesses** must be online and producing. With 11 witnesses = 52% → LIB stays frozen, emergency continues. The hybrid schedule (Change 6) mixes real witnesses alongside committee: witnesses get their normal slots, committee fills gaps. No special re-registration needed — witnesses just need to be running with their pre-existing `signing_key`. - -7. **Should the deterministic hash tie-breaking apply only during emergency mode?** **RESOLVED**: Yes, gate it behind `emergency_consensus_active` only. In normal mode, witnesses have assigned slots and forks are resolved through the existing scheduling mechanism. Hash tie-breaking is only needed during emergency when multiple nodes produce with the same committee key at the same slot. - -8. **Should `enable-stale-production` and `required-participation` config options be deprecated after HF12?** **RESOLVED** (Change 13): Keep them. They serve as manual overrides during the "distressed" phase (participation < 33% but < 1 hour since LIB). Change 9 auto-reverts to safe defaults when the network is healthy. Three-state behavior: Healthy → ignored, Distressed → honored, Emergency → auto-bypassed. - -9. **What happens when partitions with independent emergency chains reconnect?** **RESOLVED** (Changes 12+14): LIB is frozen during emergency mode. All emergency blocks are reversible. When partitions merge, the chain with higher **cumulative witness vote weight** wins (Change 14), not the longest chain. Uses raw `votes` (not `counted_votes`) to ignore partition-induced penalties. Handles top-vs-support witness splits and sybil attacks. Maximum emergency duration before fork_db overflow: ~8.3 hours (`CHAIN_MAX_UNDO_HISTORY = 10000` blocks). - -11. **What if one operator controls multiple support witnesses (Sybil)?** **RESOLVED** (Change 14): Vote-weighted comparison uses raw `votes` field. A sybil with 10 support witnesses (500 votes each = 5K total) can't outweigh a partition with even 1 top witness (100K votes). The cost of manufacturing vote weight is proportional to real stake — same security assumption as the entire DPoS model. - -12. **Should vote-weighted comparison apply outside of emergency mode?** **RESOLVED**: Yes. Apply universally for all fork resolution (not just emergency). This makes fork resolution stake-aware — forks backed by more stake-weighted witnesses are always preferred. Also increase `fork_db` standard max size from 1024 to 2400 blocks (~2 hours at 3s/block) to give more room for fork resolution. Combined with Change 15 (P2P anti-spam), rejected fork blocks don't flood the network. - -13. **How to prevent P2P spam from peers on rejected forks?** **RESOLVED** (Change 15): When vote-weighted comparison rejects a peer's fork, temporarily ignore blocks from that peer for 1 hour. The P2P layer already disconnects peers sending invalid blocks ([node.cpp:3264-3271](../../libraries/network/node.cpp#L3264)). Change 15 extends this: instead of full disconnect, add a "soft ban" timeout so the peer can reconnect later on the correct chain. - ---- - -## Reference: Key Constants - -| Constant | Value | Meaning | Source | -|---|---|---|---| -| `CHAIN_BLOCK_INTERVAL` | 3 | Seconds per block | [config.hpp:27](../../libraries/protocol/include/graphene/protocol/config.hpp#L27) | -| `CHAIN_MAX_WITNESSES` | 21 | Maximum scheduled witnesses | [config.hpp:41](../../libraries/protocol/include/graphene/protocol/config.hpp#L41) | -| `CHAIN_MAX_TOP_WITNESSES` | 11 | Top voted witnesses | [config.hpp:39](../../libraries/protocol/include/graphene/protocol/config.hpp#L39) | -| `CHAIN_MAX_SUPPORT_WITNESSES` | 10 | Support witnesses | [config.hpp:40](../../libraries/protocol/include/graphene/protocol/config.hpp#L40) | -| `CHAIN_MAX_WITNESS_MISSED_BLOCKS` | 200 | ~10 min before shutdown | [config.hpp:32](../../libraries/protocol/include/graphene/protocol/config.hpp#L32) | -| `CHAIN_IRREVERSIBLE_THRESHOLD` | 7500 (75%) | LIB advancement threshold | [config.hpp:110](../../libraries/protocol/include/graphene/protocol/config.hpp#L110) | -| `CHAIN_IRREVERSIBLE_SUPPORT_MIN_RUN` | 2 | Blocks before supporting LIB | [config.hpp:112](../../libraries/protocol/include/graphene/protocol/config.hpp#L112) | -| `CHAIN_MAX_UNDO_HISTORY` | 10000 | Max head-LIB gap | [config.hpp:108](../../libraries/protocol/include/graphene/protocol/config.hpp#L108) | -| `fork_db._max_size` | 2400 (was 1024) | Fork database depth (~2 hours) | [fork_database.hpp:117](../../libraries/chain/include/graphene/chain/fork_database.hpp#L117) | -| `CONSENSUS_WITNESS_MISS_PENALTY_PERCENT` | 100 (1%) | Miss penalty per block | [config.hpp:127](../../libraries/protocol/include/graphene/protocol/config.hpp#L127) | -| `CONSENSUS_WITNESS_MISS_PENALTY_DURATION` | 1 day | Penalty expiration | [config.hpp:128](../../libraries/protocol/include/graphene/protocol/config.hpp#L128) | diff --git a/build_mingv.sh b/build_mingw.sh similarity index 100% rename from build_mingv.sh rename to build_mingw.sh