immudb-node
Version:
Node.js SDK for immudb written in TypeScript
1,124 lines (1,123 loc) • 63.2 kB
JavaScript
"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);