Pyrpcwallet: lightweight json-rpc wallet compatible with bitcoind

[size=18pt]pyrpcwallet[/size]

https://github.com/JahPowerBit/pyrpcwallet

Lightweigt JSON RPC wallet compatible with bitcoind

* same commands and same result as bitcoind JSON-RPC API
* no need to download the blockchain
* usable as a python library to develop your own wallet
* usable as command line wallet (without json-rpc)
* private keys are crypted with the same algorithm as wallet.dat
* sqlite database easyly usable with all languages and commmand line client
* and off course compatible with counterpartyd

[size=14pt]Changelog[/size]

* v0.1

[size=14pt]installation[/size]

<br />brew update<br />brew install sqlite<br /><br />pip3 install bottle pycoin pycrypto<br /><br />pip3 install https://github.com/rogerbinns/apsw/archive/master.zip<br /><br />git clone https://github.com/JahPowerBit/pyrpcwallet.git<br /><br />cd pyrpcwallet<br /><br />

[size=14pt]Usage[/size]

<br />pyrpcwallet [-h] [--rpc-host RPC_HOST] [--rpc-port RPC_PORT]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [--rpc-user RPC_USER] [--rpc-password RPC_PASSWORD]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [--database DATABASE] [--update-interval UPDATE_INTERVAL]<br /><br />Lightweight Json RPC wallet<br /><br />optional arguments:<br />&nbsp; -h, --help&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; show this help message and exit<br />&nbsp; --rpc-host RPC_HOST&nbsp; the host to provide the JSON-RPC API (default:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localhost)<br />&nbsp; --rpc-port RPC_PORT&nbsp; port on which to provide the JSON-RPC API (default:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 8383)<br />&nbsp; --rpc-user RPC_USER&nbsp; required username to use the JSON-RPC API via HTTP<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; basic auth (default: bitcoinrpc)<br />&nbsp; --rpc-password RPC_PASSWORD<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; required password (for rpc-user) to use the JSON-RPC<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; API via HTTP basic auth (default: &quot;&quot;)<br />&nbsp; --database DATABASE&nbsp; database file path (default: wallet.db)<br />&nbsp; --update-interval UPDATE_INTERVAL<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; interval in minutes for updating balances and unspent<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outputs from blockchain.info. 0 for manual update with<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updatebalances command (default: 10).<br />

[size=14pt]Available commands[/size]

bitcoind commands

+ getinfo (return only unlock_until)
+ walletpassphrase
+ listaddressgroupings
+ getbalance
+ listunspent
+ getnewaddress
+ validateaddress
+ dumpprivkey
+ decoderawtransaction
+ signrawtransaction
+ sendrawtransaction
+ getrawtransaction
+ getblockcount
+ getblockhash
+ getblock

https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list

additional commands

+ updatebalances : retrieve from blockchain.info balances and unspent outputs. Use this command if you run pyrpcwallet with --update-interval=0

[size=14pt]Todo[/size]

+ command line client withtout json rpc server
+ functionnals test to compare result from bitcoind and pyrpcwallet
+ BIP32 features
+ add followings commands:
* addmultisigaddress
* backupwallet
* createmultisig
* getdifficulty
* getrawchangeaddress
* getreceivedbyaddress
* gettransaction
* listreceivedbyaddress
* listtransactions
* sendfrom
* sendmany
* sendtoaddress
* settxfee
* signmessage
* verifymessage
* walletlock
* walletpassphrasechange

[size=14pt]License[/size]

The MIT License (MIT)

Copyright © 2014 by JahPowerBit

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.

+1,000. Excellent work and fast release JahPB!

I’m testing counterpartyd with pyrpcwallet. First impression, it works right away, but it’s noticeably slow to build database due to blockchain data is fed from blockchain.info, maybe it’s best to use it with a snapshot of counterpartyd database and go from there.


