Browse Source

deleted: mmgen/connection.py
deleted: mmgen/proxy.py
new file: mmgen/rpc/__init__.py
new file: mmgen/rpc/config.py
new file: mmgen/rpc/connection.py
new file: mmgen/rpc/data.py
new file: mmgen/rpc/exceptions.py
new file: mmgen/rpc/proxy.py
new file: mmgen/rpc/util.py

philemon 11 years ago
parent
commit
db5ce0295e
12 changed files with 1307 additions and 754 deletions
  1. 1 1
      mmgen-addrimport
  2. 1 1
      mmgen-txsend
  3. 1 1
      mmgen/__init__.py
  4. 0 737
      mmgen/connection.py
  5. 54 0
      mmgen/rpc/__init__.py
  6. 75 0
      mmgen/rpc/config.py
  7. 743 0
      mmgen/rpc/connection.py
  8. 168 0
      mmgen/rpc/data.py
  9. 203 0
      mmgen/rpc/exceptions.py
  10. 8 6
      mmgen/rpc/proxy.py
  11. 49 0
      mmgen/rpc/util.py
  12. 4 8
      mmgen/tx.py

+ 1 - 1
mmgen-addrimport

@@ -51,7 +51,7 @@ check_infile(cmd_args[0])
 seed_id,addr_data = parse_addrs_file(cmd_args[0])
 seed_id,addr_data = parse_addrs_file(cmd_args[0])
 
 
 from mmgen.tx import connect_to_bitcoind
 from mmgen.tx import connect_to_bitcoind
-c = connect_to_bitcoind(mmgen=True)
+c = connect_to_bitcoind(http_timeout=3600)
 
 
 message = """
 message = """
 Importing addresses can take a long time, up to 30 min. per address on a
 Importing addresses can take a long time, up to 30 min. per address on a

+ 1 - 1
mmgen-txsend

@@ -83,7 +83,7 @@ confirm_or_exit(warn, what, expect)
 
 
 msg("Sending transaction")
 msg("Sending transaction")
 
 
-c = connect_to_bitcoind(mmgen=True)
+c = connect_to_bitcoind()
 
 
 try:
 try:
 	tx = c.sendrawtransaction(tx_sig)
 	tx = c.sendrawtransaction(tx_sig)

+ 1 - 1
mmgen/__init__.py

@@ -18,8 +18,8 @@
 """
 """
 MMGen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 MMGen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 """
 """
