10

I am playing around with bitoinj and I can't seem to even get the most basic functionality running.

What I want to do: I have one wallet with one address. I want to dowload blockchain and from that, get the wallet balance.

What I did is following code (in scala, but it is more or less the same thing as Java), the wallet is in address.walet, I want the blockain to be saved at saved.blockchain:

val params = NetworkParameters.prodNet
val walletFile = new java.io.File("address.wallet");
val wallet = Wallet.loadFromFile(walletFile)

val key = wallet.keychain.get(0)
val address:String = key.toAddress(params).toString
println("ADDRESS IS : "+address)

val blockStore = new BoundedOverheadBlockStore(params, new java.io.File("saved.blockchain"))
val chain = new BlockChain(params, wallet, blockStore)
val peerGroup = new PeerGroup(params, chain)
peerGroup.setUserAgent("BitToy", "0.1")

peerGroup.addPeerDiscovery(new DnsDiscovery(params))
peerGroup.addWallet(wallet)
println("START DOWNLOADING BLOCKCHAIN")

peerGroup.start()
peerGroup.downloadBlockChain()
peerGroup.stop()
println("DONE; BALANCE IS :")
println(wallet.getBalance)

I do have balance on the address in the wallet.

Now, when I run it for the first time, the blockchain (or, rather, the headers) gets downloaded and I see the correct balance. However, when I run it for second time, I just see:

ADDRESS IS : [correct address here]
Aug 19, 2012 8:06:00 AM com.google.bitcoin.store.BoundedOverheadBlockStore load
INFO: Reading block store from saved.blockchain
Aug 19, 2012 8:06:00 AM com.google.bitcoin.store.BoundedOverheadBlockStore load
INFO: Read chain head from disk: 00000000000001b10c347b5ec05f9a1910d541905c5cd8827784a5c3e0695c95
Aug 19, 2012 8:06:00 AM com.google.bitcoin.core.BlockChain <init>
INFO: chain head is at height 194575:
v1 block: 
   previous block: 00000000000005ac50dc06021362cd4c284fafd4a1bdb7bad2849c978a875bb1
   merkle root: 158aedd0bc3386c7686f85ab933fd9e3ecb38e348b121ed0e61e2e776eda04a1
   time: [1345356028] Sun Aug 19 08:00:28 CEST 2012
   difficulty target (nBits): 436709470
   nonce: 4238997601

START DOWNLOADING BLOCKCHAIN
Aug 19, 2012 8:06:31 AM com.google.bitcoin.discovery.DnsDiscovery getPeers
INFO: DNS lookup for dnsseed.bitcoin.dashjr.org failed.
Aug 19, 2012 8:06:36 AM com.google.bitcoin.core.TCPNetworkConnection$NetworkHandler channelConnected
INFO: Announcing ourselves as: /BitCoinJ:0.6-SNAPSHOT/BitMessage:0.1/
Aug 19, 2012 8:06:41 AM com.google.bitcoin.core.Peer$PeerHandler exceptionCaught
INFO: com.google.bitcoin.core.Peer$PeerHandler@193f6e2 - No route to host
Aug 19, 2012 8:06:46 AM com.google.bitcoin.core.Peer$PeerHandler exceptionCaught
INFO: com.google.bitcoin.core.Peer$PeerHandler@61736e - No route to host
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.TCPNetworkConnection$NetworkHandler channelConnected
INFO: Announcing ourselves as: /BitCoinJ:0.6-SNAPSHOT/BitMessage:0.1/
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.PeerGroup handleNewPeer
INFO: Peer(seed.bitcoin.sipa.be/50.130.4.89:8333): New peer
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.PeerGroup handleNewPeer
INFO:   starting block chain download
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.PeerGroup setDownloadPeer
INFO: Setting download peer: Peer(seed.bitcoin.sipa.be/50.130.4.89:8333)
Downloading block chain of size 0. 
Done downloading block chain
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.Peer blockChainDownload
INFO: Peer(seed.bitcoin.sipa.be/50.130.4.89:8333): blockChainDownload(0000000000000000000000000000000000000000000000000000000000000000) current head = 00000000000001b10c347b5ec05f9a1910d541905c5cd8827784a5c3e0695c95
DONE; BALANCE IS :
0
Aug 19, 2012 8:06:52 AM com.google.bitcoin.core.PeerGroup$PeerGroupThread run
INFO: shutdown start

