区块 练习1《区块链编程》第九章
代码实现p154
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:22:46
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:26:57
class Tx:
...
def is_coinbase(self):
'''Returns whether this transaction is a coinbase transaction or not'''
# check that there is exactly 1 input
if len(self.tx_ins) != 1:
return False
# grab the first input
first_input = self.tx_ins[0]
# check that first input prev_tx is b'\x00' * 32 bytes
if first_input.prev_tx != b'\x00' * 32:
return False
# check that first input prev_index is 0xffffffff
if first_input.prev_index != 0xffffffff:
return False
return True
测试
无
练习2
代码实现p156
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:27:51
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:27:51
class Tx:
...
def coinbase_height(self):
'''Returns the height of the block this coinbase transaction is in
Returns None if this transaction is not a coinbase transaction
'''
# if this is NOT a coinbase transaction, return None
if not self.is_coinbase() :
return None
# grab the first cmd
element = self.tx_ins[0].script_sig.cmds[0]
# convert the cmd from little endian to int
return little_endian_to_int(element)
测试
无
练习3
代码实现p157
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:33:46
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:33:46
class Block:
...
@classmethod
def parse(cls, s):
'''Takes a byte stream and parses a block. Returns a Block object'''
# s.read(n) will read n bytes from the stream
# version - 4 bytes, little endian, interpret as int
version = little_endian_to_int(s.read(4))
# prev_block - 32 bytes, little endian (use [::-1] to reverse)
prev_block = s.read(32)[::-1]
# merkle_root - 32 bytes, little endian (use [::-1] to reverse)
merkle_root = s.read(32)[::-1]
# timestamp - 4 bytes, little endian, interpret as int
timestamp = little_endian_to_int(s.read(4))
# bits - 4 bytes
bits = s.read(4)
# nonce - 4 bytes
nonce = s.read(4)
# initialize class
return cls(version, prev_block, merkle_root, timestamp, bits, nonce)
测试
无
练习4
代码实现p157
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:40:27
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:40:27
class Block:
...
def serialize(self):
'''Returns the 80 byte block header'''
# version - 4 bytes, little endian
result = int_to_little_endian(self.version, 4)
# prev_block - 32 bytes, little endian
result += self.prev_block[::-1]
# merkle_root - 32 bytes, little endian
result += self.merkle_root[::-1]
# timestamp - 4 bytes, little endian
result += int_to_little_endian(self.timestamp, 4)
# bits - 4 bytes
result += self.bits
# nonce - 4 bytes
result += self.nonce
return result
运行结果
无
练习5
代码实现p157
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:44:10
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:44:10
class Block:
...
def hash(self):
'''Returns the hash256 interpreted little endian of the block'''
# serialize
s = self.serialize()
# hash256
sha = hash256(s)
# reverse
return sha[::-1]
运行结果
无
练习6
代码实现p158
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:45:44
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:45:44
class Block:
...
def bip9(self):
'''Returns whether this block is signaling readiness for BIP9'''
# BIP9 is signalled if the top 3 bits are 001
# remember version is 32 bytes so right shift 29 (>> 29) and see if
# that is 001
return self.version >> 29 == 0b001
运行结果
无
练习7
代码实现p159
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:47:52
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:47:52
class Block:
...
def bip91(self):
'''Returns whether this block is signaling readiness for BIP91'''
# BIP91 is signalled if the 5th bit from the right is 1
# shift 4 bits to the right and see if the last bit is 1
return self.version >> 4 & 1 == 1
运行结果
无
练习8
代码实现p159
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:49:22
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:49:22
class Block:
...
def bip141(self):
'''Returns whether this block is signaling readiness for BIP141'''
# BIP91 is signalled if the 2nd bit from the right is 1
# shift 1 bit to the right and see if the last bit is 1
return self.version >> 1 & 1 == 1
运行结果
无
练习9
代码实现p162
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 11:50:48
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 11:50:48
def bits_to_target(bits):
'''Turns bits into a target (large 256-bit integer)'''
# last byte is exponent
exponent = bits[-1]
# the first three bytes are the coefficient in little endian
coefficient = little_endian_to_int(bits[:-1])
# the formula is:
# coefficient * 256**(exponent-3)
return coefficient * 256 ** (exponent - 3)
运行结果
无
练习10
代码实现p163
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 14:12:28
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 14:12:28
class Block:
...
def difficulty(self):
'''Returns the block difficulty based on the bits'''
# note difficulty is (target of lowest difficulty) / (self's target)
# lowest difficulty has bits that equal 0xffff001d
lowest = 0xffff * 256 ** (0x1d - 3)
return lowest / self.target()
运行结果
无
练习11
代码实现p163
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 14:16:14
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 14:16:14
class Block:
...
def check_pow(self):
'''Returns whether this block satisfies proof of work'''
# get the hash256 of the serialization of this block
sha = hash256(self.serialize())
# interpret this hash as a little-endian number
proof = little_endian_to_int(sha)
# return whether this integer is less than the target
return proof < self.target()
运行结果
无
练习12
代码实现p165
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 14:19:07
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 14:26:27
from io import BytesIO
from block import Block
from helper import TWO_WEEKS
from helper import target_to_bits
block1_hex = '000000203471101bbda3fe307664b3283a9ef0e97d9a38a7eacd88000000\
00000000000010c8aba8479bbaa5e0848152fd3c2289ca50e1c3e58c9a4faaafbdf5803c5448dd\
b845597e8b0118e43a81d3'
block2_hex = '02000020f1472d9db4b563c35f97c428ac903f23b7fc055d1cfc26000000\
000000000000b3f449fcbe1bc4cfbcb8283a0d2c037f961a3fdf2b8bedc144973735eea707e126\
4258597e8b0118e5f00474'
last_block = Block.parse(BytesIO(bytes.fromhex(block1_hex)))
first_block = Block.parse(BytesIO(bytes.fromhex(block2_hex)))
time_differential = last_block.timestamp - first_block.timestamp
if time_differential > TWO_WEEKS * 4:
time_differential = TWO_WEEKS * 4
if time_differential < TWO_WEEKS // 4:
time_differential = TWO_WEEKS // 4
new_target = last_block.target() * time_differential // TWO_WEEKS
new_bits = target_to_bits(new_target)
print(new_bits.hex())
运行结果
80df6217
[Finished in 342ms]
练习13
代码实现p165
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-14 14:31:48
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-14 14:49:10
MAX_TARGET = 0xffff * 256**(0x1d - 3)
def calculate_new_bits(previous_bits, time_differential):
'''Calculates the new bits given
a 2016-block time differential and the previous bits'''
# if the time differential is greater than 8 weeks, set to 8 weeks
if time_differential > TWO_WEEKS * 4:
time_differential = TWO_WEEKS * 4
# if the time differential is less than half a week, set to half a week
if time_differential < TWO_WEEKS // 4:
time_differential = TWO_WEEKS // 4
# the new target is the previous target * time differential / two weeks
new_target = bits_to_target(previous_bits) * time_differential // TWO_WEEKS
# if the new target is bigger than MAX_TARGET, set to MAX_TARGET
if new_target > MAX_TARGET:
new_target = MAX_TARGET
# convert the new target to bits
return target_to_bits(new_target)
运行结果
无
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)