跳转到内容

编码传递与中途截取

发件人把一份编码消息寄给一位收件人。中继经手人在途中复制了这份消息,完整读过副本,但手里的 密钥解不开它。收件人收到原件后,委托一位持有正确密钥的人代为解读,再把解读结果开放给一名复核者。

这个示例回答的问题是:“拿到副本”“读过”“读懂”这三件事怎样分开记录?替别人完成的解读又怎样记录, 才能让重放直接复用已记录的结果?

所有持有人、时间和内容代码都是合成的测试值。

  • canwu-information,负责信息流转的模拟领域扩展,以及它的规划入口 InformationLifecycle::plan。
  • 同内容副本:第二个 Representation(表现形式),使用 ContentRelation::SameContent,并有一条 指向原件的父边。
  • 状态为 InterpretationStatus::Failed 和 Succeeded 的 Interpretation(解读)记录,每条都绑定 它所读的访问记录和表现形式。
  • 委托解读:InterpretationAuthority::Delegated 引用一条已持久化的命令,命令中带有 DelegationClaimV1。
  • 每条只面向一个持有人的知识发布(持有人相对知识),以及通过 InformationPlugin 完成的快照恢复、精确重放和紧凑检查点恢复。
Terminal window
cargo run -p canwu-information --example encoded_interception

所有检查通过后,程序打印一行结果;任何一项检查失败,程序都会提前停止:

encoded_interception: in-transit copy, failed access interpretation, delegated decode, restricted review release, authoritative save/load, exact replay without external decoding, and compact reconstruction verified

每个短语对应源码中的一组检查;最后三项来自 examples/support/mod.rs 中的 verify_authoritative_operation_roundtrip,委托解读和复核发布各运行一次。

编码消息从发件人到复核者的时序. 查看图表源码.
查看图表源码
sequenceDiagram
  participant S as 发件人 H-601
  participant R as 经手人 H-603
  participant P as 收件人 H-602
  participant D as 受托解读者 H-604
  participant V as 复核者 H-605
  S->>R: 发往 H-602,投递尝试 InTransit(第 2–4 分钟)
  Note over R: 复制出 SameContent 副本(第 5 分钟)
  R->>R: 阅读副本,decode_k1 解读失败(第 6–7 分钟)
  R->>P: 投递尝试 Delivered,收件人阅读(第 12–13 分钟)
  Note over P,D: 委托声明,能力 decode_k2
  D-->>P: 解读成功,生成结果内容(第 14–15 分钟)
  P->>V: 复核发布转为 Active(第 17–19 分钟)

场景代码在 encoded_interception.rs, 共用的辅助函数在 support/mod.rs。 和机密副本与定向发布一样,记录是逐条请求在脱离 运行时的账本上规划出来的。

持有人 角色
H-601 发件人
H-602 指定收件人,委托解读并发布复核结果
H-603 中继经手人,复制消息并尝试解读
H-604 替 H-602 解读的受托人
H-605 复核者

原始表现形式写明了读懂它需要的能力:

payload: RepresentationPayload {
format: "grouped_symbols_v1".to_owned(),
created_at: minute(1),
operation: "encode_k2".to_owned(),
content_relation: ContentRelation::SameContent,
sources: Vec::new(),
claimed_source: None,
interpretation_capability: Some("decode_k2".to_owned()),
},

发往 H-602 的定向 Dispatch 转为 Active。它的 DeliveryAttempt(投递尝试)以 relay 角色记下 H-603,并转为 InTransit。

2. 经手人复制消息(第 5 分钟)

Section titled “2. 经手人复制消息(第 5 分钟)”

经手人为同一份内容创建第二个表现形式:

content_relation: ContentRelation::SameContent,
sources: vec![RepresentationSourceEdge {
parent: encoded.clone(),
completeness_per_mille: 1_000,
fidelity_per_mille: 1_000,
}],

SameContent 要求副本与父表现形式引用同一条 Content 记录(validate_representation_lineage)。 经手人还为副本创建了自己保管的 Instance。

3. 经手人读了副本,却没能解读(第 6–7 分钟)

Section titled “3. 经手人读了副本,却没能解读(第 6–7 分钟)”

经手人的访问引用截取得到的载体实例,并完整读过副本(extent_per_mille: 1_000)。他的解读记录:

payload: InterpretationPayload {
interpreted_at: minute(7),
status: InterpretationStatus::Failed,
capability: "decode_k1".to_owned(),
confidence_per_mille: 0,
authenticity: None,
},
authority: InterpretationAuthority::HolderSelf,

Failed 这个结果由示例给出。扩展把 capability 和 interpretation_capability 当作标签保存, 解读能否成功由你的应用判断。扩展检查的是结果的记录方式(见 lifecycle.rs 中的 validate_interpretation):

  • 每条解读都要有 input_access、input_representation、performed_by 和 performed_for 引用,且每个输入表现形式都必须是某条输入访问读过的;
  • Failed 的解读不带 result_content,Partial 或 Succeeded 的解读必须带;
  • 使用 HolderSelf 时,执行者与服务对象必须是同一个持有人。

示例直接验证了第二条规则:缺少 result_content 的 Succeeded 请求必须失败。

