177

I am trying to check the balance of a given Bitcoin address by using ONLY the locally stored blockchain (downloaded via Bitcoin Core). Something similar to this (by using NBitCoin and/or QBitNinja), but without needing access to the network:

private static readonly QBitNinjaClient client = new QBitNinjaClient(Network.Main);

public decimal CheckBalance(BitcoinPubKeyAddress address)
{
    var balanceModel = client.GetBalance(address, true).Result;
    decimal balance = 0;

    if (balanceModel.Operations.Count > 0)
    {
        var unspentCoins = new List<Coin>();
        foreach (var operation in balanceModel.Operations)
            unspentCoins.AddRange(operation.ReceivedCoins.Select(coin => coin as Coin));
        balance = unspentCoins.Sum(x => x.Amount.ToDecimal(MoneyUnit.BTC));
    }
    return balance;
}

The example above needs access to the network. I need to do the same thing offline. I came up with something like this, but obviously it doesn't work:

public decimal CheckBalanceLocal(BitcoinPubKeyAddress address)
{
    var node = Node.ConnectToLocal(Network.Main);
    node.VersionHandshake();
    var chain = node.GetChain();

    var store = new BlockStore(@"F:\Program Files\Bitcoin\Cache\blocks", Network.Main);

    var index = new IndexedBlockStore(new InMemoryNoSqlRepository(), store);
    index.ReIndex();

    var headers = chain.ToEnumerable(false).ToArray();

    var balance = (
        from header in headers
        select index.Get(header.HashBlock) 
        into block
        from tx in block.Transactions
        from txout in tx.Outputs
        where txout.ScriptPubKey.GetDestinationAddress(Network.Main) == address
        select txout.Value.ToDecimal(MoneyUnit.BTC)).Sum();

    return balance;
}
  1. It hangs during the query
  2. I want something instead of InMemoryNoSqlRepository to be stored in a file in order to prevent using ReIndex() which slows everything down

My requirement is to Check Balance the same way as in the first method but by querying blocks stored on my disk.

Actually what I require might just be an answer to this question:

Milad Rashidi
  • 1,026
  • 4
  • 14
  • 33
