Skip to content

异构链数据验证服务开发手册

0xstride edited this page Apr 28, 2026 · 2 revisions

1. HCDVS 在可信跨链中的职责 🔐

1.1 开发目标

HCDVS(Hetero-Chain Data Verifier Service,异构链数据验证服务)是 AntChain Bridge 的可信验证层。它验证异构链数据是否真实、完整、可被对应链的共识规则和账本证明规则接受。BBC 负责把链上数据读出来,HCDVS 负责判断这些数据能不能被信任。

这份手册同样围绕下面的跨链方向展开:

eth.from.domain -> Relayer1 -> Relayer2 -> fisco.to.domain

这个方向中,源链是 Ethereum2,所以源链消息验证主要由 Ethereum2 HCDVS 完成;目标链是 FISCO BCOS,所以投递写链由 FISCO BCOS BBC 完成。若方向反过来,源链变成 FISCO BCOS,消息验证就由 FISCO BCOS HCDVS 完成。理解这一点后,双 Relayer 场景就不会被误解成“两个 Relayer 互相信任”,真正的信任来自 PTC、TpBTA 和 HCDVS 验证结果。

1.2 HCDVS 与 PTC 的关系

PTC 是调用者,HCDVS 是验证执行者。Committee PTC 的每个节点在背书前都会调用对应 product 的 HCDVS:

  • product=ethereum2 时,调用 Ethereum2 HCDVS。
  • product=fiscobcos 时,调用 FISCO BCOS HCDVS。

PTC 聚合多个节点的验证结果,形成 TpBTA 或跨链消息背书。四节点 Committee PTC 下,本文默认 threshold > 2,即至少 3 个节点验证通过。

1.3 示例验证链路

1.3.1 Mermaid 验证架构图

flowchart LR
    R["Relayer"] --> P["Committee PTC"]
    P --> N1["Committee Node 1"]
    P --> N2["Committee Node 2"]
    P --> N3["Committee Node 3"]
    P --> N4["Committee Node 4"]
    N1 --> EH["Ethereum2 HCDVS"]
    N2 --> EH
    N3 --> EH
    N4 --> EH
    EH --> ER["VerifyResult"]
    P --> B["Embedded BCDNS"]
    B --> T["TpBTA / PTC Trust Root"]
Loading

1.3.2 验证不等于转发

Relayer 可以把消息从 Relayer1 传到 Relayer2,但目标链是否接受消息,取决于 PTC 背书和链上 PTC Hub 中的 TpBTA。HCDVS 验证通过是可信消息链路的核心条件。

2. 核心数据结构 🧱

2.1 BTA

BTA(Blockchain Trust Anchor,区块链信任锚)描述一条链的初始可信身份。注册 TpBTA 时,PTC 会先验证 BTA 中描述的初始状态是否可信。

2.1.1 subject identity

subject identity 是 BTA 中最关键的链特定字段,由各插件自定义序列化格式:

  • Ethereum2:通常包含 eth2ChainConfig、current sync committee、next sync committee 等。
  • FISCO BCOS:通常包含 AM 合约地址、sealer list 或可推导共识身份的信息。

2.1.1.1 实现边界

subject identity 不应写成通用 JSON 模板后跨链复用。Ethereum2 和 FISCO BCOS 的可信身份完全不同,HCDVS 只会按对应 product 的格式解析。

2.1.2 AM 合约地址

BTA 还会携带 AM 合约身份。HCDVS 必须检查共识状态中的 AM 合约地址和 BTA 中的 AM 身份一致,否则攻击者可能把其他合约日志伪装成跨链消息。

2.2 ConsensusState

ConsensusState 是统一的共识状态封装。它本身不要求所有链使用同一种区块头结构,而是把链特定数据放入 stateDataconsensusNodeInfoendorsements

2.2.1 Ethereum2 的 slot/stateData

