@ocap/statedb-qldb
Version:
OCAP statedb adapter that uses amazon qldb as backend statedb
139 lines (118 loc) • 4.77 kB
JavaScript
/* 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;