def get_tx_data(tx_hex): """Accepts unsigned transactions.""" tx = bitcoin.rpc('decoderawtransaction', [tx_hex]) # Get destination output and data output. destination, btc_amount, data = None, None, b'' for vout in tx['vout']: # Sum data chunks to get data. (Can mix OP_RETURN and multi-sig.) asm = vout['scriptPubKey']['asm'].split(' ') if asm[0] == 'OP_RETURN' and len(asm) == 2: # OP_RETURN data_chunk = binascii.unhexlify(bytes(asm[1], 'utf-8')) data += data_chunk elif asm[0] == '1' and asm[3] == '2' and asm[ 4] == 'OP_CHECKMULTISIG': # Multi-sig data_pubkey = binascii.unhexlify(bytes(asm[2], 'utf-8')) data_chunk_length = data_pubkey[0] # No ord() necessary?! data_chunk = data_pubkey[1:data_chunk_length + 1] data += data_chunk # Destination is the first output before the data. if not destination and not btc_amount and not data: if 'addresses' in vout['scriptPubKey']: address = vout['scriptPubKey']['addresses'][0] if bitcoin.base58_decode( address, config.ADDRESSVERSION): # If address is valid... destination, btc_amount = address, round( D(vout['value']) * config.UNIT) continue return destination, btc_amount, data
def get_tx_data (tx_hex): """Accepts unsigned transactions.""" tx = bitcoin.rpc('decoderawtransaction', [tx_hex]) # Get destination output and data output. destination, btc_amount, data = None, None, b'' for vout in tx['vout']: # Sum data chunks to get data. (Can mix OP_RETURN and multi-sig.) asm = vout['scriptPubKey']['asm'].split(' ') if asm[0] == 'OP_RETURN' and len(asm) == 2: # OP_RETURN data_chunk = binascii.unhexlify(bytes(asm[1], 'utf-8')) data += data_chunk elif asm[0] == '1' and asm[3] == '2' and asm[4] == 'OP_CHECKMULTISIG': # Multi-sig data_pubkey = binascii.unhexlify(bytes(asm[2], 'utf-8')) data_chunk_length = data_pubkey[0] # No ord() necessary?! data_chunk = data_pubkey[1:data_chunk_length + 1] data += data_chunk # Destination is the first output before the data. if not destination and not btc_amount and not data: if 'addresses' in vout['scriptPubKey']: address = vout['scriptPubKey']['addresses'][0] if bitcoin.base58_decode(address, config.ADDRESSVERSION): # If address is valid... destination, btc_amount = address, round(D(vout['value']) * config.UNIT) continue return destination, btc_amount, data
def parse_hex(unsigned_tx_hex): tx = bitcoin.rpc('decoderawtransaction', [unsigned_tx_hex]) source, destination, btc_amount, fee, data = blocks.get_tx_info(tx) cursor = db.cursor() tx_hash = hashlib.sha256(chr(tx_index).encode('utf-8')).hexdigest() global tx_index block_index = config.BURN_START + tx_index block_hash = hashlib.sha512(chr(block_index).encode('utf-8')).hexdigest() block_time = block_index * 10000000 cursor.execute( '''INSERT INTO blocks( block_index, block_hash, block_time) VALUES(?,?,?)''', (block_index, block_hash, block_time)) cursor.execute( '''INSERT INTO transactions( tx_index, tx_hash, block_index, block_time, source, destination, btc_amount, fee, data) VALUES(?,?,?,?,?,?,?,?,?)''', (tx_index, tx_hash, block_index, tx_index, source, destination, btc_amount, fee, data)) cursor.execute( '''SELECT * FROM transactions \ WHERE tx_index=?''', (tx_index, )) tx = cursor.fetchall()[0] blocks.parse_tx(db, tx) # After parsing every transaction, check that the credits, debits sum properly. cursor.execute('''SELECT * FROM balances''') for balance in cursor.fetchall(): amount = 0 cursor.execute( '''SELECT * FROM debits \ WHERE (address = ? AND asset = ?)''', (balance['address'], balance['asset'])) for debit in cursor.fetchall(): amount -= debit['amount'] cursor.execute( '''SELECT * FROM credits \ WHERE (address = ? AND asset = ?)''', (balance['address'], balance['asset'])) for credit in cursor.fetchall(): amount += credit['amount'] assert amount == balance['amount'] tx_index += 1 cursor.close()
def get_tx_data (tx_hex): """Accepts unsigned transactions.""" tx = bitcoin.rpc('decoderawtransaction', [tx_hex])['result'] # Loop through outputs until you come upon OP_RETURN, then get the data. # NOTE: This assumes only one OP_RETURN output. data = None for vout in tx['vout']: asm = vout['scriptPubKey']['asm'].split(' ') if asm[0] == 'OP_RETURN' and len(asm) == 2: data = binascii.unhexlify(asm[1]) return data
def market (give_asset, get_asset): os.system('cls' if os.name=='nt' else 'clear') # Open orders. orders = util.get_orders(db, validity='Valid', show_expired=False, show_empty=False) table = PrettyTable(['Give Quantity', 'Give Asset', 'Get Quantity', 'Get Asset', 'Price', 'Price Assets', 'Fee', 'Time Left', 'Tx Hash']) for order in orders: if give_asset and order['give_asset'] != give_asset: continue if get_asset and order['get_asset'] != get_asset: continue order = format_order(order) table.add_row(order) print('Open Orders') print(str(table.get_string(sortby='Price'))) print('\n') # Open bets. bets = util.get_bets(db, validity='Valid', show_expired=False, show_empty=False) table = PrettyTable(['Bet Type', 'Feed Address', 'Deadline', 'Target Value', 'Leverage', 'Wager', 'Counterwager', 'Odds', 'Time Left', 'Tx Hash']) for bet in bets: bet = format_bet(bet) table.add_row(bet) print('Open Bets') print(str(table)) print('\n') # Matched orders awaiting BTC payments from you. my_addresses = [ element['address'] for element in bitcoin.rpc('listreceivedbyaddress', [0,True])['result'] ] awaiting_btcs = util.get_order_matches(db, validity='Valid: awaiting BTC payment', addresses=my_addresses, show_expired=False) table = PrettyTable(['Matched Order ID', 'Time Left']) for order_match in awaiting_btcs: order_match = format_order_match(order_match) table.add_row(order_match) print('Order Matches Awaiting BTC Payment') print(str(table)) print('\n') # Feeds broadcasts = util.get_broadcasts(db, validity='Valid', order_by='timestamp DESC') table = PrettyTable(['Feed Address', 'Timestamp', 'Text', 'Value', 'Fee Multiplier']) seen_addresses = [] for broadcast in broadcasts: # Always show only the latest broadcast from a feed address. if broadcast['source'] not in seen_addresses: feed = format_feed(broadcast) table.add_row(feed) seen_addresses.append(broadcast['source']) else: continue print('Feeds') print(str(table)) time.sleep(30)
def parse_hex (unsigned_tx_hex): tx = bitcoin.rpc('decoderawtransaction', [unsigned_tx_hex]) source, destination, btc_amount, fee, data = blocks.get_tx_info(tx) parse_hex_cursor = db.cursor() tx_hash = hashlib.sha256(chr(tx_index).encode('utf-8')).hexdigest() global tx_index parse_hex_cursor.execute('''INSERT INTO transactions( tx_index, tx_hash, block_index, block_time, source, destination, btc_amount, fee, data) VALUES(?,?,?,?,?,?,?,?,?)''', (tx_index, tx_hash, tx_index, tx_index, source, destination, btc_amount, fee, data) ) parse_hex_cursor.execute('''SELECT * FROM transactions \ WHERE tx_index=?''', (tx_index,)) tx = parse_hex_cursor.fetchall()[0] heaps = blocks.init_heaps(db) blocks.parse_tx(db, tx, heaps) # After parsing every transaction, check that the credits, debits sum properly. cursor.execute('''SELECT * FROM balances''') for balance in cursor.fetchall(): amount = 0 cursor.execute('''SELECT * FROM debits \ WHERE (address = ? AND asset = ?)''', (balance['address'], balance['asset'])) for debit in cursor.fetchall(): amount -= debit['amount'] cursor.execute('''SELECT * FROM credits \ WHERE (address = ? AND asset = ?)''', (balance['address'], balance['asset'])) for credit in cursor.fetchall(): amount += credit['amount'] assert amount == balance['amount'] tx_index += 1 parse_hex_cursor.close()
def get_history (address): if not bitcoin.rpc('validateaddress', [address])['result']['isvalid']: raise exceptions.InvalidAddressError('Not a valid Bitcoin address:', address) history = {} history['balances'] = get_balances(address=address) history['sends'] = get_sends(validity='Valid', source=address) history['orders'] = get_orders(validity='Valid', address=address) history['order_matches'] = get_order_matches(validity='Valid', addresses=[address]) history['btcpays'] = get_btcpays(validity='Valid') history['issuances'] = get_issuances(validity='Valid', issuer=address) history['broadcasts'] = get_broadcasts(validity='Valid', source=address) history['bets'] = get_bets(validity='Valid', address=address) history['bet_matches'] = get_bet_matches(validity='Valid', addresses=[address]) history['dividends'] = get_dividends(validity='Valid', address=address) history['burns'] = get_burns(validity='Valid', address=address) return history
def get_bets (validity=None, address=None, show_empty=True, show_expired=True): db = sqlite3.connect(config.DATABASE) db.row_factory = sqlite3.Row cursor = db.cursor() cursor.execute('''SELECT * FROM bets ORDER BY odds DESC, tx_index''') block_count = bitcoin.rpc('getblockcount', [])['result'] bets = [] for bet in cursor.fetchall(): if validity and bet['Validity'] != validity: continue if not show_empty and not bet['wager_remaining']: continue if address and bet['source'] != address: continue time_left = util.get_time_left(bet) if not show_expired and time_left < 0: continue bets.append(dict(bet)) cursor.close() return bets
def get_tx_data (tx_hex): """Accepts unsigned transactions.""" tx = bitcoin.rpc('decoderawtransaction', [tx_hex])['result'] # Get destination output and data output. destination, btc_amount, data = None, None, None for vout in tx['vout']: # Destination is the first output before the data. if not destination and not btc_amount and not data: if 'addresses' in vout['scriptPubKey']: address = vout['scriptPubKey']['addresses'][0] if bitcoin.base58_decode(address, config.ADDRESSVERSION): # If address is valid… destination, btc_amount = address, round(D(vout['value']) * config.UNIT) # Assume only one OP_RETURN output. if not data: asm = vout['scriptPubKey']['asm'].split(' ') if asm[0] == 'OP_RETURN' and len(asm) == 2: data = binascii.unhexlify(asm[1]) return destination, btc_amount, data
def get_orders (validity=None, address=None, show_empty=True, show_expired=True): db = sqlite3.connect(config.DATABASE) db.row_factory = sqlite3.Row cursor = db.cursor() cursor.execute('''SELECT * FROM orders ORDER BY price ASC, tx_index''') block_count = bitcoin.rpc('getblockcount', [])['result'] orders = [] for order in cursor.fetchall(): if validity and order['Validity'] != validity: continue if not show_empty and not order['give_remaining']: continue if address and order['source'] != address: continue # Ignore BTC orders one block early. time_left = util.get_time_left(order) if not show_expired and not ((time_left > 0 and order['give_id'] and order['get_id']) or time_left > 1): continue orders.append(dict(order)) cursor.close() return orders
def wallet(): #total_table = PrettyTable(['Asset', 'Balance']) wallet = {'addresses': {}} totals = {} for group in bitcoin.rpc('listaddressgroupings', []): for bunch in group: address, btc_balance = bunch[:2] get_address = util.get_address(db, address=address) balances = get_address['balances'] #table = PrettyTable(['Asset', 'Balance']) assets = {} empty = True if btc_balance: #table.add_row(['BTC', btc_balance]) # BTC assets['BTC'] = btc_balance if 'BTC' in totals.keys(): totals['BTC'] += btc_balance else: totals['BTC'] = btc_balance empty = False for balance in balances: asset = balance['asset'] balance = D(util.devise(db, balance['amount'], balance['asset'], 'output')) if balance: if asset in totals.keys(): totals[asset] += balance else: totals[asset] = balance #table.add_row([asset, balance]) assets[asset] = balance empty = False if not empty: wallet['addresses'][address] = assets wallet['totals'] = totals #print(wallet) response.content_type = 'application/json' return json.dumps(wallet, cls=DecimalEncoder)
logger.addHandler(fileh) #API requests logging (don't show on console in normal operation) requests_log = logging.getLogger("requests") requests_log.setLevel(logging.DEBUG if args.verbose else logging.WARNING) if args.action == None: args.action = 'server' # TODO # Check versions. util.versions_check(db) # Check that bitcoind is running, communicable, and caught up with the blockchain. # Check that the database has caught up with bitcoind. if not args.force: bitcoin.bitcoind_check(db) if args.action not in ('server', 'reparse', 'rollback', 'potentials'): util.database_check(db, bitcoin.rpc('getblockcount', [])) # TODO # Do something. # MESSAGE CREATION if args.action == 'send': quantity = util.devise(db, args.quantity, args.asset, 'input') cli('create_send', [args.source, args.destination, args.asset, quantity], args.unsigned) elif args.action == 'order': fee_required, fee_fraction_provided = D(args.fee_fraction_required), D( args.fee_fraction_provided) give_quantity, get_quantity = D(args.give_quantity), D(
def decode_raw_transaction(raw_transaction): if pytest.config.option.initrawtransactions or pytest.config.option.saverawtransactions: return bitcoin.rpc('decoderawtransaction', [raw_transaction]) else: return util_test.decoderawtransaction(rawtransactions_db, raw_transaction)
print(colorama.Fore.WHITE + colorama.Style.BRIGHT + 'Open Orders' + colorama.Style.RESET_ALL) print(colorama.Fore.BLUE + str(table) + colorama.Style.RESET_ALL) print('\n') # Open bets. bets = api.get_bets(validity='Valid', show_expired=False, show_empty=False) table = PrettyTable(['Bet Type', 'Feed Address', 'Deadline', 'Threshold', 'Leverage', 'Wager', 'Counterwager', 'Odds', 'Time Left', 'Tx Hash']) for bet in bets: bet = format_bet(bet) table.add_row(bet) print(colorama.Fore.WHITE + colorama.Style.BRIGHT + 'Open Bets' + colorama.Style.RESET_ALL) print(colorama.Fore.GREEN + str(table) + colorama.Style.RESET_ALL) print('\n') # Matched orders waiting for BTC payments from you. my_addresses = [ element['address'] for element in bitcoin.rpc('listreceivedbyaddress', [0,True])['result'] ] awaiting_btcs = api.get_order_matches(validity='Valid: awaiting BTC payment', addresses=my_addresses, show_expired=False) table = PrettyTable(['Matched Order ID', 'Time Left']) for order_match in awaiting_btcs: order_match = format_order_match(order_match) table.add_row(order_match) print(colorama.Fore.WHITE + colorama.Style.BRIGHT + 'Order Matches Awaiting BTC Payment' + colorama.Style.RESET_ALL) print(colorama.Fore.CYAN + str(table) + colorama.Style.RESET_ALL) time.sleep(30) elif args.action == 'history': history = api.get_history(args.address) # Balances. balances = history['balances']
elif args.asset == 'BTC': total = None divisible = True asset_id = util.get_asset_id(args.asset) print('Asset Name:', args.asset) print('Asset ID:', asset_id) print('Total Issued:', total) elif args.action == 'wallet': total_table = PrettyTable(['Asset', 'Balance']) totals = {} print() # TODO: This should be burns minus issuance fees (so it won’t depend on escrowed funds). for group in bitcoin.rpc('listaddressgroupings', []): for bunch in group: address, btc_balance = bunch[:2] get_address = util.get_address(db, address=address) balances = get_address['balances'] table = PrettyTable(['Asset', 'Balance']) empty = True if btc_balance: table.add_row(['BTC', btc_balance]) # BTC if 'BTC' in totals.keys(): totals['BTC'] += btc_balance else: totals['BTC'] = btc_balance empty = False for balance in balances: asset = balance['asset'] balance = D( util.devise(db, balance['amount'], balance['asset'],
total = util.devise(db, total, args.asset, 'output') divisible = bool(issuances[-1]['divisible']) issuer = issuances[-1]['issuer'] # Issuer of last issuance. print('Asset Name:', args.asset) print('Asset ID:', util.get_asset_id(args.asset)) print('Total Issued:', total) print('Divisible:', divisible) print('Issuer:', issuer) elif args.action == 'wallet': total_table = PrettyTable(['Asset', 'Balance']) totals = {} print() for group in bitcoin.rpc('listaddressgroupings', []): for bunch in group: address, btc_balance = bunch[:2] get_address = util.get_address(db, address=address) balances = get_address['balances'] table = PrettyTable(['Asset', 'Balance']) empty = True if btc_balance: table.add_row(['BTC', btc_balance]) # BTC if 'BTC' in totals.keys(): totals['BTC'] += btc_balance else: totals['BTC'] = btc_balance empty = False for balance in balances: asset = balance['asset'] balance = D(util.devise(db, balance['amount'], balance['asset'], 'output')) if balance: