New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

postchain-client

Package Overview
Dependencies
Maintainers
4
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postchain-client

Client library for accessing a Postchain node through REST.

  • 1.1.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
823
decreased by-0.36%
Maintainers
4
Weekly downloads
 
Created
Source

Postchain client

Example:

let crypto = require("crypto");
let secp256k1 = require("secp256k1");
let { encryption } = require("postchain-client")

// Create some dummy keys
let signerPrivKeyA = Buffer.alloc(32, "a");
let signerPubKeyA = secp256k1.publicKeyCreate(signerPrivKeyA);
let signerPrivKeyB = Buffer.alloc(32, "b");
let signerPubKeyB = secp256k1.publicKeyCreate(signerPrivKeyB);

// Create a simple signature provider.
// This is the standard way of signing a message using the gtxClient,
// and it can be used with the restClient too. Look further below for
// more details on how to use it.
let signatureProviderA = newSignatureProvider({privKey: signerPrivKeyA})

// The lower-level client that can be used for any
// postchain client messages. It only handles binary data.
let restClient = require("postchain-client").restClient;

// The higher-level client that is used for generic transactions, GTX.
// This utilizes the GTX format described below to pass function calls
// from the client to the postchain backend implementation.
let gtxClient = require("postchain-client").gtxClient;

// Each blockchain has a blockchainRID, that identifies the blockchain
// we want to work with. This blockchainRID must match the blockchain RID
// encoded into the first block of the blockchain. How the blockchainRID
// is constructed is up to the creator of the blockchain. In this example
// we use the linux command:
// echo "A blockchain example"| sha256sum
let blockchainRID = "7d565d92fd15bd1cdac2dc276cbcbc5581349d05a9e94ba919e1155ef4daf8f9";

// Create an instance of the rest client and configure it for a specific set of
// base urls and a blockchinRID. You may set an optional pool size for the connection pool,
// default pool size is 10. Applications that do hundreds of requests
// per second may consider setting this a bit higher, for example 100.
// It *may* speed things up a bit. You may also set an opitional
// poolinginterval in milliseconds, default is set to 500, a fail over 
// config wich include attemps per endpoint and attempt interval, default is 3 and 500.
let rest = restClient.createRestClient([`http://localhost:7741`], blockchainRID, 5, 1000);

// Create an instance of the higher-level gtx client. It will
// use the rest client instance and it will allow calls to functions
// fun1 and fun2. The backend implementation in Postchain must
// provide those functions.
let gtx = gtxClient.createClient(rest, blockchainRID, ["fun1", "fun2"]);

// Start a new request. A request instance is created.
// The public keys are the keys that must sign the request
// before sending it to postchain. Can be empty.
let req = gtx.newTransaction([signatureProviderA.pubKey, signerPubKeyB]);

// call fun1 with three arguments: a string, an array and a Buffer
req.fun1("arg1", ["arg2", [1, 2]], Buffer.from("hello"));
// call the same function with only one argument
req.fun1("arg1");
// call fun2
req.fun2(1, 2);

// Signing can be done either through the sign() function ...
// The signatureProvider method sign() will be called, and
// it's expected to return the signature of the digest it's given
// as input (of type Buffer). It needs to return the output of
// secp256k1.ecdsaSign(...params).signature
await req.sign(signatureProviderA);
// You can also use this, if you don't need a signature provider
// The second parameter is optional, it will be generated if not given
//await req.sign(signerPrivKeyA, signerPubKeyA);

// ... or by the addSignature() function
let bufferToSign = req.getBufferToSign();
// Sign the buffer externally.
let signatureFromB = askUserBToSign(bufferToSign);
// and add the signature to the request
req.addSignature(signerPubKeyB, signatureFromB);

// Finally send the request and supply an error callback
req.send((error) => {
  if (error) {
    console.log(error);
  }
});

// Now we can query Postchain. The backend must have a method
// query method named "findStuff" (readOnlyConn, queryObject) that can
// understand the query object and typically perform a search using
// the database connection readOnlyConn. The backend query function
// can return any serializable result object you chose
gtx.query("findStuff", { text: "arg1" });

// This will make a request with a single operation
// and a single signature.
req = gtx.newTransaction(blockchainRID, [signatureProviderA.pubkey]);
req.fun1("arg1");
await req.sign(signatureProviderA);
req.send((error) => {
  if (!error) {
    done();
  }
});

function sha256(buffer) {
  return crypto.createHash("sha256").update(buffer).digest();
}

// This is to demonstrate that you can use external signing
// mechanisms. It could be a complex function, requiring you
// to sign from your phone, another device, or something else again
function askUserBToSign(buffer) {
  // The signed digest is a double sha-256
  var digest = sha256(sha256(buffer));
  return secp256k1.sign(digest, signerPrivKeyB).signature;
}

// The complex signature process can, however, even be implemented in
// a signatureProvider. Once you have a callback like the one above, 
// it's a simple matter of making a signature provider:
let signatureProviderB {
  pubKey: signerPubKeyB,
  sign: askUserBToSign
}

A very simple backend for the above client might look like this:

module.exports.createSchema = async function (conn) {
  console.log("Creating schema in backend");
  await conn.query(
    "CREATE TABLE IF NOT EXISTS example " +
      "(id SERIAL PRIMARY KEY, stuff TEXT NOT NULL)"
  );
};

// Example backend implementation that doesn't do anything but log the function calls
module.exports.backendFunctions = {
  fun1: async function (
    conn,
    tx_iid,
    call_index,
    signers,
    stringArg,
    arrayArg,
    bufferArg
  ) {
    console.log("fun1 called in backend");
  },
  fun2: async function (conn, tx_iid, call_index, signers, intArg1, intArg2) {
    console.log("fun2 called in backend");
  },
};

module.exports.backendQueries = {
  findStuff: async function (readOnlyConn, queryObject) {
    console.log("Search for " + queryObject.text);
    if (queryObject.text === "giveMeHits") {
      return { hits: 4 };
    }
    return { hits: 0 };
  },
};

GTX architecture

Generic transactions were developed to make it easier to make user implementations of Postchain. The user doesn't have to invent a binary format for it's transactions. With GTX you specify a set of functions that you will call from the client, and the GTX client will serialize the function calls, sign them and send to Postchain.

User
 |
 | req.fun1('arg1', 'arg2');
 | req.fun2('arg1'); req.sign(privKeyA); req.send(err => {})
 v
GtxClient
 |
 | <Buffer with serialized message>
 v
RestClient
 |
 | POST http://localhost:7741/tx {tx: 'hex encoded message'}
 v
RestApi
 |
 | <Buffer with serialized message>
 v
Postchain
 |
 | backend.fun1(conn, tx_iid, 0, [pubKeyA], 'arg1', 'arg2');
 | backend.fun2(conn, tx_iid, 1, [pubKeyA], 'arg1');
 v
Backend

The first four arguments to backend.fun1 are

  • conn is a database connection that the backend function can use to query/update the database
  • tx_iid is the primary key of this postchain transaction.
  • call_index, 0 in this example. It's the index within the GTX of the current call
  • signers, all signers of this GTX. The signatures from these signers are already verified by the GTX framework when the backend function is called.

FAQs

Package last updated on 17 Feb 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc