《区块链编程》第十二章

《区块链编程》第十二章

简单支付验证

练习1

p200

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 15:12:21
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 15:16:41
from helper import hash160
bit_field_size = 10
bit_field = [0] * bit_field_size
for item in (b'hello world', b'goodbye'):
    h = hash160(item)
    bit = int.from_bytes(h, 'big') % bit_field_size
    bit_field[bit] = 1
print(bit_field)


测试

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[Finished in 610ms]

练习2

p203

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 15:18:00
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 15:22:27
from bloomfilter import BloomFilter, BIP37_CONSTANT
from helper import bit_field_to_bytes, murmur3
field_size = 10
function_cuont = 5
tweak = 99
items = (b'Hello World', b'Goodbye!')
bit_field_size = field_size * 8
bit_field = [0] * bit_field_size
for item in items:
    for i in range(function_cuont):
        seed = i * BIP37_CONSTANT + tweak
        h = murmur3(item, seed=seed)
        bit = h % bit_field_size
        bit_field[bit] = 1
print(bit_field)
print(bit_field_to_bytes(bit_field).hex())


测试

[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
4000600a080000010940
[Finished in 374ms]

练习3

p203

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 15:23:41
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 15:23:41
class BloomFilter:
    ...
    def add(self, item):
        '''Add an item to the filter'''
        # iterate self.function_count number of times
        for i in range(self.function_count):
            # BIP0037 spec seed is i*BIP37_CONSTANT + self.tweak
            seed = i * BIP37_CONSTANT + self.tweak
            # get the murmur3 hash given that seed
            h = murmur3(item, seed)
            # set the bit at the hash mod the bitfield size (self.size*8)
            bit = h % (self.size * 8)
            # set the bit field at bit to be 1
            self.bit_field[bit] = 1
        

测试

练习4

p204

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 15:26:42
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 15:26:42
class BloomFilter:
    ...
    def filterload(self, flag=1):
        '''Return the filterload message'''
        # start the payload with the size of the filter in bytes
        payload = encode_varint(self.size)
        # next add the bit field using self.filter_bytes()
        payload += self.filter_bytes()
        # function count is 4 bytes little endian
        payload += int_to_little_endian(self.function_count, 4)
        # tweak is 4 bytes little endian
        payload += int_to_little_endian(self.tweak, 4)
        # flag is 1 byte little endian
        payload += int_to_little_endian(flag, 1)
        # return a GenericMessage whose command is b'filterload'
        # and payload is what we've calculated
        return GenericMessage(b'filterload', payload)

运行结果

练习5

p205

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 15:30:50
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 15:30:50
class GetDataMessage:
    ...
    def serialize(self):
        # start with the number of items as a varint
        result = encode_varint(len(self.data))
        # loop through each tuple (data_type, identifier) in self.data
        for data_type, identifier in self.data:
            # data type is 4 bytes Little-Endian
            result += int_to_little_endian(data_type, 4)
            # identifier needs to be in Little-Endian
            result += identifier[::-1]
        return result

运行结果

练习6

p206

代码实现

# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date:   2022-01-17 19:35:47
# @Last Modified by:   从化北
# @Last Modified time: 2022-01-17 20:10:25
import time
from block import Block
from bloomfilter import BloomFilter
from ecc import PrivateKey
from helper import(
    decode_base58,
    encode_varint,
    hash256,
    little_endian_to_int,
    read_varint,
)
from merkleblock import MerkleBlock
from network import(
    GetDataMessage,
    GetHeadersMessage,
    HeadersMessage,
    NetworkEnvelope,
    SimpleNode,
    TX_DATA_TYPE,
    FILTERED_BLOCK_DATA_TYPE,
)
from script import p2pkh_script, Script
from tx import Tx, TxIn, TxOut
last_block_hex = '000000000000001516868f7978c999c087861a5f61302b660a226f7d2deffba6'
secret = little_endian_to_int(hash256(b'***********'))
private_key = PrivateKey(secret=secret)
addr = private_key.point.address(testnet=True)
h160 = decode_base58(addr)
target_address = 'mvgTF5toE4Y7d59ibvq5E7fMka7uiAYprs'
target_h160 = decode_base58(target_address)
target_script = p2pkh_script(target_h160)
fee = 5000
node = SimpleNode('testnet.programmingbitcoin.com', testnet=True, logging=False)
bf = BloomFilter(30, 5, 90210)
bf.add(h160)
node.handshake()
node.send(bf.filterload())
start_block = bytes.fromhex(last_block_hex)
getheaders = GetHeadersMessage(start_block=start_block)
node.send(getheaders)
headers = node.wait_for(HeadersMessage)
last_block = None
getdata = GetDataMessage()
for b in headers.blocks:
    if not b.check_pow():
        raise RuntimeError('proof of work is invalid')
    if last_block is not None and b.prev_block != last_block:
        raise RuntimeError('chain broken')
    getdata.add_data(FILTERED_BLOCK_DATA_TYPE, b.hash())
    last_block = b.hash()
node.send(getdata)
prev_tx, prev_index, prev_amount = None, None, None
while prev_tx is None:
    message = node.wait_for(MerkleBlock, Tx)
    if message.command == b'merkleblock':
        if not message.is_valid():
            raise RuntimeError('invalid merkle proof')
    else:
        message.testnet = True
        for i, tx_out in enumerate(message.tx_outs):
            if tx_out.script_pubkey.address(testnet=True) == addr:
                prev_tx = message.hash()
                prev_index = i
                prev_amount = tx_out.amount
                print('found: {}:{}'.format(prev_tx.hex(), prev_index))
tx_in = TxIn(prev_tx, prev_index)
output_amount = prev_amount - fee
tx_out = TxOut(output_amount, target_script)
tx_obj = Tx(1, [tx_in], [tx_out], 0, testnet=True)
print(tx_obj.sign_input(0, private_key))
print(tx_obj.serialize().hex())
node.send(tx_obj)
time.sleep(1)
getdata = GetDataMessage()
getdata.add_data(TX_DATA_TYPE, tx_obj.hash())
node.send(getdata)
received_tx = node.wait_for(Tx)
if received_tx.id() == tx_obj.id():
    print("success!")


运行结果

found: fe696aa4947ed9a02b27f65bdfd0d01a5ffea85924df34a8afa04efc5ea2c861:1
True
010000000161c8a25efc4ea0afa834df2459a8fe5f1ad0d0df5bf6272ba0d97e94a46a69fe010000006a473044022055d412f7b16c2ffd3ec68f2b19c0189087e2dd1ef9a988559e68c43858db3092022056683ab8e0b0675198acec2b30b4082e54c2cd06ed986dcee6118d53bce28962012103ee84c2eb9f347de0cc501f3b109eb14e93ee0d77f60c9eb61993cb5a45f1d95dffffffff0188130000000000001976a914a655cbb0b31bcd08157a6aeecc5d76a2e5be2bbe88ac00000000
[Finished in 5.6s]

说明

测试6中,的success没有提示。
我后续实验了一下, received_tx.id()和tx_obj.id() 并不一致。
然后我又运行了一下给的example。 结果是一致的。
不知道为什么。好难受
还有, getdata的payload中,第三个Hash identifier 代表什么? 我本以为它代表想要获得数据的哈希值。 但是好像并不是那样,我试验了一些,还是没搞懂。哎。
我在GitHub上提交了一个issue,有人知道的话,快来救救孩子吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值