CardanoSoftware Development

Cardano Mempool monitoring with Yaci Java Library

In this post, I am going to explain how to monitor a local Cardano node’s mempool using Java or any JVM language. To do that we are going to use a small Java library called “Yaci” and we need an instance of Cardano node.

What’s Yaci ?

An opensource project which implements Cardano mini-protocol.

Mini-protocols are a set of protocols which are used to enable communication between different Cardano nodes. These protocols can also be used by other client applications like indexer, explorer, wallets to fetch data from a node and create their own data store. There are two categories: node-to-node and node-to-client. The node-to-client protocol suite is mostly for trusted clients like wallets and chain consumers.

Yaci implements most of the mini protocols including local transaction submission.

To find the list of mini-protocols currently supported by Yaci, please visit project’s GitHub page.

https://github.com/bloxbean/yaci#status

To simplify the usage of mini protocol, it also provides various high level apis for different scenarios. So Java developers don’t need to understand the low level protocol details. There are two types of high level apis

  • Listener based

Using listener based apis, you can easily get callbacks for different events like new blocks, rollback etc.

Using reactive apis, you can receive blocks data through a Flux and can compose functionalities using available operators like filter, map etc.

Usage Scenarios Examples :

The followings are few examples where Yaci can be used

  • To listen real-time events from a node (Example: Token minting, Token minted for a policy, Transactions …)
  • Receive block/transaction data and create your own data store or query layer
  • Alert or notification based on events in blockchain
  • Create your own indexer
  • Implement a Tx submission service by submitting transactions to a local Cardano node or a remote node with node-to-client protocol exposed through a relay like “socat”

Mempool monitoring

As mentioned earlier, we will go through the steps required for local mempool monitoring.

Pre-requisites

  1. Local Tx Monitor is a node-to-client protocol. Node-to-client protocols are exposed through Unix domain socket. So that a local trusted client can connect and access those info from Cardano node. But you can use a relay like “socat” to expose Unix domain socket through a TCP socket for remote clients.

Example :

socat TCP-LISTEN:31001,fork UNIX-CONNECT:/data/cardano/pre-prod/db/node.socket

The apis for local tx monitoring in yaci accepts both path host / port and local socket file.

2. Create a Java app and add Yaci dependency to it

<dependency>
     <groupId>com.bloxbean.cardano</groupId>
     <artifactId>yaci</artifactId>
     <version>0.1.2</version>
</dependency>

Note: Get the latest released version of Yaci from project’s GitHub.

As we will be getting transaction bytes from the mempool, we will use “cardano-client-lib” to get transaction hash and to de-serialize transaction. This is only required for our example.

<dependency>
      <groupId>com.bloxbean.cardano</groupId>
      <artifactId>cardano-client-lib</artifactId>
      <version>0.4.0</version>
</dependency>

Configure and start the connection

First we need to setup the connection to a Cardano node through node-to-client protocol. So let’s get the path to Cardano’s nodeSocketFile and network’s protocol magic.

 String nodeSocketFile = "~/cardano-node/preprod/db/node.socket";
 long protocolMagic = Constants.PREPROD_PROTOCOL_MAGIC;

Note: You can use com.bloxbean.cardano.yaci.core.common.Constant class to get protocol magics for public networks.

Alternatively, if the node-to-client protocol is exposed through a relay like “socat”, get host and port.

Now, create an instance of LocalClientProvider and start the client.
As LocalClientProvider supports both local state query and local tx monitor mini protocols, you can now execute supported queries on a node.

 LocalClientProvider localClientProvider = new LocalClientProvider(nodeSocketFile, protocolMagic);
 localClientProvider.start();

In the above code snippet, we are creating a local client and then starting the client.

Let’s get “LocalTxMonitorClient” from localClientProvider.

LocalTxMonitorClient localTxMonitorClient = localClientProvider.getTxMonitorClient();

Now we are ready to query the node.

Query Mempool Transactions

To get the list of transactions currently in the mempool, we need to first acquire a mempool snapshot and then query the snapshot. You can acquire and query in two method calls or just use “acquireAndGetMempoolTransactionsAsMono()” which wraps both steps in one method call.

In this example, let’s monitor the mempool in a loop. Acquire method is a blocking call, so the program waits there till the availability of new snapshot.

while (true) {
     // local tx monitor code
}

Let’s add the following code snippets in the above while(true) loop.

List<byte[]> txBytesList = localTxMonitorClient.acquireAndGetMempoolTransactionsAsMono().block();

The above code will acquire a new snapshot when available and return a list of transactions as bytes in a Mono. We are using “block()” to get the list of transactions through a blocking call.
Note: You should use Mono’s non-blocking api like “subscribe” in your application to avoid blocking.

Now that we have a list of transactions as bytes, we can loop through the list to get transaction hashes and de-serialize available transactions. This can be easily done using Cardano Client Lib.

