Solana/交易/签名与验证

示例交易

为了避免读者不停切换页面, 我将待分析的交易复制在了每一小节的开头.

{
    "signatures": [
        "3NPdLTf2Xp1XUu82VVVKgQoHfiUau3wGPTKAhbNzm8Rx5ebNQfHBzCGVsagXyQxRCeEiGr1jgr4Vn32UEAx1Aov3"
    ],
    "message": {
        "header": [
            1,
            0,
            1
        ],
        "account_keys": [
            "6ASf5EcmmEHTgDJ4X4ZT5vT6iHVJBXPg5AN5YoTCpGWt",
            "8pM1DN3RiT8vbom5u1sNryaNT1nyL8CTTW3b5PwWXRBH",
            "11111111111111111111111111111111"
        ],
        "recent_blockhash": "6vAwzjtGMrN3mJ8o7iGVDjMM46e2AnctqmjvLbqtESrx",
        "instructions": [
            {
                "program": 2,
                "account": [
                    0,
                    1
                ],
                "data": "3Bxs3zzLZLuLQEYX"
            }
        ]
    }
}

签名

一个典型的 solana 交易分为两大核心部分: 签名和消息. 签名是交易的"通行证". 签名通过私钥生成, 确保交易的真实性和不可篡改性. 消息部分则明确指定操作细节, 通过这种分离, solana 可以并行处理大量交易, 极大提升吞吐量.

每个签名的长度均为 64 字节, 签名数组的长度取决于 message.header 中指定的签名数量(稍后会解释). 在这个例子中, 只有一个签名, 表明交易由一个账户发起并验证.

多签名交易(例如需要多个账户授权)会包含多个签名.

签名由账户的私钥对序列化后的交易的"消息"部分进行签名生成.

例: 请使用 ada 的私钥 0x01 对上述交易进行签名, 并验证签名结果是否和交易中的签名一致.

答:

import pxsol

tx = pxsol.core.Transaction.serialize_decode(bytearray([
    0x01, 0x76, 0x7a, 0xe2, 0x66, 0x60, 0xc1, 0x42, 0x94, 0x1a, 0x59, 0x61, 0xf6, 0xde, 0xc7, 0x23,
    0x7c, 0xae, 0x73, 0x3e, 0xdf, 0xe6, 0x51, 0x7c, 0x37, 0xfb, 0xb8, 0x48, 0x1f, 0x46, 0xbb, 0xb5,
    0x3c, 0xe3, 0x00, 0xe7, 0x14, 0xb4, 0x78, 0x40, 0x14, 0x2c, 0x93, 0xa4, 0xe6, 0x60, 0x0c, 0x50,
    0xfd, 0xa9, 0x75, 0x60, 0xab, 0x64, 0x1d, 0xb0, 0xce, 0x19, 0x55, 0x9b, 0x25, 0x1d, 0x66, 0xdf,
    0x04, 0x01, 0x00, 0x01, 0x03, 0x4c, 0xb5, 0xab, 0xf6, 0xad, 0x79, 0xfb, 0xf5, 0xab, 0xbc, 0xca,
    0xfc, 0xc2, 0x69, 0xd8, 0x5c, 0xd2, 0x65, 0x1e, 0xd4, 0xb8, 0x85, 0xb5, 0x86, 0x9f, 0x24, 0x1a,
    0xed, 0xf0, 0xa5, 0xba, 0x29, 0x74, 0x22, 0xb9, 0x88, 0x75, 0x98, 0x06, 0x8e, 0x32, 0xc4, 0x44,
    0x8a, 0x94, 0x9a, 0xdb, 0x29, 0x0d, 0x0f, 0x4e, 0x35, 0xb9, 0xe0, 0x1b, 0x0e, 0xe5, 0xf1, 0xa1,
    0xe6, 0x00, 0xfe, 0x26, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xe9, 0x77, 0x4a, 0x3c, 0xad, 0x5c, 0x33, 0xf1, 0xfb, 0x6b,
    0x37, 0xa0, 0x3d, 0x4f, 0x00, 0x9a, 0x31, 0x09, 0x81, 0x18, 0xd2, 0xce, 0xae, 0xbf, 0x43, 0x0a,
    0xf3, 0x01, 0xad, 0x25, 0x0d, 0x01, 0x02, 0x02, 0x00, 0x01, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00,
    0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00,
]))

s = pxsol.eddsa.sign(bytearray([0x00] * 31 + [0x01]),  tx.message.serialize())
assert s == tx.signatures[0]

验证过程

当交易提交到 solana 网络时, 验证节点首先会检查 signatures 的数量是否与 message.header 匹配, 然后使用账户的公钥(来自 account_keys) 验证每个签名是否有效.

在我们的例子中, 签名对应 account_keys 中的第一个账户: 6ASf5EcmmEHTgDJ4X4ZT5vT6iHVJBXPg5AN5YoTCpGWt. 这个账户是交易的发起者, 且支付了交易费用.

例: 验证上述交易的签名有效.

答:

import pxsol

tx = pxsol.core.Transaction.serialize_decode(bytearray([
    0x01, 0x76, 0x7a, 0xe2, 0x66, 0x60, 0xc1, 0x42, 0x94, 0x1a, 0x59, 0x61, 0xf6, 0xde, 0xc7, 0x23,
    0x7c, 0xae, 0x73, 0x3e, 0xdf, 0xe6, 0x51, 0x7c, 0x37, 0xfb, 0xb8, 0x48, 0x1f, 0x46, 0xbb, 0xb5,
    0x3c, 0xe3, 0x00, 0xe7, 0x14, 0xb4, 0x78, 0x40, 0x14, 0x2c, 0x93, 0xa4, 0xe6, 0x60, 0x0c, 0x50,
    0xfd, 0xa9, 0x75, 0x60, 0xab, 0x64, 0x1d, 0xb0, 0xce, 0x19, 0x55, 0x9b, 0x25, 0x1d, 0x66, 0xdf,
    0x04, 0x01, 0x00, 0x01, 0x03, 0x4c, 0xb5, 0xab, 0xf6, 0xad, 0x79, 0xfb, 0xf5, 0xab, 0xbc, 0xca,
    0xfc, 0xc2, 0x69, 0xd8, 0x5c, 0xd2, 0x65, 0x1e, 0xd4, 0xb8, 0x85, 0xb5, 0x86, 0x9f, 0x24, 0x1a,
    0xed, 0xf0, 0xa5, 0xba, 0x29, 0x74, 0x22, 0xb9, 0x88, 0x75, 0x98, 0x06, 0x8e, 0x32, 0xc4, 0x44,
    0x8a, 0x94, 0x9a, 0xdb, 0x29, 0x0d, 0x0f, 0x4e, 0x35, 0xb9, 0xe0, 0x1b, 0x0e, 0xe5, 0xf1, 0xa1,
    0xe6, 0x00, 0xfe, 0x26, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xe9, 0x77, 0x4a, 0x3c, 0xad, 0x5c, 0x33, 0xf1, 0xfb, 0x6b,
    0x37, 0xa0, 0x3d, 0x4f, 0x00, 0x9a, 0x31, 0x09, 0x81, 0x18, 0xd2, 0xce, 0xae, 0xbf, 0x43, 0x0a,
    0xf3, 0x01, 0xad, 0x25, 0x0d, 0x01, 0x02, 0x02, 0x00, 0x01, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00,
    0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00,
]))

assert pxsol.eddsa.verify(tx.message.account_keys[0].p, tx.message.serialize(), tx.signatures[0])