Ethereum2 中:

  • height 表示 Beacon slot。
  • hash 表示 Beacon block root。
  • parentHash 表示父 Beacon block root。
  • stateData 包含 Beacon header、execution payload header、light client update 等。
  • endorsements 包含 sync aggregate 和 signature slot。

2.2.1.1 missed slot 处理

如果某个 slot missed,BBC 可能返回空 root 状态,HCDVS 应识别该状态不能承载跨链消息证明。消息验证不能从 missed slot 通过。

2.2.2 FISCO 的 height/sealer signatures

FISCO BCOS 中:

  • height 表示区块高度。
  • hash 表示区块 hash。
  • parentHash 表示父区块 hash。
  • stateData 包含 transactions root、receipts root、state root 等。
  • consensusNodeInfo 包含 sealer list。
  • endorsements 包含区块签名集合。

2.3 CrossChainMessage

CrossChainMessage 表示 BBC 从源链读出的跨链消息。核心字段包括:

  • message:AM 原文。
  • type:消息类型,通常是 AUTH_MSG。
  • provableData:证明这条消息存在于源链账本中的数据。

2.4 ProvableLedgerData

2.4.1 ledgerData

ledgerData 保存包含 AM 消息原文的账本数据。Ethereum2 通常保存 AM log 相关 JSON;FISCO BCOS 通常保存 transaction receipt JSON。

2.4.2 proof

proof 保存账本存在性证明。Ethereum2 侧一般是 receipt proof;FISCO BCOS 侧一般包含 receiptHashtxReceiptProofreceiptsRoot

2.4.3 txHash/blockHash/timestamp

这些字段用于把消息和链上交易、区块、时间关联起来。HCDVS 不能只校验 message 字节相等,还必须确认它确实来自对应交易和区块。

3. HCDVS 四个接口详解 🧭

3.1 verifyAnchorConsensusState

3.1.1 调用时机

注册 TpBTA 时,PTC 使用 verifyAnchorConsensusState 验证第一份 anchor state。该状态一旦通过,会成为后续共识状态推进的起点。

3.1.2 Ethereum2 验证目标

Ethereum2 需要验证:

  • BTA 中的 sync committee 大小与链配置一致。
  • anchor state 中 AM 合约地址与 BTA AM 身份一致。
  • sync committee 签名能验证 Beacon 状态。
  • 如 anchor state 位于 period 边界,正确处理 next sync committee。

3.1.3 FISCO 验证目标

FISCO BCOS 需要验证:

  • BTA 中 AM 合约地址与状态中的 AM 身份一致。
  • stateData 中关键区块状态字段完整。
  • endorsements 中签名来自 sealer list。
  • 有效签名数量满足多数阈值。

3.2 verifyConsensusState

3.2.1 Anchor 推进时调用

Anchor 服务后续推进源链可信状态时,PTC 使用父状态验证子状态。通过后,子状态可以成为新的可信状态。

3.2.2 Ethereum2 period boundary

Ethereum2 的难点是 sync committee period 切换。如果子状态位于当前 period 最后 slot,HCDVS 需要验证 light client update,并把 next sync committee 切换为 current sync committee。

3.2.2.1 边界失败的典型表现

如果 next sync committee 没有正确进入 consensusNodeInfo,后续状态可能出现 sync committee signature is invalidmissing next sync committee for endorsements

3.2.3 FISCO 父子区块关系

FISCO 需要检查子区块 parentHash 是否等于父状态 hash,再用父状态中的 sealer list 验证子区块签名。

3.3 verifyCrossChainMessage

3.3.1 Ethereum2 receipt root/log topic

Ethereum2 验证消息时,需要证明 AM log 存在于交易 receipt,receipt proof 计算出的 root 等于 execution payload header 中的 receipts root,且 log topic、logger 地址、log data 都和 AM 消息一致。

3.3.2 FISCO receipt root/Merkle proof

