《区块链编程》第八章

《区块链编程》第八章

支付到脚本哈希

练习1

p140

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-12 15:15:30
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-12 15:15:30
def op_checkmultisig(stack, z):
    if len(stack) < 1:
        return False
    n = decode_num(stack.pop())
    if len(stack) < n + 1:
        return False
    sec_pubkeys = []
    for _ in range(n):
        sec_pubkeys.append(stack.pop())
    m = decode_num(stack.pop())
    if len(stack) < m + 1:
        return False
    der_signatures = []
    for _ in range(m):
        der_signatures.append(stack.pop()[:-1])  # <1>
    stack.pop()  # <2>
    try:
        # parse all the points
        points = [S256Point.parse(sec) for sec in sec_pubkeys]
        # parse all the signatures
        sigs = [Signature.parse(der) for der in der_signatures]
        # loop through the signatures
        for sig in sigs:
            # if we have no more points, signatures are no good
            if len(points) == 0:
                return False
            # we loop until we find the point which works with this signature
            while points:
                # get the current point from the list of points
                point = points.pop(0)
                # we check if this signature goes with the current point
                if point.verify(z, sig):
                    break
        stack.append(encode_num(1))
        # the signatures are valid, so push a 1 to the stack
        # tag::source1[]

    except (ValueError, SyntaxError):
        return False
    return True


测试

练习2

p149

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-12 15:35:32
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-12 15:38:00


def h160_to_p2pkh_address(h160, testnet=False):
    if testnet:
        prefix = b'\x6f'
    else:
        prefix = b'\x00'
    return encode_base58_checksum(prefix + h160)


测试

练习3

p149

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-12 15:55:43
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-12 15:56:25


def h160_to_p2sh_address(h160, testnet=False):
    if testnet:
        prefix = b'\x05'
    else:
        prefix = b'\xc4'
    return encode_base58_checksum(prefix + h160)

测试

练习4

p152

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-12 17:14:50
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-12 17:45:04
from io import BytesIO
from ecc import S256Point, Signature
from helper import hash256, int_to_little_endian, encode_varint
from script import Script
from tx import Tx, SIGHASH_ALL, TxIn, TxOut

hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6\
bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8\
fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4e\
e942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef\
53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022\
01475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103\
b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04\
d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f40090000\
0000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976\
a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da\
1574e6b3c192ecfb52cc8984ee7b6c568700000000'

hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4b\
b71'

hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8ee\
f53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402\
2'
hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca88\
30bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7f\
bdbd4bb7152ae'

sec = bytes.fromhex(hex_sec)
der = bytes.fromhex(hex_der)
redeem_Script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script)))
stream = BytesIO(bytes.fromhex(hex_tx))
tx_obj = Tx.parse(stream)
s = int_to_little_endian(tx_obj.version, 4)
s += encode_varint(len(tx_obj.tx_ins))
# 因为是1-of-2多签,所以i这里没有加循环
i = tx_obj.tx_ins[0]
s += TxIn(i.prev_tx, i.prev_index, redeem_Script, i.sequence).serialize()
s += encode_varint(len(tx_obj.tx_outs))
for tx_out in tx_obj.tx_outs:
    s += tx_out.serialize()
s += int_to_little_endian(tx_obj.locktime, 4)
s += int_to_little_endian(SIGHASH_ALL, 4)
z = int.from_bytes(hash256(s), 'big')
point = S256Point.parse(sec)
sig = Signature.parse(der)
print(point.verify(z, sig))

运行结果

True
[Finished in 828ms]

练习5

p152

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-12 17:46:50
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-12 17:46:50
class Tx:
...
    def sig_hash(self, input_index, redeem_script=None):
        '''Returns the integer representation of the hash that needs to get
        signed for index input_index'''
        # start the serialization with version
        # use int_to_little_endian in 4 bytes
        s = int_to_little_endian(self.version, 4)
        # add how many inputs there are using encode_varint
        s += encode_varint(len(self.tx_ins))
        # loop through each input using enumerate, so we have the input index
        for i, tx_in in enumerate(self.tx_ins):
            # if the input index is the one we're signing
            if i == input_index:
                # if the RedeemScript was passed in, that's the ScriptSig
                if redeem_script:
                    script_sig = redeem_script
                # otherwise the previous tx's ScriptPubkey is the ScriptSig
                else:
                    script_sig = tx_in.script_pubkey(self.testnet)
            # Otherwise, the ScriptSig is empty
            else:
                script_sig = None
            # add the serialization of the input with the ScriptSig we want
            s += TxIn(
                prev_tx=tx_in.prev_tx,
                prev_index=tx_in.prev_index,
                script_sig=script_sig,
                sequence=tx_in.sequence,
            ).serialize()
        # add how many outputs there are using encode_varint
        s += encode_varint(len(self.tx_outs))
        # add the serialization of each output
        for tx_out in self.tx_outs:
            s += tx_out.serialize()
        # add the locktime using int_to_little_endian in 4 bytes
        s += int_to_little_endian(self.locktime, 4)
        # add SIGHASH_ALL using int_to_little_endian in 4 bytes
        s += int_to_little_endian(SIGHASH_ALL, 4)
        # hash256 the serialization
        h256 = hash256(s)
        # convert the result to an integer using int.from_bytes(x, 'big')
        return int.from_bytes(h256, 'big')

    def verify_input(self, input_index):
        '''Returns whether the input has a valid signature'''
        # get the relevant input
        tx_in = self.tx_ins[input_index]
        # grab the previous ScriptPubKey
        script_pubkey = tx_in.script_pubkey(testnet=self.testnet)
        # check to see if the ScriptPubkey is a p2sh using
        # Script.is_p2sh_script_pubkey()
        if script_pubkey.is_p2sh_script_pubkey():
            # the last cmd in a p2sh is the RedeemScript
            cmd = tx_in.script_sig.cmds[-1]
            # prepend the length of the RedeemScript using encode_varint
            raw_redeem = encode_varint(len(cmd)) + cmd  
            # parse the RedeemScript
            redeem_script = Script.parse(BytesIO(raw_redeem))
        # otherwise RedeemScript is None
        else:
            redeem_script = None
        # get the signature hash (z)

        # pass the RedeemScript to the sig_hash method
        z = self.sig_hash(input_index, redeem_script)
        # combine the current ScriptSig and the previous ScriptPubKey
        combined = tx_in.script_sig + script_pubkey
        # evaluate the combined script
        return combined.evaluate(z)


运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值