Skip to main content

@hlf-core/transport-common

This package contains exactly what must match on both sides — on the client and in the chaincode. It depends neither on fabric-network nor on fabric-shim, and lives in both places as one and the same code. In other words, it is the protocol itself, factored out separately so that it cannot be accidentally implemented differently on the two sides.

The key idea of the whole transport is formulated right here: the interaction is built not on a set of contract functions but on a single one. Any command is packed into an envelope and travels through the single method transportFabricExecute (this and the neighboring constants are defined in the package). What exactly was invoked is determined by the name field in the envelope. From this follows an important consequence: adding a new command does not require reinstalling the chaincode — it is enough to register a handler by name.

The base command class is TransportFabricCommandAsync<U, V> with the isReadonly flag. The request itself travels in TransportFabricRequestPayload<U> — an envelope with the fields id, name, request, options, isReadonly, and isNeedReply. The envelope has a parse method, which on the chaincode side checks the function name and the number of parameters, deserializes the data, restores the defaults, and validates them, and a clear method, which clears the default values before sending. The latter is not optimization for optimization’s sake: everything that travels in the envelope will be written to the ledger forever, so there must be nothing superfluous there. A characteristic detail: the Ed25519 algorithm is considered the default and is not transmitted over the network at all.

The response comes back in TransportFabricResponsePayload<V>, and here the result and the error live in one response field. Thanks to this, a chaincode error reaches the client as an object with a code and details, rather than as lost context.

The command options (TransportFabricCommandOptions) add the fields userId and signature to the standard @ts-core options — that very application-level signature:

export interface ITransportFabricCommandOptions extends ITransportCommandOptions {
userId?: string;
signature?: ISignature;
}

The readonly command NonceGetCommand is responsible for a fresh nonce — the client takes the current value, increments it, and signs the next command with it:

export class NonceGetCommand extends TransportFabricCommandAsync<string, string> {
public static readonly NAME = 'NonceGetCommand';
constructor(uid: UID) {
super(NonceGetCommand.NAME, getUid(uid), null, true); // the last argument is isReadonly
}
}

For more on signature verification, see the “Security” section.

The chaincode metadata is factored out here as well — ChaincodeMode, IChaincodeMetadata, ChaincodeMetadataGetCommand — through which the client can, for example, find out whether a contract has batch mode enabled and choose the appropriate transport.