Querying for contracts using Java

How do I query for a list of contracts and their data in Java?

I’ve generated java bindings and saw that it’s possible to get a list of transactions but I’m not sure how to work with the TransactionFilter API, or how I can use a GetActiveContractsRequest instance.

Does anyone have examples?

Querying for contracts may come in different shapes and forms and the Ledger API has limited querying capabilities. As such and in absence of further details with regards to the kind of need you need to fulfill, I’ll share a usage pattern which is quite common and appeared many times in our experience.

If you’re interested in the active contracts set (i.e. the contracts which have not been archived and are thus available to be used to exercise a choice) the usual approach is that of using the active contracts and transaction services together as an event source, keeping a view of active contracts:

  • ask for the currently active contracts hitting ActiveContracsService#GetActiveContracts
  • receive a list of active contracts, together with the ledger offset at which they are valid
  • feed the offset you received as the starting offset into TransactionService#GetTransactions
  • the “concatenation” of these two result is effectively an unbound stream of CreateEvents (signaling a contract being created) and ArchiveEvents (signaling a contract being archived). CreateEvents carry the contract payload as defined in your Daml model, and both CreateEvents and ArchiveEvents expose the contract ID, allowing you to add contracts to your local set and removing them upon consumption
  • by using the logic described above against some kind of persistent database, you can build rich querying capabilities (e.g. indexing a contract payload by a specific field)

You can read more about those two services in our documentation (here for version 2.2.0). You can read more about the details about those two in the Ledger API reference (here as well for the same version).

2 Likes

Thank you for the answer, I’m not sure the syntax you quoted is for Java. For any future readers, I’m using this instead: client.getActiveContractSetClient().getActiveContracts(myFilter, verbose). This was referenced from the quickstart-java template.

What you’ve stated seems to work well to maintain a local cache of the contracts. Is there an existing project that does something similar?

The HTTP JSON API Service is probably a very good example of this approach, although it’s meant for a generic use case and not tuned to a specific set of payload-specific queries.

One important note: the HTTP JSON API Service in particular takes one specific approach to this, by updating its cache on an ongoing basis only for currently active queries. This allows the HTTP JSON API not to have to maintain an access token but explicitly ask for it as part of the query. Another approach could be to keep your cached contracts always up-to-date by maintaining a running open stream from the Ledger API. This could be a viable approach if you plan to keep a relatively small view of relevant contracts for your application but comes at the cost of having to maintain the access token throughout the service lifecycle.

I see - do you have a link to the source code or documentation on how they maintain this cache?

I believe the bulk of the logic should be in these two places:

@Stephen do you have other places you think are valuable sources of information?

AcsTxStreams can be thought of as the part that assembles the ACS (if used) and transaction service queries into a single event source. Any application doing this will almost always want something very similar to this.

The DB-specific query backends complete the story, but you’ll find a mixture of things that are important to any DB contract storage cache here and things that are complicated by the specific requirements of the JSON API.

ContractsFetch combines those two. It is much closer to something that you’ll always need, but there are still several complicating factors brought on by the generality of the JSON API that will be irrelevant to many use cases. For example, we have complex “livelocking” behavior brought on by the need to maintain many parallel, overlapping, but out-of-sync datasets, which I would guess to be uncommon for application use cases.