From cc7011848ddeae8c5bfbba68a1088a2f9dda3072 Mon Sep 17 00:00:00 2001 From: philemon Date: Wed, 29 Jan 2014 20:03:59 +0400 Subject: [PATCH] HTTP timeout fix for addrimport modified: mmgen-addrimport modified: mmgen/config.py modified: mmgen/rpc/connection.py modified: mmgen/rpc/proxy.py modified: mmgen/tx.py --- mmgen-addrimport | 7 +- mmgen/config.py | 2 + mmgen/rpc/connection.py | 1419 ++++++++++++++++++++------------------- mmgen/rpc/proxy.py | 160 ++--- mmgen/tx.py | 4 +- 5 files changed, 806 insertions(+), 786 deletions(-) diff --git a/mmgen-addrimport b/mmgen-addrimport index 752f1389..d06c38e5 100755 --- a/mmgen-addrimport +++ b/mmgen-addrimport @@ -23,7 +23,6 @@ mmgen-addrimport: Import addresses generated by mmgen-addrgen into an import sys from mmgen.Opts import * -from mmgen.config import * from mmgen.license import * from mmgen.utils import check_infile,confirm_or_exit from mmgen.tx import connect_to_bitcoind,parse_addrs_file @@ -51,7 +50,10 @@ check_infile(cmd_args[0]) seed_id,addr_data = parse_addrs_file(cmd_args[0]) -c = connect_to_bitcoind(http_timeout=3600) +import mmgen.config +mmgen.config.http_timeout = 3600 + +c = connect_to_bitcoind() message = """ Importing addresses can take a long time - up to 30 min. per address on a @@ -59,6 +61,7 @@ low-powered computer such as a netbook. """ confirm_or_exit(message, "continue", expect="YES") + for n,i in enumerate(addr_data): comment = " " + i[2] if len(i) == 3 else "" label = "%s:%s%s" % (seed_id,i[0],comment) diff --git a/mmgen/config.py b/mmgen/config.py index a5e1fa03..cea4161d 100755 --- a/mmgen/config.py +++ b/mmgen/config.py @@ -31,6 +31,8 @@ seed_len = 256 mnemonic_lens = [i / 32 * 3 for i in seed_lens] +http_timeout = 30 + from os import getenv debug = True if getenv("MMGEN_DEBUG") else False diff --git a/mmgen/rpc/connection.py b/mmgen/rpc/connection.py index 91881713..19482895 100755 --- a/mmgen/rpc/connection.py +++ b/mmgen/rpc/connection.py @@ -1,7 +1,5 @@ # Copyright (C) 2013 by philemon -# Added configurable http_timeout and methods for -# sendrawtransaction, -# importaddress +# Added methods for sendrawtransaction(), importaddress() # # Previous copyright from bitcoin-python/connection.py: # Copyright (c) 2010 Witchspace @@ -29,715 +27,726 @@ Connect to Bitcoin server via JSON-RPC. from mmgen.rpc.proxy import JSONRPCException, AuthServiceProxy from mmgen.rpc.exceptions import _wrap_exception, WalletPassphraseIncorrect, WalletAlreadyUnlocked from mmgen.rpc.data import (ServerInfo, AccountInfo, AddressInfo, TransactionInfo, - AddressValidation, WorkItem, MiningInfo) + AddressValidation, WorkItem, MiningInfo) class BitcoinConnection(object): - """ - A BitcoinConnection object defines a connection to a bitcoin server. - It is a thin wrapper around a JSON-RPC API connection. + """ + A BitcoinConnection object defines a connection to a bitcoin server. + It is a thin wrapper around a JSON-RPC API connection. - Up-to-date for SVN revision 198. + Up-to-date for SVN revision 198. - Arguments to constructor: + Arguments to constructor: - - *user* -- Authenticate as user. - - *password* -- Authentication password. - - *host* -- Bitcoin JSON-RPC host. - - *port* -- Bitcoin JSON-RPC port. - """ - def __init__(self, user, password, host='localhost', port=8332, - use_https=False,http_timeout=30): - """ - Create a new bitcoin server connection. - """ - url = 'http{s}://{user}:{password}@{host}:{port}/'.format( - s='s' if use_https else '', - user=user, password=password, host=host, port=port) - self.url = url - try: - self.proxy = AuthServiceProxy(url,http_timeout=http_timeout) - except JSONRPCException as e: - raise _wrap_exception(e.error) + - *user* -- Authenticate as user. + - *password* -- Authentication password. + - *host* -- Bitcoin JSON-RPC host. + - *port* -- Bitcoin JSON-RPC port. + """ + def __init__(self, user, password, host='localhost', port=8332, use_https=False): + """ + Create a new bitcoin server connection. + """ + url = 'http{s}://{user}:{password}@{host}:{port}/'.format( + s='s' if use_https else '', + user=user, password=password, host=host, port=port) + self.url = url + try: + self.proxy = AuthServiceProxy(url) + except JSONRPCException as e: + raise _wrap_exception(e.error) # importaddress
[label] [rescan=true] - def importaddress(self,address,label=None): - """ - """ - try: - return self.proxy.importaddress(address,label) - except JSONRPCException as e: - raise _wrap_exception(e.error) + def importaddress(self,address,label=None): + """ + """ + try: + return self.proxy.importaddress(address,label) + except JSONRPCException as e: + raise _wrap_exception(e.error) # sendrawtransaction [allowhighfees=false] - def sendrawtransaction(self,tx): - """ - """ - try: - return self.proxy.sendrawtransaction(tx) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def stop(self): - """ - Stop bitcoin server. - """ - try: - self.proxy.stop() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getblock(self, hash): - """ - Returns information about the given block hash. - """ - try: - return self.proxy.getblock(hash) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getblockcount(self): - """ - Returns the number of blocks in the longest block chain. - """ - try: - return self.proxy.getblockcount() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getblockhash(self, index): - """ - Returns hash of block in best-block-chain at index. - - :param index: index ob the block - - """ - try: - return self.proxy.getblockhash(index) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getblocknumber(self): - """ - Returns the block number of the latest block in the longest block chain. - Deprecated. Use getblockcount instead. - """ - return self.getblockcount() - - def getconnectioncount(self): - """ - Returns the number of connections to other nodes. - """ - try: - return self.proxy.getconnectioncount() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getdifficulty(self): - """ - Returns the proof-of-work difficulty as a multiple of the minimum difficulty. - """ - try: - return self.proxy.getdifficulty() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getgenerate(self): - """ - Returns :const:`True` or :const:`False`, depending on whether generation is enabled. - """ - try: - return self.proxy.getgenerate() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def setgenerate(self, generate, genproclimit=None): - """ - Enable or disable generation (mining) of coins. - - Arguments: - - - *generate* -- is :const:`True` or :const:`False` to turn generation on or off. - - *genproclimit* -- Number of processors that are used for generation, -1 is unlimited. - - """ - try: - if genproclimit is None: - return self.proxy.setgenerate(generate) - else: - return self.proxy.setgenerate(generate, genproclimit) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def gethashespersec(self): - """ - Returns a recent hashes per second performance measurement while generating. - """ - try: - return self.proxy.gethashespersec() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getinfo(self): - """ - Returns an :class:`~mmgen.rpc.data.ServerInfo` object containing various state info. - """ - try: - return ServerInfo(**self.proxy.getinfo()) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getmininginfo(self): - """ - Returns an :class:`~mmgen.rpc.data.MiningInfo` object containing various - mining state info. - """ - try: - return MiningInfo(**self.proxy.getmininginfo()) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getnewaddress(self, account=None): - """ - Returns a new bitcoin address for receiving payments. - - Arguments: - - - *account* -- If account is specified (recommended), it is added to the address book - so that payments received with the address will be credited to it. - - """ - try: - if account is None: - return self.proxy.getnewaddress() - else: - return self.proxy.getnewaddress(account) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getaccountaddress(self, account): - """ - Returns the current bitcoin address for receiving payments to an account. - - Arguments: - - - *account* -- Account for which the address should be returned. - - """ - try: - return self.proxy.getaccountaddress(account) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def setaccount(self, bitcoinaddress, account): - """ - Sets the account associated with the given address. - - Arguments: - - - *bitcoinaddress* -- Bitcoin address to associate. - - *account* -- Account to associate the address to. - - """ - try: - return self.proxy.setaccount(bitcoinaddress, account) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getaccount(self, bitcoinaddress): - """ - Returns the account associated with the given address. - - Arguments: - - - *bitcoinaddress* -- Bitcoin address to get account for. - """ - try: - return self.proxy.getaccount(bitcoinaddress) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getaddressesbyaccount(self, account): - """ - Returns the list of addresses for the given account. - - Arguments: - - - *account* -- Account to get list of addresses for. - """ - try: - return self.proxy.getaddressesbyaccount(account) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def sendtoaddress(self, bitcoinaddress, amount, comment=None, comment_to=None): - """ - Sends *amount* from the server's available balance to *bitcoinaddress*. - - Arguments: - - - *bitcoinaddress* -- Bitcoin address to send to. - - *amount* -- Amount to send (float, rounded to the nearest 0.01). - - *minconf* -- Minimum number of confirmations required for transferred balance. - - *comment* -- Comment for transaction. - - *comment_to* -- Comment for to-address. - - """ - try: - if comment is None: - return self.proxy.sendtoaddress(bitcoinaddress, amount) - elif comment_to is None: - return self.proxy.sendtoaddress(bitcoinaddress, amount, comment) - else: - return self.proxy.sendtoaddress(bitcoinaddress, amount, comment, comment_to) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getreceivedbyaddress(self, bitcoinaddress, minconf=1): - """ - Returns the total amount received by a bitcoin address in transactions with at least a - certain number of confirmations. - - Arguments: - - - *bitcoinaddress* -- Address to query for total amount. - - - *minconf* -- Number of confirmations to require, defaults to 1. - """ - try: - return self.proxy.getreceivedbyaddress(bitcoinaddress, minconf) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getreceivedbyaccount(self, account, minconf=1): - """ - Returns the total amount received by addresses with an account in transactions with - at least a certain number of confirmations. - - Arguments: - - - *account* -- Account to query for total amount. - - *minconf* -- Number of confirmations to require, defaults to 1. - - """ - try: - return self.proxy.getreceivedbyaccount(account, minconf) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def gettransaction(self, txid): - """ - Get detailed information about transaction - - Arguments: - - - *txid* -- Transactiond id for which the info should be returned - - """ - try: - return TransactionInfo(**self.proxy.gettransaction(txid)) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getrawtransaction(self, txid, verbose=True): - """ - Get transaction raw info - - Arguments: - - - *txid* -- Transactiond id for which the info should be returned. - - *verbose* -- If False, return only the "hex" of the transaction. - - """ - try: - if verbose: - return TransactionInfo(**self.proxy.getrawtransaction(txid, 1)) - return self.proxy.getrawtransaction(txid, 0) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def createrawtransaction(self, inputs, outputs): - """ - Creates a raw transaction spending given inputs - (a list of dictionaries, each containing a transaction id and an output number), - sending to given address(es). - - Returns hex-encoded raw transaction. - - Example usage: - >>> conn.createrawtransaction( - [{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c", - "vout": 0}], - {"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50}) - - - Arguments: - - - *inputs* -- A list of {"txid": txid, "vout": n} dictionaries. - - *outputs* -- A dictionary mapping (public) addresses to the amount - they are to be paid. - """ - try: - return self.proxy.createrawtransaction(inputs, outputs) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def signrawtransaction(self, hexstring, previous_transactions=None, private_keys=None): - """ - Sign inputs for raw transaction (serialized, hex-encoded). - - Returns a dictionary with the keys: - "hex": raw transaction with signature(s) (hex-encoded string) - "complete": 1 if transaction has a complete set of signature(s), 0 if not - - Arguments: - - - *hexstring* -- A hex string of the transaction to sign. - - *previous_transactions* -- A (possibly empty) list of dictionaries of the form: - {"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex}, representing - previous transaction outputs that this transaction depends on but may not yet be - in the block chain. - - *private_keys* -- A (possibly empty) list of base58-encoded private - keys that, if given, will be the only keys used to sign the transaction. - """ - try: - return dict(self.proxy.signrawtransaction(hexstring, previous_transactions, private_keys)) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def decoderawtransaction(self, hexstring): - """ - Produces a human-readable JSON object for a raw transaction. - - Arguments: - - - *hexstring* -- A hex string of the transaction to be decoded. - """ - try: - return dict(self.proxy.decoderawtransaction(hexstring)) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listsinceblock(self, block_hash): - try: - res = self.proxy.listsinceblock(block_hash) - res['transactions'] = [TransactionInfo(**x) for x in res['transactions']] - return res - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listreceivedbyaddress(self, minconf=1, includeempty=False): - """ - Returns a list of addresses. - - Each address is represented with a :class:`~mmgen.rpc.data.AddressInfo` object. - - Arguments: - - - *minconf* -- Minimum number of confirmations before payments are included. - - *includeempty* -- Whether to include addresses that haven't received any payments. - - """ - try: - return [AddressInfo(**x) for x in - self.proxy.listreceivedbyaddress(minconf, includeempty)] - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listaccounts(self, minconf=1, as_dict=False): - """ - Returns a list of account names. - - Arguments: - - - *minconf* -- Minimum number of confirmations before payments are included. - - *as_dict* -- Returns a dictionary of account names, with their balance as values. - """ - try: - if as_dict: - return dict(self.proxy.listaccounts(minconf)) - else: - return self.proxy.listaccounts(minconf).keys() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listreceivedbyaccount(self, minconf=1, includeempty=False): - """ - Returns a list of accounts. - - Each account is represented with a :class:`~mmgen.rpc.data.AccountInfo` object. - - Arguments: - - - *minconf* -- Minimum number of confirmations before payments are included. - - - *includeempty* -- Whether to include addresses that haven't received any payments. - """ - try: - return [AccountInfo(**x) for x in - self.proxy.listreceivedbyaccount(minconf, includeempty)] - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listtransactions(self, account=None, count=10, from_=0, address=None): - """ - Returns a list of the last transactions for an account. - - Each transaction is represented with a :class:`~mmgen.rpc.data.TransactionInfo` object. - - Arguments: - - - *account* -- Account to list transactions from. Return transactions from - all accounts if None. - - *count* -- Number of transactions to return. - - *from_* -- Skip the first transactions. - - *address* -- Receive address to consider - """ - accounts = [account] if account is not None else self.listaccounts(as_dict=True).iterkeys() - try: - return [TransactionInfo(**tx) for acc in accounts for - tx in self.proxy.listtransactions(acc, count, from_) if - address is None or tx["address"] == address] - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def backupwallet(self, destination): - """ - Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path - with filename. - - Arguments: - - *destination* -- directory or path with filename to backup wallet to. - - """ - try: - return self.proxy.backupwallet(destination) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def validateaddress(self, validateaddress): - """ - Validate a bitcoin address and return information for it. - - The information is represented by a :class:`~mmgen.rpc.data.AddressValidation` object. - - Arguments: -- Address to validate. - - - - *validateaddress* - """ - try: - return AddressValidation(**self.proxy.validateaddress(validateaddress)) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getbalance(self, account=None, minconf=None): - """ - Get the current balance, either for an account or the total server balance. - - Arguments: - - *account* -- If this parameter is specified, returns the balance in the account. - - *minconf* -- Minimum number of confirmations required for transferred balance. - - """ - args = [] - if account: - args.append(account) - if minconf is not None: - args.append(minconf) - try: - return self.proxy.getbalance(*args) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def move(self, fromaccount, toaccount, amount, minconf=1, comment=None): - """ - Move from one account in your wallet to another. - - Arguments: - - - *fromaccount* -- Source account name. - - *toaccount* -- Destination account name. - - *amount* -- Amount to transfer. - - *minconf* -- Minimum number of confirmations required for transferred balance. - - *comment* -- Comment to add to transaction log. - - """ - try: - if comment is None: - return self.proxy.move(fromaccount, toaccount, amount, minconf) - else: - return self.proxy.move(fromaccount, toaccount, amount, minconf, comment) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def sendfrom(self, fromaccount, tobitcoinaddress, amount, minconf=1, comment=None, - comment_to=None): - """ - Sends amount from account's balance to bitcoinaddress. This method will fail - if there is less than amount bitcoins with minconf confirmations in the account's - balance (unless account is the empty-string-named default account; it - behaves like the sendtoaddress method). Returns transaction ID on success. - - Arguments: - - - *fromaccount* -- Account to send from. - - *tobitcoinaddress* -- Bitcoin address to send to. - - *amount* -- Amount to send (float, rounded to the nearest 0.01). - - *minconf* -- Minimum number of confirmations required for transferred balance. - - *comment* -- Comment for transaction. - - *comment_to* -- Comment for to-address. - - """ - try: - if comment is None: - return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf) - elif comment_to is None: - return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf, comment) - else: - return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf, - comment, comment_to) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def sendmany(self, fromaccount, todict, minconf=1, comment=None): - """ - Sends specified amounts from account's balance to bitcoinaddresses. This method will fail - if there is less than total amount bitcoins with minconf confirmations in the account's - balance (unless account is the empty-string-named default account; Returns transaction ID - on success. - - Arguments: - - - *fromaccount* -- Account to send from. - - *todict* -- Dictionary with Bitcoin addresses as keys and amounts as values. - - *minconf* -- Minimum number of confirmations required for transferred balance. - - *comment* -- Comment for transaction. - - """ - try: - if comment is None: - return self.proxy.sendmany(fromaccount, todict, minconf) - else: - return self.proxy.sendmany(fromaccount, todict, minconf, comment) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def verifymessage(self, bitcoinaddress, signature, message): - """ - Verifies a signature given the bitcoinaddress used to sign, - the signature itself, and the message that was signed. - Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid. - - Arguments: - - - *bitcoinaddress* -- the bitcoinaddress used to sign the message - - *signature* -- the signature to be verified - - *message* -- the message that was originally signed - - """ - try: - return self.proxy.verifymessage(bitcoinaddress, signature, message) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def getwork(self, data=None): - """ - Get work for remote mining, or submit result. - If data is specified, the server tries to solve the block - using the provided data and returns :const:`True` if it was successful. - If not, the function returns formatted hash data (:class:`~mmgen.rpc.data.WorkItem`) - to work on. - - Arguments: - - - *data* -- Result from remote mining. - - """ - try: - if data is None: - # Only if no data provided, it returns a WorkItem - return WorkItem(**self.proxy.getwork()) - else: - return self.proxy.getwork(data) - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def listunspent(self, minconf=1, maxconf=999999): - """ - Returns a list of unspent transaction inputs in the wallet. - - Arguments: - - - *minconf* -- Minimum number of confirmations required to be listed. - - - *maxconf* -- Maximal number of confirmations allowed to be listed. - - - """ - try: - return [TransactionInfo(**tx) for tx in - self.proxy.listunspent(minconf, maxconf)] - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def keypoolrefill(self): - "Fills the keypool, requires wallet passphrase to be set." - try: - self.proxy.keypoolrefill() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def walletpassphrase(self, passphrase, timeout, dont_raise=False): - """ - Stores the wallet decryption key in memory for seconds. - - - *passphrase* -- The wallet passphrase. - - - *timeout* -- Time in seconds to keep the wallet unlocked - (by keeping the passphrase in memory). - - - *dont_raise* -- instead of raising `~mmgen.rpc.exceptions.WalletPassphraseIncorrect` - return False. - """ - try: - self.proxy.walletpassphrase(passphrase, timeout) - return True - except JSONRPCException as e: - json_exception = _wrap_exception(e.error) - if dont_raise: - if isinstance(json_exception, WalletPassphraseIncorrect): - return False - elif isinstance(json_exception, WalletAlreadyUnlocked): - return True - raise json_exception - - def walletlock(self): - """ - Removes the wallet encryption key from memory, locking the wallet. - After calling this method, you will need to call walletpassphrase - again before being able to call any methods which require the wallet - to be unlocked. - """ - try: - return self.proxy.walletlock() - except JSONRPCException as e: - raise _wrap_exception(e.error) - - def walletpassphrasechange(self, oldpassphrase, newpassphrase, dont_raise=False): - """ - Changes the wallet passphrase from to . - - Arguments: - - - *dont_raise* -- instead of raising `~mmgen.rpc.exceptions.WalletPassphraseIncorrect` - return False. - """ - try: - self.proxy.walletpassphrasechange(oldpassphrase, newpassphrase) - return True - except JSONRPCException as e: - json_exception = _wrap_exception(e.error) - if dont_raise and isinstance(json_exception, WalletPassphraseIncorrect): - return False - raise json_exception + def sendrawtransaction(self,tx): + """ + """ + try: + return self.proxy.sendrawtransaction(tx) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def stop(self): + """ + Stop bitcoin server. + """ + try: + self.proxy.stop() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getblock(self, hash): + """ + Returns information about the given block hash. + """ + try: + return self.proxy.getblock(hash) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getblockcount(self): + """ + Returns the number of blocks in the longest block chain. + """ + try: + return self.proxy.getblockcount() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getblockhash(self, index): + """ + Returns hash of block in best-block-chain at index. + + :param index: index ob the block + + """ + try: + return self.proxy.getblockhash(index) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getblocknumber(self): + """ + Returns the block number of the latest block in the longest block chain. + Deprecated. Use getblockcount instead. + """ + return self.getblockcount() + + def getconnectioncount(self): + """ + Returns the number of connections to other nodes. + """ + try: + return self.proxy.getconnectioncount() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getdifficulty(self): + """ + Returns the proof-of-work difficulty as a multiple of the minimum difficulty. + """ + try: + return self.proxy.getdifficulty() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getgenerate(self): + """ + Returns :const:`True` or :const:`False`, depending on whether + generation is enabled. + """ + try: + return self.proxy.getgenerate() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def setgenerate(self, generate, genproclimit=None): + """ + Enable or disable generation (mining) of coins. + + Arguments: + + - *generate* -- is :const:`True` or :const:`False` to turn generation + on or off. + - *genproclimit* -- Number of processors that are used for generation, + -1 is unlimited. + + """ + try: + if genproclimit is None: + return self.proxy.setgenerate(generate) + else: + return self.proxy.setgenerate(generate, genproclimit) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def gethashespersec(self): + """ + Returns a recent hashes per second performance measurement while generating. + """ + try: + return self.proxy.gethashespersec() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getinfo(self): + """ + Returns an :class:`~mmgen.rpc.data.ServerInfo` object containing + various state info. + """ + try: + return ServerInfo(**self.proxy.getinfo()) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getmininginfo(self): + """ + Returns an :class:`~mmgen.rpc.data.MiningInfo` object containing various + mining state info. + """ + try: + return MiningInfo(**self.proxy.getmininginfo()) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getnewaddress(self, account=None): + """ + Returns a new bitcoin address for receiving payments. + + Arguments: + + - *account* -- If account is specified (recommended), it is added to the + address book so that payments received with the address will be + credited to it. + + """ + try: + if account is None: + return self.proxy.getnewaddress() + else: + return self.proxy.getnewaddress(account) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getaccountaddress(self, account): + """ + Returns the current bitcoin address for receiving payments to an account. + + Arguments: + + - *account* -- Account for which the address should be returned. + + """ + try: + return self.proxy.getaccountaddress(account) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def setaccount(self, bitcoinaddress, account): + """ + Sets the account associated with the given address. + + Arguments: + + - *bitcoinaddress* -- Bitcoin address to associate. + - *account* -- Account to associate the address to. + + """ + try: + return self.proxy.setaccount(bitcoinaddress, account) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getaccount(self, bitcoinaddress): + """ + Returns the account associated with the given address. + + Arguments: + + - *bitcoinaddress* -- Bitcoin address to get account for. + """ + try: + return self.proxy.getaccount(bitcoinaddress) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getaddressesbyaccount(self, account): + """ + Returns the list of addresses for the given account. + + Arguments: + + - *account* -- Account to get list of addresses for. + """ + try: + return self.proxy.getaddressesbyaccount(account) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def sendtoaddress(self, bitcoinaddress, amount, comment=None, comment_to=None): + """ + Sends *amount* from the server's available balance to *bitcoinaddress*. + + Arguments: + + - *bitcoinaddress* -- Bitcoin address to send to. + - *amount* -- Amount to send (float, rounded to the nearest 0.01). + - *minconf* -- Minimum number of confirmations required for transferred + balance. + - *comment* -- Comment for transaction. + - *comment_to* -- Comment for to-address. + + """ + try: + if comment is None: + return self.proxy.sendtoaddress(bitcoinaddress, amount) + elif comment_to is None: + return self.proxy.sendtoaddress(bitcoinaddress, amount, comment) + else: + return self.proxy.sendtoaddress(bitcoinaddress, amount, comment, comment_to) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getreceivedbyaddress(self, bitcoinaddress, minconf=1): + """ + Returns the total amount received by a bitcoin address in transactions + with at least a certain number of confirmations. + + Arguments: + + - *bitcoinaddress* -- Address to query for total amount. + + - *minconf* -- Number of confirmations to require, defaults to 1. + """ + try: + return self.proxy.getreceivedbyaddress(bitcoinaddress, minconf) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getreceivedbyaccount(self, account, minconf=1): + """ + Returns the total amount received by addresses with an account in + transactions with at least a certain number of confirmations. + + Arguments: + + - *account* -- Account to query for total amount. + - *minconf* -- Number of confirmations to require, defaults to 1. + + """ + try: + return self.proxy.getreceivedbyaccount(account, minconf) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def gettransaction(self, txid): + """ + Get detailed information about transaction + + Arguments: + + - *txid* -- Transactiond id for which the info should be returned + + """ + try: + return TransactionInfo(**self.proxy.gettransaction(txid)) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getrawtransaction(self, txid, verbose=True): + """ + Get transaction raw info + + Arguments: + + - *txid* -- Transactiond id for which the info should be returned. + - *verbose* -- If False, return only the "hex" of the transaction. + + """ + try: + if verbose: + return TransactionInfo(**self.proxy.getrawtransaction(txid, 1)) + return self.proxy.getrawtransaction(txid, 0) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def createrawtransaction(self, inputs, outputs): + """ + Creates a raw transaction spending given inputs + (a list of dictionaries, each containing a transaction id and an output + number), sending to given address(es). + + Returns hex-encoded raw transaction. + + Example usage: + >>> conn.createrawtransaction( + [{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c", + "vout": 0}], + {"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50}) + + + Arguments: + + - *inputs* -- A list of {"txid": txid, "vout": n} dictionaries. + - *outputs* -- A dictionary mapping (public) addresses to the amount + they are to be paid. + """ + try: + return self.proxy.createrawtransaction(inputs, outputs) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def signrawtransaction(self, hexstring, previous_transactions=None, private_keys=None): + """ + Sign inputs for raw transaction (serialized, hex-encoded). + + Returns a dictionary with the keys: + "hex": raw transaction with signature(s) (hex-encoded string) + "complete": 1 if transaction has a complete set of signature(s), 0 if not + + Arguments: + + - *hexstring* -- A hex string of the transaction to sign. + - *previous_transactions* -- A (possibly empty) list of dictionaries of + the form: + {"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex}, + representing previous transaction outputs that this transaction depends + on but may not yet be in the block chain. + - *private_keys* -- A (possibly empty) list of base58-encoded private + keys that, if given, will be the only keys used to sign the transaction. + """ + try: + return dict(self.proxy.signrawtransaction(hexstring, + previous_transactions, private_keys)) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def decoderawtransaction(self, hexstring): + """ + Produces a human-readable JSON object for a raw transaction. + + Arguments: + + - *hexstring* -- A hex string of the transaction to be decoded. + """ + try: + return dict(self.proxy.decoderawtransaction(hexstring)) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listsinceblock(self, block_hash): + try: + res = self.proxy.listsinceblock(block_hash) + res['transactions'] = [TransactionInfo(**x) for x in res['transactions']] + return res + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listreceivedbyaddress(self, minconf=1, includeempty=False): + """ + Returns a list of addresses. + + Each address is represented with a + :class:`~mmgen.rpc.data.AddressInfo` object. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + - *includeempty* -- Whether to include addresses that haven't received + any payments. + + """ + try: + return [AddressInfo(**x) for x in + self.proxy.listreceivedbyaddress(minconf, includeempty)] + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listaccounts(self, minconf=1, as_dict=False): + """ + Returns a list of account names. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + - *as_dict* -- Returns a dictionary of account names, with their balance as values. + """ + try: + if as_dict: + return dict(self.proxy.listaccounts(minconf)) + else: + return self.proxy.listaccounts(minconf).keys() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listreceivedbyaccount(self, minconf=1, includeempty=False): + """ + Returns a list of accounts. + + Each account is represented with a :class:`~mmgen.rpc.data.AccountInfo` object. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + + - *includeempty* -- Whether to include addresses that haven't received any payments. + """ + try: + return [AccountInfo(**x) for x in + self.proxy.listreceivedbyaccount(minconf, includeempty)] + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listtransactions(self, account=None, count=10, from_=0, address=None): + """ + Returns a list of the last transactions for an account. + + Each transaction is represented with a :class:`~mmgen.rpc.data.TransactionInfo` object. + + Arguments: + + - *account* -- Account to list transactions from. Return transactions from + all accounts if None. + - *count* -- Number of transactions to return. + - *from_* -- Skip the first transactions. + - *address* -- Receive address to consider + """ + accounts = [account] if account is not None else self.listaccounts(as_dict=True).iterkeys() + try: + return [TransactionInfo(**tx) for acc in accounts for + tx in self.proxy.listtransactions(acc, count, from_) if + address is None or tx["address"] == address] + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def backupwallet(self, destination): + """ + Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path + with filename. + + Arguments: + - *destination* -- directory or path with filename to backup wallet to. + + """ + try: + return self.proxy.backupwallet(destination) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def validateaddress(self, validateaddress): + """ + Validate a bitcoin address and return information for it. + + The information is represented by a :class:`~mmgen.rpc.data.AddressValidation` object. + + Arguments: -- Address to validate. + + + - *validateaddress* + """ + try: + return AddressValidation(**self.proxy.validateaddress(validateaddress)) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getbalance(self, account=None, minconf=None): + """ + Get the current balance, either for an account or the total server balance. + + Arguments: + - *account* -- If this parameter is specified, returns the balance in the account. + - *minconf* -- Minimum number of confirmations required for transferred balance. + + """ + args = [] + if account: + args.append(account) + if minconf is not None: + args.append(minconf) + try: + return self.proxy.getbalance(*args) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def move(self, fromaccount, toaccount, amount, minconf=1, comment=None): + """ + Move from one account in your wallet to another. + + Arguments: + + - *fromaccount* -- Source account name. + - *toaccount* -- Destination account name. + - *amount* -- Amount to transfer. + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment to add to transaction log. + + """ + try: + if comment is None: + return self.proxy.move(fromaccount, toaccount, amount, minconf) + else: + return self.proxy.move(fromaccount, toaccount, amount, minconf, comment) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def sendfrom(self, fromaccount, tobitcoinaddress, amount, minconf=1, comment=None, + comment_to=None): + """ + Sends amount from account's balance to bitcoinaddress. This method will fail + if there is less than amount bitcoins with minconf confirmations in the account's + balance (unless account is the empty-string-named default account; it + behaves like the sendtoaddress method). Returns transaction ID on success. + + Arguments: + + - *fromaccount* -- Account to send from. + - *tobitcoinaddress* -- Bitcoin address to send to. + - *amount* -- Amount to send (float, rounded to the nearest 0.01). + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment for transaction. + - *comment_to* -- Comment for to-address. + + """ + try: + if comment is None: + return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf) + elif comment_to is None: + return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf, comment) + else: + return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf, comment, comment_to) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def sendmany(self, fromaccount, todict, minconf=1, comment=None): + """ + Sends specified amounts from account's balance to bitcoinaddresses. + This method will fail if there is less than total amount bitcoins with + minconf confirmations in the account's balance (unless account is the + empty-string-named default account; Returns transaction ID on + success. + + Arguments: + + - *fromaccount* -- Account to send from. + - *todict* -- Dictionary with Bitcoin addresses as keys and amounts as + values. + - *minconf* -- Minimum number of confirmations required for transferred + balance. + - *comment* -- Comment for transaction. + + """ + try: + if comment is None: + return self.proxy.sendmany(fromaccount, todict, minconf) + else: + return self.proxy.sendmany(fromaccount, todict, minconf, comment) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def verifymessage(self, bitcoinaddress, signature, message): + """ + Verifies a signature given the bitcoinaddress used to sign, + the signature itself, and the message that was signed. + Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid. + + Arguments: + + - *bitcoinaddress* -- the bitcoinaddress used to sign the message + - *signature* -- the signature to be verified + - *message* -- the message that was originally signed + + """ + try: + return self.proxy.verifymessage(bitcoinaddress, signature, message) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def getwork(self, data=None): + """ + Get work for remote mining, or submit result. + If data is specified, the server tries to solve the block + using the provided data and returns :const:`True` if it was successful. + If not, the function returns formatted hash data (:class:`~mmgen.rpc.data.WorkItem`) + to work on. + + Arguments: + + - *data* -- Result from remote mining. + + """ + try: + if data is None: + # Only if no data provided, it returns a WorkItem + return WorkItem(**self.proxy.getwork()) + else: + return self.proxy.getwork(data) + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def listunspent(self, minconf=1, maxconf=999999): + """ + Returns a list of unspent transaction inputs in the wallet. + + Arguments: + + - *minconf* -- Minimum number of confirmations required to be listed. + + - *maxconf* -- Maximal number of confirmations allowed to be listed. + + + """ + try: + return [TransactionInfo(**tx) for tx in + self.proxy.listunspent(minconf, maxconf)] + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def keypoolrefill(self): + "Fills the keypool, requires wallet passphrase to be set." + try: + self.proxy.keypoolrefill() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def walletpassphrase(self, passphrase, timeout, dont_raise=False): + """ + Stores the wallet decryption key in memory for seconds. + + - *passphrase* -- The wallet passphrase. + + - *timeout* -- Time in seconds to keep the wallet unlocked + (by keeping the passphrase in memory). + + - *dont_raise* -- instead of raising `~mmgen.rpc.exceptions.WalletPassphraseIncorrect` + return False. + """ + try: + self.proxy.walletpassphrase(passphrase, timeout) + return True + except JSONRPCException as e: + json_exception = _wrap_exception(e.error) + if dont_raise: + if isinstance(json_exception, WalletPassphraseIncorrect): + return False + elif isinstance(json_exception, WalletAlreadyUnlocked): + return True + raise json_exception + + def walletlock(self): + """ + Removes the wallet encryption key from memory, locking the wallet. + After calling this method, you will need to call walletpassphrase + again before being able to call any methods which require the wallet + to be unlocked. + """ + try: + return self.proxy.walletlock() + except JSONRPCException as e: + raise _wrap_exception(e.error) + + def walletpassphrasechange(self, oldpassphrase, newpassphrase, dont_raise=False): + """ + Changes the wallet passphrase from to . + + Arguments: + + - *dont_raise* -- instead of raising + `~mmgen.rpc.exceptions.WalletPassphraseIncorrect` return False. + """ + try: + self.proxy.walletpassphrasechange(oldpassphrase, newpassphrase) + return True + except JSONRPCException as e: + json_exception = _wrap_exception(e.error) + if dont_raise and isinstance(json_exception, WalletPassphraseIncorrect): + return False + raise json_exception diff --git a/mmgen/rpc/proxy.py b/mmgen/rpc/proxy.py index b17ba11d..1457747b 100755 --- a/mmgen/rpc/proxy.py +++ b/mmgen/rpc/proxy.py @@ -1,6 +1,6 @@ """ Copyright (C) 2013 by philemon - Added configurable http_timeout + Added http_timeout from mmgen.config Previous copyright from bitcoin-python/proxy.py: @@ -10,7 +10,7 @@ ServiceProxy class: - HTTP connections persist for the life of the AuthServiceProxy object - (if server supports HTTP/1.1) + (if server supports HTTP/1.1) - sends protocol 'version', per JSON-RPC 1.1 - sends proper, incrementing 'id' - sends Basic HTTP authentication headers @@ -39,99 +39,105 @@ """ try: - import http.client as httplib + import http.client as httplib except ImportError: - import httplib + import httplib import base64 import json import decimal try: - import urllib.parse as urlparse + import urllib.parse as urlparse except ImportError: - import urlparse + import urlparse USER_AGENT = "AuthServiceProxy/0.1" class JSONRPCException(Exception): - def __init__(self, rpcError): - Exception.__init__(self) - self.error = rpcError + def __init__(self, rpcError): + Exception.__init__(self) + self.error = rpcError +import mmgen.config + class AuthServiceProxy(object): - def __init__(self, serviceURL, serviceName=None, http_timeout=30): - self.__serviceURL = serviceURL - self.__serviceName = serviceName - self.__url = urlparse.urlparse(serviceURL) - if self.__url.port is None: - port = 80 - else: - port = self.__url.port - self.__idcnt = 0 - authpair = "%s:%s" % (self.__url.username, self.__url.password) - authpair = authpair.encode('utf8') - self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair) - if self.__url.scheme == 'https': - self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, - None, None, False, http_timeout) - else: - self.__conn = httplib.HTTPConnection(self.__url.hostname, port, - False, http_timeout) + def __init__(self, serviceURL, serviceName = None): - def __getattr__(self, name): - if self.__serviceName != None: - name = "%s.%s" % (self.__serviceName, name) - return AuthServiceProxy(self.__serviceURL, name) + self.__serviceURL = serviceURL + self.__serviceName = serviceName + self.__url = urlparse.urlparse(serviceURL) + if self.__url.port is None: + port = 80 + else: + port = self.__url.port + self.__idcnt = 0 + authpair = "%s:%s" % (self.__url.username, self.__url.password) + authpair = authpair.encode('utf8') + self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair) - def __call__(self, *args): - self.__idcnt += 1 + http_timeout = mmgen.config.http_timeout - postdata = json.dumps({ - 'version': '1.1', - 'method': self.__serviceName, - 'params': args, - 'id': self.__idcnt}) - try: - self.__conn.request('POST', self.__url.path, postdata, - { 'Host' : self.__url.hostname, - 'User-Agent' : USER_AGENT, - 'Authorization' : self.__authhdr, - 'Content-type' : 'application/json' }) - except: - print "Unable to connect to bitcoind. Exiting" - import sys - sys.exit(2) + if self.__url.scheme == 'https': + self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, + None, None, False, timeout=http_timeout) + else: + self.__conn = httplib.HTTPConnection(self.__url.hostname, port, + False, timeout=http_timeout) - httpresp = self.__conn.getresponse() - if httpresp is None: - raise JSONRPCException({ - 'code' : -342, 'message' : 'missing HTTP response from server'}) + def __getattr__(self, name): + if self.__serviceName != None: + name = "%s.%s" % (self.__serviceName, name) + return AuthServiceProxy(self.__serviceURL, name) - resp = httpresp.read() - resp = resp.decode('utf8') - resp = json.loads(resp, parse_float=decimal.Decimal) - if 'error' in resp and resp['error'] != None: - raise JSONRPCException(resp['error']) - elif 'result' not in resp: - raise JSONRPCException({ - 'code' : -343, 'message' : 'missing JSON-RPC result'}) - else: - return resp['result'] + def __call__(self, *args): + self.__idcnt += 1 - def _batch(self, rpc_call_list): - postdata = json.dumps(list(rpc_call_list)) - self.__conn.request('POST', self.__url.path, postdata, - { 'Host' : self.__url.hostname, - 'User-Agent' : USER_AGENT, - 'Authorization' : self.__authhdr, - 'Content-type' : 'application/json' }) + postdata = json.dumps({ + 'version': '1.1', + 'method': self.__serviceName, + 'params': args, + 'id': self.__idcnt}) + try: + self.__conn.request('POST', self.__url.path, postdata, + { 'Host' : self.__url.hostname, + 'User-Agent' : USER_AGENT, + 'Authorization' : self.__authhdr, + 'Content-type' : 'application/json' }) + except: + print "Unable to connect to bitcoind. Exiting" + import sys + sys.exit(2) - httpresp = self.__conn.getresponse() - if httpresp is None: - raise JSONRPCException({ - 'code' : -342, 'message' : 'missing HTTP response from server'}) + httpresp = self.__conn.getresponse() + if httpresp is None: + raise JSONRPCException({ + 'code' : -342, 'message' : 'missing HTTP response from server'}) - resp = httpresp.read() - resp = resp.decode('utf8') - resp = json.loads(resp, parse_float=decimal.Decimal) - return resp + resp = httpresp.read() + resp = resp.decode('utf8') + resp = json.loads(resp, parse_float=decimal.Decimal) + if 'error' in resp and resp['error'] != None: + raise JSONRPCException(resp['error']) + elif 'result' not in resp: + raise JSONRPCException({ + 'code' : -343, 'message' : 'missing JSON-RPC result'}) + else: + return resp['result'] + + def _batch(self, rpc_call_list): + postdata = json.dumps(list(rpc_call_list)) + self.__conn.request('POST', self.__url.path, postdata, + { 'Host' : self.__url.hostname, + 'User-Agent' : USER_AGENT, + 'Authorization' : self.__authhdr, + 'Content-type' : 'application/json' }) + + httpresp = self.__conn.getresponse() + if httpresp is None: + raise JSONRPCException({ + 'code' : -342, 'message' : 'missing HTTP response from server'}) + + resp = httpresp.read() + resp = resp.decode('utf8') + resp = json.loads(resp, parse_float=decimal.Decimal) + return resp diff --git a/mmgen/tx.py b/mmgen/tx.py index 24438703..7e0623be 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -48,7 +48,7 @@ Selected mmgen inputs: %s""" } -def connect_to_bitcoind(http_timeout=30): +def connect_to_bitcoind(): host,port,user,passwd = "localhost",8332,"rpcuser","rpcpassword" cfg = get_cfg_options((user,passwd)) @@ -57,7 +57,7 @@ def connect_to_bitcoind(http_timeout=30): f = mmgen.rpc.connection.BitcoinConnection try: - c = f(cfg[user],cfg[passwd],host,port,http_timeout=http_timeout) + c = f(cfg[user],cfg[passwd],host,port) except: msg("Unable to establish RPC connection with bitcoind") sys.exit(2)