《区块链编程》第十章
比特币通信网络
练习1
p168
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 10:46:13
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:18:29
class NetworkEnvelope:
...
@classmethod
def parse(cls, s, testnet=False):
'''Takes a stream and creates a NetworkEnvelope'''
# check the network magic
magic = s.read(4)
if magic == b'':
raise RuntimeError('Connection reset!')
if testnet:
expected_magic = TESTNET_NETWORK_MAGIC
else:
expected_magic = NETWORK_MAGIC
if magic != expected_magic:
raise RuntimeError('magic is not right {} vs {}' /
.format(magic.hex(), expected_magic.hex()))
# command 12 bytes
command = s.read(12)
# strip the trailing 0's
command = command.strip(b'\x00')
# payload length 4 bytes, little endian
payload_length = little_endian_to_int(s.read(4))
# checksum 4 bytes, first four of hash256 of payload
checksum = s.read(4)
# payload is of length payload_length
payload = s.read(payload_length)
calculated_checksum = hash256(payload)[:4]
# verify checksum
if calculated_checksum != checksum:
raise IOError('checksum dose not match')
# return an instance of the class
return cls(command, payload, testnet=testnet)
测试
无
练习2
p168
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 11:18:08
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:20:12
from network import NetworkEnvelope
from io import BytesIO
message_hex = 'f9beb4d976657261636b000000000000000000005df6e0e2'
stream = BytesIO(bytes.fromhex(message_hex))
envelope = NetworkEnvelope.parse(stream)
print(envelope.command)
print(envelope.payload)
测试
b'verack'
b''
[Finished in 365ms]
练习3
p168
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 11:23:57
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:23:57
class NetworkEnvelope:
...
def serialize(self):
'''Returns the byte serialization of the entire network message'''
# add the network magic
result = self.magic
# command 12 bytes
# fill with 0's
result += self.command + b'\x00' * (12 - len(self.command))
# payload length 4 bytes, little endian
result += int_to_little_endian(len(self.payload), 4)
# checksum 4 bytes, first four of hash256 of payload
result += hash256(self.payload)[:4]
# payload
result += self.payload
return result
测试
无
练习4
p169
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 11:27:40
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:27:40
class VersionMessage:
...
def serialize(self):
'''Serialize this message to send over the network'''
# version is 4 bytes little endian
result = int_to_little_endian(self.version, 4)
# services is 8 bytes little endian
result += int_to_little_endian(self.services, 8)
# timestamp is 8 bytes little endian
result += int_to_little_endian(self.timestamp, 8)
# receiver services is 8 bytes little endian
result += int_to_little_endian(self.receiver_services, 8)
# IPV4 is 10 00 bytes and 2 ff bytes then receiver ip
result += b'\x00' * 10 + b'\xff\xff' + self.receiver_ip
# receiver port is 2 bytes, big endian
result += int_to_little_endian(self.receiver_port, 2)
# sender services is 8 bytes little endian
result += int_to_little_endian(self.sender_services, 8)
# IPV4 is 10 00 bytes and 2 ff bytes then sender ip
result += b'\x00' * 10 + b'\xff\xff' + self.sender_ip
# sender port is 2 bytes, big endian
result += int_to_little_endian(self.sender_port, 2)
# nonce should be 8 bytes
result += self.nonce
# useragent is a variable string, so varint first
result += encode_varint(len(self.user_agent))
result += self.user_agent
# latest block is 4 bytes little endian
result += int_to_little_endian(self.latest_block, 4)
# relay is 00 if false, 01 if true
if self.relay:
result += b'\x01'
else:
result += b'\x00'
return result
运行结果
无
练习5
p172
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 11:36:28
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:36:28
class SimpleNode:
...
def handshake(self):
'''Do a handshake with the other node.
Handshake is sending a version message and getting a verack back.'''
# create a version message
version = VersionMessage()
# send the command
self.send(version)
# wait for a verack message
self.wait_for(VerAckMessage)
运行结果
无
练习6
p174
代码实现
# -*- coding: utf-8 -*-
# @Author: 从化北(喵星人)
# @Date: 2022-01-15 11:37:20
# @Last Modified by: 从化北
# @Last Modified time: 2022-01-15 11:37:20
class GetHeadersMessage:
...
def serialize(self):
'''Serialize this message to send over the network'''
# protocol version is 4 bytes little-endian
result = int_to_little_endian(self.version, 4)
# number of hashes is a varint
result += encode_varint(self.num_hashes)
# start block is in little-endian
result += self.start_block[::-1]
# end block is also in little-endian
result += self.end_block[::-1]
return result
运行结果
无