UNPKG

immudb-node

Version:

Node.js SDK for immudb written in TypeScript

1,124 lines (1,123 loc) 63.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const dotenv = __importStar(require("dotenv")); const grpc = __importStar(require("@grpc/grpc-js")); const empty = __importStar(require("google-protobuf/google/protobuf/empty_pb")); dotenv.config(); const schemaTypes = __importStar(require("./proto/schema_pb")); const services = __importStar(require("./proto/schema_grpc_pb")); const util = __importStar(require("./util")); const tx_1 = require("./tx"); const state_1 = __importDefault(require("./state")); const verification_1 = require("./verification"); const consts_1 = require("./consts"); const common_1 = require("./common"); class ImmudbClient { constructor({ host = process.env.IMMUDB_HOST || '127.0.0.1', port = process.env.IMMUDB_PORT || '3322', certs, rootPath = consts_1.DEFAULT_ROOTPATH, }) { // init insecure grpc auth this._auth = grpc.credentials.createInsecure(); // init secure grpc auth if (certs !== undefined) { this._auth = grpc.credentials.createSsl(Buffer.from(JSON.stringify(certs))); } // initialize client from service this.client = new services.ImmuServiceClient(`${host}:${port}`, this._auth); // init empty grpc metadata this._metadata = new grpc.Metadata(); // init state this.state = new state_1.default({ client: this.client, rootPath }); } static async getInstance(config) { const { user = process.env.IMMUDB_USER, password = process.env.IMMUDB_PWD, database: databasename = process.env.IMMUDB_DEFAULT_DB, autoDatabase = true, autoLogin = true } = config; try { if (!ImmudbClient.instance) { console.log(`${consts_1.CLIENT_INIT_PREFIX} creating new ImmudbClient instance with config`, '\n', `${util.maskConfig(config)}`); ImmudbClient.instance = new ImmudbClient(config); console.log(`${consts_1.CLIENT_INIT_PREFIX} init new instance`); await ImmudbClient.instance.initClient(user, password, databasename, autoLogin, autoDatabase); } else { console.log(`${consts_1.CLIENT_INIT_PREFIX} using already available ImmudbClient instance`); } return new Promise((resolve) => resolve(ImmudbClient.instance)); } catch (err) { await ImmudbClient.instance.shutdown(); return new Promise((_, reject) => reject(err)); } } async initClient(user, password, databasename, autoLogin = true, autoDatabase = true) { // by default automatically manage user login with dotenv variables if (autoLogin) { // login if (user && password) { const resLogin = await this.login({ user, password }); const token = resLogin ? util.maskString(resLogin.token) : ''; console.log('ImmudbClient: login', token); } } else { console.log(`${consts_1.CLIENT_INIT_PREFIX} skipped automatic init login (manual client login is required)`); if (autoDatabase) { console.warn(`${consts_1.CLIENT_INIT_PREFIX} it's not possible to 'autoDatabase' if 'autoLogin' is set to false`, '\n', `(the following ops will fallback to use '${consts_1.DEFAULT_DATABASE}' database)`); } } // by default automatically manage database ops with dotenv variables if (autoLogin && autoDatabase) { // get current database list const resList = await this.listDatabases(); if (resList && resList.databasesList.some(db => db.databasename === databasename)) { // useDatabase database specified if it // already exists await this.useDatabase({ databasename: consts_1.DEFAULT_DATABASE }); console.log(`${consts_1.CLIENT_INIT_PREFIX} useDatabase '${consts_1.DEFAULT_DATABASE}'`); } else if (databasename) { // run createDatabase and useDatabase if databasename // is different than the default one await this.createDatabase({ databasename }); console.log(`${consts_1.CLIENT_INIT_PREFIX} createDatabase '${databasename}'`); await this.useDatabase({ databasename }); console.log(`${consts_1.CLIENT_INIT_PREFIX} useDatabase '${databasename}'`); } else { // run createDatabase and useDatabase if default // databasename is missing await this.useDatabase({ databasename: consts_1.DEFAULT_DATABASE }); console.log(`${consts_1.CLIENT_INIT_PREFIX} useDatabase '${databasename}'`); } } else { console.log(`${consts_1.CLIENT_INIT_PREFIX} skipped automatic init database`, '\n', `(manual client database ops are required, '${consts_1.DEFAULT_DATABASE}' database will be used otherwise)`); } // fetch health status await this.health(); } async shutdown() { this.state.commit(); this.logout(); process.exit(0); } async login(params) { try { const { user, password } = params; const req = new schemaTypes.LoginRequest(); req.setUser(util.utf8Encode(user)); req.setPassword(util.utf8Encode(password)); return new Promise((resolve, reject) => this.client.login(req, this._metadata, (err, res) => { if (err) { console.error('Login Error', err); return reject(err); } this._token = res.getToken(); this._metadata.remove('authorization'); this._metadata.add('authorization', `Bearer ${this._token}`); resolve({ token: this._token, warning: util.utf8Decode(res.getWarning()), }); })); } catch (err) { console.error('Login Error', err); } } async createDatabase({ databasename }) { try { const req = new schemaTypes.Database(); req.setDatabasename(databasename); return new Promise((resolve, reject) => this.client.createDatabase(req, this._metadata, (err, res) => { if (err) { console.error('Create database error', err); return reject(err); } return resolve(res); })); } catch (err) { console.error('Create database error', err); } } async useDatabase({ databasename }) { try { const req = new schemaTypes.Database(); req.setDatabasename(databasename); return new Promise((resolve, reject) => this.client.useDatabase(req, this._metadata, async (err, res) => { if (err) { console.error('Use database error', err); return reject(err); } else { const token = res.getToken(); this._metadata.remove('authorization'); this._metadata.add('authorization', `Bearer ${token}`); this._activeDatabase = databasename; resolve(res.toObject()); } })); } catch (err) { console.error('Use database error', err); } } async set({ key, value }) { try { const req = new schemaTypes.SetRequest(); const kv = new schemaTypes.KeyValue(); kv.setKey(util.utf8Encode(key)); kv.setValue(util.utf8Encode(value)); req.setKvsList([kv]); return new Promise((resolve, reject) => this.client.set(req, this._metadata, async (err, res) => { if (err) { console.error('Set error', err); return reject(err); } else { const resObject = res.toObject(); resolve(resObject); } })); } catch (err) { console.error('Set error', err); } } async get({ key }) { try { const req = new schemaTypes.KeyRequest(); req.setKey(util.utf8Encode(key)); return new Promise((resolve, reject) => this.client.get(req, this._metadata, (err, res) => { if (err) { console.error('Get error', err); reject(err.message); } else { resolve({ tx: res && res.getTx(), key: util.utf8Decode(res && res.getKey()), value: util.utf8Decode(res && res.getValue()), }); } })); } catch (err) { console.error(err); } } async listDatabases() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => this.client.databaseList(req, this._metadata, (err, res) => { if (err) { console.error('List databases error', err); return reject(err); } const dl = res && res.getDatabasesList(); const l = []; for (let i = 0; dl && i < dl.length; i++) { l.push(dl[i].toObject()); } resolve({ databasesList: l, }); })); } catch (err) { console.error(err); } } async changePermission(params) { try { const { action, permission, username, database } = params; const req = new schemaTypes.ChangePermissionRequest(); req.setAction(action); req.setPermission(permission); req.setUsername(username); req.setDatabase(database); return new Promise((resolve, reject) => this.client.changePermission(req, this._metadata, (err, res) => { if (err) { console.error('Change permission error', err); return reject(err); } else { resolve(res); } })); } catch (err) { console.error(err); } } async listUsers() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => this.client.listUsers(req, this._metadata, (err, res) => { if (err) { console.error('List users error', err); reject(err.message); } const ul = res && res.getUsersList(); const l = []; for (let i = 0; ul && i < ul.length; i++) { const u = ul[i]; const pl = u.getPermissionsList(); const p = []; for (let j = 0; j < pl.length; j++) { p.push({ database: pl[j].getDatabase(), permission: pl[j].getPermission(), }); } l.push({ user: util.utf8Decode(u.getUser()), permissionsList: p, createdby: u.getCreatedby(), createdat: u.getCreatedat(), active: u.getActive(), }); } resolve({ usersList: l, }); })); } catch (err) { console.error(err); } } async createUser(params) { try { const req = new schemaTypes.CreateUserRequest(); req.setUser(util.utf8Encode(params && params.user)); req.setPassword(util.utf8Encode(params && params.password)); req.setPermission(params && params.permission); req.setDatabase(params && params.database); return new Promise((resolve, reject) => this.client.createUser(req, this._metadata, (err, res) => { if (err) { console.error('Create user error', err); return reject(err); } resolve(res); })); } catch (err) { console.error(err); } } async changePassword(params) { try { const req = new schemaTypes.ChangePasswordRequest(); req.setUser(util.utf8Encode(params && params.user)); req.setOldpassword(util.utf8Encode(params && params.oldpassword)); req.setNewpassword(util.utf8Encode(params && params.newpassword)); return new Promise((resolve, reject) => this.client.changePassword(req, this._metadata, (err, res) => { if (err) { console.error('Change password error', err); return reject(err); } resolve(res); })); } catch (err) { console.error(err); } } async logout() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => this.client.logout(req, this._metadata, (err, res) => { if (err) { console.error('Logout error', err); reject(err.message); } resolve(res); })); } catch (err) { console.error(err); } } async setActiveUser(params) { try { const req = new schemaTypes.SetActiveUserRequest(); req.setUsername(params && params.username); req.setActive(params && params.active); return new Promise((resolve, reject) => this.client.setActiveUser(req, this._metadata, (err, res) => { if (err) { console.error('Set active user error', err); return reject(err); } resolve(res); })); } catch (err) { console.error(err); } } async health() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => { const call = this.client.health(req, this._metadata, (err, res) => { if (err) { console.error('Health error', err); return reject(err); } resolve({ status: res.getStatus(), version: res.getVersion(), }); }); call.on('_metadata', meta => { this._serverUUID = meta.get('immudb-uuid')[0]; }); }); } catch (err) { console.error(err); } } async count({ prefix }) { try { const req = new schemaTypes.KeyPrefix(); req.setPrefix(util.utf8Encode(prefix)); return new Promise((resolve, reject) => this.client.count(req, this._metadata, (err, res) => { if (err) { console.error('Count error', err); return reject(err); } resolve(res.toObject()); })); } catch (err) { console.error(err); } } async countAll() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => this.client.countAll(req, this._metadata, (err, res) => { if (err) { console.error('Count all error', err); return reject(err); } resolve(res.toObject()); })); } catch (err) { console.error(err); } } async scan({ seekkey, prefix, desc, limit, sincetx, nowait } = {}) { try { const req = new schemaTypes.ScanRequest(); if (seekkey !== undefined) { req.setSeekkey(util.utf8Encode(seekkey)); } if (prefix !== undefined) { req.setPrefix(util.utf8Encode(prefix)); } if (desc !== undefined) { req.setDesc(desc); } if (limit !== undefined) { req.setLimit(limit); } if (sincetx !== undefined) { req.setSincetx(sincetx); } if (nowait !== undefined) { req.setNowait(nowait); } return new Promise((resolve, reject) => this.client.scan(req, this._metadata, (err, res) => { if (err) { console.error('Scan error', err); return reject(err); } const result = []; const il = res && res.getEntriesList(); for (let i = 0; il && i < il.length; i++) { const item = il[i]; result.push({ tx: item.getTx(), key: util.utf8Decode(item.getKey()), value: util.utf8Decode(item.getValue()), }); } resolve({ entriesList: result, }); })); } catch (err) { console.error(err); } } async history({ key, offset, limit, desc, sincetx }) { try { const req = new schemaTypes.HistoryRequest(); req.setKey(util.utf8Encode(key)); offset && req.setOffset(offset); limit && req.setLimit(limit); desc && req.setDesc(desc); sincetx && req.setSincetx(sincetx); return new Promise((resolve, reject) => this.client.history(req, this._metadata, (err, res) => { if (err) { console.error('History error', err); return reject(err); } const entriesList = res.getEntriesList(); const result = entriesList.reduce((entries, entry) => entries.concat({ tx: entry.getTx(), key: util.utf8Decode(entry.getKey()), value: util.utf8Decode(entry.getValue()), }), []); resolve({ entriesList: result }); })); } catch (err) { console.error(err); } } async zScan({ set, seekkey, seekscore, seekattx, inclusiveseek, limit, desc, sincetx, nowait, minscore, maxscore }) { try { const req = new schemaTypes.ZScanRequest(); req.setSet(util.utf8Encode(set)); seekkey && req.setSeekkey(util.utf8Encode(seekkey)); seekscore && req.setSeekscore(seekscore); seekattx && req.setSeekattx(seekattx); inclusiveseek && req.setInclusiveseek(inclusiveseek); limit && req.setLimit(limit); desc && req.setDesc(desc); sincetx && req.setSincetx(sincetx); nowait && req.setNowait(nowait); if (minscore) { const minScore = new schemaTypes.Score(); minScore.setScore(minscore.score); req.setMinscore(minScore); } if (maxscore) { const maxScore = new schemaTypes.Score(); maxScore.setScore(maxscore.score); req.setMaxscore(maxScore); } return new Promise((resolve, reject) => this.client.zScan(req, this._metadata, (err, res) => { if (err) { console.error('zScan error', err); return reject(err); } const entriesList = res.getEntriesList(); const result = entriesList.reduce((entries, entry) => entries.concat({ set: util.utf8Decode(entry.getSet()), key: util.utf8Decode(entry.getKey()), score: entry.getScore(), attx: entry.getAttx() }), []); resolve({ entriesList: result }); })); } catch (err) { console.error(err); } } async currentState() { try { const req = new empty.Empty(); return new Promise((resolve, reject) => this.client.currentState(req, this._metadata, (err, res) => { if (err) { reject(err); } else { const signature = res.getSignature(); const state = { db: res.getDb(), txid: res.getTxid(), txhash: res.getTxhash_asU8(), signature: signature?.toObject() }; this.state.set({ databaseName: this._activeDatabase, serverName: this._serverUUID }, state); resolve({ db: this._activeDatabase, txid: res.getTxid(), txhash: res.getTxhash(), signature: { signature: util.utf8Encode(signature && signature.getSignature()), publickey: util.utf8Encode(signature && signature.getPublickey()) }, }); } })); } catch (err) { console.error(err); } } async zAdd(params) { const reqParams = Object.assign({}, params, { attx: 0 }); return this.zAddAt(reqParams); } async zAddAt({ set, score = 0, key, attx = 0 }) { try { const req = new schemaTypes.ZAddRequest(); req.setSet(util.utf8Encode(set)); req.setScore(score); req.setKey(util.utf8Encode(key)); req.setAttx(attx); req.setBoundref(attx > 0); return new Promise((resolve, reject) => this.client.zAdd(req, this._metadata, (err, res) => { if (err) { console.error('zAdd error', err); return reject(err); } resolve({ id: res.getId(), prevalh: util.getAlh(res), ts: res.getTs(), nentries: res.getNentries(), eh: res.getEh(), bltxid: res.getBltxid(), blroot: res.getBlroot(), }); })); } catch (err) { console.error(err); } } async verifiedZAdd(params) { const reqParams = Object.assign({}, params, { attx: 0 }); return await this.verifiedZAddAt(reqParams); } async verifiedZAddAt({ set, score, key, attx }) { try { const state = await this.state.get({ serverName: this._serverUUID, databaseName: this._activeDatabase, metadata: this._metadata }); const req = new schemaTypes.VerifiableZAddRequest(); const uintSet = util.utf8Encode(set); const uintKey = util.utf8Encode(key); const zar = new schemaTypes.ZAddRequest(); zar.setSet(uintSet); zar.setScore(score); zar.setKey(uintKey); zar.setAttx(attx); zar.setBoundref(attx > 0); req.setZaddrequest(zar); req.setProvesincetx(state.getTxid()); return new Promise((resolve, reject) => this.client.verifiableZAdd(req, this._metadata, (err, res) => { if (err) { console.error('verifiedZAddAt error', err); reject(err); } else { const resTx = res.getTx(); if (resTx === undefined) { console.error('Error getting verifiedZAddAt tx'); reject(); } else { const txMetadata = resTx.getMetadata(); if (txMetadata === undefined) { console.error('Error getting verifiedZAddAt txMetadata'); reject(); } else { const nEntries = txMetadata.getNentries(); if (nEntries !== 1) { console.error('nEntries verification failed for verifiedZAddAt'); reject(); } const tx = tx_1.txFrom(resTx); const eKv = util.encodeZAdd(uintSet, score, uintKey, attx); const inclusionProof = tx_1.proofTx(tx, eKv.getKey_asU8()); if (inclusionProof === undefined) { console.error('Error getting inclusionProof for verifiedZAddAt'); reject(); } else { let verifies = verification_1.verifyInclusion(inclusionProof, util.digestKeyValue(eKv), tx.htree.root); if (verifies === false) { console.error('Inclusion verification for verifiedZAddAt failed'); reject(); } const dualProof = res.getDualproof(); if (dualProof === undefined) { console.error('Error getting dualProof for verifiedZAddAt'); reject(); } else { const tTxMetadata = dualProof.getTargettxmetadata(); if (tTxMetadata === undefined) { console.error('Error getting tx metadata from dualProof in verifiedZAddAt'); reject(); } else { if (!util.equalArray(tx.htree.root, tTxMetadata.getEh_asU8())) { console.error('verifiedZAddAt error'); } const txid = state.getTxid(); const txhash = state.getTxhash_asU8(); let sourceId; let sourceAlh; if (txid === 0) { sourceId = tx.id; sourceAlh = tx.alh; } else { sourceId = txid; sourceAlh = txhash; } const targetId = tx.id; const targetAlh = util.getAlh(tTxMetadata); verifies = verification_1.verifyDualProof(dualProof, sourceId, targetId, sourceAlh, targetAlh); if (verifies === false) { console.error('Dual verification for verifiedZAddAt failed'); reject(); } this.state.set({ serverName: this._serverUUID, databaseName: this._activeDatabase }, { txid: targetId, txhash: targetAlh, signature: res.getSignature()?.toObject(), db: this._activeDatabase }); resolve(tTxMetadata.toObject()); } } } } } } })); } catch (err) { console.error(err); } } async setReference(params) { const setReferenceAtParameters = Object.assign({}, params, { attx: 0 }); return await this.setReferenceAt(setReferenceAtParameters); } async setReferenceAt({ key, referencedKey, attx }) { try { const req = new schemaTypes.ReferenceRequest(); req.setKey(util.utf8Encode(key)); req.setReferencedkey(util.utf8Encode(referencedKey)); req.setAttx(attx); req.setBoundref(attx > 0); return new Promise((resolve, reject) => this.client.setReference(req, this._metadata, (err, res) => { if (err) { console.error('Reference error', err); return reject(err); } resolve({ id: res.getId(), prevalh: util.getAlh(res), ts: res.getTs(), nentries: res.getNentries(), eh: res.getEh(), bltxid: res.getBltxid(), blroot: res.getBlroot(), }); })); } catch (err) { console.error(err); } } async verifiedSetReference(params) { const vSetReferenceAtParameters = Object.assign({}, params, { attx: 0 }); return await this.verifiedSetReferenceAt(vSetReferenceAtParameters); } async verifiedSetReferenceAt({ key, referencedKey, attx }) { try { const state = await this.state.get({ serverName: this._serverUUID, databaseName: this._activeDatabase, metadata: this._metadata }); const txid = state.getTxid(); const txhash = state.getTxhash_asU8(); const uint8Key = util.utf8Encode(key); const uint8RefKey = util.utf8Encode(referencedKey); const req = new schemaTypes.VerifiableReferenceRequest(); const refReq = new schemaTypes.ReferenceRequest(); refReq.setKey(uint8Key); refReq.setReferencedkey(uint8RefKey); refReq.setAttx(attx); refReq.setBoundref(attx > 0); req.setReferencerequest(refReq); req.setProvesincetx(txid); return new Promise((resolve, reject) => this.client.verifiableSetReference(req, this._metadata, (err, res) => { if (err) { console.error('verifiedSetReferenceAt error', err); reject(err); } else { const resTx = res.getTx(); if (resTx === undefined) { console.error('Error getting transaction from verifiedSetReferenceAt response'); reject(); } else { const resTxMetadata = resTx.getMetadata(); if (resTxMetadata === undefined) { console.error('Error getting transaction metadata from verifiedSetReferenceAt response'); reject(); } else { const nEntries = resTxMetadata.getNentries(); if (nEntries !== 1) { console.error('nEntries verification failed for verifiedSetReferenceAt'); reject(); } const tx = tx_1.txFrom(resTx); const inclusionProof = tx_1.proofTx(tx, util.prefixKey(uint8Key)); const eKv = new schemaTypes.KeyValue(); eKv.setKey(util.prefixKey(uint8Key)); eKv.setValue(util.encodeReferenceValue(uint8RefKey, attx)); if (inclusionProof === undefined) { console.error('Error getting inclusionProof from verifiedSetReferenceAt response'); reject(); } else { let verifies = verification_1.verifyInclusion(inclusionProof, util.digestKeyValue(eKv), tx.htree.root); if (verifies === false) { console.error('Inclusion verification failed for verifiedSetReferenceAt'); reject(); } const dualProof = res.getDualproof(); if (dualProof === undefined) { console.error('Error getting dualProof from verifiedSetReferenceAt response'); reject(); } else { let sourceId; let sourceAlh; if (txid === 0) { sourceId = tx.id; sourceAlh = tx.alh; } else { sourceId = txid; sourceAlh = txhash; } const targetId = tx.id; const targetAlh = util.getAlh(resTxMetadata); verifies = verification_1.verifyDualProof(dualProof, sourceId, targetId, sourceAlh, targetAlh); if (!verifies) { console.error('Dual verification failed for verifiedSetReferenceAt'); reject(); } this.state.set({ serverName: this._serverUUID, databaseName: this._activeDatabase }, { db: this._activeDatabase, txid: targetId, txhash: targetAlh, signature: res.getSignature()?.toObject() }); const txMetadataObject = { id: resTxMetadata.getId(), prevalh: util.getAlh(resTxMetadata), ts: resTxMetadata.getTs(), nentries: resTxMetadata.getNentries(), eh: resTxMetadata.getEh_asU8(), bltxid: resTxMetadata.getBltxid(), blroot: resTxMetadata.getBlroot_asU8(), }; resolve(txMetadataObject); } } } } } })); } catch (err) { console.error(err); } } async setAll({ kvsList }) { try { const req = new schemaTypes.SetRequest(); const kvls = kvsList.map(({ key, value }) => { const kv = new schemaTypes.KeyValue(); kv.setKey(util.utf8Encode(key)); kv.setValue(util.utf8Encode(value)); return kv; }); req.setKvsList(kvls); return new Promise((resolve, reject) => this.client.set(req, this._metadata, (err, res) => { if (err) { console.error('setAll error', err); reject(err); } else { resolve({ id: res.getId(), prevalh: util.getAlh(res), ts: res.getTs(), nentries: res.getNentries(), eh: res.getEh(), bltxid: res.getBltxid(), blroot: res.getBlroot(), }); } })); } catch (err) { console.error(err); } } async execAll({ operationsList }) { try { const req = new schemaTypes.ExecAllRequest(); const opl = operationsList.map(({ kv, zadd, ref }) => { const op = new schemaTypes.Op(); const keyValue = new schemaTypes.KeyValue(); const zAddReq = new schemaTypes.ZAddRequest(); const refReq = new schemaTypes.ReferenceRequest(); if (kv !== undefined && kv !== null) { const { key, value } = kv; keyValue.setKey(key); keyValue.setValue(value); } if (zadd !== undefined && zadd !== null) { const { set, score, key, attx, boundref } = zadd; zAddReq.setSet(set); zAddReq.setScore(score); zAddReq.setKey(key); zAddReq.setAttx(attx); zAddReq.setBoundref(boundref); } if (ref !== undefined && ref !== null) { const { key, referencedkey, attx, boundref } = ref; refReq.setKey(key); refReq.setReferencedkey(referencedkey); refReq.setAttx(attx); refReq.setBoundref(boundref); } op.setKv(keyValue); op.setZadd(zAddReq); op.setRef(refReq); return op; }); req.setOperationsList(opl); return new Promise((resolve, reject) => this.client.execAll(req, this._metadata, (err, res) => { if (err) { console.error('execeAll error', err); reject(err); } else { resolve({ id: res.getId(), prevalh: util.getAlh(res), ts: res.getTs(), nentries: res.getNentries(), eh: res.getEh(), bltxid: res.getBltxid(), blroot: res.getBlroot(), }); } })); } catch (err) { console.error(err); } } async getAll({ keysList, sincetx }) { try { const req = new schemaTypes.KeyListRequest(); const encodedKeys = keysList.map(util.utf8Encode); req.setKeysList(encodedKeys); req.setSincetx(sincetx); return new Promise((resolve, reject) => this.client.getAll(req, this._metadata, (err, res) => { if (err) { console.error('Get all error', err); reject(err); } const entriesList = res.getEntriesList(); const result = entriesList.reduce((entries, entry) => entries.concat({ tx: entry.getTx(), key: util.utf8Decode(entry.getKey()), value: util.utf8Decode(entry.getValue()), }), []); resolve({ entriesList: result }); })); } catch (err) { console.error(err); } } async verifiedSet({ key, value }) { try { const state = await this.state.get({ databaseName: this._activeDatabase, serverName: this._serverUUID, metadata: this._metadata }); const txid = state.getTxid(); const txhash = state.getTxhash_asU8(); const req = new schemaTypes.VerifiableSetRequest(); const kv = new schemaTypes.KeyValue(); const setRequest = new schemaTypes.SetRequest(); const uint8Key = util.utf8Encode(key); const uint8Value = util.utf8Encode(value); kv.setKey(uint8Key); kv.setValue(uint8Value); setRequest.setKvsList([kv]); req.setProvesincetx(txid); req.setSetrequest(setRequest); return new Promise((resolve, reject) => this.client.verifiableSet(req, this._metadata, async (err, res) => { if (err) { console.error('verifiedSet error', err); reject(err); } else { const verifiableTx = res.getTx(); if (verifiableTx === undefined) { console.error('Error getting verifiableTx from verifiedSet response'); reject(); } else { const tx = tx_1.txFrom(verifiableTx); const inclusionProof = tx_1.proofTx(tx, util.prefixKey(uint8Key)); if (inclusionProof === undefined) { console.error('Error getting inclusionProof for verifiedSet'); reject(); } else { const eKv = util.encodeKeyValue(uint8Key, uint8Value); let verifies = verification_1.verifyInclusion(inclusionProof, util.digestKeyValue(eKv), tx.htree.root); if (!verifies) { console.error('verifiedSet inclusion verification failed', err); reject(err); } const dualProof = res.getDualproof(); if (!dualProof) { } else { const tTxMetadata = dualProof.getTargettxmetadata(); const sTxMetadata = dualProof.getSourcetxmetadata(); if (!tTxMetadata || !sTxMetadata) { } else { if (!util.equalArray(tx.htree.root, tTxMetadata.getEh_asU8())) { console.error('verifiedSet error'); } let sourceId; let sourceAlh; if (txid === 0) { sourceId = tx.id; sourceAlh = util.getAlh(sTxMetadata); } else { sourceId = txid; sourceAlh = txhash; } const targetId = tx.id; const targetAlh = util.getAlh(tTxMetadata); verifies = verification_1.verifyDualProof(dualProof, sourceId, targetId, sourceAlh, targetAlh); if (!verifies) { console.error('verifiedSet dual verification failed', err); reject(err); } this.state.set({ serverName: this._serverUUID, databaseName: this._activeDatabase }, { db: this._activeDatabase, txid: targetId, txhash: targetAlh, signature: res.getSignature()?.toObject() }); resolve(tTxMetadata.toObject()); } } } } } })); } catch (err) { console.error(err); } } async verifiedGet({ key, attx, sincetx }) { try { const state = await this.state.get({ databaseName: this._activeDatabase, serverName: this._serverUUID, metadata: this._metadata }); const txid = state.getTxid(); const txhash = state.getTxhash_asU8(); const req = new schemaTypes.VerifiableGetRequest(); const kr = new schemaTypes.KeyRequest(); const uint8Key = util.utf8Encode(key); kr.setKey(uint8Key); if (attx !== undefined) { kr.setAttx(attx); } if (sincetx !== undefined) { kr.setSincetx(sincetx); } req.setKeyrequest(kr); req.setProvesincetx(txid); return new Promise((resolve, reject) => this.client.verifiableGet(req, this._metadata, async (err, res) => { if (err) { console.error(err); reject(err); } else { const inclusionproof = res.getInclusionproof(); const verifiabletx = res.getVerifiabletx(); const entry = res.getEntry(); if (!inclusionproof || !verifiabletx || !entry) { console.error('Server verifiedGet error'); reject(); } else { const referencedby = entry.getReferencedby(); let vTx; let kv = new schemaTypes.KeyValue(); if (referencedby === undefined) { vTx = entry.getTx(); kv.setKey(util.prefixKey(uint8Key)); kv.setValue(util.prefixValue(entry.getValue_asU8())); } else { const encRefKey = referencedby.getKey_asU8(); const atTx = referencedby.getAttx(); const entryKey = entry.getKey_asU8(); vTx = referencedby.getTx(); kv.setKey(util.prefixKey(encRefKey)); kv.setValue(util.encodeReferenceValue(entryKey, atTx)); } const dualproof = verifiabletx.getDualproof(); if (dualproof === undefined) { console.error('Server verifiedGet error'); reject(); } else { const targettxmetadata = dualproof.getTargettxmetadata(); const sourcetxmetadata = dualproof.getSourcetxmetadata(); if (targettxmetadata === undefined || sourcetxmetadata === undefined) { console.error('Server verifiedGet error'); reject(); } else { let eh; let sourceId; let sourceAlh; let targetId; let targetAlh; if (txid <= vTx) { const tPrevalh = util.getAlh(targettxmetadata); eh = targettxmetadata.getEh_asU8(); sourceId = txid; sourceAlh = txhash; targetId = vTx; targetAlh = tPrevalh; } else { const sPrevalh = util.getAlh(sourcetxmetadata);