UNPKG

@ocap/statedb-qldb

Version:

OCAP statedb adapter that uses amazon qldb as backend statedb

139 lines (118 loc) 4.77 kB
/* eslint-disable no-underscore-dangle */ const merge = require('lodash/merge'); const AwsSdk = require('aws-sdk'); const { StateDB } = require('@ocap/statedb'); const { QldbDriver, RetryConfig } = require('amazon-qldb-driver-nodejs'); const https = require('https'); const Table = require('./table/base'); const Account = require('./table/account'); const Token = require('./table/token'); const Rollup = require('./table/rollup'); const { name, version } = require('../package.json'); // eslint-disable-next-line import/order const debug = require('debug')(name); class QLDBStateDB extends StateDB { /** * Creates an instance of QLDBStateDB. * * @param {object} [config={}] config object * @param {string} config.ledgerName QLDB ledger name * @param {object} config.clientOptions QLDB Client options * @param {string} config.clientOptions.region which region does the QLDB ledger live in * @param {string} config.clientOptions.accessKeyId * @param {string} config.clientOptions.secretAccessKey * @param {string} config.clientOptions.region which region does the QLDB ledger live in * @param {bool} config.debug wether turn on debug mode * @memberof QLDBStateDB */ constructor(config = {}) { super(); this.config = merge( { ledgerName: '', maxConcurrentTransactions: 2000, // QLDB has a hard limit for 30 seconds timeout, each transaction takes 1 seconds to execute // The retryLimit should not exceed that limit in worst case // If the retryLimit is exceeded, OCC error will be thrown retryLimit: 10, clientOptions: {}, }, config ); if (!this.config.ledgerName) { throw new Error('QLDB statedb requires config.ledgerName to work'); } if (!this.config.clientOptions) { throw new Error('QLDB statedb requires config.clientOptions to work'); } if (!this.config.clientOptions.region) { throw new Error('QLDB statedb requires config.clientOptions.region to work'); } if (!this.config.clientOptions.accessKeyId) { throw new Error('QLDB statedb requires config.clientOptions.accessKeyId to work'); } if (!this.config.clientOptions.secretAccessKey) { throw new Error('QLDB statedb requires config.clientOptions.secretAccessKey to work'); } if (config.debug) { AwsSdk.config.logger = console; } this.name = name; this.version = version; this.driver = this._createDriver(); this.account = new Account('account', this.driver, 'address'); this.asset = new Table('asset', this.driver, 'address'); this.factory = new Table('factory', this.driver, 'address'); this.delegation = new Table('delegation', this.driver, 'address'); this.tx = new Table('tx', this.driver, 'hash'); this.token = new Token('token', this.driver, 'address'); this.chain = new Table('chain', this.driver, 'address'); this.stake = new Table('stake', this.driver, 'address'); this.rollup = new Rollup('rollup', this.driver, 'address'); this.rollupBlock = new Table('rollupBlock', this.driver, 'hash'); this.evidence = new Table('evidence', this.driver, 'hash'); this.attachReadyListeners(); if (process.env.NODE_ENV !== 'test') { this._ensureTables(); } } runAsLambda(cb, { retryLimit } = {}) { return this.driver.executeLambda(cb, retryLimit != null ? new RetryConfig(retryLimit) : undefined); } _createDriver() { // Replace this value as appropriate for your application const { ledgerName, maxConcurrentTransactions, retryLimit, clientOptions } = this.config; const serviceConfig = { ...clientOptions, httpOptions: { agent: new https.Agent({ keepAlive: true, // Set this to the same value as `maxConcurrentTransactions`(previously called `poolLimit`) // Do not rely on the default value of `Infinity` maxSockets: maxConcurrentTransactions, }), }, }; const retryConfig = new RetryConfig(retryLimit); const driver = new QldbDriver(ledgerName, serviceConfig, maxConcurrentTransactions, retryConfig); return driver; } _ensureTables() { return this.driver.getTableNames().then(async (tableNames) => { const tables = Object.keys(this.readyMarks); // eslint-disable-next-line no-restricted-syntax for (const x of tables) { if (tableNames.includes(x)) { debug('table ready', { name: x }); this[x].markReady(); } else { debug('table pending', { name: x }); // eslint-disable-next-line no-await-in-loop await this[x].initialize(); } } return tables; }); } } module.exports = QLDBStateDB;