def is_valid_addr(address: str, token_name: str) -> bool: try: if token_name == 'HTDF': return len(address) == 43 and address.startswith('htdf1') and address.islower() elif token_name == 'ETH' or token_name == 'USDT': return len(address) == 42 and address.startswith('0x') and int(address, base=16) elif token_name == 'BTC': if g_IS_MAINNET: SelectParams('mainnet') addr = CBitcoinAddress(s = address) else: SelectParams('testnet') addr = CBitcoinAddress(s = address) assert addr is not None , 'addr is None' #如果没有抛异常直接返回即可 return True else: raise RuntimeError(f"unknow token_name: {token_name}") except Exception as e: logger.error(f'is_valid_addr() , {address} is invalid address, error:{e}') return False pass
def test_emergency_txout(bitcoind): """Test mostly the emergency tx locktime""" amount = Decimal("50") - Decimal("500") / Decimal(COIN) privkeys = [CKey(os.urandom(32)) for _ in range(4)] pubkeys = [k.pub for k in privkeys] txo = emergency_txout(pubkeys, COIN * amount) addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) # This makes a transaction with only one vout txid = bitcoind.pay_to(addr, amount) new_amount = amount - Decimal("500") / Decimal(COIN) addr = bitcoind.getnewaddress() txin = CTxIn(COutPoint(lx(txid), 0), nSequence=4464) txout = CTxOut(new_amount * COIN, CBitcoinAddress(addr).to_scriptPubKey()) tx = CMutableTransaction([txin], [txout], nVersion=2) tx_hash = SignatureHash(emergency_script(pubkeys), tx, 0, SIGHASH_ALL, int(amount * COIN), SIGVERSION_WITNESS_V0) sigs = [k.sign(tx_hash) + bytes([SIGHASH_ALL]) for k in privkeys] witness_script = [bytes(0), *sigs, emergency_script(pubkeys)] tx.wit = CTxWitness([CTxInWitness(CScriptWitness(witness_script))]) # 1 month of locktime bitcoind.generate_block(4464 - 2) with pytest.raises(VerifyRejectedError, match="non-BIP68-final"): bitcoind.send_tx(tx.serialize().hex()) bitcoind.generate_block(1) bitcoind.send_tx(tx.serialize().hex()) assert bitcoind.has_utxo(addr)
def partial_spend_p2sh_mediator(redeemScript, rein, mediator_address, mediator_sig=False): txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet) if len(txins) == 0: raise ValueError('No unspent txins found') txins_str = "" txins_obj = [] for txid, vout in txins: txins_str += " " + txid + "-" + str(vout) txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout))) fee = 0.00025 amount = round(total_value - fee, 8) if amount <= 0: raise ValueError('Not enough value in the inputs') if mediator_sig: txout = CMutableTxOut( amount * COIN, CBitcoinAddress(mediator_address).to_scriptPubKey()) tx = CMutableTransaction(txins_obj, [txout]) seckey = CBitcoinSecret(rein.user.dkey) ntxins = len(txins_obj) sig = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig += " " + b2x(seckey.sign(sighash) + x("01")) return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address), sig[1:]) return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address))
def hashtimelockcontract(funder, redeemer, secret, locktime): funderAddr = CBitcoinAddress(funder) redeemerAddr = CBitcoinAddress(redeemer) h = sha256(secret) blocknum = bitcoind.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime print("REDEEMBLOCKNUM BITCOIN", redeemblocknum) redeemScript = CScript([ OP_IF, OP_SHA256, h, OP_EQUALVERIFY, OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG ]) print("Redeem script for p2sh contract on Bitcoin blockchain:", b2x(redeemScript)) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) return { 'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(redeemScript), 'redeemer': redeemer, 'funder': funder }
def hashtimelockcontract(proxy, funder, redeemer, commitment, locktime): funderAddr = CBitcoinAddress('ms6KpXRvUwwygwzgRoANRwgcGskXcnEwAr') redeemerAddr = CBitcoinAddress('mph94e6SCNUPpyZBhBXHdRZyz1f4DDzeJK') if type(commitment) == str: commitment = x(commitment) else: raise ValueError("Commitment was not a string: {0}".format(commitment)) blocknum = proxy.getblockcount() print("Current blocknum on Bitcoin: ", blocknum) redeemblocknum = blocknum + locktime print("Redeemblocknum on Bitcoin: ", redeemblocknum) redeemScript = CScript([ OP_IF, OP_SHA256, commitment, OP_EQUALVERIFY, OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG]) # print("Redeem script for p2sh contract on Bitcoin blockchain: " # "{0}".format(b2x(redeemScript))) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey( txin_scriptPubKey) p2sh = str(txin_p2sh_address) # Import address at same time you create proxy.importaddress(p2sh, "", False) print("p2sh computed", p2sh) return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(redeemScript), 'redeemer': redeemer, 'funder': funder, 'locktime': locktime}
def create_transaction_output(address, transaction_fee): """ Create a single transaction output :param address: :param transaction_fee: :return: """ addr = CBitcoinAddress(address) tx_out = CMutableTxOut(transaction_fee, addr.to_scriptPubKey()) return tx_out
def create_transaction_output(address, transaction_fee): """ Create a single transaction output :param address: :param transaction_fee: :return: """ bitcoin_address = CBitcoinAddress(address) tx_out = CMutableTxOut(transaction_fee, bitcoin_address.to_scriptPubKey()) return tx_out
def create_transaction_output(address, output_value): """ Create a single transaction output :param address: :param output_value: :return: """ bitcoin_address = CBitcoinAddress(address) tx_out = CMutableTxOut(output_value, bitcoin_address.to_scriptPubKey()) return tx_out
def partial_spend_p2sh(redeemScript, rein, daddr=None, alt_amount=None, alt_daddr=None): if daddr is None: daddr = rein.user.daddr txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet) if len(txins) == 0: raise ValueError( 'Primary escrow is empty. Please inform client to add funds.') txins_str = "" txins_obj = [] for txid, vout in txins: txins_str += " " + txid + "-" + str(vout) txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout))) fee = float(PersistConfig.get(rein, 'fee', 0.001)) amount = round(total_value - fee, 8) if alt_amount: amount = round(amount - alt_amount, 8) if amount <= 0. or alt_amount > total_value - fee: click.echo("amount: " + str(amount) + " alt_amount: " + str(alt_amount) + " total_value: " + str(total_value)) raise ValueError( 'Primary escrow balance too low. Please inform client to add funds.' ) txouts = [] txout = CMutableTxOut(amount * COIN, CBitcoinAddress(daddr).to_scriptPubKey()) txouts.append(txout) if alt_amount: txout_alt = CMutableTxOut( round(alt_amount, 8) * COIN, CBitcoinAddress(alt_daddr).to_scriptPubKey()) txouts.append(txout_alt) tx = CMutableTransaction(txins_obj, txouts) ntxins = len(txins_obj) seckey = CBitcoinSecret(rein.user.dkey) sig = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig += " " + b2x(seckey.sign(sighash)) + "01" if alt_amount: return (txins_str[1:], "{:.8f}".format(amount), daddr, "{:.8f}".format(alt_amount), alt_daddr, sig[1:]) return (txins_str[1:], "{:.8f}".format(amount), daddr, sig[1:])
def make_unsigned(cls, outpoints, outputs, tx_fee=TRANSACTION_FEE, testnet=False, out_value=None): """ Build an unsigned transaction. Args: outpoints: A `list` of `dict` objects which contain a txid, vout, value, and scriptPubkey. outputs: If a single address the full value of the inputs (minus the tx fee) will be sent there. Otherwise it should be a `list` of `dict` objects containing address and value. tx_fee: The Bitcoin network fee to be paid on this transaction. testnet: Should this transaction be built for testnet? out_value: used if you want to specify a specific output value otherwise the full value of the inputs (minus the tx fee) will be used. """ # build the inputs from the outpoints object SelectParams("testnet" if testnet else "mainnet") txins = [] in_value = 0 for outpoint in outpoints: in_value += outpoint["value"] txin = CMutableTxIn( COutPoint(lx(outpoint["txid"]), outpoint["vout"])) txin.scriptSig = CScript(x(outpoint["scriptPubKey"])) txins.append(txin) # build the outputs txouts = [] if isinstance(outputs, list): for output in outputs: value = output["value"] address = output["address"] txouts.append( CMutableTxOut(value, CBitcoinAddress(address).to_scriptPubKey())) else: value = out_value if out_value is not None else (in_value - tx_fee) txouts.append( CMutableTxOut(value, CBitcoinAddress(outputs).to_scriptPubKey())) # make the transaction tx = CMutableTransaction(txins, txouts) return BitcoinTransaction(tx)
def find_transaction_to_address(self, p2sh): self.bitcoind.importaddress(p2sh, "", False) txs = self.bitcoind.listunspent() for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): logging.debug("Found tx to p2sh: {0}".format(p2sh)) return tx
def get_coinbase_info(blockheight): '''Gets coinbase tag and addresses of a block with specified height. Returns: addresses - A list of p2sh/p2pkh addresses corresponding to the outputs. Returns None in place of an unrecognizable scriptPubKey. tag - the UTF-8 decoded scriptSig. Raises: Exceptions originating from bitcoin.rpc.Proxy, if there is a problem with JSON-RPC. ''' block = proxy.getblock(proxy.getblockhash(blockheight)) coinbase_tx = block.vtx[0] assert coinbase_tx.is_coinbase() addresses = [] for output in coinbase_tx.vout: try: addr = str(CBitcoinAddress.from_scriptPubKey(output.scriptPubKey)) except (CBitcoinAddressError, ValueError): addr = None else: addr = addr.decode('ascii') addresses.append(addr) tag = str(coinbase_tx.vin[0].scriptSig).decode('utf-8', 'ignore') return addresses, tag
def send_ulogos(request): try: user = request.user address = CBitcoinAddress(request.POST['address']) if not str(address).startswith('1'): return fail(10104, '暂不支持该类型比特币地址领取ULOGOS') signature = request.POST['signature'] if not verify_signature(address, signature): return fail(10099, '签名不正确') except Base58Error: return fail(10098, '比特币地址输入不正确') except Exception as e: logger.error(e) return fail() try: balance = redis_server.get(str(address)) if not balance: return fail(10101, '比特币区块高度478558快照中不存在该地址') balance = Decimal(str(balance)) / 100000000 if balance <= 0: return fail(10102, '比特币地址余额不对') except Exception as e: logger.error(e) return fail(10103, '比特币地址余额获取失败') try: create_ulogos_dispatch(user, str(address), signature, balance) return success(data={'btc': balance, 'ulogos': balance, 'bitcoinlogo': balance}) except Exception as e: logger.error(e) return fail(10100, '您已提交过领币申请,请勿重复提交')
def listunspent(self, minconf=0, maxconf=9999999, addrs=None): """Return unspent transaction outputs in wallet Outputs will have between minconf and maxconf (inclusive) confirmations, optionally filtered to only include txouts paid to addresses in addrs. """ r = None if addrs is None: r = self._call('listunspent', minconf, maxconf) else: addrs = [str(addr) for addr in addrs] r = self._call('listunspent', minconf, maxconf, addrs) r2 = [] for unspent in r: unspent['outpoint'] = COutPoint(lx(unspent['txid']), unspent['vout']) del unspent['txid'] del unspent['vout'] # address isn't always available as Bitcoin Core allows scripts w/o # an address type to be imported into the wallet, e.g. non-p2sh # segwit try: unspent['address'] = CBitcoinAddress(unspent['address']) except KeyError: pass unspent['scriptPubKey'] = CScript( unhexlify(unspent['scriptPubKey'])) unspent['amount'] = int(unspent['amount'] * COIN) r2.append(unspent) return r2
def validateaddress(self, address): """Return information about an address""" r = self._call('validateaddress', str(address)) r['address'] = CBitcoinAddress(r['address']) if 'pubkey' in r: r['pubkey'] = unhexlify(r['pubkey']) return r
def spend_p2sh_mediator(redeemScript, txins_str, amounts, daddrs, sig, rein): txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txins_obj = [] for txin_str in txins_str.split(): txin_list = txin_str.split("-") txins_obj.append( CMutableTxIn(COutPoint(lx(txin_list[0]), int(txin_list[1])))) txouts = [] len_amounts = len(amounts) for i in range(0, len_amounts): txouts.append( CMutableTxOut( round(amounts[i], 8) * COIN, CBitcoinAddress(daddrs[i]).to_scriptPubKey())) tx = CMutableTransaction(txins_obj, txouts) seckey = CBitcoinSecret(rein.user.dkey) ntxins = len(txins_obj) sig_list = [] for s in sig.split(): sig_list.append(x(s)) sig2_str = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig2 = seckey.sign(sighash) + x("01") sig2_str += " " + b2x(sig2) txins_obj[i].scriptSig = CScript( [OP_0, sig2, sig_list[i], txin_redeemScript]) VerifyScript(txins_obj[i].scriptSig, txin_scriptPubKey, tx, i, (SCRIPT_VERIFY_P2SH, )) tx_bytes = tx.serialize() hash = sha256(sha256(tx_bytes).digest()).digest() txid = b2x(hash[::-1]) txid_causeway = broadcast_tx(b2x(tx_bytes), rein) return (txid, sig2_str[1:])
def build_bounce_tx(self, txid_hex): #Generate p2sh script pub key. redeem_script = self.fund_redeem_script(self.my) redeem_script_hash160 = self.hash160_script(redeem_script) txin_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Generate address to receive bounce. if "bounce" not in self.key_pairs: self.key_pairs["bounce"] = self.key_pair_from_address( self.jsonrpc[self.my].getnewaddress(), self.my) #Setup tx inputs and outputs. txid = lx(txid_hex) vout = 0 txin = CTxIn(COutPoint(txid, vout), CScript(), 0) #Sequence number 0. txout = CTxOut( (self.send_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, CBitcoinAddress( self.key_pairs["bounce"]["addr"]["base58"]).to_scriptPubKey()) #Locktime is unsigned int 4, unix timestamp in little endian format. #(Conversion to little endian is handled by the library already.) nlock_time = datetime.datetime.now() + datetime.timedelta( seconds=self.future_minutes * 60) nlock_time = int(nlock_time.strftime("%s")) #Create unsigned transaction. tx = CTransaction([txin], [txout], nlock_time) return b2x(tx.serialize())
def test_vault_txout(bitcoind): """Test that vault_txout() produces a valid output.""" amount = Decimal("50") - Decimal("500") / Decimal(COIN) addresses = [bitcoind.rpc.getnewaddress() for i in range(4)] pubkeys = [bytes.fromhex(bitcoind.rpc.getaddressinfo(addr)["pubkey"]) for addr in addresses] privkeys = [bitcoind.rpc.dumpprivkey(addr) for addr in addresses] txo = vault_txout(pubkeys, COIN * amount) addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) # This makes a transaction with only one vout txid = bitcoind.pay_to(addr, amount) new_amount = amount - Decimal("500") / Decimal(COIN) addr = bitcoind.getnewaddress() tx = bitcoind.rpc.createrawtransaction([{"txid": txid, "vout": 0}], [{addr: float(new_amount)}]) tx = bitcoind.rpc.signrawtransactionwithkey(tx, privkeys, [ { "txid": txid, "vout": 0, # no change output "scriptPubKey": b2x(txo.scriptPubKey), "witnessScript": b2x(vault_script(pubkeys)), "amount": str(amount) } ]) bitcoind.send_tx(tx["hex"]) assert bitcoind.has_utxo(addr)
def find_transaction_to_address(self, p2sh): self.bitcoind.importaddress(p2sh, "", False) txs = self.bitcoind.listunspent() for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): print("Found tx to p2sh", p2sh) return tx
def getrawchangeaddress(self): """Returns a new Bitcoin address, for receiving change. This is for use with raw transactions, NOT normal use. """ r = self._call('getrawchangeaddress') return CBitcoinAddress(r)
def _validate_output(self, output: Dict) -> None: if 'address' not in output: raise InvalidSignatureRequest("no address in output") if not isinstance(output['address'], (str, )): err_msg = "output addresses must be base58-encoded strings" raise InvalidSignatureRequest(err_msg) if output['address'][:2] in ('bc', 'tb'): err_msg = "bech32 addresses are unsupported (output)" raise InvalidSignatureRequest(err_msg) try: base58.CBase58Data(output['address']) except base58.InvalidBase58Error: err_msg = "output addresses must be base58-encoded strings" raise InvalidSignatureRequest(err_msg) except base58.Base58ChecksumError: err_msg = "invalid output address checksum" raise InvalidSignatureRequest(err_msg) try: CBitcoinAddress(output['address']) except CBitcoinAddressError: err_msg = "invalid output address (check mainnet vs. testnet)" raise InvalidSignatureRequest(err_msg) if 'amount' not in output: raise InvalidSignatureRequest("no amount in output") if type(output['amount']) != int: err_msg = "output amount must be an integer (satoshis)" raise InvalidSignatureRequest(err_msg) if output['amount'] <= 0: raise InvalidSignatureRequest("invalid output amount")
def creates_add_input(bitcoind, tx): """Creates and add an input to a CMutableTransaction, SIGHASH_ALL. :returns: The txid of the first stage fee bumping tx (for convenience) """ # First we get some coins privkey = CKey(os.urandom(32)) scriptPubKey = CScript([OP_0, Hash160(privkey.pub)]) address = CBitcoinAddress.from_scriptPubKey(scriptPubKey) # Let's say we want to increase the fees by 5000 sats amount = 5000 # Bitcoind is nice and will create the first stage transaction first_txid = bitcoind.rpc.sendtoaddress(str(address), amount / COIN) vout_index = get_output_index( bitcoind.rpc.getrawtransaction(first_txid, 1), amount) # === We don't generate a block yet ! === tx.vin.append( CTxIn(COutPoint(lx(first_txid), vout_index), nSequence=0xfffffffe)) # Sign the new input with ALL tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0) sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL]) tx.wit.vtxinwit.append(CTxInWitness(CScriptWitness([sig, privkey.pub]))) return first_txid
def listunspent(self, minconf=0, maxconf=9999999, addrs=None): """Return unspent transaction outputs in wallet Outputs will have between minconf and maxconf (inclusive) confirmations, optionally filtered to only include txouts paid to addresses in addrs. """ r = None if addrs is None: r = self._call('listunspent', minconf, maxconf) else: addrs = [str(addr) for addr in addrs] r = self._call('listunspent', minconf, maxconf, addrs) r2 = [] for unspent in r: unspent['outpoint'] = COutPoint(lx(unspent['txid']), unspent['vout']) del unspent['txid'] del unspent['vout'] unspent['address'] = CBitcoinAddress(unspent['address']) unspent['scriptPubKey'] = CScript(unhexlify(unspent['scriptPubKey'])) unspent['amount'] = int(unspent['amount'] * COIN) r2.append(unspent) return r2
def is_valid_address(cls, address: str) -> bool: try: CBitcoinAddress(address) except (CBitcoinAddressError, Base58ChecksumError, InvalidBase58Error): return False return True
def spend_command(args): args.addr = CBitcoinAddress(args.addr) redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy() prevouts = [] for prevout in args.prevouts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: args.parser.error('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: args.parser.error('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: args.parser.error('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, prevout in prevouts], [CTxOut(sum_in - fees, args.addr.to_scriptPubKey())], args.nLockTime) signed_tx = CTransaction([ CTxIn(txin.prevout, spend_hodl_redeemScript(args.privkey, args.nLockTime, unsigned_tx, i), nSequence=0) for i, txin in enumerate(unsigned_tx.vin) ], unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
def collect_transactions(): blockchain = Blockchain() count = blockchain.get_block_count() start = Info.objects.get(id=1) logger.info('Blockchain count: %d' % count) logger.info('Fetching blocks from %d' % (start.height + 1)) for height in range(start.height + 1, count + 1): block = blockchain.get_block_by_height(height) for tx in block.vtx: txid = b2lx(tx.GetTxid()) txsrlzr = BaseTransactionSerializer(data={ 'id': txid, 'vin': [], 'vout': [] }) if txsrlzr.is_valid(): newtx = txsrlzr.save() else: newtx = Transaction.objects.get(id=txid) for v in tx.vin: newtx.vin = [] if not v.prevout.is_null(): t = Transaction.objects.get(id=b2lx(v.prevout.hash)) coin_id = t.vout[v.prevout.n] newtx.vin.append(coin_id) coin = Coin.objects.get(id=coin_id) coin.spendable = False coin.frozen = False coin.save() for i, v in enumerate(tx.vout): newtx.vout = [] if v.nValue > 0: data = { 'txid': txid, 'vout': i, 'owner': str(CBitcoinAddress.from_scriptPubKey(v.scriptPubKey)), 'value': v.nValue, 'height': height, 'spendable': True, 'frozen': False, } serializer = BaseCoinSerializer(data=data) if serializer.is_valid(): coin = serializer.save() else: coin = Coin.objects.get(txid=data['txid'], vout=i) newtx.vout.append(coin.id) # else: # print(blockchain.get_data_from_vout(v)) newtx.save() start.height = count start.save() logger.info('Successfully loaded all transactions.')
def create_transaction_output(output_): """ transform the transaction output into hex code :param output__: unsigned transaction output :return: output formatted as transaction hex code """ return CMutableTxOut(output_['value'], CBitcoinAddress(output_['address']).to_scriptPubKey())
def addr_from_script(script): """Generate output addres from scriptPubKey""" try: addr = str(CBitcoinAddress.from_scriptPubKey(script)) except CBitcoinAddressError: addr = None return addr
def validateaddress(self, address): """Return information about an address""" r = self._call('validateaddress', str(address)) if r['isvalid']: r['address'] = CBitcoinAddress(r['address']) if 'scriptPubKey' in r: r['scriptPubKey'] = unhexlify(r['scriptPubKey']) return r
def do(self, args): genesis_outpoints = {} genesis_scriptPubKeys = set() for str_outpoint, str_qty in args.genesis_outpoints: outpoint = ParseCOutPointArg.str_to_COutPoint( str_outpoint, args.parser) qty = int(str_qty) if outpoint in genesis_outpoints: args.parser.exit('dup outpoint %r' % outpoint) logging.debug('Genesis outpoint: %s:%d %d' % (b2lx(outpoint.hash), outpoint.n, qty)) genesis_outpoints[outpoint] = qty for str_addr in args.genesis_addrs: addr = CBitcoinAddress(str_addr) scriptPubKey = addr.to_scriptPubKey() if scriptPubKey in genesis_scriptPubKeys: args.parser.exit('dup addr %s' % str_addr) logging.debug('Genesis scriptPubKey: %s (%s)' % (b2x(scriptPubKey), str(addr))) genesis_scriptPubKeys.add(scriptPubKey) for hex_scriptPubKey in args.genesis_scriptPubKeys: scriptPubKey = CScript(x(hex_scriptPubKey)) if scriptPubKey in genesis_scriptPubKeys: args.parser.exit('dup addr %s' % hex_scriptPubKey) logging.debug('Genesis scriptPubKey: %s' % b2x(scriptPubKey)) genesis_scriptPubKeys.add(scriptPubKey) stegkey = os.urandom(ColorDef.STEGKEY_LEN) if args.stegkey is not None: stegkey = x(args.stegkey) colordef = ColorDef(genesis_outpoints=genesis_outpoints, genesis_scriptPubKeys=genesis_scriptPubKeys, birthdate_blockheight=args.birthdate_blockheight, stegkey=stegkey) ColorDefFileSerializer.stream_serialize(colordef, args.fd)
def send_vault_tx(bitcoind, pubkeys, amount): """Creates a vault transaction for {amount} *sats*""" txo = vault_txout(pubkeys, amount) addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) # This makes a transaction with only one vout amount_for_bitcoind = Decimal(amount) / Decimal(COIN) txid = bitcoind.pay_to(addr, amount_for_bitcoind) return txid
def do(self, args): genesis_outpoints = {} genesis_scriptPubKeys = set() for str_outpoint, str_qty in args.genesis_outpoints: outpoint = ParseCOutPointArg.str_to_COutPoint(str_outpoint, args.parser) qty = int(str_qty) if outpoint in genesis_outpoints: args.parser.exit('dup outpoint %r' % outpoint) logging.debug('Genesis outpoint: %s:%d %d' % (b2lx(outpoint.hash), outpoint.n, qty)) genesis_outpoints[outpoint] = qty for str_addr in args.genesis_addrs: addr = CBitcoinAddress(str_addr) scriptPubKey = addr.to_scriptPubKey() if scriptPubKey in genesis_scriptPubKeys: args.parser.exit('dup addr %s' % str_addr) logging.debug('Genesis scriptPubKey: %s (%s)' % (b2x(scriptPubKey), str(addr))) genesis_scriptPubKeys.add(scriptPubKey) for hex_scriptPubKey in args.genesis_scriptPubKeys: scriptPubKey = CScript(x(hex_scriptPubKey)) if scriptPubKey in genesis_scriptPubKeys: args.parser.exit('dup addr %s' % hex_scriptPubKey) logging.debug('Genesis scriptPubKey: %s' % b2x(scriptPubKey)) genesis_scriptPubKeys.add(scriptPubKey) stegkey = os.urandom(ColorDef.STEGKEY_LEN) if args.stegkey is not None: stegkey = x(args.stegkey) colordef = ColorDef(genesis_outpoints=genesis_outpoints, genesis_scriptPubKeys=genesis_scriptPubKeys, birthdate_blockheight=args.birthdate_blockheight, stegkey=stegkey) ColorDefFileSerializer.stream_serialize(colordef, args.fd)
def _check_output_address(mytx): print for vout in mytx.vout: pubkey = vout.scriptPubKey address = b2lx(CBitcoinAddress.from_scriptPubKey(pubkey)) address = "".join(map(str.__add__, address[-2::-2], address[-1::-2])) #print address address = int(address, 16) for bl in blacklist: if hex(bl.start) <= hex(address) <= hex(bl.end): print "This address use by: " + bl.name return False return True
class SpendScripts(object): def __init__(self, payto_addr): self.payto = CBitcoinAddress(payto_addr) self.proxy = bitcoin.rpc.Proxy() self.prevouts = [] def add_prevout(self, txid, vout, redeemer): outpoint = COutPoint(lx(txid), vout) try: prevout = self.proxy.gettxout(outpoint) except IndexError: raise Exception("Outpoint %s not found" % (outpoint,)) prevtx = prevout['txout'] if prevtx.scriptPubKey != redeemer.p2sh_scriptPubKey: raise Exception("Outpoint %s has incorrect scriptPubKey (%s; expected %s)" % (outpoint, b2x(prevtx.scriptPubKey), b2x(redeemer.p2sh_scriptPubKey))) self.prevouts.append((outpoint, prevtx, redeemer)) 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 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 payment_ack(serialized_Payment_message): """Generates a PaymentACK object, captures client refund address and returns a message""" pao = o.PaymentACK() pao.payment.ParseFromString(serialized_Payment_message) pao.memo = "String shown to user after payment confirmation" refund_address = CBitcoinAddress.from_scriptPubKey(CScript(pao.payment.refund_to[0].script)) sds_pa = pao.SerializeToString() open("sds_pa_blob", "wb").write(sds_pa) headers = {"Content-Type": "application/bitcoin-payment", "Accept": "application/bitcoin-paymentack"} http_response_object = urllib2.Request("file:sds_pa_blob", None, headers) return http_response_object
def get(cls, address): """Get a Channel with the specified address.""" row = g.dat.execute( "SELECT * from CHANNELS WHERE address = ?", (address,)).fetchone() if row is None: raise Exception("Unknown address", address) address, commitment = row commitment = CMutableTransaction.deserialize(commitment) commitment = CMutableTransaction.from_tx(commitment) assert len(commitment.vin) == 1 assert len(commitment.vout) == 2 commitment.vin[0].scriptSig = AnchorScriptSig.from_script( commitment.vin[0].scriptSig) for tx_out in commitment.vout: tx_out.scriptPubKey = CBitcoinAddress.from_scriptPubKey(tx_out.scriptPubKey) return cls(address, commitment.vin[0], commitment.vout[0], commitment.vout[1])
def check_for_funding(self, address): """ Check to see if any of the outputs pay the given address Args: address: base58check encoded bitcoin address Returns: a `list` of `dict` outpoints if any of the outputs match the address else None. """ outpoints = [] for i in range(len(self.tx.vout)): addr = CBitcoinAddress.from_scriptPubKey(self.tx.vout[i].scriptPubKey) if str(addr) == address: o = { "txid": b2lx(self.tx.GetHash()), "vout": i, "value": self.tx.vout[i].nValue, "scriptPubKey": self.tx.vout[i].scriptPubKey.encode("hex") } outpoints.append(o) return outpoints if len(outpoints) > 0 else None
def create_transaction_output(address, transaction_fee): """Create a transaction output""" addr = CBitcoinAddress(address) tx_out = CMutableTxOut(transaction_fee, addr.to_scriptPubKey()) return tx_out
def dataReceived(self, data): self.buffer += data header = MsgHeader.from_bytes(self.buffer) if len(self.buffer) < header.msglen + 24: return try: stream = BytesIO(self.buffer) m = MsgSerializable.stream_deserialize(stream) self.buffer = stream.read() if m.command == "verack": self.timeouts["verack"].cancel() del self.timeouts["verack"] if "version" not in self.timeouts: self.on_handshake_complete() elif m.command == "version": self.version = m if m.nVersion < 70001 or m.nServices != 1: self.transport.loseConnection() self.timeouts["version"].cancel() del self.timeouts["version"] msg_verack().stream_serialize(self.transport) if self.blockchain is not None: self.to_download = self.version.nStartingHeight - self.blockchain.get_height() if "verack" not in self.timeouts: self.on_handshake_complete() elif m.command == "getdata": for item in m.inv: if item.hash in self.inventory and item.type == 1: transaction = msg_tx() transaction.tx = self.inventory[item.hash] transaction.stream_serialize(self.transport) elif m.command == "inv": for item in m.inv: # This is either an announcement of tx we broadcast ourselves or a tx we have already downloaded. # In either case we only need to callback here. if item.type == 1 and item.hash in self.subscriptions: self.subscriptions[item.hash]["callback"](item.hash) # This is the first time we are seeing this txid. Let's download it and check to see if it sends # coins to any addresses in our subscriptions. elif item.type == 1 and item.hash not in self.inventory: self.timeouts[item.hash] = reactor.callLater(5, self.response_timeout, item.hash) cinv = CInv() cinv.type = 1 cinv.hash = item.hash getdata_packet = msg_getdata() getdata_packet.inv.append(cinv) getdata_packet.stream_serialize(self.transport) # The peer announced a new block. Unlike txs, we should download it, even if we've previously # downloaded it from another peer, to make sure it doesn't contain any txs we didn't know about. elif item.type == 2 or item.type == 3: if self.state == State.DOWNLOADING: self.download_tracker[0] += 1 cinv = CInv() cinv.type = 3 cinv.hash = item.hash getdata_packet = msg_getdata() getdata_packet.inv.append(cinv) getdata_packet.stream_serialize(self.transport) if self.state != State.DOWNLOADING: self.log.debug("Peer %s:%s announced new %s %s" % (self.transport.getPeer().host, self.transport.getPeer().port, CInv.typemap[item.type], b2lx(item.hash))) elif m.command == "tx": if m.tx.GetHash() in self.timeouts: self.timeouts[m.tx.GetHash()].cancel() for out in m.tx.vout: try: addr = str(CBitcoinAddress.from_scriptPubKey(out.scriptPubKey)) except Exception: addr = None if addr in self.subscriptions: if m.tx.GetHash() not in self.subscriptions: # It's possible the first time we are hearing about this tx is following block # inclusion. If this is the case, let's make sure we include the correct number # of confirmations. in_blocks = self.inventory[m.tx.GetHash()] if m.tx.GetHash() in self.inventory else [] confirms = [] if len(in_blocks) > 0: for block in in_blocks: confirms.append(self.blockchain.get_confirmations(block)) self.subscriptions[m.tx.GetHash()] = { "announced": 0, "ann_threshold": self.subscriptions[addr][0], "confirmations": max(confirms) if len(confirms) > 0 else 0, "last_confirmation": 0, "callback": self.subscriptions[addr][1], "in_blocks": in_blocks, "tx": m.tx } self.subscriptions[addr][1](m.tx.GetHash()) if m.tx.GetHash() in self.inventory: del self.inventory[m.tx.GetHash()] elif m.command == "merkleblock": if self.blockchain is not None: self.blockchain.process_block(m.block) if self.state != State.DOWNLOADING: self.blockchain.save() # check for block inclusion of subscribed txs for match in m.block.get_matched_txs(): if match in self.subscriptions: self.subscriptions[match]["in_blocks"].append(m.block.GetHash()) else: # stick the hash here in case this is the first we are hearing about this tx. # when the tx comes over the wire after this block, we will append this hash. self.inventory[match] = [m.block.GetHash()] # run through subscriptions and callback with updated confirmations for txid in self.subscriptions: try: confirms = [] for block in self.subscriptions[txid]["in_blocks"]: confirms.append(self.blockchain.get_confirmations(block)) self.subscriptions[txid]["confirmations"] = max(confirms) self.subscriptions[txid]["callback"](txid) except Exception: pass # If we are in the middle of an initial chain download, let's check to see if we have # either reached the end of the download or if we need to loop back around and make # another get_blocks call. if self.state == State.DOWNLOADING: self.download_count += 1 percent = int((self.download_count / float(self.to_download))*100) if self.download_listener is not None: self.download_listener.progress(percent, self.download_count) self.download_listener.on_block_downloaded((self.transport.getPeer().host, self.transport.getPeer().port), header, self.to_download - self.download_count + 1) if percent == 100: if self.download_listener is not None: self.download_listener.download_complete() self.log.info("Chain download 100% complete") self.download_tracker[1] += 1 # We've downloaded every block in the inv packet and still have more to go. if (self.download_tracker[0] == self.download_tracker[1] and self.blockchain.get_height() < self.version.nStartingHeight): if self.timeouts["download"].active(): self.timeouts["download"].cancel() self.download_blocks(self.callbacks["download"]) # We've downloaded everything so let's callback to the client. elif self.blockchain.get_height() >= self.version.nStartingHeight: self.blockchain.save() self.state = State.CONNECTED self.callbacks["download"]() if self.timeouts["download"].active(): self.timeouts["download"].cancel() elif m.command == "headers": if self.timeouts["download"].active(): self.timeouts["download"].cancel() for header in m.headers: # If this node sent a block with no parent then disconnect from it and callback # on client.check_for_more_blocks. if self.blockchain.process_block(header) is None: self.blockchain.save() self.callbacks["download"]() self.transport.loseConnection() return self.download_count += 1 percent = int((self.download_count / float(self.to_download))*100) if self.download_listener is not None: self.download_listener.progress(percent, self.download_count) self.download_listener.on_block_downloaded((self.transport.getPeer().host, self.transport.getPeer().port), header, self.to_download - self.download_count + 1) if percent == 100: if self.download_listener is not None: self.download_listener.download_complete() self.log.info("Chain download 100% complete") # The headers message only comes in batches of 500 blocks. If we still have more blocks to download # loop back around and call get_headers again. if self.blockchain.get_height() < self.version.nStartingHeight: self.download_blocks(self.callbacks["download"]) else: self.blockchain.save() self.callbacks["download"]() self.state = State.CONNECTED elif m.command == "ping": msg_pong(nonce=m.nonce).stream_serialize(self.transport) else: self.log.debug("Received message %s from %s:%s" % (m.command, self.transport.getPeer().host, self.transport.getPeer().port)) if len(self.buffer) >= 24: self.dataReceived("") except Exception: traceback.print_exc()
def dataReceived(self, data): self.buffer += data # if self.buffer.length >= sizeof(message header) # messageHeader := MessageHeader.deserialize(self.buffer) # if messageHeader.payloadLength > someBigNumber # throw DropConnection # if self.buffer.length < messageHeader.payloadLength # return try: m = MsgSerializable.from_bytes(self.buffer) self.buffer = "" if m.command == "verack": self.timeouts["verack"].cancel() del self.timeouts["verack"] if "version" not in self.timeouts: self.on_handshake_complete() elif m.command == "version": self.version = m if m.nVersion < 70001: self.transport.loseConnection() self.timeouts["version"].cancel() del self.timeouts["version"] msg_verack().stream_serialize(self.transport) if "verack" not in self.timeouts: self.on_handshake_complete() elif m.command == "getdata": for item in m.inv: if item.hash in self.inventory and item.type == 1: transaction = msg_tx() transaction.tx = self.inventory[item.hash] transaction.stream_serialize(self.transport) elif m.command == "inv": for item in m.inv: # callback tx if item.type == 1 and item.hash in self.subscriptions: self.subscriptions[item.hash]["callback"](item.hash) # download tx and check subscription elif item.type == 1 and item.hash not in self.inventory: self.timeouts[item.hash] = reactor.callLater(5, self.response_timeout, item.hash) cinv = CInv() cinv.type = 1 cinv.hash = item.hash getdata_packet = msg_getdata() getdata_packet.inv.append(cinv) getdata_packet.stream_serialize(self.transport) # download block elif item.type == 2 or item.type == 3: cinv = CInv() cinv.type = 3 cinv.hash = item.hash getdata_packet = msg_getdata() getdata_packet.inv.append(cinv) getdata_packet.stream_serialize(self.transport) print "Peer %s:%s announced new %s %s" % (self.transport.getPeer().host, self.transport.getPeer().port, CInv.typemap[item.type], b2lx(item.hash)) elif m.command == "tx": if m.tx.GetHash() in self.timeouts: self.timeouts[m.tx.GetHash()].cancel() for out in m.tx.vout: addr = str(CBitcoinAddress.from_scriptPubKey(out.scriptPubKey)) if addr in self.subscriptions: if m.tx.GetHash() not in self.subscriptions: self.subscriptions[m.tx.GetHash()] = { "announced": 0, "ann_threshold": self.subscriptions[addr][0], "confirmations": 0, "callback": self.subscriptions[addr][1], "in_blocks": self.inventory[m.tx.GetHash()] if m.tx.GetHash() in self.inventory else [], "tx": m.tx } self.subscriptions[addr][1](m.tx.GetHash()) if m.tx.GetHash() in self.inventory: del self.inventory[m.tx.GetHash()] elif m.command == "merkleblock": self.blockchain.process_block(m.block) if self.blockchain is not None: # check for block inclusion of subscribed txs for match in m.block.get_matched_txs(): if match in self.subscriptions: self.subscriptions[match]["in_blocks"].append(m.block.GetHash()) else: # stick the hash here in case this is a tx we missed on broadcast. # when the tx comes over the wire after this block, we will append this hash. self.inventory[match] = [m.block.GetHash()] # run through subscriptions and callback with updated confirmations for txid in self.subscriptions: if len(txid) == 32: confirms = [] for block in self.subscriptions[txid]["in_blocks"]: confirms.append(self.blockchain.get_confirmations(block)) self.subscriptions[txid]["confirmations"] = max(confirms) self.subscriptions[txid]["callback"](txid) elif m.command == "headers": self.timeouts["download"].cancel() to_download = self.version.nStartingHeight - self.blockchain.get_height() i = 1 for header in m.headers: self.blockchain.process_block(header) if i % 50 == 0 or int((i / float(to_download))*100) == 100: print "Chain download %s%% complete" % int((i / float(to_download))*100) i += 1 if self.blockchain.get_height() < self.version.nStartingHeight: self.download_blocks(self.callbacks["download"]) elif self.callbacks["download"]: self.callbacks["download"]() else: print "Received message %s from %s:%s" % (m.command, self.transport.getPeer().host, self.transport.getPeer().port) except Exception: pass
def getnewaddress_command(args): fund_addr = CBitcoinAddress.from_scriptPubKey(args.wallet.make_paytopubkeyhash()) args.wallet.save() print('Pay to %s to fund your wallet' % fund_addr)
def __init__(self, payto_addr): self.payto = CBitcoinAddress(payto_addr) self.proxy = bitcoin.rpc.Proxy() self.prevouts = []
def build_mandatory_multisig(mandatory_pubkey, other_pubkeys): txin_redeemScript = CScript([x(mandatory_pubkey), OP_CHECKSIGVERIFY, 1, x(other_pubkeys[0]), x(other_pubkeys[1]), 2, OP_CHECKMULTISIG]) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) return (b2x(txin_redeemScript), str(txin_p2sh_address))
args = parser.parse_args() logging.root.setLevel('DEBUG') if args.testnet: bitcoin.SelectParams('testnet') rpc = bitcoin.rpc.Proxy() args.dust = int(args.dust * COIN) feeperbyte1 = args.fee1 / 1000 * COIN feeperbyte2 = args.fee2 / 1000 * COIN # Construct payment tx payment_address = CBitcoinAddress(args.address) payment_txout = CTxOut(int(args.amount * COIN), payment_address.to_scriptPubKey()) change_txout = CTxOut(0, rpc.getnewaddress().to_scriptPubKey()) tx = CTransaction() tx.vout.append(change_txout) tx.vout.append(payment_txout) # Add all undesirable txouts meant to reduce propagation if args.op_return: op_ret_txout = CTxOut(0, CScript([OP_RETURN, b'\x00unsuccessful double-spend attempt\x00'])) tx.vout.append(op_ret_txout) if args.multisig: multisig_txout = CTxOut(args.dust,
try: rpc.gettransaction(args.txid) except IndexError as err: parser.exit('Invalid txid: Not in wallet.') txinfo = rpc.getrawtransaction(args.txid, True) tx = CMutableTransaction.from_tx(txinfo['tx']) if 'confirmations' in txinfo and txinfo['confirmations'] > 0: parser.exit("Transaction already mined; %d confirmations." % txinfo['confirmations']) # Find a txout that was being used for change change_txout = None for vout in tx.vout: try: addr = CBitcoinAddress.from_scriptPubKey(vout.scriptPubKey) except ValueError: continue if rpc.validateaddress(addr)['ismine']: change_txout = vout break if change_txout is None: # No suitable change txout; no txout was an address in our wallet. # # Create a new txout for use as change. addr = rpc.getrawchangeaddress() change_txout = CMutableTxOut(0, addr.to_scriptPubKey()) tx.vout.append(change_txout)
def build_2_of_3(pubkeys): txin_redeemScript = CScript([2, x(pubkeys[0]), x(pubkeys[1]), x(pubkeys[2]), 3, OP_CHECKMULTISIG]) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) return (b2x(txin_redeemScript), str(txin_p2sh_address))
seckey = CBitcoinSecret.from_secret_bytes(h) # Create a redeemScript. Similar to a scriptPubKey the redeemScript must be # satisfied for the funds to be spent. txin_redeemScript = CScript([seckey.pub, OP_CHECKSIG]) print(b2x(txin_redeemScript)) # Create the magic P2SH scriptPubKey format from that redeemScript. You should # look at the CScript.to_p2sh_scriptPubKey() function in bitcoin.core.script to # understand what's happening, as well as read BIP16: # https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address and print it. # You'll need to send some funds to it to create a txout to spend. txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) print('Pay to:',str(txin_p2sh_address)) # Same as the txid:vout the createrawtransaction RPC call requires # # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin # transaction hashes are shown little-endian rather than the usual big-endian. # There's also a corresponding x() convenience function that takes big-endian # hex and converts it to bytes. txid = lx('bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae') vout = 0 # Create the txin structure, which includes the outpoint. The scriptSig # defaults to being empty. txin = CMutableTxIn(COutPoint(txid, vout))
# wouldn't conflict with the old one and you'd pay everyone twice! tx2.vin = tx2.vin[0:1] if not args.first_seen_safe and len(tx2.vout) > 0: # Delete the change output. # # Unfortunately there isn't any way to ask Bitcoin Core if a given address # is a change address; if you're sending yourself funds to test the feature # it's not possible to distinguish change from send-to-self outputs. # # So instead we always build transactions such that the first output is # change, and we delete only that output. Not pretty - you don't want to do # something that dumb and anti-privacy in a real wallet - but without a way # of keeping state this is the best we've got. try: addr = CBitcoinAddress.from_scriptPubKey(tx2.vout[0].scriptPubKey) except ValueError: pass else: # There is an edge case not handled: if we have multiple outputs but # didn't need a change output. But whatever, this is just a demo! if len(tx2.vout) > 1 and rpc.validateaddress(addr)['ismine']: tx2.vout = tx2.vout[1:] # Add the new output payment_txout = CMutableTxOut(args.amount, args.address.to_scriptPubKey()) tx2.vout.append(payment_txout) r = rpc.fundrawtransaction(tx2) tx2 = CMutableTransaction.from_tx(r['tx'])