moving to mongodb storage

This commit is contained in:
harpagon210 2019-06-03 18:36:11 -05:00
parent 43d54bbff0
commit db1e554d37
17 changed files with 1555 additions and 447 deletions

View File

@ -1,3 +1,4 @@
services: mongodb
language: node_js language: node_js
node_js: node_js:
- "10.5" - "10.5"

View File

@ -1,6 +1,8 @@
{ {
"chainId": "00000000000000000002", "chainId": "mainnet1",
"rpcNodePort": 5000, "rpcNodePort": 5000,
"databaseURL": "mongodb://localhost:27017",
"databaseName": "ssc",
"dataDirectory": "./data/", "dataDirectory": "./data/",
"databaseFileName": "database.db", "databaseFileName": "database.db",
"blocksLogFilePath": "./blocks.log", "blocksLogFilePath": "./blocks.log",
@ -12,6 +14,6 @@
"https://rpc.steemviz.com", "https://rpc.steemviz.com",
"https://steemd.minnowsupportproject.org" "https://steemd.minnowsupportproject.org"
], ],
"startSteemBlock": 29056257, "startSteemBlock": 29864752,
"genesisSteemBlock": 29056257 "genesisSteemBlock": 29862600
} }

View File

@ -80,7 +80,6 @@ class Block {
for (let i = 0; i < nbTransactions; i += 1) { for (let i = 0; i < nbTransactions; i += 1) {
const transaction = this.transactions[i]; const transaction = this.transactions[i];
await this.processTransaction(ipc, jsVMTimeout, transaction, currentDatabaseHash); // eslint-disable-line await this.processTransaction(ipc, jsVMTimeout, transaction, currentDatabaseHash); // eslint-disable-line
currentDatabaseHash = transaction.databaseHash; currentDatabaseHash = transaction.databaseHash;

View File

@ -1,19 +1,20 @@
const CONSTANTS = { const CONSTANTS = {
// mainnet // mainnet
/*
UTILITY_TOKEN_SYMBOL: 'ENG', UTILITY_TOKEN_SYMBOL: 'ENG',
STEEM_PEGGED_ACCOUNT: 'steem-peg', STEEM_PEGGED_ACCOUNT: 'steem-peg',
INITIAL_TOKEN_CREATION_FEE: '100', INITIAL_TOKEN_CREATION_FEE: '100',
SSC_STORE_QTY: '0.001', SSC_STORE_QTY: '0.001',
*/
// testnet // testnet
/*
UTILITY_TOKEN_SYMBOL: 'SSC', UTILITY_TOKEN_SYMBOL: 'SSC',
STEEM_PEGGED_ACCOUNT: 'steemsc', STEEM_PEGGED_ACCOUNT: 'steemsc',
INITIAL_TOKEN_CREATION_FEE: '0', INITIAL_TOKEN_CREATION_FEE: '0',
SSC_STORE_QTY: '1', SSC_STORE_QTY: '1',
*/
UTILITY_TOKEN_PRECISION: 8, UTILITY_TOKEN_PRECISION: 8,
STEEM_PEGGED_SYMBOL: 'STEEMP', STEEM_PEGGED_SYMBOL: 'STEEMP',

View File

@ -175,7 +175,7 @@ class SmartContracts {
} }
const newContract = { const newContract = {
name, _id: name,
owner: finalSender, owner: finalSender,
code: codeTemplate, code: codeTemplate,
codeHash: SHA256(codeTemplate).toString(enchex), codeHash: SHA256(codeTemplate).toString(enchex),

68
package-lock.json generated
View File

@ -261,6 +261,11 @@
"base-x": "^3.0.2" "base-x": "^3.0.2"
} }
}, },
"bson": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
"integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
},
"buffer-xor": { "buffer-xor": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
@ -1604,6 +1609,12 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
}, },
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"merge-descriptors": { "merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -1717,6 +1728,26 @@
} }
} }
}, },
"mongodb": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.6.tgz",
"integrity": "sha512-qnHc4tjEkHKemuzBq9R7ycYnhFE0Dlpt6+n6suoZp2DcDdqviQ+teloJU24fsOw/PLmr75yGk4mRx/YabjDQEQ==",
"requires": {
"mongodb-core": "3.2.6",
"safe-buffer": "^5.1.2"
}
},
"mongodb-core": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.6.tgz",
"integrity": "sha512-i+XRVjur9D0ywGF7cFebOUnALnbvMHajdNhhl3TQuopW6QDE655G8CpPeERbqSqfa3rOKEUo08lENDIiBIuAvQ==",
"requires": {
"bson": "^1.1.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
}
},
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@ -2133,6 +2164,22 @@
"integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
"dev": true "dev": true
}, },
"require_optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
"requires": {
"resolve-from": "^2.0.0",
"semver": "^5.1.0"
},
"dependencies": {
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
}
}
},
"resolve": { "resolve": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
@ -2220,6 +2267,15 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"secp256k1": { "secp256k1": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.2.tgz", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.2.tgz",
@ -2243,8 +2299,7 @@
"semver": { "semver": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
"dev": true
}, },
"send": { "send": {
"version": "0.16.2", "version": "0.16.2",
@ -2345,6 +2400,15 @@
"is-fullwidth-code-point": "^2.0.0" "is-fullwidth-code-point": "^2.0.0"
} }
}, },
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
}
},
"spdx-correct": { "spdx-correct": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",

View File

@ -25,6 +25,7 @@
"js-base64": "^2.5.1", "js-base64": "^2.5.1",
"line-by-line": "^0.1.6", "line-by-line": "^0.1.6",
"lokijs": "^1.5.6", "lokijs": "^1.5.6",
"mongodb": "^3.2.6",
"node-cleanup": "^2.1.2", "node-cleanup": "^2.1.2",
"read-last-lines": "^1.6.0", "read-last-lines": "^1.6.0",
"seedrandom": "^3.0.1", "seedrandom": "^3.0.1",

View File

@ -1,9 +1,8 @@
const fs = require('fs-extra'); /* eslint-disable no-await-in-loop */
const Loki = require('lokijs');
const SHA256 = require('crypto-js/sha256'); const SHA256 = require('crypto-js/sha256');
const enchex = require('crypto-js/enc-hex'); const enchex = require('crypto-js/enc-hex');
const validator = require('validator'); const validator = require('validator');
const lfsa = require('../libs/loki-fs-structured-adapter'); const { MongoClient } = require('mongodb');
const { IPC } = require('../libs/IPC'); const { IPC } = require('../libs/IPC');
const BC_PLUGIN_NAME = require('./Blockchain.constants').PLUGIN_NAME; const BC_PLUGIN_NAME = require('./Blockchain.constants').PLUGIN_NAME;
@ -22,61 +21,75 @@ let chain = null;
let saving = false; let saving = false;
let databaseHash = ''; let databaseHash = '';
const initSequence = async (name, startID = 1) => {
const sequences = database.collection('sequences');
await sequences.insertOne({ _id: name, seq: startID });
};
const getNextSequence = async (name) => {
const sequences = database.collection('sequences');
const sequence = await sequences.findOneAndUpdate(
{ _id: name }, { $inc: { seq: 1 } }, { new: true },
);
return sequence.value.seq;
};
const getLastSequence = async (name) => {
const sequences = database.collection('sequences');
const sequence = await sequences.findOne({ _id: name });
return sequence.seq;
};
const getCollection = async name => new Promise((resolve) => {
database.collection(name, { strict: true }, (err, collection) => {
// collection does not exist
if (err) {
resolve(null);
}
resolve(collection);
});
});
// load the database from the filesystem // load the database from the filesystem
async function init(conf, callback) { const init = async (conf, callback) => {
const { const {
autosaveInterval, databaseURL,
databaseFileName, databaseName,
dataDirectory,
} = conf; } = conf;
const databaseFilePath = dataDirectory + databaseFileName;
// init the database // init the database
database = new Loki(databaseFilePath, { const client = await MongoClient.connect(databaseURL, { useNewUrlParser: true });
adapter: new lfsa(), // eslint-disable-line new-cap database = await client.db(databaseName);
autosave: autosaveInterval > 0, // await database.dropDatabase();
autosaveInterval, // return
}); // get the chain collection and init the chain if not done yet
// check if the app has already be run const coll = await getCollection('chain');
if (fs.pathExistsSync(databaseFilePath)) {
// load the database from the filesystem to the RAM
database.loadDatabase({}, (errorDb) => {
if (errorDb) {
callback(errorDb);
}
// if the chain or the contracts collection doesn't exist we return an error if (coll === null) {
chain = database.getCollection('chain'); await initSequence('chain', 0);
const contracts = database.getCollection('contracts'); chain = await database.createCollection('chain');
if (chain === null || contracts === null) {
callback('The database is missing either the chain or the contracts table');
}
callback(null); await database.createCollection('transactions');
}); await database.createCollection('contracts');
} else { } else {
// create the data directory if necessary and empty it if files exists chain = coll;
fs.emptyDirSync(dataDirectory);
// init the main tables
chain = database.addCollection('chain', { indices: ['blockNumber'], disableMeta: true });
database.addCollection('transactions', { unique: ['txid'], disableMeta: true });
database.addCollection('contracts', { indices: ['name'], disableMeta: true });
callback(null);
} }
} callback(null);
};
async function generateGenesisBlock(conf, callback) { const generateGenesisBlock = async (conf, callback) => {
const { const {
chainId, chainId,
genesisSteemBlock, genesisSteemBlock,
} = conf; } = conf;
// check if genesis block hasn't been generated already // check if genesis block hasn't been generated already
const genBlock = actions.getBlockInfo(0); let genBlock = await actions.getBlockInfo(0);
if (!genBlock) { if (!genBlock) {
// insert the genesis block // insert the genesis block
@ -90,55 +103,49 @@ async function generateGenesisBlock(conf, callback) {
}, },
}, },
); );
chain.insert(res.payload); genBlock = res.payload;
// initialize the block production tools genBlock._id = await getNextSequence('chain'); // eslint-disable-line no-underscore-dangle
// BlockProduction.initialize(database, genesisSteemBlock);
await chain.insertOne(genBlock);
} }
callback(); callback();
} };
// save the blockchain as well as the database on the filesystem // save the blockchain as well as the database on the filesystem
actions.save = (callback) => { actions.save = (callback) => {
saving = true; saving = true;
// save the database from the RAM to the filesystem saving = false;
database.saveDatabase((err) => { callback(null);
saving = false;
if (err) {
callback(err);
}
callback(null);
});
}; };
// save the blockchain as well as the database on the filesystem // save the blockchain as well as the database on the filesystem
function stop(callback) { const stop = (callback) => {
actions.save(callback); actions.save(callback);
} };
function addTransactions(block) { const addTransactions = async (block) => {
const transactionsTable = database.getCollection('transactions'); const transactionsTable = database.collection('transactions');
const { transactions } = block; const { transactions } = block;
const nbTransactions = transactions.length; const nbTransactions = transactions.length;
for (let index = 0; index < nbTransactions; index += 1) { for (let index = 0; index < nbTransactions; index += 1) {
const transaction = transactions[index]; const transaction = transactions[index];
const transactionToSave = { const transactionToSave = {
txid: transaction.transactionId, _id: transaction.transactionId,
blockNumber: block.blockNumber, blockNumber: block.blockNumber,
index, index,
}; };
transactionsTable.insert(transactionToSave); await transactionsTable.insertOne(transactionToSave); // eslint-disable-line no-await-in-loop
} }
} };
function updateTableHash(contract, table, record) { const updateTableHash = async (contract, table, record) => {
const contracts = database.getCollection('contracts'); const contracts = database.collection('contracts');
const contractInDb = contracts.findOne({ name: contract }); const contractInDb = await contracts.findOne({ _id: contract });
if (contractInDb && contractInDb.tables[table] !== undefined) { if (contractInDb && contractInDb.tables[table] !== undefined) {
const recordHash = SHA256(JSON.stringify(record)).toString(enchex); const recordHash = SHA256(JSON.stringify(record)).toString(enchex);
@ -146,143 +153,192 @@ function updateTableHash(contract, table, record) {
contractInDb.tables[table].hash = SHA256(tableHash + recordHash).toString(enchex); contractInDb.tables[table].hash = SHA256(tableHash + recordHash).toString(enchex);
contracts.update(contractInDb); await contracts.updateOne({ _id: contract }, { $set: contractInDb });
databaseHash = SHA256(databaseHash + contractInDb.tables[table].hash).toString(enchex); databaseHash = SHA256(databaseHash + contractInDb.tables[table].hash).toString(enchex);
} }
}
actions.initDatabaseHash = (previousDatabaseHash) => {
databaseHash = previousDatabaseHash;
}; };
actions.getDatabaseHash = () => databaseHash; actions.initDatabaseHash = (previousDatabaseHash, callback) => {
databaseHash = previousDatabaseHash;
callback();
};
actions.getTransactionInfo = (txid) => { // eslint-disable-line no-unused-vars actions.getDatabaseHash = (payload, callback) => {
const transactionsTable = database.getCollection('transactions'); callback(databaseHash);
};
const transaction = transactionsTable.findOne({ txid }); actions.getTransactionInfo = async (txid, callback) => {
const transactionsTable = database.collection('transactions');
const transaction = await transactionsTable.findOne({ _id: txid });
let result = null;
if (transaction) { if (transaction) {
const { index, blockNumber } = transaction; const { index, blockNumber } = transaction;
const block = actions.getBlockInfo(blockNumber); const block = await actions.getBlockInfo(blockNumber);
if (block) { if (block) {
return Object.assign({}, { blockNumber }, block.transactions[index]); result = Object.assign({}, { blockNumber }, block.transactions[index]);
} }
} }
return null; callback(result);
}; };
actions.addBlock = (block) => { // eslint-disable-line no-unused-vars actions.addBlock = async (block, callback) => {
chain.insert(block); const finalBlock = block;
addTransactions(block); finalBlock._id = await getNextSequence('chain'); // eslint-disable-line no-underscore-dangle
await chain.insertOne(finalBlock);
await addTransactions(finalBlock);
callback();
}; };
actions.getLatestBlockInfo = () => { // eslint-disable-line no-unused-vars actions.getLatestBlockInfo = async (payload, callback) => {
const { maxId } = chain; const _idNewBlock = await getLastSequence('chain'); // eslint-disable-line no-underscore-dangle
return chain.get(maxId);
const lastestBlock = await chain.findOne({ _id: _idNewBlock - 1 });
callback(lastestBlock);
}; };
actions.getBlockInfo = blockNumber => chain.findOne({ blockNumber }); actions.getBlockInfo = async (blockNumber, callback) => {
const block = await chain.findOne({ _id: blockNumber });
if (callback) {
callback(block);
}
return block;
};
/** /**
* Get the information of a contract (owner, source code, etc...) * Get the information of a contract (owner, source code, etc...)
* @param {String} contract name of the contract * @param {String} contract name of the contract
* @returns {Object} returns the contract info if it exists, null otherwise * @returns {Object} returns the contract info if it exists, null otherwise
*/ */
actions.findContract = (payload) => { actions.findContract = async (payload, callback) => {
const { name } = payload; const { name } = payload;
if (name && typeof name === 'string') { if (name && typeof name === 'string') {
const contracts = database.getCollection('contracts'); const contracts = database.collection('contracts');
const contractInDb = contracts.findOne({ name });
const contractInDb = await contracts.findOne({ _id: name });
if (contractInDb) { if (contractInDb) {
if (callback) {
callback(contractInDb);
}
return contractInDb; return contractInDb;
} }
} }
if (callback) {
callback(null);
}
return null; return null;
}; };
/** /**
* add a smart contract to the database * add a smart contract to the database
* @param {String} name name of the contract * @param {String} _id _id of the contract
* @param {String} owner owner of the contract * @param {String} owner owner of the contract
* @param {String} code code of the contract * @param {String} code code of the contract
* @param {String} tables tables linked to the contract * @param {String} tables tables linked to the contract
*/ */
actions.addContract = (payload) => { // eslint-disable-line no-unused-vars actions.addContract = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { const {
name, _id,
owner, owner,
code, code,
tables, tables,
} = payload; } = payload;
if (name && typeof name === 'string' if (_id && typeof _id === 'string'
&& owner && typeof owner === 'string' && owner && typeof owner === 'string'
&& code && typeof code === 'string' && code && typeof code === 'string'
&& tables && typeof tables === 'object') { && tables && typeof tables === 'object') {
const contracts = database.getCollection('contracts'); const contracts = database.collection('contracts');
contracts.insert(payload); await contracts.insertOne(payload);
} }
callback();
}; };
/** /**
* update a smart contract in the database * update a smart contract in the database
* @param {String} name name of the contract * @param {String} _id _id of the contract
* @param {String} owner owner of the contract * @param {String} owner owner of the contract
* @param {String} code code of the contract * @param {String} code code of the contract
* @param {String} tables tables linked to the contract * @param {String} tables tables linked to the contract
*/ */
actions.updateContract = (payload) => { // eslint-disable-line no-unused-vars
actions.updateContract = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { const {
name, _id,
owner, owner,
code, code,
tables, tables,
} = payload; } = payload;
if (name && typeof name === 'string' if (_id && typeof _id === 'string'
&& owner && typeof owner === 'string' && owner && typeof owner === 'string'
&& code && typeof code === 'string' && code && typeof code === 'string'
&& tables && typeof tables === 'object') { && tables && typeof tables === 'object') {
const contracts = database.getCollection('contracts'); const contracts = database.collection('contracts');
if (contracts.findOne({ name, owner }) !== null) { if (contracts.findOne({ _id, owner }) !== null) {
contracts.update(payload); await contracts.updateOne({ _id }, { $set: payload });
} }
} }
callback();
}; };
/** /**
* Add a table to the database * Add a table to the database
* @param {String} contractName name of the contract * @param {String} contractName name of the contract
* @param {String} tableName name of the table * @param {String} tableName name of the table
* @param {Array} indexes array of string containing the name of the indexes to create * @param {Array} indexes array of string containing the name of the indexes to create
*/ */
actions.createTable = (payload) => { // eslint-disable-line no-unused-vars actions.createTable = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { contractName, tableName, indexes } = payload; const { contractName, tableName, indexes } = payload;
let result = false;
// check that the params are correct // check that the params are correct
// each element of the indexes array have to be a string if defined // each element of the indexes array have to be a string if defined
if (validator.isAlphanumeric(tableName) if (validator.isAlphanumeric(tableName)
&& Array.isArray(indexes) && Array.isArray(indexes)
&& (indexes.length === 0 && (indexes.length === 0
|| (indexes.length > 0 && indexes.every(el => typeof el === 'string' && validator.isAlphanumeric(el))))) { || (indexes.length > 0 && indexes.every(el => typeof el === 'string' && validator.isAlphanumeric(el))))) {
const finalTableName = `${contractName}_${tableName}`; const finalTableName = `${contractName}_${tableName}`;
// get the table from the database // get the table from the database
const table = database.getCollection(finalTableName); let table = await getCollection(finalTableName);
if (table === null) { if (table === null) {
// if it doesn't exist, create it (with the binary indexes) // if it doesn't exist, create it (with the binary indexes)
database.addCollection(finalTableName, { indices: indexes, disableMeta: true }); await initSequence(finalTableName);
return true; await database.createCollection(finalTableName);
table = database.collection(finalTableName);
if (indexes.length > 0) {
const nbIndexes = indexes.length;
for (let i = 0; i < nbIndexes; i += 1) {
const index = indexes[i];
const finalIndex = {};
finalIndex[index] = 1;
await table.createIndex(finalIndex);
}
}
result = true;
} }
} }
return false; callback(result);
}; };
/** /**
@ -328,10 +384,10 @@ actions.find = (payload) => { // eslint-disable-line no-unused-vars
if (tableData) { if (tableData) {
// if there is an index passed, check if it exists // if there is an index passed, check if it exists
if (ind.length > 0 && ind.every(el => tableData.binaryIndices[el.index] !== undefined || el.index === '$loki')) { if (ind.length > 0 && ind.every(el => tableData.binaryIndices[el.index] !== undefined || el.index === '$loki' || el.index === '_id')) {
return tableData.chain() return tableData.chain()
.find(query) .find(query)
.compoundsort(ind.map(el => [el.index, el.descending])) .compoundsort(ind.map(el => [el.index === '$loki' ? '_id' : el.index, el.descending]))
.offset(off) .offset(off)
.limit(lim) .limit(lim)
.data(); .data();
@ -351,6 +407,65 @@ actions.find = (payload) => { // eslint-disable-line no-unused-vars
} }
}; };
/**
* retrieve records from the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {JSON} query query to perform on the table
* @param {Integer} limit limit the number of records to retrieve
* @param {Integer} offset offset applied to the records set
* @param {Array<Object>} indexes array of index definitions { index: string, descending: boolean }
* @returns {Array<Object>} returns an array of objects if records found, an empty array otherwise
*/
actions.find = async (payload, callback) => {
try {
const {
contract,
table,
query,
limit,
offset,
indexes,
} = payload;
const lim = limit || 1000;
const off = offset || 0;
const ind = indexes || [];
let result = null;
if (contract && typeof contract === 'string'
&& table && typeof table === 'string'
&& query && typeof query === 'object'
&& JSON.stringify(query).indexOf('$regex') === -1
&& Array.isArray(ind)
&& (ind.length === 0
|| (ind.length > 0
&& ind.every(el => el.index && typeof el.index === 'string'
&& el.descending !== undefined && typeof el.descending === 'boolean')))
&& Number.isInteger(lim)
&& Number.isInteger(off)
&& lim > 0 && lim <= 1000
&& off >= 0) {
const finalTableName = `${contract}_${table}`;
const tableData = await getCollection(finalTableName);
if (tableData) {
// if there is an index passed, check if it exists
// TODO: check index exists
result = await tableData.find(query, {
limit: lim,
skip: off,
sort: ind.map(el => [el.index, el.descending === true ? 'desc' : 'asc']),
}).toArray();
}
}
callback(result);
} catch (error) {
callback(null);
}
};
/** /**
* retrieve a record from the table of a contract * retrieve a record from the table of a contract
* @param {String} contract contract name * @param {String} contract contract name
@ -358,23 +473,25 @@ actions.find = (payload) => { // eslint-disable-line no-unused-vars
* @param {JSON} query query to perform on the table * @param {JSON} query query to perform on the table
* @returns {Object} returns a record if it exists, null otherwise * @returns {Object} returns a record if it exists, null otherwise
*/ */
actions.findOne = (payload) => { // eslint-disable-line no-unused-vars actions.findOne = async (payload, callback) => { // eslint-disable-line no-unused-vars
try { try {
const { contract, table, query } = payload; const { contract, table, query } = payload;
let result = null;
if (contract && typeof contract === 'string' if (contract && typeof contract === 'string'
&& table && typeof table === 'string' && table && typeof table === 'string'
&& query && typeof query === 'object' && query && typeof query === 'object'
&& JSON.stringify(query).indexOf('$regex') === -1) { && JSON.stringify(query).indexOf('$regex') === -1) {
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
const tableData = database.getCollection(finalTableName); const tableData = await getCollection(finalTableName);
return tableData ? tableData.findOne(query) : null; if (tableData) {
result = await tableData.findOne(query);
}
} }
return null; callback(result);
} catch (error) { } catch (error) {
return null; callback(null);
} }
}; };
@ -384,20 +501,23 @@ actions.findOne = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to save in the table * @param {String} record record to save in the table
*/ */
actions.insert = (payload) => { // eslint-disable-line no-unused-vars actions.insert = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { contract, table, record } = payload; const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
let finalRecord = null;
const contractInDb = actions.findContract({ name: contract }); const contractInDb = await actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) { if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName); const tableInDb = await getCollection(finalTableName);
if (tableInDb) { if (tableInDb) {
const result = tableInDb.insert(record); finalRecord = record;
updateTableHash(contract, finalTableName, result); finalRecord._id = await getNextSequence(finalTableName); // eslint-disable-line
return result; await tableInDb.insertOne(finalRecord);
await updateTableHash(contract, finalTableName, finalRecord);
} }
} }
return null;
callback(finalRecord);
}; };
/** /**
@ -406,16 +526,18 @@ actions.insert = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to remove from the table * @param {String} record record to remove from the table
*/ */
actions.remove = (payload) => { // eslint-disable-line no-unused-vars actions.remove = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { contract, table, record } = payload; const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract }); const contractInDb = await actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) { if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName); const tableInDb = await getCollection(finalTableName);
if (tableInDb) { if (tableInDb) {
updateTableHash(contract, finalTableName, record); await updateTableHash(contract, finalTableName, record);
tableInDb.remove(record); tableInDb.deleteOne({ _id: record._id }); // eslint-disable-line no-underscore-dangle
callback();
} }
} }
}; };
@ -426,18 +548,21 @@ actions.remove = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to update in the table * @param {String} record record to update in the table
*/ */
actions.update = (payload) => { // eslint-disable-line no-unused-vars actions.update = async (payload, callback) => {
const { contract, table, record } = payload; const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract }); const contractInDb = await actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) { if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName); const tableInDb = await getCollection(finalTableName);
if (tableInDb) { if (tableInDb) {
updateTableHash(contract, finalTableName, record); await updateTableHash(contract, finalTableName, record);
tableInDb.update(record);
tableInDb.updateOne({ _id: record._id }, { $set: record }); // eslint-disable-line
} }
} }
callback();
}; };
/** /**
@ -447,18 +572,20 @@ actions.update = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} record record to update in the table * @param {String} record record to update in the table
* @returns {Object} returns the table details if it exists, null otherwise * @returns {Object} returns the table details if it exists, null otherwise
*/ */
actions.getTableDetails = (payload) => { // eslint-disable-line no-unused-vars actions.getTableDetails = async (payload, callback) => {
const { contract, table } = payload; const { contract, table } = payload;
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract }); const contractInDb = await actions.findContract({ name: contract });
let tableDetails = null;
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) { if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName); const tableInDb = await getCollection(finalTableName);
if (tableInDb) { if (tableInDb) {
return { ...tableInDb, data: [] }; tableDetails = Object.assign({}, contractInDb.tables[finalTableName]);
tableDetails.indexes = await tableInDb.indexInformation();
} }
} }
return null; callback(tableDetails);
}; };
/** /**
@ -467,18 +594,19 @@ actions.getTableDetails = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @returns {Object} returns true if the table exists, false otherwise * @returns {Object} returns true if the table exists, false otherwise
*/ */
actions.tableExists = (payload) => { // eslint-disable-line no-unused-vars actions.tableExists = async (payload, callback) => {
const { contract, table } = payload; const { contract, table } = payload;
const finalTableName = `${contract}_${table}`; const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract }); let result = false;
const contractInDb = await actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) { if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName); const tableInDb = await getCollection(finalTableName);
if (tableInDb) { if (tableInDb) {
return true; result = true;
} }
} }
return false; callback(result);
}; };
/** /**
@ -490,7 +618,7 @@ actions.tableExists = (payload) => { // eslint-disable-line no-unused-vars
* @param {Array<Object>} indexes array of index definitions { index: string, descending: boolean } * @param {Array<Object>} indexes array of index definitions { index: string, descending: boolean }
* @returns {Array<Object>} returns an array of objects if records found, an empty array otherwise * @returns {Array<Object>} returns an array of objects if records found, an empty array otherwise
*/ */
actions.dfind = (payload) => { // eslint-disable-line no-unused-vars actions.dfind = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { const {
table, table,
query, query,
@ -503,27 +631,18 @@ actions.dfind = (payload) => { // eslint-disable-line no-unused-vars
const off = offset || 0; const off = offset || 0;
const ind = indexes || []; const ind = indexes || [];
const tableData = database.getCollection(table); const tableInDb = await getCollection(table);
let records = [];
if (tableData) { if (tableInDb) {
// if there is an index passed, check if it exists records = await tableInDb.find(query, {
if (ind.length > 0) { limit: lim,
return tableData.chain() skip: off,
.find(query) sort: ind.map(el => [el.index, el.descending === true ? 'desc' : 'asc']),
.compoundsort(ind.map(el => [el.index, el.descending])) });
.offset(off)
.limit(lim)
.data();
}
return tableData.chain()
.find(query)
.offset(off)
.limit(lim)
.data();
} }
return []; callback(records);
}; };
/** /**
@ -532,15 +651,17 @@ actions.dfind = (payload) => { // eslint-disable-line no-unused-vars
* @param {JSON} query query to perform on the table * @param {JSON} query query to perform on the table
* @returns {Object} returns a record if it exists, null otherwise * @returns {Object} returns a record if it exists, null otherwise
*/ */
actions.dfindOne = (payload) => { // eslint-disable-line no-unused-vars actions.dfindOne = async (payload, callback) => {
const { table, query } = payload; const { table, query } = payload;
const tableData = database.getCollection(table); const tableInDb = await getCollection(table);
if (tableData) { let record = null;
return tableData.findOne(query);
if (tableInDb) {
record = await tableInDb.findOne(query);
} }
return null; callback(record);
}; };
/** /**
@ -548,11 +669,15 @@ actions.dfindOne = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to save in the table * @param {String} record record to save in the table
*/ */
actions.dinsert = (payload) => { // eslint-disable-line no-unused-vars actions.dinsert = async (payload, callback) => {
const { table, record } = payload; const { table, record } = payload;
const tableInDb = database.getCollection(table); const tableInDb = database.collection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record); const finalRecord = record;
return tableInDb.insert(record); finalRecord._id = await getNextSequence(table); // eslint-disable-line
await tableInDb.insertOne(finalRecord);
await updateTableHash(table.split('_')[0], table.split('_')[1], record);
callback(finalRecord);
}; };
/** /**
@ -560,12 +685,16 @@ actions.dinsert = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to update in the table * @param {String} record record to update in the table
*/ */
actions.dupdate = (payload) => { // eslint-disable-line no-unused-vars actions.dupdate = async (payload, callback) => {
const { table, record } = payload; const { table, record } = payload;
const tableInDb = database.getCollection(table); const tableInDb = database.collection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record); await updateTableHash(table.split('_')[0], table.split('_')[1], record);
tableInDb.update(record); await tableInDb.updateOne(
{ _id: record._id }, { $set: record }, // eslint-disable-line no-underscore-dangle
);
callback();
}; };
/** /**
@ -573,12 +702,14 @@ actions.dupdate = (payload) => { // eslint-disable-line no-unused-vars
* @param {String} table table name * @param {String} table table name
* @param {String} record record to remove from the table * @param {String} record record to remove from the table
*/ */
actions.dremove = (payload) => { // eslint-disable-line no-unused-vars actions.dremove = async (payload, callback) => { // eslint-disable-line no-unused-vars
const { table, record } = payload; const { table, record } = payload;
const tableInDb = database.getCollection(table); const tableInDb = database.collection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record); await updateTableHash(table.split('_')[0], table.split('_')[1], record);
tableInDb.remove(record); await tableInDb.deleteOne({ _id: record._id }); // eslint-disable-line no-underscore-dangle
callback();
}; };
ipc.onReceiveMessage((message) => { ipc.onReceiveMessage((message) => {
@ -609,9 +740,10 @@ ipc.onReceiveMessage((message) => {
}); });
} else if (action && typeof actions[action] === 'function') { } else if (action && typeof actions[action] === 'function') {
if (!saving) { if (!saving) {
const res = actions[action](payload); actions[action](payload, (res) => {
// console.log('action', action, 'res', res, 'payload', payload); // console.log('action', action, 'res', res, 'payload', payload);
ipc.reply(message, res); ipc.reply(message, res);
});
} else { } else {
ipc.reply(message); ipc.reply(message);
} }

625
plugins/Database.loki.js Normal file
View File

@ -0,0 +1,625 @@
const fs = require('fs-extra');
const Loki = require('lokijs');
const SHA256 = require('crypto-js/sha256');
const enchex = require('crypto-js/enc-hex');
const validator = require('validator');
const lfsa = require('../libs/loki-fs-structured-adapter');
const { IPC } = require('../libs/IPC');
const BC_PLUGIN_NAME = require('./Blockchain.constants').PLUGIN_NAME;
const BC_PLUGIN_ACTIONS = require('./Blockchain.constants').PLUGIN_ACTIONS;
const { PLUGIN_NAME, PLUGIN_ACTIONS } = require('./Database.constants');
const PLUGIN_PATH = require.resolve(__filename);
const actions = {};
const ipc = new IPC(PLUGIN_NAME);
let database = null;
let chain = null;
let saving = false;
let databaseHash = '';
// load the database from the filesystem
async function init(conf, callback) {
const {
autosaveInterval,
databaseFileName,
dataDirectory,
} = conf;
const databaseFilePath = dataDirectory + databaseFileName;
// init the database
database = new Loki(databaseFilePath, {
adapter: new lfsa(), // eslint-disable-line new-cap
autosave: autosaveInterval > 0,
autosaveInterval,
});
// check if the app has already be run
if (fs.pathExistsSync(databaseFilePath)) {
// load the database from the filesystem to the RAM
database.loadDatabase({}, (errorDb) => {
if (errorDb) {
callback(errorDb);
}
// if the chain or the contracts collection doesn't exist we return an error
chain = database.getCollection('chain');
const contracts = database.getCollection('contracts');
if (chain === null || contracts === null) {
callback('The database is missing either the chain or the contracts table');
}
callback(null);
});
} else {
// create the data directory if necessary and empty it if files exists
fs.emptyDirSync(dataDirectory);
// init the main tables
chain = database.addCollection('chain', { indices: ['blockNumber'], disableMeta: true });
database.addCollection('transactions', { unique: ['txid'], disableMeta: true });
database.addCollection('contracts', { indices: ['name'], disableMeta: true });
callback(null);
}
}
async function generateGenesisBlock(conf, callback) {
const {
chainId,
genesisSteemBlock,
} = conf;
// check if genesis block hasn't been generated already
const genBlock = actions.getBlockInfo(0);
if (!genBlock) {
// insert the genesis block
const res = await ipc.send(
{
to: BC_PLUGIN_NAME,
action: BC_PLUGIN_ACTIONS.CREATE_GENESIS_BLOCK,
payload: {
chainId,
genesisSteemBlock,
},
},
);
chain.insert(res.payload);
// initialize the block production tools
// BlockProduction.initialize(database, genesisSteemBlock);
}
callback();
}
// save the blockchain as well as the database on the filesystem
actions.save = (callback) => {
saving = true;
// save the database from the RAM to the filesystem
database.saveDatabase((err) => {
saving = false;
if (err) {
callback(err);
}
callback(null);
});
};
// save the blockchain as well as the database on the filesystem
function stop(callback) {
actions.save(callback);
}
function addTransactions(block) {
const transactionsTable = database.getCollection('transactions');
const { transactions } = block;
const nbTransactions = transactions.length;
for (let index = 0; index < nbTransactions; index += 1) {
const transaction = transactions[index];
const transactionToSave = {
txid: transaction.transactionId,
blockNumber: block.blockNumber,
index,
};
transactionsTable.insert(transactionToSave);
}
}
function updateTableHash(contract, table, record) {
const contracts = database.getCollection('contracts');
const contractInDb = contracts.findOne({ name: contract });
if (contractInDb && contractInDb.tables[table] !== undefined) {
const recordHash = SHA256(JSON.stringify(record)).toString(enchex);
const tableHash = contractInDb.tables[table].hash;
contractInDb.tables[table].hash = SHA256(tableHash + recordHash).toString(enchex);
contracts.update(contractInDb);
databaseHash = SHA256(databaseHash + contractInDb.tables[table].hash).toString(enchex);
}
}
actions.initDatabaseHash = (previousDatabaseHash) => {
databaseHash = previousDatabaseHash;
};
actions.getDatabaseHash = () => databaseHash;
actions.getTransactionInfo = (txid) => { // eslint-disable-line no-unused-vars
const transactionsTable = database.getCollection('transactions');
const transaction = transactionsTable.findOne({ txid });
if (transaction) {
const { index, blockNumber } = transaction;
const block = actions.getBlockInfo(blockNumber);
if (block) {
return Object.assign({}, { blockNumber }, block.transactions[index]);
}
}
return null;
};
actions.addBlock = (block) => { // eslint-disable-line no-unused-vars
chain.insert(block);
addTransactions(block);
};
actions.getLatestBlockInfo = () => { // eslint-disable-line no-unused-vars
const { maxId } = chain;
return chain.get(maxId);
};
actions.getBlockInfo = blockNumber => chain.findOne({ blockNumber });
/**
* Get the information of a contract (owner, source code, etc...)
* @param {String} contract name of the contract
* @returns {Object} returns the contract info if it exists, null otherwise
*/
actions.findContract = (payload) => {
const { name } = payload;
if (name && typeof name === 'string') {
const contracts = database.getCollection('contracts');
const contractInDb = contracts.findOne({ name });
if (contractInDb) {
return contractInDb;
}
}
return null;
};
/**
* add a smart contract to the database
* @param {String} name name of the contract
* @param {String} owner owner of the contract
* @param {String} code code of the contract
* @param {String} tables tables linked to the contract
*/
actions.addContract = (payload) => { // eslint-disable-line no-unused-vars
const {
name,
owner,
code,
tables,
} = payload;
if (name && typeof name === 'string'
&& owner && typeof owner === 'string'
&& code && typeof code === 'string'
&& tables && typeof tables === 'object') {
const contracts = database.getCollection('contracts');
contracts.insert(payload);
}
};
/**
* update a smart contract in the database
* @param {String} name name of the contract
* @param {String} owner owner of the contract
* @param {String} code code of the contract
* @param {String} tables tables linked to the contract
*/
actions.updateContract = (payload) => { // eslint-disable-line no-unused-vars
const {
name,
owner,
code,
tables,
} = payload;
if (name && typeof name === 'string'
&& owner && typeof owner === 'string'
&& code && typeof code === 'string'
&& tables && typeof tables === 'object') {
const contracts = database.getCollection('contracts');
if (contracts.findOne({ name, owner }) !== null) {
contracts.update(payload);
}
}
};
/**
* Add a table to the database
* @param {String} contractName name of the contract
* @param {String} tableName name of the table
* @param {Array} indexes array of string containing the name of the indexes to create
*/
actions.createTable = (payload) => { // eslint-disable-line no-unused-vars
const { contractName, tableName, indexes } = payload;
// check that the params are correct
// each element of the indexes array have to be a string if defined
if (validator.isAlphanumeric(tableName)
&& Array.isArray(indexes)
&& (indexes.length === 0
|| (indexes.length > 0 && indexes.every(el => typeof el === 'string' && validator.isAlphanumeric(el))))) {
const finalTableName = `${contractName}_${tableName}`;
// get the table from the database
const table = database.getCollection(finalTableName);
if (table === null) {
// if it doesn't exist, create it (with the binary indexes)
database.addCollection(finalTableName, { indices: indexes, disableMeta: true });
return true;
}
}
return false;
};
/**
* retrieve records from the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {JSON} query query to perform on the table
* @param {Integer} limit limit the number of records to retrieve
* @param {Integer} offset offset applied to the records set
* @param {Array<Object>} indexes array of index definitions { index: string, descending: boolean }
* @returns {Array<Object>} returns an array of objects if records found, an empty array otherwise
*/
actions.find = (payload) => { // eslint-disable-line no-unused-vars
try {
const {
contract,
table,
query,
limit,
offset,
indexes,
} = payload;
const lim = limit || 1000;
const off = offset || 0;
const ind = indexes || [];
if (contract && typeof contract === 'string'
&& table && typeof table === 'string'
&& query && typeof query === 'object'
&& JSON.stringify(query).indexOf('$regex') === -1
&& Array.isArray(ind)
&& (ind.length === 0
|| (ind.length > 0
&& ind.every(el => el.index && typeof el.index === 'string'
&& el.descending !== undefined && typeof el.descending === 'boolean')))
&& Number.isInteger(lim)
&& Number.isInteger(off)
&& lim > 0 && lim <= 1000
&& off >= 0) {
const finalTableName = `${contract}_${table}`;
const tableData = database.getCollection(finalTableName);
if (tableData) {
// if there is an index passed, check if it exists
if (ind.length > 0 && ind.every(el => tableData.binaryIndices[el.index] !== undefined || el.index === '$loki')) {
return tableData.chain()
.find(query)
.compoundsort(ind.map(el => [el.index, el.descending]))
.offset(off)
.limit(lim)
.data();
}
return tableData.chain()
.find(query)
.offset(off)
.limit(lim)
.data();
}
}
return null;
} catch (error) {
return null;
}
};
/**
* retrieve a record from the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {JSON} query query to perform on the table
* @returns {Object} returns a record if it exists, null otherwise
*/
actions.findOne = (payload) => { // eslint-disable-line no-unused-vars
try {
const { contract, table, query } = payload;
if (contract && typeof contract === 'string'
&& table && typeof table === 'string'
&& query && typeof query === 'object'
&& JSON.stringify(query).indexOf('$regex') === -1) {
const finalTableName = `${contract}_${table}`;
const tableData = database.getCollection(finalTableName);
return tableData ? tableData.findOne(query) : null;
}
return null;
} catch (error) {
return null;
}
};
/**
* insert a record in the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {String} record record to save in the table
*/
actions.insert = (payload) => { // eslint-disable-line no-unused-vars
const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName);
if (tableInDb) {
const result = tableInDb.insert(record);
updateTableHash(contract, finalTableName, result);
return result;
}
}
return null;
};
/**
* remove a record in the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {String} record record to remove from the table
*/
actions.remove = (payload) => { // eslint-disable-line no-unused-vars
const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName);
if (tableInDb) {
updateTableHash(contract, finalTableName, record);
tableInDb.remove(record);
}
}
};
/**
* update a record in the table of a contract
* @param {String} contract contract name
* @param {String} table table name
* @param {String} record record to update in the table
*/
actions.update = (payload) => { // eslint-disable-line no-unused-vars
const { contract, table, record } = payload;
const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName);
if (tableInDb) {
updateTableHash(contract, finalTableName, record);
tableInDb.update(record);
}
}
};
/**
* get the details of a smart contract table
* @param {String} contract contract name
* @param {String} table table name
* @param {String} record record to update in the table
* @returns {Object} returns the table details if it exists, null otherwise
*/
actions.getTableDetails = (payload) => { // eslint-disable-line no-unused-vars
const { contract, table } = payload;
const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName);
if (tableInDb) {
return { ...tableInDb, data: [] };
}
}
return null;
};
/**
* check if a table exists
* @param {String} contract contract name
* @param {String} table table name
* @returns {Object} returns true if the table exists, false otherwise
*/
actions.tableExists = (payload) => { // eslint-disable-line no-unused-vars
const { contract, table } = payload;
const finalTableName = `${contract}_${table}`;
const contractInDb = actions.findContract({ name: contract });
if (contractInDb && contractInDb.tables[finalTableName] !== undefined) {
const tableInDb = database.getCollection(finalTableName);
if (tableInDb) {
return true;
}
}
return false;
};
/**
* retrieve records from the table
* @param {String} table table name
* @param {JSON} query query to perform on the table
* @param {Integer} limit limit the number of records to retrieve
* @param {Integer} offset offset applied to the records set
* @param {Array<Object>} indexes array of index definitions { index: string, descending: boolean }
* @returns {Array<Object>} returns an array of objects if records found, an empty array otherwise
*/
actions.dfind = (payload) => { // eslint-disable-line no-unused-vars
const {
table,
query,
limit,
offset,
indexes,
} = payload;
const lim = limit || 1000;
const off = offset || 0;
const ind = indexes || [];
const tableData = database.getCollection(table);
if (tableData) {
// if there is an index passed, check if it exists
if (ind.length > 0) {
return tableData.chain()
.find(query)
.compoundsort(ind.map(el => [el.index, el.descending]))
.offset(off)
.limit(lim)
.data();
}
return tableData.chain()
.find(query)
.offset(off)
.limit(lim)
.data();
}
return [];
};
/**
* retrieve a record from the table
* @param {String} table table name
* @param {JSON} query query to perform on the table
* @returns {Object} returns a record if it exists, null otherwise
*/
actions.dfindOne = (payload) => { // eslint-disable-line no-unused-vars
const { table, query } = payload;
const tableData = database.getCollection(table);
if (tableData) {
return tableData.findOne(query);
}
return null;
};
/**
* insert a record
* @param {String} table table name
* @param {String} record record to save in the table
*/
actions.dinsert = (payload) => { // eslint-disable-line no-unused-vars
const { table, record } = payload;
const tableInDb = database.getCollection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record);
return tableInDb.insert(record);
};
/**
* update a record in the table
* @param {String} table table name
* @param {String} record record to update in the table
*/
actions.dupdate = (payload) => { // eslint-disable-line no-unused-vars
const { table, record } = payload;
const tableInDb = database.getCollection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record);
tableInDb.update(record);
};
/**
* remove a record
* @param {String} table table name
* @param {String} record record to remove from the table
*/
actions.dremove = (payload) => { // eslint-disable-line no-unused-vars
const { table, record } = payload;
const tableInDb = database.getCollection(table);
updateTableHash(table.split('_')[0], table.split('_')[1], record);
tableInDb.remove(record);
};
ipc.onReceiveMessage((message) => {
const {
action,
payload,
// from,
} = message;
if (action === 'init') {
init(payload, (res) => {
console.log('successfully initialized'); // eslint-disable-line no-console
ipc.reply(message, res);
});
} else if (action === 'stop') {
stop((res) => {
console.log('successfully saved'); // eslint-disable-line no-console
ipc.reply(message, res);
});
} else if (action === PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK) {
generateGenesisBlock(payload, () => {
ipc.reply(message);
});
} else if (action === PLUGIN_ACTIONS.SAVE) {
actions.save((res) => {
console.log('successfully saved'); // eslint-disable-line no-console
ipc.reply(message, res);
});
} else if (action && typeof actions[action] === 'function') {
if (!saving) {
const res = actions[action](payload);
// console.log('action', action, 'res', res, 'payload', payload);
ipc.reply(message, res);
} else {
ipc.reply(message);
}
} else {
ipc.reply(message);
}
});
module.exports.PLUGIN_PATH = PLUGIN_PATH;
module.exports.PLUGIN_NAME = PLUGIN_NAME;
module.exports.PLUGIN_ACTIONS = PLUGIN_ACTIONS;

