Bitcoinj dev (1) - generate address and receive funds

in bitcoinj •  9 years ago 

Introduction

Bitcoinj is a library designed specifically to interact with Bitcoin network. You can use it to interact with real bitcoin blockchain, or play around in TestNet - bitcoin's testing network. It allows us to do some pretty cool stuff. This post (and hopefully a series of them) is my way of trying to learn more about bitcoin, and its inner workings by using this library. For starters, I'd like to focus on simple tasks - creating a wallet, an address, and receiving some funds to it. This introduction assumes you'll be able to download the library, and include it into Java project, either using Maven, or manually.

Initial setup

I'll be using Java programming language to interact with the library, but there are a few other possibilities: Javascript, Python, Ruby, etc.
Download the library from the official website. At the time of writing, newest version is 0.14.3. Include it into your project.

Every Java application has a starting point - a main class, with famous public static void main method. Lets create a new Main class:

public class Main {
    public static void main(String[] args) {
        // code here
    }
}

Network, Wallet and WalletAppKit

First off, we have to select a network we'll be using. Network can be either real bitcoin network, working with real bitcoin, on the current blockchain, or one of bitcoin's test networks. Since I am using the library for learning purposes, I'll use test network - TestNet3 - current bitcoin test network.
In order to generate address for ourselves, we need a wallet. To quote the documentation:

"A Wallet stores keys and a record of transactions that send and receive value from those keys. Using these, it is able to create new transactions that spend the recorded transactions, and this is the fundamental operation of the Bitcoin protocol"

In other words, we use wallet to keep track of our addresses (keys), and use it to send transactions to other addresses. Since most of the applications needs a lot of stuff to be instantiated before starting, bitcoinj offers us a higher level object that create most of the stuff for us WalletAppKit. It wraps a lot of boilerplate code we would need to write. Let's get back to our code. In our Main class, we'll have to create a new WalletAppKit. Since it will prepare configuration for network connection, we need to tell it what network to use. Also, SPV downloads block headers from the network, so we'll have to specify where those files should be downloaded, as well as what the file name would look like. Here is the code:

    // we're using TestNet3
    NetworkParameters params = TestNet3Params.get();
    
    // WalletAppKit creates 2 files - .wallet file and .spvchain file 
    // use any string you want
    String filePrefix = "forwarding-service-testnet";
    
    // and finally, we create WalletAppKit, providing it with network parameter
    // location of where to download block headers, and a file prefix
    WalletAppKit kit = new WalletAppKit(params, new File("."), filePrefix);

Ok, we've created a WalletAppKit, but nothing has been started yet. We can start the kit, by invoking

kit.startAsync()

in our main method. If you inspect library code, you'll see that WalletAppKit class extends AbstractIdleService class. AbstractIdleService is a part of Google's Guava Service. Calling startAsync() on an object extending AbstractIdleService will call the startUp method of that object (in this case WalletAppKit's startUp()) asynchronously. Reasons for starting this asynchronously are many, but the most obvious one is the UI blocking. Many wallet applications will use some kind of UI, and it might not be a good idea to have everything blocked while block headers are being downloaded. Since we're building a console application, we'll have to wait for everything to be downloaded, and then use the WalletAppKit object. We do this by calling

kit.awaitRunning();

This will halt our application, until the asynchronous download of block headers is finished.

Balance and addresses

WalletAppKit has plenty of methods we could use to get information about our wallet, network, connected peers, blockchain etc. We're currently interested only in our wallet. Let's generate an address and print it out

kit.wallet().addWatchedAddress(kit.wallet().freshReceiveAddress());
System.out.println("New address created");
List<Address> list = kit.wallet().getWatchedAddresses();
System.out.println("You have " + list.size() + " addresses!");
for (Address a: list) {
    System.out.println(a.toString());
}

This will generate an address, print out the number of addresses we have, load them and print each of them out. Keep in mind that, whenever you start the program, a new address will be generated and added to your wallet. Let's print out the balance. Easy way to get balance is this:

String balance = kit.wallet().getBalance().toFriendlyString();
System.out.println(balance);

Since we haven't put any bitcoin in our address, balance will be 0.0 BTC. Let's add some BTC. Remember, we're using TestNet, and bitcoin there is free. Head over to the testnet3 free faucet, enter your newly generated address, and receive some bitcoin.
You can start the application again, and hopefully your balance will be changed (you'll also get a new address in your wallet). You might need to wait until the next block is mined - check blocks here in order to have your balance display new state.

Conclusion

We've covered quite a lot of stuff in this post. Next time, we'll try to address the problem of unconfirmed transactions and return the BTC received by the faucet by creating a transaction of our own. Why send them back to faucet? This is a test network, and other people might want to use them to test their applications, so keeping the faucet running will help with that.
In a retrospective, here is the whole class

// various imports
public class Main {

    public static void main(String[] args) {

        NetworkParameters params = TestNet3Params.get();

        String filePrefix = "forwarding-service-testnet";

        WalletAppKit kit = new WalletAppKit(params, new File("."), filePrefix);

        // Download the block chain and wait until it's done.
        kit.startAsync();
        kit.awaitRunning();

        List<Address> list = kit.wallet().getWatchedAddresses();
        if (list.size() < 2) {
            kit.wallet().addWatchedAddress(kit.wallet().freshReceiveAddress());
            System.out.println("New address created");
        }

        System.out.println("You have " + list.size() + " addresses!");
        for (Address a: list) {
            System.out.println(a.toString());
        }

        String balance = kit.wallet().getBalance().toFriendlyString();
        System.out.println(balance);
    }
}

#bitcoinj #bitcoin #bitcoin-dev #java

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Is there a way to not generate new addresses everytime we start the program?

Congratulations @epson121! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 3 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!