1.4.0 • Published 4 years ago

@toolscip/scip-lib v1.4.0

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
4 years ago

scip-lib

Version Downloads/week License

This is a simple Smart Contract Invocation Protocol compliant parser and generator library written in Typescript for Node.js. It was built out as an extension of the jsonrpc-lib since SCIP is made out as an extension of JSON-RPC.

Table of Contents

Installation

The package can be simply installed via npm, a suggestion is to import the package locally as follow:

npm install --save @toolscip/scip-lib

Usage

In order to use this module you just have to import it like any other npm package:

JavaScript import

const scip = require('@toolscip/scip-lib');

Typescript import

import scip from '@toolscip/scip-lib';
// or
import { scip } from '@toolscip/scip-lib';

One of the main functionality that this package provides is the parse function that allows a client to parse a string message, checks whether it a SCIP-compliant message and then if valid it generates the corresponding SCIP object, otherwise it throws an exception (i.e. ErrorObject) containing information about what is invalid in the string message.

Suppose to have received a message request as the following one:

{
  "jsonrpc": "2.0",
  "id": "abcdefg",
  "method": "Invoke",
  "params": {
    "functionId": "send",
    "inputs": [
      {
        "type": {
          "type": "number"
        },
        "name": "amount",
        "value": 50
      }
    ],
    "outputs": []
  }
}

Now you just have to invoke the parse function providing the message as input, if the message is valid the function will return the object instance of a SCIP message (i.e. ScipInvocation, ScipSubscription, ScipUnsubscription, ScipQuery, ScipCallback, ScipSuccess and ScipError).

try {
  const obj = scip.parse(msg);
  // `obj` will be an instance of a ScipInvocation class
} catch (err) {
  console.log('Error message: ' + err.message); // error description
  console.log('Error code: ' + err.code); // scip error code
  console.log('Error data: ' + err.data); // scip error additional data
}

Note: the input message must be in string format.

There are two different flavours of the parse function, the parseRequest and the parseResponse, which act exactly as the parse function, providing additional check over the specific SCIP message by throwing an error if the parsed data is not a request or a response respectively.

This package provides also other function that are mainly used to create new SCIP messages instances, all of them require an id (i.e. json-rpc id) and a params object that must be a valid SCIP params object in according to the specific invoked function (i.e. Invocation, FunctionSubscription, EventSubscription, FunctionUnsubscription, EventUnsubscription, FunctionQuery, EventQuery, QueryResult and Callback).

The params object can be directly provided as instance of one of the aforementioned classes or as generic JSON object.

const param = {
  functionId: 'send',
  inputs: [
    {
      type: {
        type: 'number',
      },
      name: 'amount',
      value: 50,
    },
  ],
  outputs: [],
};

try {
  const invObj = scip.invoke('abcdefg', param);
  // 'invObj' will be an instance of a ScipInvocation
} catch (err) {
  console.log('Error message: ' + err.message); // error description
  console.log('Error code: ' + err.code); // scip error code
  console.log('Error data: ' + err.data); // scip error additional data
}

SCIP Specification

The Smart Contract Invocation Protocol is a protocol intended to provide a protocol specification in the context of blockchains integration that allows external consumer applications to invoke smart contract functions in a uniform manner regardless of the underlying blockchain technology. Moreover it provides the capability to monitor smart contracts at runtime. Its core consists of a set of methods that can be used by blockchain-external consumer application to interact with smart contracts.

In particular the protocol defines four different methods which are used to perform the following operations:

  • The invocation of a smart contract function
  • The subscription to notifications regarding function invocations or event occurrences
  • The unsubscription from live monitoring
  • The querying of past invocations or events

Invoke Method

This method allows an external application to invoke a specific smart contract's function. It requires a synchronous response notifying the success or not of the request and then an asynchronous message notifying the result of the function invocation.

Subscribe Method

This method allows to monitor smart contract's functions and/or events, in particular can be used to be notified whenever an event is triggered by the smart contract or a specific function has been invoked. It requires a synchronous response notifying the success or not of the request and then one or more asynchronous responses notifying the occurrences of what the consumer have subscribed.

Unsubscribe Method

This method is simply used to cancel previously established subscription, this can be used to cancel one or more subscription in according to the request parameters.

Query Method

This is a fully synchronous request method which is used to retrieve past event occurrences or function invocations. This method does not have asynchronous responses from the gateway.

Binding

SCIP does not force to use a specific protocol for carrying all these messages, hence different bindings could be used. Here, we have decided to propose a JSON-RPC binding for SCIP, which is a stateless transport-agnostic remote procedure call protocol that uses JSON as its data format. A complete binding can be found at scip binding.

