def calculate_tx_fees(coins, currency, tx_hex): #Process source TX. rpc = coins[currency]["rpc"]["sock"] tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) #Tally input coins. input_total = decimal.Decimal(0) for vin in tx.vin: txid = b2lx(vin.prevout.hash) vin_tx_hex = rpc.getrawtransaction(txid) vin_tx = CTransaction.deserialize(binascii.unhexlify(vin_tx_hex)) input_value = vin_tx.vout[vin.prevout.n].nValue input_total += decimal.Decimal(str_money_value(input_value)) #Tally output coins. output_total = decimal.Decimal(0) for vout in tx.vout: output_value = decimal.Decimal(str_money_value(vout.nValue)) output_total += output_value #TX fees are the difference between the source and fees = input_total - output_total #Return totals and fees. return [input_total, output_total, fees]
def getrawtransaction(self, txid, verbose=False): """Return transaction with hash txid Raises IndexError if transaction not found. verbose - If true a dict is returned instead with additional information on the transaction. Note that if all txouts are spent and the transaction index is not enabled the transaction may not be available. """ try: r = self._call("getrawtransaction", b2lx(txid), 1 if verbose else 0) except JSONRPCError as ex: raise IndexError( "%s.getrawtransaction(): %s (%d)" % (self.__class__.__name__, ex.error["message"], ex.error["code"]) ) if verbose: r["tx"] = CTransaction.deserialize(unhexlify(r["hex"])) del r["hex"] del r["txid"] del r["version"] del r["locktime"] del r["vin"] del r["vout"] r["blockhash"] = lx(r["blockhash"]) if "blockhash" in r else None else: r = CTransaction.deserialize(unhexlify(r)) return r
def getrawtransaction(self, txid, verbose=False): """Return transaction with hash txid Raises IndexError if transaction not found. verbse - If true a dict is returned instead with additional information on the transaction. Note that if all txouts are spent and the transaction index is not enabled the transaction may not be available. """ try: r = self._call('getrawtransaction', b2lx(txid), 1 if verbose else 0) except JSONRPCException as ex: raise IndexError('%s.getrawtransaction(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) if verbose: r['tx'] = CTransaction.deserialize(unhexlify(r['hex'])) del r['hex'] del r['txid'] del r['version'] del r['locktime'] del r['vin'] del r['vout'] r['blockhash'] = lx(r['blockhash']) if 'blockhash' in r else None else: r = CTransaction.deserialize(unhexlify(r)) return r
def withdrawfromvault(self, fromvaultaddress, toaddress, amount): vault = self.getvault(fromvaultaddress) received = self.chaindb.listreceivedbyvault(fromvaultaddress) received = received.values()[0] if received['value'] < amount + 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = 2 * utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees account = self.getaccount() changeaddress = fromvaultaddress self.logger.debug("Change address: %s" % changeaddress) change_txout.scriptPubKey = \ utils.vault_address_to_pay_to_vault_script(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_WITHDRAW) + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return tx
def overridevaulttx(self, fromvaultaddress, toaddress): vault = self.getvault(fromvaultaddress) # select the input addresses received = self.chaindb.listallreceivedbyvault(fromvaultaddress) if not received: self.logger.warning("Empty vault, exiting, return") return None, None received = received.values()[0] if received['value'] < 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return None, None # calculate remaining amount amount = received['value'] - 2 * utils.calculate_fees(None) # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) # get the script vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_OVERRIDE) + chr(len(vault['master_public_key'])) + \ vault['master_public_key'] + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return amount, tx
def as_tx(self): sum_in = sum(prevtx.nValue for _,prevtx,_ in self.prevouts) sig_size = sum(redeemer.spendbytes for _,_,redeemer in self.prevouts) tx_size = (4 + # version field 2 + # # of txins len(self.prevouts) * 41 + # txins, excluding sigs sig_size + # txins, sigs only 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(self.proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size * feerate / 1000) tx = CMutableTransaction( [CTxIn(outpoint, nSequence=0) for outpoint,_,_ in self.prevouts], [CTxOut(sum_in - fees, self.payto.to_scriptPubKey())], 0) for n,(_,_,redeemer) in enumerate(self.prevouts): redeemer.mutate_spend(tx, n) unsigned_tx = CTransaction.from_tx(tx) for n,(_,_,redeemer) in enumerate(self.prevouts): txin = CMutableTxIn.from_txin(tx.vin[n]) txin.scriptSig = redeemer.sign_spend(unsigned_tx, n) tx.vin[n] = CTxIn.from_txin(txin) print(b2x(tx.serialize()))
def check_refund_works(self, tx_hex, owner_first_sig, owner_second_sig, recipient_sig, actor): global error_log_path try: tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) redeem_script = bond_redeem_script(self.ecdsa_us, self.ecdsa_them, self.factory.ecdsa_arbiters[0], actor) redeem_script_hash160 = hash160_script(redeem_script) print(tx_hex) print(redeem_script) tx.vin[0].scriptSig = CScript([OP_0, owner_first_sig, owner_second_sig, recipient_sig, redeem_script["bin"]]) p2sh_script_pub_key = CScript([OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) print(redeem_script_hash160) VerifyScript(tx.vin[0].scriptSig, p2sh_script_pub_key, tx, 0, (SCRIPT_VERIFY_P2SH,)) signed_tx_hex = b2x(tx.serialize()) return { "tx_hex": signed_tx_hex, "txid": calculate_txid(signed_tx_hex) } except Exception as e: error = parse_exception(e) log_exception(error_log_path, error) print(error) print("Check refund failed.") return None
def provide_transaction(self, transaction_data): self.send_lock.acquire() if self.send_transaction_cache.contains(transaction_data): self.send_lock.release() return if len(transaction_data) > self.MAX_RELAY_TRANSACTION_BYTES and (len(transaction_data) > self.MAX_RELAY_OVERSIZE_TRANSACTION_BYTES or self.send_transaction_cache.get_flag_count() >= MAX_EXTRA_OVERSIZE_TRANSACTIONS): self.send_lock.release() return try: relay_data = pack('>3I', self.MAGIC_BYTES, self.TRANSACTION_TYPE, len(transaction_data)) relay_data += transaction_data self.relay_sock.sendall(relay_data) self.send_transaction_cache.add(transaction_data, len(transaction_data) > self.MAX_RELAY_OVERSIZE_TRANSACTION_BYTES) if deserialize_utils: transaction = CTransaction.deserialize(transaction_data) print("Sent transaction " + str(b2lx(transaction.GetHash())) + " of size " + str(len(transaction_data))) else: print("Sent transaction of size " + str(len(transaction_data))) except (OSError, socket.error) as err: print("Failed to send to relay node: ", err) self.send_lock.release()
def cmd_mkwitness(args): tx = None if args.tx is not None: serialized_tx = args.tx tx = CTransaction.deserialize(serialized_tx) else: tx = args.proxy.getrawtransaction(args.txid) txproof = TxProof(tx=tx) for seal_fd in args.seal_fds: seal = BitcoinSingleUseSeal.deserialize(seal_fd.read()) txinproof = None txoutproof = None for i, txin in enumerate(txproof.tx.vin): if txin.prevout == seal.outpoint: txinproof = TxInProof(i=i, txproof=txproof) txoutproof = TxOutProof(i=0, txproof=txproof) break else: args.parser.error("Seal '%s' not closed by this transaction" % seal_fd.name) witness = BitcoinSealWitness(seal=seal, txinproof=txinproof, txoutproof=txoutproof) witness_filename = seal_fd.name + '.witness' logging.info("Creating witness file '%s'" % witness_filename) with open(seal_fd.name + '.witness', 'xb') as witness_fd: witness_fd.write(witness.serialize())
class msg_tx(MsgSerializable): command = b"tx" def __init__(self, protover=PROTO_VERSION): super(msg_tx, self).__init__(protover) self.tx = CTransaction() @classmethod def msg_deser(cls, f, protover=PROTO_VERSION): c = cls() c.tx = CTransaction.stream_deserialize(f) return c def msg_ser(self, f): self.tx.stream_serialize(f) def __repr__(self): return "msg_tx(tx=%s)" % (repr(self.tx))
def createrawtransaction(self, *args): """Get rawtransactions when provided vin and vout FIXME: Implement options and accept outpoints instead of user args """ r = self._call('createrawtransaction', *args) r = str(r) tx = CTransaction.deserialize(unhexlify(r)) return tx
def signrawtransaction(self, tx, *args): """Sign inputs for transaction FIXME: implement options """ hextx = hexlify(tx.serialize()) r = self._call('signrawtransaction', hextx, *args) r['tx'] = CTransaction.deserialize(unhexlify(r['hex'])) del r['hex'] return r
def sign_refund_tx(self, tx_hex, key_no=1, actor="us"): key_no -= 1 if key_no == 0: ecdsa = self.ecdsa_us[0] if key_no == 1: ecdsa = self.ecdsa_us[1] tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) sighash = SignatureHash(bond_redeem_script(self.ecdsa_us, self.ecdsa_them, self.factory.ecdsa_arbiters[0], actor)["bin"], tx, 0, SIGHASH_ALL) seckey = CBitcoinSecret.from_secret_bytes(ecdsa.get_private_key("bin"), compressed=True) sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) return sig
def mutate_tx(tx_hex): """ Mutates a raw transaction using TX malleability in the scriptSig (specifically, the OP codes.) This function shouldn't be used beyond testing as it uses an ugly eval() hack. https://en.bitcoin.it/wiki/Transaction_Malleability """ tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) script_sig = repr(tx.vin[0].scriptSig)[9:] script_sig = eval("CScript([OP_1, OP_DROP, " + script_sig) tx.vin[0].scriptSig = script_sig return b2x(tx.serialize())
def __init__(self, nVersion=2, hashPrevBlock=b'\x00'*32, hashMerkleRoot=b'\x00'*32, nTime=0, nBits=0, nNonce=0, auxpow=None, vtx=()): """Create a new block""" super(CAltcoinBlock, self).__init__(nVersion, hashPrevBlock, hashMerkleRoot, nTime, nBits, nNonce, auxpow) vMerkleTree = tuple(bitcoin.core.CBlock.build_merkle_tree_from_txs(vtx)) object.__setattr__(self, 'vMerkleTree', vMerkleTree) object.__setattr__(self, 'vtx', tuple(CTransaction.from_tx(tx) for tx in vtx))
def set_tx(self): """Set the spending transaction and (en|dis)able the input index box.""" txt = str(self.tx_edit.toPlainText()) if not txt: self.tx = None self.input_idx.setEnabled(False) self.tx_edit.setToolTip('') return self.tx = CTransaction.deserialize(txt.decode('hex')) self.tx_edit.setToolTip(''.join(['Tx ID: ', bitcoin.core.b2lx(self.tx.GetHash())])) self.input_idx.setRange(0, len(self.tx.vin) - 1) self.input_idx.setEnabled(True)
def signrawtransaction(self, tx, *args): """Sign inputs for transaction FIXME: implement options """ if getattr(tx, "serialize", None) is not None: hextx = hexlify(tx.serialize()) else: # then assume we got a raw string already hextx = tx r = self._call('signrawtransaction', hextx, *args) r['tx'] = CTransaction.deserialize(unhexlify(r['hex'])) del r['hex'] return r
def sign_setup_tx(tx_hex, redeem_script, ecdsa): tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) sighash = SignatureHash(redeem_script["bin"], tx, 0, SIGHASH_ALL) print(b"Signing = " + sighash) print(ecdsa.get_public_key()) seckey = CBitcoinSecret.from_secret_bytes(ecdsa.get_private_key("bin"), compressed=True) sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) print(b"Pub key = " + ecdsa.get_public_key("bin")) print(b"Sig = " + sig) print() return sig
def recover_command(args): args.fee_per_kb = int(args.fee_per_kb * COIN) addr = CBitcoinAddress(args.addr) tx = CTransaction() sum_value_in = 0 dummy_scriptSig = CScript([b'\x00'*74]) inputs = {} for outpoint, txout in tuple(args.wallet.unspent_txouts.items())[0:500]: sum_value_in += txout.nValue tx.vin.append(CTxIn(outpoint, dummy_scriptSig)) inputs[outpoint] = txout tx.vout.append(CTxOut(-1, addr.to_scriptPubKey())) fees = int((len(tx.serialize())/1000) * args.fee_per_kb) tx.vout[0].nValue = sum_value_in - fees # Sign the transaction for (i, txin) in enumerate(tx.vin): prevout_scriptPubKey = inputs[txin.prevout].scriptPubKey sighash = SignatureHash(prevout_scriptPubKey, tx, i, SIGHASH_ALL) seckey = args.wallet.keypairs[prevout_scriptPubKey] sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) if prevout_scriptPubKey[-1] == OP_CHECKMULTISIG: txin.scriptSig = CScript([OP_0, sig]) elif prevout_scriptPubKey[-1] == OP_CHECKSIG and prevout_scriptPubKey[-2] == OP_EQUALVERIFY: txin.scriptSig = CScript([sig, seckey.pub]) VerifyScript(txin.scriptSig, prevout_scriptPubKey, tx, i) print(b2x(tx.serialize()))
def get_utxo(self, address): """Gets all the Unspent Transaction Outs from a given <address> """ script_pubkey = CBitcoinAddress(address).to_scriptPubKey() txs = self.get_response("blockchain.address.get_history", [address]) spent = {} utxos = [] for tx in txs: raw = self.get_raw_transaction(tx["tx_hash"], tx["height"]) data = CTransaction.deserialize(to_binary(raw)) for vin in data.vin: spent[(to_little_endian_hex(vin.prevout.hash), vin.prevout.n)] = 1 for outindex, vout in enumerate(data.vout): if vout.scriptPubKey == script_pubkey: utxos += [(tx["tx_hash"], outindex, vout.nValue, to_hex(vout.scriptPubKey))] return [u for u in utxos if not u[0:2] in spent]
def get_utxo(self, address): script_pubkey = CBitcoinAddress(address).to_scriptPubKey() txs = self.get_response('blockchain.address.get_history', [address]) spent = {} utxos = [] for tx in txs: print tx raw = self.get_raw_transaction(tx['tx_hash'], tx['height']) data = CTransaction.deserialize(to_binary(raw)) for vin in data.vin: spent[(to_little_endian_hex(vin.prevout.hash), vin.prevout.n)] = 1 for outindex, vout in enumerate(data.vout): if vout.scriptPubKey == script_pubkey: utxos += [(tx['tx_hash'], outindex, vout.nValue, to_hex(vout.scriptPubKey))] return [u for u in utxos if not u[0:2] in spent]
def deserialize(self): self.clear() txt = str(self.raw_tx_edit.toPlainText()) try: txt = txt.decode('hex') except Exception: self.status_message('Raw transaction must be hex.', True) return try: self.tx = tx = CTransaction.deserialize(txt) except Exception: self.status_message('Cannot deserialize transaction.', True) return self.tx_widget.set_tx(tx) self.status_message('Deserialized transaction {}'.format(bitcoin.core.b2lx(tx.GetHash())))
def spend_preimage(redeem_script, preimages, redeemer_sig, serial_tx): """ Creates a transaction fulfilling the redeem script of the preimage P2SH. Arguements: redeem_script (bytes): The script that specifies the conditions that a tx has to fulfill to transfer funds from the `funding_tx` preimages (list): The preimages that hash into the hash values specified in the `redeem_script` redeemer_sig (bytes): The signature of the redeemer on the `serial_tx` serial_tx (bytes): The serial transaction Returns: The serial raw transaction that passes the script verification """ # 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 + [redeem_script]) # Verify script redeem_script = CScript(redeem_script) try: VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) except ValidationError: print("spend_preimage: Script failed to verify") return None serial_tx = tx.serialize() txid = b2lx(Hash(serial_tx)) print("spend_preimage: TXID is %s" % txid) print("spend_preimage: RAW TX is %s" % b2x(serial_tx)) return serial_tx
def test_path_from_msg_to_txid(self): def T(msg, tx): path = path_from_msg_to_txid(msg, tx) self.assertEqual(path(msg), tx.GetHash()) tx = CTransaction.deserialize(x('0100000001e853c9e0c133547fd9e162b1d3860dd0f27d5b9b8a7430d28896c00fbb3f1bc7000000008c49304602210095bcd54ebd0caa7cee75f0f89de472a765e6ef4b98c5fd4b32c7f9d4905db9ae022100ebd3f668e3a1a36d56e30184c27531dbb9fc136c84b1282be562064d86997d1e014104727eb4fdcc90658cd26abe7dcb0ae7297810b15b9e27c32bcf8e3edd934901968806dc18b1276d7273cc4c223feee0070361ed947888a3cef422bebfede96e08ffffffff020065cd1d000000001976a91468c6c2b3c0bc4a8eeb10d16a300d627a31a3b58588ac0008af2f000000001976a9141d87f0a54a1d704ffc70eae83b025698bc0fdcfc88ac00000000')) # txid in vin T(lx('c71b3fbb0fc09688d230748a9b5b7df2d00d86d3b162e1d97f5433c1e0c953e8'), tx) # part of a script T(x('1d87f0a54a1d704ffc70eae83b025698bc0fdcfc'), tx) # beginning of the tx T(x('0100000001e853c9e0c133547fd9'), tx) # end of the tx T(x('98bc0fdcfc88ac00000000'), tx)
def spend_escrow(redeem_script, payer_sig, redeemer_sig, serial_tx): """ Creates a transaction fulfilling the redeem script of the escrow P2SH. Arguements: redeem_script (bytes): The script that specifies the conditions that a tx has to fulfill to transfer funds from the `funding_tx` payer_sig (bytes): The signature of the payer on the `serial_tx` redeemer_sig (bytes): The signature of the redeemer on the `serial_tx` serial_tx (bytes): The serial transaction Returns: The serial raw transaction that passes the script verification """ # 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_0, payer_sig + '\x01', redeemer_sig + '\x01', redeem_script]) # Verify script redeem_script = CScript(redeem_script) serial_tx = tx.serialize() try: VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) except ValidationError: print("spend_escrow: Script failed to verify") return None serial_tx = tx.serialize() txid = b2lx(Hash(serial_tx)) print("spend_escrow: TXID is %s" % txid) print("spend_escrow: RAW TX is %s" % b2x(serial_tx)) return serial_tx
def broadcast_tx(self, tx): """ Sends the tx to half our peers and waits for half of the remainder to announce it via inv packets before calling back. """ def on_peer_anncounce(txid): self.subscriptions[txhash]["announced"] += 1 if self.subscriptions[txhash]["announced"] >= self.subscriptions[txhash]["ann_threshold"]: if self.subscriptions[txid]["timeout"].active(): self.subscriptions[txid]["timeout"].cancel() self.subscriptions[txid]["deferred"].callback(True) d = defer.Deferred() transaction = CTransaction.stream_deserialize(BytesIO(unhexlify(tx))) txhash = transaction.GetHash() self.inventory[txhash] = transaction cinv = CInv() cinv.type = 1 cinv.hash = txhash inv_packet = msg_inv() inv_packet.inv.append(cinv) self.bloom_filter.insert(txhash) self.subscriptions[txhash] = { "announced": 0, "ann_threshold": len(self.peers)/4, "callback": on_peer_anncounce, "confirmations": 0, "in_blocks": [], "deferred": d, "timeout": reactor.callLater(10, d.callback, False) } for peer in self.peers[len(self.peers)/2:]: peer.protocol.load_filter() for peer in self.peers[:len(self.peers)/2]: peer.protocol.send_message(inv_packet) return d
def test_is_coinbase(self): tx = CTransaction() self.assertFalse(tx.is_coinbase()) tx.vin.append(CTxIn()) # IsCoinBase() in reference client doesn't check if vout is empty self.assertTrue(tx.is_coinbase()) tx.vin[0].prevout.n = 0 self.assertFalse(tx.is_coinbase()) tx.vin[0] = CTxIn() tx.vin.append(CTxIn()) self.assertFalse(tx.is_coinbase())
def load_test_vectors(name): with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: for test_case in json.load(fd): # Comments designated by single length strings if len(test_case) == 1: continue assert len(test_case) == 3 prevouts = {} for json_prevout in test_case[0]: assert len(json_prevout) == 3 n = json_prevout[1] if n == -1: n = 0xffffffff prevout = COutPoint(lx(json_prevout[0]), n) prevouts[prevout] = parse_script(json_prevout[2]) tx = CTransaction.deserialize(x(test_case[1])) enforceP2SH = test_case[2] yield (prevouts, tx, enforceP2SH)
def SignatureHash(script, txTo, inIdx, hashtype): if inIdx >= len(txTo.vin): return (0, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) txtmp = CTransaction() txtmp.copy(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = script.vch if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): return (0, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = Hash(s) return (hash,)
def fundrawtransaction(self, tx, include_watching=False): """Add inputs to a transaction until it has enough in value to meet its out value. include_watching - Also select inputs which are watch only Returns dict: {'tx': Resulting tx, 'fee': Fee the resulting transaction pays, 'changepos': Position of added change output, or -1, } """ hextx = hexlify(tx.serialize()) r = self._call('fundrawtransaction', hextx, include_watching) r['tx'] = CTransaction.deserialize(unhexlify(r['hex'])) del r['hex'] r['fee'] = int(r['fee'] * COIN) return r
def check_setup_works(tx_hex, redeem_script, owner_first_sig, owner_second_sig, third_party_sig): try: tx = CTransaction.deserialize(binascii.unhexlify(tx_hex)) redeem_script_hash160 = hash160_script(redeem_script) if owner_first_sig != None and owner_second_sig != None and third_party_sig != None: tx.vin[0].scriptSig = CScript([OP_0, owner_first_sig, owner_second_sig, third_party_sig, redeem_script["bin"]]) p2sh_script_pub_key = CScript([OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) VerifyScript(tx.vin[0].scriptSig, p2sh_script_pub_key, tx, 0, (SCRIPT_VERIFY_P2SH,)) signed_tx_hex = b2x(tx.serialize()) return { "tx_hex": signed_tx_hex, "txid": calculate_txid(signed_tx_hex) } except Exception as e: error = parse_exception(e) log_exception(error_log_path, error) print(error) print("Check setup works failed.") print(e) return None
def deserialize_raw_transaction(raw_transaction: str) -> CTransaction: ''' Checking if transaction can be deserialized (is not corrupted). Args: raw_transaction (str): transaction to check Returns: CTransaction: transaction object Raises: ImpossibleDeserialization: when transaction is corrupted Example: >>> from clove.network import Litecoin >>> network = Litecoin() >>> network.deserialize_raw_transaction('0100000001aa25fd5f63cb41d6ee7dd495256046b4c3f17d4540a1b258a06bfefac30da60900000000fdff0047304402201c8869d359b5599ecffd51a96f0a8799392c98c4e15242762ba455e37b1f5d6302203f2974e9afc8d641f9363167df48e5a845a8deba1381bf5a1b549ac04718a1ac01410459cdb91eb7298bc2578dc4e7ac2109ac3cfd9dc9818795c5583e720d2114d540724bf26b4541f683ff51968db627a04eecd1f5cff615b6350dad5fb595f8adf420c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9514c5163a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac00000000015a7b0100000000001976a91485c0522f6e23beb11cc3d066cd20ed732648a4e688ac00000000') # noqa: E501 CTransaction((CTxIn(COutPoint(lx('09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa'), 0), CScript([x('304402201c8869d359b5599ecffd51a96f0a8799392c98c4e15242762ba455e37b1f5d6302203f2974e9afc8d641f9363167df48e5a845a8deba1381bf5a1b549ac04718a1ac01'), x('0459cdb91eb7298bc2578dc4e7ac2109ac3cfd9dc9818795c5583e720d2114d540724bf26b4541f683ff51968db627a04eecd1f5cff615b6350dad5fb595f8adf4'), x('c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9'), 1, x('63a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac')]), 0x0),), (CTxOut(0.00097114*COIN, CScript([OP_DUP, OP_HASH160, x('85c0522f6e23beb11cc3d066cd20ed732648a4e6'), OP_EQUALVERIFY, OP_CHECKSIG])),), 0, 1, CTxWitness()) # noqa: E501 ''' try: return CTransaction.deserialize(x(raw_transaction)) except Exception: raise ImpossibleDeserialization()
def add_input(self, serial_id: int, prevtx: str, prevtx_vout: int, max_witness_len: int, script: str, sequence: int, privkey: str = None) -> None: # Find the txid of the transaction prev_tx = CTransaction.deserialize(bytes.fromhex(prevtx)) txin = CTxIn(COutPoint(prev_tx.GetTxid(), prevtx_vout), nSequence=sequence) # Get the previous output for its outscript + value prev_vout = prev_tx.vout[prevtx_vout] self.inputs.append({'input': txin, 'serial_id': serial_id, 'sats': prev_vout.nValue, 'prev_outscript': prev_vout.scriptPubKey.hex(), 'redeemscript': script, 'max_witness_len': max_witness_len, 'privkey': privkey, })
def sendtoaddress(self, toaddress, amount): # select the input addresses funds = 0 subaccounts = [] accounts = self.getaccounts() for account in accounts: for address, subaccount in account.iteritems(): if subaccount['balance'] == 0: continue else: subaccounts.append(subaccount) # print "got one subaccount", subaccount # print "subaccounts: ", subaccounts funds = funds + subaccount['balance'] if funds >= amount + utils.calculate_fees(None): break # print "subaccounts 2: ", subaccounts # incase of insufficient funds, return if funds < amount + utils.calculate_fees(None): print "In sufficient funds, exiting, return" return # create transaction tx = CTransaction() # print "subaccounts 3: ", subaccounts # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount public_keys = [] private_keys = [] # secrets = [] # print "subaccounts 4: ", subaccounts for subaccount in subaccounts: # print "subaccount: ", subaccount # get received by from address previous_txouts = subaccount['received'] # print "Previous txouts", previous_txouts for received in previous_txouts: txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = binascii.unhexlify(received['scriptPubKey']) tx.vin.append(txin) nValueIn = nValueIn + received['value'] public_keys.append(subaccount['public_key']) private_keys.append(subaccount['private_key']) # secrets.append(subaccount['secret']) if nValueIn >= amount + utils.calculate_fees(tx): break if nValueIn >= amount + utils.calculate_fees(tx): break # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees changeaddress = subaccounts[0]['address'] change_txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) # sign the transaction for public_key, private_key, txin in zip(public_keys, private_keys, tx.vin): key = CKey() key.set_pubkey(public_key) key.set_privkey(private_key) signature = key.sign(txhash) # scriptSig = chr(len(signature)) + hash_type + signature + chr(len(public_key)) + public_key scriptSig = chr(len(signature)) + signature + chr(len(public_key)) + public_key print "Adding signature: ", binascii.hexlify(scriptSig) txin.scriptSig = scriptSig print "Tx Validity: ", tx.is_valid() return tx