Pages:
Author

Topic: [ANN] BitcoinArmory-Daemon - armory on web servers - page 5. (Read 20590 times)

legendary
Activity: 1428
Merit: 1093
Core Armory Developer

Also, I am unsure about the difference between spendable, unconfirmed and ultimate in address balances. Can someone clear this up for me? It didn't behave how I expected. eg:

Into one address I had 1.2 btc transferred with 8 confirmations and 2.1 btc with 1 confirmation, and I got this result:
spendable - 3.3
unconfirmed - 0
ultimate - 3.3


(1) Ultimate/Full includes every, confirmed and not confirmed
(2) Spendable includes everything (SentToSelf || >1 confirmation)
(3) Unconfirmed is (NotSentToSelf && <6 confirmations)

EDIT:  I realize now it would've been clearer to say avoid "Spendable" and just say "Confirmed".  Though maybe not: you send coins to yourself in Armory and they show with 0 confirmations, yet it still shows up as confirmed.  That doesn't fit well with folks conditioned to believe that nothing is confirmed until 1+.  Ehhh... whatever.  I'm leaving it.
mav
full member
Activity: 169
Merit: 107
Indeed, twisted seems to be the way to go. I've written a twisted web server which allows for threaded interaction with the armory wallet and blockchain.

I'm looking for feedback about what functionality to incorporate (and in what format) from people who may want to use this.

Currently I've got a basic web server with the following url structure (only basic calls for my needs so far but I plan to extend it further)

URLDESCRIPTIONARGSOPTIONAL defaultCONSIDERATIONS
/wallet/getAddressgets the next unused address from the watch-only wallet
/blockchain/getAddressBalancegets the balance of an address (not necessarily in your wallet)address=XbalType=Spendable | unconfirmed | ultimateUnsure to use balType from armory client or minconf from satoshi client

My doubt with the url design is whether to emulate as closely as possible the internal class structure of armoryengine or whether to design an entirely new abstraction with wallet and blockchain etc (like above table) which is independent of the wallet type (satoshi / armory etc). My thoughts right now are to replicate the internal structure of armory, since this is a wrapper for armory and not a generic application. But then I think perhaps a generic web interface would be good to have...

