Libbitcoin: Checking an Address’ Balance

Libbitcoin: Checking an Address’ Balance

Querying an address’ balance with libbitcoin-client is a rather straight forward process. If you haven’t already installed libbitcoin-client, click here to learn how.

Now, to check an address balance we’ll need a function to make calls to a libbitcoin-server(BS), a function to parse the outputs into a balance and the main function to set the address to check.

I’ve created a file called Balance.cpp and included the usual headers and namespaces.

#include <bitcoin/bitcoin.hpp>
#include <bitcoin/client.hpp>
#include <string.h>
#include <iostream>
using namespace bc;

Now, the function to call the server is very similar to the tutorial on how to fetch the current blockchain height, making use of the connection struct to set the connection settings before instantiating an obelisk_client object with those settings.

void getBalance(wallet::payment_address address)
{
 client::connection_type connection = {};
 connection.retries = 3;
 connection.timeout_seconds = 8;
 connection.server = config::endpoint("tcp://mainnet.libbitcoin.net:9091");

 client::obelisk_client client(connection);

Now, for this call two callback handlers are necessary on for the response and one for the error. The on_error handler will simply display the error message returned by the server. The response handler is going to return chain::history::list object of all the outputs associated with the address both spent and unspent, thus the need for a separate parsing function. In our handler were just going to pass the history object to a different function and display the balance that is returned. Again, note the use of libbitcoin’s encode_base10 function for placing the decimal in a uint64_t number.


static const auto on_done = [](const chain::history::list& rows)
 {
      uint64_t balance = balancer(rows);
      std::cout << encode_base10(balance, 8) << std::endl;

 };
 static const auto on_error2 = [](const code ec) {

      std::cout << "Error Code: " << ec.message() << std::endl;

 };

Finally, to finish off the BS call, we simply connect the client to the server and use the fetch history function passing our address and handlers as arguments.


 if(!client.connect(connection))
 {
 std::cout << "Fail" << std::endl;
 } else {
 std::cout << "Connection Succeeded" << std::endl;
 }

 client.blockchain_fetch_history2(on_error2, on_done, address);
 client.wait();

Now, the function to parse this history is going to need to return a unsigned long long, aka uint64_t, and take a vector of chain::history objects as an argument. Then we simply iterate over the list and check if each output has a spend that is a null_hash as this indicates an unspent output. Aggregate these unspent outputs into one balance variable and return it to the callback function. Like so:


uint64_t balancer(const chain::history::list& rows)
{
 uint64_t unspent_balance = 0;

 for(const auto& row: rows)
 {

 // spend unconfirmed (or no spend attempted)
 if (row.spend.hash() == null_hash)
 unspent_balance += row.value;
 }
 return unspent_balance;
}

With that, all we need to do is set the address in the main function and call our getBalance function.


int main()
{

 wallet::payment_address addy("3MYPG87AYvyGrDyBHnUFsgqWGJ6zkfmsqu");
 getBalance(addy);


}

recommended compilation method is as follows:


alpha$ g++ -std=c++11 -o balance Balance.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin libbitcoin-client)
alpha$ ./balance

The output should look like this:

Balance

For the full sample code for all tutorials, please visit the LibbitcoinTutorials repo on github.

 

5 comments on “Libbitcoin: Checking an Address’ Balance

  1. When I compiled the balance.cpp I got the following error. Can you tell me what’s going on?
    from balance.cpp:1:
    /usr/include/c++/5/bits/unique_ptr.h:49:28: note: declared here
    template class auto_ptr;
    ^
    balance.cpp:8:32: error: ‘history’ in namespace ‘libbitcoin::chain’ does not name a type
    uint64_t balancer(const chain::history::list& rows)
    ^
    balance.cpp:8:45: error: expected unqualified-id before ‘&’ token
    uint64_t balancer(const chain::history::list& rows)
    ^
    balance.cpp:8:45: error: expected ‘)’ before ‘&’ token
    balance.cpp:8:47: error: expected initializer before ‘rows’
    uint64_t balancer(const chain::history::list& rows)

    • Aaron Jaramillo Post Author

      Hey kelvin,

      Can you show me the code you are using? It looks like the compiler is not properly linking to the “history” struct, but I cannot recreate your error.
      Are you including and namespacing the necessary libbitcoin libraries?

      -Aaron

  2. include
    #include
    #include
    #include

    using namespace bc;

    uint64_t balancer(const chain::history::list& rows)
    {
    uint64_t unspent_balance = 0;

    for(const auto& row: rows)
    {

    // spend unconfirmed (or no spend attempted)
    if (row.spend.hash() == null_hash)
    unspent_balance += row.value;
    }
    return unspent_balance;
    }

    void getBalance(wallet::payment_address address)
    {
    client::connection_type connection = {};
    connection.retries = 3;
    connection.timeout_seconds = 8;
    connection.server = config::endpoint(“tcp://testnet.libbitcoin.net:9091”);

    client::obelisk_client client(connection);

    static const auto on_done = [](const chain::history::list& rows)
    {
    uint64_t balance = balancer(rows);
    std::cout<< encode_base10(balance, 8) << std::endl;

    };
    static const auto on_error2 = [](const code ec) {

    std::cout << "Error Code: " << ec.message() << std::endl;

    };

    if(!client.connect(connection))
    {
    std::cout << "Fail" << std::endl;
    } else {
    std::cout << "Connection Succeeded" << std::endl;
    }

    client.blockchain_fetch_history2(on_error2, on_done, address);
    client.wait();

    }

    int main(){

    wallet::payment_address addy("mnrnjVFimDFrNkszzMtecr4yrMKmEuMRbv");
    getBalance(addy);

    }

  3. Oh, I can’t paste the code here. The comment box will miss the #include part of code.

    • Aaron Jaramillo Post Author

      Kelvin,

      The first error thrown is, I think, because auto_pointers are deprecated in c++11 yet still used by older versions of boost to implement smart pointers. If you’re using an older version of boost with a current libbitcoin release updating boost may help.

      you can also eliminate the use of auto in the balancer function, though I’m not sure this alone will help your issue. changing the line:

      for(const auto row: rows)
      

      To:

      for(const chain::history row: rows)
      

      Other aspects of this post need updating such as the libbitcoin-server testnet port(19091) and the fetch_history2 function needs to be updated to fetch_history3.

      Make sure you’re including the proper linking flags when you compile.

      g++ -std=c++11 -o balance Balance.cpp $(pkg-config –cflags libbitcoin –libs libbitcoin libbitcoin-client)

      These changes are reflected in the github repo. Try running this updated code: https://www.github.com/AaronJaramillo/LibbitcoinTutorial/blob/master/HDKeychain/Balance.cpp
      and let me know if it works.

      Also, feel free to open an issue on the tutorial github repo if you have any more questions, they have better code markup options.
      (https://www.github.com/AaronJaramillo/LibbitcoinTutorial)

      -Aaron

Leave a Reply

Your email address will not be published.