This post covers Bitcoin Transaction Websockets, as a method to get all of the newest, unconfirmed Bitcoin transactions over the Bitcoin network using a websocket whose implementation is provided in Java.
Bitcoin Transaction Websockets
In the world of Bitcoin, just like in the FIAT world, one of the fundamental entities is a transaction, sending or receiving money to or from someone. A Bitcoin transaction is a piece of data, containing details for that very transaction such as the amount, sender/receiver Bitcoin addresses, hash etc.
These transactions are sent from one Bitcoin address to another. Every Bitcoin address belongs to a wallet. To explain a wallet entirely is a huge topic in its own regard, but if you are not familiar with it, it is just a metaphor for an actual wallet. The only difference is that it is a digital one, carrying Bitcoins. For sending or receiving Bitcoins, the two parties must have a wallet, and that wallet in turn contains Bitcoin addresses, where new Bitcoin addresses are created and added to the wallet upon request.
So when a transaction is sent from one Bitcoin address to another, the wallet that owns the receiver address needs to be notified. This is not a big issue when both the users have installed a Bitcoin Daemon on their systems, where the daemon contains only one wallet. But in the case of an application that needs to keep track of multiple wallets and their Bitcoin addresses, then all of the transactions taking place on the Bitcoin network must be kept a track of, so that we can get the transactions that we care about.
Aurora Solutions recently partnered with Safello.com, a service where users can create and import wallets from blockchain.info, for a better and seamless user experience with state of the art workflows, we came up with the challenge of handling the wallet transactions for a huge number of wallets, for thousands of already registered customers to be approximate. So we had to watch each and every transaction that took place on the Bitcoin network. And to be precise, the statistics show the number of transactions per day to be over 120,000.
To receive this amount of transactions without any miss, there are a few ways. Web Sockets, Web Hooks or polling after regular time intervals. In this post, we are going to talk about Bitcoin Transaction websockets, and the programming language is Java.
For a Bitcoin Transaction websockets to work, we need to first connect with the Bitcoin Transaction Websockets server. Once we communicate with it, we need to subscribe to a service. The following Bitcoin transaction websocket client code shows this mechanism. The code for the websocket client is always the same(depending on which websocket implementation you are using), the only difference is the url of the websocket server and the type of subscription.
The class implements the IWebSocketClient, the following dependencies need to be added:
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
The class contains annotated methods, that are implementations of the declarations in the IWebSocketClient. The first thing we need to do is to is connect to the server:
@ClientEndpoint
public class ChainWebSocketClient implements IWebSocketClient {
@Override
public void run() {
// Initialise the WebSocket Container and Session
initializeWebSocketSession();
}
/**
* Initialises the Bitcoin Transaction websockets session by making repetitive calls until the session is initialized
*/
private void initializeWebSocketSession()
{
try {
boolean sessionInitialised = false;
// Initialise the container if it is null
if(container == null)
{
container = ContainerProvider.getWebSocketContainer();
}
// Keep on trying to start the session until it doesn't start
while(!sessionInitialised){
// Try catch for the session initialisation for the web socket. So we can try again if it fails
try {
this.session = container.connectToServer(ChainWebSocketClient.class, URI.create("wss://ws.chain.com/v2/notifications"));
// Only mark success if the session has been created
if(this.session != null){
sessionInitialised = true;
LOG.debug("Chain.com web socket client initialized successfully. Ping timer started");
}
}
// Handle errors
catch (Exception e) {
LOG.error("Error while initialising Chain.com's WebSockets: \n" + e.getMessage(), e);
}
}
} catch (Exception e) {
LOG.error(e.toString());
e.printStackTrace();
}
}
…
The above code communicates with chain.com’s web socket server. To know whether we have connected successfully with the server, we have to implement the OnOpen method:
@OnOpen
public void onOpen(Session session) throws IOException
{
// Providing 0 or negative value as the timeout means that the session will never timeout
session.setMaxIdleTimeout(0);
// Set the maximum binary message buffer size to double than the default size
session.setMaxBinaryMessageBufferSize(16384);
// Set the maximum text message buffer size to double than the default size
session.setMaxTextMessageBufferSize(16384);
JsonObject subscriptionMessage = new JsonObject();
subscriptionMessage.addProperty("block_chain", "bitcoin");
subscriptionMessage.addProperty("type", "new-transaction");
session.getBasicRemote().sendText(subscriptionMessage.toString());
LOG.info("Subscribed for unconfirmed tranasctions from Chain.com.");
}
As soon as we connect to the server, this method, which acts as an event handler, will be invoked. And as soon as it gets invoked, we subscribe for the respective service, in this case, all the new Bitcoin transactions.
Once we have subscribed to a service the websocket server is providing, we will start receiving messages in the OnMessage method:
@OnMessage
public void onMessage(String message, boolean isLastPartOfMessage)
{
//add the message part into the message buffer
messageBuffer.append(message);
//If the message is completely received, process the message buffer
if(isLastPartOfMessage)
{
try
{
// Do some work
}
catch (Exception e)
{
LOG.error(e.getMessage(), e, message);
}
finally
{
messageBuffer = new StringBuilder();
}
}
}
The above method will keep on receiving all the Bitcoin transactions, and it is upto the coder on what to do with it. Though it is advised, that whenever a new transaction comes in, it should be put onto a new thread or message queue without much calculation of any sort being done before. The reason is that with the tremendous stream of messages arriving to the OnMessage method, we do not want to occupy it for long as we do not want to miss any transaction. So any calculation or operation that needs to be done on every transaction, should be done on another thread.
Some Bitcoin transaction websockets servers automatically ping the connected clients to know if they are still active. Some servers don’t. But some servers may have a default client timeout if they realize that the client is no longer active. This realization is done by receiving ping messages from the client, so the client has to send a ping message after regular intervals(mostly after 20-30 seconds) to let the server know that it is active. This is shown in the following code:
private void sendPingMessage(String pingMessage){
RemoteEndpoint remoteEndpoint = session.getAsyncRemote();
// Async Send of a PING to remote endpoint
ByteBuffer payload = ByteBuffer.wrap(pingMessage.getBytes());
try
{
remoteEndpoint.sendPing(payload);
//LOG.debug("Ping message sent");
}
catch (IOException e)
{
LOG.error("Error while sending ping message", e.getMessage(), e);
e.printStackTrace(System.err);
}
}
One could start a timer that invokes the sendPingMessage() method after the specified amount of time.
And finally, there is the last piece of the puzzle, the OnClose method. This method is called when the connection between the client and the server is closed, normally or abnormally. This method is useful if the programmer wants to reinitialize the Bitcoin transaction websockets client as soon as it closes, so that it connects yet again with the server and keep receiving messages. Whatever the programmer does, is up-to their requirements. This method is annotated with @OnClose.
Bitcoin Transaction Websockets Servers
There are numerous service providers that provide the functionality of providing Bitcoin transaction websockets. We, so far, have tested two of them thoroughly: Chain.com & Blockchain.info.
Blockchain.info provides a lot of functionality other than transactions through Bitcoin transaction websockets, have done a remarkable job and stand as one of the pioneers in the Bitcoin industry. Though, their websocket server suffers a lag in sending transactions continuously and sometimes even stops sending messages. At Least until january 2015, this was the case. Hopefully they have made some changes to improve this.
Chain.com on the other hand, has a rock-solid foundation for sending transactions through websockets. The transactions keep on coming in without any halt or delay, and their server automatically checks through ping messages whether the client is alive or not. Although their websocket feature is in beta phase, if someone wants to implement a Bitcoin transaction websocket client, Chain.com is the way to go.
This will do it for this blog post. Hopefully this will give an insight into the websocket best practices in general, and retrieving Bitcoin transaction websockets & Bitcoin Development in particular.
Comments