Any particular feature requests will be given priority over general coverage (once I've satisfied my own needs), so make them in this thread.

Suggestions about how the implementation are most welcome.




Also, I am unsure about the difference between spendable, unconfirmed and ultimate in address balances. Can someone clear this up for me? It didn't behave how I expected. eg:

Into one address I had 1.2 btc transferred with 8 confirmations and 2.1 btc with 1 confirmation, and I got this result:
spendable - 3.3
unconfirmed - 0
ultimate - 3.3
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
This is why I prevent Armory from opening twice.  Wallet operations are not threadsafe. Not at all!  

However, one benefit of python-twisted is that it is guaranteed to run as a single-thread, so as long as there is only one instance of Armory, it's perfectly safe.

For your purposes, not using python-twisted, need to do something else.  Actually, I would recommend using python-twisted to create a server/daemon process to handle (serially) all requests for wallet interaction.  Make sure everything goes through that interface.  The wallet design has been remarkably robust (I even test it with mid-write interrupts and it recovers fine).  But as you can see, two simultaneous operations can break it pretty easily.  

mav
full member
Activity: 169
Merit: 107
Anticipating that servers often create multiple threads to handle concurrent requests, I wanted to get a feel for how armoryengine would respond to attempts at fetching many addresses at the same time. I ran the following test code and it borked my watch-only wallet file, to the point where I couldn't even get an address out of it without threading.

Code:
from armoryengine import *
from threading import Thread

def get_addr():
    wlt = PyBtcWallet().readWalletFile('test.watchonly.wallet')
    addr = wlt.getNextUnusedAddress()
    print addr.getAddrStr()

for a in range(10):
    Thread(target=get_addr, args=()).start()

Whenever I call readWalletFile on a borked wallet file, with or without threading, I get the following error:

Code:
***ERROR:  Requested wallet is for a different blockchain!
           Wallet is for:   

.../armoryengine.py", line 6907, in unpackHeader
    print '           Wallet is for:   ', BLOCKCHAINS[self.magicBytes]


The purpose of this post is just to gather the info, I will look more into how to handle this in the near future. Any suggestions from wise heads are welcome.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Hah!  I didn't even notice this thread.  I'll offer lots of advice for you...

Most importantly, checkout extras/sample_armory_code.py.   That has a lot of details about how to load the blockchain and access address balances.  Constructing transactions isn't so obvious, but it's do-able.

I'm kinda swamped this month, but I'm subscribed now and will provide tips on using the armoryengine.py where I can.

Btw, I did intend for armoryengine.py + _CppBlockUtils.so/.dll/.pyd to be a nice standalone, full-featured library.  I'm pretty sure that all the ArmoryQt.py and qtdialogs.py code only uses armoryengine.py, but does not expand it (thus, anything that Armory does, you can do with just those files).  There's no JSON interface yet, but I think I can add it...

 
P.S. -- The dependencies for just armoryengine+cppBlockUtils is:

Code:
build-essential
swig
python-dev
python-twisted

All of it is in the Ubuntu repos.  Doing this in Windows is far from easy, but I'm pretty sure the original instructions posted 6 months ago still work.
mav
full member
Activity: 169
Merit: 107

Note that this code does not seem to allow interaction with the bitcoin network, only with the wallet. Thus, getting the balance of an armory address from the watchonly wallet is not possible with this code (which is my next task to figure out). Any suggestions how to go about it are most welcome. I imagine this functionality should be possible from the satoshi bitcoin client, but I have yet to figure out how to get the balance of an address not in the current (satoshi) wallet. I'm also looking into how armory connects to bitcoind and how it gets balances for addresses.


I found an answer for these questions and have posted some code about how to get the balance of an address.

Calling BDM_LoadBlockchainFile is very slow (tens of seconds on my machine) since I'm guessing it loads and parses the entire blockchain. I'm going to look into how to incorporate that command (probably with some others to make it useful) and create a kind of 'bitcoind' for armory, which will be able to access the watch-only armory wallet, and also be able to get balances for that wallet. It seems from the comments in the armory source code that any address balance can be easily fetched, not just addresses in the wallet (can't find the comment sorry).

Code:
from armoryengine import *

wlt = PyBtcWallet().readWalletFile('armory_2hdJwWB5h_.watchonly.wallet')

addr = wlt.getNextUnusedAddress()
print 'The new address: '
print '   Hash160:  ', binary_to_hex(addr.getAddr160(), BIGENDIAN)
print '   Base58:   ', addr.getAddrStr()
print '   Index:    ', addr.chainIndex
print '   Have Pub: ', addr.hasPubKey()
print '   Have Priv:', addr.hasPrivKey()

BDM_LoadBlockchainFile()

print wlt.getAddrBalance(addr.getAddr160())  #This prints the address balance from the address above

As for a Ruby port, sorry I'm not going to be much help cause I don't know any ruby. Perhaps someone else will step up and investigate. Possibly if a bitcoind style implementation of armory can be developed, with a json api, perhaps your ruby could access armory through that interface rather than as a direct language port. Time will tell.
legendary
Activity: 1372
Merit: 1008
1davout
I would totally donate a few coins for an Armory port to Ruby
mav
full member
Activity: 169
Merit: 107
Here is some more info which I found from testing today.

I wanted to cut the armory source down to remove dependency on qt, and thus run just a simple script to access the watchonly wallet on my web server without installing the whole of armory.

My goal in this post is to get new addresses from a watch-only wallet using python, on a server without qt installed.

Steps:

From the source at https://github.com/etotheipi/BitcoinArmory I took only the following file:

  • armoryengine.py

There were two more files I needed, which are not in the github repo (presumably compiled on install), so I got them from my armory install, located in /usr/share/armory and added them to the folder containing the above three files.

  • CppBlockUtils.py
  • _CppBlockUtils.so

Note there is no dependency on qt for any of these files.

I copied a watchonly wallet from armory into the folder containing the specially selected files above, and created a test.py file as below. It worked! The test script read the wallet file and created / printed the details of the next address.

Code:
from armoryengine import *
wlt = PyBtcWallet().readWalletFile('test.watchonly.wallet')
addr = wlt.getNextUnusedAddress()

print 'The new address: '
print '   Hash160:  ', binary_to_hex(addr.getAddr160(), BIGENDIAN)
print '   Base58:   ', addr.getAddrStr()
print '   Index:    ', addr.chainIndex
print '   Have Pub: ', addr.hasPubKey()
print '   Have Priv:', addr.hasPrivKey()

This allows the web server to run a light-weight non-gui version of the watch-only capabilities of armory, which utilises the watch-only wallet.

Note that this code does not seem to allow interaction with the bitcoin network, only with the wallet. Thus, getting the balance of an armory address from the watchonly wallet is not possible with this code (which is my next task to figure out). Any suggestions how to go about it are most welcome. I imagine this functionality should be possible from the satoshi bitcoin client, but I have yet to figure out how to get the balance of an address not in the current (satoshi) wallet. I'm also looking into how armory connects to bitcoind and how it gets balances for addresses.

Any suggestions or comments are most welcome, this is all new to me.
mav
full member
Activity: 169
Merit: 107
Armory Daemon is now available on github:

https://github.com/thedawnrider/BitcoinArmory-Daemon

More info on page 2 of this thread - https://bitcointalksearch.org/topic/m.1197291

-------------------------

I thought I'd start this thread as a place to collate information about using Armory client on a webserver, since the only info I found so far was hidden on page 16 of the Armory Discussion topic.

The info below is about getting an Armory address on a webserver and it comes from https://bitcointalksearch.org/topic/m.765880

Anyone who has information or questions about using Armory on a webserver, please post it here so webdevs can make the most of Armory, which currently seems to be focusing on GUI interaction rather than API (understandably).




I put some thought into how Armory could be used for a webserver application, and I realized that with just a couple lines of python, you can generate addresses no problem on your webserver.  I added a couple convenience functions and committed them to the master branch of Armory. Here's what you do:

(1) Load Armory on your computer.  
(2) Create a regular wallet.  
(3) In Wallet Properties, "Create Watching-Only Copy"
(4) Upload watchonly wallet to webserver
(5) Setup webserver to load wallet and call wlt.getNextUnusedAddress() for each request
(6) Sit at home with the full wallet and watch/confirm/send transactions while the webserver does the work!

Demonstration code to see how to access/manipulate the wallet from a python script:

Code:
from armoryengine import *

wlt = PyBtcWallet().readWalletFile('/home/server/web_server.watchonly.wallet')
wlt.setAddrPoolSize(1000)

# Quick printing of addr info, and shows how to access various props of the addr
def pprint(addr):
   print 'The new address: '
   print '   Hash160:  ', binary_to_hex(addr.getAddr160(), BIGENDIAN)
   print '   Base58:   ', addr.getAddrStr()
   print '   Index:    ', addr.chainIndex
   print '   Have Pub: ', addr.hasPubKey()
   print '   Have Priv:', addr.hasPrivKey()
  
print 'Get the next unused address...'
addr = wlt.getNextUnusedAddress()
pprint(addr)

print 'Generating 10 more addresses:'
for i in range(10):
   addr = wlt.getNextUnusedAddress()
   print '\t', addr.chainIndex, '\t', addr.getAddrStr()

print 'Get addr #15'
a160 = wlt.getAddress160ByChainIndex(15)
print binary_to_hex(a160, BIGENDIAN)
addr = wlt.addrMap[a160]
pprint(addr)

print 'This wallet has %d addresses computed' % wlt.getHighestComputedIndex()
print 'Addresses used: %d ' % wlt.getHighestUsedIndex()

Here's the output on a watching-only wallet (this is actually the output of the second time I ran it):

Code:
Get the next unused address...
The new address:
   Hash160:   728b0b8cc930cb4756328e743b7b2e7dde93a35f
   Base58:    mpEeSrEr3EiyCMRskT5VrELkY8X9ZwT3BV
   Index:     11
   Have Pub:  True
   Have Priv: False

Generating 10 more addresses:
12 mrhzBHQcn7jmhvpbcfW6ebiAFEm9qZF6AL
13 moPM3KPygygsWzvUHfeDsmPChL5xWycc5y
14 n4ZtG47TNMifGJ57msGAs8ZD1HeVqSqRyx
15 mw3cxXKCaKitV8w1wBRrpjQNWu4od5Nd5H
16 n1UGPkUgUXiwsotzfpAezpy6NkRg1fGMv5
17 muFPi3pAw7Rbb9aGc9UJPX9m6JT1VGHf9J
18 n3TRNc86Vmi2EygvjeMsAXXAYhPygR2sQK
19 mikSy5FjeSPVBSaXDs8ihMKrMgZsoohsjz
20 mwb8h2PJvGGGQTA7QBgvPVrWowQZi43ZD2
21 mpBFZ1H6AcRqHUZ7ETz1Xh1PqaPiMvdQDM

Get addr #15
c42ea65330263fd9c02fe5ca2e3a1c44dca356aa
The new address:
   Hash160:   c42ea65330263fd9c02fe5ca2e3a1c44dca356aa
   Base58:    mw3cxXKCaKitV8w1wBRrpjQNWu4od5Nd5H
   Index:     15
   Have Pub:  True
   Have Priv: False

This wallet has 1021 addresses computed
Addresses used: 21

Your webserver can run blissfully ignorant about what is actually going on with the wallet, it just gives out a new address on every request.  You can sit at home on your computer with Armory running and the full wallet there, with full control.  But someone who compromises the webserver will not get anything!

If you want the webserver to track incoming transactions, it will require loading the blockchain and checking for new blocks periodically.  It's not a lot of code, but I'll save it for later if you are interested.

One other thing:  Armory uses the crypto++ library, which is not particularly fast at ECDSA operations (and my key generation algorithm is kinda slow, which is why I'll be upgrading to a new one, soon).   My [decent] system can generate about 200 addr/sec.  So this script takes a few sec to run.  But all keys are stored in the wallet, so they don't have to be recomputed when you restart the script.
Pages:
Jump to: