Skip to content

Commit

Permalink
Improvements to eventing documentation (hyperledger#462)
Browse files Browse the repository at this point in the history
Signed-off-by: Mark S. Lewis <[email protected]>
  • Loading branch information
bestbeforetoday authored Jun 30, 2022
1 parent 0bdbe63 commit 60d82f0
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
* Checkpointer allows update of a checkpoint position after events are successfully processed.
*/
public interface Checkpointer extends Checkpoint {

/**
* Checkpoint a successfully processed block.
* <p>Note that the block number is an unsigned 64-bit integer, with the sign bit used to hold the top bit of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

/**
* Builder used to create a new events request.
*
* <p>If both a start block and checkpoint are specified, and the checkpoint has a valid position set, the
* checkpoint position is used and the specified start block is ignored. If the checkpoint is unset then the start block
* is used.</p>
*
* <p>If no start position is specified, eventing begins from the next committed block.</p>
*
* @param <T> Event type returned by the request.
*/
public interface EventsBuilder<T> extends Builder<EventsRequest<T>> {
Expand Down
59 changes: 43 additions & 16 deletions java/src/main/java/org/hyperledger/fabric/client/Network.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,55 @@
* <ul>
* <li>Obtain a specific smart contract deployed to the network using {@link #getContract(String)}, in order to
* submit and evaluate transactions for that smart contract.</li>
* <li>Listen for events emitted when blocks are committed to the ledger using
* {@link #getChaincodeEvents(String, CallOption...)} or {@link #newChaincodeEventsRequest(String)}.</li>
* <li>Listen for chaincode events emitted by transactions when they are committed to the ledger using
* {@link #getChaincodeEvents(String)} or {@link #newChaincodeEventsRequest(String)}.</li>
* <li>Listen for block events emitted when blocks are committed to the ledger:
* <ul>
* <li><strong>Blocks</strong> using {@link #getBlockEvents()} or {@link #newBlockEventsRequest()}.</li>
* <li><strong>Filtered blocks</strong> {@link #getFilteredBlockEvents()} or {@link #newFilteredBlockEventsRequest()}.</li>
* <li><strong>Blocks and private data </strong> {@link #getBlockAndPrivateDataEvents()} or {@link #newBlockAndPrivateDataEventsRequest()}.</li>
* </ul>
* </li>
* </ul>
*
* <p>Chaincode events example:</p>
* <p>To safely handle connection errors during eventing, it is recommended to use a checkpointer to track eventing
* progress. This allows eventing to be resumed with no loss or duplication of events.</p>
*
* <p>Chaincode events example</p>
* <pre>{@code
* try (CloseableIterator<ChaincodeEvent> events = network.getChaincodeEvents("chaincodeName")) {
* events.forEachRemaining(event -> {
* // Process event
* });
* Checkpointer checkpointer = new InMemoryCheckpointer();
* while (true) {
* ChaincodeEventsRequest request = network.newChaincodeEventsRequest("chaincodeName")
* .checkpoint(checkpointer)
* .startBlock(blockNumber) // Ignored if the checkpointer has checkpoint state
* .build();
* try (CloseableIterator<ChaincodeEvent> events = request.getEvents()) {
* events.forEachRemaining(event -> {
* // Process then checkpoint event
* checkpointer.checkpointChaincodeEvent(event);
* });
* } catch (io.grpc.StatusRuntimeException e) {
* // Connection error
* }
* }
* }</pre>
* *
* <p>Chaincode event replay example</p>
*
* <p>Block events example</p>
* <pre>{@code
* ChaincodeEventsRequest request = network.newChaincodeEventsRequest("chaincodeName")
* .startBlock(blockNumber)
* .build();
* try (CloseableIterator<ChaincodeEvent> events = request.getEvents()) {
* events.forEachRemaining(event -> {
* // Process event
* });
* Checkpointer checkpointer = new InMemoryCheckpointer();
* while (true) {
* ChaincodeEventsRequest request = network.newBlockEventsRequest()
* .checkpoint(checkpointer)
* .startBlock(blockNumber) // Ignored if the checkpointer has checkpoint state
* .build();
* try (CloseableIterator<Block> events = request.getEvents()) {
* events.forEachRemaining(event -> {
* // Process then checkpoint block
* checkpointer.checkpointBlock(event.getHeader().getNumber());
* });
* } catch (io.grpc.StatusRuntimeException e) {
* // Connection error
* }
* }
* }</pre>
*/
Expand Down
6 changes: 3 additions & 3 deletions node/src/blockeventsrequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface BlockEventsRequest extends Signable {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* ```typescript
* const blocks = await request.getEvents();
* try {
* for async (const block of blocks) {
Expand All @@ -49,7 +49,7 @@ export interface FilteredBlockEventsRequest extends Signable {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* ```typescript
* const blocks = await request.getEvents();
* try {
* for async (const block of blocks) {
Expand All @@ -75,7 +75,7 @@ export interface BlockAndPrivateDataEventsRequest extends Signable {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* ```typescript
* const events = await network.getBlockAndPrivateEventsData();
* try {
* for async (const event of events) {
Expand Down
2 changes: 1 addition & 1 deletion node/src/chaincodeeventsrequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ChaincodeEventsRequest extends Signable {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* ```typescript
* const events = await request.getEvents();
* try {
* for async (const event of events) {
Expand Down
14 changes: 7 additions & 7 deletions node/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,23 @@ import { SubmittedTransaction } from './submittedtransaction';
* {@link Gateway.newSignedCommit} methods respectively.
*
* @example Evaluate transaction
* ```
* ```typescript
* const result = await contract.evaluate('transactionName', {
* arguments: ['one', 'two'],
* // Specify additional proposal options here
* });
* ```
*
* @example Submit transaction
* ```
* ```typescript
* const result = await contract.submit('transactionName', {
* arguments: ['one', 'two'],
* // Specify additional proposal options here
* });
* ```
*
* @example Async submit
* ```
* ```typescript
* const commit = await contract.submitAsync('transactionName', {
* arguments: ['one', 'two']
* });
Expand All @@ -64,7 +64,7 @@ import { SubmittedTransaction } from './submittedtransaction';
* ```
*
* @example Fine-grained submit transaction
* ```
* ```typescript
* const proposal = contract.newProposal('transactionName');
* const transaction = await proposal.endorse();
* const commit = await transaction.submit();
Expand All @@ -74,7 +74,7 @@ import { SubmittedTransaction } from './submittedtransaction';
* ```
*
* @example Off-line signing
* ```
* ```typescript
* const unsignedProposal = contract.newProposal('transactionName');
* const proposalBytes = unsignedProposal.getBytes();
* const proposalDigest = unsignedProposal.getDigest();
Expand Down Expand Up @@ -116,7 +116,7 @@ export interface Contract {
* This can be used for querying the world state.
*
* This method is equivalent to:
* ```
* ```typescript
* contract.evaluate(name, { arguments: [ arg1, arg2 ] });
* ```
* @param name - Name of the transaction to invoke.
Expand All @@ -133,7 +133,7 @@ export interface Contract {
* committed to the ledger.
*
* This method is equivalent to:
* ```
* ```typescript
* contract.submit(name, { arguments: [ arg1, arg2 ] });
* ```
* @param name - Name of the transaction to be invoked.
Expand Down
5 changes: 5 additions & 0 deletions node/src/eventsbuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { Checkpoint } from './checkpointer';

/**
* Options used when requesting events.
*
* If both a start block and checkpoint are specified, and the checkpoint has a valid position set, the checkpoint
* position is used and the specified start block is ignored. If the checkpoint is unset then the start block is used.
*
* If no start position is specified, eventing begins from the next committed block.
*/
export interface EventsOptions {
/**
Expand Down
2 changes: 1 addition & 1 deletion node/src/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { TransactionImpl } from './transaction';
/**
* Options used when connecting to a Fabric Gateway.
* @example
* ```
* ```typescript
* function defaultTimeout(): grpc.CallOptions {
* return {
* deadline: Date.now() + 5000, // 5 second timeout
Expand Down
61 changes: 54 additions & 7 deletions node/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,53 @@ import { SigningIdentity } from './signingidentity';
* Network represents a network of nodes that are members of a specific Fabric channel. The Network can be used to
* access deployed smart contracts, and to listen for events emitted when blocks are committed to the ledger. Network
* instances are obtained from a Gateway using the {@link Gateway.getNetwork} method.
*
* To safely handle connection errors during eventing, it is recommended to use a checkpointer to track eventing
* progress. This allows eventing to be resumed with no loss or duplication of events.
*
* @example Chaincode events
* ```typescript
* const checkpointer = checkpointers.inMemory();
*
* while (true) {
* const events = await network.getChaincodeEvents(chaincodeName, {
* checkpoint: checkpointer,
* startBlock: BigInt(101), // Ignored if the checkpointer has checkpoint state
* });
* try {
* for async (const event of events) {
* // Process then checkpoint event
* await checkpointer.checkpointChaincodeEvent(event)
* }
* } catch (err: unknown) {
* // Connection error
* } finally {
* events.close();
* }
* }
* ```
*
* @example Block events
* ```typescript
* const checkpointer = checkpointers.inMemory();
*
* while (true) {
* const events = await network.getBlockEvents({
* checkpoint: checkpointer,
* startBlock: BigInt(101), // Ignored if the checkpointer has checkpoint state
* });
* try {
* for async (const event of events) {
* // Process then checkpoint block
* await checkpointer.checkpointBlock(event.getHeader().getNumber())
* }
* } catch (err: unknown) {
* // Connection error
* } finally {
* events.close();
* }
* }
* ```
*/
export interface Network {
/**
Expand All @@ -41,7 +88,7 @@ export interface Network {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* ```typescript
* const events = await network.getChaincodeEvents(chaincodeName, { startBlock: BigInt(101) });
* try {
* for async (const event of events) {
Expand Down Expand Up @@ -69,8 +116,8 @@ export interface Network {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* const blocks = await network.getBlockEvents();
* ```typescript
* const blocks = await network.getBlockEvents({ startBlock: BigInt(101) });
* try {
* for async (const block of blocks) {
* // Process block
Expand All @@ -96,8 +143,8 @@ export interface Network {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* const blocks = await network.getFilteredBlockEvents();
* ```typescript
* const blocks = await network.getFilteredBlockEvents({ startBlock: BigInt(101) });
* try {
* for async (const block of blocks) {
* // Process block
Expand All @@ -123,8 +170,8 @@ export interface Network {
* @throws {@link GatewayError}
* Thrown by the iterator if the gRPC service invocation fails.
* @example
* ```
* const events = await network.getBlockAndPrivateEventsData();
* ```typescript
* const events = await network.getBlockAndPrivateEventsData({ startBlock: BigInt(101) });
* try {
* for async (const event of events) {
* // Process block and private data event
Expand Down
Loading

0 comments on commit 60d82f0

Please sign in to comment.