bltjs
Version:
A BigchainDB Load Tester
226 lines (225 loc) • 11.8 kB
JavaScript
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const driver = __importStar(require("bigchaindb-driver"));
const bip39 = __importStar(require("bip39"));
const NodeInfo_1 = require("./NodeInfo");
exports.NodeInfo = NodeInfo_1.NodeInfo;
const ApiInfo_1 = require("./ApiInfo");
exports.ApiInfo = ApiInfo_1.ApiInfo;
const BltAsset_1 = require("./BltAsset");
exports.BltAsset = BltAsset_1.BltAsset;
const BltMetadata_1 = require("./BltMetadata");
exports.BltMetadata = BltMetadata_1.BltMetadata;
const TestResult_1 = require("./TestResult");
exports.TestResult = TestResult_1.TestResult;
const axios_1 = __importDefault(require("axios"));
/**
* Blt (BigchainDB Load Tester) is the main class which we use to execute functionality in regards to the bigchaindb node/cluster we connected to.
*/
class Blt {
/**
* Initialize a new Blt instance.
*
* @constructor
* @param {string} connection_protocol - The protocol to connect to the node. (e.g. "https")
* @param {string} node_host - The host of the node to connect to. (e.g. "test.bigchaindb.com")
* @param {string} [node_port = ""] - The port of the node.
* @param {string} [api_path = "/api/v1/"] - The path to the API.
* @param {string} [api_id = ""] - The ID of the application.
* @param {string} [api_key = ""] - The Key of the application.
*/
constructor(connection_protocol, node_host, node_port = "", api_path = "/api/v1/", app_id = "", app_key = "") {
this.connection_protocol = connection_protocol;
this.node_host = node_host;
this.node_port = node_port;
this.api_path = api_path;
this.app_id = app_id;
this.app_key = app_key;
this.keySeed = "Blt";
if (connection_protocol == undefined)
throw new Error("Connection protocol is undefined.");
if (node_host == undefined)
throw new Error("Node host is undefined.");
if (this.app_id === "" || this.app_key === "") {
this.connection = new driver.Connection(this.api_url);
}
else {
this.connection = new driver.Connection(this.api_url, {
app_id: this.app_id,
app_key: this.app_key
});
}
}
/**
* Return the keypair that will be used by Blt to sign transactions.
*
* @returns {any} The keypair generated with the Bltjs keySeed.
*/
get bltIdentity() {
return this.generateKeyPair(this.keySeed);
}
/**
* Generate an Ed25519 keypair by using supplied seed.
*
* @param {string} keySeed - The string to be used as seed.
* @returns {any} The generated keypair.
*/
generateKeyPair(keySeed) {
return new driver.Ed25519Keypair(bip39.mnemonicToSeed(keySeed).slice(0, 32));
}
/**
* Get the root url of the node. (e.g. https://test.bigchaindb.com)
*
* @returns {string} The root url of the node.
*/
get root_url() {
return this.connection_protocol + "://" + this.node_host + ":" + this.node_port;
}
/**
* Get the url of the api. (e.g. "https://test.bigchaindb.com/api/v1/")
*
* @returns {string} The api url.
*/
get api_url() {
return this.root_url + this.api_path;
}
/**
* Retrieve the Node information (from the node url and node api url).
*
* @returns {Promise<NodeInfo>} The nodes information encapsulated in a NodeInfo object.
*/
getNodeInformation() {
return new Promise((resolve, reject) => {
axios_1.default.get(this.root_url).then(response => {
let returnedNodeInfo = NodeInfo_1.NodeInfo.copyConstructor(response.data);
resolve(returnedNodeInfo);
}).catch(error => {
reject(new Error(error));
});
});
}
/**
* Send a supplied amount of CREATE transactions to the BigchainDB node.
*
* @param {string} testId - The ID or name of the test.
* @param {number} [amount = 100] - The amount of transactions to be posted to the BigchainDB network.
* @param {any} [onTransactionIssued = () => {}] - A callback function that can be supplied which gets called each time a transaction is issued.
*
* @returns {Promise<TestResult>} A promise that will resolve the TestResult for this test.
*/
testCreateTransactions(testId, amount = 100, onTransactionIssued = () => { }) {
let startTime = new Date();
let transactions = new Array();
let transactionPromises = new Array();
for (let transactionIndex = 0; transactionIndex < amount; transactionIndex++) {
let newTransaction = this.generateCreateTransaction(testId, transactionIndex);
transactions.push(newTransaction);
let transactionPromise = this.connection.postTransactionCommit(newTransaction);
transactionPromises.push(transactionPromise);
transactionPromise.then(response => {
onTransactionIssued(testId, newTransaction, response, transactionIndex);
});
}
return new Promise((resolve, reject) => {
Promise.all(transactionPromises).then(responses => {
let endTime = new Date();
let newTestResult = new TestResult_1.TestResult(testId, transactions, responses, startTime, endTime);
resolve(newTestResult);
}).catch(error => {
reject(error);
});
});
}
/**
* Create a chain of a supplied amount of TRANSFER transactions.
*
* @param {string} testId - The ID or name of the test.
* @param {number} [amount = 100] - The amount of transactions to be issued.
* @param {any} [onTransactionIssued = () => {}] - A callback function that can be supplied which gets called each time a transaction is issued.
*
* @returns {Promise<TestResult>} A promise that will resolve the TestResult for this test.
*/
testTransferTransactions(testId, amount = 100, onTransactionIssued = () => { }) {
let startTime = new Date();
let transactions = new Array();
let responses = new Array();
let transactionIndex = 0;
let newCreateTransaction = this.generateCreateTransaction(testId);
transactions.push(newCreateTransaction);
return this.connection.postTransactionCommit(newCreateTransaction).then(response => {
onTransactionIssued(testId, newCreateTransaction, response, transactionIndex);
responses.push(response);
return this.connection.getTransaction(response.id);
}).then(latestTransaction => {
return this.issueTransferTransactionRecursively(testId, latestTransaction, amount, ++transactionIndex, transactions, responses, startTime, onTransactionIssued);
});
}
/**
* Chain TRANSER transactions recusrively, because loops don't play nice with promises.
*
* @param {string} testId - The name/ID of the test. Will also be used as seed for the keypairs to be used in the test-transactions.
* @param {any} previousTransaction - The transaction that should be transferred.
* @param {number} amound - The amount of times the transaction should be transferred in total.
* @param {number} transactionIndex - The index of this transaction relative to the total amount of transactions that need to be issued in this test.
* @param {Array<any>} transactions - The array where all issued transactions will be stored.
* @param {Array<any>} responses - The array where all the responses will be stored.
* @param {Date} startTime - The timestamp indicating the start of the test.
* @param {any} [onTransactionIssued = () => {}] - A callback function that can be supplied which gets called each time a transaction is issued.
*
* @returns {Promise<TestResult>} A promise that will resolve the TestResult for this test.
*/
issueTransferTransactionRecursively(testId, previousTransaction, amount, transactionIndex, transactions, responses, startTime, onTransactionIssued = () => { }) {
// Check if we've reached the amount of transactions we wanted.
if (transactionIndex === amount) {
return new Promise((resolve, reject) => {
resolve(new TestResult_1.TestResult(testId, transactions, responses, startTime, new Date()));
});
}
let newTransaction = this.generateTransferTransaction(testId, previousTransaction, transactionIndex);
transactions.push(newTransaction);
return this.connection.postTransactionCommit(newTransaction).then(response => {
onTransactionIssued(testId, newTransaction, response, transactionIndex);
responses.push(response);
return this.connection.getTransaction(response.id);
}).then(latestTransaction => {
return this.issueTransferTransactionRecursively(testId, latestTransaction, amount, ++transactionIndex, transactions, responses, startTime, onTransactionIssued);
});
}
/**
* Create a CREATE transaction with a new BltAsset as asset.
*
* @param {string} testId - The name/ID of the test. Will also be used as seed for the keypairs to be used in the test-transactions.
* @param {number} [transferTransactionIndex = 0] - The index of this transaction relative to the total amount of transactions that need to be issued in this test.
*
* @returns {any} The newly created CREATE transaction.
*/
generateCreateTransaction(testId, transactionIndex = 0) {
const newTransaction = driver.Transaction.makeCreateTransaction(new BltAsset_1.BltAsset(testId, transactionIndex), null, [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(this.generateKeyPair(testId).publicKey))
], this.generateKeyPair(testId).publicKey);
return driver.Transaction.signTransaction(newTransaction, this.generateKeyPair(testId).privateKey);
}
/**
* Create a TRANSFER transaction for a certain BltAsset with supplied ID.
*
* @param {string} testId - The name/ID of the test. Will also be used as seed for the keypairs to be used in the test-transactions.
* @param {any} previousTransaction - The transaction that should be transferred on.
* @param {number} [transferTransactionIndex = 0] - The index of this transaction relative to the total amount of transactions that need to be issued in this test.
*
* @returns {any} the newly created TRANSFER transaction.
*/
generateTransferTransaction(testId, previousTransaction, transferTransactionIndex = 0) {
const newTransferTransaction = driver.Transaction.makeTransferTransaction([{ tx: previousTransaction, output_index: 0 }], [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(this.generateKeyPair(testId).publicKey))], new BltMetadata_1.BltMetadata(transferTransactionIndex));
return driver.Transaction.signTransaction(newTransferTransaction, this.generateKeyPair(testId).privateKey);
}
}
exports.Blt = Blt;