rvnlord
  • 2,728
  • 3
  • 14
  • 22
  • Is using QBitNinja a requirement? Because I remember I did the same with BitcoinLib some years ago (memories are quite rusty but I'm sure I had local bitcoin node and used that to query different kind of stuff, including balance). – Evk May 12 '17 at 10:02
  • 1
    Ideally I would like to use NBitcoin only like in my second method which doesn't work and I don't know why. QBitNinja Server on IIS is my second option, but as you mentioned BitcoinLib, I might give it a try as a last resort. Balance here is just an example, I would like to query local blockchain for many interesting things. Though I thought that BitcoinLib is not updated anymore. I appreciate any help and it looks like you are the only one who is trying so far :). So yes I will give you the 50 rep if no one give better answer. – rvnlord May 12 '17 at 12:01
  • Well last commit was 7 months ago, not that long ago (and there is pending pull request by contibutor in march current year), so I wouldn't say it's not updated any more. As for querying for many interesting things - BitcoinLib is just a proxy to official RPC api, so I guess you can query everything with it. Though of course if you already put some work into QBitNinja I understand you might want to stick with it. – Evk May 12 '17 at 12:06
  • 1
    I don't have a local node but I worked with blockchain code a good bit about 4 years ago. I can give a very good educated guess that the reason why this may be taking so long is the way the serialized blockchain data is structured and the way the linq engine queries that data. I suspect that your routine is "hanging" because the underlying parsing/querying code isn't optimized. Your code is very-likely working but it may need some underlying optimizations for responsive execution. – RLH Jan 16 '18 at 13:13
  • 12
    Hi, it's an old question but I saw this yesterday. I tried your code with NBitcoin. Your code works on my partial old local node only if I comment this line index.ReIndex(); and this line var chain = node.GetChain();. I also tweaked my code a little bit that instead of GetChain I did GetBlocks. and simillar changes to make it work. I don't want to get downvoted so I am posting this comment :) . I hope it helps you. – Hey24sheep Jan 27 '18 at 14:00
  • 19
    @Hey24sheep Your code works? Then post it as answer. I don't believe anybody would downvote you for a working solution. – Martin Braun Mar 21 '18 at 23:29
  • 1
    @modiX and Kobik, I couldn't find my project and I don't have the node now So I can't reproduce it, idk Why (Might be that my node needs to be synced before I can do anything). I found out that this is obsolete method anyway. We should use some explorer or something now. https://github.com/MetacoSA/NBitcoin/issues/332 – Hey24sheep Mar 22 '18 at 17:44
  • @kobik and modix, https://programmingblockchain.gitbooks.io/programmingblockchain/content/wallet/web-api.html – Hey24sheep Mar 22 '18 at 17:45
  • 5
    Why are people afraid to post a solution and get down voted? Is this a sign that Bitcoin is not what we think it is? Should I NOT be concerned as a Bitcoin speculator? Referring to comment made by @Hey24sheep and others. Yellow flag time? – Rich Bianco May 30 '18 at 00:08
  • @Hey24sheep: Kindly post it as an answer with code snippet so I can mark it as accepted answer, thanks. – rvnlord Sep 06 '18 at 18:54
  • 1
    @rvnlord Hi, I am sorry but I don't have the code and the node to check it back. I tried it again when I was responded to but I wasn't able to get the same results that I got before. I did that long ago. – Hey24sheep Sep 08 '18 at 02:37
  • @Hey24sheep Just a tip for next time: even if you post an answer and get downvoted, deleting it will get you all your points back anyway.. Besides, as others have mentioned, if you have a working solution with proper explanation in your answer, I don't see any reason why someone would downvote you for it. – Kevin Cruijssen Sep 18 '18 at 09:40
  • @KevinCruijssen I will remember it the next time. I had a working solution. I am just afraid of downvotes, cuz I have been downvoted for right answers in the past. – Hey24sheep Nov 30 '18 at 05:00
  • 1
    @Hey24sheep You can be downvoted for correct answer, working solution, valid question, speaking the truth or for nothing at all. Don't let such silly things define you. If your knowledge adds value to the topic and helps somebody, that is the most important thing. Don't let anyone discourage you. I corrected the code, thanks to your advice sometime earlier, however I can't test it against the local node because I don't have one anymore. I am grateful for your contribution though. If you provide working solution as an answer, whenever you feel ready, I will make sure you receive a bounty. – rvnlord Nov 30 '18 at 20:42
  • 1
    @rvnlord I don't have the solution or the node. I will keep it in mind for the next time though :) Thanks – Hey24sheep Dec 02 '18 at 12:23

1 Answers1

3

The first and second attempts in your question are nothing alike. First one uses json rpc to ask the daemon for the balance (and I dare say it's the proper way - you don't take the top off your car engine and push the pistons up and down yourself to achieve forward motion, do you?) the second attempts to open the daemon's database itself and calculate the balance directly.

You don't "need a network" to query the localhost, you just need a machine that has TCP/IP support installed, so just use the first method by whatever means - either by using a library that writes the relevant json-rpc data into an http request, or by forming the relevant http request yourself..

BitcoinLib may or may not be maintained (I don't know) but that doesn't invalidate its ability to query your local daemon; as far as I know GetBalance hasn't been removed or refactored, and I use BitcoinLib with the latest bitcoind for a variety of operations including GetBalance

Caius Jard
  • 47,616
  • 4
  • 34
  • 62
  • 1
    I completely forgot about this question. @Hey24sheep solved the problem, though I don't have full local node available now. I needed attempt to query LOCAL and OFFLINE data back then. I needed to query it much faster than I can achieve by using APIs to 3rd party sources. – rvnlord Sep 06 '18 at 18:53