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:
- Clone the SDK
- Create a connection to the Orion cluster
- 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:
- Create the required directory using the command
mkdir -p github.com/hyperledger-labs
- Change the current working directory to the above created directory by issuing the command
cd github.com/hyperledger-labs
- 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.
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
andIP 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.
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()