def refund_tx(self, payer_sig, serial_tx, redeem_script): ''' Sends a transaction refunding the funder of the P2SH address. ''' # Read in transaction temp_tx = CTransaction.deserialize(serial_tx) tx = CMutableTransaction.from_tx(temp_tx) txin = tx.vin[0] # Set script sig txin.scriptSig = CScript([payer_sig + '\x01', OP_FALSE, redeem_script]) # Verify script redeem_script = CScript(redeem_script) VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) serial_tx = tx.serialize() if not self.test: # txid = self.self.proxy.sendrawtransaction(tx) txid = b2lx(Hash(serial_tx)) else: txid = b2lx(Hash(serial_tx)) self.logger.info("refund_tx: TXID is %s", txid) self.logger.info("refund_tx: RAW TX is %s", b2x(serial_tx)) return serial_tx
def spend_escrow(self, payer_sig, redeemer_sig, serial_tx, redeem_script): ''' Sends a transaction fulfilling the redeem script of escrow tx ''' # Read in transaction temp_tx = CTransaction.deserialize(serial_tx) tx = CMutableTransaction.from_tx(temp_tx) txin = tx.vin[0] # Set script sig txin.scriptSig = CScript([ OP_FALSE, payer_sig + '\x01', redeemer_sig + '\x01', OP_TRUE, redeem_script ]) # Verify script redeem_script = CScript(redeem_script) serial_tx = tx.serialize() VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) serial_tx = tx.serialize() if not self.test: # txid = self.proxy.sendrawtransaction(tx) txid = b2lx(Hash(serial_tx)) else: txid = b2lx(Hash(serial_tx)) self.logger.info("spend_escrow: TXID is %s", txid) self.logger.info("spend_escrow: RAW TX is %s", b2x(serial_tx)) return serial_tx
def send_inventory(self, serialized_transaction) -> msg_getdata: message = msg_inv() inventory = CInv() inventory.type = MSG_TX hash_transaction = Hash(serialized_transaction) inventory.hash = hash_transaction message.inv.append(inventory) timeout = time() + NODE_COMMUNICATION_TIMEOUT while time() < timeout: node = self.connect() if node is None: self.reset_connection() continue if not self.send_message(message): self.terminate(node) continue messages = self.capture_messages([ msg_getdata, ]) if not messages: self.terminate(node) continue logger.info('[%s] Node responded correctly.', node) return messages[0]
def build_merkle_tree_from_txids(txids): """Build a full Block merkle tree from txids txids - iterable of txids Returns a new merkle tree in deepest first order. The last element is the merkle root. WARNING! If you're reading this because you're learning about crypto and/or designing a new system that will use merkle trees, keep in mind that the following merkle tree algorithm has a serious flaw related to duplicate txids, resulting in a vulnerability. (CVE-2012-2459) Bitcoin has since worked around the flaw, but for new applications you should use something different; don't just copy-and-paste this code without understanding the problem first. """ merkle_tree = list(txids) size = len(txids) j = 0 while size > 1: for i in range(0, size, 2): i2 = min(i+1, size-1) merkle_tree.append(Hash(merkle_tree[j+i] + merkle_tree[j+i2])) j += size size = (size + 1) // 2 return merkle_tree
def broadcast_transaction(self, raw_transaction: str) -> Optional[str]: ''' Sends given transaction to connected node. Args: raw_transaction (str): hex string containing signed transaction Returns: str, None: transaction address if transaction was sent, None otherwise. ''' deserialized_transaction = self.deserialize_raw_transaction( raw_transaction) serialized_transaction = deserialized_transaction.serialize() get_data = self.send_inventory(serialized_transaction) if not get_data: logger.debug( ConnectionProblem( 'Clove could not get connected with any of the nodes for too long.' )) self.reset_connection() return node = self.get_current_node() if all(el.hash != Hash(serialized_transaction) for el in get_data.inv): logger.debug( UnexpectedResponseFromNode( 'Node did not ask for our transaction', node)) self.reset_connection() return message = msg_tx() message.tx = deserialized_transaction if not self.send_message(message, 20): return logger.info('[%s] Looking for reject message.', node) messages = self.capture_messages([ msg_reject, ], timeout=REJECT_TIMEOUT, buf_size=8192, ignore_empty=True) if messages: logger.debug(TransactionRejected(messages[0], node)) self.reset_connection() return logger.info('[%s] Reject message not found.', node) transaction_address = b2lx(deserialized_transaction.GetHash()) logger.info('[%s] Transaction %s has just been sent.', node, transaction_address) return transaction_address
def spend_preimage(self, preimages, redeemer_sig, serial_tx, redeem_script): ''' Sends a transaction fulfilling the redeem script of the preimage P2SH ''' # Read in transaction temp_tx = CTransaction.deserialize(serial_tx) tx = CMutableTransaction.from_tx(temp_tx) txin = tx.vin[0] # Setup preimages in reverse order script = [] for p in reversed(preimages): script += [p] # Create script sig txin.scriptSig = CScript([redeemer_sig + '\x01'] + script + [OP_TRUE, redeem_script]) # Verify script redeem_script = CScript(redeem_script) VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) serial_tx = tx.serialize() if not self.test: # txid = self.proxy.sendrawtransaction(tx) txid = b2lx(Hash(serial_tx)) else: txid = b2lx(Hash(serial_tx)) self.logger.info("spend_preimage: TXID is %s", txid) self.logger.info("spend_preimage: RAW TX is %s", b2x(serial_tx)) return serial_tx
def parse_partial_mekel_tree(self, node, bit_list, hashes_list, transactions_hashes): flag = bit_list.pop(0) if (flag == "0"): return hashes_list.pop(0) if (flag == "1" and node.left is None): transaction_hash = hashes_list.pop(0) transactions_hashes.append(b2lx(transaction_hash)) return transaction_hash hash_left = self.parse_partial_mekel_tree(node.left, bit_list, hashes_list, transactions_hashes) if node.right: hash_right = self.parse_partial_mekel_tree(node.right, bit_list, hashes_list, transactions_hashes) else: hash_right = hash_left return Hash(hash_left + hash_right)
def send_inventory(self, serialized_transaction) -> Optional[msg_getdata]: ''' Sends inventory message with given serialized transaction to connected node. Returns: msg_getdata, None: get data request or None if something went wrong Note: This method is used by `broadcast_transaction` to inform connected node about existence of the new transaction. ''' message = msg_inv() inventory = CInv() inventory.type = MSG_TX hash_transaction = Hash(serialized_transaction) inventory.hash = hash_transaction message.inv.append(inventory) timeout = time() + NODE_COMMUNICATION_TIMEOUT while time() < timeout: node = self.connect() if node is None: self.reset_connection() continue if not self.send_message(message): self.terminate(node) continue messages = self.capture_messages([ msg_getdata, ]) if not messages: self.terminate(node) continue logger.info('[%s] Node responded correctly.', node) return messages[0]
print("\nTransformed properties") print("%s %s" % ("Version hex little endian:", reversed_version_hex)) print("%s %s" % ("Previous block hash little endian:", reversed_prev_block_hash)) print("%s %s" % ("Merkle root little endian:", reversed_merkle_root)) print("%s %s" % ("Timestamp hex little endian:", reversed_time_hex)) print("%s %s" % ("Difficulty hex little endian:", reversed_diff_bits)) print("%s %s" % ("Nonce hex little endian:", reversed_nonce_hex)) header_str = ( reversed_version_hex + reversed_prev_block_hash + reversed_merkle_root + reversed_time_hex + reversed_diff_bits + reversed_nonce_hex ) header_bytes = header_str.decode('hex') block_hash_bytes_le = Hash(header_bytes) computed_block_hash = b2lx(block_hash_bytes_le) print("%s %s" % ("\nComputed block hash:", computed_block_hash)) if computed_block_hash == block_hash: print("Block's hash is valid!") else: print("Block's hash is not valid!") print("%s %s" % ("Expected:", computed_block_hash)) print("%s %s" % ("Actual:", block_hash)) print("")
def hex_hash(self): # bytes to little-endian hex return b2lx(Hash(self.native().serialize()))
def txid(self): return Hash(self.serialize())