Hyperledger Composer Historian
Warning: This is the first part of the implementation of functionality to track the transactions and asset updates. There are additional use cases that are not a covered by this implementation. Details are being tracked in GitHub issue 55. There may be changes to the HistorianRecord (documented below) as a result.
The Historian is a registry populated with HistorianRecords
that contains information about historical transactions. When a transaction is submitted, the HistorianRecord
is updated, and over time, maintains a history of transactions within a business network, and the participants and identities involved in submitting those transactions. HistorianRecord
assets can be queried using Composer Queries to extract specific records or data. An example would be tracking the lifecycle of an asset such as a Land Title, from creation (with a Land Title ID) through update, through ownership changes carried out by different identities and/or participants. The transactions associated with this example can be queried in Historian, say, over a given time period.
Historian Record
A HistorianRecord
is an 'asset' defined in the Hyperledger Composer system namespace. HistorianRecord
s are defined as follows.
asset HistorianRecord identified by transactionId {
o String transactionId
o String transactionType
--> Transaction transactionInvoked
--> Participant participantInvoking optional
--> Identity identityUsed optional
o Event[] eventsEmitted optional
o DateTime transactionTimestamp
}
String transactionId
Using the transaction id as the uuidString transactionType
Type of the transaction that was submittedTransaction transactionInvoked
Relationship to transactionParticipant participantInvoking
Participant who invoked this transactionIdentity identityUsed
The identity that was used by the participantEvent[] eventsEmitted
The events that where emitted by this transactionIdDateTime transactionTimestamp
Use the transaction's timestamp
It's important to note that the Transaction, Participant and Identity are relationships. Applications that wish to obtain these attributes must resolve this relationship.
Tracking Transactions
The historian registry is updated for each successful transaction, transactions which fail are not recorded. In addition, several operations that the Hyperledger Composer runtime makes are classed as transactions. These 'system transactions' are defined in the Hyperledger Composer system model. The following will add HistorianRecord
assets.
- Add, Remove and Update of Assets
- Add, Remove and Update of Participants
- Issue, Bind, Activate and Revoke of Identities
Note that the retrieval of assets and participants is not tracked.
Querying the Historian
The established APIs for querying and working with resources and relationship are applicable. The historian is a registry containing assets (HistorianRecords) so can be queried.
For example to get all the HistorianRecord
assets a typical promise chain would be as follows.
let historian = await businessNetworkConnection.getHistorian();
let historianRecords = historian.getAll();
console.log(prettyoutput(historianRecords));
As this is a 'getAll' call it will potentially return high volume of data. Therefore the query capability is vital in being able to select a subset of records. A typical example would be to select records based on a time. This uses the query capability to select records where the transaction timestamp is past a certain point. The returned records can be processed in exactly the same way.
let now = new Date();
now.setMinutes(10); // set the date to be time you want to query from
let q1 = businessNetworkConnection.buildQuery('SELECT org.hyperledger.composer.system.HistorianRecord ' +
'WHERE (transactionTimestamp > _$justnow)');
await businessNetworkConnection.query(q1,{justnow:now});
More advanced queries can be used; for example, the following query selects and returns the Add, Update, and Remove asset system transactions.
// build the special query for historian records
let q1 = businessNetworkConnection.buildQuery(
`SELECT org.hyperledger.composer.system.HistorianRecord
WHERE (transactionType == 'AddAsset' OR transactionType == 'UpdateAsset' OR transactionType == 'RemoveAsset')`
);
await businessNetworkConnection.query(q1);