FISCO 验证消息时,需要证明 transaction receipt 存在于区块 receipts root 下,再从 receipt 的 log entries 中找到 SendAuthMessage 事件,并确认事件消息和 CrossChainMessage.message 一致。

3.4 parseMessageFromLedgerData

3.4.1 Ethereum2 AM log

Ethereum2 从 ledgerData 中解析 AM log,再用合约 ABI 提取非 indexed 参数中的 AM 原文。

3.4.2 FISCO SendAuthMessage event

FISCO 从 transaction receipt JSON 的 logEntries 中查找 SendAuthMessage 事件,解析出事件里的消息字节。

4. Ethereum2 HCDVS 实现重点 🔍

4.1 Ethereum2 验证模型

4.1.1 Beacon header

Beacon header 提供 slot、root、parent root 等共识层信息。HCDVS 会校验 ConsensusState.height/hash/parentHash 与 Beacon header 一致。

4.1.2 sync committee

sync committee 是验证 Beacon 状态签名的核心。BTA subject identity 中保存初始 current sync committee;后续状态推进时可能维护 next sync committee。

4.1.3 light client update

light client update 用于在 period 边界更新 sync committee。没有正确处理它,链在 period 切换后会出现签名验证失败。

4.1.4 execution payload receiptsRoot

跨链消息存在性最终要落到 execution payload header 的 receipts root。receipt proof 计算得到的 root 必须等于这个字段。

4.2 verifyAnchorConsensusState

4.2.1 验证步骤

  1. 从 BTA subject identity 解析 Ethereum2 链配置和 current sync committee。
  2. 从 anchor state 的 stateData 解析 Ethereum2 共识状态。
  3. 比对 AM 合约地址。
  4. endorsements 解析 sync aggregate。
  5. 验证共识状态签名和区块数据。
  6. 必要时更新 next/current sync committee。

4.2.1.1 成功后的状态传递

验证成功后,Ethereum2 HCDVS 会把更新后的 sync committee 信息写入 anchorState.consensusNodeInfo。这一步不是可选项,否则后续 verifyConsensusState 没有可信 committee 输入。

4.2.2 源码逐行注释:EthereumHcdvsService.verifyAnchorConsensusState

// 从 BTA 中解析 Ethereum2 初始可信身份;这是验证 sync committee 的来源。
var subject = EthSubjectIdentity.fromJson(new String(bta.getSubjectIdentity()));

// 解析 BBC 放入 stateData 的 Ethereum2 专有共识状态数据。
// schema/spec 必须来自同一个 eth2ChainConfig,否则反序列化和验证都会错位。
var data = EthConsensusStateData.fromJson(new String(anchorState.getStateData()), schema, spec);

// 校验 AM 合约身份,防止其他合约事件被伪装成跨链系统消息。
if (!amInBta.equals(data.getAmContract())) {
    return VerifyResult.fail("invalid am contract");
}

// 解析 sync aggregate;committee size 必须和链配置一致。
var endorsements = EthConsensusEndorsements.fromJson(new String(anchorState.getEndorsements()), committeeSize);

// 执行 Ethereum2 共识状态验证,包括 sync committee 签名和 light client 相关校验。
data.validate(subject.getCurrentSyncCommittee(), endorsements, subject.getEth2ChainConfig());

// 把更新后的 sync committee 状态写回共识状态,供后续 verifyConsensusState 继承。
anchorState.setConsensusNodeInfo(subject.toJson().getBytes());

// 所有检查通过后,PTC 节点才可以继续产生背书。
return VerifyResult.success();

4.3 verifyConsensusState

4.3.1 验证步骤

  1. 从父状态 consensusNodeInfo 读取 current/next sync committee。
  2. 解析父状态和子状态的 Ethereum2 数据。
  3. 校验 AM 合约地址不变。
  4. 校验子状态 slot、root、parent root。
  5. 如遇 period 边界,校验 light client update。
  6. 选择正确的 sync committee 验证 endorsements。
  7. 更新子状态 consensusNodeInfo