for(byte[] txBytes: txBytesList) {
    String txHash = TransactionUtil.getTxHash(txBytes);
    System.out.println("Tx Hash >> " + txHash);

    Transaction transaction = Transaction.deserialize(txBytes);
    System.out.println("Tx Body >> " + transaction);
}

Finally, let’s get the mempool size and capacity. Local tx monitor also provides information like mempool capacity, size and no of txs.

The following code snippet is getting the mempool status. You can see that we are using “getMempoolSizeAndCapacity()” in the below code snippet. This method doesn’t acquire a new snapshot and it uses the already acquired snapshot in the previous call.
But if you want to acquire a new snapshot and query mempool status, then you can use “acquireAndGetMempoolSizeAndCapacity()”.

MempoolStatus mempoolStatus = localTxMonitorClient.getMempoolSizeAndCapacity().block();
System.out.println("Mem Pool >> " + mempoolStatus);

Our mempool monitoring app is now ready. Run this program and then submit few transactions to this node through another program or Cardano CLI, you should start seeing the transactions as soon as those are available in mempool.

Sample Output:

Waiting to acquire next snapshot ...
Mem Pool >> MempoolStatus(capacityInBytes=178176, sizeInBytes=0, numberOfTxs=0)
Waiting to acquire next snapshot ...
Tx Hash >> 4d7ce3ece2f9aa36550763753df3885344b1f15ea1e67dd7c9f3f49924f0f480
Tx Body >> Transaction(body=TransactionBody(inputs=[TransactionInput{transactionId=7e36a90a9b85902d5b42599f831d...
Waiting to acquire next snapshot ...

That’s it. We covered only one use case in this post, but Yaci provides different apis which can support many different types of use cases.

Here’s a list of few major high level apis in Yaci that you may find interesting

  • BlockStreamer : Reactive api to start getting blocks from current tip or from a given point.
  • BlockSync : Get latest block data starting from current tip through a listener.
  • BlockRangeSync : Get blocks data from point-1 to poin-2 through a listener
  • LocalTxSubmissionClient : To submit a transaction to Cardano node
  • TipFinder To find the tip through a simple method call

Full source code of mempool monitoring example

import com.bloxbean.cardano.client.exception.CborDeserializationException;
import com.bloxbean.cardano.client.transaction.spec.Transaction;
import com.bloxbean.cardano.client.transaction.util.TransactionUtil;
import com.bloxbean.cardano.yaci.core.common.Constants;
import com.bloxbean.cardano.yaci.helper.LocalClientProvider;
import com.bloxbean.cardano.yaci.helper.LocalTxMonitorClient;
import com.bloxbean.cardano.yaci.helper.model.MempoolStatus;

import java.util.List;

public class LocalTxMonitorSample {

    public static void main(String[] args) throws CborDeserializationException {
        String nodeSocketFile = "~/cardano-node/preprod/db/node.socket";
        long protocolMagic = Constants.PREPROD_PROTOCOL_MAGIC;

        LocalClientProvider localClientProvider = new LocalClientProvider(nodeSocketFile, protocolMagic);
        localClientProvider.start();
        LocalTxMonitorClient localTxMonitorClient = localClientProvider.getTxMonitorClient();

        while (true) {
            System.out.println("Waiting to acquire next snapshot ...");
            List<byte[]> txBytesList = localTxMonitorClient.acquireAndGetMempoolTransactionsAsMono().block();

            for(byte[] txBytes: txBytesList) {
                String txHash = TransactionUtil.getTxHash(txBytes);
                System.out.println("Tx Hash >> " + txHash);

                Transaction transaction = Transaction.deserialize(txBytes);
                System.out.println("Tx Body >> " + transaction);
            }

            MempoolStatus mempoolStatus = localTxMonitorClient.getMempoolSizeAndCapacity().block();
            System.out.println("Mem Pool >> " + mempoolStatus);
        }
    }
}
<dependency>
     <groupId>com.bloxbean.cardano</groupId>
     <artifactId>yaci</artifactId>
     <version>0.1.2</version>
</dependency>
     <dependency>
     <groupId>com.bloxbean.cardano</groupId>
     <artifactId>cardano-client-lib</artifactId>
     <version>0.4.0</version>
</dependency>

References:
1. Yaci : A Cardano Mini Protocols implementation in Java (https://github.com/bloxbean/yaci)

2. Cardano Client Lib : Cardano client library in Java (https://github.com/bloxbean/cardano-client-lib)

3. Yaci CLI : A CLI example using Yaci (https://github.com/bloxbean/yaci-cli)

Published on Java Code Geeks with permission by Satya Ranjan, partner at our JCG program. See the original article here: Cardano Mempool monitoring with Yaci Java Library

Opinions expressed by Java Code Geeks contributors are their own.

Satya

Satya is a solution architect and developer with more than 20 years of experience who has worked in a wide variety of organizations from product development, banking to IT consultancy. He is also a blockchain enthusiast.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button