《区块链编程》第五章
Posted 从化北
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《区块链编程》第五章相关的知识,希望对你有一定的参考价值。
《区块链编程》第五章
交易
交易的组成
- 版本号
- 输入
i. 父交易的id
ii. 父交易output的序号
iii. 签名脚本
iv. 序列号 - 输出
i. amount
ii. 公钥脚本 - 时间锁
练习1
p88
代码实现
from helper import little_endian_to_int
from io import BytesIO
class Tx:
def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
self.version = version
self.tx_ins = tx_ins # <1>
self.tx_outs = tx_outs
self.locktime = locktime
self.testnet = testnet # <2>
def __repr__(self):
tx_ins = ''
for tx_in in self.tx_ins:
tx_ins += tx_in.__repr__() + '\\n'
tx_outs = ''
for tx_out in self.tx_outs:
tx_outs += tx_out.__repr__() + '\\n'
return 'tx: \\nversion: \\ntx_ins:\\ntx_outs:\\nlocktime: '.format(
self.id(),
self.version,
tx_ins,
tx_outs,
self.locktime,
)
def id(self): # <3>
'''Human-readable hexadecimal of the transaction hash'''
return self.hash().hex()
def hash(self): # <4>
'''Binary hash of the legacy serialization'''
return hash256(self.serialize())[::-1]
# end::source1[]
@classmethod
def parse(cls, s, testnet=False):
'''Takes a byte stream and parses the transaction at the start
return a Tx object
'''
version = little_endian_to_int(s.read(4))
return cls(version, None, None, None, testnet=testnet)
if __name__ == '__main__':
tx = '01000000'
stream = BytesIO(bytes.fromhex(tx))
print(Tx.parse(stream).version)
测试
1
[Finished in 306ms]
练习2
p92
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-04 15:38:18
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-04 16:33:55
from helper import little_endian_to_int, read_varint
from io import BytesIO
from script import Script
class Tx:
def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
self.version = version
self.tx_ins = tx_ins #
self.tx_outs = tx_outs
self.locktime = locktime
self.testnet = testnet #
@classmethod
def parse(cls, s, testnet=False):
'''Takes a byte stream and parses the transaction at the start
return a Tx object
'''
# BytesIO的read会改变游标的位置。但不会更改BytesIO的数据
version = little_endian_to_int(s.read(4))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
return cls(version, inputs, None, None, testnet=testnet)
class TxIn:
def __init__(self, prev_tx, prev_index, script_sig=None, sequence=0xffffffff):
self.prev_tx = prev_tx
self.prev_index = prev_index
if script_sig is None: # <1>
self.script_sig = Script()
else:
self.script_sig = script_sig
self.sequence = sequence
def __repr__(self):
return ':'.format(
self.prev_tx.hex(),
self.prev_index,
)
# end::source2[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_input at the start
return a TxIn object
'''
prev_tx = s.read(32)[::-1]
prev_index = little_endian_to_int(s.read(4))
script_sig = Script.parse(s)
sequence = little_endian_to_int(s.read(4))
return cls(prev_tx, prev_index, script_sig, sequence)
if __name__ == '__main__':
raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
stream = BytesIO(raw_tx)
tx = Tx.parse(stream)
print(tx.tx_ins)
测试
[d1c789a9c60383bf715f3f6ad9d14b91fe55f3deb369fe5d9280cb1a01793f81:0]
[Finished in 309ms]
练习3
p94
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-04 16:58:44
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-04 17:03:18
from helper import little_endian_to_int, read_varint
from io import BytesIO
from script import Script
class Tx:
def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
self.version = version
self.tx_ins = tx_ins #
self.tx_outs = tx_outs
self.locktime = locktime
self.testnet = testnet #
@classmethod
def parse(cls, s, testnet=False):
'''Takes a byte stream and parses the transaction at the start
return a Tx object
'''
# BytesIO的read会改变游标的位置。但不会更改BytesIO的数据
version = little_endian_to_int(s.read(4))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
num_outputs = read_varint(s)
outputs = []
for _ in range(num_outputs):
outputs.append(TxOut.parse(s))
return cls(version, inputs, outputs, None, testnet=testnet)
class TxIn:
def __init__(self, prev_tx, prev_index, script_sig=None, sequence=0xffffffff):
self.prev_tx = prev_tx
self.prev_index = prev_index
if script_sig is None: # <1>
self.script_sig = Script()
else:
self.script_sig = script_sig
self.sequence = sequence
def __repr__(self):
return ':'.format(
self.prev_tx.hex(),
self.prev_index,
)
# end::source2[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_input at the start
return a TxIn object
'''
prev_tx = s.read(32)[::-1]
prev_index = little_endian_to_int(s.read(4))
script_sig = Script.parse(s)
sequence = little_endian_to_int(s.read(4))
return cls(prev_tx, prev_index, script_sig, sequence)
class TxOut:
def __init__(self, amount, script_pubkey):
self.amount = amount
self.script_pubkey = script_pubkey
def __repr__(self):
return ':'.format(self.amount, self.script_pubkey)
# end::source3[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_output at the start
return a TxOut object
'''
amount = little_endian_to_int(s.read(8))
script_pubkey = Script.parse(s)
return cls(amount, script_pubkey)
# amount is an integer in 8 bytes, little endian
# use Script.parse to get the ScriptPubKey
# return an instance of the class (see __init__ for args)
# raise NotImplementedError
# tag::source4[]
def serialize(self): # <1>
'''Returns the byte serialization of the transaction output'''
result = int_to_little_endian(self.amount, 8)
result += self.script_pubkey.serialize()
return result
# end::source4[]
if __name__ == '__main__':
raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
stream = BytesIO(raw_tx)
tx = Tx.parse(stream)
# print(tx.tx_ins)
print(tx.tx_outs)
测试
[32454049:OP_DUP OP_HASH160 bc3b654dca7e56b04dca18f2566cdaf02e8d9ada OP_EQUALVERIFY OP_CHECKSIG, 10011545:OP_DUP OP_HASH160 1c4bc762dd5423e332166702cb75f40df79fea12 OP_EQUALVERIFY OP_CHECKSIG]
[Finished in 319ms]
练习4
p95
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-04 17:04:41
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-04 17:05:35
from helper import little_endian_to_int, read_varint
from io import BytesIO
from script import Script
class Tx:
def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
self.version = version
self.tx_ins = tx_ins #
self.tx_outs = tx_outs
self.locktime = locktime
self.testnet = testnet #
@classmethod
def parse(cls, s, testnet=False):
'''Takes a byte stream and parses the transaction at the start
return a Tx object
'''
# BytesIO的read会改变游标的位置。但不会更改BytesIO的数据
version = little_endian_to_int(s.read(4))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
num_outputs = read_varint(s)
outputs = []
for _ in range(num_outputs):
outputs.append(TxOut.parse(s))
locktime = little_endian_to_int(s.read(4))
return cls(version, inputs, outputs, locktime, testnet=testnet)
class TxIn:
def __init__(self, prev_tx, prev_index, script_sig=None, sequence=0xffffffff):
self.prev_tx = prev_tx
self.prev_index = prev_index
if script_sig is None: # <1>
self.script_sig = Script()
else:
self.script_sig = script_sig
self.sequence = sequence
def __repr__(self):
return ':'.format(
self.prev_tx.hex(),
self.prev_index,
)
# end::source2[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_input at the start
return a TxIn object
'''
prev_tx = s.read(32)[::-1]
prev_index = little_endian_to_int(s.read(4))
script_sig = Script.parse(s)
sequence = little_endian_to_int(s.read(4))
return cls(prev_tx, prev_index, script_sig, sequence)
class TxOut:
def __init__(self, amount, script_pubkey):
self.amount = amount
self.script_pubkey = script_pubkey
def __repr__(self):
return ':'.format(self.amount, self.script_pubkey)
# end::source3[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_output at the start
return a TxOut object
'''
amount = little_endian_to_int(s.read(8))
script_pubkey = Script.parse(s)
return cls(amount, script_pubkey)
# amount is an integer in 8 bytes, little endian
# use Script.parse to get the ScriptPubKey
# return an instance of the class (see __init__ for args)
# raise NotImplementedError
# tag::source4[]
def serialize(self): # <1>
'''Returns the byte serialization of the transaction output'''
result = int_to_little_endian(self.amount, 8)
result += self.script_pubkey.serialize()
return result
# end::source4[]
if __name__ == '__main__':
raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
stream = BytesIO(raw_tx)
tx = Tx.parse(stream)
# print(tx.tx_ins)
print(tx.locktime)
运行结果
410393
[Finished in 320ms]
练习5
p95
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-04 17:06:15
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-04 17:11:16
from helper import little_endian_to_int, read_varint
from io import BytesIO
from script import Script
class Tx:
def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
self.version = version
self.tx_ins = tx_ins #
self.tx_outs = tx_outs
self.locktime = locktime
self.testnet = testnet #
@classmethod
def parse(cls, s, testnet=False):
'''Takes a byte stream and parses the transaction at the start
return a Tx object
'''
# BytesIO的read会改变游标的位置。但不会更改BytesIO的数据
version = little_endian_to_int(s.read(4))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
num_outputs = read_varint(s)
outputs = []
for _ in range(num_outputs):
outputs.append(TxOut.parse(s))
locktime = little_endian_to_int(s.read(4))
return cls(version, inputs, outputs, locktime, testnet=testnet)
class TxIn:
def __init__(self, prev_tx, prev_index, script_sig=None, sequence=0xffffffff):
self.prev_tx = prev_tx
self.prev_index = prev_index
if script_sig is None: # <1>
self.script_sig = Script()
else:
self.script_sig = script_sig
self.sequence = sequence
def __repr__(self):
return ':'.format(
self.prev_tx.hex(),
self.prev_index,
)
# end::source2[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_input at the start
return a TxIn object
'''
prev_tx = s.read(32)[::-1]
prev_index = little_endian_to_int(s.read(4))
script_sig = Script.parse(s)
sequence = little_endian_to_int(s.read(4))
return cls(prev_tx, prev_index, script_sig, sequence)
class TxOut:
def __init__(self, amount, script_pubkey):
self.amount = amount
self.script_pubkey = script_pubkey
def __repr__(self):
return ':'.format(self.amount, self.script_pubkey)
# end::source3[]
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses the tx_output at the start
return a TxOut object
'''
amount = little_endian_to_int(s.<以上是关于《区块链编程》第五章的主要内容,如果未能解决你的问题,请参考以下文章