4.3.2 源码逐行注释:EthereumHcdvsService.verifyConsensusState

// 父状态已经被验证过,因此其中保存的 sync committee 状态是当前可信输入。
var subject = EthSubjectIdentity.fromJson(new String(parentState.getConsensusNodeInfo()));

// 解析待验证状态;schema/spec 必须和父状态来自同一条 Ethereum2 链配置。
var curr = EthConsensusStateData.fromJson(new String(stateToVerify.getStateData()), schema, spec);

// 解析父状态,用于检查 AM 合约、父子 root 和 period 边界。
var parent = EthConsensusStateData.fromJson(new String(parentState.getStateData()), schema, spec);

// 同一条源链的 AM 合约不应在连续状态中无故变化。
if (!parent.getAmContract().equals(curr.getAmContract())) {
    return VerifyResult.fail("am contract not equal");
}

// 验证 Beacon 链父子链接关系,子状态 parentRoot 必须等于父状态 root。
if (!curr.getBeaconBlockHeader().getParentRoot().equals(parent.getBeaconBlockHeader().getRoot())) {
    return VerifyResult.fail("invalid parent hash");
}

// 使用选定的 sync committee 验证 block endorsement;period 边界时可能使用 next committee。
curr.validateBlock(committeeForBlockVerification, endorsements, subject.getEth2ChainConfig());

// 把更新后的 committee 信息写入子状态,作为下一轮状态验证的可信输入。
stateToVerify.setConsensusNodeInfo(subject.toJson().getBytes());

4.4 verifyCrossChainMessage

4.4.1 验证步骤

  1. 解码 message 中的 receipt proof。
  2. 从当前共识状态读取 execution payload receipts root。
  3. 验证 receipt proof 计算出的 root。
  4. 从 ledgerData 中解析 AM log。
  5. 校验 log index、topic、logger 地址和 log data。
  6. 返回成功。

4.4.1.1 验证重点

Ethereum2 消息验证不是只检查 AM 原文是否相等,还要检查 receipt proof、log topic、logger 地址与 execution payload receipts root 的整条链路。

4.4.2 源码逐行注释:EthereumHcdvsService.verifyCrossChainMessage

// 解码 BBC 构造的 receipt proof;证明格式必须和 BBC 侧完全一致。
var proof = EthReceiptProof.decodeFromJson(new String(message.getProvableData().getProof()));

// 解析当前可信共识状态,读取 execution payload header。
var data = EthConsensusStateData.fromJson(new String(currState.getStateData()), schema, spec);

// 通过 receipt proof 重新计算 receipts root。
var rootCalc = proof.validateAndGetRoot();

// 从可信 Beacon 状态中的 execution payload header 取期望 receipts root。
var rootExpect = data.getExecutionPayloadHeader().getReceiptsRoot();

// 两个 root 不一致,说明 receipt 不属于当前可信区块。
if (rootCalc.compareTo(rootExpect) != 0) {
    return VerifyResult.fail("receipt root not equal");
}

// 解析账本数据中的 AM log,后续会与 proof 里的 log 逐项比对。
var ledgerLog = EthAuthMessageLog.decodeFromJson(new String(message.getProvableData().getLedgerData()));

// 确保 proof 中的日志发出者就是当前共识状态记录的 AM 合约地址。
if (!msgLogInProof.getLogger().equals(data.getAmContract())) {
    return VerifyResult.fail("logger not am contract");
}

5. FISCO BCOS HCDVS 实现重点 🧩

5.1 FISCO 验证模型

5.1.1 sealer list

sealer list 是 FISCO 共识节点集合。HCDVS 用它验证区块签名是否来自合法节点。

5.1.2 多数签名阈值

四节点标准链下,不能只验证一个签名。应按多数阈值验证,例如四节点至少需要 3 个有效签名。