In according to the binding proposed in the specification we have built this library out of a JSON-RPC parser library since every SCIP message is also a JSON-RPC 2.0 compliant message. Hence the SCIP can be seen as a restriction of the JSON-RPC protocol:

  • jsonrpc: 2.0 as for generic json-rpc message
  • id: string or number as for any json-rpc message
  • method: this can only be one of invoke, subscribe, unsubscribe and query
  • params: the parameter object must have specific form in acccording to the method that has to be invoked.
  • result: any, as for a generic json-rpc success response
  • error: same error object in a generic json-rpc error response, SCIP provides additional codes that are strictly correlated to the blockchain field.

Reference: A complete protocol specification can be found in the Github repository.

Classes

This library was built in an OOP perspective, providing a class definition for each SCIP message.

SCIP Requests

RequestClassMethodParamsDescription
InvocationScipInvocationInvokeInvocationFunction invocation request object
SubscriptionScipSubscriptionSubscribeEventSubscription or FunctionSubscriptionFunction/event subscription request object
UnsubscriptionScipUnsubscriptionUnsubscribeEventUnsubscription or FunctionUnsubscriptionCancel subscription request object
QueryScipQueryQueryEventQuery or FunctionQueryFunction/event query request object

Note: the params objects are specific class objects

SCIP Responses

ResponseClassDescription
Success (sync)ScipSuccessGeneric synchronous success response object
Error (sync)ScipErrorSynchronous error response object
Query Response (sync)ScipQueryResultSynchronous response of a Query request, extension of ScipSuccess
Callback (async)ScipCallbackAsynchronous response of a SCIP gateway, in a json-rpc context it acts as a Notification

Reference: a complete class documentation can be found at scip-lib.

Functions

This library provides a set of tools that allows a client to easily handle and generates SCIP messages, in particular it provides the following functions:

FunctionReturnDescription
parseScipMessageParse a generic object checking its validity, if so it returns the specific SCIP object instance, otherwise it throws an ErrorObject
parseRequestScipRequestSame as parse function, which, in addition, throws an error even if the parsed data is a valid SCIP message but not a valid request (e.g. a response)
parseResponseScipResponseSame as parse function, which, in addition, throws an error even if the parsed data is a valid SCIP message but not a valid async or sync response (e.g. a request)
invokeScipInvocationGenerates a ScipInvocation message if the params is a valid Invocation object.
subscribeEventScipSubscriptionGenerates a ScipSubscription message if the params is a valid EventSubscription object.
subscribeFunctionScipSubscriptionGenerates a ScipSubscription message if the params is a valid FunctionSubscription object.
unsubscribeEventScipUnsubscriptionGenerates a ScipUnsubscription message if the params is a valid EventUnsubscription object.
unsubscribeFunctionScipUnsubscriptionGenerates a ScipUnsubscription message if the params is a valid FunctionUnsubscription object.
queryEventScipQueryGenerates a ScipQuery message if the params is a valid EventQuery object.
queryFunctionScipQueryGenerates a ScipQuery message if the params is a valid FunctionQuery object.

Examples

A simple example of scip-lib usage is inside a SCIP server.

Note: express and body-parser are external packages, which are strictly correlated to the following example of usage, but they are not mandatory, you can use whatever you prefer.

import * as express from 'express';
import * as bodyParser from 'body-parser';
import scip, { ScipMessage, types } from '@toolscip/scip-lib';

const PORT = 8000;
const app = express();

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

/* Handle POST request */
app.post('/', (req, res) => {
  const body = req.body;
  try {
    const request = scip.parseRequest(body);
    const result = handleRequest(request);
    const response = scip.success(request.id, result); // SCIP success response
    res.json(response);
  } catch (err) {
    // notice that err is already a valid jsonrpc ErrorObject
    const error = scip.error(req.body.id, err); // SCIP error response
    res.json(error);
  }
});

/* Start the server */
app.listen(PORT, () => {
  console.log(`Server started at port ${PORT}`);
});

The handleRequest can be written as follows:

/**
 * Executes some task in according to the specific kind of the SCIP request, hence in 'jsonrpc' context, it performs the code directly associated with the called 'method'.
 * @param msg: message request
 * @returns the result of the specific message invocation
 */
function handleRequest(msg: ScipMessage): any {
  if (msg instanceof types.ScipInvocation) {
    // ...
  } else if (msg instanceof types.ScipInvocation) {
  } else if (msg instanceof types.ScipSubscription) {
  } else if (msg instanceof types.ScipUnsubscription) {
  } else if (msg instanceof types.ScipQuery) {
  } // ...
}

If you want to see another, completely different, example of usage please take a look at the clisc, a Node.js command line interface, which was built for automating the SCIP request invocations.

Contributing

Feel free to post questions and problems on the issue tracker. Pull requests are welcome!

Feel free to fork and modify or add new features and functionality to the library