Skip to content

Chaincode Client

The @gala-chain/client package provides a client for interacting with the chaincode. Currently, it supports the following client types: * client for interacting directly with the Hyperledger Fabric network, built on top of the fabric-network and fabric-ca-client packages; * client for interacting with the chaincode via REST API that meets the GalaChain REST API specification, used internally at GalaGames, and is also compatible with the slightly different REST API exposed by Fablo REST.

All client types share the same API, so it is easy to switch between them, depending on your needs.

Also, @gala-chain/client package is designed to be lightweight. This is why fabric-network and fabric-ca-client dependencies are marked as optional peerDependencies and should be installed separately.

Hyperledger Fabric Client

In order to connect to the Hyperledger Fabric network, you need to provide the following configuration: 1. HFClientParams - information containing basic information about network topology and credentials for connecting to the network; 2. ContractConfig - information about the chaincode that will be used to interact with the network. 3. Optionally, a custom API specification to make the client type-safe.

HFClientConfig

The HFClientConfig interface defines parameters that are required to connect to the Hyperledger Fabric network.

```typescript
const params: HFClientConfig = {
  orgMsp: "PartnerOrg1",
  userId: "admin",
  userSecret: "adminpw",
  connectionProfilePath: path.resolve(networkRoot, "connection-profiles/cpp-partner.json")
};
  • orgMsp - Hyperledger Fabric MSP name of the organization that the client will connect to;
  • userId - id of the user in Fabric CA that will be used to connect to the network;
  • userSecret - password/secret of the user in CA;
  • connectionProfilePath - path to the connection profile file that describes the network topology.

Both adminId and adminPass are required to authorize the client with the network. If they are not provided, the client will try to get them from the environment variables ADMIN_ID and ADMIN_PASS respectively.

The connectionProfilePath should refer to a valid connection profile JSON file. For local development, you can use the connection profile provided in the <network-root>/connection-profiles directory of the network generated by GalaChain CLI.

ContractConfig

The ContractConfig interface defines parameters that are required to interact with the chaincode.

const contract: ContractConfig = {
  channelName: "product-channel",
  chaincodeName: "basic-product",
  contractName: "PublicKeyContract"
};
  • channelName - name of the channel that the client will connect to;
  • chaincodeName - name of the chaincode that the client will use to interact with the network;
  • contractName - name of the contract that the client will use to interact with the chaincode.

Creating the client

const client: ChainClient = gcclient
  .forConnectionProfile(params)
  .forContract(contract);

The client creation is a two-step process. First, you need to create a client builder instance using the forConnectionProfile method. Then the forContract method returns the actual client instance.

As a result, you get a ChainClient instance that can be used to interact with the chaincode. It supports evaluateTransaction and submitTransaction methods that are used to invoke chaincode functions.

After you end interacting with the chaincode, you should disconnect the client:

await client.disconnect();

Otherwise, the client will keep the GRPC connection to the network open.

REST API Client

The REST API client is used to interact with the chaincode via REST API, that matches the specification of managed infrastructure of GalaChain.

In order to connect to the REST API, you need to provide the following configuration: 1. RestApiClientConfig - information containing basic information about path mapping and credentials for connecting to the network; 2. ContractConfig - information about the chaincode that will be used to interact with the network. 3. Optionally, a custom API specification to make the client type-safe.

RestApiClientConfig

The RestApiClientConfig interface defines parameters that are required to connect to the REST API.

const params: RestApiClientConfig = {
  apiUrl: "http://localhost:3000/api",
  configPath: path.resolve(__dirname, "api-config.json")
};
  • orgMsp - Hyperledger Fabric MSP name of the organization that the client will connect to;
  • apiUrl - URL of the REST API;
  • configPath - path to the configuration file that describes path mapping for channels, chaincodes, and contracts. Sample configuration file can be found in the e2e directory of the chaincode generated from template by GalaChain CLI.

ContractConfig

The ContractConfig interface defines parameters that are required to interact with the chaincode.

const contract: ContractConfig = {
  channelName: "product-channel",
  chaincodeName: "basic-product",
  contractName: "PublicKeyContract"
};
  • channelName - name of the channel that the client will connect to;
  • chaincodeName - name of the chaincode that the client will use to interact with the network;
  • contractName - name of the contract that the client will use to interact with the chaincode.

Creating the client

const client: ChainClient = gcclient
  .forApiConfig(params)
  .forContract(contract);

The client creation is a two-step process. First, you need to create a client builder instance using the forConnectionProfile method. Then the forContract method returns the actual client instance.

As a result, you get a ChainClient instance that can be used to interact with the chaincode. It supports evaluateTransaction and submitTransaction methods that are used to invoke chaincode functions.

After you end interacting with the chaincode, you should disconnect the client:

await client.disconnect();

Builder and actual client

For all high-level operations, the client uses the Builder pattern: 1. first, you create a builder instance using the forConnectionProfile or forApiConfig method; 2. then you configure the builder instance using the forContract method.

Since all ChainClient builders share the same interface, you can just parametrize the builder type and use the same code for all client types, for instance:

const builder: ChainClientBuilder = process.env.USE_REST_API === "true"
  ? gcclient.forApiConfig(...) 
  : gcclient.forConnectionProfile(...);

const client: ChainClient = builder.forContract(...);

Extending the client API

The @gala-chain/client package provides a default API definition that is used to make the client type-safe. By default ChainClient defines evaluateTransaction and submitTransaction methods that are used to interact with the chaincode. However, you can provide your own API definition, if you want to extend the client API or use a different API. The API definition is a function that accepts a ChainClient instance and returns an object with methods that will be added to the client.

function customAPI(client: ChainClient) {
  return {
    async GetProfile(privateKey: string) {
      const dto = new GetMyProfileDto().signed(privateKey, false);
      const response = await client.evaluateTransaction("GetMyProfile", dto, UserProfile);
      if (GalaChainResponse.isError(response)) {
        throw new Error(`Cannot get profile: ${response.Message} (${response.ErrorKey})`);
      } else {
        return response.Data as UserProfile;
      }
    }
  };
}

Now, when you enhance the client with your custom API, you can use not only default methods but also the ones that you defined:

const client: ChainClient = ...;
client.evaluateTransaction(...);  // available
client.submitTransaction(...);    // available
client.GetProfile(...);           // compilation error

const extendedClient = client.extend(customAPI);
client.evaluateTransaction(...);  // available
client.submitTransaction(...);    // available
client.GetProfile(...);           // available