def recv_headers(self, payload): count, payload = read_var_int(payload) assert count <= 2000 headers = [] for i in range(count): hdr, payload = read_bytes(payload, Constants.BLOCKHEADER_SIZE, bytes, 'big') headers.append(hdr) tx_count, payload = read_var_int(payload) assert tx_count == 0 self.network.received_headers(self, headers)
def recv_inv(self, payload): count, payload = read_var_int(payload) for i in range(count): data, payload = read_bytes(payload, 36, bytes, 'big') inv = InventoryVector.from_serialized(data) # TODO get data if we need it # invs.append( inv ) # self.send_getdata( invs ) print(inv)
def recv_reject(self, payload): length_msg, payload = read_var_int(payload) raw_msg, payload = read_bytes(payload, length_msg, bytes, 'big') msg = raw_msg.decode('ascii') ccode, payload = read_bytes(payload, 1, int, 'little') length_reason, payload = read_var_int(payload) raw_reason, payload = read_bytes(payload, length_reason, bytes, 'big') reason = raw_reason.decode('utf-8') data = payload.hex() print("{} reject {}: {}, {} {}".format( self.address['host'], msg, { Constants.REJECT_MALFORMED: "malformed", Constants.REJECT_INVALID: "invalid", Constants.REJECT_OBSOLETE: "obsolete", Constants.REJECT_DUPLICATE: "duplicate", Constants.REJECT_NONSTANDARD: "non standard", Constants.REJECT_DUST: "dust", Constants.REJECT_INSUFFICIENTFEE: "insufficient fee", Constants.REJECT_CHECKPOINT: "checkpoint" }[ccode], reason, data))
def recv_getdata(self, payload): count, payload = read_var_int(payload) for i in range(count): data, payload = read_bytes(payload, 36, bytes, 'big') inv = InventoryVector.from_serialized(data) if inv in self.inventory: if inv.is_tx(): try: tx = self.txdb[inv.get_id()] except: raise NetworkError("cannot retrieve transaction") else: self.send_tx(bytes.fromhex(tx))
def recv_addr(self, payload): count, payload = read_var_int(payload) for i in range(count): data, payload = read_bytes(payload, 30, bytes, 'big') address = deserialize_network_address(data, with_timestamp=True) if not any([ address['host'] == na['host'] for na in self.network.peer_list ]) & (address['host'] != "") & (address['port'] == Constants.DEFAULT_PORT) & ( len(self.network.peer_list) < self.network.MAX_PEER_ADDRESSES): self.network.peer_list.append(address) print("New peer address: {}".format(address['host'])) assert payload == bytes()
def recv_version(self, payload): if len(payload) < 20: self.state = 'dead' return try: self.version, payload = read_bytes(payload, 4, int, 'little') self.services, payload = read_bytes(payload, 8, int, 'little') self.time, payload = read_bytes(payload, 8, int, 'little') addr_recv, payload = read_bytes(payload, 26, bytes, 'big') my_network_address = deserialize_network_address( addr_recv, with_timestamp=False) addr_trans, payload = read_bytes(payload, 26, bytes, 'big') peer_network_address = deserialize_network_address( addr_trans, with_timestamp=False) nonce, payload = read_bytes(payload, 8, int, 'little') peer_user_agent_size, payload = read_var_int(payload) peer_user_agent, payload = read_bytes(payload, peer_user_agent_size, bytes, 'big') self.block_height, payload = read_bytes(payload, 4, int, 'little') relay, payload = read_bytes(payload, 1, int, 'little') assert payload == bytes() except: self.state = 'dead' return print(" Peer address: {}\n Services: {:d}\n User Agent: {}".format( peer_network_address['host'], peer_network_address['services'], peer_user_agent.decode('ascii'))) self.send_verack() self.peer_verack += 1 if not self.sent_version: self.send_version() if self.peer_verack == 2: self.handshake_time = time.time() print("{} handshake done".format(self.address['host']))
def from_serialized(self, raw): assert isinstance(raw, bytes) self.raw = raw version, raw = read_bytes(raw, 4, int, 'little') input_count, raw = read_var_int(raw) txins = [] for i in range(input_count): txin = {} txin['txid'], raw = read_bytes(raw, 32, hex, 'little') txin['index'], raw = read_bytes(raw, 4, int, 'little') scriptsize, raw = read_var_int(raw) unlockingScript, raw = read_bytes(raw, scriptsize, bytes, 'big') txin['unlocking_script'] = unlockingScript.hex() if (txin['txid'] == "00" * 32) & (txin['index'] == 0xffffffff): # Coinbase input txin['type'] = "coinbase" else: t, signatures, pubkeys, address, redeem_script = parse_unlocking_script( unlockingScript) txin['type'] = t if t == "p2pk": txin['signatures'] = [sig.hex() for sig in signatures] elif t == "p2pkh": txin['signatures'] = [sig.hex() for sig in signatures] txin['pubkeys'] = pubkeys txin['address'] = address elif t == "p2sh": # only p2sh-ms for the moment txin['signatures'] = [sig.hex() for sig in signatures] txin['pubkeys'] = pubkeys txin['address'] = address txin['redeem_script'] = redeem_script elif t == "p2ms": raise TransactionError("we do not parse p2ms outputs") else: raise TransactionError("cannot parse unlocking script") txin['nsigs'] = len(signatures) txin['sequence'], raw = read_bytes(raw, 4, int, 'little') txins.append(txin) output_count, raw = read_var_int(raw) txouts = [] for i in range(output_count): txout = {} txout['value'], raw = read_bytes(raw, 8, int, 'little') scriptsize, raw = read_var_int(raw) lockingScript, raw = read_bytes(raw, scriptsize, bytes, 'big') txout['locking_script'] = lockingScript.hex() t, address, data = parse_locking_script(lockingScript) txout['type'] = t if t in ("p2pkh", "p2sh"): txout['address'] = address elif t == "p2pk": txout['address'] = address elif t == "nulldata": txout['data'] = data elif t == "p2ms": raise TransactionError("we do not parse p2pk and p2ms outputs") else: raise TransactionError("cannot parse unlocking script") txouts.append(txout) locktime, raw = read_bytes(raw, 4, int, 'little') return self(version, txins, txouts, locktime)