From 0c6d0104b0e289ebdcc5d98b06108158362400e6 Mon Sep 17 00:00:00 2001 From: Philipp Piwo Date: Sun, 14 Nov 2021 17:19:00 +0100 Subject: [PATCH] refactor!: use calldata lib sdk, use snapshotting in tests --- package-lock.json | 65 +++++++++++++------------ package.json | 2 +- src/env/env.js | 28 +++++------ src/init/artifacts/test/exampleTests.js | 27 +++++----- src/init/init.js | 12 ++--- src/init/update-artifacts/package.json | 2 +- src/lib/index.js | 8 +-- src/lib/utils.js | 65 +++++++++++++++++++++++++ src/test/test.js | 6 +-- src/utils/fs-utils.js | 19 +++----- src/utils/utils.js | 1 - 11 files changed, 147 insertions(+), 88 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfa16ac6..1655c3b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,35 +4,44 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@aeternity/aepp-calldata": { + "version": "github:aeternity/aepp-calldata-js#4e8a07b65fbe19de60ea7f3eef5c25e45d8daea7", + "from": "github:aeternity/aepp-calldata-js#for-sdk", + "requires": { + "base64check": "^2.1.3", + "blakejs": "^1.1.0", + "bs58check": "^2.1.2", + "rlp": "^2.2.4" + } + }, "@aeternity/aepp-sdk": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@aeternity/aepp-sdk/-/aepp-sdk-9.0.1.tgz", - "integrity": "sha512-LfLH25/5S23aSV35qRJGoFMAuHO/Ti7q/bOKxcx+ItflZeui9ow3/bnRkQjmvJopf8T82kP/C+F1sT7LKL1Fzg==", + "version": "github:aeternity/aepp-sdk-js#f1e9c4f514d0a294bdd0f8a7d6f5a781a32bf3d4", + "from": "github:aeternity/aepp-sdk-js#develop", "requires": { + "@aeternity/aepp-calldata": "github:aeternity/aepp-calldata-js#for-sdk", "@aeternity/bip39": "^0.1.0", "@aeternity/json-bigint": "^0.3.1", - "@babel/runtime-corejs3": "^7.14.0", + "@babel/runtime-corejs3": "^7.15.4", "@stamp/it": "^1.1.0", "@stamp/required": "^1.0.1", "aes-js": "^3.1.2", "bignumber.js": "^9.0.1", "bip32-path": "^0.4.2", - "blakejs": "^1.1.0", + "blakejs": "^1.1.1", "bs58check": "^2.1.2", "buffer": "^6.0.3", "cross-fetch": "^3.1.4", "crypto-browserify": "^3.12.0", "ed2curve": "^0.3.0", "events": "^3.3.0", - "joi-browser": "^13.4.0", "libsodium-wrappers-sumo": "0.7.9", "path-browserify": "^1.0.1", "process": "^0.11.10", "ramda": "^0.27.1", - "rlp": "2.2.6", + "rlp": "2.2.7", "sha.js": "^2.4.11", "stream-browserify": "^3.0.0", - "swagger-client": "^3.13.5", + "swagger-client": "^3.17.0", "tweetnacl": "^1.0.3", "tweetnacl-auth": "^1.0.1", "uuid": "^8.3.2", @@ -143,9 +152,9 @@ } }, "@babel/runtime-corejs3": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.0.tgz", - "integrity": "sha512-Oi2qwQ21X7/d9gn3WiwkDTJmq3TQtYNz89lRnoFy8VeZpWlsyXvzSwiRrRZ8cXluvSwqKxqHJ6dBd9Rv+p0ZGQ==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz", + "integrity": "sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ==", "requires": { "core-js-pure": "^3.19.0", "regenerator-runtime": "^0.13.4" @@ -430,6 +439,15 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "base64check": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/base64check/-/base64check-2.1.3.tgz", + "integrity": "sha512-bXdtbzXYUWyLbJm2m89k0k2i8bVNnBI2xRsAAQPCCY65KYOg8nGCQhu7FZjmu595wyr+5K+8GyqkHhRig6gxNQ==", + "requires": { + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "bignumber.js": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", @@ -1697,16 +1715,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "joi-browser": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/joi-browser/-/joi-browser-13.4.0.tgz", - "integrity": "sha512-TfzJd2JaJ/lg/gU+q5j9rLAjnfUNF9DUmXTP9w+GfmG79LjFOXFeM7hIFuXCBcZCivUDFwd9l1btTV9rhHumtQ==" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2260,18 +2268,11 @@ } }, "rlp": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", - "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", "requires": { - "bn.js": "^4.11.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "bn.js": "^5.2.0" } }, "safe-buffer": { diff --git a/package.json b/package.json index 8e72f779..2946a8fd 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "license": "ISC", "dependencies": { - "@aeternity/aepp-sdk": "^9.0.1", + "@aeternity/aepp-sdk": "github:aeternity/aepp-sdk-js.git#develop", "axios": "^0.24.0", "commander": "^8.3.0", "promisify-child-process": "^4.1.1", diff --git a/src/env/env.js b/src/env/env.js index 14d2d941..d97f0d1f 100644 --- a/src/env/env.js +++ b/src/env/env.js @@ -1,17 +1,17 @@ -const {spawn, exec} = require("promisify-child-process"); +const { spawn, exec } = require('promisify-child-process'); -const {print, printError} = require('../utils/utils'); -const {nodeConfiguration, compilerConfiguration, proxyConfiguration} = require('../config/node-config.json'); +const { print, printError } = require('../utils/utils'); +const { nodeConfiguration, compilerConfiguration, proxyConfiguration } = require('../config/node-config.json'); async function isEnvRunning() { - const info = await getInfo() + const info = await getInfo(); if (info) { const containers = [nodeConfiguration.containerName, compilerConfiguration.containerName, proxyConfiguration.containerName]; - return containers.every(containerName => { - const line = info.split('\n').find(line => line.includes(containerName)) - return line && line.includes('Up') - }) + return containers.every((containerName) => { + const line = info.split('\n').find((line) => line.includes(containerName)); + return line && line.includes('Up'); + }); } return false; @@ -55,8 +55,8 @@ async function stopEnv(running) { async function startEnv(nodeVersion, compilerVersion) { print('===== starting env ====='); - await exec(`NODE_TAG=${nodeVersion} COMPILER_TAG=${compilerVersion} docker-compose pull`) - await exec(`NODE_TAG=${nodeVersion} COMPILER_TAG=${compilerVersion} docker-compose up -d`) + await exec(`NODE_TAG=${nodeVersion} COMPILER_TAG=${compilerVersion} docker-compose pull`); + await exec(`NODE_TAG=${nodeVersion} COMPILER_TAG=${compilerVersion} docker-compose up -d`); print('===== Env was successfully started! ====='); } @@ -70,18 +70,16 @@ async function printInfo(running) { print(await getInfo()); } - async function getInfo() { - const info = await exec(`docker-compose ps`); + const info = await exec('docker-compose ps'); if (info && info.stdout) { return info.stdout; } - return null + return null; } module.exports = { - run + run, }; - diff --git a/src/init/artifacts/test/exampleTests.js b/src/init/artifacts/test/exampleTests.js index b828ea4b..48516192 100644 --- a/src/init/artifacts/test/exampleTests.js +++ b/src/init/artifacts/test/exampleTests.js @@ -1,20 +1,14 @@ -const {assert} = require('chai'); -const {Universal, MemoryAccount, Node} = require('@aeternity/aepp-sdk'); -const {wallets, networks, utils} = require('@aeternity/aeproject'); +const { assert } = require('chai'); +const { utils } = require('@aeternity/aeproject'); const EXAMPLE_CONTRACT_SOURCE = './contracts/ExampleContract.aes'; describe('ExampleContract', () => { + let client; let contract; before(async () => { - const client = await Universal.compose({ - deepProps: {Ae: {defaults: {interval: 50}}} - })({ - nodes: [{name: 'node', instance: await Node({url: networks.devmode.nodeUrl, ignoreVersion: true})}], - compilerUrl: networks.devmode.compilerUrl, - accounts: [MemoryAccount({keypair: wallets[0]})] - }); + client = await utils.getClient(); // a filesystem object must be passed to the compiler if the contract uses custom includes const filesystem = utils.getFilesystem(EXAMPLE_CONTRACT_SOURCE); @@ -23,15 +17,20 @@ describe('ExampleContract', () => { const contract_content = utils.getContractContent(EXAMPLE_CONTRACT_SOURCE); // initialize the contract instance - contract = await client.getContractInstance(contract_content, {filesystem}); + contract = await client.getContractInstance(contract_content, { filesystem }); + await contract.deploy(); + + // create a snapshot of the blockchain state + await utils.createSnapshot(client); }); - it('deploy ExampleContract', async () => { - await contract.deploy(); + // after each test roll back to initial state + afterEach(async () => { + await utils.rollbackSnapshot(client); }); it('call ExampleContract', async () => { - const {decodedResult} = await contract.methods.example(42) + const { decodedResult } = await contract.methods.example(42); assert.equal(decodedResult, 42); }); }); diff --git a/src/init/init.js b/src/init/init.js index e6695ae1..0aefb388 100644 --- a/src/init/init.js +++ b/src/init/init.js @@ -1,9 +1,9 @@ -const {exec} = require('promisify-child-process'); +const { exec } = require('promisify-child-process'); const constants = require('./constants.json'); -const {print} = require('../utils/utils'); +const { print } = require('../utils/utils'); -const {copyFolderRecursiveSync, fileExists} = require('../utils/fs-utils'); +const { copyFolderRecursiveSync, fileExists } = require('../utils/fs-utils'); async function run(update) { if (update) { @@ -48,12 +48,12 @@ const setupArtifacts = async () => { const updateArtifacts = async () => { print('===== creating project file and directory structure ====='); - let fileSource = `${__dirname}${constants.updateArtifactsDir}`; - let destination = constants.artifactsDest; + const fileSource = `${__dirname}${constants.updateArtifactsDir}`; + const destination = constants.artifactsDest; await copyFolderRecursiveSync(fileSource, destination); }; module.exports = { - run + run, }; diff --git a/src/init/update-artifacts/package.json b/src/init/update-artifacts/package.json index 8b81fd51..9e244eab 100644 --- a/src/init/update-artifacts/package.json +++ b/src/init/update-artifacts/package.json @@ -6,7 +6,7 @@ "test": "mocha ./test/**/*.js --timeout 0 --exit" }, "dependencies": { - "@aeternity/aepp-sdk": "^9.0.1" + "@aeternity/aepp-sdk": "github:aeternity/aepp-sdk-js.git#develop" }, "devDependencies": { "@aeternity/aeproject": "^3.0.5", diff --git a/src/lib/index.js b/src/lib/index.js index c62468b7..de401203 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -3,7 +3,7 @@ const wallets = require('./wallets.json'); const utils = require('./utils'); module.exports = { - utils: utils, - networks: networks, - wallets: wallets -} + utils, + networks, + wallets, +}; diff --git a/src/lib/utils.js b/src/lib/utils.js index 7662ab96..9ca9600b 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -1,5 +1,11 @@ const fs = require('fs'); const path = require('path'); +const http = require('http'); +const { exec } = require('promisify-child-process'); +const { Universal, MemoryAccount, Node } = require('@aeternity/aepp-sdk'); + +const networks = require('./networks.json'); +const wallets = require('./wallets.json'); const getContractContent = (contractSource) => fs.readFileSync(contractSource, 'utf8'); @@ -40,7 +46,66 @@ const getFilesystem = (contractSource) => { return filesystem; }; +async function get(url) { + return new Promise((resolve, reject) => { + const req = http.request(url, { method: 'GET' }, (res) => { + if (res.statusCode < 200 || res.statusCode > 299) { + return reject(new Error(`HTTP status code ${res.statusCode}`)); + } + + const body = []; + res.on('data', (chunk) => body.push(chunk)); + res.on('end', () => resolve(Buffer.concat(body).toString())); + }); + + req.on('error', (err) => reject(err)); + + req.on('timeout', () => { + req.destroy(); + reject(new Error('Request time out')); + }); + + req.end(); + }); +} + +const getClient = async () => Universal.compose({ + deepProps: { Ae: { defaults: { interval: 50 } } }, +})({ + nodes: [{ name: 'node', instance: await Node({ url: networks.devmode.nodeUrl, ignoreVersion: true }) }], + compilerUrl: networks.devmode.compilerUrl, + accounts: [MemoryAccount({ keypair: wallets[0] })], +}); + +const awaitKeyBlocks = async (client, n = 1) => { + const height = await client.height(); + await get(`http://localhost:3001/emit_kb?n=${n}`); + await client.awaitHeight(height + n); +}; + +let snapshotHeight = -1; + +const createSnapshot = async (client) => { + snapshotHeight = await client.height(); + await awaitKeyBlocks(client, 1); +}; + +const rollbackSnapshot = async (client) => { + const currentBlockHeight = await client.height(); + if (currentBlockHeight > snapshotHeight) { + // TODO replace with http api call + const cmd = `docker exec aeproject_node bin/aeternity db_rollback --height ${snapshotHeight}`; + await exec(cmd); + await awaitKeyBlocks(client, 1); + } else { + } +}; + module.exports = { getContractContent, getFilesystem, + awaitKeyBlocks, + createSnapshot, + rollbackSnapshot, + getClient, }; diff --git a/src/test/test.js b/src/test/test.js index 46c87bce..9c154979 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -1,5 +1,5 @@ -const {print} = require("../utils/utils"); -const {exec} = require("promisify-child-process"); +const { exec } = require('promisify-child-process'); +const { print } = require('../utils/utils'); const run = async () => { const workingDirectory = process.cwd(); @@ -10,7 +10,7 @@ const run = async () => { async function test() { print('===== Starting Tests ====='); - const child = exec(`npm test`) + const child = exec('npm test'); child.stdout.on('data', (out) => process.stdout.write(out)); child.stderr.on('data', (err) => process.stderr.write(err)); diff --git a/src/utils/fs-utils.js b/src/utils/fs-utils.js index ac9d8aa6..0b54722a 100644 --- a/src/utils/fs-utils.js +++ b/src/utils/fs-utils.js @@ -10,11 +10,12 @@ async function promptOverwrite(target) { }); const input = response.value.trim(); - return input === 'YES' || input === 'yes' || input === 'Y' || input === 'y' + return input === 'YES' || input === 'yes' || input === 'Y' || input === 'y'; } async function copyFolderRecursiveSync(srcDir, dstDir) { - let src, dst; + let src; let + dst; return fs.readdirSync(srcDir).reduce(async (accPromise, file) => { await accPromise; @@ -27,15 +28,11 @@ async function copyFolderRecursiveSync(srcDir, dstDir) { fs.mkdirSync(dst); } - await copyFolderRecursiveSync(src, dst) - } else { - if (!fs.existsSync(dst)) { - fs.writeFileSync(dst, fs.readFileSync(src)); - } else { - if (await promptOverwrite(dst)) { - fs.writeFileSync(dst, fs.readFileSync(src)); - } - } + await copyFolderRecursiveSync(src, dst); + } else if (!fs.existsSync(dst)) { + fs.writeFileSync(dst, fs.readFileSync(src)); + } else if (await promptOverwrite(dst)) { + fs.writeFileSync(dst, fs.readFileSync(src)); } }, Promise.resolve()); } diff --git a/src/utils/utils.js b/src/utils/utils.js index 82ee0439..187ab98a 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,7 +1,6 @@ const config = require('../config/config.json'); const getNetwork = (network) => { - const networks = { local: { url: config.localhostParams.url,