From 750b78743fdfc6e80d4d57cd5a387d1e5a183d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ad=C3=A1n=20SDPC?= Date: Tue, 20 Sep 2022 15:31:11 +0200 Subject: [PATCH] feat(rad2sol): handle duplicated query names --- src/bin/rad2sol.js | 32 ++++++++++++++++++++---------- src/lib/rad2sol/scripts.js | 37 +++++++++++++++++++---------------- src/lib/rad2sol/steps.js | 40 +++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/bin/rad2sol.js b/src/bin/rad2sol.js index d15a295..6da211d 100755 --- a/src/bin/rad2sol.js +++ b/src/bin/rad2sol.js @@ -26,24 +26,36 @@ const writeJson = asPath(argv("write-json", "./migrations")); const schemaDir = path.resolve(__dirname, "../../assets"); const schema = loadSchema(fs, path, schemaDir, "witnet"); -const queriesNames = glob.sync(queryDir, {}).reduce((acc, queryPath) => { - if ((fs.lstatSync(queryPath)).isFile()) { - acc.push(path.resolve(queryPath)); - return acc; +function addQuery(acc, rawPath) { + let resolvedPath = path.resolve(rawPath); + let queryName = path.basename(rawPath).split('.')[0]; + + const existing = acc[queryName]; + if (existing) { + const error = Error(`Duplicated query name "${queryName}. Please rename one of the following files:\n - First occurrence at ${existing.path}\n - Found repetition at ${resolvedPath}`); + fail(error, process, true); } else { - return acc.concat(glob.sync(`${queryPath}*.js`).map(x => path.resolve(x))); + acc[queryName] = { bytecode: null, path: rawPath }; } -}, []); -const queriesList = {} +} -const script = readCompileEncodeWriteSolScript(fs, path, vm, schema, writeContracts, queriesList, queriesNames); +const queries = glob.sync(queryDir, {}).reduce((acc, rawPath) => { + if ((fs.lstatSync(rawPath)).isFile()) { + addQuery(acc, rawPath) + } else { + glob.sync(path.resolve(rawPath, "*.js")).forEach(rawPath => addQuery(acc, rawPath)); + } + return acc; +}, {}); + +const script = readCompileEncodeWriteSolScript(fs, path, vm, schema, writeContracts, queries); queriesBanner(); Promise.all(script.reduce( (prev, step) => prev.map((p, i) => p.then(v => step(v, i))), - queriesNames.map(fileName => Promise.resolve(fileName)))) + Object.values(queries).map(fileName => Promise.resolve(fileName)))) .then(() => queriesSucceed(path, writeContracts, writeJson)) - .then(() => { if (writeJson !== Utils.Disabled) { writeQueriesToJson(fs, path, queriesList, writeJson) } }) + .then(() => { if (writeJson !== Utils.Disabled) { writeQueriesToJson(fs, path, queries, writeJson) } }) .then(() => writeMigrations(fs, path, contractsDir, writeUserMigrations, writeWitnetMigrations)) .catch((error) => fail(error, process, verbose)); diff --git a/src/lib/rad2sol/scripts.js b/src/lib/rad2sol/scripts.js index 98035e9..f50411e 100644 --- a/src/lib/rad2sol/scripts.js +++ b/src/lib/rad2sol/scripts.js @@ -3,51 +3,54 @@ import {Disabled} from "../../utils"; function readScript (fs) { return [ - filePath => { console.log(`> Compiling ${filePath}`); return filePath }, - filePath => readFile(filePath, fs), + query => { console.log(`> Compiling ${query.path}`); return query }, + query => readFile(query.path, fs), ]; } -function compileScript (vm, requestPaths) { +function compileScript (vm, queryNames) { return [ compile, - (code, i) => execute(code, requestPaths[i], process.env.PWD, vm), + (code, i) => execute(code, queryNames[i], process.env.PWD, vm), pack, ]; } -function encodeScript (path, schema, requestsList, requestPaths) { +function encodeScript (path, schema, queries) { + const queryNames = Object.keys(queries); return [ (request) => intoProtoBuf(request, schema), buff => buff.toString("hex"), (hex, i) => { - requestsList[path.basename(requestPaths[i]).replace(/\.js/, "")] = { bytecode: `0x${hex}` } + queries[queryNames[i]].bytecode = `0x${hex}` return hex } ]; } -function writeSolScript (fs, path, requestPaths, writeContracts) { +function writeSolScript (fs, path, writeContracts, queries) { + const queryNames = Object.keys(queries); return [ - (hex, i) => intoSol(hex, path.basename(requestPaths[i])), - (sol, i) => { if (writeContracts !== Disabled) { writeSol(fs, path, sol, path.basename(requestPaths[i]), writeContracts) } }, + (query, i) => intoSol(queryNames[i], query), + (sol, i) => { if (writeContracts !== Disabled) { writeSol(fs, path, sol, writeContracts, queryNames[i]) } }, ]; } -function readCompileEncodeScript (fs, path, vm, schema, requestPaths, requestsList) { +function readCompileEncodeScript (fs, path, vm, schema, queries) { + const queryNames = Object.keys(queries) return [ - ...readScript(fs, path, queryDir), - ...compileScript(vm, requestPaths), - ...encodeScript(path, schema, requestsList, requestPaths), + ...readScript(fs, path), + ...compileScript(vm, queryNames), + ...encodeScript(path, schema, queries), ]; } -function readCompileEncodeWriteSolScript (fs, path, vm, schema, writeContracts, requestsList, requestsPaths) { +function readCompileEncodeWriteSolScript (fs, path, vm, schema, writeContracts, queries) { return [ ...readScript(fs), - ...compileScript(vm, requestsPaths), - ...encodeScript(path, schema, requestsList, requestsPaths), - ...writeSolScript(fs, path, requestsPaths, writeContracts), + ...compileScript(vm, queries), + ...encodeScript(path, schema, queries), + ...writeSolScript(fs, path, writeContracts, queries), ]; } diff --git a/src/lib/rad2sol/steps.js b/src/lib/rad2sol/steps.js index 8ad3a1c..a96b99a 100644 --- a/src/lib/rad2sol/steps.js +++ b/src/lib/rad2sol/steps.js @@ -159,8 +159,8 @@ export function intoProtoBuf (query, schema) { return schema.DataRequestOutput.encode(query) } -export function intoSol (hex, fileName) { - const contractName = fileName.replace(/\.js/, ""); +export function intoSol (queryName, query) { + const contractName = queryName; return `// SPDX-License-Identifier: MIT @@ -175,48 +175,48 @@ import "witnet-solidity-bridge/contracts/requests/WitnetRequestInitializableBase // The bytecode of the ${contractName} query that will be sent to Witnet contract ${contractName}Request is WitnetRequestInitializableBase { function initialize() public { - WitnetRequestInitializableBase.initialize(hex"${hex}"); + WitnetRequestInitializableBase.initialize(hex"${query.hex}"); } } ` } -export function writeQueriesToJson (fs, path, newRequests, dir) { - let existingRequests = {} +export function writeQueriesToJson (fs, path, newQueries, dir) { + let existingQueries = {} const listFilePath = path.resolve(dir, QUERIES_JSON_FILE_NAME) if (fs.existsSync(listFilePath)) { - existingRequests = JSON.parse(readFile(listFilePath, fs)) + existingQueries = JSON.parse(readFile(listFilePath, fs)) } - if (existingRequests) { - Object.keys(newRequests).forEach((key) => { - if (existingRequests[key]) { - if (isRoutedQuery(existingRequests[key]) && !isRoutedQuery(newRequests[key])) { + if (existingQueries) { + Object.keys(newQueries).forEach((key) => { + if (existingQueries[key]) { + if (isRoutedQuery(existingQueries[key]) && !isRoutedQuery(newQueries[key])) { // Don't keep the bytecode field if the old query is not a routed query and the new query is - const { bytecode , ...validExistingRequestsFields } = existingRequests[key] - newRequests[key] = { ...validExistingRequestsFields, ...newRequests[key] } + const { bytecode , ...validExistingRequestsFields } = existingQueries[key] + newQueries[key] = { ...validExistingRequestsFields, ...newQueries[key] } } else { - newRequests[key] = { ...existingRequests[key], ...newRequests[key] } + newQueries[key] = { ...existingQueries[key], ...newQueries[key] } } } }) // Make sure we don't delete any routed price feeds that have been generated manually (not present in newRequests) - Object.entries(existingRequests).forEach(([key, query]) => { - if (!newRequests[key] && !query.bytecode) { - newRequests[key] = query + Object.entries(existingQueries).forEach(([key, query]) => { + if (!newQueries[key] && !query.bytecode) { + newQueries[key] = query } }) } fs.writeFileSync( listFilePath, - JSON.stringify(sortObjectKeys(newRequests), null, 4) + JSON.stringify(sortObjectKeys(newQueries), null, 4) ); } -export function writeSol (fs, path, sol, fileName, writeContracts) { - const solFileName = fileName.replace(/\.js/, ".sol"); +export function writeSol (fs, path, sol, writeContracts, queryName) { + const solFileName = `${queryName}.sol`; fs.writeFileSync(path.resolve(writeContracts, solFileName), sol); - return fileName + return queryName } export function writeMigrations (fs, path, contractsDir, writeUserMigrations, writeWitnetMigrations) {