5.1.3 receipt root 与 Merkle proof

FISCO 的跨链消息存在性依赖 transaction receipt 和 Merkle proof。HCDVS 需要确认 proof 中的 receipts root 与共识状态中的 receipts root 一致。

5.2 verifyAnchorConsensusState

5.2.1 验证步骤

  1. 从 BTA subject identity 解析 AM 合约地址。
  2. 校验 AM 地址与 BTA AM 身份一致。
  3. 解析 anchor state 的 stateData
  4. 解析 endorsementsconsensusNodeInfo
  5. 计算最低签名数量。
  6. 验证签名有效数量。

5.2.2 源码逐行注释:FISCOBCOSHCDVSService.verifyAnchorConsensusState

// FISCO BTA subject identity 使用 JSON 表达链特定身份。
JSONObject subject = JSON.parseObject(new String(bta.getSubjectIdentity()));

// 取出 AM 合约地址;后续所有跨链消息都必须来自该 AM 合约。
String amContract = subject.getString("amContract");

// 检查 subject identity 中的 AM 地址与 BTA 标准字段中的 AM 身份一致。
if (!checkAmContract(decode(amContract), bta.getAmId())) {
    return VerifyResult.fail("AM合约地址不匹配");
}

// 解析 BBC 写入的区块状态数据,例如 transactionsRoot、receiptsRoot、stateRoot。
JSONObject stateData = JSON.parseObject(new String(anchorState.getStateData()));

// 取区块签名集合;为空时不能继续做可信验证。
JSONArray signatures = endorsements.getJSONArray("signatures");

// 取共识节点集合;签名必须来自这些合法 sealer。
JSONArray sealers = consensusNodeInfo.getJSONArray("sealerList");

// 按 sealer 数量计算最低有效签名数,四节点通常至少需要 3 个。
int min = calculateMinRequiredSignatures(sealers.size());

// 逐个验证签名是否由合法 sealer 产生,并统计有效签名数量。
int valid = verifySignatures(signatures, sealers, anchorState.getHashHex());

5.3 verifyConsensusState

5.3.1 验证步骤

  1. 解析父子状态数据。
  2. 检查父子状态字段完整。
  3. 校验子区块 parentHash 等于父区块 hash
  4. 从父状态读取 sealer list。
  5. 用父状态 sealer list 验证子状态签名。

5.3.2 源码逐行注释:FISCOBCOSHCDVSService.verifyConsensusState

// 父状态必须能解析成 FISCO 区块状态数据。
JSONObject parentData = JSON.parseObject(new String(parentState.getStateData()));

// 子状态也必须能解析成 FISCO 区块状态数据。
JSONObject childData = JSON.parseObject(new String(stateToVerify.getStateData()));

// 取子状态中的 parentHash,用于验证链式关系。
String childParentHash = HexUtil.encodeHexStr(stateToVerify.getParentHash());

// 子状态必须接在父状态之后,否则状态推进不可信。
if (!childParentHash.equalsIgnoreCase(parentState.getHashHex())) {
    return VerifyResult.fail("区块链接关系验证失败");
}

// 父状态的 sealer list 是验证子区块签名的可信输入。
JSONArray sealers = parentConsensusNodeInfo.getJSONArray("sealerList");

// 子状态必须携带区块签名集合。
JSONArray signatures = childEndorsements.getJSONArray("signatures");

// 验证子区块签名是否来自合法 sealer,且有效数量满足多数阈值。
int valid = verifySignatures(signatures, sealers, stateToVerify.getHashHex());

5.4 verifyCrossChainMessage

5.4.1 验证步骤

  1. 检查消息带有 provableData
  2. 校验消息高度与当前共识状态高度一致。
  3. 从共识状态读取 receipts root。
  4. ledgerData 解析 transaction receipt。
  5. proof 解析 receipt proof。
  6. 验证 proof root 与状态 receipts root 一致。
  7. 查找 SendAuthMessage 事件。
  8. 校验事件消息与 CrossChainMessage.message 一致。