assert!(ledger.plan(&invalid_success_without_result).is_err());

投递尝试转为 Delivered,并向 H-602 发布 RepresentationAvailable。收件人的访问引用 delivery_attempt、dispatch 和原始表现形式;经手人的访问引用的是截取得到的载体实例,两次阅读 各有各的证据。

5. 受托人替收件人解读(第 14–15 分钟)

Section titled “5. 受托人替收件人解读(第 14–15 分钟)”

解读结果是从原件衍生出的新内容,代码为 SYN-E8-42-R。成功的解读把 H-604 记为执行者、H-602 记为服务对象,并绑定结果:

holder_reference("performed_by", &performer_holder),
holder_reference("performed_for", &destination_holder),
DomainReference::from_typed("result_content", decoded_content.clone()),

它的权限来自委托:

authority: InterpretationAuthority::Delegated {
evidence: EvidenceRef::Command(CommandId::new(1)),
authority_grant: DELEGATED_AUTHORITY_GRANT.to_owned(),
},

授权代码 DELEGATED_AUTHORITY_GRANT(interpret_for_holder)告诉 InformationPlugin:到发给 canwu-authority 的 delegate_interpretation_v1 插件命令中,按 claim 键读取委托声明。示例里, support/mod.rs 中的 CaseAuthorityPlugin 注册了这条命令,权威运行中的第一条命令携带如下声明:

Some(DelegationClaimV1 {
format_version: 1,
performed_by: EntityRef::Person(PersonId::new(604)),
performed_for: destination_holder.clone(),
capabilities: vec!["decode_k2".to_owned()],
not_before: Some(SimTime::EPOCH),
expires_at: None,
}),

应用这条解读时,插件检查声明是否写明了这个执行者、这个服务对象和这项能力,以及解读时间是否落在 [not_before, expires_at) 之内。检查不通过,操作就以 invalid_authority 被拒绝。

权威运行结束后,只有收件人得到新的知识:

assert_authoritative_knowledge(
canwu,
&destination_holder,
&["interpretation_recorded"],
)?;
assert_authoritative_knowledge(canwu, &review_holder, &[])?;
assert_authoritative_knowledge(canwu, &source_holder, &[])?;
assert_authoritative_knowledge(canwu, &performer_holder, &[])

重放时,辅助函数用 PersistedResultReplayPlugin 代替 CaseAuthorityPlugin。它对同一条命令的 处理函数只接受已经带有记录结果的载荷,否则以 ReplayMismatch 失败;因此重放通过,就说明结果来自 日志。

6. 把结果开放给复核者(第 16–19 分钟)

Section titled “6. 把结果开放给复核者(第 16–19 分钟)”

受托人把结果渲染成 review_text_v1 表现形式。接着,H-602 创建由 H-602 和 H-605 组成的 显式受众,并为这个表现形式创建面向受众的发布。激活同样在 Canwu 中执行一遍:

assert_authoritative_knowledge(canwu, &destination_holder, &["release_available"])?;
assert_authoritative_knowledge(canwu, &review_holder, &["release_available"])?;
assert_authoritative_knowledge(canwu, &source_holder, &[])?;
assert_authoritative_knowledge(canwu, &performer_holder, &[])
  • 副本、访问和解读是三条独立的记录。经手人手里有完整副本,也完整读过,却仍然没有解读结果。
  • 解读成败是应用输入。扩展规定的是结果怎样记录,包括结果内容的绑定。
  • 委托解读只向服务对象发布知识,受托人不会因此得到任何知识。
  • 委托声明保存在已持久化的命令里,重放时直接从日志核验权限。
  • 在经手人那条失败的解读中加入 DomainReference::from_typed("result_content", content.clone())。 规划会失败,报错 failed interpretation cannot have result content。
  • 把经手人那条解读的 performed_for 改成 destination_holder,权限仍用 HolderSelf。规划会失败, 报错 self interpretation authority requires performer and holder equality。
  • 把 DelegationClaimV1 的 capabilities 改成 vec!["decode_k1".to_owned()]。脱离运行时的 规划仍会成功,但 InformationPlugin 以 invalid_authority 拒绝该操作,示例停止并报错 authoritative case operation did not complete: Rejected。

表现形式可以在 RepresentationPayload::claimed_source 中写明它声称的来源;对它的解读随后可以在 InterpretationPayload::authenticity 中记录一条真伪判定 (AuthenticityFinding):是否接受声称的来源、一个简短的 basis(例如 "seal_mismatch"),以及 置信度。判定必须引用这次解读所读、并且带有 claimed_source 的表现形式的当前版本,否则 InformationPlugin 以 invalid_lifecycle 拒绝该操作。这样,一份伪造的文书可以记为“已经解读”, 同时不接受它声称的发送者。持有人识破伪造的概率由应用抽样决定(见模型归属), 本示例中 authenticity 为 None,真伪判定测试构造了一条这样的判定。

InterpretationAuthority::InstitutionalRole 与委托形式类似,但它按授权代码 interpret_as_assigned_role,从某条 AuthorityAssignment 记录的确切版本中读取声明。

打开可运行示例

阅读示例共用的辅助函数

阅读解读权限测试

阅读真伪判定测试