-
 __all__ = [
 __all__ = [
+	'rpc',
 	'addr.py',
 	'addr.py',
 	'bitcoin.py',
 	'bitcoin.py',
 	'config.py',
 	'config.py',

+ 0 - 737
mmgen/connection.py

@@ -1,737 +0,0 @@
-# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-"""
-Connect to Bitcoin server via JSON-RPC.
-"""
-from mmgen.proxy import JSONRPCException, AuthServiceProxy
-from bitcoinrpc.exceptions import (_wrap_exception, WalletPassphraseIncorrect,
-			WalletAlreadyUnlocked)
-from bitcoinrpc.data import (ServerInfo, AccountInfo, AddressInfo,
-			TransactionInfo, AddressValidation, WorkItem, MiningInfo)
-
-
-class MMGenBitcoinConnection(object):
-	"""
-	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.
-
-	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):
-		"""
-		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 <address> [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)
-
-# sendrawtransaction <hex string> [allowhighfees=false]
-	def sendrawtransaction(self,tx):
-		"""
-		"""
-		try:
-			return self.proxy.sendrawtransaction(tx)
-		except JSONRPCException as e:
-			raise _wrap_exception(e.error)
-
-#     def getbalance(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:`~bitcoinrpc.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:`~bitcoinrpc.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:`~bitcoinrpc.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:`~bitcoinrpc.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:`~bitcoinrpc.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 <from_> 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:`~bitcoinrpc.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:`~bitcoinrpc.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 <timeout> 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 `~bitcoinrpc.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 <oldpassphrase> to <newpassphrase>.
-# 
-#         Arguments:
-# 
-#         - *dont_raise* -- instead of raising `~bitcoinrpc.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

+ 54 - 0
mmgen/rpc/__init__.py

@@ -0,0 +1,54 @@
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""
+bitcoin-python - Easy-to-use Bitcoin API client
+"""
+
+
+def connect_to_local(filename=None):
+    """
+    Connect to default bitcoin instance owned by this user, on this machine.
+
+    Returns a :class:`~mmgen.rpc.connection.BitcoinConnection` object.
+
+    Arguments:
+
+        - `filename`: Path to a configuration file in a non-standard location (optional)
+    """
+    from mmgen.rpc.connection import BitcoinConnection
+    from mmgen.rpc.config import read_default_config
+
+    cfg = read_default_config(filename)
+    port = int(cfg.get('rpcport', '18332' if cfg.get('testnet') else '8332'))
+    rcpuser = cfg.get('rpcuser', '')
+
+    return BitcoinConnection(rcpuser, cfg['rpcpassword'], 'localhost', port)
+
+
+def connect_to_remote(user, password, host='localhost', port=8332,
+                      use_https=False):
+    """
+    Connect to remote or alternative local bitcoin client instance.
+
+    Returns a :class:`~mmgen.rpc.connection.BitcoinConnection` object.
+    """
+    from mmgen.rpc.connection import BitcoinConnection
+
+    return BitcoinConnection(user, password, host, port, use_https)

+ 75 - 0
mmgen/rpc/config.py

@@ -0,0 +1,75 @@
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""
+Utilities for reading bitcoin configuration files.
+"""
+
+
+def read_config_file(filename):
+    """
+    Read a simple ``'='``-delimited config file.
+    Raises :const:`IOError` if unable to open file, or :const:`ValueError`
+    if an parse error occurs.
+    """
+    f = open(filename)
+    try:
+        cfg = {}
+        for line in f:
+            line = line.strip()
+            if line and not line.startswith("#"):
+                try:
+                    (key, value) = line.split('=', 1)
+                    cfg[key] = value
+                except ValueError:
+                    pass  # Happens when line has no '=', ignore
+    finally:
+        f.close()
+    return cfg
+
+
+def read_default_config(filename=None):
+    """
+    Read bitcoin default configuration from the current user's home directory.
+
+    Arguments:
+
+    - `filename`: Path to a configuration file in a non-standard location (optional)
+    """
+    if filename is None:
+        import os
+        import platform
+        home = os.getenv("HOME")
+        if not home:
+            raise IOError("Home directory not defined, don't know where to look for config file")
+
+        if platform.system() == "Darwin":
+            location = 'Library/Application Support/Bitcoin/bitcoin.conf'
+        else:
+            location = '.bitcoin/bitcoin.conf'
+        filename = os.path.join(home, location)
+
+    elif filename.startswith("~"):
+        import os
+        filename = os.path.expanduser(filename)
+
+    try:
+        return read_config_file(filename)
+    except (IOError, ValueError):
+        pass  # Cannot read config file, ignore

+ 743 - 0
mmgen/rpc/connection.py

@@ -0,0 +1,743 @@
+# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Added configurable http_timeout and methods for
+#   sendrawtransaction,
+#   importaddress
+#
+# Previous copyright from bitcoin-python/connection.py:
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""
+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)
+
+
+class BitcoinConnection(object):
+    """
+    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.
+
+    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)
+
+# importaddress <address> [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)
+
+# sendrawtransaction <hex string> [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 <from_> 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 <timeout> 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 <oldpassphrase> to <newpassphrase>.
+
+        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

+ 168 - 0
mmgen/rpc/data.py

