Skip to main content

Creating a Connection and Opening a Session with SDK

When we use the SDK to perform queries and transactions, the following three steps must be executed first:

  1. Clone the SDK
  2. Create a connection to the Orion cluster
  3. Open a database session with the Orion cluster

Let's look at these three steps in more detail.

info

Here's an example of creating a connection and opening a session: orion-sdk-go/examples/api/.

1) Cloning the SDK Repository

To write queries and transactions using the SDK, first execute the following steps:

  1. Create the required directory using the command mkdir -p github.com/hyperledger-labs
  2. Change the current working directory to the above created directory by issuing the command cd github.com/hyperledger-labs
  3. Clone the go SDK repository with git clone https://github.com/hyperledger-labs/orion-sdk-go

We can then use the APIs provided by the SDK.

2) Copying the Crypto Materials

We need root CA certificates and user certificates to submit queries and transactions using the SDK.

  • While creating a connection, we need to provide RootCAs configuration.
  • While opening a session, we need to provide the user's certificate and private key.

For all examples shown in this documentation, we use the crypto materials available in the deployment/crypto folder in the orion-server repository.

Hence, copy the github.com/hyperledger-labs/orion-server/deployment/crypto to the location where you write/use example code provided in this documentation.

3) Creating a Connection to the Orion Cluster

3.1) Source Code

The following function creates a connection to our single node Orion cluster deployed using the sample configuration.

create-connection.go
package main

import (
"github.com/hyperledger-labs/orion-sdk-go/pkg/bcdb"
"github.com/hyperledger-labs/orion-sdk-go/pkg/config"
"github.com/hyperledger-labs/orion-server/pkg/logger"
)

func createConnection() (bcdb.BCDB, error) {
logger, err := logger.New(
&logger.Config{
Level: "debug",
OutputPath: []string{"stdout"},
ErrOutputPath: []string{"stderr"},
Encoding: "console",
Name: "bcdb-client",
},
)
if err != nil {
return nil, err
}

conConf := &config.ConnectionConfig{
ReplicaSet: []*config.Replica{
{
ID: "bdb-node-1",
Endpoint: "http://127.0.0.1:6001",
},
},
RootCAs: []string{
"./crypto/CA/CA.pem",
},
Logger: logger,
}

db, err := bcdb.Create(conConf)
if err != nil {
return nil, err
}

return db, nil
}

3.2) Source Code Commentary

The bcdb.Create() method in the bcdb package at the SDK prepares a connection context to the Orion cluster and loads the certificate of root certificate authorities.

The signature of the Create() function is shown below:

func Create(config *config.ConnectionConfig) (BCDB, error)

The parameter config.ConnectionConfig holds the following:

  • ID and IP address of each Orion node in the cluster
  • Certificate of root CAs
  • Logger for logging messages

The structure of the config.ConnectionConfig is shown below:

// ConnectionConfig required configuration in order to
// open session with BCDB instance, replica set informations
// servers root CAs
type ConnectionConfig struct {
// List of replicas URIs client can connect to
ReplicaSet []*Replica
// Keeps path to the server's root CA
RootCAs []string
// Logger instance, if nil an internal logger is created
Logger *logger.SugarLogger
}

// Replica
type Replica struct {
// ID replica's ID
ID string
// Endpoint the URI of the replica to connect to
Endpoint string
}

In our simple deployment, we have only one node in the cluster. Hence, we have one Replica with the ID as bdb-node-1 and Endpoint as http://127.0.0.1:6001. Further, we have only one root certificate authority and hence, the RootCAs holds the path to a single CA's certificate only.

The Create() returns the BCDB implementation that allows the user to create database sessions with the Orion cluster.

type BCDB interface {
// Session instantiates session to the database
Session(config *config.SessionConfig) (DBSession, error)
}

4) Opening a Database Session

4.1) Source Code

Once we created the Orion connection and received the BCDB object instance, we can open a database session by calling the Session() method. The Session object authenticates the database user against the database server. The following function opens a database session for an already existing database connection.

open-session.go
package main

import (
"time"

"github.com/hyperledger-labs/orion-sdk-go/pkg/bcdb"
"github.com/hyperledger-labs/orion-sdk-go/pkg/config"
)

func openSession(db bcdb.BCDB, userID string) (bcdb.DBSession, error) {
sessionConf := &config.SessionConfig{
UserConfig: &config.UserConfig{
UserID: userID,
CertPath: "./crypto/" + userID + "/" + userID + ".pem",
PrivateKeyPath: "./crypto/" + userID + "/" + userID + ".key",
},
TxTimeout: 20 * time.Second,
QueryTimeout: 10 * time.Second,
}

session, err := db.Session(sessionConf)
if err != nil {
return nil, err
}

return session, nil
}

4.2) Source Code Commentary

The signature of Session() method is shown below:

Session(config *config.SessionConfig) (DBSession, error)

The Session() takes config.SessionConfig as a parameter that holds the user configuration (user's ID and credentials) and various configuration parameters, such as transaction timeout and query timeout. The structure of the config.SessionConfig is shown below:

// SessionConfig keeps per database session
// configuration information
type SessionConfig struct {
UserConfig *UserConfig
// The transaction timeout given to the server in case of tx sync commit - `tx.Commit(true)`.
// SDK will wait for `TxTimeout` + some communication margin
// or for timeout error from server, whatever come first.
TxTimeout time.Duration
// The query timeout - SDK will wait for query result maximum `QueryTimeout` time.
QueryTimeout time.Duration
}


// UserConfig user related information
// maintains wallet with public and private keys
type UserConfig struct {
// UserID the identity of the user
UserID string
// CertPath path to the user's certificate
CertPath string
// PrivateKeyPath path to the user's private key
PrivateKeyPath string
}

As the admin user is submitting the transactions, we have set the UserConfig to hold the userID of admin, certificate, and private key of the admin user. The transaction timeout is set to 20 seconds. This means that the SDK waits for 20 seconds to receive the transaction's status and receipt synchronously. Once timeout happens, the SDK needs to pool for the transaction status asynchronously.

The Session() returns the DBSession implementation that allows the user to execute various database transactions and queries. The DBSession implementation supports the following methods:

// DBSession captures user's session
type DBSession interface {
// DBsTx starts a Database Administration Transaction
DBsTx() (DBsTxContext, error)
// UserTx starts a User Administration Transaction
UsersTx() (UsersTxContext, error)
// DataTx starts a Data Transaction
DataTx(options ...TxContextOption) (DataTxContext, error)
// LoadDataTx loads a pre-compileted data transaction
LoadDataTx(*types.DataTxEnvelope) (LoadedDataTxContext, error)
// ConfigTx starts a Cluster Configuration Transaction
ConfigTx() (ConfigTxContext, error)
// Provenance returns a provenance querier that supports various provenance queries
Provenance() (Provenance, error)
// Ledger returns a ledger querier that supports various ledger queries
Ledger() (Ledger, error)
// JSONQuery returns a JSON querier that supports complex queries on value fields using JSON syntax
JSONQuery() (JSONQuery, error)
}

Once the user gets the DBSession, any type of transaction can be started:

    tx, err := session.DBsTx()