def _start_monitor_nodes(self): for serv in self.config['coinservs']: conn = CoinserverRPC( "http://{0}:{1}@{2}:{3}/" .format(serv['username'], serv['password'], serv['address'], serv['port']), pool_kwargs=dict(maxsize=serv.get('maxsize', 10))) conn.config = serv conn.name = "{}:{}".format(serv['address'], serv['port']) self._down_connections.append(conn)
def __init__(self, bootstrap): ConfigObject.__init__(self, bootstrap) self.coinserv = CoinserverRPC("http://{0}:{1}@{2}:{3}/".format( bootstrap['coinserv']['username'], bootstrap['coinserv']['password'], bootstrap['coinserv']['address'], bootstrap['coinserv']['port'], pool_kwargs=dict(maxsize=bootstrap.get('maxsize', 10)))) self.exchangeable = bool(self.exchangeable) self.minimum_payout = dec(self.minimum_payout) # If a pool payout addr is specified, make sure it matches the # configured address version. if self.pool_payout_addr is not None: try: ver = address_version(self.pool_payout_addr) except (KeyError, AttributeError): ver = None if ver not in self.address_version: raise ConfigurationException( "{} is not a valid {} address. Must be version {}, got version {}" .format(self.pool_payout_addr, self.key, self.address_version, ver)) # Check to make sure there is a configured pool address for # unexchangeable currencies if self.exchangeable is False and self.pool_payout_addr is None: raise ConfigurationException( "Unexchangeable currencies require a pool payout addr." "No valid address found for {}".format(self.key))
def __init__(self, config, logger=None): if not config: raise CoinRPCException( {'code': -1, 'message': 'Invalid configuration file'}) self._set_config(**config) if logger: self.logger = logger else: logging.Formatter.converter = datetime.time.gmtime self.logger = logging.getLogger(self.config['logger_name']) self.logger.setLevel(getattr(logging, self.config['log_level'])) self.conn = CoinserverRPC("http://{0}:{1}@{2}:{3}/" .format(self.coinserv['username'], self.coinserv['password'], self.coinserv['address'], self.coinserv['port'], pool_kwargs=dict(maxsize=self.maxsize)))
def __init__(self, bootstrap): bootstrap['_algo'] = bootstrap.pop('algo', None) if bootstrap['_algo'] is None: raise ConfigurationException( "A currency in config.toml is missing an entry in " "defaults.toml! The following config may help identify it: {}". format(bootstrap)) ConfigObject.__init__(self, bootstrap) if self.coinserv: cfg = self.coinserv self.coinserv = CoinserverRPC("http://{0}:{1}@{2}:{3}/".format( cfg['username'], cfg['password'], cfg['address'], cfg['port'], pool_kwargs=dict(maxsize=bootstrap.get('maxsize', 10)))) self.coinserv.config = cfg elif self.sellable or self.mineable or self.buyable: raise ConfigurationException( "Coinserver must be configured for {}!".format(self.key)) self.sellable = bool(self.sellable) self.buyable = bool(self.buyable) self.merged = bool(self.merged) self.minimum_payout = dec(self.minimum_payout) # If a pool payout addr is specified, make sure it matches the # configured address version. if self.pool_payout_addr is not None: try: ver = address_version(self.pool_payout_addr) except (KeyError, AttributeError): ver = None if ver not in self.address_version: raise ConfigurationException( "{} is not a valid {} address. Must be version {}, got version {}" .format(self.pool_payout_addr, self.key, self.address_version, ver)) # Check to make sure there is a configured pool address for # unsellable currencies if self.sellable is False and self.pool_payout_addr is None and self.mineable: raise ConfigurationException( "Unsellable currencies require a pool payout addr." "No valid address found for {}".format(self.key))
ch.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) root.addHandler(ch) root.setLevel(getattr(logging, args.log_level)) config = {'pass': None} for line in args.config_path: pts = line.strip().split("=") if len(pts) != 2: continue config[pts[0]] = pts[1] if args.passphrase_file: config['pass'] = args.passphrase_file.read().strip() rpc_connection = CoinserverRPC( "http://{rpcuser}:{rpcpassword}@localhost:{rpcport}/" .format(**config)) try: balance = rpc_connection.getbalance() except CoinRPCException as e: logging.error("Unable to retrieve balance, rpc returned {}".format(e)) exit(1) try: balance = Decimal(balance) except ValueError: logging.error("Bogus data returned by balance call, exiting" .format(str(balance)[:100])) exit(1)
def getinfo(self, *args, **kwargs): res = CoinserverRPC.__getattr__(self, "getinfo") res = res(*args, **kwargs) self.last_getinfo = res self.last_getinfo['time'] = time.time() return res
def __init__(self, *args, **kwargs): CoinserverRPC.__init__(self, *args, **kwargs) self._conn.ConnectionCls = TimedHTTPConnection self.last_getinfo = None self.name = None
ch.setLevel(logging.DEBUG) ch.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) root.addHandler(ch) root.setLevel(getattr(logging, args.log_level)) config = {'pass': None} for line in args.config_path: pts = line.strip().split("=") if len(pts) != 2: continue config[pts[0]] = pts[1] if args.passphrase_file: config['pass'] = args.passphrase_file.read().strip() rpc_connection = CoinserverRPC( "http://{rpcuser}:{rpcpassword}@localhost:{rpcport}/".format(**config)) try: balance = rpc_connection.getbalance() except CoinRPCException as e: logging.error("Unable to retrieve balance, rpc returned {}".format(e)) exit(1) try: balance = Decimal(balance) except ValueError: logging.error("Bogus data returned by balance call, exiting".format( str(balance)[:100])) exit(1) if balance < Decimal("0.001"):
class CoinRPC(object): """ Treating the RPC as a python object is pretty convenient. All possible exceptions thrown by RPC code are raised as CoinRPCException, making error handling pretty easy """ def __getattr__(self, attr): return self.config[attr] def _set_config(self, **kwargs): # A fast way to set defaults for the kwargs then set them as attributes self.config = dict(maxsize=10, tx_fee=0, min_confirms=6, enabled=True, account="", logger_name="coin_rpc", log_level="INFO") self.config.update(kwargs) required_conf = ['coinserv', 'currency_code'] error = False for req in required_conf: if req not in self.config: print("{} is a required configuration variable".format(req)) error = True coinserv_required_conf = ['username', 'password', 'address', 'port'] for req in coinserv_required_conf: if req not in self.coinserv: print( "{} is a required coinserv configuration variable".format( req)) error = True if error: raise CoinRPCException({ 'code': -1, 'message': 'Errors occurred while configuring ' 'CoinRPC obj' }) def __init__(self, config, logger=None): if not config: raise CoinRPCException({ 'code': -1, 'message': 'Invalid configuration file' }) self._set_config(**config) if logger: self.logger = logger else: logging.Formatter.converter = datetime.time.gmtime self.logger = logging.getLogger(self.config['logger_name']) self.logger.setLevel(getattr(logging, self.config['log_level'])) self.conn = CoinserverRPC("http://{0}:{1}@{2}:{3}/".format( self.coinserv['username'], self.coinserv['password'], self.coinserv['address'], self.coinserv['port'], pool_kwargs=dict(maxsize=self.maxsize))) @rpc_conn def poke_rpc(self): return self.conn.getnetworkinfo() @rpc_conn def set_tx_fee(self, amount): amount = float(amount) try: self.conn.settxfee(amount) except CoinRPCException: self.logger.warn("{} coinserver reported failure attempting to " "set tx fee to {}".format(self.currency_code, amount), exc_info=True) raise else: self.logger.info("{} coinserver tx fee set to {}".format( self.currency_code, amount)) @rpc_conn def get_transaction(self, coin_tx): """ Runs gettransaction rpc call gettransaction sample output: {u'amount': Decimal('0.37810015'), u'blockhash': u'321e3dc1ad953ce585bbc2863effd29976f7f432e82e0af5a0e9a84ea096f373', u'blockindex': 2, u'blocktime': 1406482864, u'confirmations': 22, u'details': [{u'account': u'personal_mining_address', u'address': u'VvAQomockqLj5uto6UKq7EXGAAxpkcWAio', u'amount': Decimal('0.37810015'), u'category': u'receive'}], u'time': 1406482863, u'timereceived': 1406482863, u'txid': u'd405e871740cc058e2121144362f18012f14e6d3ef702afa343c4c10469642c0'} """ try: tx_info = self.conn.gettransaction(coin_tx) except CoinRPCException as e: if e.code == -5: self.logger.warn('Transaction {} not found in the {} ' 'wallet'.format(coin_tx, self.currency_code)) raise else: raise self.logger.info("Found local info on {} TX {}".format( self.currency_code, coin_tx)) self.logger.debug(pprint.pformat(tx_info)) try: tx = CoinTransaction.create(tx_info, self.currency_code) except (KeyError, AssertionError): self.logger.warn('Got unexpected Coin RPC gettransaction ' 'response \n{}'.format(pprint.pformat(tx_info)), exc_info=True) raise CoinRPCException else: return tx @rpc_conn def list_transactions(self, account="''", count=10): """ Runs the 'listtransactions' rpc call on the given currency's rpc server and returns transactions listtransactions sample output: [ { "account" : "scm", "address" : "LKyGLZ4tLYjWEDGFzT94KvCdUFYvm7KyXj", "category" : "send", "amount" : -7.97790612, "fee" : 0.00000000, "confirmations" : 2819, "blockhash" : "2da8acefd9e9b5c0c2b0ccb655e1423c950a8c7877847c614f48a5e55235026f", "blockindex" : 1, "blocktime" : 1410849255, "txid" : "0e9b03a9d212263b1c28a9945463a8d3d451926885b2f2c2106f49c8fd6bbc95", "time" : 1410849251, "timereceived" : 1410849251 } ] """ result = self.conn.listtransactions(account, count) self.logger.debug("Received {} {} transactions".format( len(result), self.currency_code)) transactions = [] try: for tx_info in result: tx = CoinTransaction.create(tx_info, self.currency_code) transactions.append(tx) except KeyError as e: self.logger.warn( "Key error grabbing {} transactions. Got: {}".format( self.currency_code, e)) raise CoinRPCException else: return transactions @rpc_conn def unlock_wallet(self, seconds=10): if self.coinserv['wallet_pass']: try: wallet = self.conn.walletpassphrase( self.coinserv['wallet_pass'], seconds) except CoinRPCException as e: # Some wallets get grumpy about unlock attempts when they're # not encrypted if e.code == -15: self.logger.warn("Unlocking {} wallet unnecessary, its " "not encrypted. You should probably " "encrypt it...".format( self.currency_code)) else: self.logger.info("Unlocking {} wallet. Success: {}".format( self.currency_code, wallet)) @rpc_conn def send_many(self, account, recip): """ Runs the 'sendmany' rpc call on the given currency's rpc server """ # Coercy account to a STR account = str(account) # Coerce all amounts to float for k, amount in recip.iteritems(): recip[k] = float(amount) self.unlock_wallet() self.set_tx_fee(self.tx_fee) try: coin_tx = self.conn.sendmany(account, recip) except CoinRPCException as e: self.logger.error( "Unable to send funds! CoinRPC returned an error " "{}".format(e), exc_info=True) raise CoinRPCException else: self.logger.info("Successfully ran sendmany for {} to {}".format( self.currency_code, recip)) # Lookup the transaction we just created to grab fees tx = self.get_transaction(coin_tx) return coin_tx, tx @rpc_conn def get_balance(self, account=None): """ Runs the 'getbalance' rpc call on the given currency's rpc server """ if not account and not self.account: balance = self.conn.getbalance() else: balance = self.conn.getbalance(account or self.account) self.logger.info("Found {} {} balance in local wallet".format( balance, self.currency_code)) return balance @rpc_conn def get_block(self, block_hash): """ Runs the 'getblock' rpc call on the given currency's rpc server """ block_info = self.conn.getblock() self.logger.debug("For block {} received info:".format( block_hash, block_info)) try: assert 'height' in block_info assert 'confirmations' in block_info assert 'hash' in block_info except AssertionError: self.logger.warn( 'Got unexpected {} RPC getblock response. Got: {}'.format( self.currency_code, pprint.pformat(block_info)), exc_info=True) return block_info @rpc_conn def get_transactions_since(self, blockhash, confirms=1): """ Runs the 'listsinceblock' rpc call on the given currency's rpc server and returns transactions listsinceblock sample output: { "lastblock" : "0000000004ba22e9f8cea2e843b34f7eeaa2c3b7004ddcf19bfd8af0215fc0cc", "transactions" : [ { "account" : "", "address" : "mzE6DJMHPghYpVg4GCurMbxSSXBfW1KCFH", "amount" : 1.0, "category" : "receive", "confirmations" : 0, "time" : 1399200157, "timereceived" : 1399200157, "txid" : "917248d57293a7fd3a88aa3a26026d2e4d6a1d4eef898519b20419f2339c265c", "walletconflicts" : [ ] } ] } """ result = self.conn.listsinceblock(blockhash, confirms) self.logger.info("For {} block {} received : {}".format( self.currency_code, blockhash, result)) transactions = [] try: for tx_info in result['transactions']: tx = CoinTransaction.create(tx_info, self.currency_code) transactions.append(tx) lastblock = result['lastblock'] except KeyError as e: self.logger.warn("Key error grabbing {} transactions since {}" " Got: {}".format(blockhash, self.currency_code, e)) raise CoinRPCException else: return transactions, lastblock @rpc_conn def get_received(self, address, confirms=1): """ Runs the 'receivedbyaddress' rpc call on the given currency's rpc server and returns tx ids """ results = self.conn.receivedbyaddress(address, confirms) self.logger.info("For {} block {} received : {}".format( self.currency_code, results)) for result in results: try: transactions = result['txids'] except KeyError as e: self.logger.warn( "Key error with {} txids for {}. Got: {}".format( self.currency_code, address, e)) raise CoinRPCException else: return transactions @rpc_conn def get_block_count(self): """ Runs the 'getblockcount' rpc call on the given currency's rpc server and returns the count """ count = self.conn.getblockcount() self.logger.info("Got {} height for: {}".format( count, self.currency_code)) return count @rpc_conn def get_block_hash(self, index): """ Runs the 'getblockhash' rpc call on the given currency's rpc server and returns the height """ hash = self.conn.getblockhash(index) self.logger.info("For {} height {} received : {}".format( self.currency_code, index, hash)) return hash
class CoinRPC(object): """ Treating the RPC as a python object is pretty convenient. All possible exceptions thrown by RPC code are raised as CoinRPCException, making error handling pretty easy """ def __getattr__(self, attr): return self.config[attr] def _set_config(self, **kwargs): # A fast way to set defaults for the kwargs then set them as attributes self.config = dict(maxsize=10, tx_fee=0, min_confirms=6, enabled=True, account="", logger_name="coin_rpc", log_level="INFO") self.config.update(kwargs) required_conf = ['coinserv', 'currency_code'] error = False for req in required_conf: if req not in self.config: print("{} is a required configuration variable".format(req)) error = True coinserv_required_conf = ['username', 'password', 'address', 'port'] for req in coinserv_required_conf: if req not in self.coinserv: print("{} is a required coinserv configuration variable".format(req)) error = True if error: raise CoinRPCException( {'code': -1, 'message': 'Errors occurred while configuring ' 'CoinRPC obj'}) def __init__(self, config, logger=None): if not config: raise CoinRPCException( {'code': -1, 'message': 'Invalid configuration file'}) self._set_config(**config) if logger: self.logger = logger else: logging.Formatter.converter = datetime.time.gmtime self.logger = logging.getLogger(self.config['logger_name']) self.logger.setLevel(getattr(logging, self.config['log_level'])) self.conn = CoinserverRPC("http://{0}:{1}@{2}:{3}/" .format(self.coinserv['username'], self.coinserv['password'], self.coinserv['address'], self.coinserv['port'], pool_kwargs=dict(maxsize=self.maxsize))) @rpc_conn def poke_rpc(self): return self.conn.getinfo() @rpc_conn def set_tx_fee(self, amount): amount = float(amount) try: self.conn.settxfee(amount) except CoinRPCException: self.logger.warn("{} coinserver reported failure attempting to " "set tx fee to {}". format(self.currency_code, amount), exc_info=True) raise else: self.logger.info("{} coinserver tx fee set to {}". format(self.currency_code, amount)) @rpc_conn def get_transaction(self, coin_tx): """ Runs gettransaction rpc call gettransaction sample output: {u'amount': Decimal('0.37810015'), u'blockhash': u'321e3dc1ad953ce585bbc2863effd29976f7f432e82e0af5a0e9a84ea096f373', u'blockindex': 2, u'blocktime': 1406482864, u'confirmations': 22, u'details': [{u'account': u'personal_mining_address', u'address': u'VvAQomockqLj5uto6UKq7EXGAAxpkcWAio', u'amount': Decimal('0.37810015'), u'category': u'receive'}], u'time': 1406482863, u'timereceived': 1406482863, u'txid': u'd405e871740cc058e2121144362f18012f14e6d3ef702afa343c4c10469642c0'} """ try: tx_info = self.conn.gettransaction(coin_tx) except CoinRPCException as e: if e.code == -5: self.logger.warn('Transaction {} not found in the {} ' 'wallet'.format(coin_tx, self.currency_code)) raise else: raise self.logger.info("Found local info on {} TX {}" .format(self.currency_code, coin_tx)) self.logger.debug(pprint.pformat(tx_info)) try: tx = CoinTransaction.create(tx_info, self.currency_code) except (KeyError, AssertionError): self.logger.warn('Got unexpected Coin RPC gettransaction ' 'response \n{}'.format(pprint.pformat(tx_info)), exc_info=True) raise CoinRPCException else: return tx @rpc_conn def list_transactions(self, account="''", count=10): """ Runs the 'listtransactions' rpc call on the given currency's rpc server and returns transactions listtransactions sample output: [ { "account" : "scm", "address" : "LKyGLZ4tLYjWEDGFzT94KvCdUFYvm7KyXj", "category" : "send", "amount" : -7.97790612, "fee" : 0.00000000, "confirmations" : 2819, "blockhash" : "2da8acefd9e9b5c0c2b0ccb655e1423c950a8c7877847c614f48a5e55235026f", "blockindex" : 1, "blocktime" : 1410849255, "txid" : "0e9b03a9d212263b1c28a9945463a8d3d451926885b2f2c2106f49c8fd6bbc95", "time" : 1410849251, "timereceived" : 1410849251 } ] """ result = self.conn.listtransactions(account, count) self.logger.debug("Received {} {} transactions" .format(len(result), self.currency_code)) transactions = [] try: for tx_info in result: tx = CoinTransaction.create(tx_info, self.currency_code) transactions.append(tx) except KeyError as e: self.logger.warn("Key error grabbing {} transactions. Got: {}" .format(self.currency_code, e)) raise CoinRPCException else: return transactions @rpc_conn def unlock_wallet(self, seconds=10): if self.coinserv['wallet_pass']: try: wallet = self.conn.walletpassphrase(self.coinserv['wallet_pass'], seconds) except CoinRPCException as e: # Some wallets get grumpy about unlock attempts when they're # not encrypted if e.code == -15: self.logger.warn("Unlocking {} wallet unnecessary, its " "not encrypted. You should probably " "encrypt it...".format(self.currency_code)) else: self.logger.info("Unlocking {} wallet. Success: {}". format(self.currency_code, wallet)) @rpc_conn def send_many(self, account, recip): """ Runs the 'sendmany' rpc call on the given currency's rpc server """ # Coercy account to a STR account = str(account) # Coerce all amounts to float for k, amount in recip.iteritems(): recip[k] = float(amount) self.unlock_wallet() self.set_tx_fee(self.tx_fee) try: coin_tx = self.conn.sendmany(account, recip) except CoinRPCException as e: self.logger.error("Unable to send funds! CoinRPC returned an error " "{}".format(e), exc_info=True) raise CoinRPCException else: self.logger.info("Successfully ran sendmany for {} to {}". format(self.currency_code, recip)) # Lookup the transaction we just created to grab fees tx = self.get_transaction(coin_tx) return coin_tx, tx @rpc_conn def get_balance(self, account=None): """ Runs the 'getbalance' rpc call on the given currency's rpc server """ if not account and not self.account: balance = self.conn.getbalance() else: balance = self.conn.getbalance(account or self.account) self.logger.info("Found {} {} balance in local wallet". format(balance, self.currency_code)) return balance @rpc_conn def get_block(self, block_hash): """ Runs the 'getblock' rpc call on the given currency's rpc server """ block_info = self.conn.getblock() self.logger.debug("For block {} received info:".format(block_hash, block_info)) try: assert 'height' in block_info assert 'confirmations' in block_info assert 'hash' in block_info except AssertionError: self.logger.warn('Got unexpected {} RPC getblock response. Got: {}' .format(self.currency_code, pprint.pformat(block_info)), exc_info=True) return block_info @rpc_conn def get_transactions_since(self, blockhash, confirms=1): """ Runs the 'listsinceblock' rpc call on the given currency's rpc server and returns transactions listsinceblock sample output: { "lastblock" : "0000000004ba22e9f8cea2e843b34f7eeaa2c3b7004ddcf19bfd8af0215fc0cc", "transactions" : [ { "account" : "", "address" : "mzE6DJMHPghYpVg4GCurMbxSSXBfW1KCFH", "amount" : 1.0, "category" : "receive", "confirmations" : 0, "time" : 1399200157, "timereceived" : 1399200157, "txid" : "917248d57293a7fd3a88aa3a26026d2e4d6a1d4eef898519b20419f2339c265c", "walletconflicts" : [ ] } ] } """ result = self.conn.listsinceblock(blockhash, confirms) self.logger.info("For {} block {} received : {}" .format(self.currency_code, blockhash, result)) transactions = [] try: for tx_info in result['transactions']: tx = CoinTransaction.create(tx_info, self.currency_code) transactions.append(tx) lastblock = result['lastblock'] except KeyError as e: self.logger.warn("Key error grabbing {} transactions since {}" " Got: {}".format(blockhash, self.currency_code, e)) raise CoinRPCException else: return transactions, lastblock @rpc_conn def get_received(self, address, confirms=1): """ Runs the 'receivedbyaddress' rpc call on the given currency's rpc server and returns tx ids """ results = self.conn.receivedbyaddress(address, confirms) self.logger.info("For {} block {} received : {}" .format(self.currency_code, results)) for result in results: try: transactions = result['txids'] except KeyError as e: self.logger.warn("Key error with {} txids for {}. Got: {}" .format(self.currency_code, address, e)) raise CoinRPCException else: return transactions @rpc_conn def get_block_count(self): """ Runs the 'getblockcount' rpc call on the given currency's rpc server and returns the count """ count = self.conn.getblockcount() self.logger.info("Got {} height for: {}" .format(count, self.currency_code)) return count @rpc_conn def get_block_hash(self, index): """ Runs the 'getblockhash' rpc call on the given currency's rpc server and returns the height """ hash = self.conn.getblockhash(index) self.logger.info("For {} height {} received : {}" .format(self.currency_code, index, hash)) return hash