def check_pow(self): """Returns whether this block satisfies proof of work""" # get the hash256 of the serialization of this block block_hash = hash256(self.serialize()) # interpret this hash as a little-endian number proof = little_endian_to_int(block_hash) # return whether this integer is less than the target return proof < self.target()
def parse(cls, stream): """Takes a byte stream and parses the block header at the start return a Block object """ # version is an integer in 4 bytes, little-endian version = little_endian_to_int(stream.read(4)) # previous block is a 32 bytes little-endian reversed with [::-1] prev_block = stream.read(32)[::-1] # merkle root is a 32 bytes little-endian reversed with [::-1] merkle_root = stream.read(32)[::-1] # timestamp is an integer in 4 bytes, little-endian, timestamp = little_endian_to_int(stream.read(4)) # bits is a 4 bytes bits = stream.read(4) # nonce is a 4 bytes nonce = stream.read(4) return cls(version, prev_block, merkle_root, timestamp, bits, nonce)
def parse(cls, s): version = little_endian_to_int(s.read(4)) services = little_endian_to_int(s.read(8)) timestamp = little_endian_to_int(s.read(8)) receiver_services = little_endian_to_int(s.read(8)) receiver_ip = s.read(16).strip(b"\x00").strip(b"\xff") receiver_port = int.from_bytes(s.read(2), "big") sender_services = little_endian_to_int(s.read(8)) sender_ip = s.read(16).strip(b"\x00").strip(b"\xff") sender_port = int.from_bytes(s.read(2), "big") nonce = s.read(8) user_agent_len = read_varint(s) user_agent = s.read(user_agent_len) latest_block = little_endian_to_int(s.read(4)) relay = s.read(1) == b"\x01" return cls( version, services, timestamp, receiver_services, receiver_ip, receiver_port, sender_services, sender_ip, sender_port, nonce, user_agent, latest_block, relay, )
def parse(cls, s): """Takes a byte stream and parses a merkle block. Returns a Merkle Block object""" # version - 4 bytes, Little-Endian integer version = little_endian_to_int(s.read(4)) # prev_block - 32 bytes (use [::-1]) prev_block = s.read(32)[::-1] # merkle_root - 32 bytes (use [::-1]) merkle_root = s.read(32)[::-1] # timestamp - 4 bytes, Little-Endian integer timestamp = little_endian_to_int(s.read(4)) # bits - 4 bytes bits = s.read(4) # nonce - 4 bytes nonce = s.read(4) # total transactions in block - 4 bytes, Little-Endian integer total = little_endian_to_int(s.read(4)) # number of transaction hashes - varint num_hashes = read_varint(s) # each transaction is 32 bytes, Little-Endian hashes = [] for _ in num_hashes: hashes.append(little_endian_to_int(s.read(32)[::-1])) # length of flags field - varint flags_length = read_varint(s) # read the flags field flags = s.read(flags_length) # initialize class return cls( version, prev_block, merkle_root, timestamp, bits, nonce, total, hashes, flags, )
def parse(cls, s, testnet=False): """Takes a stream and creates a NetworkEnvelope""" # First 4 bytes are the network magic magic = s.read(4) if magic == b"": raise IOError("Connection reset!") if testnet: expected_magic = TESTNET_NETWORK_MAGIC else: expected_magic = NETWORK_MAGIC if magic != expected_magic: raise SyntaxError( "magic is not right {} vs {}".format(magic.hex(), expected_magic.hex()) ) # next 12 bytes are the command field # more details about each commands https://en.bitcoin.it/wiki/Protocol_documentation command = s.read(12) # remove trailing x00 bytes from command command = command.strip(b"\x00") # 4 bytes payload length in little endian payload_length = little_endian_to_int(s.read(4)) # 4 bytes payload checksum first 4 bytes of hash256 of the payload payload_checksum = s.read(4) # payload payload = s.read(payload_length) # get first 4 bytes of the payload hash256 calculated_checksum = hash256(payload)[:4] # check if the first 4 bytes hash256 of the payload match the checksum if calculated_checksum != payload_checksum: raise IOError("checksum does not match") return cls(command, payload, testnet=testnet)