class BitcoinService: def __init__(self): self.access = AuthServiceProxy("http://*****:*****@[email protected]:8332") def getInfo(self): return self.access.getinfo() def getlistreceivedbyaddress(self, num): return self.access.listreceivedbyaddress(num) def getBalance(self): return self.access.getbalance() def isValidAddress(self, addr): return self.access.validateaddress(addr) def generateAddress(self): return self.access.getnewaddress() def getAccount(self, addr): return self.access.getaccount(addr) def getAccountAddr(self, account): return self.access.getaccountaddress(account) def getreceivedbyaddress(self, addr): return self.access.getreceivedbyaddress(addr) def sendtoaddress(self, addr, amount, comment=""): return self.acccess.sendtoaddress(addr, amount, comment)
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)
# rpc_user and rpc_password are set in the bitcoin.conf file access = AuthServiceProxy("http://*****:*****@127.0.0.1:10022/") cmd = sys.argv[1].lower() if cmd == "backupwallet": try: path = raw_input("Enter destination path/filename: ") print access.backupwallet(path) except: print "\n---An error occurred---\n" elif cmd == "getaccount": try: addr = raw_input("Enter a Bitcoin address: ") print access.getaccount(addr) except: print "\n---An error occurred---\n" elif cmd == "getaccountaddress": try: acct = raw_input("Enter an account name: ") print access.getaccountaddress(acct) except: print "\n---An error occurred---\n" elif cmd == "getaddressesbyaccount": try: acct = raw_input("Enter an account name: ") print access.getaddressesbyaccount(acct) except:
class FullNode: def __init__(self, conf_dir=None, rpcuser=None, rpcpassword=None, rpcport=None, rpchost='127.0.0.1', network="main"): if rpcport is None: rpcport = {'main':8332,'test':18332,'stn':9332, 'regtest':18332}[network] if conf_dir is None: if platform.system() == 'Darwin': conf_dir = os.path.expanduser('~/Library/Application Support/Bitcoin/') elif platform.system() == 'Windows': conf_dir = os.path.join(os.environ['APPDATA'], 'Bitcoin') else: conf_dir = os.path.expanduser('~/.bitcoin') if network == 'regtest': conf_dir = os.path.join(conf_dir, 'regtest') if network == 'test': conf_dir = os.path.join(conf_dir, 'testnet3') elif network == 'stn': conf_dir = os.path.join(conf_dir, 'stn') if rpcuser is None: cookie = os.path.join(conf_dir, '.cookie') with open(cookie) as f: rpcuserpass = f.read() # Use cookie if no rpcuser specified if rpcuser: uri = "http://{}:{}@{}:{}".format(rpcuser, rpcpassword, rpchost, rpcport) else: uri = "http://{}@{}:{}".format(rpcuserpass, rpchost, rpcport) self.network = network self.conf_dir = conf_dir self.uri = uri self.rpc = AuthServiceProxy(self.uri) self.rpcport = rpcport self.rpchost = rpchost self.network = network rpcnet = self.rpc.getblockchaininfo()['chain'] if rpcnet != network: raise ValueError("rpc server is on '%s' network, you passed '%s'" % (rpcnet, network)) def __getattr__(self, rpc_method): return RPCMethod(rpc_method, self) def __dir__(self): fulllist = [] fulllist.extend(bitsv_methods) fulllist.extend(standardmethods) fulllist.extend(self.__dict__.keys()) return fulllist def rpc_connect(self): return AuthServiceProxy(self.uri) def rpc_reconnect(self): self.rpc = AuthServiceProxy(self.uri) class Decorators: @classmethod def handle_broken_pipe(cls, f): @wraps(f) def reconnect_if_needed(self, *args, **kwargs): try: return f(self, *args, **kwargs) except BrokenPipeError: self.rpc_reconnect() # reconnect and try again return f(self, *args) return reconnect_if_needed @Decorators.handle_broken_pipe def get_balance(self, address): return sum(unspent.amount for unspent in self.get_unspents(address)) @Decorators.handle_broken_pipe def get_transactions(self, address): acct = self.rpc.getaccount(address) txs = self.rpc.listtransactions(acct) txids = (tx['txid'] for tx in txs) txids = list(txids) return txids @Decorators.handle_broken_pipe def get_transaction(self, txid): rawtx = self.rpc.getrawtransaction(txid) txjson = self.rpc.decoderawtransaction(rawtx) inputs = [] outputs = [] amount_in = 0 amount_out = 0 for vin in txjson['vin']: src = self.rpc.getrawtransaction(vin['txid'], True) src = self.rpc.decoderawtransaction(src['hex']) src = src['vout'][vin['vout']] addr = None if 'addresses' in src['scriptPubKey']: addr = src['scriptPubKey']['addresses'][0] amount = int((src['value'] * BSV_TO_SAT_MULTIPLIER).normalize()) amount_in += amount part = TxInput(addr, amount) inputs += [part] for vout in txjson['vout']: addr = None if 'addresses' in vout['scriptPubKey']: addr = vout['scriptPubKey']['addresses'][0] amount = int((vout['value'] * BSV_TO_SAT_MULTIPLIER).normalize()) amount_out += amount part = TxOutput(addr, amount, asm=vout['scriptPubKey']['asm']) outputs += [part] tx = Transaction(txjson['txid'], amount_in, amount_out) for part in inputs: tx.add_input(part) for part in outputs: tx.add_output(part) return tx @Decorators.handle_broken_pipe def get_unspents(self, address): unspents = self.rpc.listunspent(0, 9999999, [address], True) return [Unspent( amount=int((tx['amount'] * BSV_TO_SAT_MULTIPLIER).normalize()), confirmations=tx['confirmations'], script=tx['scriptPubKey'], txid=tx['txid'], txindex=tx['vout'] ) for tx in unspents] @Decorators.handle_broken_pipe def send_transaction(self, tx_hex): return self.rpc.sendrawtransaction(tx_hex, True)
if (len(inputUser.strip()) > 0): logger.info( "Checking {} configuration for holding account address...".format( coinConfFileName)) holdingAddressConfigName = holdingAddressPrefix + inputUser if holdingAddressConfigName in configBag: holdingWalletAddress = configBag[holdingAddressConfigName] else: logger.error( "Holding Address configuration '{}' is missing. Aborting.".format( holdingAddressConfigName)) exit() logger.info( "Finding account for address {}...".format(holdingWalletAddress)) holdingWalletName = rpcConnection.getaccount(holdingWalletAddress) if (holdingWalletName is not None): logger.info( "Cool {}, let's get started. This script will use {} as the holding wallet ({})." .format(inputUser, holdingWalletName, holdingWalletAddress)) else: logger.error( "Failed to lookup account for user '{}'".format(inputUser)) else: logger.critical("Unrecognized user '{}'. Aborting.".format(inputUser)) exit() print() logger.info("Processing all node accounts...") walletAccounts = rpcConnection.listaccounts() allUnspent = []