5.4.1.1 验证重点

FISCO BCOS 的 ledgerDataproof 必须来自同一笔交易回执和同一区块。只要其中一个字段复用了旧数据,收据根或交易哈希校验就会失败。

5.4.2 源码逐行注释:FISCOBCOSHCDVSService.verifyCrossChainMessage

// 没有证明数据就不能做可信验证,即使 AM 原文看起来正确也不能通过。
if (message.getProvableData() == null) {
    return VerifyResult.fail("跨链消息没有可证明数据");
}

// 消息必须属于当前共识状态对应的区块高度。
if (messageHeight != currState.getHeight().longValue()) {
    return VerifyResult.fail("消息高度与当前状态高度不匹配");
}

// 从可信状态中取 receiptsRoot,作为 proof 验证目标。
String receiptsRootInState = stateData.getString("receiptsRoot");

// 解析 BBC 放入 ledgerData 的 FISCO transaction receipt。
JSONObject receiptObj = JSON.parseObject(new String(message.getProvableData().getLedgerData()));

// 解析 BBC 放入 proof 的 receiptHash、txReceiptProof、receiptsRoot。
JSONObject proofObj = JSON.parseObject(new String(message.getProvableData().getProof()));

// proof 声称的 receiptsRoot 必须等于区块状态中的 receiptsRoot。
if (!proofReceiptsRoot.equalsIgnoreCase(receiptsRootInState)) {
    return VerifyResult.fail("收据根不匹配");
}

// 在交易回执日志中查找 AM 合约发出的 SendAuthMessage 事件。
AuthMessageEventResult event = findAuthMessageEvent(receiptObj.getJSONArray("logEntries"));

// 事件中的 AM 原文必须与 CrossChainMessage.message 完全一致。
if (!Arrays.equals(event.getMessage(), message.getMessage())) {
    return VerifyResult.fail("事件中的消息内容与跨链消息不一致");
}

5.5 parseMessageFromLedgerData

5.5.1 解析步骤

FISCO 的 parseMessageFromLedgerData 会把 ledgerData 当作 transaction receipt JSON 解析,然后查找 SendAuthMessage 事件,返回事件里的消息原文。

5.5.2 源码逐行注释:FISCOBCOSHCDVSService.parseMessageFromLedgerData

// BBC 把 FISCO transaction receipt 序列化后放入 ledgerData。
String receiptJson = new String(ledgerData);

// 按同一格式反序列化为 JSON,便于读取日志。
JSONObject receiptObj = JSON.parseObject(receiptJson);

// 获取交易回执中的所有 log entries。
JSONArray logEntries = receiptObj.getJSONArray("logEntries");

// 查找并解析 SendAuthMessage 事件。
AuthMessageEventResult event = findAuthMessageEvent(logEntries);

// 找到事件后返回 AM 原文;该值应与 CrossChainMessage.message 一致。
if (event != null) {
    return event.getMessage();
}

// 没有找到事件时返回空字节,上层验证通常会因此失败或报错。
return new byte[0];

6. PTC、TpBTA 与双 Relayer 信任关系 🛡️

6.1 Relayer1 与 Relayer2 不互相作为信任根

eth.from.domain -> Relayer1 -> Relayer2 -> fisco.to.domain 中,Relayer1 和 Relayer2 只是负责传输和调度。可信性来自 PTC 背书、HCDVS 验证和链上 PTC Hub 中保存的可信材料。

6.2 Embedded BCDNS 公开 TpBTA

TpBTA 上传到 Embedded BCDNS 后,其他 Relayer 可以按源域名查询。目标链验证消息时,需要知道源链 BTA 已经被可信 PTC 验证过。

6.3 Committee PTC 四节点 3/4 背书

四节点 Committee PTC 中,四个节点都可以背书。threshold > 2 表示至少三个节点验证通过。只启动一两个节点不符合本文路线。

6.4 eth.from.domain 到 fisco.to.domain 的验证时序

6.4.1 Mermaid 时序图

sequenceDiagram
    participant R1 as "Relayer1"
    participant P as "Committee PTC"
    participant EH as "Ethereum2 HCDVS"
    participant B as "Embedded BCDNS"
    participant R2 as "Relayer2"
    participant FB as "FISCO BBC"
    participant F as "FISCO BCOS"
    R1->>P: 提交 Ethereum2 ConsensusState 和 CrossChainMessage
    P->>EH: verifyConsensusState
    P->>EH: verifyCrossChainMessage
    EH-->>P: VerifyResult.success
    P->>B: 查询或发布 TpBTA
    R1->>R2: 传递已验证消息
    R2->>FB: relayAuthMessage
    FB->>F: 调用 AM/SDP/业务合约
Loading

6.4.2 反向链路

若从 fisco.to.domain 发往 eth.from.domain,PTC 调用的是 FISCO BCOS HCDVS,验证 FISCO 区块签名、receipt root、Merkle proof 和 SendAuthMessage 事件;目标链投递则由 Ethereum2 BBC 完成。

7. Q&A ❓

7.1 Ethereum2 出现 sync committee signature is invalid 怎么办?

优先检查 eth2ChainConfig 是否来自当前 Beacon API,BTA subject identity 是否用当前链当前 slot 生成,slot 是否靠近 sync committee period 边界。私链重建后继续使用旧配置是最常见原因。

7.2 Ethereum2 出现 receipt root not equal 怎么办?

说明 receipt proof 计算出的 root 和 execution payload header 中的 receipts root 不一致。重点检查消息的 ledgerDataproof、slot、交易哈希是否来自同一个区块。

7.3 Ethereum2 出现 none light client update at last slot in period 怎么办?

说明状态位于 period 边界,但缺少可验证的 light client update。应等待可用 update,或避开边界 slot 构造初始 BTA;如果 Beacon 返回 Fulu 而插件期望 Deneb,应重建链。

7.4 FISCO 签名数量不足怎么办?

检查 consensusNodeInfo 中 sealer list 是否完整,endorsements 中签名是否来自当前区块,四节点链是否至少有多数有效签名。不要通过降低验证阈值绕过。

7.5 FISCO 收据根不匹配怎么办?

检查 proof.receiptsRootstateData.receiptsRoot、transaction receipt 是否来自同一高度同一区块。若使用缓存或复用旧消息,很容易出现 root 不匹配。

7.6 FISCO 回执中没有 SendAuthMessage 怎么办?

确认扫描的合约地址是 AM 合约,不是 SDP 或业务合约。还要确认业务调用确实触发了 SDP 发送跨链消息,而不是只更新了本地状态。

7.7 HCDVS 本地单测可用但 Committee Node 加载失败怎么办?

常见原因是 Committee Node 的插件目录、classpath 或 native library 路径与本地单测不同。FISCO BCOS 尤其要确认 WedPR native library 能被 Committee Node JVM 加载。

7.8 BBC 与 HCDVS 序列化格式不一致怎么办?

BBC 负责写入 stateDataledgerDataproof;HCDVS 负责读取这些 bytes。任何字段名、编码、大小写、十六进制前缀不一致,都会导致验证失败。新增链插件时,应把 BBC/HCDVS 的序列化契约写成单测。

7.9 TpBTA 未生效怎么排查?

先确认 PTC 注册 BTA 成功,再确认 TpBTA 已上传到 BCDNS,最后确认目标链 PTC Hub 中能查询到对应源域名的 TpBTA。双 Relayer 场景中,不要把“Relayer 能通信”误认为“目标链已经信任源链”。

Clone this wiki locally