hmm… it just died,
<br /> $ counterpartyd server<br />Status: RESTART<br />Status: NEW DATABASE<br />Block: 278270<br />Block: 278271<br />Traceback (most recent call last):<br />&nbsp; File &quot;/home/counterpartyd_build/dist/counterpartyd/counterpartyd.py&quot;, line 806, in <module><br />&nbsp; &nbsp; blocks.follow(db)<br />&nbsp; File &quot;/home/counterpartyd_build/dist/counterpartyd/lib/blocks.py&quot;, line 756, in follow<br />&nbsp; &nbsp; tx = bitcoin.get_raw_transaction(tx_hash)<br />&nbsp; File &quot;/home/counterpartyd_build/dist/counterpartyd/lib/bitcoin.py&quot;, line 54, in get_raw_transaction<br />&nbsp; &nbsp; return rpc('getrawtransaction', [tx_hash, 1])<br />&nbsp; File &quot;/home/counterpartyd_build/dist/counterpartyd/lib/bitcoin.py&quot;, line 153, in rpc<br />&nbsp; &nbsp; raise exceptions.BitcoindError('{}'.format(response_json['error']))<br />lib.exceptions.BitcoindError: {'message': 'Bad status code returned from blockchain.info: 500', 'code': -1}<br />


maybe leeching too much data from blockchain.info triggers a ban?

Thank you for testing!

this bug it’s because BCI return some time http 500 error: https://blockchain.info/rawtx/c647261cd01de4de4c969f9616c6d01508a53d7751e8a7a54808c8f477c7c7ca?format=hex

[quote]maybe it’s best to use it with a snapshot of counterpartyd database and go from there.[/quote]

Yes! i actually made research for the best solution. Yet it is impossible not to have a local sqlite and make requests to blockscan for example.
Here some ways we can do that:

1) git repository, with auto push every block. But it’s very difficult to embed GIT in a cross platform application
2) use of sqlite virtual table. When you make sql request, sqlite relay the request to a remote mysql server. Don’t know if it’s possible, need test.
3) use of the message table of counterpartyd. Each message have a index that can be used for synchronisation. But for now, balances are no included in message.
4) user of bsdiff/bspatch (https://pypi.python.org/pypi/bsdiff4/1.1.4). Server can generate snapshot each 10 blocks, and patch each block, or something like that
5) use txt diff of cleaned sql dump

What do you think?
it would also be nice to have the opinion of the devs about this.
Thks

I saw that counterparty can reparse transactions very quickly when there’s some minor database changes.
If we could download a compatible snapshot up to a certain block, can counterparty verify the snapshot and all transactions?

Then we should be able to sync the remaining blocks from blockhain.info without using too much bandwith.

well, I’m not sure if getting rawtransaction data from a blockexplorer web to build counterpartyd db is the right idea,
because the data is quite humongous, so it does not really make counterpartyd wallet light,


I’m thinking of something that works like


local counterpartyd _ that has its sqlite being a slave of a _ public fullnode counterpartyd _ master sqlite, they do automatic master slave replication. The local counterpartyd only reads from db.


and the local counterpartyd connects to your pyrpcwallet just for sending operations (create_send/bet/transmit/etc)


Not sure if sqlite can do master-slave replication, but it should be possible to replace it with postgresql or mysql


or better if


counterpartyd can provide some api for rpc db replication

Ok, i think i found the solution :slight_smile:
if you look the code of counterpartyws, the main functions i use form counterpartyd is XXXX.compose(). These functions take all transactions parameters and return an unsigned hex. So i just need a server API that make the job of theses functions: takes transaction parameters and return an unsigned hex. And this API is ready! it’s counterpatyws :-))
So what i need to do is:
- put counterpartyws on a public server,
- force the unsigned parameter to true
- add query to get balances for an arbitrary address
- embed pyrpcwallet in BoottleXCP as git submodule
- add checkbox in the config dialog to switch from heavy to light wallet
And the wallet will be really light, no need the blockchain and no need of the counterparty database.
I have now all the bricks for the lightweight wallet, it remain only to assemble. If all goes well it should be ready by next weekend (my wife will strangle me :-))

[quote author=JahPowerBit link=topic=166.msg1185#msg1185 date=1394495987]
Ok, i think i found the solution :slight_smile:
if you look the code of counterpartyws, the main functions i use form counterpartyd is XXXX.compose(). These functions take all transactions parameters and return an unsigned hex. So i just need a server API that make the job of theses functions: takes transaction parameters and return an unsigned hex. And this API is ready! it’s counterpatyws :-))
So what i need to do is:
- put counterpartyws on a public server,
- force the unsigned parameter to true
- add query to get balances for an arbitrary address
- embed pyrpcwallet in BoottleXCP as git submodule
- add checkbox in the config dialog to switch from heavy to light wallet
And the wallet will be really light, no need the blockchain and no need of the counterparty database.
I have now all the bricks for the lightweight wallet, it remain only to assemble. If all goes well it should be ready by next weekend (my wife will strangle me :-))
[/quote]

I think this is pretty smart. However, here’s my question: When you switch to heavy wallet, will the user need to provide a Counterparty/Bitcoind instance with which to connect? Is this what you meant above or did I mess up my understanding?

[quote author=BitcoinTangibleTrust link=topic=166.msg1186#msg1186 date=1394496941]
I think this is pretty smart. However, here’s my question: When you switch to heavy wallet, will the user need to provide a Counterparty/Bitcoind instance with which to connect? Is this what you meant above or did I mess up my understanding?
[/quote]

Yes. In heavy wallet mode, you need a bitcoind instance running, and you can follow blocks and have a counterparty locale database.
In light mode, you have a pyrpcwallet instance running, and you don’t have a counterparty locale database.

Sweet, so if we have a few of counterpartyws servers running, we should be able to query them to find consensus of responses

[quote author=romerun link=topic=166.msg1199#msg1199 date=1394530704]
Sweet, so if we have a few of counterpartyws servers running, we should be able to query them to find consensus of responses
[/quote]

yes great idea thks! i will add the ability top put several counterpartyws hosts in the config file.
And also add in bootlexcp a dialog box confirmation with the outputs  (decoded locally of course) of the transactions generated by counterpartyws.

Very cool, I’ll check it out.

So I just did a push : https://github.com/JahPowerBit/counterpartyws

counterpartyws can now be used in 3 ways :

Heavy GUI
You must have bitcoind running. Counterpartyd follows blocks and uses local sqlite database to compose transaction.

Light GUI
You must have pyrpcwallet running and set composer-host and composer-port in config file. Counterpartyws uses distant counterpartyws running as Transactions Composer.

Transactions composer
You must have bitcoind running. Used by light counterpartyws to compose transactions.

We can say light wallet is ready in beta version (BoottleXCP is in fact only a GUI for counterpartyws, yes a GUI for a GUI ;-))
I need now to embed pyrpcwallet and counterpartyws in boottlexcp, and make intensive tests (Sorry about that, but I really do not have time to test as much as I should. But I planned to write tests as soon as I have time)

EDIT: Tomorrow I put online a counterpartyws in Transaction composer mode on xcpcomposer.jahpowerbit.org.


would be nice if user can specify those config options – gui-host / port / composer-host / port, etc, over command line to override what in counterpartyd.conf, since both bitcoind and counterpartyd have this ability and I’ve found it useful on some cases.


Also, this gcomposerui-port looks a bit like a typo,

<br />&nbsp; &nbsp; if has_config and 'gcomposerui-port' in configfile['Default'] and configfile['Default']['composer-port']:<br />&nbsp; &nbsp; &nbsp; &nbsp; config.COMPOSER_PORT = configfile['Default']['composer-port']<br />&nbsp; &nbsp; else:<br />


also, bictoid_infos => bitcoind_infos, getinfo => bitcoind_infos


<br />&nbsp; &nbsp; &nbsp; &nbsp; config.MODE = &quot;gui&quot;<br />&nbsp; &nbsp; &nbsp; &nbsp; if args.light:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bictoind_infos = bitcoin.rpc(&quot;getinfo&quot;, [])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if 'pyrpcwallet' not in getinfo:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raise Exception(&quot;You must have pyrpcwallet running to run counterpartyws in light mode&quot;)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config.LIGHT = True<br /><br /><br />&nbsp; &nbsp; write_pid()<br />


well , not sure how to report bugs at this stage

Thank you Romerun.

[quote author=romerun link=topic=166.msg1286#msg1286 date=1394991470]

would be nice if user can specify those config options – gui-host / port / composer-host / port, etc, over command line to override what in counterpartyd.conf, since both bitcoind and counterpartyd have this ability and I’ve found it useful on some cases.
[/quote]

Your right. Added on my todo list.


[quote author=romerun link=topic=166.msg1286#msg1286 date=1394991470]
Also, this gcomposerui-port looks a bit like a typo,

<br />&nbsp; &nbsp; if has_config and 'gcomposerui-port' in configfile['Default'] and configfile['Default']['composer-port']:<br />&nbsp; &nbsp; &nbsp; &nbsp; config.COMPOSER_PORT = configfile['Default']['composer-port']<br />&nbsp; &nbsp; else:<br />
[/quote]

fixed.

[quote author=romerun link=topic=166.msg1286#msg1286 date=1394991470]
also, bictoid_infos => bitcoind_infos, getinfo => bitcoind_infos


<br />&nbsp; &nbsp; &nbsp; &nbsp; config.MODE = &quot;gui&quot;<br />&nbsp; &nbsp; &nbsp; &nbsp; if args.light:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bictoind_infos = bitcoin.rpc(&quot;getinfo&quot;, [])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if 'pyrpcwallet' not in getinfo:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raise Exception(&quot;You must have pyrpcwallet running to run counterpartyws in light mode&quot;)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config.LIGHT = True<br /><br /><br />&nbsp; &nbsp; write_pid()<br />


well , not sure how to report bugs at this stage
[/quote]

also fixed.
Sorry for that! I need a little more sleep!

I’m trying to find out addresses in my pyrpcwallet, so I send newaddress but got:


<br /> ./bitcoind -rpcconnect=172.17.42.1 getnewaddress<br /> <br />error: {&quot;message&quot;:&quot;'Wallet' object has no attribute 'secret_exponent'&quot;,&quot;code&quot;:-1}<br />
is pyrpcwallet is deterministic wallet ? Do i need to initialize the seed or something before use?

[quote author=romerun link=topic=166.msg1293#msg1293 date=1395030082]
I’m trying to find out addresses in my pyrpcwallet, so I send newaddress but got:


<br /> ./bitcoind -rpcconnect=172.17.42.1 getnewaddress<br /> <br />error: {&quot;message&quot;:&quot;'Wallet' object has no attribute 'secret_exponent'&quot;,&quot;code&quot;:-1}<br />
is pyrpcwallet is deterministic wallet ? Do i need to initialize the seed or something before use?
[/quote]

Fixed.
Romerun thank you. I am very grateful for these tests!
No, for now the wallet is not deterministic. But it is planned to add this feature in pyrpcwallet.

Hi, after creating 3 addresses and restarting the wallet, I’m getting this (using the latest repo):




<br />> python pyrpcwallet.py --rpc-user testingrpc --rpc-password test<br />Bottle v0.12.4 server starting up (using WSGIRefServer())...<br />Listening on http://localhost:8383/<br />Updating balances and unspent outputs from Blockchain.info...Hit Ctrl-C to quit.<br /><br /><br />Exception in thread Thread-1:<br />Traceback (most recent call last):<br />&nbsp; File &quot;C:\\Python33\\lib\\threading.py&quot;, line 901, in _bootstrap_inner<br />&nbsp; &nbsp; self.run()<br />&nbsp; File &quot;C:\\Python33\\lib\\threading.py&quot;, line 858, in run<br />&nbsp; &nbsp; self._target(*self._args, **self._kwargs)<br />&nbsp; File &quot;C:\\Python33\\pyrpcwallet\\lib\\json_rpc.py&quot;, line 56, in update_balances<br />&nbsp; &nbsp; db.update()<br />&nbsp; File &quot;C:\\Python33\\pyrpcwallet\\lib\\wallet_db.py&quot;, line 86, in update<br />&nbsp; &nbsp; new_unspent['txid'],<br />TypeError: 'NoneType' object is not subscriptable<br /><br /><br />
[font=verdana]
[font=Verdana]Hope this helps![/font][/font]

Thank you Flatfly!
I can not reproduce … it seems that the BCI txid returned is None. But, it is a priori not possible if bci does not return an error …
It is possible that you send me these 3 addresses?

[quote author=JahPowerBit link=topic=166.msg1320#msg1320 date=1395095576]
Thank you Flatfly!
I can not reproduce … it seems that the BCI txid returned is None. But, it is a priori not possible if bci does not return an error …
It is possible that you send me these 3 addresses?
[/quote]


Hi,


the 3 addresses are

15oVaaeeBjuD1THXJWBiMUvy2TBTjRWVU7
1PYcti521Kct2m2YtxnTNt1FTYc96cMa3H
1KaLBbyp39dhqCrpC95qmGZFg33f3HZDuB


They are empty, as I just generated them for testing.
Would you like the wallet.db file as well?


Edit: I just tried with a new wallet.db file, and a new address, and I’m getting the same error.
  Perhaps one of my dependencies is a bad version? I’m going to double-check that.