资讯动态

EOSIO Context-Free Data(CFD)详解:交易无上下文数据机制与 eosio-blocklog 剪枝实战

发布时间:2026/9/23 18:02:39 来源:尧图企业网站定制
区块链【免费下载链接】eosAn open source smart contract platform项目地址https://gitcode.com/gh_mirrors/eo/eos点击查看免费下载本篇技术指南围绕 EOSIO 区块链交易中的特殊数据段Context-Free Data无上下文数据简称 CFD展开系统讲解其概念定义、典型使用场景、剪枝pruning机制的设计动机与安全边界并结合eosio-blocklog命令行工具给出完整、可复现的 CFD 剪枝操作步骤。阅读完本文你将掌握CFD 在交易结构中的存储形态与源码级实现、nodeos 支持剪枝所需满足的六项能力以及如何在已定稿finalized区块的区块日志中安全移除交易的无上下文数据同时理解剪枝对节点验证模式全量验证 / 轻量验证与链完整性的影响边界。Overview为什么需要 Context-Free Data区块链的不可变性immutability使得数据可以被安全地存储同时保证数据的完整性integrity。然而这一优势也带来一个副作用移除链上非必要数据变得非常困难。为此EOSIO 区块链在交易transaction内开辟了一个特殊的数据段称为context-free data无上下文数据。正如其名称所示存储在该数据段中的数据被视为不依赖任何先前上下文或依赖关系free of previous contexts or dependencies因此它们具备被移除的可能性。更重要的是这种移除可以在不损害区块链完整性的前提下安全执行。区块链完整性提示对 context-free data 的剪枝并不会削弱或放松区块链的安全性。配置为全量验证模式full validation mode的节点仍然能够检测出包含被剪枝交易数据的区块上的完整性违规行为。概念什么数据适合放入 Context-Free Data设计 context-free data 的目标是让区块链应用在交易中有选择地存储非关键信息。原文档给出的典型示例包括具有瞬时性或临时性的二级区块链数据secondary blockchain data与交易消息相关联的短期、非关键数据用户在某篇链上文章下发表的评论内容。概括而言任何对区块链运行和完整性并非至关重要的数据都可以作为 context-free data 存储。此外它还可以用于满足特定区域关于数据使用和个人信息方面的法律法规要求例如在需要时可被移除的个人数据。从概念上理解context-free data 与普通 action 数据的关键区别在于它不参与交易签名与权限校验的核心逻辑剪枝后不会破坏区块与交易的完整性校验。交易结构中的 CFD源码视角为理解剪枝究竟“剪”掉了什么需要先看清 CFD 在交易结构中的位置。在signed_transaction中与 CFD 直接相关的有两个字段见 transaction.hppcontext_free_actions无上下文动作列表如示例中的payloadless合约的doit动作context_free_data一个vectorbytes每个 context-free action 对应一个数据条目。交易被打包为packed_transaction后这些可剪枝内容被归纳到prunable_data可剪枝数据结构中。其类型是一个std::variant见 transaction.hpp包含四种状态| variant 成员 | 含义 | |-|-| |full_legacy| 旧版完整形态含signatures、packed_context_free_data与context_free_segments| |full| 新版完整形态含signatures与context_free_segments| |partial| 部分剪枝形态仅保留可校验的摘要信息 | |none| 无可剪枝数据 |剪枝操作在源码层面等价于调用prunable_data_type::prune_all()将变体从full/full_legacy状态切换为partial状态。这一设计正是链完整性得以保留的关键即便签名字段被清空、CFD 段被移除prunable_digest()见 transaction.hpp 与 transaction.hpp仍能对剩余内容计算摘要全量验证节点可据此发现任何完整性违规。需要特别留意的是源码中的两个接口语义见 transaction.hppget_signatures()若签名已被剪枝则返回 nullptrget_context_free_data()若任一 context-free data 段已被剪枝则返回 nullptr。这从侧面说明一旦数据被剪枝节点便无法再取回原始签名与 CFD 内容只能依赖摘要完成校验——这是理解剪枝后只能进行“轻量区块验证”的关键。剪枝Pruning机制使用 context-free data 的区块链应用往往希望在不影响链完整性的前提下移除其内容。这一目标通过pruning剪枝流程实现。移除与某交易关联的 context-free data为区块链应用带来两项能力提供一种删除不依赖任何上下文或相互依赖的交易数据的机制提供一种在移除该类数据的同时维持区块链完整性的途径。需要明确的是context-free data 的剪枝仅允许在可信节点之间进行轻量区块验证light block validation。完整的区块验证——包括交易签名验证与权限授权检查transaction signature verification and permission authorization checks——在发生剪枝的区块和交易上无法在不违反完整性校验的前提下完全进行。私有链上的剪枝私有 EOSIO 区块链是 context-free data 剪枝的最大受益者。其受控的运行环境允许可信节点以轻量验证模式运行从而使区块链应用能够在私有 EOSIO 链上充分使用这一强大特性。nodeos 对剪枝的支持Pruning Supportnodeos对 context-free data 剪枝的支持体现在以下六个方面原文档明确列出的要求正确处理已定稿区块中、交易被剪枝后移除的 context-free data高效删除任意已定稿交易内既有的 context-free data正确处理由state history 插件生成、且 context-free data 已被移除的交易追踪transaction traces高效删除state history 插件所用 trace 日志中已定稿交易内既有的 context-free data支持点对点P2P同步包含被移除 context-free data 的区块提供工具支持在不可逆区块日志irreversible blocks log与 state history 插件 trace 日志中实际执行 CFD 剪枝。剪枝工具节点运营者可以使用eosio-blocklog实用工具对给定交易执行 context-free data 剪枝。具体操作步骤见 如何剪枝 context-free data。剪枝的源码级实现区块日志blocks.log中的剪枝在 block_log.cpp 中block_log::prune_transactions(block_num, ids)负责定位指定区块号的流然后调用内部的prune_trxs完成实际剪枝。其核心逻辑见 block_log.cpp为遍历区块内的每笔交易若交易 ID 命中待剪枝列表则调用ptx.prune_all()将已剪枝的 ID 从待处理列表中移除若该区块内发生了任意交易的剪枝将区块标记为signed_block::prune_state_type::incomplete见 block.hpp该枚举还包含complete与complete_legacy从区块起始位置重新打包区块数据并写回流。state history trace 日志中的剪枝在 state_history/log.cpp 中state_history_traces_log::prune_transactions对 trace 日志执行同样操作。一个重要的实现事实是trace 日志版本 0version 0不支持交易剪枝代码通过EOS_ASSERT(version 0, ...)显式拒绝在旧版本日志上执行剪枝。eosio-blocklog 中的调度入口在 eosio-blocklog/main.cpp 中prune_transactions分别对block_log区块日志与state_history_traces_logtrace 日志执行剪枝并把两者的结果累加若未能完全剪掉所有指定交易会将未剪枝的交易 ID 输出到stderr。同时main.cpp 明确提示未指定--block-num与--transaction时--prune-transactions不执行任何操作。eosio-blocklog 工具参考eosio-blocklog是一个命令行界面CLI实用工具允许节点运营者对nodeos实例产生的区块日志执行底层操作。它支持以下操作将一定范围的区块转换为 JSON 格式单对象或数组依据blocks目录下的blocks.log生成blocks.index在指定区块范围内裁剪trimblocks.log与blocks.index在blocks.log与blocks.index之间执行一致性测试若blocks.log损坏修复并重建blocks.index剪枝给定交易按交易 ID 与区块号内的 context-free data将操作结果输出到文件或stdout默认。完整选项表| 选项默认值 | 说明 | |-|-| |--blocks-dir arg (blocks)| 区块目录的位置绝对路径或相对于当前目录的相对路径 | |--state-history-dir arg (state-history)|state-history目录的位置绝对路径或相对于当前目录的相对路径 | |-o [ --output-file ] arg| 生成输出所写入的文件绝对或相对路径。未指定时输出到stdout| |-f [ --first ] arg (0)| 要记录的第一个区块号若指定trim-blocklog则为要保留的第一个区块 | |-l [ --last ] arg (4294967295)| 要记录的最后一个区块号若指定trim-blocklog则为要保留的最后一个区块 | |--no-pretty-print| 不进行美化打印。若需管道传给jq以提高性能可启用此选项 | |--as-json-array| 将 JSON 区块以 JSON 数组形式输出否则输出为独立 JSON 对象 | |--make-index| 依据blocks.log创建blocks.index。必须指定blocks-dir位置。output-file可相对当前目录或使用绝对路径默认是blocks-dir/blocks.index | |--trim-blocklog| 裁剪blocks.log与blocks.index。必须指定blocks-dir并给出first和/或last选项 | |--fix-irreversible-blocks| 当既有区块日志与索引不一致时自动修复区块日志与索引文件——若最高索引区块有效则采用之否则修复区块日志并重建索引 | |--smoke-test| 快速测试blocks.log与blocks.index是否格式良好且相互一致 | |--block-num arg (0)| 包含待剪枝交易的区块号 | |-t [ --transaction ] arg| 待剪枝的交易 ID | |--prune-transactions| 剪枝指定区块号block-num中指定交易内的 context-free data 与签名 | |-h [ --help ]| 打印帮助信息并退出 |退出行为当eosio-blocklog启动时工具会尝试执行指定操作并产生以下两种结果之一成功所选操作执行完毕工具以零错误码无错误退出失败工具向stderr输出错误信息并以非零错误码表示错误退出。实战如何剪枝交易中的 Context-Free Data以下操作步骤来自 如何剪枝 context-free data展示了从一笔交易中剪枝 context-free data 的完整流程启动eosio-blocklog工具并携带--prune-transactions选项、包含 context-free data 的交易 ID以及下文指定的附加选项。公有链上的数据剪枝警告交易数据剪枝不适用于公有 EOSIO 区块链除非事先已通过 EOSIO 共识机制获得生产者绝对多数supermajority的同意。即使公有 EOSIO 网络上的某个出块节点剪枝了交易中的 context-free data也只会影响该节点自身区块链的完整性不会被破坏。前置条件开始操作前需要提前确认或完成以下事项拥有一个已定稿区块finalized block中、包含 context-free data 的已失效交易retired transactionID熟悉交易的 context-free data 数据段复习eosio-blocklog命令行实用工具参考。操作步骤按以下步骤剪枝交易中的 context-free data定位你想要剪枝的交易 ID例如trx_id交易 ID 也可在交易的id字段中找到定位包含该交易的区块号例如block_num确保与交易的block_num字段一致找到区块目录与 state history 目录如适用例如blocks_dir与state_hist_dir按如下方式启动eosio-blocklogeosio-blocklog [--blocks-dir blocks_dir] [--state-history-dir state_hist_dir] --prune-transactions --block-num block_num --transaction trx_id [--transaction trx_id2 ...]若操作成功eosio-blocklog静默退出错误码为零无错误区块日志中被剪枝交易内的以下字段被更新prunable_data[prunable_data][0]字段从 0 变为 1signatures字段被置为空数组context_free_data字段被置为空数组packed_context_free_data字段若存在被移除。若操作失败eosio-blocklog向stderr输出错误并以非零错误码退出。补充说明若多笔交易位于同一区块内可一次性向eosio-blocklog传入多个交易 ID可使用eosio-blocklog展示包含被剪枝交易的区块。完整示例以下示例复现上述 操作步骤 中的全过程。剪枝前的交易样本以下是一笔包含 context-free data 的交易样本{ id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, trx: { receipt: { status: executed, cpu_usage_us: 155, net_usage_words: 14, trx: [ 1, { compression: none, prunable_data: { prunable_data: [ 0, { signatures: [ SIG_K1_K3AJXEMFH99KScLFC1cnLA3WDnVK7WRsS8BtafHfP4VWmfQXXwX21KATVVtrCqopkcve6V8noc5bS4BJkwgSsonpfpWEJi ], packed_context_free_data: 0203a1b2c3031a2b3c } ] }, packed_trx: ec42545f7500ffe8aa290000000100305631191abda90000000000901d4d00000100305631191abda90000000000901d4d0100305631191abda900000000a8ed32320000 } ] }, trx: { expiration: 2020-09-06T02:01:16, ref_block_num: 117, ref_block_prefix: 699066623, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [ { account: payloadless, name: doit, authorization: [], data: } ], actions: [ { account: payloadless, name: doit, authorization: [ { actor: payloadless, permission: active } ], data: } ], signatures: [ SIG_K1_K3AJXEMFH99KScLFC1cnLA3WDnVK7WRsS8BtafHfP4VWmfQXXwX21KATVVtrCqopkcve6V8noc5bS4BJkwgSsonpfpWEJi ], context_free_data: [ a1b2c3, 1a2b3c ] } }, block_time: 2020-09-06T02:00:47.000, block_num: 119, last_irreversible_block: 128, traces: [ { action_ordinal: 1, creator_action_ordinal: 0, closest_unnotified_ancestor_action_ordinal: 0, receipt: { receiver: payloadless, act_digest: 4f09a630d4456585ee4ec5ef96c14151587367ad381f9da445b6b6239aae82cf, global_sequence: 156, recv_sequence: 2, auth_sequence: [], code_sequence: 1, abi_sequence: 1 }, receiver: payloadless, act: { account: payloadless, name: doit, authorization: [], data: }, context_free: true, elapsed: 206, console: Im a payloadless action, trx_id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, block_num: 119, block_time: 2020-09-06T02:00:47.000, producer_block_id: null, account_ram_deltas: [], account_disk_deltas: [], except: null, error_code: null, return_value_hex_data: }, { action_ordinal: 2, creator_action_ordinal: 0, closest_unnotified_ancestor_action_ordinal: 0, receipt: { receiver: payloadless, act_digest: b8871e8f3c79b02804a2ad28acb015f503e7f6e56f35565e5fa37b6767da1aa5, global_sequence: 157, recv_sequence: 3, auth_sequence: [ [ payloadless, 3 ] ], code_sequence: 1, abi_sequence: 1 }, receiver: payloadless, act: { account: payloadless, name: doit, authorization: [ { actor: payloadless, permission: active } ], data: }, context_free: false, elapsed: 11, console: Im a payloadless action, trx_id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, block_num: 119, block_time: 2020-09-06T02:00:47.000, producer_block_id: null, account_ram_deltas: [], account_disk_deltas: [], except: null, error_code: null, return_value_hex_data: } ] }执行步骤以上述交易复现操作步骤定位交易 ID1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23定位区块号119找到区块目录与 state history 目录如适用例如blocks_dir与state_hist_dir按如下方式启动eosio-blocklogeosio-blocklog --blocks-dir blocks_dir --state-history-dir state_hist_dir --prune-transactions --block-num 119 --transaction 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23若成功工具静默返回若失败工具向stderr输出错误。剪枝后的交易样本再次获取该交易时被剪枝的交易呈现如下形态{ id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, trx: { receipt: { status: executed, cpu_usage_us: 155, net_usage_words: 14, trx: [ 1, { compression: none, prunable_data: { prunable_data: [ 1, { digest: 6f29ea8ab323ffee90585238ff32300c4ee6aa563235ff05f3c1feb855f09189 } ] }, packed_trx: ec42545f7500ffe8aa290000000100305631191abda90000000000901d4d00000100305631191abda90000000000901d4d0100305631191abda900000000a8ed32320000 } ] }, trx: { expiration: 2020-09-06T02:01:16, ref_block_num: 117, ref_block_prefix: 699066623, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [ { account: payloadless, name: doit, authorization: [], data: } ], actions: [ { account: payloadless, name: doit, authorization: [ { actor: payloadless, permission: active } ], data: } ], signatures: [], context_free_data: [] } }, block_time: 2020-09-06T02:00:47.000, block_num: 119, last_irreversible_block: 131, traces: [ { action_ordinal: 1, creator_action_ordinal: 0, closest_unnotified_ancestor_action_ordinal: 0, receipt: { receiver: payloadless, act_digest: 4f09a630d4456585ee4ec5ef96c14151587367ad381f9da445b6b6239aae82cf, global_sequence: 156, recv_sequence: 2, auth_sequence: [], code_sequence: 1, abi_sequence: 1 }, receiver: payloadless, act: { account: payloadless, name: doit, authorization: [], data: }, context_free: true, elapsed: 206, console: Im a payloadless action, trx_id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, block_num: 119, block_time: 2020-09-06T02:00:47.000, producer_block_id: null, account_ram_deltas: [], account_disk_deltas: [], except: null, error_code: null, return_value_hex_data: }, { action_ordinal: 2, creator_action_ordinal: 0, closest_unnotified_ancestor_action_ordinal: 0, receipt: { receiver: payloadless, act_digest: b8871e8f3c79b02804a2ad28acb015f503e7f6e56f35565e5fa37b6767da1aa5, global_sequence: 157, recv_sequence: 3, auth_sequence: [ [ payloadless, 3 ] ], code_sequence: 1, abi_sequence: 1 }, receiver: payloadless, act: { account: payloadless, name: doit, authorization: [ { actor: payloadless, permission: active } ], data: }, context_free: false, elapsed: 11, console: Im a payloadless action, trx_id: 1b9a9c53f9b692d3382bcc19c0c21eb22207e2f51a30fe88dabbb45376b6ff23, block_num: 119, block_time: 2020-09-06T02:00:47.000, producer_block_id: null, account_ram_deltas: [], account_disk_deltas: [], except: null, error_code: null, return_value_hex_data: } ] }字段变化说明对比剪枝前后可观察到被剪枝交易中以下字段发生了变化prunable_data[prunable_data][0]字段变为 1即prunable_data变体从完整形态切换为partial形态仅保留digest摘要signatures字段现在为空数组context_free_data字段为空数组packed_context_free_data字段被移除。值得注意的是剪枝后的prunable_data中保留了digest即源码中的prunable_digest这正是“移除签名与 CFD 内容后仍能维持链完整性校验”的实现载体。注意事项与最佳实践公有链默认不适用除非已通过 EOSIO 共识获得生产者绝对多数同意否则不应在公有 EOSIO 区块链上剪枝交易数据即便执行了也仅影响执行节点自身不会破坏链完整性。私有链是首选场景私有 EOSIO 链的受控环境允许可信节点以轻量验证模式运行是 context-free data 剪枝功能的最佳落地场景例如满足数据使用与个人信息相关的合规要求。验证模式限制剪枝后区块仅能在可信节点间进行轻量验证涉及签名验证与权限授权检查的全量验证无法在剪枝区块上完整执行。trace 日志版本约束从源码state_history/log.cpp可以确认state history 插件的trace 日志版本 0 不支持交易剪枝需确保 trace 日志版本高于 0。命令行校验未同时指定--block-num与--transaction时--prune-transactions不会执行任何操作见 eosio-blocklog/main.cpp。剪枝后验证完成剪枝后可重新读取交易确认prunable_data形态、空签名与空context_free_data并可借助eosio-blocklog展示包含被剪枝交易的区块。相关文档Context-Free Data 概念文档如何剪枝 Context-Free Data操作指南eosio-blocklog 工具参考nodeos 区块日志与重放相关指南state history 插件文档赞分享区块链【免费下载链接】eosAn open source smart contract platform项目地址https://gitcode.com/gh_mirrors/eo/eos点击查看免费下载相关推荐EOSIO 节点运维实战使用 eosio-blocklog 修剪交易的 Context-Free DataEOSIO 节点运维实战使用 eosio blocklog 修剪交易的 Context Free Data 导读 Context Free Data简称 C区块链EOSIO eosio-blocklog 使用指南区块日志底层操作、索引重建、修剪与交易剪枝EOSIO eosio blocklog 使用指南区块日志底层操作、索引重建、修剪与交易剪枝 eosio blocklog 是 EOSIO 节点配套的命令行工区块链EOSIO 实用工具指南eosio-blocklog 与 trace_api_util 的深度实战解析EOSIO 实用工具指南eosio blocklog 与 trace_api_util 的深度实战解析 eosio blocklog 与 trace_api_区块链创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价