Polkadot tx-wrapper离线签名中ExtrinsicPayload作用与签名长度不一致问题
问题解答
1. ExtrinsicPayload的作用
ExtrinsicPayload是Substrate/Polkadot生态中用于标准化封装交易待签名内容的核心结构,它会按照链的元数据定义和交易协议,将交易方法、nonce、交易有效期(era)、手续费参数、链规格版本、创世哈希等所有需要参与签名的字段按指定编码规则组合,保证最终生成的待签名内容符合链上验签逻辑,避免因编码格式或字段缺失导致签名无效。
2. s1与s2签名结果不一致的原因
核心是你手动构造待签名payload的逻辑和ExtrinsicPayload内置sign方法的逻辑不匹配,具体问题如下:
- 序列化参数错误:你调用
extrinsicPayload.toU8a({method: true})时指定了method: true,该参数会让序列化结果只包含交易方法部分,漏掉了era、nonce、tip、specVersion、transactionVersion、genesisHash等所有需要参与签名的扩展字段,导致你手动生成的actualPayload和内置sign方法使用的待签名内容完全不同。 - 签名前缀问题:如果你使用的
alice是@polkadot/keyring生成的账号,内置sign方法默认会对待签名内容添加<Bytes>包裹前缀后再签名,而你直接调用alice.sign(actualPayload)时如果没有显式指定{withType: true}参数,也会导致签名输入不一致。 - 哈希逻辑一致性:如果payload长度超过256字节,需确认你手动调用的
registry.hash方法的算法(默认是Blake2b256)和内置sign方法使用的哈希逻辑一致,正常情况下两者默认逻辑一致,但如果手动修改过配置也会导致差异。
修正后的验证代码
import { getRegistry } from '@substrate/txwrapper-polkadot'; import { u8aToHex } from '@polkadot/util'; const registry = getRegistry({ chainName: 'Polkadot', specName, specVersion, metadataRpc, }); const extrinsicPayload = registry.createType('ExtrinsicPayload', unsigned, {version: unsigned.version}); // 去掉method:true参数,序列化全部签名字段 const extrinsicPayloadU8a = extrinsicPayload.toU8a() const actualPayload = extrinsicPayloadU8a.length > 256 ? registry.hash(extrinsicPayloadU8a) : extrinsicPayloadU8a; // 签名时添加withType参数,和内置sign逻辑对齐 const s1 = u8aToHex(alice.sign(actualPayload, { withType: true })); console.log("s1", s1, s1.length); const s2 = extrinsicPayload.sign(alice).signature; console.log("s2", s2, s2.length);
修改后s1和s2的结果会完全一致。
内容的提问来源于stack exchange,提问作者Amin Talebi
相关产品推荐
相关产品推荐

