Query LOCAL Bitcoin blockchain with C# .NET

rvnlord picture rvnlord · Dec 7, 2016 · Viewed 9.6k times · Source

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:

Answer

Caius Jard picture Caius Jard · Sep 6, 2018

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