and the balance is zero. If I delete the saved blockchain and let it re-download again, it works again, but only for one time.

What am I doing wrong?

2

OK, now I get it.

I can't.

Bitcoinj saves only the headers. And - what I did not know - you can't get the balance with just headers.

For more ingormation you can see the exact description what is in the headers here https://en.bitcoin.it/wiki/Block_hashing_algorithm

What I can do, however, is saving the wallet right afterwards. Which I will do.


previous "answer"/thinking out loud:

I am poking around in source code.

It seems like the important part is when sendTransactionsToWallet is called in BlockChain.java - but it gets only called during connectBlock and nothing else.

connectBlock is called only during add. And the only added blocks are the new blocks from the network, not the ones from BlockStore.

But I will look around the code a bit more.


I am not sure, what terrible would happen, if I rewrote the constructor of BlockChain.java from:

/**
 * Constructs a BlockChain connected to the given list of wallets and a store.
 */
public BlockChain(NetworkParameters params, List<Wallet> wallets,
                  BlockStore blockStore) throws BlockStoreException {
    this.blockStore = blockStore;
    chainHead = blockStore.getChainHead();
    log.info("chain head is at height {}:\n{}", chainHead.getHeight(), chainHead.getHeader());
    this.params = params;
    this.wallets = new ArrayList<Wallet>(wallets);
}

to (writing from my head, getters/setters might not be right, etc)

/**
 * Constructs a BlockChain connected to the given list of wallets and a store.
 */
public BlockChain(NetworkParameters params, List<Wallet> wallets,
                  BlockStore blockStore) throws BlockStoreException {
    this.blockStore = blockStore;
    chainHead = blockStore.getChainHead();
    log.info("chain head is at height {}:\n{}", chainHead.getHeight(), chainHead.getHeader());
    this.params = params;
    this.wallets = new ArrayList<Wallet>(wallets);
    StoredBlock sBlock = blockStore.getChainHead();
    Sha256Hash prevHash = sBlock.header.prevBlockHash();
    while (prevHash!=Sha256Hash.ZERO_HASH) {
        for (Wallet wallet:wallets){
            sendTransactionsToWallet(sBlock, NewBlockType.SIDE_CHAIN, wallet, sBlock.transactions); 
        }
        sBlock = blockStore.get(hash);
        prevHash = sBlock.header.prevBlockHash();
    }
}

but again, I don't want to reinvent the wheel or anything.

2

It is possible to do what you want by simply using the PostgresFullPrunedBlockStore class for storage and then you will just need to call Address.calculateBalanceForAddress() in order to get the balance of the desired address.

  • Unfortunately, it's kind of old question and I am no longer experimenting with bitcoinj so I cannot accept you, but I will let community decide by voting I guess – Karel Bílek Jun 26 '14 at 14:01
  • No worries, I just felt to answer because there have been updates with bitcoinj recently and I thought others might want to know this. – Biteasy.com Jun 26 '14 at 14:26
  • How big is postgress db going to be ? 100GB+ and growing fast right ? – Pavel Niedoba Mar 14 '16 at 19:12
  • Heh, the answer is still hanging in there even in 2017... I have no idea how bitcoinj looks now. – Karel Bílek Jul 1 '17 at 17:26
0

I thought I would mention that (mainly to save bandwidth) I have added a simple caching option into MultiBit where it simply saves the blocks received into a directory, each block is called [hash of block].block

You can use this to grab the transactions etc. as you want later. Of course it takes up space! It is in the MultiBit v0.5 branch. The main controlling class is CacheManager. It might be useful to you.

The bloom filter work Matt Corrallo is doing to filter the tx at the server side is IMHO the right way to manage the size of the block chain - this is just a stop gap until that gets into bitcoinj.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.