def main(): access = ServiceProxy("http://*****:*****@127.0.0.1:8332") txid = sys.argv[1] # print txid txinfo = access.gettransaction(txid) pprint.pprint(txinfo) # Check the details to make sure it's an incoming transaction # Ensure everything is incoming, to avoid # mirroring change/consolidation transactions. myaddresses = set() for details in txinfo["details"]: # print details if details["category"] != "receive": return myaddresses.add(details["address"]) tx = access.decoderawtransaction(txinfo["hex"]) pprint.pprint(tx) # Now gather all the outputs to send back newtx_inputs = [] total_amount = Decimal(0) for vout in tx["vout"]: for address in vout["scriptPubKey"]["addresses"]: if address in myaddresses: newtx_inputs.append({"txid":txid,"vout":vout["n"]}) total_amount += vout["value"] break print newtx_inputs print total_amount # Now find the sendign addresses, and choose one at random # to receive the funds. total_inputs = Decimal("0") addresses = [] for vin in tx["vin"]: intxid = vin["txid"] invout = vin["vout"] # Get the outputs of the input transaction intx = access.getrawtransaction(intxid,1) # print intxid, invout vout = intx["vout"][invout] # pprint.pprint(vout) total_inputs += vout["value"] addresses.extend(vout["scriptPubKey"]["addresses"]) print "Total inputs: %f" % total_inputs print addresses to_address = random.choice(addresses) # Build a transaction with the output of the original transaction as input # and to_address as output. newtx_hex = access.createrawtransaction(newtx_inputs,{to_address:float(total_amount)}) newtx_hex = access.signrawtransaction(newtx_hex)["hex"] print newtx_hex # print >>open("/home/user/a.txt","a"), access.decoderawtransaction(newtx_hex) access.sendrawtransaction(newtx_hex)
class BitcoinRPC: def __init__(self): self.connection = None self.network_info = None self.version = None self.relay_fee = None self.establish_connection() def establish_connection(self): endpoint = 'http://{user}:{pwd}@{host}:{port}'.format( user=NETWORK_SETTINGS['BTC']['user'], pwd=NETWORK_SETTINGS['BTC']['password'], host=NETWORK_SETTINGS['BTC']['host'], port=NETWORK_SETTINGS['BTC']['port']) print(endpoint) self.connection = AuthServiceProxy(endpoint) self.network_info = self.connection.getnetworkinfo() self.version = int(str(self.network_info['version'])[:2]) res = requests.get('https://api.bitcore.io/api/BTC/mainnet/fee/3') self.relay_fee = int(json.loads(res.text)['feerate'] * DECIMALS['BTC']) def reconnect(self): self.establish_connection() def create_raw_transaction(self, input_params, output_params): self.reconnect() return self.connection.createrawtransaction(input_params, output_params) def sign_raw_transaction(self, tx, private_key): self.reconnect() if self.version >= 17: return self.connection.signrawtransactionwithkey(tx, [private_key]) else: return self.connection.signrawtransaction(tx, None, [private_key]) def send_raw_transaction(self, tx_hex): self.reconnect() return self.connection.sendrawtransaction(tx_hex) def construct_and_send_tx(self, input_params, output_params, private_key): tx = self.create_raw_transaction(input_params, output_params) signed = self.sign_raw_transaction(tx, private_key) try: tx_hash = self.send_raw_transaction(signed['hex']) print('tx', tx_hash, flush=True) return tx_hash except Exception as e: print('FAILED SENDING TRANSACTION', flush=True) print(e, flush=True) return None def validateaddress(self, address): self.reconnect() return self.connection.validateaddress(address)
def main(): rpc_user = '******' rpc_password = '******' rpc = AuthServiceProxy(f'http://{rpc_user}:{rpc_password}@127.0.0.1:18332/') #rpc = AuthServiceProxy(f'http://{rpc_user}:{rpc_password}@172.17.0.2:18332/') print(rpc.getinfo()) best_block_hash = rpc.getbestblockhash() print(rpc.getblock(best_block_hash)) blhash = rpc.getblockhash(0) #blhashはブロックのhash文字列 bl = rpc.getblock(blhash) #blはブロック情報 print(bl) dummy_address = '2MudgRfNaaw96kqAWziZ5JGsPbo2pzQp7Jy' change_address = '2NAVrak22jX3DQyDqnoqdm5ZTak1RgXWPzo' filename = 'mark_token.btc.json' url='https://drive.google.com/file/d/1ZR6Q5sCM_acUpPy7s3d9GJH8I2Plh4FI/view?usp=sharing' with open(filename, 'rb') as f: data2 = f.read() hashdata=hashlib.sha256(data2).hexdigest() js={'file_hash':hashdata,'url':url} data=json.dumps(js).encode("UTF-8") while True: if len(data) >= 80: buffer = data[:80] data = data[80:] elif len(data) == 0: break else: buffer = data data = b'' first_unspent = rpc.listunspent()[0] txid = first_unspent['txid'] vout = first_unspent['vout'] input_amount = first_unspent['amount'] SATOSHI = Decimal("0.00000001") change_amount = input_amount - Decimal("0.005") - SATOSHI tx = rpc.createrawtransaction([{"txid": txid, "vout": vout}],[{change_address: change_amount}, {'data': hexlify(buffer).decode('utf-8')}, ]) tx = rpc.signrawtransactionwithwallet(tx)['hex'] rpc.sendrawtransaction(tx) block_hash = rpc.generatetoaddress(1, change_address)[0] block = rpc.getblock(block_hash) txs = block['tx'][1:] print(f'# of txs: {len(txs)}') pprint(txs) for tx_hash in txs: raw_tx = rpc.gettransaction(tx_hash)['hex'] decoded_tx = rpc.decoderawtransaction(raw_tx) # pprint(decoded_tx) print(decoded_tx['vout'][1]['scriptPubKey']['asm'])
def transfer_coins(): success = False txid = '0000' vout = 0 rpc_connection = AuthServiceProxy("http://%s:%[email protected]:52541" % (rpcuser, rpcpassword)) # STEP 1. select best, smallest, txid to transfer # bulwark-cli listunspent 70 9999999 '''["bRTwEvdihGjjCKRSiLM84xZaiwgfZCADFx"]''' addr = [bwkaddress_from] listunspent = rpc_connection.listunspent(70, 999999, addr) #print len(listunspent) smallestvalidamount = 100000000.0 for k in range(len(listunspent)): if listunspent[k]["amount"] >= transfer_amount and listunspent[k][ "spendable"]: if listunspent[k]["amount"] <= smallestvalidamount: smallestvalidamount = listunspent[k]["amount"] txid = listunspent[k]["txid"] vout = listunspent[k]["vout"] if smallestvalidamount < 10000000.0: print " | valid txid found for sending", transfer_amount, " :", listunspent[ k]["txid"], " ", smallestvalidamount # STEP 2. create raw tx # format cli: bulwark-cli createrawtransaction '[{"txid" : "000000000...000","vout" : 1}]' '{"bRTw...adres": 101.0, "bGM....adres": 4.41}' change = decimal.Decimal(smallestvalidamount) - decimal.Decimal( transfer_amount) - decimal.Decimal(0.00001) json1 = [{"txid": txid, "vout": vout}] json2 = { bwkaddress_from: float(change), bwkaddress_to: float(transfer_amount) } #print(json.dumps(json1)) rawtx_hex = rpc_connection.createrawtransaction(json1, json2) # STEP 3. unlock wallet if not wallet_manually_unlocked_mode: rpc_connection.walletpassphrase(walletpassphrase, 99999999, wallet_manually_unlocked_mode) # STEP 4. sign raw tx # format cli: bulwark-cli signrawtransaction 00000...ab23 rawsigned = rpc_connection.signrawtransaction(rawtx_hex) # STEP 5. send raw tx # format cli: bulwark-cli sendrawtransaction 00000...gb23 signed_hex = rawsigned["hex"] sendresult = rpc_connection.sendrawtransaction(signed_hex) if "{" not in sendresult: #in case error it gives a {..json error message } success = True print " | done sending coins, blockchain txid will be ", sendresult return success
def create_raw_op_return_transaction(metadata): """ Method used to create a transaction with embedded data through OP_RETURN Args: metadata (str) Returns: Raw transaction (hex) Author address (str) """ rpc = AuthServiceProxy( ("http://%s:%[email protected]:%s/") % (config['RPC_USER'], config['RPC_PASS'], config['RPC_PORT'])) if sys.getsizeof(metadata) > MAX_OP_RETURN_BYTES: raise Exception("Metadata size is over MAX_OP_RETURN_BYTES") if len(metadata) < 4: raise Exception( "This tool set does not currently support reading op_return data with less than 4 chars" ) input_tx = get_input() init_raw_tx = rpc.createrawtransaction( [{ "txid": input_tx["txid"], "vout": input_tx["vout"] }], { input_tx["address"]: TX_BURN_AMOUNT, rpc.getnewaddress(): round(float(input_tx["amount"]) - 1.1 * TX_BURN_AMOUNT, 8) }) oldScriptPubKey = init_raw_tx[len(init_raw_tx) - 60:len(init_raw_tx) - 8] newScriptPubKey = b"6a" + hexlify( bytes(chr(len(metadata)), encoding='utf-8')) + hexlify( bytes(metadata, encoding='utf-8')) newScriptPubKey = hexlify( bytes(chr(len(unhexlify(newScriptPubKey))), encoding='utf-8')) + newScriptPubKey if oldScriptPubKey not in init_raw_tx: raise Exception("Something broke!") op_return_tx = init_raw_tx.replace(oldScriptPubKey, newScriptPubKey.decode('ascii')) print(rpc.decoderawtransaction(op_return_tx)['vout']) return op_return_tx, input_tx["address"]
class BitcoinRPC: def __init__(self): self.connection = None self.network_info = None self.version = None self.relay_fee = None self.establish_connection() def establish_connection(self): print('http://' + NETWORK_SETTINGS['DUC']['user'] + ':' + NETWORK_SETTINGS['DUC']['password'] + '@' + NETWORK_SETTINGS['DUC']['host'] + ':' + NETWORK_SETTINGS['DUC']['port']) self.connection = AuthServiceProxy( 'http://' + NETWORK_SETTINGS['DUC']['user'] + ':' + NETWORK_SETTINGS['DUC']['password'] + '@' + NETWORK_SETTINGS['DUC']['host'] + ':' + NETWORK_SETTINGS['DUC']['port']) self.network_info = self.connection.getnetworkinfo() self.relay_fee = int(self.network_info['relayfee'] * DECIMALS['DUC']) def reconnect(self): self.establish_connection() def create_raw_transaction(self, input_params, output_params): self.reconnect() return self.connection.createrawtransaction(input_params, output_params) def sign_raw_transaction(self, tx, private_key): self.reconnect() return self.connection.signrawtransaction(tx, None, [private_key]) def send_raw_transaction(self, tx_hex): self.reconnect() return self.connection.sendrawtransaction(tx_hex) def construct_and_send_tx(self, input_params, output_params, private_key): tx = self.create_raw_transaction(input_params, output_params) print('raw tx', tx, flush=True) signed = self.sign_raw_transaction(tx, private_key) print('signed tx', signed, flush=True) try: tx_hash = self.send_raw_transaction(signed['hex']) print('tx', tx_hash, flush=True) return tx_hash except Exception as e: print('FAILED SENDING TRANSACTION', flush=True) print(e, flush=True) return None
def send_data(rpc_connection: authproxy.AuthServiceProxy, hexdata: str, tx_ins: list = ()) -> Transaction: """Creates, funds, signs and sends an OP_RETURN transaction including hexdata Parameters ---------- rpc_connection : bitcoinrpc.authproxy.AuthServiceProxy The RPC connection to the bitcoind client hexdata : str The hex encoded data to be included in the transaction tx_ins : list, optional List of namedtuples 'Transaction', representing UTXOs to fund the transaction Returns ------- Transaction Change UTXO Raises ------ ValueError If hexdata is more than MAX_DATA_LENGTH bytes RuntimeError If the transaction could not be signed """ if len(hexdata) / 2 > MAX_DATA_LENGTH: raise ValueError("hexdata too big") inputs = [{"txid": tx.txid, "vout": tx.vout} for tx in tx_ins] unfinished_tx = rpc_connection.createrawtransaction( inputs, {"data": hexdata}) funded_tx = rpc_connection.fundrawtransaction(unfinished_tx) signed_tx = rpc_connection.signrawtransactionwithwallet(funded_tx["hex"]) if signed_tx["complete"] is False: raise RuntimeError("bitcoind could not sign the transaction.") txid = rpc_connection.sendrawtransaction(signed_tx["hex"]) change_utxo = Transaction(txid, funded_tx["changepos"]) return change_utxo
class BitcoinRPC: def __init__(self): self.connection = None self.network_info = None self.version = None self.relay_fee = None self.establish_connection() def establish_connection(self): self.connection = AuthServiceProxy(NETWORK_SETTINGS['BTC']['endpoint']) self.network_info = self.connection.getnetworkinfo() self.version = int(str(self.network_info['version'])[:2]) self.relay_fee = int(self.network_info['relayfee'] * DECIMALS['BTC']) def reconnect(self): self.establish_connection() def create_raw_transaction(self, input_params, output_params): self.reconnect() return self.connection.createrawtransaction(input_params, output_params) def sign_raw_transaction(self, tx, private_key): self.reconnect() if self.version >= 17: return self.connection.signrawtransactionwithkey(tx, [private_key]) else: return self.connection.signrawtransaction(tx, None, [private_key]) def send_raw_transaction(self, tx_hex): self.reconnect() return self.connection.sendrawtransaction(tx_hex) def construct_and_send_tx(self, input_params, output_params, private_key): tx = self.create_raw_transaction(input_params, output_params) signed = self.sign_raw_transaction(tx, private_key) try: tx_hash = self.send_raw_transaction(signed['hex']) print('tx', tx_hash, flush=True) return tx_hash except Exception as e: print('FAILED SENDING TRANSACTION', flush=True) print(e, flush=True) return None
def main(): bitcoin = AuthServiceProxy("http://{}:{}@127.0.0.1:{}".format( RPCUSER, RPCPASSWORD, RPCPORT)) address = ADDRESS if address is None: address = bitcoin.getaddressesbyaccount("")[0] print("Using wallet address: ", address) parent_txid = "NULL" subprotocols = [None, gen_media, gen_pastebin, gen_randomdata] # Create nodes... for i in range(NUM_NODES_TO_CREATE): node = create_node(address, parent_txid) # Add subprotocols to node for _ in range(5): subprotocol = secrets.choice(subprotocols) if subprotocol is not None: node['subprotocols'].append(subprotocol()) # Create OP_RETURN data data = b'meta' + encode_function(ENCODING)(node) assert (len(data) < 100000) # sanity check for op_return max limit data_hex = data.hex() # bitcoin rpc commands to create and fund tx with metanet data in OP_RETURN rawtx = bitcoin.createrawtransaction([], {'data': data_hex}) result = bitcoin.fundrawtransaction(rawtx, {'changeAddress': address}) rawtx = result['hex'] result = bitcoin.signrawtransaction(rawtx) assert (result['complete']) signedtx = result['hex'] txid = bitcoin.sendrawtransaction(signedtx) # Prepare for next iteration parent_txid = txid print("[Node {}]: https://test.whatsonchain.com/tx/{}".format(i, txid))
SATOSHI = Decimal("0.00000001") change_amount = input_amount - Decimal("0.005") - SATOSHI # Marker address we're going to replace # Produces a pattern that's easy to search for mainnet = 0 if mainnet: dummy_address = "1111111111111111111114oLvT2" else: dummy_address = "mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8" # My change address change_address = "mhZuYnuMCZLjZKeDMnY48xsR5qkjq7bAr9" tx = rpc.createrawtransaction([{"txid": txid, "vout": vout}], \ {change_address: change_amount, \ dummy_address: SATOSHI}) # Pattern to replace # Represents length of script, then OP_DUP OP_HASH160, # then length of hash, then 20 bytes of zeros, OP_EQUALVERIFY OP_CHECKSIG oldScriptPubKey = "1976a914000000000000000000000000000000000000000088ac" # Data to insert data = "Melons." if len(data) > 75: raise Exception("Can't contain this much data-use OP_PUSHDATA1") newScriptPubKey = "6a" + hexlify(chr(len(data))) + hexlify(data) #Append int of length to start
class DucatuscoreInterface: endpoint = None settings = None def __init__(self): self.settings = NETWORK_SETTINGS['DUC'] self.setup_endpoint() self.rpc = AuthServiceProxy(self.endpoint) self.check_connection() def setup_endpoint(self): self.endpoint = 'http://{user}:{pwd}@{host}:{port}'.format( user=self.settings['user'], pwd=self.settings['password'], host=self.settings['host'], port=self.settings['port']) return def check_connection(self): block = self.rpc.getblockcount() if block and block > 0: return True else: raise Exception('Ducatus node not connected') def transfer(self, address, amount): #try: value = int(amount) / DECIMALS['DUC'] print('try sending {value} DUC to {addr}'.format(value=value, addr=address)) self.rpc.walletpassphrase(self.settings['wallet_password'], 30) res = self.rpc.sendtoaddress(address, value) print(res) return res '''except JSONRPCException as e: err = 'DUCATUS TRANSFER ERROR: transfer for {amount} DUC for {addr} failed' \ .format(amount=amount, addr=address) print(err, flush=True) print(e, flush=True) raise DucatuscoreInterfaceException(err)''' def validate_address(self, address): for attempt in range(10): print('attempt', attempt, flush=True) try: rpc_response = self.rpc.validateaddress(address) except RemoteDisconnected as e: print(e, flush=True) rpc_response = False if not isinstance(rpc_response, bool): print(rpc_response, flush=True) break else: raise Exception('cannot validate address with 10 attempts') return rpc_response['isvalid'] def get_unspent(self, tx_hash, count): return self.rpc.gettxout(tx_hash, count) def get_fee(self): return self.rpc.getinfo()['relayfee'] def get_unspent_input(self, tx_hash, payment_address): last_response = {} count = 0 while isinstance(last_response, dict): rpc_response = self.get_unspent(tx_hash, count) last_response = rpc_response input_addresses = rpc_response['scriptPubKey']['addresses'] if payment_address in input_addresses: return rpc_response, count count += 1 def internal_transfer(self, tx_list, address_from, address_to, amount, private_key): print('start raw tx build', flush=True) print('tx_list', tx_list, 'from', address_from, 'to', address_to, 'amount', amount, flush=True) try: input_params = [] for payment_hash in tx_list: unspent_input, input_vout_count = self.get_unspent_input( payment_hash, address_from) print('unspent input', unspent_input, flush=True) input_params.append({ 'txid': payment_hash, 'vout': input_vout_count }) transaction_fee = self.get_fee() * DECIMALS['DUC'] send_amount = (Decimal(amount) - transaction_fee) / DECIMALS['DUC'] print('input_params', input_params, flush=True) output_params = {address_to: send_amount} print('output_params', output_params, flush=True) tx = self.rpc.createrawtransaction(input_params, output_params) print('raw tx', tx, flush=True) signed = self.rpc.signrawtransaction(tx, None, [private_key]) print('signed tx', signed, flush=True) tx_hash = self.rpc.sendrawtransaction(signed['hex']) print('tx', tx_hash, flush=True) return tx_hash except JSONRPCException as e: print( 'DUCATUS TRANSFER ERROR: transfer for {amount} DUC for {addr} failed' .format(amount=amount, addr=address_to), flush=True) print(e, flush=True) raise DucatuscoreInterfaceException(e)
raw_input('发送到哪个地址? (例如33hxAeUqNnFs3gdayu7aAaijhTbbfnphq8) ')) if SendAddress == "33hxAeUqNnFs3gdayu7aAaijhTbbfnphq8": print "太感谢了,你选择捐赠给johnson Diao" print Leftover = int( unspent[WhichTrans]["amount"] * 100000000) - HowMuch - SetTxFee print "将要发送您的比特币到这个地址:", SendAddress, "账户里会留下来 ", Leftover, " 聪", ",这些币会发送到找零地址:", ChangeAddress print "会发送 ", SetTxFee, " 聪的网络手续费给矿工" print print "将要创建发送单" rawtransact = bitcoin.createrawtransaction( [{ "txid": unspent[WhichTrans]["txid"], "vout": unspent[WhichTrans]["vout"], "scriptPubKey": unspent[WhichTrans]["scriptPubKey"], "redeemScript": unspent[WhichTrans]["redeemScript"] }], { SendAddress: HowMuch / 100000000.00, ChangeAddress: Leftover / 100000000.00 }) print "发送单为:", rawtransact print print print "现在我们要用私钥进行签名" multisigprivkeyone = str(raw_input("请输入第一个私钥:")) print signedone = bitcoin.signrawtransaction( rawtransact, [{ "txid": unspent[WhichTrans]["txid"], "vout": unspent[WhichTrans]["vout"],
class UsdtWallet(): USDT_BLOCK_NUM = 'http://www.tokenview.com:8088/coin/latest/USDT' USDT_TX_API = 'https://api.omniexplorer.info/v1/transaction/address' USDT_URL_BALANCE = 'https://api.omniexplorer.info/v1/address/addr/' def __init__(self, consul_client=None): if consul_client: self.init_consul(consul_client) def init_consul(self, app, consul_client): self.propertyid = 31 # self.usdt_rpc_user = app.config["USDT_RPC_USER"] # self.usdt_rpc_password = app.config["USDT_RPC_PWD"] # self.usdt_passphrase = app.config.get('GETH_USDT_PASSPHRASE') # self.consul_client = consul_client # # self.wallet_url = self.consul_client.getRandomOneAvailableServiceIpPort(ConsulServiceName.USDTEREUM_CLI) # self.wallet_url = '47.52.131.71:7332' # print(self.wallet_url) # self.usdtcoin_cli = AuthServiceProxy( # "http://%s:%s@" % (self.usdt_rpc_user, self.usdt_rpc_password) + self.wallet_url, timeout=10) # if not self.is_connected(): # logging.error('Connect USDT wallet node fial') self.usdtcoin_cli = AuthServiceProxy("http://%s:%[email protected]:7332" % ('xianda', 'ABQOqmPZ0tr95f5Z')) def is_connected(self): """获取钱包状态判读是否链接""" try: if self.usdtcoin_cli.getwalletinfo().get('walletversion'): return True return False except Exception as e: return False def is_syncing(self): """节点是否在同步中""" # 注意返回Flase表示节点同步完成 info = self.usdtcoin_cli.getblockchaininfo() # print(info['blocks'], info['headers']) if info['blocks'] != info['headers']: return False else: return True def accountCreate(self, accountName): # 否则,创建账户,并返回账户地址 address = self.usdtcoin_cli.getaccountaddress(accountName) privateKey = self.usdtcoin_cli.dumpprivkey(address) return privateKey, address # 檢驗賬戶是否有效 def is_valid_address(self, address): if address is None or address == '': return False else: try: # print(self.usdtcoin_cli.validateaddress(address)) return self.usdtcoin_cli.validateaddress(address).get( 'isvalid') except: return False # 獲取餘額 def get_balance(self, address): """获取余额,默认最新区块""" try: balance = str( self.usdtcoin_cli.omni_getbalance(address, self.propertyid)['balance']) except Exception as e: logging.error('USDT node get balance error:{}'.format(str(e))) raise Exception('USDT node get balance error') return Decimal(balance) def get_block_num(self): """获取最新区块数""" try: block_num = self.usdtcoin_cli.getblockcount() except Exception as e: logging.error('Get eth node block number error:{}'.format(str(e))) return return block_num def get_nonce(self, address): """获取账户nonce值""" try: # pending 获得最新已使用的nonce,对nonce进行加1 nonce = len( self.usdtcoin_cli.omni_listpendingtransactions(address)) except Exception as e: logging.error('USDT node get balance error:{}'.format(str(e))) raise Exception('USDT node get balance error') return nonce def get_mian_block_num(self): """获取公链上的最新区块数""" try: header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36', } ret = session_pool.get(self.USDT_BLOCK_NUM, headers=header, timeout=30).json() if ret is None: logging.error('Get usdt main chain block number error') return block_num = ret.get('data') except Exception as e: logging.error( 'Get usdt main chain block number error:{}'.format(e)) return return block_num # int def get_minerFee(self, address): data = {'addr': address} try: balance = None rets = session_pool.post(self.USDT_URL_BALANCE, data=data, timeout=50).json().get('balance') if rets or len(rets) != 0: for ret in rets: if ret.get('propertyinfo') and int( ret.get('propertyinfo').get('propertyid')) == 0: balance = ret.get('value') except Exception as e: logging.error( 'Request USDT_TX_API error address:{},error:{},url:{}'.format( address, str(e), self.USDT_TX_API)) raise Exception('USDT node get balance error') return Decimal(balance) / 100000000 def usdt_transaction_record(self, address, last_timestamp, start_block=None, end_block=None): """查询账户交易记录""" if start_block is None: start_block = 0 if end_block is None: end_block = 99999999 # 可能会有重复记录,使用此方法 run_function = lambda x, y: x if y in x else x + [y] data = {'addr': address, 'page': 0} try: rets = session_pool.post(self.USDT_TX_API, data=data, timeout=50).json() except Exception as e: logging.error( 'Request USDT_TX_API error address:{},error:{},url:{}'.format( address, str(e), self.USDT_TX_API)) rets = None new_records = [] ret = rets.get('transactions') if ret is None: return new_records ret_page_num = int(rets.get('pages')) if ret_page_num == 1: # print(ret_page_num) self.query_records(address, ret, new_records, last_timestamp, start_block, end_block) return (reduce(run_function, [ [], ] + new_records)) else: for i in range(0, ret_page_num): data = {'addr': address, 'page': i} try: ret = session_pool.post( self.USDT_TX_API, data=data, timeout=50).json().get('transactions') except Exception as e: logging.error( 'Request USDT_TX_API error address:{},error:{},url:{}'. format(address, str(e), self.USDT_TX_API)) ret = None if ret is None: return new_records self.query_records(address, ret, new_records, last_timestamp, start_block, end_block) return (reduce(run_function, [ [], ] + new_records)) def query_records(self, address, records, new_records, last_timestamp, start_block, end_block): for record in records: propertyid = record.get('propertyid') valid = record.get('valid') block = record.get('block') if valid and int(propertyid) == 31 and int(start_block) <= int( block) and int(block) <= int(end_block): to_address = record['referenceaddress'] # 是否为收款记录 current_timestamp = int(record['blocktime']) # 当前记录时间戳 confirmations = int(record['confirmations']) # 交易记录确认数 record_hash = record['txid'] amount = Decimal(record['amount']) if to_address.lower() != address.lower(): continue if int(last_timestamp) > int(current_timestamp): continue if Order.hash_is_exist(record_hash): continue if amount < Decimal('0.0000001'): continue if confirmations < 2: break else: new_records.append(record) else: if records is None: logging.error( 'Request USDT_TX_API fail address:{} ret:{}, url:{}'. format(address, str(records), self.USDT_TX_API)) return new_records def hash_get_detail(self, tx_hash): """hash获取交易细节,用于确认链外交易是否被确认""" # 交易是否被确认.status=1(被确认) is_confirm = False # 是否确认 is_success = False # 如果已确认,交易是否成功 msg = None # 未被确认返回异常信息(一般超时),确认失败:失败的细节,确认成功:交易详情 fee = None # 确认成功交易的手续费 try: ret = self.usdtcoin_cli.omni_gettransaction(tx_hash) # 获取交易细节 except Exception as e: msg = str(e) return is_confirm, is_success, msg, fee confirm = ret.get('confirmations') if confirm < 1: # 确认交易失败 msg = dict(fail_detail=str(ret)) return is_confirm, is_success, msg, fee else: # 确认交易成功 is_confirm = True is_success = True fee = ret.get('fee') msg = dict(confirm=str(ret), tx_detail=str(ret)) return is_confirm, is_success, msg, fee def payment(self, addrfrom, addrto, amount): """普通付款""" # 单位换算 payload = {'from': addrfrom, 'to': addrto, 'value': str(amount)} try: # 钱包转账,返回交易哈希值 tx_hash = self.usdtcoin_cli.omni_send(addrfrom, addrto, self.propertyid, str(amount)) return True, tx_hash except Exception as e: payload.update(dict(errormsg=str(e))) logging.error('usdt payment error:{}'.format(str(payload))) return False, str(e) def raw_transaction(self, minerfee_address, fromAddr, toAddre, value, miner_minfee): # 查询USDT未使用的UTXO USDT_unspents = self.usdtcoin_cli.listunspent(1, 9999999, [fromAddr]) if not USDT_unspents: return False, str('No USDT UTXO model available') USDT_unspent = USDT_unspents[0] # 查询BTC未使用的UTXO(矿工费) BTC_unspents = self.usdtcoin_cli.listunspent(1, 9999999, [minerfee_address]) if not BTC_unspents: return False, str('No BTC UTXO model available') BTC_unspent = BTC_unspents[0] # 所用值 from_txid = USDT_unspent['txid'] from_scriptPubKey = USDT_unspent['scriptPubKey'] from_vout = USDT_unspent['vout'] from_amount = USDT_unspent['amount'] to_txid = BTC_unspent['txid'] to_scriptPubKey = BTC_unspent['scriptPubKey'] to_vout = BTC_unspent['vout'] to_amount = BTC_unspent['amount'] rawtransactionparams = [ dict(txid=from_txid, scriptPubKey=from_scriptPubKey, vout=from_vout), dict(txid=to_txid, scriptPubKey=to_scriptPubKey, vout=to_vout), ] # 创建原生BTC交易获取哈希值 RawTxChangeparams = [ # 转出地址必须放在第一个,矿工费地址放在下面 dict(txid=from_txid, scriptPubKey=from_scriptPubKey, vout=from_vout, value=from_amount), dict(txid=to_txid, scriptPubKey=to_scriptPubKey, vout=to_vout, value=to_amount), ] # 构造发送代币类型和代币数量数据 payload = self.usdtcoin_cli.omni_createpayload_simplesend( self.propertyid, str(value)) print('usdt交易', payload) # 构造交易基本数据 data = {} btc_txid = self.usdtcoin_cli.createrawtransaction( rawtransactionparams, data) # 在交易上绑定代币数据 rawtx = self.usdtcoin_cli.omni_createrawtx_opreturn(btc_txid, payload) print('usdt交易绑定到btc交易的哈希', rawtx) # 在交易上添加接收地址 rawtx = self.usdtcoin_cli.omni_createrawtx_reference(rawtx, toAddre) print('添加接受地址', rawtx) # 在交易数据上指定矿工费用 rawtx = self.usdtcoin_cli.omni_createrawtx_change( rawtx, RawTxChangeparams, minerfee_address, Decimal(miner_minfee)) print('设置手续的哈希', rawtx) # 签名 ret = self.usdtcoin_cli.signrawtransaction(rawtx) if not ret['complete']: return False, str('Incomplete signature') # 广播 tx_hash = self.usdtcoin_cli.sendrawtransaction(ret['hex']) print('交易哈希', tx_hash) if tx_hash: return True, tx_hash
r['txid'], "vout": r['vout'], "scriptPubKey": r['scriptPubKey'], "redeemScript": "522103133255e240ded2cd1d0b8fa5b659fd7713b74f6ea074f4a80e3cb1f0677df0612103985457b91195038af91c1c7b09c693e9a141681319b683c46871b2dbf1beb09d52ae" }] print "" print "TX", tx # 2 cents trans = bitcoin.createrawtransaction( tx, { multiaddress: 0.004, company1: 0.0001, company2: 0.0002, company3: 0.0003, company4: 0.0003 }) print trans print "" print "Signing raw transaction" signed1 = bitcoin.signrawtransaction( trans, tx, ["cRuMbJGz3WN7cVzbUe4iLfT7g5hPZX4eoukYeAwdXsVNjkbRBcJ3"]) print signed1 print "" print "Signing raw2 transaction" signed2 = bitcoin.signrawtransaction( signed1['hex'], tx,
class WalletBase: def __init__(self, pay_tx_fee, min_tx_fee, prio_threshold, dust_soft_limit, free_tx_size): self.proxy = None self.pay_tx_fee = pay_tx_fee self.min_tx_fee = min_tx_fee self.prio_threshold = prio_threshold self.dust_soft_limit = dust_soft_limit self.free_tx_size = free_tx_size def set_size(self, base_size, input_size, output_size): self.base_size = base_size self.input_size = input_size self.output_size = output_size def load_config(self, config_path): # trick to load a config file without sections con = open(config_path, 'r').read() dummy_fp = io.StringIO(("[%s]\n" % TMP_SECTION) + con) config = configparser.ConfigParser() config.readfp(dummy_fp) ## utility function def get_conf(key, default=None): if config.has_option(TMP_SECTION, key): return config.get(TMP_SECTION, key) return default self.rpc_user = get_conf('rpcuser') self.rpc_pass = get_conf('rpcpassword') self.rpc_port = int(get_conf('rpcport')) self.rpc_host = get_conf('rpcconnect', '127.0.0.1') if config.has_option(TMP_SECTION, 'paytxfee'): self.pay_tx_fee = int(float(get_conf('paytxfee')) * 10**8) if config.has_option(TMP_SECTION, 'mintxfee'): self.min_tx_fee = int(float(get_conf('mintxfee')) * 10**8) def connect(self): self.proxy = AuthServiceProxy('http://%s:%s@%s:%d/' % (self.rpc_user, self.rpc_pass, self.rpc_host, self.rpc_port)) def get_size(self, inputs, outputs): raw = self.proxy.createrawtransaction(inputs, outputs) return len(raw) / 2 ## Deprecate after official supports for getrawchangeaddress in major coins def get_change_address(self): groups = self.proxy.listaddressgroupings() for group in groups: for entry in group: if len(entry) == 3: ## maybe with account continue elif len(entry) == 2: res = self.proxy.validateaddress(entry[0]) if 'account' not in res: return entry[0] else: raise RuntimeError('never reach') return self.proxy.getnewaddress() ## ref: wallet.cpp CWallet::CreateTransaction def calculate(self, inputs, address, amount, chgaddress): tmp = {address: float(amount) / 10**8, chgaddress: 1 } size = self.get_size(inputs, tmp) total = 0 prio = 0 for inp in inputs: raw = self.proxy.getrawtransaction(inp['txid']) tx = self.proxy.decoderawtransaction(raw) value = tx['vout'][inp['vout']]['value'] conf = self.proxy.gettransaction(inp['txid'])['confirmations'] total += int(value * 10**8) prio += int(value * 10**8) * (conf + 1) prio = int(prio / size) payfee = self.pay_tx_fee * (1 + int(size / 1000)) minfee = self.min_tx_fee * (1 + int(size / 1000)) if prio >= self.prio_threshold and size < self.free_tx_size: minfee = 0 if amount < self.dust_soft_limit: minfee += self.min_tx_fee if total-amount-minfee < self.dust_soft_limit: minfee += self.min_tx_fee fee = max(payfee, minfee) change = total - amount - fee if change <= 0: raise RuntimeError('Insufficient inputs: change = %f' % (float(change) / 10**8)) return { 'total': total, 'fee': fee, 'change': change, 'size': size, 'prio': prio } def send(self, inputs, address, amount): chgaddress = self.get_change_address() res = self.calculate(inputs, address, amount, chgaddress) outputs = { address: float(amount) / 10**8, chgaddress: float(res['change']) / 10**8 } raw = self.proxy.createrawtransaction(inputs, outputs) signed = self.proxy.signrawtransaction(raw) if not signed['complete']: raise RuntimeError('signatures are missing') return self.proxy.sendrawtransaction(signed['hex']) def show_send_info(self, inputs, address, amount): chgaddress = self.get_change_address() res = self.calculate(inputs, address, amount, chgaddress) print('Total amount: %f' % (float(res['total']) / 10**8)) print('Send: %f to %s' % (float(amount) / 10**8, address)) print('Change: %f to %s' % (float(res['change']) / 10**8, chgaddress)) print('Fee: %f' % (float(res['fee']) / 10**8)) print('Size: %d bytes' % res['size']) print('Priority: %d' % res['prio']) def unspent_coins(self): coins = self.proxy.listunspent(6) for c in coins: c['amount'] = int(c['amount'] * 10**8) c['prio'] = c['amount'] * (c['confirmations'] + 1) return coins
def do(self): rpc = AuthServiceProxy('http://' + settings.BITCOIN_RPC_USERNAME + ':' + settings.BITCOIN_RPC_PASSWORD + '@' + settings.BITCOIN_RPC_IP + ':' + str(settings.BITCOIN_RPC_PORT)) # Send all outgoing transactions that are ready to go otxs_to_send = OutgoingTransaction.objects.filter(inputs_selected_at__isnull=False, sent_at=None) for otx in otxs_to_send: # Gather inputs argument inputs = [] for inpt in otx.inputs.all(): inputs.append({ 'txid': inpt.bitcoin_txid, 'vout': inpt.bitcoin_vout, }) # Gather outputs argument outputs = {} for output in otx.outputs.all(): outputs.setdefault(output.bitcoin_address, Decimal(0)) outputs[output.bitcoin_address] += output.amount # Use arguments to create, sign and send raw transaction raw_tx = rpc.createrawtransaction(inputs, outputs) signing_result = rpc.signrawtransaction(raw_tx) raw_tx_signed = signing_result['hex'] if signing_result['complete']: # Calculate how much fee each wallet needs to pay total_fees = otx.calculateFee() fees_for_wallets = [] if total_fees: txs_count = len(otx.txs.all()) for tx in otx.txs.all(): wallet_found = False for fee_for_wallet in fees_for_wallets: if fee_for_wallet['wallet'] == tx.wallet: fee_for_wallet['amount'] += total_fees / txs_count wallet_found = True if not wallet_found: fees_for_wallets.append({ 'wallet': tx.wallet, 'amount': total_fees / txs_count, }) for fee_for_wallet in fees_for_wallets: fee_for_wallet['amount'] = fee_for_wallet['amount'].quantize(Decimal('0.00000001')) fee_receiving_wallet = getOrCreateChangeWallet() fee_receiving_address = fee_receiving_wallet.getOrCreateAddress(0) rpc.sendrawtransaction(raw_tx_signed) # Atomically mark outgoing transaction as send and reduce fees from wallets. with transaction.atomic(): otx.sent_at = now() otx.save(update_fields=['sent_at']) total_effective_fee = Decimal(0) sending_addresses = [] for fee_for_wallet in fees_for_wallets: wallet = fee_for_wallet['wallet'] amount = fee_for_wallet['amount'] # Sending transaction Transaction.objects.create( wallet=wallet, amount=-amount, description='Fee from sent Bitcoins', receiving_address=fee_receiving_address, ) # Reduce funds wallet = Wallet.objects.get(path=wallet.path) wallet.extra_balance -= amount wallet.save(update_fields=['extra_balance']) # Keep track who sent this sending_addresses.append({ 'amount': amount, }) total_effective_fee += amount # Receiving transaction Transaction.objects.create( wallet=fee_receiving_wallet, amount=total_effective_fee, description='Fee refund from sent Bitcoins', sending_addresses=sending_addresses, ) # Add funds fee_receiving_wallet = Wallet.objects.get(path=fee_receiving_wallet.path) fee_receiving_wallet.extra_balance += total_effective_fee fee_receiving_wallet.save(update_fields=['extra_balance']) # Get all outgoing transactions that do not have any inputs selected otxs_without_inputs = OutgoingTransaction.objects.filter(inputs_selected_at=None) # If all outgoing transactions are fine, then do nothing more if otxs_without_inputs.count() == 0: return # TODO: Some lock here might be a good idea, just to be sure! # List all unspent outputs that aren't already assigned to some outgoing transaction unspent_outputs_raw = rpc.listunspent(settings.CONFIRMED_THRESHOLD) unspent_outputs = [] for unspent_output in unspent_outputs_raw: txid = unspent_output['txid'] vout = unspent_output['vout'] if unspent_output['spendable']: # If there is no existing input, then this output isn't assigned yet if OutgoingTransactionInput.objects.filter(bitcoin_txid=txid, bitcoin_vout=vout).count() == 0: unspent_outputs.append(unspent_output) # Assign inputs to those transactions that do not have them set for otx in otxs_without_inputs: # Calculate how much is being sent outputs_total = otx.outputs.aggregate(Sum('amount'))['amount__sum'] or Decimal(0) # Calculate fee tx_size = 148 * otx.inputs.count() + 34 * (otx.outputs.count() + 1) + 10 fee = settings.TRANSACTION_FEE_PER_KILOBYTE * ((tx_size + 999) / 1000) # Now assign inputs until there is enough for outputs inputs_total = otx.inputs.aggregate(Sum('amount'))['amount__sum'] or Decimal(0) while inputs_total < outputs_total + fee and len(unspent_outputs) > 0: # Find unspent output that has most confirmations best_unspent_output = None best_unspent_output_i = None best_unspent_output_confirmations = 0 for unspent_outputs_i in range(len(unspent_outputs)): unspent_output = unspent_outputs[unspent_outputs_i] if unspent_output['confirmations'] > best_unspent_output_confirmations: best_unspent_output = unspent_output best_unspent_output_i = unspent_outputs_i best_unspent_output_confirmations = unspent_output['confirmations'] # Assign this unspent output as input OutgoingTransactionInput.objects.create( tx=otx, amount=best_unspent_output['amount'], bitcoin_txid=best_unspent_output['txid'], bitcoin_vout=best_unspent_output['vout'], ) inputs_total += best_unspent_output['amount'] # Recalculate fee tx_size += 148 fee = settings.TRANSACTION_FEE_PER_KILOBYTE * ((tx_size + 999) / 1000) # Remove the best output from unspent outputs del unspent_outputs[best_unspent_output_i] # If there was no suitable unspent outputs, then it means hot wallet does not # have enough funds for this transaction. We have to give up. Already assigned # inputs are, however, not cleared. Because of this, we have to give up # totally, because this transaction wasted rest of the available outputs. if inputs_total < outputs_total + fee: break # Calculate how much extra there is, and send it back to some of the change # addresses. If the system fails right after this operation, it doesn't matter, # because the inputs and outputs have perfect match, and next runs will do # nothing but set the "inputs_selected_at" timestamp. extra_amount = inputs_total - (outputs_total + fee) if extra_amount > Decimal(0): change_wallet = getOrCreateChangeWallet() change_address = change_wallet.getOrCreateAddress(0) OutgoingTransactionOutput.objects.create(tx=otx, amount=extra_amount, bitcoin_address=change_address.address) # Enough inputs was assigned, so marking this transaction fully assigned otx.inputs_selected_at = now() otx.save(update_fields=['inputs_selected_at'])
amount = min(Decimal(args.max_amt_per_output), na) if ((na - amount) < 10): amount = na addr = b.getnewaddress('consolidate') if (Decimal(str(float(amount))) > 0): if addr not in out: out[addr] = float(0) out[addr] += float(amount) na -= Decimal(str(float(amount))) print 'Paying %s RVN (%s fee) to:' % (sum([ Decimal(str(out[k])) for k in out.keys() ]), amt - sum([Decimal(str(out[k])) for k in out.keys()])) for o in out.keys(): print ' %s %s' % (o, out[o]) txn = b.createrawtransaction(txouts, out) a = raw_input('Sign the transaction? y/[n]: ') if a != 'y': exit(0) signed_txn = b.signrawtransaction(txn) print signed_txn print 'Bytes: %d Fee: %s' % (len(signed_txn['hex']) / 2, amt - sum( [Decimal(str(out[x])) for x in out.keys()])) a = raw_input('Send the transaction? y/[n]: ') if a != 'y': exit(0) txid = b.sendrawtransaction(signed_txn['hex'])
# Get Transaction id and output # of unspent transaction txid = unspent[i]['txid'] vout = unspent[i]['vout'] # Remove the fee from the unspent transaction balance. # The remainder is returned to the senders change_address amount = amount - tx_fee change_address = rpc_connection.getrawchangeaddress() # New transaction input input = [{"txid": txid, "vout": vout}] # New transaction output including amount sent to change_address and the hexadecimal string output = {change_address: amount, "data": hex.decode()} # Create unsigned transaction raw_tx = rpc_connection.createrawtransaction(input, output) # Unlock user wallet before signing, assuming the pass[hrase is stored in environment variables as WALLET_PASS (safe?) rpc_connection.walletpassphrase(os.environ.get("WALLET_PASS"), 100) # Sign transaction and send signed_tx = rpc_connection.signrawtransaction(raw_tx) status = rpc_connection.sendrawtransaction(signed_tx["hex"]) # print the decoded transaction decoded = rpc_connection.decoderawtransaction(signed_tx["hex"]) if signed_tx['complete']: print("status: complete") print("tx info: " + str(decoded)) else: print("error: " + signed_tx['error'])
elif args.command == "send-to-sidechain": cht = os.popen("%s %s -g -r %s -d %s" % (contracthashtool_path, testnet_arg, redeem_script, args.p2shSideAddress)) cht_read = cht.read() nonce = cht_read.split("\n")[0 + is_testnet][7:] full_contract = cht_read.split("\n")[1 + is_testnet][26:] send_address = cht_read.split("\n")[3 + is_testnet][40:] assert(cht.close() == None) if full_contract[0:8] != "50325348": print("You must use a P2SH address") exit(1) print("Sending %s to %s..." % (args.coinAmt, send_address)) print("(nonce: %s)" % nonce) try: tx_hex = bitcoin.createrawtransaction([], {send_address: Decimal(args.coinAmt)}) tx_hex = bitcoin.fundrawtransaction(tx_hex)['hex'] tx = bitcoin.signrawtransaction(tx_hex) assert(tx['complete']) tx_hex = tx['hex'] total_length = len(tx_hex)/2 total_length += 14*32 # maximum length of spv proof 1MB blocks total_length += 1000 # len(full_contract) + len(secondScriptPubKey) and rounded up to 1000 if total_length >= 10000: print("Transaction is too large.") exit(1) txid = bitcoin.sendrawtransaction(tx_hex)
print("Vector ID of Output: ", utxo_vout) print("UTXO Amount........: ", utxo_amt) print("Tx Amount..........: ", recipient_amt) print("Recipient Address..: ", recipient_address) print("Change Address.....: ", change_address) print("Miner Fee..........: ", miner_fee) print("Change Amount......: ", change_amt) print("---------------------------------------------------------------\n") ## 2. Create Raw Transaction txids_vouts = [{"txid": utxo_txid, "vout": utxo_vout}] addresses_amts = { f"{recipient_address}": recipient_amt, f"{change_address}": change_amt } unsigned_tx_hex = rpc_client.createrawtransaction(txids_vouts, addresses_amts) print("---------------------------------------------------------------") print("Unsigned Transaction Hex: ", unsigned_tx_hex) print("---------------------------------------------------------------\n") ## 3. Sign Raw Transaction address_priv_key = [] # list of priv keys of each utxo address_priv_key.append(rpc_client.dumpprivkey(utxo_address)) signed_tx = rpc_client.signrawtransactionwithkey(unsigned_tx_hex, address_priv_key) print("---------------------------------------------------------------") print("Signed Transaction: ") print("----------------------") pprint(signed_tx) print("---------------------------------------------------------------\n")
def check_for_stake(self, RPC, log): try: rpc_connection = AuthServiceProxy("http://%s:%[email protected]:%s"%(RPC['user'], RPC['pw'], RPC['port'])) # Check integrity of wallet before getting wallet info check_wallet = rpc_connection.checkwallet() except: return "Unable to connect to wallet. Verify that it's running and your RPC settings are correct" if 'wallet check passed' not in check_wallet: log.info(check_wallet) rpc_connection.repairwallet() log.info("**Wallet was repaired**") try: txs = rpc_connection.listunspent(int(RPC['min_conf']), int(RPC['max_conf'])) # Only work with inputs that aren't mature except: return "Unable to run 'listunspent' over RPC, check that the wallet is still running" input_sum = 0 utxo_size = Decimal(RPC['UTXO_size']) input_tx = [] addresses_to_reuse = [] for each_tx in txs: # Check out each existing transaction for desired size, sum up inputs that aren't if each_tx['amount'] != utxo_size: input_sum += each_tx['amount'] input_tx.append({"txid":each_tx['txid'],"vout":each_tx['vout']}) if 'account' in each_tx and each_tx['account'] == 'stake_script' and each_tx['address'] not in addresses_to_reuse: # reuse input addresses for a new output if they have the label 'stake_script' addresses_to_reuse.append(each_tx['address']) if input_sum < utxo_size: log.debug("DEBUG: Total coins: {0} is not enough to make a new packet of {1}".format(input_sum, utxo_size)) return "Total coins: {0} is not enough to make a new packet of {1} :DEBUG".format(input_sum, utxo_size) # Reuse or make a new change and stake addresses change_address = rpc_connection.getaddressesbyaccount("change") if len(change_address) == 0: change_address = [rpc_connection.getnewaddress("change")] stake_addresses = rpc_connection.getaddressesbyaccount("stake_script") for addr in stake_addresses: amount = rpc_connection.getreceivedbyaddress(addr) if amount == 0 and addr not in addresses_to_reuse: # Only reuse addresses with the label stake_script and zero balance for safety addresses_to_reuse.append(addr) output_addresses = {} number_of_splits = int(input_sum / utxo_size) if len(addresses_to_reuse) < number_of_splits: # Make as many new addresses as needed to split inputs into 'size' outputs num_to_make = number_of_splits - len(addresses_to_reuse) #if not arg.noconfirm: # TODO implement # print("About to make {0} new stake address(es), confirm".format(num_to_make)) # get_permission() for _ in range(num_to_make): addresses_to_reuse.append(rpc_connection.getnewaddress('stake_script')) for _ in range(number_of_splits): output_addresses[addresses_to_reuse.pop()] = utxo_size #print(output_addresses) assert(int(input_sum / utxo_size) == len(output_addresses)), "Not enough output addresses for number of UTXO splits!" number_of_splits = len(output_addresses) numbytes = 181 * len(input_tx) + 34* (number_of_splits+1) + 10 numKB = math.ceil(numbytes / 1000) TX_FEE = Decimal(RPC['transaction_fee']) * numKB log.debug("transaction fee is %d : %d bytes, fee multiple is %d"%(TX_FEE, numbytes,numKB)) change_amount = input_sum - (utxo_size * number_of_splits) - TX_FEE output_addresses[change_address[0]] = change_amount assert (change_amount > 0), "Change amount cannot be less than zero" assert(change_amount + TX_FEE + (utxo_size*number_of_splits) == input_sum), "Coins will be lost if the total output != input" log.debug("{0} Inputs {1}".format(len(input_tx),input_tx)) log.debug("{0} Outputs {1}".format(len(output_addresses), output_addresses)) log.info("{0} (Input total) = {2} ({1}_UTXO packets) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE)) # Generate, sign, and send the raw transaction raw_tx = rpc_connection.createrawtransaction(input_tx, output_addresses) signed_tx = rpc_connection.signrawtransaction(raw_tx) if not signed_tx['complete']: log.error("Signing failed of raw tranaction: {0}\nInputs: {1}\nOutputs: {2}".format(raw_tx, input_tx, output_addresses)) return "Signing of raw transaction did not complete successfully, make sure wallet is functioning properly" #if not arg.noconfirm: # print("About to send transaction, confirm") # get_permission() log.info("Attempting to send: {0} (Total inputs) = {2} ({1} new UTXO) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE)) try: sent = rpc_connection.sendrawtransaction(signed_tx['hex']) except Exception as e: return "Sending transaction failed (Your wallet might need more time to update): {0}".format(str(e)) log.info("TX successful: transaction ID: {0}".format(sent)) now = datetime.datetime.now().strftime("%m-%d %H:%M") return "{6} TX {5} successful: {0} (Total inputs) = {2} ({1} new UTXO) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE, sent, now)
def generate_valid_source_tx( s: protocol.State, con: AuthServiceProxy, max_tx: int ) -> None: # Transmit enough funds to addresses so that we won't need # to use coinbase transactions. # There are at most MAX many transactions in one step. Hence, # we need at most that many different addresses. (We can always # use the change addresses because our transactions have nearly # no costs) num_addr = max_tx // 10 # We want at most 50 advertisements to use the # same address s.source_tx = [] start = con.getblockcount() + 1 con.generate(num_addr + 101) top = con.getblockcount() interval = range(start, top - 100) block_hashes = con.batch_([["getblockhash", h] for h in interval]) blocks = con.batch_([["getblock", ha, 2] for ha in block_hashes]) del block_hashes txs = [block['tx'][0] for block in blocks] del blocks sent_txs = [] i = 0 value = -1 txid = -1 n = -1 for tx in txs: for out in tx['vout']: if out['scriptPubKey']['type'] == 'pubkey': # The pubkey transactions are coinbase transactions because value = out['value'] txid = tx['txid'] n = out['n'] if value == -1 or txid == -1 or n == -1: raise RuntimeError("No coinbase transaction found.") addr = con.getnewaddress() sent_value = float(value) / 2 # create two addresses per transaction raw_tx = con.createrawtransaction([{'txid': txid, 'vout': n}], { addr: sent_value}) # The - is for the fees funded_tx = con.fundrawtransaction(raw_tx) signed_tx = con.signrawtransactionwithwallet(funded_tx["hex"]) if signed_tx["complete"] is False: raise RuntimeError( "bitcoind could not sign the transaction. (During " "Initialization)") txid = con.sendrawtransaction(signed_tx["hex"]) sent_txs.append(txid) i += 1 # Create a block each 100 transactions if i == 100: con.generate(1) i = 0 con.generate(1) txs = con.batch_([['getrawtransaction', txid, 1] for txid in sent_txs]) for tx in txs: for out in tx['vout']: vout = out['n'] s.source_tx.append(opreturn.Transaction(tx['txid'], vout)) c = 0 for utxo in s.source_tx: if not protocol.is_valid_utxo(utxo): c += 1 print("Found %d invalid utxos." % c)
else: print SendAddress = str(raw_input('发送到哪个地址? (例如33hxAeUqNnFs3gdayu7aAaijhTbbfnphq8) ')) if SendAddress == "33hxAeUqNnFs3gdayu7aAaijhTbbfnphq8": print "太感谢了,你选择捐赠给johnson Diao" print Leftover = int(unspent[WhichTrans]["amount"]*100000000)-HowMuch-SetTxFee print "将要发送您的比特币到这个地址:",SendAddress,"账户里会留下来 ", Leftover," 聪",",这些币会发送到找零地址:",ChangeAddress print "会发送 ",SetTxFee," 聪的网络手续费给矿工" print print "将要创建发送单" rawtransact = bitcoin.createrawtransaction ([{"txid":unspent[WhichTrans]["txid"], "vout":unspent[WhichTrans]["vout"], "scriptPubKey":unspent[WhichTrans]["scriptPubKey"], "redeemScript":unspent[WhichTrans]["redeemScript"]}],{SendAddress:HowMuch/100000000.00,ChangeAddress:Leftover/100000000.00}) print "发送单为:", rawtransact print print print "现在我们要用私钥进行签名" multisigprivkeyone = str(raw_input("请输入第一个私钥:")) print signedone = bitcoin.signrawtransaction (rawtransact, [{"txid":unspent[WhichTrans]["txid"], "vout":unspent[WhichTrans]["vout"],"scriptPubKey":unspent[WhichTrans]["scriptPubKey"], "redeemScript":unspent[WhichTrans]["redeemScript"]}], [multisigprivkeyone]) print "签名结果" print signedone print
fee_rate = get_fee_rate() elif fee_type == "conf_target": conf_target = get_conf_target() # TODO: use a higher amount for pure name transactions? name_amount = Decimal("0.01") print("Name amount is ", name_amount, "NMC") coin_control_enabled, name_new_vin = get_coin_control_inputs() # TODO: find another way to set the label that doesn't use deprecated "account" field? name_new_address = rpc_connection.getnewaddress("Name: " + name_to_register) name_new_vout = {name_new_address: name_amount} # TODO: set locktime and/or replaceable? name_new_create = rpc_connection.createrawtransaction(name_new_vin, name_new_vout) print("name_new create:", rpc_connection.decoderawtransaction(name_new_create)) name_new_name_index = rawtx_output_index(name_new_create, name_new_address) print("name_new_name_index:", name_new_name_index) name_new_op = { "op": "name_new", "name": name_to_register, } name_new_with_name = rpc_connection.namerawtransaction(name_new_create, name_new_name_index, name_new_op)
(contracthashtool_path, testnet_arg, redeem_script, args.p2shSideAddress)) cht_read = cht.read() nonce = cht_read.split("\n")[0 + is_testnet][7:] full_contract = cht_read.split("\n")[1 + is_testnet][26:] send_address = cht_read.split("\n")[3 + is_testnet][40:] assert (cht.close() == None) if full_contract[0:8] != "50325348": print("You must use a P2SH address") exit(1) print("Sending %s to %s..." % (args.coinAmt, send_address)) print("(nonce: %s)" % nonce) try: tx_hex = bitcoin.createrawtransaction( [], {send_address: Decimal(args.coinAmt)}) tx_hex = bitcoin.fundrawtransaction(tx_hex)['hex'] tx = bitcoin.signrawtransaction(tx_hex) assert (tx['complete']) tx_hex = tx['hex'] total_length = len(tx_hex) / 2 total_length += 14 * 32 # maximum length of spv proof 1MB blocks total_length += 1000 # len(full_contract) + len(secondScriptPubKey) and rounded up to 1000 if total_length >= 10000: print("Transaction is too large.") exit(1) txid = bitcoin.sendrawtransaction(tx_hex)
print("Vector ID of Output: ", utxo_vout) print("UTXO Amount........: ", utxo_amt) print("Tx Amount..........: ", recipient_amt) print("Recipient Address..: ", recipient_address) print("Change Address.....: ", change_address) print("Miner Fee..........: ", miner_fee) print("Change Amount......: ", change_amt) print("---------------------------------------------------------------\n") ## create a raw transacion txids_vouts = [{"txid": utxo_txid, "vout": utxo_vout}] addresses_amts = { f"{recipient_address}": recipient_amt, f"{change_address}": change_amt } create_raw_tx = rpc_client.createrawtransaction(txids_vouts, addresses_amts) unsigned_tx_hex = create_raw_tx print("---------------------------------------------------------------") print("Unsigned Transaction Hex: ", unsigned_tx_hex) print("---------------------------------------------------------------\n") ## Check details of the Transaction tx_details = rpc_client.decoderawtransaction(unsigned_tx_hex) print("---------------------------------------------------------------") print("New Transaction Details:") print("-----------------------") pprint(tx_details) print("---------------------------------------------------------------\n") ## Sign Transanciton address_priv_key = [] # list of priv keys of each utxo
data = "@rusticbison" if len(data) > 75: print("Data length is {}".format(len(data))) raise Exception("Too much data, use OP_PUSHDATA1 instead") hex_format_data = binascii.hexlify(data) print(hex_format_data) hexstring = rpc_connection.createrawtransaction( [{ "txid": txid, "vout": vout }], { "data": hex_format_data, new_bitcoin_address: send_amount_string, raw_change_address: change_amount_string }) print("=" * 20) print(hexstring) print("-" * 20) print("address ==>%s" % address) privkey = rpc_connection.dumpprivkey(address) print("/" * 20) sign_raw_transaction = rpc_connection.signrawtransaction( hexstring, [{
for u in allUnspent: inputsList.append({ "txid": u["txid"], "vout": u["vout"], "address": changeAddress }) inputsWithScriptKeysList.append({ "txid": u["txid"], "vout": u["vout"], "scriptPubKey": u["scriptPubKey"] }) # createrawtransaction [{"txid":txid,"vout":n},...] {address:amount,...} print() logger.info("Creating tx hash going to address {}...".format(toAddresses)) createTxHex = rpcConnection.createrawtransaction(inputsList, toAddresses) createTxJson = rpcConnection.decoderawtransaction(createTxHex) if len(createTxHex.strip()) > 0: # pprint(rpcConnection.decodescript(createTxHex)); # pprint(rpcConnection.decoderawtransaction(createTxHex)); createTxID = createTxJson["txid"] logger.info( "TX was successfulling created. TxID is: {}".format(createTxID)) else: logger.error("Failed to create tx. Aborting.") exit() # signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] [sighashtype="ALL"] print() logger.info("Signing tx...") signTxResult = rpcConnection.signrawtransaction(createTxHex,
class BtcWallet(): """btc钱包""" BTC_BLOCK_API = 'https://blockchain.info/' def __init__(self, app=None, consul_client=None): if app and consul_client: self.init_consul(app, consul_client) def init_consul(self, app, consul_client): try: rpc_user = app.config.get('CONFIG_BITCOIND_RPC_USER') rpc_pwd = app.config.get('CONFIG_BITCOIND_RPC_PASSWORD') wallet_passphrase = app.config.get('CONFIG_BITCOIND_WALLET_PASSWORD') self.ipport = consul_client.getRandomOneAvailableServiceIpPort(ConsulServiceName.BTC_CLI) # s = "http://%s:%s@" % (self.user, self.pwd) + self.ipport # print(s) self.bitcoin_cli = AuthServiceProxy( "http://%s:%s@" % (rpc_user, rpc_pwd) + self.ipport, timeout=10) print("Succeed to connect to the BTC node") except Exception as e: print(str(e)) print("Failed to connect to the BTC node") # 是否连接BTC节点 def is_connected(self): try: if self.bitcoin_cli.getwalletinfo().get('walletversion'): return True return False except Exception as e: print(str(e)) print("Failed to connect to the BTC node") # 节点是否同步 def is_sync(self): ret = self.bitcoin_cli.getblockchaininfo() if ret.get('blocks') != ret.get("headers"): return False else: return True # btc地址是否有效 def is_valid_address(self, coin_address): if coin_address is None or coin_address == '': return False else: ret = self.bitcoin_cli.validateaddress(coin_address).get('isvalid') print('账户检查结果:', ret) return ret # return self.bitcoin_cli.validateaddress(coin_address).get('isvalid') # 获取账户余额, 默认经过6个区块确认 def get_balance(self, coin_address): transaction_lists = self.bitcoin_cli.listunspent(1, 99999999, [coin_address]) print(transaction_lists) current_amount = 0 for transaction_list in transaction_lists: amount = transaction_list.get('amount') amount = float(amount) current_amount += amount return current_amount def get_balance_by_account(self, account): try: ret = self.bitcoin_cli.getbalance(account) return ret except Exception as e: logging.error('get balance error:{}'.format(str(e))) return None def estimate_fee(self): try: fee = self.bitcoin_cli.estimatefee(6) return fee except Exception as e: logging.error('get fee error:{}'.format(str(e))) return None def create_account(self, stellar_account): # private = random_key() # address = pubtoaddr(privtopub(private)) # print(address, private) # return address, private address = self.bitcoin_cli.getnewaddress(stellar_account) private_key = self.bitcoin_cli.dumpprivkey(address) return address, private_key def get_block_num(self): """获取最新区块数""" try: block_num = self.bitcoin_cli.getblockcount() return block_num except Exception as e: logging.error('Get btc node block number error:{}'.format(str(e))) return None def get_chain_info(self): ret = self.bitcoin_cli.getblockchaininfo() return ret def get_block_info(self, block_num): """获取区块的详细信息""" param = "block-height/{}?format=json".format(block_num) api_url = self.BTC_BLOCK_API + param # print(api_url) blocks = requests.get(api_url, timeout=500).json() # print(type(blocks)) return blocks # 链外转帐,普通交易 def payment(self, btc_base_account, address_to, amount): try: txid = self.bitcoin_cli.sendfrom(btc_base_account, address_to, amount) return True, txid except Exception as e: logging.error('btc payment error:{}'.format(str(e))) return False, str(e) def hash_get_detail(self, tx_id): """ Arguments: 1. "txid" (string, required) The transaction id """ # 根据txid获取确认链外交易信息 ret = self.bitcoin_cli.gettransaction(tx_id) abandoned = ret.get("details")[0].get("abandoned") # 获取abandon信息 confirmation_num = ret.get('confirmations') # 获取确认数 # 如果确认数小于1,则未确认 if confirmation_num < 1: msg = dict(confirm=str(ret)) # msg = ret.get("details")[0] return False, False, msg, None # 如果确认数大于1,则确认 else: msg = dict(confirm=str(ret)) # msg = ret fee = abs(ret.get("fee")) if abandoned: return True, False, msg, None else: return True, True, msg, fee def raw_payment(self, address_from, address_to, collect_amount): inputs = [] # 获取地址余额信息 try: unspend_lists = self.bitcoin_cli.listunspent(1, 9999999, [address_from]) for unspend_list in unspend_lists: # if unspend_list.get('amount') <= 0: # continue # else: txid = unspend_list.get('txid') vout = unspend_list.get('vout') inputs.append({'txid': txid, 'vout': vout}) outputs = {address_to: round(collect_amount, 8)} # 交易建立和签名时不用连接比特币网络,只有在执行交易时才需要将交易发送到网络 # 创建裸交易 transaction_hash = self.bitcoin_cli.createrawtransaction(inputs, outputs) # 使用私钥签名,获取16进制信息 hex = self.bitcoin_cli.signrawtransaction(transaction_hash).get('hex') # 广播到p2p网络,返回交易哈希 trading_hash = self.bitcoin_cli.sendrawtransaction(hex, False) return True, trading_hash, '' except Exception as e: print(e) return None, None, '' def btc_transaction_record(self, block_num): # 获取某一区块信息 block_info = self.get_block_info(block_num) blocks = block_info.get('blocks') txs = blocks[0].get('tx') records = [] for tx in txs: outs = tx.get('out') hash = tx.get('hash') inputs = tx.get('inputs') p_out = inputs[0].get('prev_out') if not p_out: continue else: addr_from = p_out.get('addr') for out in outs: re = [] addr_to = out.get('addr') value = out.get('value') / (10 ** 8) # addr_to与User表中绑定的地址进行对比,如果有,则说明此address_to有冲币记录 user = User.address_query_user('BTC', addr_to) if not user: continue else: re.append(addr_from) re.append(addr_to) re.append(value) re.append(hash) records.append(re) return records def get_accounts(self, addr): try: ad = self.bitcoin_cli.getaccount(addr) return ad except Exception as e: # logging.error('get btc_account error:{}'.format(str(e))) return None def get_address_byaccount(self, account): re = self.bitcoin_cli.getaddressesbyaccount(account) return re def test1(self): transaction_list = self.bitcoin_cli.listaccounts() # transaction_list = self.bitcoin_cli.getwalletinfo() print(transaction_list)
# Create outputs my_addr = utxo["address"] change = input_value - burn_amount - fee op_return = payment_details.outputs[0].script[2:].hex() outputs = [ { "data": op_return }, { my_addr: change # Change output } ] # Create tx raw_tx_unsigned = rpc_connection.createrawtransaction(inputs, outputs) signed_tx = rpc_connection.signrawtransactionwithwallet(raw_tx_unsigned) signed_raw_tx = bytes.fromhex(signed_tx["hex"]) # Construct payment message payment = Payment(merchant_data=payment_details.merchant_data, transactions=[signed_raw_tx]) payment_raw = payment.SerializeToString() print("Sending Payment...") # Send payment payment_url = BASE_URL_A + payment_details.payment_url headers = { "Content-Type": "application/bitcoincash-payment", "Accept": "application/bitcoincash-paymentack" }
class RawTxn: def __init__(self, rpc_user, rpc_password, rpc_port, transfer_info_filepath: str, label: str): global network_port_map_g #self.rpc_connection = rpc_connection self.transfer_info_filepath = transfer_info_filepath # print('rpc_user = %s' % rpc_user) # print('rpc_password = %s' % rpc_password) # print('rpc_port = %d' % rpc_port) self.rpc_connection = AuthServiceProxy( "http://%s:%[email protected]:%d" % (rpc_user, rpc_password, rpc_port)) self.inuseAddressMap = None self.label = label def getInputsForAddress(self, address: str): inputs = [] # print('address = %s' % address) if self.inuseAddressMap == None: unspent_list = [ unspent for unspent in self.rpc_connection.listunspent() if unspent['label'] == self.label ] self.setInuseAddressMap(unspent_list) # print('inuse_address_map[%s] = %s' % (address, self.inuse_address_map[address])) for txn in self.inuse_address_map[address]: # print('txn = %s' % txn) for vout_amount_map in self.inuse_address_map[address][txn]: value = vout_amount_map['amount'] out_index = vout_amount_map['vout'] inputs.append({ 'txid': txn, 'vout': out_index, 'address': address, 'value': value }) return inputs def setInuseAddressMap(self, unspent_list: list): self.inuse_address_map = {} for unspent in unspent_list: address = unspent['address'] if address not in self.inuse_address_map: self.inuse_address_map[address] = {} txid = unspent['txid'] if txid not in self.inuse_address_map[address]: self.inuse_address_map[address][txid] = [] vout = unspent['vout'] amount = unspent['amount'] self.inuse_address_map[address][txid].append({ 'vout': vout, 'amount': float(amount) }) def getNetworkInfo(self): networkinfo = self.rpc_connection.getnetworkinfo() network_client, version = networkinfo['subversion'].split( '/')[1].split(':') if network_client == 'Satoshi': network = 'bitcoin' print('Network = bitcoin') elif network_client == 'LitecoinCore': network = litecoin print('Network = litecoin') else: print('Network client: %s is not supported' % network_client) exit() return network, version def checkAddressIsReused(self, address: str, network): if network == 'bitcoin': res = requests.get('https://blockchain.info/rawaddr/' + address) jsonobj = json.loads(res.text) return (jsonobj['total_sent'] != 0) elif network == 'litecoin': res = requests.get('https://chain.so/api/v2/address/LTC/' + address) jsonobj = json.loads(res.text) return (jsonobj['data']['received_value'] != jsonobj['data']['balance']) else: print('Network client: %s is not supported' % network_client) exit() def getInputs(self, amount: float): global inuse_address_value_map_g # print('********** target value = %f' % amount) if len(inuse_address_value_map_g) == 0: unspent_list = [ unspent for unspent in self.rpc_connection.listunspent() if unspent['label'] == self.label ] self.setInuseAddressMap(unspent_list) # print('Inuse addresses are 0') setInuseAddressValueMap(self.inuse_address_map) # print('************* inuse_address_value_map = %s' % inuse_address_value_map_g) inputs = [] value = 0 address_value_map = [{ 'address': address, 'amount': address_value } for address, address_value in inuse_address_value_map_g.items()] network, _ = self.getNetworkInfo() allocated_address_value_map = [] for address_value in address_value_map: if self.checkAddressIsReused(address_value['address'], network) == True: allocated_address_value_map.append(address_value) amount = amount - address_value['amount'] address_inputs = self.getInputsForAddress( address_value['address']) inputs.extend(address_inputs) for allocated_address_value in allocated_address_value_map: address_value_map.remove(allocated_address_value) address_value_map = sorted(address_value_map, key=lambda k: k['amount']) # print('sorted address value map = %s' % address_value_map) if amount > 0: remaining_amount = amount for address_value in address_value_map: if address_value['amount'] < remaining_amount: address_inputs = self.getInputsForAddress( address_value['address']) inputs.extend(address_inputs) remaining_amount -= address_value['amount'] else: address_inputs = self.getInputsForAddress( address_value_map[-1]['address']) inputs.extend(address_inputs) remaining_amount -= address_value['amount'] break if remaining_amount > 0: print('Error: Insufficient Balance') return None # print('inputs = %s' % inputs) return inputs def getInputsForAddressList(self, address_list: list): inputs = [] for address in address_list: address_inputs = self.getInputsForAddress(address) inputs.extend(address_inputs) # print('inputs = %s' % inputs) return inputs def getAmountFromInputs(self, inputs: list): reduce(lambda x, y: x + y, [inp[amount] for inp in inputs]) def estimatefee(self, raw_txn: bytes, fee_rate: float): vbytes = calculateVBytes(raw_txn) # print('vbytes = %f' % vbytes) estimated_fee = round(fee_rate * (vbytes / 1000), 8) # print('vbytes = %f' % vbytes) # print('estimated_fee = %f' % estimated_fee) return vbytes, estimated_fee # def getRawTransaction(self, inputs: list, outs: list, change_address: str, fee_rate: float, jsonobj: dict): ## print('fee_rate = %f' % fee_rate) # # tx_ins = [{'txid': inp['txid'], 'vout': inp['vout']} for inp in inputs] # # # first get raw transaction without change ## print('111111111: tx_ins = %s, outs = %s' % (tx_ins, outs)) # raw_txn = self.rpc_connection.createrawtransaction(tx_ins, outs) # # vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) # target_value = getTargetValue(outs) # #target_addresses = list(outs) # # input_value = getInputValue(inputs) # # change_value = round(input_value - target_value - estimated_fee, 8) # # # if change_value is not 0 then estimated_fee and change_value are wrong # if change_value == 0: # jsonobj['Raw Txn'] = raw_txn # jsonobj['Inputs'] = inputs # # return jsonobj # # new_outs = deepcopy(outs) # new_outs.append({change_address: round(change_value, 8)}) ## print('2222222222: tx_ins = %s, new_outs = %s' % (tx_ins, new_outs)) ## print('estimated_fee = %f' % estimated_fee) # raw_txn = self.rpc_connection.createrawtransaction(tx_ins, new_outs) # vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) # change_value = round(input_value - target_value - estimated_fee, 8) # while change_value < 0: # inputs = self.getInputs(round(target_value + estimated_fee, 8)) # tx_ins = [{'txid': inp['txid'], 'vout': inp['vout']} for inp in inputs] ## print('33333333333: tx_ins = %s, outs = %s' % (tx_ins, outs)) ## print('estimated_fee = %f' % estimated_fee) # raw_txn = self.rpc_connection.createrawtransaction(tx_ins, new_outs) # vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) # input_value = getInputValue(inputs) # # change_value = round(input_value - target_value - estimated_fee, 8) # new_outs = deepcopy(outs) # new_outs.append({change_address: round(change_value, 8)}) ## print('44444444444444: tx_ins = %s, new_outs = %s' % (tx_ins, new_outs)) ## print('estimated_fee = %f' % estimated_fee) # raw_txn = self.rpc_connection.createrawtransaction(tx_ins, new_outs) ## print('raw txn = %s' % raw_txn) # # jsonobj['Raw Txn'] = raw_txn # jsonobj['Inputs'] = inputs # jsonobj['VBytes'] = vbytes # # return jsonobj def getRawTransaction(self, inputs: list, outs: dict, change_address: str, fee_rate: float, jsonobj: dict): # print('fee_rate = %f' % fee_rate) tx_ins = [{'txid': inp['txid'], 'vout': inp['vout']} for inp in inputs] # first get raw transaction without change # print('111111111: tx_ins = %s, outs = %s' % (tx_ins, outs)) raw_txn = self.rpc_connection.createrawtransaction(tx_ins, outs) vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) target_value = getTargetValue(outs) #target_addresses = list(outs) input_value = getInputValue(inputs) change_value = round(input_value - target_value - estimated_fee, 8) # if change_value is not 0 then estimated_fee and change_value are wrong if change_value == 0: jsonobj['Raw Txn'] = raw_txn jsonobj['Inputs'] = inputs return jsonobj new_outs = deepcopy(outs) new_outs[change_address] = round(change_value, 8) # print('2222222222: tx_ins = %s, new_outs = %s' % (tx_ins, new_outs)) # print('estimated_fee = %f' % estimated_fee) raw_txn = self.rpc_connection.createrawtransaction(tx_ins, new_outs) vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) change_value = round(input_value - target_value - estimated_fee, 8) while change_value < 0: inputs = self.getInputs(round(target_value + estimated_fee, 8)) tx_ins = [{ 'txid': inp['txid'], 'vout': inp['vout'] } for inp in inputs] # print('33333333333: tx_ins = %s, outs = %s' % (tx_ins, outs)) # print('estimated_fee = %f' % estimated_fee) raw_txn = self.rpc_connection.createrawtransaction( tx_ins, new_outs) vbytes, estimated_fee = self.estimatefee( binascii.unhexlify(raw_txn), fee_rate) input_value = getInputValue(inputs) change_value = round(input_value - target_value - estimated_fee, 8) new_outs = deepcopy(outs) new_outs[change_address] = round(change_value, 8) # print('44444444444444: tx_ins = %s, new_outs = %s' % (tx_ins, new_outs)) # print('estimated_fee = %f' % estimated_fee) raw_txn = self.rpc_connection.createrawtransaction(tx_ins, new_outs) # print('raw txn = %s' % raw_txn) jsonobj['Raw Txn'] = raw_txn jsonobj['Inputs'] = inputs jsonobj['VBytes'] = vbytes return jsonobj # def getRawTxnFromOuts(self, txout: list, change_address: str, fee_rate: float, jsonobj: dict): # target_value = getTargetValue(txout) # inputs = self.getInputs(target_value) # return self.getRawTransaction(inputs, txout, change_address, fee_rate, jsonobj) def getRawTxnFromOuts(self, txout: dict, change_address: str, fee_rate: float, jsonobj: dict): target_value = getTargetValue(txout) inputs = self.getInputs(target_value) return self.getRawTransaction(inputs, txout, change_address, fee_rate, jsonobj) def getRawTxnToDivideFunds(self, input_addresses: list, out_addresses: list, fee_rate: float, jsonobj: dict): # print('fee_rate = %f' % fee_rate) inputs = self.getInputsForAddressList(input_addresses) input_value = getInputValue(inputs) each_out_value = round(input_value / len(out_addresses), 8) outs = dict([(address, each_out_value) for address in out_addresses]) tx_ins = [{'txid': inp['txid'], 'vout': inp['vout']} for inp in inputs] # first get raw transaction without change # print('111111111: tx_ins = %s, outs = %s' % (tx_ins, outs)) raw_txn = self.rpc_connection.createrawtransaction(tx_ins, outs) vbytes, estimated_fee = self.estimatefee(binascii.unhexlify(raw_txn), fee_rate) each_out_value = round( (input_value - estimated_fee) / len(out_addresses), 8) outs = dict([(address, each_out_value) for address in out_addresses]) # second get raw transaction without change # print('22222222: tx_ins = %s, outs = %s' % (tx_ins, outs)) raw_txn = self.rpc_connection.createrawtransaction(tx_ins, outs) # print('raw txn = %s' % raw_txn) jsonobj['Raw Txn'] = raw_txn jsonobj['Inputs'] = inputs jsonobj['VBytes'] = vbytes return jsonobj
total_in = 0; unspent.sort (key=lambda coin: abs(to_satoshi (coin['amount']) - target_in)); for coin in unspent: total_in += to_satoshi (coin['amount']); donation += donation_per_input; inputs.append (dict (txid = coin['txid'], vout = coin['vout'])); if total_in > target_in: break; if donation < donation_minimum: donation = donation_minimum; # FIND OUTPUTS outputs = dict (); outputs[donation_address] = from_satoshi (donation); total_in -= donation; while total_in > target_out: outputs[service.getnewaddress()] = from_satoshi (target_out); total_in -= target_out; outputs[service.getnewaddress()] = from_satoshi (total_in); # Make the transaction print service.createrawtransaction (inputs, outputs);
class DucatuscoreInterface: endpoint = None settings = None def __init__(self): self.settings = NETWORK_SETTINGS['DUC'] self.setup_endpoint() self.rpc = AuthServiceProxy(self.endpoint) self.check_connection() def setup_endpoint(self): self.endpoint = 'http://{user}:{pwd}@{host}:{port}'.format( user=self.settings['user'], pwd=self.settings['password'], host=self.settings['host'], port=self.settings['port']) return def check_connection(self): block = self.rpc.getblockcount() if block and block > 0: return True else: raise Exception('Ducatus node not connected') def transfer(self, address, amount): try: value = amount / DECIMALS['DUC'] logger.info(msg=f'try sending {value} DUC to {address}') self.rpc.walletpassphrase(self.settings['wallet_password'], 30) res = self.rpc.sendtoaddress(address, value) logger.info(msg=res) return res except JSONRPCException as e: err = f'DUCATUS TRANSFER ERROR: transfer for {amount} DUC for {address} failed' logger.error(msg=err) logger.error(msg=e) raise DucatuscoreInterfaceException(err) def validate_address(self, address): for attempt in range(10): logger.info(msg=f'attempt {attempt}') try: rpc_response = self.rpc.validateaddress(address) except RemoteDisconnected as e: logger.error(msg=e) rpc_response = False if not isinstance(rpc_response, bool): logger.info(msg=rpc_response) break else: raise Exception('cannot validate address with 10 attempts') return rpc_response['isvalid'] def get_unspent(self, tx_hash, count): return self.rpc.gettxout(tx_hash, count) def get_fee(self): return self.rpc.getinfo()['relayfee'] def get_unspent_input(self, tx_hash, payment_address): last_response = {} count = 0 while isinstance(last_response, dict): rpc_response = self.get_unspent(tx_hash, count) last_response = rpc_response input_addresses = rpc_response['scriptPubKey']['addresses'] if payment_address in input_addresses: return rpc_response, count count += 1 def internal_transfer(self, tx_list, address_from, address_to, amount, private_key): logger.info(msg='start raw tx build') logger.info( msg= f'tx_list {tx_list} from {address_from} to {address_to} amount {amount}' ) try: input_params = [] for payment_hash in tx_list: unspent_input, input_vout_count = self.get_unspent_input( payment_hash, address_from) logger.info(msg=f'unspent input {unspent_input}') input_params.append({ 'txid': payment_hash, 'vout': input_vout_count }) transaction_fee = self.get_fee() * DECIMALS['DUC'] send_amount = (Decimal(amount) - transaction_fee) / DECIMALS['DUC'] logger.info(msg=f'input_params {input_params}') output_params = {address_to: send_amount} logger.info(msg=f'output_params {output_params}') tx = self.rpc.createrawtransaction(input_params, output_params) logger.info(msg=f'raw tx {tx}') signed = self.rpc.signrawtransaction(tx, None, [private_key]) logger.info(msg=f'signed tx {signed}') tx_hash = self.rpc.sendrawtransaction(signed['hex']) logger.info(msg=f'tx {tx_hash}') return tx_hash except JSONRPCException as e: logger.error( msg= f'DUCATUS TRANSFER ERROR: transfer for {amount} DUC for {address_to} failed' ) logger.error(msg=e) raise DucatuscoreInterfaceException(e) def get_balance(self): return int(self.rpc.getbalance('') * DECIMALS['DUC'])
def submit_raw(rpc_user, rpc_password, rpc_host, send_addr=None, recv_addr=None, send_amount=None): rpc_connection = AuthServiceProxy("http://{}:{}@{}".format( rpc_user, rpc_password, rpc_host)) # ... #rpc_connection.walletpassphrase("openos", 10) # validate address ret = rpc_connection.validateaddress(recv_addr) if recv_addr else {} # ... first_unspent = rpc_connection.listunspent()[0] print(first_unspent) address = first_unspent.get("address") scriptPubKey = first_unspent.get("scriptPubKey") redeemScript = first_unspent.get("redeemScript") txid = first_unspent.get("txid") vout = first_unspent.get("vout") #first_unspent_amount = Decimal(first_unspent.get("amount")) #username = rpc_connection.getaccountaddress(send_addr) #print(username) username = '******' first_unspent_amount = Decimal(rpc_connection.getbalance(username)) raw_change_address = rpc_connection.getrawchangeaddress() new_bitcoin_address = recv_addr if recv_addr else rpc_connection.getnewaddress( ) print("raw_change_address [{}]".format(raw_change_address)) fee_obj = rpc_connection.estimatesmartfee(6) fee = fee_obj.get("feerate") # check if send_amount: print(first_unspent_amount, fee, send_amount) change_amount = first_unspent_amount - fee - send_amount else: send_amount = first_unspent_amount / 2 change_amount = first_unspent_amount / 2 - fee if change_amount < 0.00001: print(change_amount) raise Exception("Insufficient funds") change_amount_string = "%.8f" % change_amount send_amount_string = "%0.8f" % send_amount data = "@landpack" if len(data) > 75: print("Data length is {}".format(len(data))) raise Exception("Too much data, use OP_PUSHDATA1 instead") hex_format_data = binascii.hexlify(data) hexstring = rpc_connection.createrawtransaction( [{ "txid": txid, "vout": vout }], { "data": hex_format_data, new_bitcoin_address: send_amount_string, raw_change_address: change_amount_string }) privkey = rpc_connection.dumpprivkey(address) sign_raw_transaction = rpc_connection.signrawtransaction( hexstring, [{ "txid": txid, "vout": vout, "redeemScript": redeemScript, "scriptPubKey": scriptPubKey, "amount": first_unspent_amount }], [privkey]) raw_hash = sign_raw_transaction.get("hex") ret = rpc_connection.sendrawtransaction(raw_hash) return ret
class CryptoEngineBitcoin(CryptoEngine): BITCOIN_FEE = 0.0001 BITCOIN_FINAL_CONFIRMATIONS = 6 def __init__(self, url=None, path=None): super().__init__() self.rpc = AuthServiceProxy(url) def certify(self, data: bytes) -> str: #if len(data) <1 or len(data) > 32: # raise ValueError("data length must be > 0 and <= 32") blockchain_payload = DATA_PREFIX.encode() + data avail_coin = self.__get_available_coin() if avail_coin is None: raise ValueError("No coin available") inputs = [{'txid': avail_coin['txid'], 'vout': avail_coin['vout']}] outputs = {'data': binascii.hexlify(blockchain_payload).decode(), avail_coin['address']: avail_coin['amount'] - decimal.Decimal(self.BITCOIN_FEE)} rawtrans = self.rpc.createrawtransaction(inputs, outputs) #print("RAW Transaction: %s" % rawtrans) signedtrans = self.rpc.signrawtransaction(rawtrans) #print("Signed transaction: %s" % signedtrans) if not signedtrans['complete']: raise RuntimeError("Error signing transaction: %s" % (signedtrans)) txid = self.rpc.sendrawtransaction(signedtrans['hex']) #print("Transaction sent, TXID: %s" % txid) return txid def __get_available_coin(self): unspent = self.rpc.listunspent() target = None #print("# of unspent entries: %d" % len(unspent)) for i in range(0, len(unspent)): ue = unspent[i] #print("UE: %s" % ue) if ue['spendable'] and ue['amount'] >= self.BITCOIN_FEE: #print("Spendable entry found: %s" % ue) target = ue break return target def __get_fee(self): pass def check_cert(self, data: bytes): return True def cert_status(self, txid: str): tx = self.rpc.gettransaction(txid) if tx is None: return self.generate_result(STATUS_NOT_FOUND, "TX not found") confirmations = tx['confirmations'] status = -1 msg = None if confirmations == 0: status = STATUS_IN_MEMPOOL msg = "In mempool" elif confirmations < self.BITCOIN_FINAL_CONFIRMATIONS: status = STATUS_PARTIALLY_CONFIRMED msg = "Partially confirmed: %d" % confirmations else: status = STATUS_CONFIRMED msg = "Confirmed: %d" % confirmations result = super().generate_result(status, msg, confirmations) return result def unlock(self, password = None, timeout = None) -> bool: self.rpc.walletpassphrase(password, timeout) return self.is_locked() def lock(self): return self.rpc.walletlock() def is_locked(self) -> bool: code = None try: self.rpc.signmessage("", "") except JSONRPCException as err: code = err.code if code is None or code == -3: return False return True