@@ -0,0 +1,168 @@
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""
+Bitcoin RPC service, data objects.
+"""
+from mmgen.rpc.util import DStruct
+
+
+class ServerInfo(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.getinfo`.
+
+    - *errors* -- Number of errors.
+
+    - *blocks* -- Number of blocks.
+
+    - *paytxfee* -- Amount of transaction fee to pay.
+
+    - *keypoololdest* -- Oldest key in keypool.
+
+    - *genproclimit* -- Processor limit for generation.
+
+    - *connections* -- Number of connections to other clients.
+
+    - *difficulty* -- Current generating difficulty.
+
+    - *testnet* -- True if connected to testnet, False if on real network.
+
+    - *version* -- Bitcoin client version.
+
+    - *proxy* -- Proxy configured in client.
+
+    - *hashespersec* -- Number of hashes per second (if generation enabled).
+
+    - *balance* -- Total current server balance.
+
+    - *generate* -- True if generation enabled, False if not.
+
+    - *unlocked_until* -- Timestamp (seconds since epoch) after which the wallet
+                          will be/was locked (if wallet encryption is enabled).
+
+    """
+
+
+class AccountInfo(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.listreceivedbyaccount`.
+
+    - *account* -- The account of the receiving address.
+
+    - *amount* -- Total amount received by the address.
+
+    - *confirmations* -- Number of confirmations of the most recent transaction included.
+
+    """
+
+
+class AddressInfo(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.listreceivedbyaddress`.
+
+    - *address* -- Receiving address.
+
+    - *account* -- The account of the receiving address.
+
+    - *amount* -- Total amount received by the address.
+
+    - *confirmations* -- Number of confirmations of the most recent transaction included.
+
+    """
+
+
+class TransactionInfo(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.listtransactions`.
+
+    - *account* -- account name.
+
+    - *address* -- the address bitcoins were sent to, or received from.
+
+    - *category* -- will be generate, send, receive, or move.
+
+    - *amount* -- amount of transaction.
+
+    - *fee* -- Fee (if any) paid (only for send transactions).
+
+    - *confirmations* -- number of confirmations (only for generate/send/receive).
+
+    - *txid* -- transaction ID (only for generate/send/receive).
+
+    - *otheraccount* -- account funds were moved to or from (only for move).
+
+    - *message* -- message associated with transaction (only for send).
+
+    - *to* -- message-to associated with transaction (only for send).
+    """
+
+
+class AddressValidation(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.validateaddress`.
+
+    - *isvalid* -- Validatity of address (:const:`True` or :const:`False`).
+
+    - *ismine* -- :const:`True` if the address is in the server's wallet.
+
+    - *address* -- Bitcoin address.
+
+    """
+
+
+class WorkItem(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.getwork`.
+
+    - *midstate* -- Precomputed hash state after hashing the first half of the data.
+
+    - *data* -- Block data.
+
+    - *hash1* -- Formatted hash buffer for second hash.
+
+    - *target* -- Little endian hash target.
+
+    """
+
+
+class MiningInfo(DStruct):
+    """
+    Information object returned by :func:`~mmgen.rpc.connection.BitcoinConnection.getmininginfo`.
+
+    - *blocks* -- Number of blocks.
+
+    - *currentblocksize* -- Size of current block.
+
+    - *currentblocktx* -- Number of transactions in current block.
+
+    - *difficulty* -- Current generating difficulty.
+
+    - *errors* -- Number of errors.
+
+    - *generate* -- True if generation enabled, False if not.
+
+    - *genproclimit* -- Processor limit for generation.
+
+    - *hashespersec* -- Number of hashes per second (if generation enabled).
+
+    - *pooledtx* -- Number of pooled transactions.
+
+    - *testnet* -- True if connected to testnet, False if on real network.
+
+    """

+ 203 - 0
mmgen/rpc/exceptions.py

@@ -0,0 +1,203 @@
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""
+Exception definitions.
+"""
+
+
+class BitcoinException(Exception):
+    """
+    Base class for exceptions received from Bitcoin server.
+
+    - *code* -- Error code from ``bitcoind``.
+    """
+    # Standard JSON-RPC 2.0 errors
+    INVALID_REQUEST  = -32600,
+    METHOD_NOT_FOUND = -32601,
+    INVALID_PARAMS   = -32602,
+    INTERNAL_ERROR   = -32603,
+    PARSE_ERROR      = -32700,
+
+    # General application defined errors
+    MISC_ERROR                  = -1  # std::exception thrown in command handling
+    FORBIDDEN_BY_SAFE_MODE      = -2  # Server is in safe mode, and command is not allowed in safe mode
+    TYPE_ERROR                  = -3  # Unexpected type was passed as parameter
+    INVALID_ADDRESS_OR_KEY      = -5  # Invalid address or key
+    OUT_OF_MEMORY               = -7  # Ran out of memory during operation
+    INVALID_PARAMETER           = -8  # Invalid, missing or duplicate parameter
+    DATABASE_ERROR              = -20 # Database error
+    DESERIALIZATION_ERROR       = -22 # Error parsing or validating structure in raw format
+
+    # P2P client errors
+    CLIENT_NOT_CONNECTED        = -9  # Bitcoin is not connected
+    CLIENT_IN_INITIAL_DOWNLOAD  = -10 # Still downloading initial blocks
+
+    # Wallet errors
+    WALLET_ERROR                = -4  # Unspecified problem with wallet (key not found etc.)
+    WALLET_INSUFFICIENT_FUNDS   = -6  # Not enough funds in wallet or account
+    WALLET_INVALID_ACCOUNT_NAME = -11 # Invalid account name
+    WALLET_KEYPOOL_RAN_OUT      = -12 # Keypool ran out, call keypoolrefill first
+    WALLET_UNLOCK_NEEDED        = -13 # Enter the wallet passphrase with walletpassphrase first
+    WALLET_PASSPHRASE_INCORRECT = -14 # The wallet passphrase entered was incorrect
+    WALLET_WRONG_ENC_STATE      = -15 # Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+    WALLET_ENCRYPTION_FAILED    = -16 # Failed to encrypt the wallet
+    WALLET_ALREADY_UNLOCKED     = -17 # Wallet is already unlocked
+
+    def __init__(self, error):
+        Exception.__init__(self, error['message'])
+        self.code = error['code']
+
+
+##### General application defined errors
+class SafeMode(BitcoinException):
+    """
+    Operation denied in safe mode (run ``bitcoind`` with ``-disablesafemode``).
+    """
+
+
+class JSONTypeError(BitcoinException):
+    """
+    Unexpected type was passed as parameter
+    """
+InvalidAmount = JSONTypeError  # Backwards compatibility
+
+
+class InvalidAddressOrKey(BitcoinException):
+    """
+    Invalid address or key.
+    """
+InvalidTransactionID = InvalidAddressOrKey  # Backwards compatibility
+
+
+class OutOfMemory(BitcoinException):
+    """
+    Out of memory during operation.
+    """
+
+
+class InvalidParameter(BitcoinException):
+    """
+    Invalid parameter provided to RPC call.
+    """
+
+
+##### Client errors
+class ClientException(BitcoinException):
+    """
+    P2P network error.
+    This exception is never raised but functions as a superclass
+    for other P2P client exceptions.
+    """
+
+
+class NotConnected(ClientException):
+    """
+    Not connected to any peers.
+    """
+
+
+class DownloadingBlocks(ClientException):
+    """
+    Client is still downloading blocks.
+    """
+
+
+##### Wallet errors
+class WalletError(BitcoinException):
+    """
+    Unspecified problem with wallet (key not found etc.)
+    """
+SendError = WalletError  # Backwards compatibility
+
+class InsufficientFunds(WalletError):
+    """
+    Insufficient funds to complete transaction in wallet or account
+    """
+
+class InvalidAccountName(WalletError):
+    """
+    Invalid account name
+    """
+
+
+class KeypoolRanOut(WalletError):
+    """
+    Keypool ran out, call keypoolrefill first
+    """
+
+
+class WalletUnlockNeeded(WalletError):
+    """
+    Enter the wallet passphrase with walletpassphrase first
+    """
+
+
+class WalletPassphraseIncorrect(WalletError):
+    """
+    The wallet passphrase entered was incorrect
+    """
+
+
+class WalletWrongEncState(WalletError):
+    """
+    Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+    """
+
+
+class WalletEncryptionFailed(WalletError):
+    """
+    Failed to encrypt the wallet
+    """
+
+
+class WalletAlreadyUnlocked(WalletError):
+    """
+    Wallet is already unlocked
+    """
+
+
+# For convenience, we define more specific exception classes
+# for the more common errors.
+_exception_map = {
+    BitcoinException.FORBIDDEN_BY_SAFE_MODE: SafeMode,
+    BitcoinException.TYPE_ERROR: JSONTypeError,
+    BitcoinException.WALLET_ERROR: WalletError,
+    BitcoinException.INVALID_ADDRESS_OR_KEY: InvalidAddressOrKey,
+    BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
+    BitcoinException.OUT_OF_MEMORY: OutOfMemory,
+    BitcoinException.INVALID_PARAMETER: InvalidParameter,
+    BitcoinException.CLIENT_NOT_CONNECTED: NotConnected,
+    BitcoinException.CLIENT_IN_INITIAL_DOWNLOAD: DownloadingBlocks,
+    BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
+    BitcoinException.WALLET_INVALID_ACCOUNT_NAME: InvalidAccountName,
+    BitcoinException.WALLET_KEYPOOL_RAN_OUT: KeypoolRanOut,
+    BitcoinException.WALLET_UNLOCK_NEEDED: WalletUnlockNeeded,
+    BitcoinException.WALLET_PASSPHRASE_INCORRECT: WalletPassphraseIncorrect,
+    BitcoinException.WALLET_WRONG_ENC_STATE: WalletWrongEncState,
+    BitcoinException.WALLET_ENCRYPTION_FAILED: WalletEncryptionFailed,
+    BitcoinException.WALLET_ALREADY_UNLOCKED: WalletAlreadyUnlocked,
+}
+
+
+def _wrap_exception(error):
+    """
+    Convert a JSON error object to a more specific Bitcoin exception.
+    """
+    return _exception_map.get(error['code'], BitcoinException)(error)

+ 8 - 6
mmgen/proxy.py → mmgen/rpc/proxy.py

@@ -1,4 +1,9 @@
 """
 """
+  Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+  Added configurable http_timeout
+
+  Previous copyright from bitcoin-python/proxy.py:
+
   Copyright 2011 Jeff Garzik
   Copyright 2011 Jeff Garzik
 
 
   AuthServiceProxy has the following improvements over python-jsonrpc's
   AuthServiceProxy has the following improvements over python-jsonrpc's
@@ -47,9 +52,6 @@ except ImportError:
 
 
 USER_AGENT = "AuthServiceProxy/0.1"
 USER_AGENT = "AuthServiceProxy/0.1"
 
 
-HTTP_TIMEOUT = 7200
-
-
 class JSONRPCException(Exception):
 class JSONRPCException(Exception):
     def __init__(self, rpcError):
     def __init__(self, rpcError):
         Exception.__init__(self)
         Exception.__init__(self)
@@ -57,7 +59,7 @@ class JSONRPCException(Exception):
 
 
 
 
 class AuthServiceProxy(object):
 class AuthServiceProxy(object):
-    def __init__(self, serviceURL, serviceName=None):
+    def __init__(self, serviceURL, serviceName=None, http_timeout=30):
         self.__serviceURL = serviceURL
         self.__serviceURL = serviceURL
         self.__serviceName = serviceName
         self.__serviceName = serviceName
         self.__url = urlparse.urlparse(serviceURL)
         self.__url = urlparse.urlparse(serviceURL)
@@ -71,10 +73,10 @@ class AuthServiceProxy(object):
         self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair)
         self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair)
         if self.__url.scheme == 'https':
         if self.__url.scheme == 'https':
             self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, None, None,False,
             self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, None, None,False,
