(五) 区块链数据结构 – 输入脚本和输出脚本


输入脚本和输出脚本是比特币系统中,最常见的的脚本了。

当我们要支付给某个人比特币时,我们需要确保,只有接收者能花费这些比特币。在比特币系统中,会使用输出脚本来锁定交易输出,只有接收者拥有秘钥,当需要花费这笔交易输出时,提供解锁脚本即可。

比特币系统中,另一个巧妙的设计时,任何人都可以通过验证解锁脚本是否能打开锁定脚本,来判断这个交易是否合法。而在验证的过程中,支付者只需提供解锁脚本,即可完成验证,无需对外提供自己的私钥。

脚本结构

输入和输出脚本的存储格式如下:

输入脚本和输出脚本

执行过程

输入脚本和输出脚本执行过程signaturesignaturepubkeypubkey堆栈堆栈OP_DUPOP_DUPOP_HASH160OP_HASH160pubkeyHashpubkeyHashOP_EQUALVERIFYOP_EQUALVERIFYOP_CHECKSIGOP_CHECKSIG将签名signature推出栈顶signature--栈底--将支付者公钥pubkey推入栈顶pubkeysignature--栈底--复制栈顶数据,并推入栈顶pubkeypubkeysignature--栈底--取出栈顶公钥,执行HASH160计算,并推入栈顶HASH160(pubkey)pubkeysignature--栈底--将支付者公钥HASH160值推入栈顶pubkeyHashHASH160(pubkey)pubkeysignature--栈底--取出栈顶两项数据,比较是否相同,如果相同则继续执行pubkeyHash == HASH160(pubkey)pubkeysignature--栈底--取出支付者公钥和签名,验证签名是否有效CheckSig(pubkey,signature)--栈底--

核心代码

OP_DUP 复制栈顶操作

case OP_DUP:
    if (stack.size() < 1)
        throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "Attempted OP_DUP on an empty stack");
    //将栈顶数据复制一份,并推入栈顶
    stack.add(stack.getLast());
    break;

OP_HASH160 对公钥执行HASH160计算

case OP_HASH160:
    if (stack.size() < 1)
        throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "Attempted OP_HASH160 on an empty stack");
    //从栈顶取出支付者公钥,执行sha256hash160两次Hash计算,并将执行结果推入栈顶
    stack.add(Utils.sha256hash160(stack.pollLast()));
    break;

OP_EQUALVERIFY 比较公钥经过计算的HASH值与脚本中的HASH值是否一致

case OP_EQUALVERIFY:
    if (stack.size() < 2)
        throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "Attempted OP_EQUALVERIFY on a stack with size < 2");
    //从栈顶取出两项数据(支付者公钥的HASH值),比较是否相等,如果相等则继续执行,否则抛出异常
    if (!Arrays.equals(stack.pollLast(), stack.pollLast()))
        throw new ScriptException(ScriptError.SCRIPT_ERR_EQUALVERIFY, "OP_EQUALVERIFY: non-equal data");
    break;

OP_EQUALVERIFY 依据公钥和签名,验证签名是否有效

case OP_CHECKSIGVERIFY:
    if (txContainingThis == null)
        throw new IllegalStateException("Script attempted signature check but no tx was provided");
    //取出支付者公钥和签名,验证签名是否正确
    executeCheckSig(txContainingThis, (int) index, script, stack, lastCodeSepLocation, opcode, verifyFlags);
    break;

签名的生成和验证算法参见:区块链算法 – Secp256k1 签名生成和验证算法 以及证明过程


上一篇:(四)块链数据结构 - 脚本

下一篇:(六)区块链数据结构 - 密钥对(公钥和私钥)





猜你喜欢

转载自blog.csdn.net/maerdym/article/details/79857944