15
scripts/cleanDB.sh Normal file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
read -p "Enter the mongodb container name : " containerName
read -p "Enter the database name : " database
read -p "$database is going to be dropped in the container $containerName, are you sure? " -n 1 -r
echo # (optional) move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
fi
echo "Dropping database $database in the container $containerName"
docker exec $containerName /bin/sh -c "mongo $database --eval \"db.dropDatabase()\""
echo "Done extracting blocks from $containerName"

View File

@ -1,13 +1,13 @@
/* eslint-disable */ /* eslint-disable */
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block'); const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
const { MongoClient } = require('mongodb');
//process.env.NODE_ENV = 'test'; //process.env.NODE_ENV = 'test';
@ -18,16 +18,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -96,11 +94,55 @@ const unloadPlugin = (plugin) => {
} }
// dice // dice
describe.skip('dice', () => { describe.skip('dice', function() {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('makes you win', (done) => { it('makes you win', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -140,8 +182,7 @@ describe.skip('dice', () => {
it('makes you lose', (done) => { it('makes you lose', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);

View File

@ -2,16 +2,14 @@
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const { MongoClient } = require('mongodb');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
//process.env.NODE_ENV = 'test';
const conf = { const conf = {
chainId: "test-chain-id", chainId: "test-chain-id",
genesisSteemBlock: 2000000, genesisSteemBlock: 2000000,
@ -19,16 +17,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -132,11 +128,55 @@ let mktContractPayload = {
}; };
// Market // Market
describe('Market', () => { describe('Market', function() {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('creates a buy order', (done) => { it('creates a buy order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -224,8 +264,7 @@ describe('Market', () => {
it('creates buy orders with expirations', (done) => { it('creates buy orders with expirations', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -265,11 +304,11 @@ describe('Market', () => {
const sellOrders = res.payload; const sellOrders = res.payload;
assert.equal(sellOrders[0].txId, 'TXID1237'); assert.equal(sellOrders[0].txId, 'TXID1235');
assert.equal(sellOrders[0].account, 'satoshi'); assert.equal(sellOrders[0].account, 'satoshi');
assert.equal(sellOrders[0].symbol, 'TKN'); assert.equal(sellOrders[0].symbol, 'TKN');
assert.equal(sellOrders[0].price, '0.00000001'); assert.equal(sellOrders[0].price, '0.00000001');
assert.equal(sellOrders[0].quantity, 3); assert.equal(sellOrders[0].quantity, 1);
assert.equal(sellOrders[0].timestamp, 1527811200); assert.equal(sellOrders[0].timestamp, 1527811200);
assert.equal(sellOrders[0].expiration, 1527811200 + 2592000); assert.equal(sellOrders[0].expiration, 1527811200 + 2592000);
@ -281,11 +320,11 @@ describe('Market', () => {
assert.equal(sellOrders[1].timestamp, 1527811200); assert.equal(sellOrders[1].timestamp, 1527811200);
assert.equal(sellOrders[1].expiration, 1527811200 + 10); assert.equal(sellOrders[1].expiration, 1527811200 + 10);
assert.equal(sellOrders[2].txId, 'TXID1235'); assert.equal(sellOrders[2].txId, 'TXID1237');
assert.equal(sellOrders[2].account, 'satoshi'); assert.equal(sellOrders[2].account, 'satoshi');
assert.equal(sellOrders[2].symbol, 'TKN'); assert.equal(sellOrders[2].symbol, 'TKN');
assert.equal(sellOrders[2].price, '0.00000001'); assert.equal(sellOrders[2].price, '0.00000001');
assert.equal(sellOrders[2].quantity, 1); assert.equal(sellOrders[2].quantity, 3);
assert.equal(sellOrders[2].timestamp, 1527811200); assert.equal(sellOrders[2].timestamp, 1527811200);
assert.equal(sellOrders[2].expiration, 1527811200 + 2592000); assert.equal(sellOrders[2].expiration, 1527811200 + 2592000);
@ -300,8 +339,7 @@ describe('Market', () => {
it('generates error when trying to create a buy order with wrong parameters', (done) => { it('generates error when trying to create a buy order with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -345,8 +383,7 @@ describe('Market', () => {
it('creates sell orders with expirations', (done) => { it('creates sell orders with expirations', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -386,11 +423,11 @@ describe('Market', () => {
const sellOrders = res.payload; const sellOrders = res.payload;
assert.equal(sellOrders[0].txId, 'TXID1237'); assert.equal(sellOrders[0].txId, 'TXID1235');
assert.equal(sellOrders[0].account, 'satoshi'); assert.equal(sellOrders[0].account, 'satoshi');
assert.equal(sellOrders[0].symbol, 'TKN'); assert.equal(sellOrders[0].symbol, 'TKN');
assert.equal(sellOrders[0].price, '0.00000001'); assert.equal(sellOrders[0].price, '0.00000001');
assert.equal(sellOrders[0].quantity, 3); assert.equal(sellOrders[0].quantity, 1);
assert.equal(sellOrders[0].timestamp, 1527811200); assert.equal(sellOrders[0].timestamp, 1527811200);
assert.equal(sellOrders[0].expiration, 1527811200 + 2592000); assert.equal(sellOrders[0].expiration, 1527811200 + 2592000);
@ -402,11 +439,11 @@ describe('Market', () => {
assert.equal(sellOrders[1].timestamp, 1527811200); assert.equal(sellOrders[1].timestamp, 1527811200);
assert.equal(sellOrders[1].expiration, 1527811200 + 10); assert.equal(sellOrders[1].expiration, 1527811200 + 10);
assert.equal(sellOrders[2].txId, 'TXID1235'); assert.equal(sellOrders[2].txId, 'TXID1237');
assert.equal(sellOrders[2].account, 'satoshi'); assert.equal(sellOrders[2].account, 'satoshi');
assert.equal(sellOrders[2].symbol, 'TKN'); assert.equal(sellOrders[2].symbol, 'TKN');
assert.equal(sellOrders[2].price, '0.00000001'); assert.equal(sellOrders[2].price, '0.00000001');
assert.equal(sellOrders[2].quantity, 1); assert.equal(sellOrders[2].quantity, 3);
assert.equal(sellOrders[2].timestamp, 1527811200); assert.equal(sellOrders[2].timestamp, 1527811200);
assert.equal(sellOrders[2].expiration, 1527811200 + 2592000); assert.equal(sellOrders[2].expiration, 1527811200 + 2592000);
@ -421,8 +458,7 @@ describe('Market', () => {
it('creates a sell order', (done) => { it('creates a sell order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -510,8 +546,7 @@ describe('Market', () => {
it('generates error when trying to create a sell order with wrong parameters', (done) => { it('generates error when trying to create a sell order with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -556,8 +591,7 @@ describe('Market', () => {
it('cancels a buy order', (done) => { it('cancels a buy order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -692,8 +726,7 @@ describe('Market', () => {
it('cancels a sell order', (done) => { it('cancels a sell order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -831,8 +864,7 @@ describe('Market', () => {
it('buys from the market from one seller', (done) => { it('buys from the market from one seller', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -871,6 +903,7 @@ describe('Market', () => {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -936,8 +969,7 @@ describe('Market', () => {
it('buys from the market from several sellers', (done) => { it('buys from the market from several sellers', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -980,6 +1012,7 @@ describe('Market', () => {
}); });
const balances = res.payload; const balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'harpagon'); assert.equal(balances[0].account, 'harpagon');
assert.equal(balances[0].symbol, 'STEEMP'); assert.equal(balances[0].symbol, 'STEEMP');
@ -1024,8 +1057,7 @@ describe('Market', () => {
it('buys from the market partially', (done) => { it('buys from the market partially', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1068,6 +1100,7 @@ describe('Market', () => {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'harpagon'); assert.equal(balances[0].account, 'harpagon');
assert.equal(balances[0].symbol, 'STEEMP'); assert.equal(balances[0].symbol, 'STEEMP');
@ -1150,8 +1183,7 @@ describe('Market', () => {
it('sells on the market to one buyer', (done) => { it('sells on the market to one buyer', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1193,6 +1225,7 @@ describe('Market', () => {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -1258,8 +1291,7 @@ describe('Market', () => {
it('sells on the market to several buyers', (done) => { it('sells on the market to several buyers', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1306,6 +1338,7 @@ describe('Market', () => {
}); });
const balances = res.payload; const balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'harpagon'); assert.equal(balances[0].account, 'harpagon');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -1350,8 +1383,7 @@ describe('Market', () => {
it('fills a buy order from different sellers', (done) => { it('fills a buy order from different sellers', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1398,6 +1430,7 @@ describe('Market', () => {
}); });
const balances = res.payload; const balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'harpagon'); assert.equal(balances[0].account, 'harpagon');
assert.equal(balances[0].symbol, 'STEEMP'); assert.equal(balances[0].symbol, 'STEEMP');
@ -1442,8 +1475,7 @@ describe('Market', () => {
it('creates a trade history', (done) => { it('creates a trade history', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1632,8 +1664,7 @@ describe('Market', () => {
it('maintains the different metrics', (done) => { it('maintains the different metrics', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1819,8 +1850,7 @@ describe('Market', () => {
it('removes an expired sell order', (done) => { it('removes an expired sell order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1926,8 +1956,7 @@ describe('Market', () => {
it('removes an expired buy order', (done) => { it('removes an expired buy order', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -2032,8 +2061,7 @@ describe('Market', () => {
it('removes dust sell orders', (done) => { it('removes dust sell orders', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -2072,6 +2100,7 @@ describe('Market', () => {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -2149,6 +2178,7 @@ describe('Market', () => {
}); });
balances = res.payload; balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -2210,8 +2240,7 @@ describe('Market', () => {
it('removes dust buy orders', (done) => { it('removes dust buy orders', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -2253,6 +2282,7 @@ describe('Market', () => {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
@ -2330,6 +2360,7 @@ describe('Market', () => {
}); });
balances = res.payload; balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].account, 'vitalik'); assert.equal(balances[0].account, 'vitalik');
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');

View File

@ -2,18 +2,15 @@
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const BigNumber = require('bignumber.js'); const { MongoClient } = require('mongodb');
const { Base64 } = require('js-base64'); const { Base64 } = require('js-base64');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
//process.env.NODE_ENV = 'test';
const conf = { const conf = {
chainId: "test-chain-id", chainId: "test-chain-id",
genesisSteemBlock: 2000000, genesisSteemBlock: 2000000,
@ -21,16 +18,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -117,10 +112,52 @@ let contractPayload = {
describe('smart tokens', function () { describe('smart tokens', function () {
this.timeout(30000); this.timeout(30000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('should enable delegation', (done) => { it('should enable delegation', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -174,8 +211,7 @@ describe('smart tokens', function () {
it('should not enable delegation', (done) => { it('should not enable delegation', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -228,8 +264,7 @@ describe('smart tokens', function () {
it('should delegate tokens', (done) => { it('should delegate tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -334,6 +369,7 @@ describe('smart tokens', function () {
}); });
balances = res.payload; balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
assert.equal(balances[0].account, 'satoshi'); assert.equal(balances[0].account, 'satoshi');
@ -369,12 +405,12 @@ describe('smart tokens', function () {
assert.equal(delegations[0].symbol, 'TKN'); assert.equal(delegations[0].symbol, 'TKN');
assert.equal(delegations[0].from, 'satoshi'); assert.equal(delegations[0].from, 'satoshi');
assert.equal(delegations[0].to, 'ned'); assert.equal(delegations[0].to, 'vitalik');
assert.equal(delegations[0].quantity, '0.00000002'); assert.equal(delegations[0].quantity, '0.00000002');
assert.equal(delegations[1].symbol, 'TKN'); assert.equal(delegations[1].symbol, 'TKN');
assert.equal(delegations[1].from, 'satoshi'); assert.equal(delegations[1].from, 'satoshi');
assert.equal(delegations[1].to, 'vitalik'); assert.equal(delegations[1].to, 'ned');
assert.equal(delegations[1].quantity, '0.00000002'); assert.equal(delegations[1].quantity, '0.00000002');
resolve(); resolve();
@ -388,8 +424,7 @@ describe('smart tokens', function () {
it('should not delegate tokens', (done) => { it('should not delegate tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -491,8 +526,7 @@ describe('smart tokens', function () {
it('should undelegate tokens', (done) => { it('should undelegate tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -534,6 +568,8 @@ describe('smart tokens', function () {
}); });
let balances = res.payload; let balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
assert.equal(balances[0].account, 'satoshi'); assert.equal(balances[0].account, 'satoshi');
assert.equal(balances[0].balance, "99.99999997"); assert.equal(balances[0].balance, "99.99999997");
@ -569,13 +605,13 @@ describe('smart tokens', function () {
assert.equal(delegations[0].symbol, 'TKN'); assert.equal(delegations[0].symbol, 'TKN');
assert.equal(delegations[0].from, 'satoshi'); assert.equal(delegations[0].from, 'satoshi');
assert.equal(delegations[0].to, 'ned'); assert.equal(delegations[0].to, 'vitalik');
assert.equal(delegations[0].quantity, '0.00000001'); assert.equal(delegations[0].quantity, '0.00000002');
assert.equal(delegations[1].symbol, 'TKN'); assert.equal(delegations[1].symbol, 'TKN');
assert.equal(delegations[1].from, 'satoshi'); assert.equal(delegations[1].from, 'satoshi');
assert.equal(delegations[1].to, 'vitalik'); assert.equal(delegations[1].to, 'ned');
assert.equal(delegations[1].quantity, '0.00000002'); assert.equal(delegations[1].quantity, '0.00000001');
transactions = []; transactions = [];
transactions.push(new Transaction(12345678901, 'TXID1242', 'satoshi', 'tokens', 'undelegate', '{ "symbol": "TKN", "quantity": "0.00000001", "to": "vitalik", "isSignedWithActiveKey": true }')); transactions.push(new Transaction(12345678901, 'TXID1242', 'satoshi', 'tokens', 'undelegate', '{ "symbol": "TKN", "quantity": "0.00000001", "to": "vitalik", "isSignedWithActiveKey": true }'));
@ -605,6 +641,7 @@ describe('smart tokens', function () {
}); });
balances = res.payload; balances = res.payload;
balances.sort((a, b) => a._id - b._id);
assert.equal(balances[0].symbol, 'TKN'); assert.equal(balances[0].symbol, 'TKN');
assert.equal(balances[0].account, 'satoshi'); assert.equal(balances[0].account, 'satoshi');
@ -682,8 +719,7 @@ describe('smart tokens', function () {
it('should not undelegate tokens', (done) => { it('should not undelegate tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -751,8 +787,7 @@ describe('smart tokens', function () {
it('should process the pending undelegations', (done) => { it('should process the pending undelegations', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -870,8 +905,7 @@ describe('smart tokens', function () {
it('should enable staking', (done) => { it('should enable staking', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -922,8 +956,7 @@ describe('smart tokens', function () {
it('should not enable staking', (done) => { it('should not enable staking', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -988,8 +1021,7 @@ describe('smart tokens', function () {
it('should not enable staking again', (done) => { it('should not enable staking again', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1050,8 +1082,7 @@ describe('smart tokens', function () {
it('should stake tokens', (done) => { it('should stake tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1180,8 +1211,7 @@ describe('smart tokens', function () {
it('should not stake tokens', (done) => { it('should not stake tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1252,8 +1282,7 @@ describe('smart tokens', function () {
it('should start the unstake process', (done) => { it('should start the unstake process', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1363,8 +1392,7 @@ describe('smart tokens', function () {
it('should not start the unstake process', (done) => { it('should not start the unstake process', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1433,8 +1461,7 @@ describe('smart tokens', function () {
it('should cancel an unstake', (done) => { it('should cancel an unstake', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1592,8 +1619,7 @@ describe('smart tokens', function () {
it('should not cancel an unstake', (done) => { it('should not cancel an unstake', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1757,8 +1783,7 @@ describe('smart tokens', function () {
it('should process the pending unstakes', (done) => { it('should process the pending unstakes', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1962,8 +1987,7 @@ describe('smart tokens', function () {
it.skip('should process thousands of pending unstakes', (done) => { it.skip('should process thousands of pending unstakes', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -2236,8 +2260,7 @@ describe('smart tokens', function () {
it('should process the pending unstakes (with multi transactions)', (done) => { it('should process the pending unstakes (with multi transactions)', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);

View File

@ -2,17 +2,14 @@
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const BigNumber = require('bignumber.js'); const { MongoClient } = require('mongodb');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
//process.env.NODE_ENV = 'test';
const conf = { const conf = {
chainId: "test-chain-id", chainId: "test-chain-id",
genesisSteemBlock: 2000000, genesisSteemBlock: 2000000,
@ -20,16 +17,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -98,12 +93,55 @@ const unloadPlugin = (plugin) => {
} }
// sscstore // sscstore
describe('sscstore smart contract', () => { describe('sscstore smart contract', function() {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('should buy tokens', (done) => { it('should buy tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -149,8 +187,7 @@ describe('sscstore smart contract', () => {
it('should not buy tokens', (done) => { it('should not buy tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -227,8 +264,7 @@ describe('sscstore smart contract', () => {
it('should update params', (done) => { it('should update params', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -275,8 +311,7 @@ describe('sscstore smart contract', () => {
it('should not update params', (done) => { it('should not update params', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);

View File

@ -2,10 +2,10 @@
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const { MongoClient } = require('mongodb');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
@ -19,16 +19,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -122,11 +120,55 @@ let spContractPayload = {
}; };
// STEEMP // STEEMP
describe('Steem Pegged', () => { describe('Steem Pegged', function () {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('buys STEEMP', (done) => { it('buys STEEMP', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -182,8 +224,7 @@ describe('Steem Pegged', () => {
it('withdraws STEEM', (done) => { it('withdraws STEEM', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -290,8 +331,7 @@ describe('Steem Pegged', () => {
it('does not withdraw STEEM', (done) => { it('does not withdraw STEEM', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);

View File

@ -2,15 +2,13 @@
const { fork } = require('child_process'); const { fork } = require('child_process');
const assert = require('assert'); const assert = require('assert');
const { Base64 } = require('js-base64'); const { Base64 } = require('js-base64');
const fs = require('fs-extra'); const { MongoClient } = require('mongodb');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block'); const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
//process.env.NODE_ENV = 'test';
const conf = { const conf = {
chainId: "test-chain-id", chainId: "test-chain-id",
genesisSteemBlock: 2000000, genesisSteemBlock: 2000000,
@ -18,16 +16,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -96,12 +92,56 @@ const unloadPlugin = (plugin) => {
} }
// Database // Database
describe('Database', () => { describe('Database', function () {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('should get the genesis block', (done) => { it('should get the genesis block', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -119,8 +159,7 @@ describe('Database', () => {
it('should get the latest block', (done) => { it('should get the latest block', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -168,11 +207,55 @@ describe('Database', () => {
}); });
// smart contracts // smart contracts
describe('Smart Contracts', () => { describe('Smart Contracts', function () {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('should deploy a basic smart contract', (done) => { it('should deploy a basic smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -207,7 +290,7 @@ describe('Smart Contracts', () => {
const res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND_CONTRACT, payload: { name: 'testContract' } }); const res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND_CONTRACT, payload: { name: 'testContract' } });
const contract = res.payload; const contract = res.payload;
assert.equal(contract.name, 'testContract'); assert.equal(contract._id, 'testContract');
assert.equal(contract.owner, 'steemsc'); assert.equal(contract.owner, 'steemsc');
resolve() resolve()
}) })
@ -220,8 +303,7 @@ describe('Smart Contracts', () => {
it('should create a table during the smart contract deployment', (done) => { it('should create a table during the smart contract deployment', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -258,11 +340,10 @@ describe('Smart Contracts', () => {
const contract = res.payload; const contract = res.payload;
assert.notEqual(contract.tables['testContract_testTable'], undefined); assert.notEqual(contract.tables['testContract_testTable'], undefined);
res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GET_TABLE_DETAILS, payload: { contract: 'testContract', table: 'testTable' } }); res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GET_TABLE_DETAILS, payload: { contract: 'testContract', table: 'testTable' } });
assert.notEqual(res.payload, null); assert.notEqual(res.payload, null);
resolve(); resolve();
}) })
.then(() => { .then(() => {
@ -274,8 +355,7 @@ describe('Smart Contracts', () => {
it('should create a table with indexes during the smart contract deployment', (done) => { it('should create a table with indexes during the smart contract deployment', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -310,10 +390,17 @@ describe('Smart Contracts', () => {
const res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GET_TABLE_DETAILS, payload: { contract: 'testContract', table: 'testTable' } }); const res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GET_TABLE_DETAILS, payload: { contract: 'testContract', table: 'testTable' } });
const table = res.payload; const table = res.payload;
const { binaryIndices } = table; const { indexes } = table;
assert.equal(indexes._id_[0][0], '_id');
assert.equal(indexes._id_[0][1], 1);
assert.equal(indexes.index1_1[0][0], 'index1');
assert.equal(indexes.index1_1[0][1], 1);
assert.equal(indexes.index2_1[0][0], 'index2');
assert.equal(indexes.index2_1[0][1], 1);
assert.notEqual(binaryIndices['index1'], undefined);
assert.notEqual(binaryIndices['index2'], undefined);
resolve(); resolve();
}) })
.then(() => { .then(() => {
@ -325,8 +412,7 @@ describe('Smart Contracts', () => {
it('should add a record into a smart contract table', (done) => { it('should add a record into a smart contract table', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -385,8 +471,7 @@ describe('Smart Contracts', () => {
it('should update a record from a smart contract table', (done) => { it('should update a record from a smart contract table', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -458,8 +543,7 @@ describe('Smart Contracts', () => {
it('should remove a record from a smart contract table', (done) => { it('should remove a record from a smart contract table', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -526,8 +610,7 @@ describe('Smart Contracts', () => {
it('should read the records from a smart contract table via pagination', (done) => { it('should read the records from a smart contract table via pagination', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -590,8 +673,8 @@ describe('Smart Contracts', () => {
let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
let users = res.payload; let users = res.payload;
assert.equal(users[0].$loki, 1); assert.equal(users[0]._id, 1);
assert.equal(users[4].$loki, 5); assert.equal(users[4]._id, 5);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -604,8 +687,8 @@ describe('Smart Contracts', () => {
res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
users = res.payload; users = res.payload;
assert.equal(users[0].$loki, 6); assert.equal(users[0]._id, 6);
assert.equal(users[4].$loki, 10); assert.equal(users[4]._id, 10);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -631,8 +714,7 @@ describe('Smart Contracts', () => {
it('should read the records from a smart contract table using an index ascending', (done) => { it('should read the records from a smart contract table using an index ascending', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -699,8 +781,8 @@ describe('Smart Contracts', () => {
let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
let users = res.payload; let users = res.payload;
assert.equal(users[0].$loki, 6); assert.equal(users[0]._id, 6);
assert.equal(users[4].$loki, 2); assert.equal(users[4]._id, 2);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -714,8 +796,8 @@ describe('Smart Contracts', () => {
res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
users = res.payload; users = res.payload;
assert.equal(users[0].$loki, 10); assert.equal(users[0]._id, 10);
assert.equal(users[4].$loki, 5); assert.equal(users[4]._id, 5);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -742,8 +824,7 @@ describe('Smart Contracts', () => {
it('should read the records from a smart contract table using an index descending', (done) => { it('should read the records from a smart contract table using an index descending', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -809,8 +890,8 @@ describe('Smart Contracts', () => {
let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); let res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
let users = res.payload; let users = res.payload;
assert.equal(users[0].$loki, 5); assert.equal(users[0]._id, 5);
assert.equal(users[4].$loki, 10); assert.equal(users[4]._id, 10);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -824,8 +905,8 @@ describe('Smart Contracts', () => {
res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload }); res = await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.FIND, payload });
users = res.payload; users = res.payload;
assert.equal(users[0].$loki, 2); assert.equal(users[0]._id, 2);
assert.equal(users[4].$loki, 6); assert.equal(users[4]._id, 6);
payload = { payload = {
contract: 'usersContract', contract: 'usersContract',
@ -852,8 +933,7 @@ describe('Smart Contracts', () => {
it('should allow only the owner of the smart contract to perform certain actions', (done) => { it('should allow only the owner of the smart contract to perform certain actions', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -934,8 +1014,7 @@ describe('Smart Contracts', () => {
it('should perform a search in a smart contract table from another smart contract', (done) => { it('should perform a search in a smart contract table from another smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1027,8 +1106,7 @@ describe('Smart Contracts', () => {
it('should execute a smart contract from another smart contract', (done) => { it('should execute a smart contract from another smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1120,8 +1198,7 @@ describe('Smart Contracts', () => {
it('should emit an event from a smart contract', (done) => { it('should emit an event from a smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1176,8 +1253,7 @@ describe('Smart Contracts', () => {
it('should emit an event from another smart contract', (done) => { it('should emit an event from another smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1255,8 +1331,7 @@ describe('Smart Contracts', () => {
it('should log an error during the deployment of a smart contract if an error is thrown', (done) => { it('should log an error during the deployment of a smart contract if an error is thrown', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1310,8 +1385,7 @@ describe('Smart Contracts', () => {
it('should log an error during the execution of a smart contract if an error is thrown', (done) => { it('should log an error during the execution of a smart contract if an error is thrown', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1368,8 +1442,7 @@ describe('Smart Contracts', () => {
it('should log an error from another smart contract', (done) => { it('should log an error from another smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1445,8 +1518,7 @@ describe('Smart Contracts', () => {
it('should generate random numbers in a deterministic way', (done) => { it('should generate random numbers in a deterministic way', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });
@ -1538,8 +1610,7 @@ describe('Smart Contracts', () => {
it('should update a smart contract', (done) => { it('should update a smart contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf }); await send(database.PLUGIN_NAME, 'MASTER', { action: database.PLUGIN_ACTIONS.GENERATE_GENESIS_BLOCK, payload: conf });

View File

@ -4,10 +4,11 @@ const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const { Base64 } = require('js-base64'); const { Base64 } = require('js-base64');
const { MongoClient } = require('mongodb');
const database = require('../plugins/Database'); const database = require('../plugins/Database');
const blockchain = require('../plugins/Blockchain'); const blockchain = require('../plugins/Blockchain');
const { Block } = require('../libs/Block');
const { Transaction } = require('../libs/Transaction'); const { Transaction } = require('../libs/Transaction');
const { CONSTANTS } = require('../libs/Constants'); const { CONSTANTS } = require('../libs/Constants');
@ -21,16 +22,14 @@ const conf = {
databaseFileName: "database.db", databaseFileName: "database.db",
autosaveInterval: 0, autosaveInterval: 0,
javascriptVMTimeout: 10000, javascriptVMTimeout: 10000,
databaseURL: "mongodb://localhost:27017",
databaseName: "testssc",
}; };
let plugins = {}; let plugins = {};
let jobs = new Map(); let jobs = new Map();
let currentJobId = 0; let currentJobId = 0;
function cleanDataFolder() {
fs.emptyDirSync(conf.dataDirectory);
}
function send(pluginName, from, message) { function send(pluginName, from, message) {
const plugin = plugins[pluginName]; const plugin = plugins[pluginName];
const newMessage = { const newMessage = {
@ -113,11 +112,55 @@ let contractPayload = {
}; };
// tokens // tokens
describe('Tokens smart contract', () => { describe('Tokens smart contract', function () {
this.timeout(10000);
before((done) => {
new Promise(async (resolve) => {
client = await MongoClient.connect(conf.databaseURL, { useNewUrlParser: true });
db = await client.db(conf.databaseName);
await db.dropDatabase();
resolve();
})
.then(() => {
done()
})
});
after((done) => {
new Promise(async (resolve) => {
await client.close();
resolve();
})
.then(() => {
done()
})
});
beforeEach((done) => {
new Promise(async (resolve) => {
db = await client.db(conf.databaseName);
resolve();
})
.then(() => {
done()
})
});
afterEach((done) => {
// runs after each test in this block
new Promise(async (resolve) => {
await db.dropDatabase()
resolve();
})
.then(() => {
done()
})
});
it('creates a token', (done) => { it('creates a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -170,8 +213,7 @@ describe('Tokens smart contract', () => {
it('generates error when trying to create a token with wrong parameters', (done) => { it('generates error when trying to create a token with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -227,8 +269,7 @@ describe('Tokens smart contract', () => {
it('updates the url of a token', (done) => { it('updates the url of a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -289,8 +330,7 @@ describe('Tokens smart contract', () => {
it('does not update the url of a token', (done) => { it('does not update the url of a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -361,8 +401,7 @@ describe('Tokens smart contract', () => {
it('updates the metadata of a token', (done) => { it('updates the metadata of a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -425,8 +464,7 @@ describe('Tokens smart contract', () => {
it('transfers the ownership of a token', (done) => { it('transfers the ownership of a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -504,8 +542,7 @@ describe('Tokens smart contract', () => {
it('does not transfer the ownership of a token', (done) => { it('does not transfer the ownership of a token', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -593,8 +630,7 @@ describe('Tokens smart contract', () => {
it('issues tokens', (done) => { it('issues tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -660,8 +696,7 @@ describe('Tokens smart contract', () => {
it('generates error when trying to issue tokens with wrong parameters', (done) => { it('generates error when trying to issue tokens with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -716,8 +751,7 @@ describe('Tokens smart contract', () => {
it('transfers tokens', (done) => { it('transfers tokens', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -819,8 +853,7 @@ describe('Tokens smart contract', () => {
it('generates errors when trying to transfer tokens with wrong parameters', (done) => { it('generates errors when trying to transfer tokens with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -878,8 +911,7 @@ describe('Tokens smart contract', () => {
it('transfers tokens to a contract', (done) => { it('transfers tokens to a contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -972,8 +1004,7 @@ describe('Tokens smart contract', () => {
it('generates errors when trying to transfer tokens to a contract with wrong parameters', (done) => { it('generates errors when trying to transfer tokens to a contract with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1031,8 +1062,7 @@ describe('Tokens smart contract', () => {
it('transfers tokens from a contract to a user', (done) => { it('transfers tokens from a contract to a user', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1132,8 +1162,7 @@ describe('Tokens smart contract', () => {
it('generates errors when trying to transfer tokens from a contract to a user with wrong parameters', (done) => { it('generates errors when trying to transfer tokens from a contract to a user with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1233,8 +1262,7 @@ describe('Tokens smart contract', () => {
it('transfers tokens from a contract to a contract', (done) => { it('transfers tokens from a contract to a contract', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);
@ -1348,8 +1376,7 @@ describe('Tokens smart contract', () => {
it('generates errors when trying to transfer tokens from a contract to another contract with wrong parameters', (done) => { it('generates errors when trying to transfer tokens from a contract to another contract with wrong parameters', (done) => {
new Promise(async (resolve) => { new Promise(async (resolve) => {
cleanDataFolder();
await loadPlugin(database); await loadPlugin(database);
await loadPlugin(blockchain); await loadPlugin(blockchain);