Corda API发行IOU触发CollectSignaturesFlow签名会话异常排查
这个异常的核心原因是:CollectSignaturesFlow要求传入的会话列表必须恰好对应所有需要对交易签名的非发起方节点——既不能多传(比如包含发起方自己的会话),也不能少传(漏掉需要签名的节点)。
原代码的问题所在
我们来拆解原代码中触发异常的关键逻辑:
List<Party> otherParties = this.state.getParticipants().stream() .filter(x -> x.getOwningKey() != me.getOwningKey()) .map(el -> (Party)el) .collect(Collectors.toList());
这里的第一个致命错误是用引用比较!=来判断公钥是否属于自己。Corda中,同一个身份的PublicKey可能是不同的对象实例(但值完全相同),!=比较的是对象引用,而非公钥的实际值。这会导致过滤条件失效,otherParties列表中错误地包含了发起方自己的身份。
当基于这个错误的otherParties创建会话列表后,CollectSignaturesFlow会收到多余的会话(发起方自己的会话),而它只需要收集除发起方之外的、需要签名的节点的签名,因此直接抛出了异常。
另外,map(el -> (Party)el)的强制转换也存在潜在风险:如果state.getParticipants()中包含匿名身份(AnonymousParty),这个转换会抛出ClassCastException,不过这不是你当前遇到的问题。
修改后代码正常运行的原因
修改后的代码直接指定了与贷款人(state.getLender())创建会话:
FlowSession lenderFlow = initiateFlow(state.getLender());
这个逻辑更精准:在IOU发行场景中,交易通常只需要借款方(发起方)和贷款方双方签名。你明确地只创建了需要签名的另一方的会话,传入CollectSignaturesFlow的会话数量完全匹配实际需要,因此流程可以正常执行。
两者的核心差异
| 原代码 | 修改后代码 |
|---|---|
| 通过过滤参与者列表获取其他方,但因公钥比较错误导致包含自己 | 直接指定需要签名的特定节点(贷款人),避免了过滤逻辑的错误 |
会话列表可能包含多余节点(比如自己),触发CollectSignaturesFlow的校验异常 | 会话列表恰好对应需要签名的非发起方,完全符合流程要求 |
| 依赖参与者列表的正确性和过滤逻辑的准确性,容错性低 | 逻辑更直接明确,避免了潜在的过滤错误 |
修复原代码的建议
如果你想保留原代码的参与者过滤逻辑,需要把公钥的比较从引用比较改为值比较:
.filter(x -> !x.getOwningKey().equals(me.getOwningKey()))
这样就能正确过滤掉发起方自己,确保otherParties列表只包含需要签名的其他节点。
内容的提问来源于stack exchange,提问作者L.Zoffoli