-                                             HTTP_TIMEOUT)
+                                             http_timeout)
         else:
         else:
             self.__conn = httplib.HTTPConnection(self.__url.hostname, port, False,
             self.__conn = httplib.HTTPConnection(self.__url.hostname, port, False,
-                                             HTTP_TIMEOUT)
+                                             http_timeout)
 
 
     def __getattr__(self, name):
     def __getattr__(self, name):
         if self.__serviceName != None:
         if self.__serviceName != None:

+ 49 - 0
mmgen/rpc/util.py

@@ -0,0 +1,49 @@
+# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+"""Generic utilities used by bitcoin client library."""
+from copy import copy
+
+
+class DStruct(object):
+    """
+    Simple dynamic structure, like :const:`collections.namedtuple` but more flexible
+    (and less memory-efficient)
+    """
+    # Default arguments. Defaults are *shallow copied*, to allow defaults such as [].
+    _fields = []
+    _defaults = {}
+
+    def __init__(self, *args_t, **args_d):
+        # order
+        if len(args_t) > len(self._fields):
+            raise TypeError("Number of arguments is larger than of predefined fields")
+        # Copy default values
+        for (k, v) in self._defaults.iteritems():
+            self.__dict__[k] = copy(v)
+        # Set pass by value arguments
+        self.__dict__.update(zip(self._fields, args_t))
+        # dict
+        self.__dict__.update(args_d)
+
+    def __repr__(self):
+        return '{module}.{classname}({slots})'.format(
+            module=self.__class__.__module__, classname=self.__class__.__name__,
+            slots=", ".join('{k}={v!r}'.format(k=k, v=v) for k, v in
+                            self.__dict__.iteritems()))

+ 4 - 8
mmgen/tx.py

@@ -36,20 +36,16 @@ specified recipient address.
 }
 }
 
 
 
 
-def connect_to_bitcoind(mmgen=False):
+def connect_to_bitcoind(http_timeout=30):
 
 
 	host,port,user,passwd = "localhost",8332,"rpcuser","rpcpassword"
 	host,port,user,passwd = "localhost",8332,"rpcuser","rpcpassword"
 	cfg = get_cfg_options((user,passwd))
 	cfg = get_cfg_options((user,passwd))
 
 
-	if mmgen:
-		import mmgen.connection
-		f = mmgen.connection.MMGenBitcoinConnection
-	else:
-		import bitcoinrpc.connection
-		f = bitcoinrpc.connection.BitcoinConnection
+	import mmgen.rpc.connection
+	f = mmgen.rpc.connection.BitcoinConnection
 
 
 	try:
 	try:
-		c = f(cfg[user],cfg[passwd],host,port)
+		c = f(cfg[user],cfg[passwd],host,port,http_timeout=http_timeout)
 	except:
 	except:
 		msg("Unable to establish RPC connection with bitcoind")
 		msg("Unable to establish RPC connection with bitcoind")
 		sys.exit(2)
 		sys.exit(2)