From eae879fdad24cd56b3918430dc40fe9a3059858e Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 00:41:29 -0300 Subject: [PATCH 01/61] finish task() step --- .env-local | 6 ++-- coreLogic.js | 28 ++++++++-------- helpers/createFile.js | 11 +++++++ helpers/dataFromCid.js | 32 ++++++++++++++++++ helpers/deleteFile.js | 11 +++++++ helpers/getKey.js | 3 ++ helpers/hashCompare.js | 26 +++++++++++++++ index.js | 16 +++++---- linktree_task.js | 75 ++++++++++++++++++++++++++++++++++++++++++ namespaceWrapper.js | 8 +++++ 10 files changed, 193 insertions(+), 23 deletions(-) create mode 100644 helpers/createFile.js create mode 100644 helpers/dataFromCid.js create mode 100644 helpers/deleteFile.js create mode 100644 helpers/getKey.js create mode 100644 helpers/hashCompare.js create mode 100644 linktree_task.js diff --git a/.env-local b/.env-local index af45ee1f..3e15fa67 100644 --- a/.env-local +++ b/.env-local @@ -12,7 +12,7 @@ INITIAL_STAKING_WALLET_BALANCE=1 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="true" +GLOBAL_TIMERS="false" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs @@ -35,13 +35,13 @@ K2_NODE_URL="https://k2-testnet.koii.live" # registering with the crete-task-cli. This variable supports a comma separated list: # TASKS="id1,id2,id3" # TASK_STAKES="1,1,1" -TASKS="" +TASKS="7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo" TASK_STAKES=1 # User can enter as many environment variables as they like below. These can be task # specific variables that are needed for the task to perform it's job. Some examples: # Secrets must follow this convention for task to be able to use it (SECRET_) -SECRET_WEB3_STORAGE_KEY="" +SECRET_WEB3_STORAGE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw" TWITTER_CONSUMER_KEY="" TWITTER_CONSUMER_SECRET="" TWITTER_BEARER_TOKEN="" diff --git a/coreLogic.js b/coreLogic.js index dbae774a..c8356514 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -1,29 +1,31 @@ const { namespaceWrapper } = require("./namespaceWrapper"); +const linktree_task = require("./linktree_task"); const crypto = require('crypto'); class CoreLogic{ async task() { // Write the logic to do the work required for submitting the values and optionally store the result in levelDB - - // Below is just a sample of work that a task can do - - try{ - - const x = Math.random().toString(); // generate random number and convert to string - const cid = crypto.createHash("sha1").update(x).digest("hex"); // convert to CID - console.log("HASH:", cid); - - // fetching round number to store work accordingly + // run linktree task + const cid = await linktree_task(); if (cid) { await namespaceWrapper.storeSet("cid", cid); // store CID in levelDB + } else { + console.log("CID NOT FOUND"); } -}catch(err){ - console.log("ERROR IN EXECUTING TASK", err); + // checking the data storage + try { + const cid_index = await namespaceWrapper.storeGet( + "testlinktree" + ); + console.log("Getting linktree index", cid_index); +} catch (err) { + console.log("CATCH IN GET", err); } - +console,log("*********task() completed*********") } + async fetchSubmission(){ // Write the logic to fetch the submission values here and return the cid string diff --git a/helpers/createFile.js b/helpers/createFile.js new file mode 100644 index 00000000..c585cf5c --- /dev/null +++ b/helpers/createFile.js @@ -0,0 +1,11 @@ +const fsPromise = require("fs/promises"); + +module.exports = async (path, data) => { + //if (!fs.existsSync('userIndex')) fs.mkdirSync('userIndex'); + + await fsPromise.writeFile(path, JSON.stringify(data), (err) => { + if (err) { + console.error(err); + } + }); +}; diff --git a/helpers/dataFromCid.js b/helpers/dataFromCid.js new file mode 100644 index 00000000..6924803a --- /dev/null +++ b/helpers/dataFromCid.js @@ -0,0 +1,32 @@ +const axios = require("axios"); +const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const storageClient = new Web3Storage({ + token: process.env.SECRET_WEB3_STORAGE_KEY, +}); + +module.exports = async (cid) => { + console.log("CID", cid); + if (storageClient) { + const res = await storageClient.get(cid); + if (!res.ok) { + // voting false + console.log("VOTE FALSE"); + + console.log("SLASH VOTE DUE TO FAKE VALUE"); + //console.log("VOTE", vote); + return false; + } else { + const file = await res.files(); + //console.log("FILE", file); + //console.log("CID", file[0].cid); + const url = `https://${file[0].cid}.ipfs.w3s.link/?filename=${file[0].name}`; + console.log("URL", url); + try { + const output = await axios.get(url); + return output; + } catch (error) { + console.log("ERROR", error); + } + } + } +}; diff --git a/helpers/deleteFile.js b/helpers/deleteFile.js new file mode 100644 index 00000000..1f17d2ef --- /dev/null +++ b/helpers/deleteFile.js @@ -0,0 +1,11 @@ +const fsPromise = require("fs/promises"); + +module.exports = async (path) => { + //if (!fs.existsSync('userIndex')) fs.mkdirSync('userIndex'); + + await fsPromise.unlink(path, (err) => { + if (err) { + console.error(err); + } + }); +}; diff --git a/helpers/getKey.js b/helpers/getKey.js new file mode 100644 index 00000000..66294729 --- /dev/null +++ b/helpers/getKey.js @@ -0,0 +1,3 @@ +module.exports = async (obj, value) => { + return Object.keys(obj).find((key) => obj[key] === value); +}; diff --git a/helpers/hashCompare.js b/helpers/hashCompare.js new file mode 100644 index 00000000..62f21022 --- /dev/null +++ b/helpers/hashCompare.js @@ -0,0 +1,26 @@ +const crypto = require("crypto"); +const { namespaceWrapper } = require("../namespaceWrapper"); + +module.exports = async (index, signature, publicKey) => { + const hash = await namespaceWrapper.verifySignature(signature, publicKey); + if (hash.error) { + console.error("Could not verify the signatures"); + } + + console.log("DATA HASH", hash.data); + + // comparing the data Hash + const expectedHash = crypto + .createHash("sha256") + .update(JSON.stringify(index)) + .digest("hex"); + + const expectedString = JSON.stringify(expectedHash); + console.log("EXPECTED HASH", expectedString); + + if (hash.data == expectedString) { + return true; + } else { + return false; + } +}; diff --git a/index.js b/index.js index ac613d92..42acb0d2 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ const {coreLogic} = require("./coreLogic"); -const { app } = require("./init"); +const { app, MAIN_ACCOUNT_PUBKEY } = require("./init"); const { namespaceWrapper } = require("./namespaceWrapper"); @@ -43,18 +43,20 @@ async function setup() { */ + console.log("*******************TESTING*******************") // Get the task state - //console.log(await namespaceWrapper.getTaskState()); + // console.log(await namespaceWrapper.getTaskState()); - //GET ROUND + // Get account public key + // console.log(MAIN_ACCOUNT_PUBKEY); - // const round = await namespaceWrapper.getRound(); - // console.log("ROUND", round); + // GET ROUND + const round = await namespaceWrapper.getRound(); + console.log("ROUND", round); // Call to do the work for the task - - //await coreLogic.task(); + await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) diff --git a/linktree_task.js b/linktree_task.js new file mode 100644 index 00000000..aa8b7101 --- /dev/null +++ b/linktree_task.js @@ -0,0 +1,75 @@ +const { namespaceWrapper } = require("./namespaceWrapper"); +const createFile = require("./helpers/createFile.js"); +const deleteFile = require("./helpers/deleteFile"); +const fs = require("fs"); +const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const storageClient = new Web3Storage({ + token: process.env.SECRET_WEB3_STORAGE_KEY, +}); +const { MAIN_ACCOUNT_PUBKEY } = require("./init"); +const crypto = require("crypto"); + +module.exports = async() => { + console.log("******/ IN Linktree Task FUNCTION /******"); + // Customize linktree test data + const linktree_data = { + "name": "test", + "description": "test description", + "background": "test-image.png", + "links": [ + {"testlink": "http://testapi.com"}, + ], + "user_pubkey": MAIN_ACCOUNT_PUBKEY, + }; + console.log('SUBMISSION VALUE', linktree_data); + + const linktree_data_payload = JSON.stringify(linktree_data); + + const hashLinktreeIndex = crypto + .createHash("sha256") + .update(linktree_data_payload) + .digest("hex"); + + console.log("HASH OF LINKTREE INDEX", hashLinktreeIndex); + + // singing the payload using the nodes private key and sending the public key along with the payload + const signature = await namespaceWrapper.payloadSigning(hashLinktreeIndex); + + console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); + + const indexSignature = { + data: linktree_data, + signature: signature, + pubKey: MAIN_ACCOUNT_PUBKEY, + }; + + console.log("INDEX SIGNATURE DATA", indexSignature); + + // upload the index of the linktree on web3.storage + const path = `userIndex/test.json`; + console.log("PATH", path); + if (!fs.existsSync("userIndex")) fs.mkdirSync("userIndex"); + await createFile(path, indexSignature); + + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log("User index uploaded to IPFS: ", cid); + + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); + + // Store the cid in level db + try { + await namespaceWrapper.storeSet("testlinktree", cid); + } catch (err) { + console.log("ERROR IN STORING test linktree", err); + res.status(404).json({ message: "ERROR in storing test linktree" }); + } + + return cid + + } else { + console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + } +}; diff --git a/namespaceWrapper.js b/namespaceWrapper.js index 631863be..fa8712e5 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -169,6 +169,14 @@ class NamespaceWrapper { return await genericHandler("payloadTrigger"); } + async verifySignature(signedMessage, pubKey) { + return await genericHandler("verifySignedData", signedMessage, pubKey); + } + + async payloadSigning(body) { + return await genericHandler("signData", body); + } + async checkSubmissionAndUpdateRound(submissionValue = "default", round) { return await genericHandler( "checkSubmissionAndUpdateRound", From be7ad78fba22e1c971a8a63e91b5a1d44c378f93 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 01:32:47 -0300 Subject: [PATCH 02/61] update fetchsubmisstion --- coreLogic.js | 19 ++++++------------- index.js | 4 +--- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index c8356514..61ed15db 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -14,16 +14,7 @@ async task() { } else { console.log("CID NOT FOUND"); } - // checking the data storage - try { - const cid_index = await namespaceWrapper.storeGet( - "testlinktree" - ); - console.log("Getting linktree index", cid_index); -} catch (err) { - console.log("CATCH IN GET", err); -} -console,log("*********task() completed*********") + console.log("*********task() completed*********") } async fetchSubmission(){ @@ -31,13 +22,14 @@ async fetchSubmission(){ // fetching round number to store work accordingly - console.log("IN FETCH SUBMISSION"); + console.log("***********IN FETCH SUBMISSION**************"); const round = await namespaceWrapper.getRound(); + console.log("ROUND NUMBER", round); // The code below shows how you can fetch your stored value from level DB - const cid = await namespaceWrapper.storeGet("cid"); // retrieves the cid - console.log("CID", cid); + const cid = await namespaceWrapper.storeGet("testlinktree"); // retrieves the cid + console.log("Linktree CID", cid); return cid; } @@ -186,6 +178,7 @@ async submitTask(roundNumber) { console.log(await namespaceWrapper.getSlot(), "current slot while calling submit"); const submission = await this.fetchSubmission(); console.log("SUBMISSION", submission); + // submit the submission to the K2 await namespaceWrapper.checkSubmissionAndUpdateRound(submission, roundNumber); console.log("after the submission call"); } catch (error) { diff --git a/index.js b/index.js index 42acb0d2..a4cd4eef 100644 --- a/index.js +++ b/index.js @@ -59,9 +59,7 @@ async function setup() { await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) - - - //await coreLogic.submitTask(round - 1); + await coreLogic.submitTask(round - 1); // Audit submissions From 6fdd6931546bd65b30a76758eb7ad9209ab13086 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 12:05:10 -0300 Subject: [PATCH 03/61] add validate function --- coreLogic.js | 10 ++- index.js | 3 +- linktree_validate.js | 160 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 linktree_validate.js diff --git a/coreLogic.js b/coreLogic.js index 61ed15db..6d8c7791 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -1,5 +1,6 @@ const { namespaceWrapper } = require("./namespaceWrapper"); const linktree_task = require("./linktree_task"); +const linktree_validate = require("./linktree_validate"); const crypto = require('crypto'); class CoreLogic{ @@ -110,11 +111,8 @@ async validateNode(submission_value, round) { // Write your logic for the validation of submission value here and return a boolean value in response -// The sample logic can be something like mentioned below to validate the submission - -// try{ - console.log("Received submission_value", submission_value, round); +const vote = await linktree_task(submission_value); // const generatedValue = await namespaceWrapper.storeGet("cid"); // console.log("GENERATED VALUE", generatedValue); // if(generatedValue == submission_value){ @@ -128,7 +126,7 @@ console.log("Received submission_value", submission_value, round); // } // For succesfull flow we return true for now -return true; +return vote; } @@ -186,7 +184,7 @@ async submitTask(roundNumber) { } } -async auditTask(roundNumber) { +async auditTask(roundNumber) { // No need to edit this function console.log("auditTask called with round", roundNumber); console.log(await namespaceWrapper.getSlot(), "current slot while calling auditTask"); await namespaceWrapper.validateAndVoteOnNodes(this.validateNode, roundNumber); diff --git a/index.js b/index.js index a4cd4eef..09dc0aeb 100644 --- a/index.js +++ b/index.js @@ -62,8 +62,7 @@ async function setup() { await coreLogic.submitTask(round - 1); // Audit submissions - - //await coreLogic.auditTask(round - 1); + await coreLogic.auditTask(round - 1); // upload distribution list to K2 diff --git a/linktree_validate.js b/linktree_validate.js new file mode 100644 index 00000000..5667ce82 --- /dev/null +++ b/linktree_validate.js @@ -0,0 +1,160 @@ +const { namespaceWrapper } = require("./namespaceWrapper"); +const dataFromCid = require("./helpers/dataFromCid"); +const getKeys = require("./helpers/getKey"); +const hashCompare = require("./helpers/hashCompare"); + +module.exports = async (submission_value) => { + const linktreeIndex = submission_value; + console.log("linktreeINDEX", linktreeIndex); + + try { + const output = await dataFromCid(linktreeIndex); + console.log("RESPONSE DATA", output.data); + const linktreeIndexData = output.data.data; + console.log("linktree INDEX DATA", linktreeIndexData); + const signature = output.data.signature; + console.log("SIGNATURES", signature); + const publicKey = output.data.pubKey; + console.log("PUBKEY", publicKey); + + if (!output.data || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; + } + + // verifying the signature and getting the original data + const check = await hashCompare(linktreeIndexData, signature, publicKey); + console.log("CHECK", check); + + if (check == true) { + console.log("IN IF"); + const values = Object.values(linktreeIndexData); + const keys = Object.keys(linktreeIndexData); + const size = values.length; + + const testlinktree_string = await namespaceWrapper.storeGet("testlinktree"); + let testlinktree = JSON.parse(testlinktree_string); + console.log("Getting Linktree list", testlinktree); + if (!testlinktree) { + console.log("NEW Linktree LIST MADE"); + testlinktree = {}; + } + + let apiResponse = await dataFromCid(values[i]); + console.log("OUTPUT FROM INDEX CID", apiResponse.data); + if (apiResponse == false) { + return false; + } + let userIndexData = apiResponse.data.data; + let index = Object.values(userIndexData); + console.log("INDEX", index[0]); + + // checking the Linktree owner sigature now : P + + const index_length = Object.keys(index[0]).length; + console.log("INDEX LENGTH", index_length); + const latest_state = await getKeys(index[0], index_length); + console.log("LATEST STATE", latest_state); + + let output = await dataFromCid(latest_state); + console.log("OUTPUT FROM LATEST STATE", output.data); + if (output == false) { + return false; + } + console.log("RESPONSE DATA", output.data); + // const Pd = JSON.stringify(output.data); + const signedMessage = output.data.signedMessage; + console.log("SIGNED MESSAGE", signedMessage); + const publicKey = output.data.pubKey; + console.log("PUBLIC KEY", publicKey); + + if (!signedMessage || !publicKey) { + console.error("Signature or public Key missing from userIndex"); + return false; + } + + // verifying the signature and getting the original data + + const verifiedPayload = await namespaceWrapper.verifySignature( + signedMessage, + publicKey + ); + if (verifiedPayload.error) { + return false; + } else { + //const verifiedPayload = JSON.parse(verifiedPayloadString); + console.log("Original Data", verifiedPayload); + + const userIndexData = verifiedPayload.data; + const parsed = JSON.parse(userIndexData); + console.log("USER INDEX DATA", parsed); + const originalLinktree = parsed.data; + console.log("ORIGINAL Linktree", originalLinktree); + const userSignature = parsed.keys.signedMessage; + console.log("SIGNATURES", userSignature); + const userPublicKey = parsed.keys.pubkey; + console.log("PUBKEY", userPublicKey); + + if (!userIndexData || !userSignature || !userPublicKey) { + console.error("No data received from web3.storage"); + return false; + } + + const check_data = await hashCompare( + originalLinktree, + userSignature, + userPublicKey + ); + if (check_data == true) { + console.log("CHECK PASSED"); + // Add the Linktree to local node + + // storing linktree Index + + try { + await namespaceWrapper.storeSet( + "linktreeIndex" + `${Linktree}`, + values[i] + ); + } catch (err) { + console.log("ERROR IN STORING Linktree", err); + res.status(404).json({ message: "ERROR in storing Linktree" }); + } + + // storing the Linktree in testlinktree + + testlinktree[Linktree] = "no"; + let testlinktree_string = JSON.stringify(testlinktree); + console.log("ADDED Linktree LIST", testlinktree_string); + await namespaceWrapper.storeSet("testlinktree", testlinktree_string); + + //storting the user Index + + let cid_index_stingified = JSON.stringify(index[0]); + console.log("USER_INDEX STRINGIFIED ", cid_index_stingified); + await namespaceWrapper.storeSet(Linktree, cid_index_stingified); + + // check the user index store + + try { + const cid_index = await namespaceWrapper.storeGet(Linktree); + console.log("Getting cid index", cid_index); + } catch (err) { + console.log("CATCH IN GET", err); + } + } else { + return false; + } + } + return true; + } else { + console.log("IN ELSE"); + return false; + } + } catch (error) { + console.log("ERROR", error); + } + + //return true; +}; + From 51a151eeea2d56e1d8cfdedc7615e750030bcb7c Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 15:43:02 -0300 Subject: [PATCH 04/61] update config --- .env-local | 6 +++--- check_task-status.js | 10 ++++++++++ coreLogic.js | 2 +- index.js | 12 ++++++------ 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 check_task-status.js diff --git a/.env-local b/.env-local index 3e15fa67..7d742bfe 100644 --- a/.env-local +++ b/.env-local @@ -8,11 +8,11 @@ NODE_MODE="service" # The nodes address SERVICE_URL="http://localhost:8080" # For CI/CD purpose to automate the staking wallet creation -INITIAL_STAKING_WALLET_BALANCE=1 +INITIAL_STAKING_WALLET_BALANCE=20 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="false" +GLOBAL_TIMERS="true" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs @@ -36,7 +36,7 @@ K2_NODE_URL="https://k2-testnet.koii.live" # TASKS="id1,id2,id3" # TASK_STAKES="1,1,1" TASKS="7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo" -TASK_STAKES=1 +TASK_STAKES=10 # User can enter as many environment variables as they like below. These can be task # specific variables that are needed for the task to perform it's job. Some examples: diff --git a/check_task-status.js b/check_task-status.js new file mode 100644 index 00000000..9b86d620 --- /dev/null +++ b/check_task-status.js @@ -0,0 +1,10 @@ +const { Connection, PublicKey } = require('@_koi/web3.js'); +async function main() { + const connection = new Connection('https://k2-testnet.koii.live'); + const accountInfo = await connection.getAccountInfo( + new PublicKey('7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo'), + ); + console.log(JSON.parse(accountInfo.data+"")); +} + +main(); \ No newline at end of file diff --git a/coreLogic.js b/coreLogic.js index 6d8c7791..49379fa7 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -29,7 +29,7 @@ async fetchSubmission(){ console.log("ROUND NUMBER", round); // The code below shows how you can fetch your stored value from level DB - const cid = await namespaceWrapper.storeGet("testlinktree"); // retrieves the cid + const cid = await namespaceWrapper.storeGet("cid"); // retrieves the cid console.log("Linktree CID", cid); return cid; } diff --git a/index.js b/index.js index 09dc0aeb..ad7d3521 100644 --- a/index.js +++ b/index.js @@ -43,7 +43,7 @@ async function setup() { */ - console.log("*******************TESTING*******************") + // console.log("*******************TESTING*******************") // Get the task state // console.log(await namespaceWrapper.getTaskState()); @@ -51,18 +51,18 @@ async function setup() { // console.log(MAIN_ACCOUNT_PUBKEY); // GET ROUND - const round = await namespaceWrapper.getRound(); - console.log("ROUND", round); + // const round = await namespaceWrapper.getRound(); + // console.log("ROUND", round); // Call to do the work for the task - await coreLogic.task(); + // await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) - await coreLogic.submitTask(round - 1); + // await coreLogic.submitTask(round - 1); // Audit submissions - await coreLogic.auditTask(round - 1); + // await coreLogic.auditTask(round - 1); // upload distribution list to K2 From dbac6b6d654ef9b775a8f94b8b69e4433e4714ea Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 15:57:34 -0300 Subject: [PATCH 05/61] update test --- index.js | 100 ++++++++++++++++++++++++++++++++++-- test/test_submitLinktree.js | 71 +++++++++++++++++++++++++ test/test_wallet.json | 1 + 3 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 test/test_submitLinktree.js create mode 100644 test/test_wallet.json diff --git a/index.js b/index.js index ad7d3521..a01f048d 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,65 @@ async function setup() { } }); + // Code for the data replication among the nodes + setInterval(async () => { + try { + const nodesUrl = `${SERVICE_URL}/nodes/${TASK_ID}`; + const res = await axios.get(nodesUrl); + if (res.status != 200) { + console.error('Error', res.status); + return; + } + + if (!res.data) { + console.error('res has no valid urls'); + return; + } + let nodeUrlList = res.data.map((e) => { + return e.data.url; + }); + console.log(nodeUrlList); + let allLinktrees = await namespaceWrapper.storeGet('linktrees'); + allLinktrees = JSON.parse(allLinktrees || '[]'); + for (let url of nodeUrlList) { + console.log(url); + const res = await axios.get(`${url}/task/${TASK_ID}/get-all-linktrees`); + if (res.status != 200) { + console.error('ERROR', res.status); + continue; + } + const payload = res.data; + /* + 1. Verify the signature + 2. Only update your db if incoming timestamp > your timestamp or you don't have the data + */ + if (!payload || payload.length == 0) continue; + for (let linkTreePayload in payload) { + const isVerified = nacl.sign.detached.verify( + new TextEncoder().encode(JSON.stringify(linkTreePayload.data)), + bs58.decode(linkTreePayload.signature), + bs58.decode(linkTreePayload.publicKey) + ); + if (!isVerified) { + console.warn(`${url} is not able to verify the signature`); + continue; + } + let localExistingLinktree = allLinktrees.find((e) => { + e.uuid == linkTreePayload.data.uuid; + }); + if (localExistingLinktree) { + if (localExistingLinktree.data.timestamp < linkTreePayload.data.timestamp) { + allLinktrees.push(linkTreePayload); + } + } else { + allLinktrees.push(linkTreePayload); + } + } + } + } catch (error) { + console.error('Some went wrong:', error); + } + }, 20000); /* GUIDE TO CALLS K2 FUNCTIONS MANUALLY @@ -87,17 +146,48 @@ async function setup() { setup(); if (app) { - // Write your Express Endpoints here. - // For Example - // app.post('/accept-cid', async (req, res) => {}) - // Sample API that return your task state - app.get('/taskState', async (req, res) => { const state = await namespaceWrapper.getTaskState(); console.log("TASK STATE", state); res.status(200).json({ taskState: state }) }) + + // API to register the linktree + app.post('/register-linktree', async (req, res) => { + const linktree = req.body.payload; + // TODO: validate the linktree structure here + /* + 1. Must have the following structure + 2. Signature must be verified by the publicKey + */ + + /* + { + data:{ + uuid:jhasjdbjhguyt23764vhyt + linktree:linktree, + timestamp:76576465, + }, + publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", + signature:"hjgasdjasbhmnbjhasgdkjsahjdkhgsakjdhgsajhyg" + } + */ + // Use the code below to sign the data payload + // const msg = new TextEncoder().encode(JSON.stringify(data)); + // const signature = nacl.sign.detached(msg, secretKey); + + let allLinktrees = await namespaceWrapper.storeGet('linktrees'); + allLinktrees = JSON.parse(allLinktrees || '[]'); + allLinktrees.push(linktree); + await namespaceWrapper.storeSet('linktrees', JSON.stringify(allLinktrees)); + return res.status(200).send({message: 'Linktree registered successfully'}); + }); + app.get('/get-all-linktrees', async (req, res) => { + let allLinktrees = await namespaceWrapper.storeGet('linktrees'); + allLinktrees = JSON.parse(allLinktrees || '[]'); + return res.status(200).send(allLinktrees); + }); } diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js new file mode 100644 index 00000000..a158d405 --- /dev/null +++ b/test/test_submitLinktree.js @@ -0,0 +1,71 @@ +const {default: axios} = require('axios'); +const {v4: uuidv4} = require('uuid'); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const fs = require("fs") +try { + const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( + new Uint8Array(JSON.parse(fs.readFileSync("tests/dummyWallet.json", 'utf-8'))) + ); + const payload = { + data: { + uuid: uuidv4(), + linktree: [ + { + key: 'official', + label: 'Official Website', + redirectUrl: 'https://spheron.network/', + }, + { + key: 'twitter', + label: 'Twitter', + redirectUrl: 'https://twitter.com/blockchainbalak', + }, + { + key: 'linkedin', + label: 'LinkedIn', + redirectUrl: 'https://www.linkedin.com/in/prakarshpathak/', + }, + // { + // "key": "medium", + // "label": "Medium", + // "iconUrl": Medium, + // "redirectUrl": "", + // }, + { + key: 'youtube', + label: 'YouTube', + redirectUrl: 'https://www.youtube.com/channel/UCIe3FlAWg06kGOrm1-c8oJg', + }, + { + key: 'discord', + label: 'Discord', + redirectUrl: 'https://discord.com/invite/ahxuCtm', + }, + { + key: 'github', + label: 'GitHub', + redirectUrl: 'https://github.com/spheronFdn/', + }, + ], + timestamp: Date.now(), + }, + publicKey: bs58.encode(publicKey), + }; + const msg = new TextEncoder().encode(JSON.stringify(payload.data)); + payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + + axios + .post('http://localhost:8080/task/Aymg9fr1qCSbKSSvud4jG74MHrRGw8EpkFVQo6rFGSQf/register-linktree', {payload}) + .then((e) => { + if (e.status != 200) { + console.log(e); + } + console.log(e.data); + }) + .catch((e) => { + console.error(e); + }); +} catch (e) { + console.error(e) +} \ No newline at end of file diff --git a/test/test_wallet.json b/test/test_wallet.json new file mode 100644 index 00000000..bfc5eba2 --- /dev/null +++ b/test/test_wallet.json @@ -0,0 +1 @@ +[158,15,47,49,79,77,203,210,130,53,57,104,184,70,233,89,56,199,75,85,60,200,254,207,246,106,71,37,238,238,120,194,243,101,151,29,124,180,174,229,189,224,88,5,141,139,110,195,51,40,151,44,14,112,71,128,87,69,149,204,80,0,132,162] From 790a94fa3905a658c5b74b7009dc0b78b4c5c2cd Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 16:02:56 -0300 Subject: [PATCH 06/61] update task id --- .env-local | 2 +- test/test_submitLinktree.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env-local b/.env-local index 7d742bfe..8412b6d4 100644 --- a/.env-local +++ b/.env-local @@ -12,7 +12,7 @@ INITIAL_STAKING_WALLET_BALANCE=20 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="true" +GLOBAL_TIMERS="false" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index a158d405..4a605667 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -56,7 +56,7 @@ try { payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); axios - .post('http://localhost:8080/task/Aymg9fr1qCSbKSSvud4jG74MHrRGw8EpkFVQo6rFGSQf/register-linktree', {payload}) + .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/register-linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); From bbb407a5de25ee842640cce3c040bfcb596aed92 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 29 Mar 2023 23:34:01 -0300 Subject: [PATCH 07/61] update --- test/test_submitLinktree.js | 11 ++++------- test/unitTest.js | 5 +++++ 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 test/unitTest.js diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 4a605667..5fc7811f 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -5,7 +5,7 @@ const nacl = require('tweetnacl'); const fs = require("fs") try { const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( - new Uint8Array(JSON.parse(fs.readFileSync("tests/dummyWallet.json", 'utf-8'))) + new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) ); const payload = { data: { @@ -26,12 +26,6 @@ try { label: 'LinkedIn', redirectUrl: 'https://www.linkedin.com/in/prakarshpathak/', }, - // { - // "key": "medium", - // "label": "Medium", - // "iconUrl": Medium, - // "redirectUrl": "", - // }, { key: 'youtube', label: 'YouTube', @@ -55,6 +49,9 @@ try { const msg = new TextEncoder().encode(JSON.stringify(payload.data)); payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + // Check payload + console.log(payload); + axios .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/register-linktree', {payload}) .then((e) => { diff --git a/test/unitTest.js b/test/unitTest.js new file mode 100644 index 00000000..0dbb4939 --- /dev/null +++ b/test/unitTest.js @@ -0,0 +1,5 @@ +const coreLogic = require('../coreLogic'); +const index = require('../index'); +coreLogic.task(); +const submission = coreLogic.fetchSubmission(); +coreLogic.validateNode(submission, 1); From 94d25ae0f3e59d7ec50b03fc284c76eb237453b5 Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 30 Mar 2023 00:33:58 -0300 Subject: [PATCH 08/61] update testing code --- .env-local | 2 +- .gitignore | 2 + coreLogic.js | 9 +--- index.js | 31 +++++++++++--- init.js | 6 +-- namespaceWrapper.js | 64 +++++++++++++++++++++++----- package.json | 2 + test/test_getallLinktree.js | 20 +++++++++ test/test_submitLinktree.js | 2 +- test/unitTest.js | 7 ++-- test/userIndex/test.json | 1 + yarn.lock | 83 ++++++++++++++++++++++++++++++++++++- 12 files changed, 198 insertions(+), 31 deletions(-) create mode 100644 test/test_getallLinktree.js create mode 100644 test/userIndex/test.json diff --git a/.env-local b/.env-local index 8412b6d4..2813a4a0 100644 --- a/.env-local +++ b/.env-local @@ -8,7 +8,7 @@ NODE_MODE="service" # The nodes address SERVICE_URL="http://localhost:8080" # For CI/CD purpose to automate the staking wallet creation -INITIAL_STAKING_WALLET_BALANCE=20 +INITIAL_STAKING_WALLET_BALANCE=15 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions diff --git a/.gitignore b/.gitignore index daf63eb6..e506791e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,7 @@ data/* executables/* namespace/* config/* +taskStateInfoKeypair.json +localKOIIDB .env taskStateInfoKeypair.json \ No newline at end of file diff --git a/coreLogic.js b/coreLogic.js index 49379fa7..378c4b0b 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -24,9 +24,6 @@ async fetchSubmission(){ // fetching round number to store work accordingly console.log("***********IN FETCH SUBMISSION**************"); - - const round = await namespaceWrapper.getRound(); - console.log("ROUND NUMBER", round); // The code below shows how you can fetch your stored value from level DB const cid = await namespaceWrapper.storeGet("cid"); // retrieves the cid @@ -112,7 +109,7 @@ async validateNode(submission_value, round) { // Write your logic for the validation of submission value here and return a boolean value in response console.log("Received submission_value", submission_value, round); -const vote = await linktree_task(submission_value); +const vote = await linktree_validate(submission_value); // const generatedValue = await namespaceWrapper.storeGet("cid"); // console.log("GENERATED VALUE", generatedValue); // if(generatedValue == submission_value){ @@ -198,6 +195,4 @@ async auditDistribution(roundNumber) { } const coreLogic = new CoreLogic(); -module.exports = { - coreLogic -}; \ No newline at end of file +module.exports = coreLogic; diff --git a/index.js b/index.js index a01f048d..6ec3d9bb 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,10 @@ const {coreLogic} = require("./coreLogic"); -const { app, MAIN_ACCOUNT_PUBKEY } = require("./init"); -const { namespaceWrapper } = require("./namespaceWrapper"); +const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); +const express = require('express'); +const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); +const {default: axios} = require('axios'); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); async function setup() { @@ -143,9 +147,13 @@ async function setup() { } -setup(); +if (taskNodeAdministered){ + setup(); +} + if (app) { + app.use(express.json()); // Sample API that return your task state app.get('/taskState', async (req, res) => { const state = await namespaceWrapper.getTaskState(); @@ -157,6 +165,14 @@ if (app) { // API to register the linktree app.post('/register-linktree', async (req, res) => { const linktree = req.body.payload; + // Check req.body + if (!linktree) { + res.status(400).json({ error: 'Invalid request' }); + return; + } else { + console.log(linktree); + } + // TODO: validate the linktree structure here /* 1. Must have the following structure @@ -174,13 +190,18 @@ if (app) { signature:"hjgasdjasbhmnbjhasgdkjsahjdkhgsakjdhgsajhyg" } */ + // Use the code below to sign the data payload - // const msg = new TextEncoder().encode(JSON.stringify(data)); - // const signature = nacl.sign.detached(msg, secretKey); + const msg = new TextEncoder().encode(JSON.stringify(linktree.data)); + const secretKey = nacl.sign.keyPair().secretKey; + const signature = nacl.sign.detached(msg, secretKey); + + console.log('Check Signature:', bs58.encode(signature)); let allLinktrees = await namespaceWrapper.storeGet('linktrees'); allLinktrees = JSON.parse(allLinktrees || '[]'); allLinktrees.push(linktree); + console.log("NEW all Linktrees: ", allLinktrees); await namespaceWrapper.storeSet('linktrees', JSON.stringify(allLinktrees)); return res.status(200).send({message: 'Linktree registered successfully'}); }); diff --git a/init.js b/init.js index 054648db..d54bbfda 100644 --- a/init.js +++ b/init.js @@ -1,7 +1,7 @@ const express = require('express'); -const TASK_NAME = process.argv[2]; +const TASK_NAME = process.argv[2] || "Local"; const TASK_ID = process.argv[3]; -const EXPRESS_PORT = process.argv[4]; +const EXPRESS_PORT = process.argv[4] || 10000; const NODE_MODE = process.argv[5]; const MAIN_ACCOUNT_PUBKEY = process.argv[6]; const SECRET_KEY = process.argv[7]; @@ -11,7 +11,7 @@ const STAKE = Number(process.argv[10]); const app = express(); -console.log('SETTING UP EXPRESS', NODE_MODE); +console.log('SETTING UP EXPRESS'); app.get('/', (req, res) => { res.send('Hello World!'); }); diff --git a/namespaceWrapper.js b/namespaceWrapper.js index fa8712e5..d44ad21a 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -1,15 +1,32 @@ const { default: axios } = require("axios"); +const levelup = require('levelup'); +const leveldown = require('leveldown'); const BASE_ROOT_URL = "http://localhost:8080/namespace-wrapper"; const { TASK_ID, MAIN_ACCOUNT_PUBKEY, SECRET_KEY } = require("./init"); const { Connection, PublicKey, Keypair } = require("@_koi/web3.js"); +const taskNodeAdministered = !!TASK_ID; +let localLevelDB; class NamespaceWrapper { /** * Namespace wrapper of storeGetAsync * @param {string} key // Path to get */ async storeGet(key) { - return await genericHandler("storeGet", key); + if (taskNodeAdministered){ + return await genericHandler("storeGet", key); + } + instantiateLevelDb(); + return new Promise((resolve, reject) => { + localLevelDB.get(key, { asBuffer: false }, (err, value) => { + if (err) { + reject(err); + } else { + resolve(value); + } + + }); + }); } /** * Namespace wrapper over storeSetAsync @@ -17,7 +34,20 @@ class NamespaceWrapper { * @param {*} value Data to set */ async storeSet(key, value) { - return await genericHandler("storeSet", key, value); + if (taskNodeAdministered){ + return await genericHandler("storeSet", key, value); + } + instantiateLevelDb(); + return new Promise((resolve, reject) => { + localLevelDB.put(key, value, {}, (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + } /** * Namespace wrapper over fsPromises methods @@ -118,7 +148,12 @@ class NamespaceWrapper { } async getTaskState() { - return await genericHandler("getTaskState"); + const response = await genericHandler("getTaskState"); + if(response.error){ + return null + } + return response + } async auditSubmission(candidatePubkey, isValid, voterKeypair, round) { @@ -358,6 +393,12 @@ class NamespaceWrapper { } } +async function instantiateLevelDb() { + if(!localLevelDB){ + localLevelDB = levelup(leveldown("./localKOIIDB")); + } +} + async function genericHandler(...args) { try { let response = await axios.post(BASE_ROOT_URL, { @@ -371,18 +412,21 @@ async function genericHandler(...args) { return null; } } catch (err) { - console.log("Error in genericHandler", err); - console.error(err.message); + console.error(`Error in genericHandler: "${args[0]}"`,err.message); console.error(err?.response?.data); - return null; + return {error:err}; } } let connection; const namespaceWrapper = new NamespaceWrapper(); -namespaceWrapper.getRpcUrl().then((rpcUrl) => { - console.log(rpcUrl, "RPC URL"); - connection = new Connection(rpcUrl, "confirmed"); -}); +if(taskNodeAdministered){ + namespaceWrapper.getRpcUrl().then((rpcUrl) => { + console.log(rpcUrl, "RPC URL"); + connection = new Connection(rpcUrl, "confirmed"); + }); +} + module.exports = { namespaceWrapper, + taskNodeAdministered, }; diff --git a/package.json b/package.json index 91d5f9e3..3a17c987 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "@_koii/create-task-cli": "^0.1.12", "axios": "^0.27.2", "express": "^4.18.1", + "leveldown": "^6.1.1", + "levelup": "^5.1.1", "node-cron": "^3.0.2", "request": "^2.88.2", "web3.storage": "^4.4.0" diff --git a/test/test_getallLinktree.js b/test/test_getallLinktree.js new file mode 100644 index 00000000..48d7b0f8 --- /dev/null +++ b/test/test_getallLinktree.js @@ -0,0 +1,20 @@ +const {default: axios} = require('axios'); +const {v4: uuidv4} = require('uuid'); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const fs = require("fs") +try { + axios + .get('http://localhost:10000/get-all-linktrees') + .then((e) => { + if (e.status != 200) { + console.log(e); + } + console.log(e.data); + }) + .catch((e) => { + console.error(e); + }); +} catch (e) { + console.error(e) +} \ No newline at end of file diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 5fc7811f..94aaff6a 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -53,7 +53,7 @@ try { console.log(payload); axios - .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/register-linktree', {payload}) + .post('http://localhost:10000/register-linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); diff --git a/test/unitTest.js b/test/unitTest.js index 0dbb4939..7a23d184 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -1,5 +1,6 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); -coreLogic.task(); -const submission = coreLogic.fetchSubmission(); -coreLogic.validateNode(submission, 1); +index() +// coreLogic.task(); +// const submission = coreLogic.fetchSubmission(); +// coreLogic.validateNode(submission, 1); diff --git a/test/userIndex/test.json b/test/userIndex/test.json new file mode 100644 index 00000000..21b48635 --- /dev/null +++ b/test/userIndex/test.json @@ -0,0 +1 @@ +{"data":{"name":"test","description":"test description","background":"test-image.png","links":[{"testlink":"http://testapi.com"}]},"signature":{"error":{"message":"Request failed with status code 422","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json","User-Agent":"axios/0.27.2","Content-Length":88},"method":"post","url":"http://localhost:8080/namespace-wrapper","data":"{\"args\":[\"signData\",\"685b6c67c4b593e7ccd0e7a9d597244d176d87588c8ff0ffd1f5160c0fc9ce4d\"]}"},"code":"ERR_BAD_REQUEST","status":422}}} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b8e0e278..7b0a6be1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -703,6 +703,18 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +abstract-leveldown@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" + integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== + dependencies: + buffer "^6.0.3" + catering "^2.0.0" + is-buffer "^2.0.5" + level-concat-iterator "^3.0.0" + level-supports "^2.0.1" + queue-microtask "^1.2.3" + accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" @@ -1124,6 +1136,11 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== +catering@^2.0.0, catering@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + cborg@^1.3.3, cborg@^1.5.4, cborg@^1.6.0, cborg@^1.8.0, cborg@^1.9.4: version "1.9.5" resolved "https://registry.npmjs.org/cborg/-/cborg-1.9.5.tgz" @@ -1339,6 +1356,14 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +deferred-leveldown@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz#39802715fda6ec06d0159a8b28bd1c7e2b1cf0bf" + integrity sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg== + dependencies: + abstract-leveldown "^7.2.0" + inherits "^2.0.3" + define-properties@^1.1.3, define-properties@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" @@ -2536,6 +2561,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.6: version "1.2.7" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" @@ -2931,6 +2961,52 @@ kleur@^3.0.3: resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +level-concat-iterator@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" + integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== + dependencies: + catering "^2.1.0" + +level-errors@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-3.0.1.tgz#4bed48a33108cd83b0e39fdf9bbd84e96fbbef9f" + integrity sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ== + +level-iterator-stream@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz#85b3438e1b4c54ce5aa8c0eb973cfb628117df9e" + integrity sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + +level-supports@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" + integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== + +leveldown@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.1.tgz#0f0e480fa88fd807abf94c33cb7e40966ea4b5ce" + integrity sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A== + dependencies: + abstract-leveldown "^7.2.0" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + +levelup@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-5.1.1.tgz#9f99699f414ac084a3f8a28fc262a1f49cd7a52c" + integrity sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg== + dependencies: + catering "^2.0.0" + deferred-leveldown "^7.0.0" + level-errors "^3.0.1" + level-iterator-stream "^5.0.0" + level-supports "^2.0.1" + queue-microtask "^1.2.3" + levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -3227,6 +3303,11 @@ nanoid@^3.0.2, nanoid@^3.1.20, nanoid@^3.1.23: resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + native-abort-controller@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/native-abort-controller/-/native-abort-controller-1.0.4.tgz" @@ -3656,7 +3737,7 @@ qs@~6.5.2: resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -queue-microtask@^1.2.2: +queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== From e5f3be217cb63b40e4ed3711cba5f3bedf106878 Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 30 Mar 2023 03:20:33 -0300 Subject: [PATCH 09/61] update testing code --- coreLogic.js | 1 + linktree_task.js | 34 +++++++++++++++++++++++++--------- test/get_local_leveldb.js | 8 ++++++++ test/unitTest.js | 4 ++-- 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 test/get_local_leveldb.js diff --git a/coreLogic.js b/coreLogic.js index 378c4b0b..f7b47c6f 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -9,6 +9,7 @@ async task() { // Write the logic to do the work required for submitting the values and optionally store the result in levelDB // run linktree task + console.log("*********task() started*********") const cid = await linktree_task(); if (cid) { await namespaceWrapper.storeSet("cid", cid); // store CID in levelDB diff --git a/linktree_task.js b/linktree_task.js index aa8b7101..ecbff4d6 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -12,15 +12,29 @@ const crypto = require("crypto"); module.exports = async() => { console.log("******/ IN Linktree Task FUNCTION /******"); // Customize linktree test data - const linktree_data = { - "name": "test", - "description": "test description", - "background": "test-image.png", - "links": [ - {"testlink": "http://testapi.com"}, - ], - "user_pubkey": MAIN_ACCOUNT_PUBKEY, - }; + console.log("Getting linktrees list"); + const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + const linktrees_list_object = JSON.parse(linktrees_list_string); + console.log("Getting linktrees list", linktrees_list_object); + + // loop through the linktrees_list to get the userIndex and upload then to web3.storage + const linktrees_list = Object.keys(linktrees_list_object); + for (let i = 0; i < Object.keys(linktrees_list).length; i++) { + const linktrees = linktrees_list[i].data.linktree; + console.log("linktrees", linktrees); + + if (linktrees_list_object[linktrees] == "yes") { + console.log(`${linktrees} was updated so adding that index`); + //fetching the user index of that linktrees + // const linktree_data_string = await namespaceWrapper.storeGet(linktrees); + const linktree_data_array = JSON.parse(linktrees); + console.log("Getting user index", linktree_data_array); + + const linktree_data = {}; + + linktree_data[linktrees] = linktree_data_array; + + console.log('SUBMISSION VALUE', linktree_data); const linktree_data_payload = JSON.stringify(linktree_data); @@ -72,4 +86,6 @@ module.exports = async() => { } else { console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); } + } +} }; diff --git a/test/get_local_leveldb.js b/test/get_local_leveldb.js new file mode 100644 index 00000000..64a79b64 --- /dev/null +++ b/test/get_local_leveldb.js @@ -0,0 +1,8 @@ +const { namespaceWrapper } = require("../namespaceWrapper"); + +async function getLocalLevelDB() { +const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + console.log("Linktrees list string", linktrees_list_string); +} + +getLocalLevelDB(); \ No newline at end of file diff --git a/test/unitTest.js b/test/unitTest.js index 7a23d184..44cfa7b4 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -1,6 +1,6 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); -index() -// coreLogic.task(); +// index() +coreLogic.task(); // const submission = coreLogic.fetchSubmission(); // coreLogic.validateNode(submission, 1); From 04038dcb22083be72cac671ca48d6bf2d73a254a Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 30 Mar 2023 12:15:41 -0300 Subject: [PATCH 10/61] update testing code --- linktree_task.js | 119 +++++++++++++++------------------ namespaceWrapper.js | 2 +- package.json | 1 + test/get_local_leveldb.js | 6 +- test/test_submitLinktree.js | 26 ++++++-- test/unitTest.js | 2 +- test/userIndex/test.json | 1 - yarn.lock | 130 +++++++++++++++++++++++++++++++++++- 8 files changed, 207 insertions(+), 80 deletions(-) delete mode 100644 test/userIndex/test.json diff --git a/linktree_task.js b/linktree_task.js index ecbff4d6..497ff4d4 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -18,74 +18,61 @@ module.exports = async() => { console.log("Getting linktrees list", linktrees_list_object); // loop through the linktrees_list to get the userIndex and upload then to web3.storage - const linktrees_list = Object.keys(linktrees_list_object); - for (let i = 0; i < Object.keys(linktrees_list).length; i++) { - const linktrees = linktrees_list[i].data.linktree; + for (let i = 0; i < linktrees_list_object.length; i++) { + console.log("i", i , "linktrees_list_object.length", linktrees_list_object.length); + const linktrees = linktrees_list_object[i]; console.log("linktrees", linktrees); - if (linktrees_list_object[linktrees] == "yes") { - console.log(`${linktrees} was updated so adding that index`); - //fetching the user index of that linktrees - // const linktree_data_string = await namespaceWrapper.storeGet(linktrees); - const linktree_data_array = JSON.parse(linktrees); - console.log("Getting user index", linktree_data_array); - - const linktree_data = {}; - - linktree_data[linktrees] = linktree_data_array; - - - console.log('SUBMISSION VALUE', linktree_data); - - const linktree_data_payload = JSON.stringify(linktree_data); - - const hashLinktreeIndex = crypto - .createHash("sha256") - .update(linktree_data_payload) - .digest("hex"); - - console.log("HASH OF LINKTREE INDEX", hashLinktreeIndex); - - // singing the payload using the nodes private key and sending the public key along with the payload - const signature = await namespaceWrapper.payloadSigning(hashLinktreeIndex); - - console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); - - const indexSignature = { - data: linktree_data, - signature: signature, - pubKey: MAIN_ACCOUNT_PUBKEY, - }; - - console.log("INDEX SIGNATURE DATA", indexSignature); - - // upload the index of the linktree on web3.storage - const path = `userIndex/test.json`; - console.log("PATH", path); - if (!fs.existsSync("userIndex")) fs.mkdirSync("userIndex"); - await createFile(path, indexSignature); - - if (storageClient) { - const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log("User index uploaded to IPFS: ", cid); - - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); - - // Store the cid in level db - try { - await namespaceWrapper.storeSet("testlinktree", cid); - } catch (err) { - console.log("ERROR IN STORING test linktree", err); - res.status(404).json({ message: "ERROR in storing test linktree" }); + if (linktrees) { + const linktree_data_payload = JSON.stringify(linktrees.data); + + const hashLinktreeIndex = crypto + .createHash("sha256") + .update(linktree_data_payload) + .digest("hex"); + + console.log("HASH OF LINKTREE INDEX", hashLinktreeIndex); + + // singing the payload using the nodes private key and sending the public key along with the payload + // const signature = await namespaceWrapper.payloadSigning(hashLinktreeIndex); + // console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); + + const indexSignature = { + data: linktree_data_payload, + pubKey: MAIN_ACCOUNT_PUBKEY, + // signature: signature, + }; + + console.log("INDEX SIGNATURE DATA", indexSignature); + + // upload the index of the linktree on web3.storage + const path = `userIndex/test.json`; + console.log("PATH", path); + if (!fs.existsSync("userIndex")) fs.mkdirSync("userIndex"); + await createFile(path, indexSignature); + + if (storageClient) { + const file = await getFilesFromPath(path); + // const cid = await storageClient.put(file); + const cid = "testingCID" + i; + console.log("User index uploaded to IPFS: ", cid); + + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); + + // Store the cid in level db + try { + await namespaceWrapper.storeSet("testlinktree", cid); + } catch (err) { + console.log("ERROR IN STORING test linktree", err); + res.status(404).json({ message: "ERROR in storing test linktree" }); + } + + return cid + + } else { + console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + } } - - return cid - - } else { - console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); } - } -} }; diff --git a/namespaceWrapper.js b/namespaceWrapper.js index d44ad21a..4088efc6 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -395,7 +395,7 @@ class NamespaceWrapper { async function instantiateLevelDb() { if(!localLevelDB){ - localLevelDB = levelup(leveldown("./localKOIIDB")); + localLevelDB = levelup(leveldown("/home/soma/code-ie/task-template-linktree/localKOIIDB")); } } diff --git a/package.json b/package.json index 3a17c987..12777f01 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "@_koi/web3.js": "^0.0.6", "@_koii/create-task-cli": "^0.1.12", + "@solana/web3.js": "^1.74.0", "axios": "^0.27.2", "express": "^4.18.1", "leveldown": "^6.1.1", diff --git a/test/get_local_leveldb.js b/test/get_local_leveldb.js index 64a79b64..e613d46d 100644 --- a/test/get_local_leveldb.js +++ b/test/get_local_leveldb.js @@ -1,8 +1,10 @@ const { namespaceWrapper } = require("../namespaceWrapper"); async function getLocalLevelDB() { -const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); - console.log("Linktrees list string", linktrees_list_string); + let linktrees_list_string; + // await namespaceWrapper.storeSet("linktrees", []); + linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + console.log("Linktrees list string", linktrees_list_string); } getLocalLevelDB(); \ No newline at end of file diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 94aaff6a..8f5f327f 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -3,10 +3,20 @@ const {v4: uuidv4} = require('uuid'); const bs58 = require('bs58'); const nacl = require('tweetnacl'); const fs = require("fs") +const solanaWeb3 = require('@solana/web3.js'); +const crypto = require('crypto'); + +// This test submits linktrees from differnet publicKey to the service and stored in localdb +async function main() { try { - const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( - new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) - ); + for (let i = 0; i < 1; i++) { + console.log('i', i); + const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); + // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( + // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) + // ); + const publicKey = publicKeyraw.toBase58(); + console.log('publicKey', publicKey); const payload = { data: { uuid: uuidv4(), @@ -44,7 +54,7 @@ try { ], timestamp: Date.now(), }, - publicKey: bs58.encode(publicKey), + publicKey: publicKey, }; const msg = new TextEncoder().encode(JSON.stringify(payload.data)); payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); @@ -52,7 +62,7 @@ try { // Check payload console.log(payload); - axios + await axios .post('http://localhost:10000/register-linktree', {payload}) .then((e) => { if (e.status != 200) { @@ -63,6 +73,10 @@ try { .catch((e) => { console.error(e); }); + } } catch (e) { console.error(e) -} \ No newline at end of file +} +} + +main(); \ No newline at end of file diff --git a/test/unitTest.js b/test/unitTest.js index 44cfa7b4..1fe46bb8 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -1,6 +1,6 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); -// index() + coreLogic.task(); // const submission = coreLogic.fetchSubmission(); // coreLogic.validateNode(submission, 1); diff --git a/test/userIndex/test.json b/test/userIndex/test.json deleted file mode 100644 index 21b48635..00000000 --- a/test/userIndex/test.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"name":"test","description":"test description","background":"test-image.png","links":[{"testlink":"http://testapi.com"}]},"signature":{"error":{"message":"Request failed with status code 422","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json","User-Agent":"axios/0.27.2","Content-Length":88},"method":"post","url":"http://localhost:8080/namespace-wrapper","data":"{\"args\":[\"signData\",\"685b6c67c4b593e7ccd0e7a9d597244d176d87588c8ff0ffd1f5160c0fc9ce4d\"]}"},"code":"ERR_BAD_REQUEST","status":422}}} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 7b0a6be1..f13b103e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -217,11 +217,26 @@ resolved "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.1.tgz" integrity sha512-Rk4SkJFaXZiznFyC/t77Q0NKS4FL7TLJJsVG2V2oiEq3kJVeTdxysEe/yRWSpnWMe808XRDJ+VFh5pt/FN5plw== +"@noble/ed25519@^1.7.0": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" + integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== + +"@noble/hashes@^1.1.2": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" + integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== + "@noble/secp256k1@^1.3.0": version "1.7.0" resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.0.tgz" integrity sha512-kbacwGSsH/CTout0ZnZWxnW1B+jH/7r/WAAKLBtrRJ/+CUH7lgmQzl3GTrQua3SGKWNSDsS6lmjnDpIJ5Dxyaw== +"@noble/secp256k1@^1.6.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -310,6 +325,28 @@ dependencies: buffer "~6.0.3" +"@solana/web3.js@^1.74.0": + version "1.74.0" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.74.0.tgz#dbcbeabb830dd7cbbcf5e31404ca79c9785cbf2d" + integrity sha512-RKZyPqizPCxmpMGfpu4fuplNZEWCrhRBjjVstv5QnAJvgln1jgOfgui+rjl1ExnqDnWKg9uaZ5jtGROH/cwabg== + dependencies: + "@babel/runtime" "^7.12.5" + "@noble/ed25519" "^1.7.0" + "@noble/hashes" "^1.1.2" + "@noble/secp256k1" "^1.6.3" + "@solana/buffer-layout" "^4.0.0" + agentkeepalive "^4.2.1" + bigint-buffer "^1.1.5" + bn.js "^5.0.0" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.1" + fast-stable-stringify "^1.0.0" + jayson "^3.4.4" + node-fetch "^2.6.7" + rpc-websockets "^7.5.1" + superstruct "^0.14.2" + "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" @@ -743,6 +780,15 @@ acorn@^8.5.0, acorn@^8.7.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +agentkeepalive@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" + integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== + dependencies: + debug "^4.1.0" + depd "^2.0.0" + humanize-ms "^1.2.1" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" @@ -937,6 +983,20 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz" @@ -1014,6 +1074,15 @@ borsh@^0.6.0: bs58 "^4.0.0" text-encoding-utf-8 "^1.0.2" +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1324,7 +1393,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1382,7 +1451,7 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@2.0.0: +depd@2.0.0, depd@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -1918,6 +1987,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz" @@ -1937,6 +2011,11 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + files-from-path@^0.2.4: version "0.2.6" resolved "https://registry.npmjs.org/files-from-path/-/files-from-path-0.2.6.tgz" @@ -2268,6 +2347,13 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -3255,7 +3341,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3350,6 +3436,13 @@ node-fetch@2.6.7, node-fetch@^2.6.1, "node-fetch@https://registry.npmjs.org/@ach resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g== +node-fetch@^2.6.7: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1.2.1: version "1.3.1" resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" @@ -3971,6 +4064,19 @@ rpc-websockets@^7.4.2: bufferutil "^4.0.1" utf-8-validate "^5.0.2" +rpc-websockets@^7.5.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.5.1.tgz#e0a05d525a97e7efc31a0617f093a13a2e10c401" + integrity sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w== + dependencies: + "@babel/runtime" "^7.17.2" + eventemitter3 "^4.0.7" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -4435,6 +4541,11 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" @@ -4710,6 +4821,11 @@ web3.storage@^4.4.0: uint8arrays "^3.0.0" w3name "^1.0.4" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webpack-cli@^4.5.0: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" @@ -4771,6 +4887,14 @@ webpack@^5.28.0: watchpack "^2.4.0" webpack-sources "^3.2.3" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" From 656d03575ba7f74a48cd1f805b15f26f6f4c713e Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 30 Mar 2023 17:00:30 -0300 Subject: [PATCH 11/61] update cidValidation --- helpers/dataFromCid.js | 2 +- linktree_task.js | 2 +- test/test_cidCreation.js | 58 +++++++++++++++++++++++++++++++++++++ test/test_cidValidation.js | 42 +++++++++++++++++++++++++++ test/test_index.js | 18 ++++++++++++ test/test_submitLinktree.js | 6 ++-- 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 test/test_cidCreation.js create mode 100644 test/test_cidValidation.js create mode 100644 test/test_index.js diff --git a/helpers/dataFromCid.js b/helpers/dataFromCid.js index 6924803a..278e0204 100644 --- a/helpers/dataFromCid.js +++ b/helpers/dataFromCid.js @@ -1,7 +1,7 @@ const axios = require("axios"); const { Web3Storage, getFilesFromPath } = require("web3.storage"); const storageClient = new Web3Storage({ - token: process.env.SECRET_WEB3_STORAGE_KEY, + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", }); module.exports = async (cid) => { diff --git a/linktree_task.js b/linktree_task.js index 497ff4d4..a6be1d0b 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -38,7 +38,7 @@ module.exports = async() => { // console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); const indexSignature = { - data: linktree_data_payload, + data: linktree_data_payloalinktrees_list_object.lengthd, pubKey: MAIN_ACCOUNT_PUBKEY, // signature: signature, }; diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js new file mode 100644 index 00000000..761588bc --- /dev/null +++ b/test/test_cidCreation.js @@ -0,0 +1,58 @@ +const createFile = require("../helpers/createFile.js"); +const deleteFile = require("../helpers/deleteFile"); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const { namespaceWrapper } = require("../namespaceWrapper"); +const fs = require("fs"); +const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const crypto = require("crypto"); +const storageClient = new Web3Storage({ + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", + }); + +async function cidcreation(){ + // Get linktree list fron localdb + const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + const linktrees_list_object = JSON.parse(linktrees_list_string); + console.log("Getting linktrees list", linktrees_list_object); + + const msg = new TextEncoder().encode(JSON.stringify(linktrees_list_object)); + const secretKey = nacl.sign.keyPair().secretKey; + const signature = nacl.sign.detached(msg, secretKey); + console.log('Check Signature:', bs58.encode(signature)); + const publicKey = nacl.sign.keyPair().publicKey; + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + } + // upload the index of the linktree on web3.storage + const path = `testLinktree/test.json`; + console.log("PATH", path); + if (!fs.existsSync("testLinktree")) fs.mkdirSync("testLinktree"); + await createFile(path, submission_value); + + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log("User Linktrees uploaded to IPFS: ", cid); + + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); + + // Store the cid in localdb + try { + await namespaceWrapper.storeSet("testlinktree", cid); + } catch (err) { + console.log("ERROR IN STORING test linktree", err); + res.status(404).json({ message: "ERROR in storing test linktree" }); + } + + return cid + } else { + console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + } +} + +cidcreation() +module.exports = cidcreation; diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js new file mode 100644 index 00000000..ce02d7c8 --- /dev/null +++ b/test/test_cidValidation.js @@ -0,0 +1,42 @@ +const { namespaceWrapper } = require("../namespaceWrapper"); +const dataFromCid = require("../helpers/dataFromCid"); +const getKeys = require("../helpers/getKey"); +const hashCompare = require("../helpers/hashCompare"); +const crypto = require('crypto'); + +let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" +async function test_cidValidation(submission_value) { + // const cid = submission_value; + const output = await dataFromCid(submission_value); + console.log("RESPONSE DATA", output.data); + // for () + try { + const linktreeIndexData = output.data.data; + const publicKey = output.data.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.data.signature; + console.log("SIGNATURE", signature); + if (!output.data || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; + } + + // verify the signature + const check = await verifySignature( signature, linktreeIndexData, publicKey); + console.log("CHECK", check); + + + } catch { + console.log("ERROR"); + } +} + +async function verifySignature( signature, linktreeIndexData, publicKey) { + const verifier = crypto.createVerify('SHA256'); + verifier.update(linktreeIndexData); + return verifier.verify(publicKey, signature, 'base64'); +} + +module.exports = test_cidValidation; + +test_cidValidation(submission_value); \ No newline at end of file diff --git a/test/test_index.js b/test/test_index.js new file mode 100644 index 00000000..e7d13909 --- /dev/null +++ b/test/test_index.js @@ -0,0 +1,18 @@ +const test_submission = require('./test_submitLinktree'); +const test_cidCreation = require('./test_cidCreation'); +const test_cidValidation = require('./test_cidValidation'); +const { namespaceWrapper } = require("../namespaceWrapper"); + +async function test() { + // 1 test submission + await test_submission(); + // 2 test the cid creation (CID need to contain all of the linktree data and signature) + await test_cidCreation(); + const cid = await namespaceWrapper.storeGet("cid"); + // 3 test the validation of the cid + await test_cidValidation(cid); + // 4 iterate over the cid and create distribution + // 5 audit the distribution +} + +test(); \ No newline at end of file diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 8f5f327f..0acbeec0 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -9,7 +9,7 @@ const crypto = require('crypto'); // This test submits linktrees from differnet publicKey to the service and stored in localdb async function main() { try { - for (let i = 0; i < 1; i++) { + for (let i = 0; i < 5; i++) { console.log('i', i); const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( @@ -79,4 +79,6 @@ try { } } -main(); \ No newline at end of file +main(); + +module.exports = main; \ No newline at end of file From 5b674e744bc46d56764e258042e5de3ee5949efa Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 30 Mar 2023 17:22:38 -0300 Subject: [PATCH 12/61] update testing --- test/test_cidValidation.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js index ce02d7c8..f0ea555a 100644 --- a/test/test_cidValidation.js +++ b/test/test_cidValidation.js @@ -2,7 +2,7 @@ const { namespaceWrapper } = require("../namespaceWrapper"); const dataFromCid = require("../helpers/dataFromCid"); const getKeys = require("../helpers/getKey"); const hashCompare = require("../helpers/hashCompare"); -const crypto = require('crypto'); +const nacl = require('tweetnacl'); let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" async function test_cidValidation(submission_value) { @@ -22,7 +22,8 @@ async function test_cidValidation(submission_value) { } // verify the signature - const check = await verifySignature( signature, linktreeIndexData, publicKey); + const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(linktreeIndexData)); + const check = await verifySignature(linktreeIndexDataUint8Array, signature, publicKey); console.log("CHECK", check); @@ -31,10 +32,8 @@ async function test_cidValidation(submission_value) { } } -async function verifySignature( signature, linktreeIndexData, publicKey) { - const verifier = crypto.createVerify('SHA256'); - verifier.update(linktreeIndexData); - return verifier.verify(publicKey, signature, 'base64'); +async function verifySignature(linktreeIndexData, signature, publicKey) { + return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); } module.exports = test_cidValidation; From 5b0f5f592d9c4629e1d4693dc01ba3126fa97eb6 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 11:15:00 -0300 Subject: [PATCH 13/61] fix a bug --- linktree_task.js | 2 +- test/test_cidCreation.js | 2 +- test/test_cidValidation.js | 6 +-- test/test_index.js | 98 +++++++++++++++++++++++++++++++++++--- 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/linktree_task.js b/linktree_task.js index a6be1d0b..497ff4d4 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -38,7 +38,7 @@ module.exports = async() => { // console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); const indexSignature = { - data: linktree_data_payloalinktrees_list_object.lengthd, + data: linktree_data_payload, pubKey: MAIN_ACCOUNT_PUBKEY, // signature: signature, }; diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js index 761588bc..6a878f0f 100644 --- a/test/test_cidCreation.js +++ b/test/test_cidCreation.js @@ -5,12 +5,12 @@ const nacl = require('tweetnacl'); const { namespaceWrapper } = require("../namespaceWrapper"); const fs = require("fs"); const { Web3Storage, getFilesFromPath } = require("web3.storage"); -const crypto = require("crypto"); const storageClient = new Web3Storage({ token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", }); async function cidcreation(){ + console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); // Get linktree list fron localdb const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); const linktrees_list_object = JSON.parse(linktrees_list_string); diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js index f0ea555a..db779be1 100644 --- a/test/test_cidValidation.js +++ b/test/test_cidValidation.js @@ -4,9 +4,9 @@ const getKeys = require("../helpers/getKey"); const hashCompare = require("../helpers/hashCompare"); const nacl = require('tweetnacl'); -let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" +// let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" async function test_cidValidation(submission_value) { - // const cid = submission_value; + console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); const output = await dataFromCid(submission_value); console.log("RESPONSE DATA", output.data); // for () @@ -22,7 +22,7 @@ async function test_cidValidation(submission_value) { } // verify the signature - const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(linktreeIndexData)); + const linktreeIndexDataUint8Array = new TextEncoder().encode(JSON.stringify(linktreeIndexData)); const check = await verifySignature(linktreeIndexDataUint8Array, signature, publicKey); console.log("CHECK", check); diff --git a/test/test_index.js b/test/test_index.js index e7d13909..19608f9a 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -1,18 +1,102 @@ -const test_submission = require('./test_submitLinktree'); -const test_cidCreation = require('./test_cidCreation'); -const test_cidValidation = require('./test_cidValidation'); const { namespaceWrapper } = require("../namespaceWrapper"); +const createFile = require("../helpers/createFile.js"); +const deleteFile = require("../helpers/deleteFile"); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const fs = require("fs"); +const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const storageClient = new Web3Storage({ + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", + }); +const dataFromCid = require("../helpers/dataFromCid"); async function test() { // 1 test submission - await test_submission(); + // await test_submission(); // 2 test the cid creation (CID need to contain all of the linktree data and signature) - await test_cidCreation(); - const cid = await namespaceWrapper.storeGet("cid"); + const cid = await cidCreation(); // 3 test the validation of the cid - await test_cidValidation(cid); + const check = await cidValidation(cid) // 4 iterate over the cid and create distribution // 5 audit the distribution } + +async function cidCreation(){ + console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); + // Get linktree list fron localdb + const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + const linktrees_list_object = JSON.parse(linktrees_list_string); + + const msg = new TextEncoder().encode(JSON.stringify(linktrees_list_object)); + console.log("MSG", msg); + const secretKey = nacl.sign.keyPair().secretKey; + const signature = nacl.sign.detached(msg, secretKey); + console.log('Check Signature:', bs58.encode(signature)); + const publicKey = nacl.sign.keyPair().publicKey; + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + } + // upload the index of the linktree on web3.storage + const path = `testLinktree/test.json`; + console.log("PATH", path); + if (!fs.existsSync("testLinktree")) fs.mkdirSync("testLinktree"); + await createFile(path, submission_value); + + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log("User Linktrees uploaded to IPFS: ", cid); + + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); + + // Store the cid in localdb + try { + await namespaceWrapper.storeSet("testlinktree", cid); + } catch (err) { + console.log("ERROR IN STORING test linktree", err); + res.status(404).json({ message: "ERROR in storing test linktree" }); + } + return cid + } else { + console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + } +} + + +async function cidValidation(submission_value) { + console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); + const output = await dataFromCid(submission_value); + console.log("RESPONSE DATA", output.data); + // for () + try { + const linktreeIndexData = output.data.data; + const publicKey = output.data.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.data.signature; + console.log("SIGNATURE", signature); + if (!output.data || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; + } + + // verify the signature + const linktreeIndexDataUint8Array = new TextEncoder().encode(JSON.stringify(linktreeIndexData)); + console.log("MSG wait to verify", linktreeIndexDataUint8Array); + const check = await verifySignature(linktreeIndexDataUint8Array, signature, publicKey); + console.log("CHECK", check); + + return check; + + } catch { + console.log("ERROR"); + } +} + +async function verifySignature(linktreeIndexData, signature, publicKey) { + return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); +} test(); \ No newline at end of file From d94d3d3b75e0df83e6ba2dbf8d535b9733e71117 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 12:09:20 -0300 Subject: [PATCH 14/61] update test code --- test/test_index.js | 51 ++++++++++++------------- test/test_nacl.js | 54 +++++++++++++++++++++++++++ test/test_withoutCID.js | 83 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 test/test_nacl.js create mode 100644 test/test_withoutCID.js diff --git a/test/test_index.js b/test/test_index.js index 19608f9a..ae350dd8 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -28,12 +28,16 @@ async function cidCreation(){ const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); const linktrees_list_object = JSON.parse(linktrees_list_string); - const msg = new TextEncoder().encode(JSON.stringify(linktrees_list_object)); - console.log("MSG", msg); const secretKey = nacl.sign.keyPair().secretKey; - const signature = nacl.sign.detached(msg, secretKey); - console.log('Check Signature:', bs58.encode(signature)); const publicKey = nacl.sign.keyPair().publicKey; + + const msg = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + console.log("MSG", msg); + + const signedMessage = nacl.sign(msg, secretKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + // console.log('Check Signature:', bs58.encode(signature)); + const submission_value = { data: linktrees_list_object, publicKey: bs58.encode(publicKey), @@ -72,28 +76,25 @@ async function cidValidation(submission_value) { const output = await dataFromCid(submission_value); console.log("RESPONSE DATA", output.data); // for () - try { - const linktreeIndexData = output.data.data; - const publicKey = output.data.publicKey; - console.log("PUBLIC KEY", publicKey); - const signature = output.data.signature; - console.log("SIGNATURE", signature); - if (!output.data || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } - - // verify the signature - const linktreeIndexDataUint8Array = new TextEncoder().encode(JSON.stringify(linktreeIndexData)); - console.log("MSG wait to verify", linktreeIndexDataUint8Array); - const check = await verifySignature(linktreeIndexDataUint8Array, signature, publicKey); - console.log("CHECK", check); - - return check; - - } catch { - console.log("ERROR"); + const linktreeIndexData = output.data.data; + const publicKey = output.data.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.data.signature; + console.log("SIGNATURE", signature); + if (!output.data || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; } + + // verify the signature + const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktreeIndexData))); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + // console.log("Data wait to verify", linktreeIndexDataUint8Array); + const check = await verifySignature(linktreeIndexDataUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${check}`); + + return check; } async function verifySignature(linktreeIndexData, signature, publicKey) { diff --git a/test/test_nacl.js b/test/test_nacl.js new file mode 100644 index 00000000..03d3ebd1 --- /dev/null +++ b/test/test_nacl.js @@ -0,0 +1,54 @@ +// test nacl verified + +const nacl = require('tweetnacl'); +const bs58 = require('bs58'); + +async function test_main() { + const submission_value = await generateAndSubmitDistributionList(); + await validate(submission_value); +} + +async function generateAndSubmitDistributionList() { + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; + + const message = { + data: "data", + publicKey: '7AwybFMYogGa8LJ3n9i8QthUs6ybEcanC8UPejM76U7h', + signature: 'P6McSGFMniTdaH5546b8b1xuL91UtjxS9RnXMxBcg8ewuvKuFwijqJHH9BSZnEnqs1niE1xx7DreRVCNqK4ZJSE' + }; + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(message))); + + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + + const submission_value = { + data: message, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + } + return submission_value +} + +async function validate(submission_value) { + const output = submission_value + console.log("RESPONSE DATA", output.data); + const publicKey = output.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.signature; + console.log("SIGNATURE", signature); + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(message))); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${isSignatureValid}`); +} + +async function verifySignature(message, signature, publicKey) { + return nacl.sign.detached.verify(message, signature, publicKey); +} + +test_main(); + diff --git a/test/test_withoutCID.js b/test/test_withoutCID.js new file mode 100644 index 00000000..1c413377 --- /dev/null +++ b/test/test_withoutCID.js @@ -0,0 +1,83 @@ +// test validation without cid +const { namespaceWrapper } = require("../namespaceWrapper"); +const createFile = require("../helpers/createFile.js"); +const deleteFile = require("../helpers/deleteFile"); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const fs = require("fs"); +const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const storageClient = new Web3Storage({ + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", + }); +const dataFromCid = require("../helpers/dataFromCid"); + +async function test() { + // 1 test submission + // await test_submission(); + // 2 test the cid creation (CID need to contain all of the linktree data and signature) + const submission_value = await cidCreation(); + // 3 test the validation of the cid + const check = await cidValidation(submission_value) + // 4 iterate over the cid and create distribution + // 5 audit the distribution +} + + +async function cidCreation(){ + console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); + // Get linktree list fron localdb + // const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + + const linktrees_list_object = { + data: "data", + publicKey: '7AwybFMYogGa8LJ3n9i8QthUs6ybEcanC8UPejM76U7h', + signature: 'P6McSGFMniTdaH5546b8b1xuL91UtjxS9RnXMxBcg8ewuvKuFwijqJHH9BSZnEnqs1niE1xx7DreRVCNqK4ZJSE' + }; + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + const secretKey = nacl.sign.keyPair().secretKey; + const publicKey = nacl.sign.keyPair().publicKey; + + const signedMessage = nacl.sign(messageUint8Array, secretKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + // console.log('Check Signature:', bs58.encode(signature)); + + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + } + // upload the index of the linktree on web3.storage + return submission_value +} + + +async function cidValidation(submission_value) { + console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); + const output = submission_value + console.log("RESPONSE DATA", output.data); + // for () + const linktreeIndexData = output.data; + const publicKey = output.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.signature; + console.log("SIGNATURE", signature); + if (!output.data || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; + } + + // verify the signature + const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktreeIndexData))); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + // console.log("Data wait to verify", linktreeIndexDataUint8Array); + const check = await verifySignature(linktreeIndexDataUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${check}`); + + return check; +} + +async function verifySignature(linktreeIndexData, signature, publicKey) { + return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); +} +test(); \ No newline at end of file From 6fea835ce9df38b03b34c51d22ba1eb3a034ebdc Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 12:41:31 -0300 Subject: [PATCH 15/61] validation pass --- test/test_index.js | 41 ++++++++++++++++++++--------------------- test/test_nacl.js | 3 ++- test/test_withoutCID.js | 35 ++++++++++++++++------------------- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/test/test_index.js b/test/test_index.js index ae350dd8..648fd306 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -24,19 +24,16 @@ async function test() { async function cidCreation(){ console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; // Get linktree list fron localdb const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); const linktrees_list_object = JSON.parse(linktrees_list_string); - const secretKey = nacl.sign.keyPair().secretKey; - const publicKey = nacl.sign.keyPair().publicKey; - - const msg = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - console.log("MSG", msg); - - const signedMessage = nacl.sign(msg, secretKey); + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + const signedMessage = nacl.sign(messageUint8Array, privateKey); const signature = signedMessage.slice(0, nacl.sign.signatureLength); - // console.log('Check Signature:', bs58.encode(signature)); const submission_value = { data: linktrees_list_object, @@ -73,28 +70,30 @@ async function cidCreation(){ async function cidValidation(submission_value) { console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); - const output = await dataFromCid(submission_value); - console.log("RESPONSE DATA", output.data); + const outputraw = await dataFromCid(submission_value); + const output = outputraw.data // for () - const linktreeIndexData = output.data.data; - const publicKey = output.data.publicKey; + const linktrees_list_object = output.data; + console.log("RESPONSE DATA", linktrees_list_object); + const publicKey = output.publicKey; console.log("PUBLIC KEY", publicKey); - const signature = output.data.signature; + const signature = output.signature; console.log("SIGNATURE", signature); - if (!output.data || !signature || !publicKey) { + + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + if (!linktrees_list_object || !signature || !publicKey) { console.error("No data received from web3.storage"); return false; } // verify the signature - const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktreeIndexData))); - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); - // console.log("Data wait to verify", linktreeIndexDataUint8Array); - const check = await verifySignature(linktreeIndexDataUint8Array, signatureUint8Array, publicKeyUint8Array); - console.log(`Is the signature valid? ${check}`); + const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${isSignatureValid}`); - return check; + return isSignatureValid; } async function verifySignature(linktreeIndexData, signature, publicKey) { diff --git a/test/test_nacl.js b/test/test_nacl.js index 03d3ebd1..d1c66b64 100644 --- a/test/test_nacl.js +++ b/test/test_nacl.js @@ -33,7 +33,8 @@ async function generateAndSubmitDistributionList() { async function validate(submission_value) { const output = submission_value - console.log("RESPONSE DATA", output.data); + const message = output.data; + console.log("RESPONSE DATA", message); const publicKey = output.publicKey; console.log("PUBLIC KEY", publicKey); const signature = output.signature; diff --git a/test/test_withoutCID.js b/test/test_withoutCID.js index 1c413377..a512537d 100644 --- a/test/test_withoutCID.js +++ b/test/test_withoutCID.js @@ -25,8 +25,9 @@ async function test() { async function cidCreation(){ console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); - // Get linktree list fron localdb - // const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; const linktrees_list_object = { data: "data", @@ -34,10 +35,7 @@ async function cidCreation(){ signature: 'P6McSGFMniTdaH5546b8b1xuL91UtjxS9RnXMxBcg8ewuvKuFwijqJHH9BSZnEnqs1niE1xx7DreRVCNqK4ZJSE' }; const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const secretKey = nacl.sign.keyPair().secretKey; - const publicKey = nacl.sign.keyPair().publicKey; - - const signedMessage = nacl.sign(messageUint8Array, secretKey); + const signedMessage = nacl.sign(messageUint8Array, privateKey); const signature = signedMessage.slice(0, nacl.sign.signatureLength); // console.log('Check Signature:', bs58.encode(signature)); @@ -54,27 +52,26 @@ async function cidCreation(){ async function cidValidation(submission_value) { console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); const output = submission_value - console.log("RESPONSE DATA", output.data); - // for () - const linktreeIndexData = output.data; + const linktrees_list_object = output.data; + console.log("RESPONSE DATA", linktrees_list_object); const publicKey = output.publicKey; console.log("PUBLIC KEY", publicKey); const signature = output.signature; console.log("SIGNATURE", signature); - if (!output.data || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } - - // verify the signature - const linktreeIndexDataUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktreeIndexData))); + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); const signatureUint8Array = bs58.decode(signature); const publicKeyUint8Array = bs58.decode(publicKey); + // if (!output.data || !signature || !publicKey) { + // console.error("No data received from web3.storage"); + // return false; + // } + + // verify the signature // console.log("Data wait to verify", linktreeIndexDataUint8Array); - const check = await verifySignature(linktreeIndexDataUint8Array, signatureUint8Array, publicKeyUint8Array); - console.log(`Is the signature valid? ${check}`); + const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${isSignatureValid}`); - return check; + return isSignatureValid; } async function verifySignature(linktreeIndexData, signature, publicKey) { From 2d3dd704701065587d11862326962959108f31ae Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 12:44:53 -0300 Subject: [PATCH 16/61] update code params --- test/test_cidCreation.js | 14 ++++++------ test/test_cidValidation.js | 45 +++++++++++++++++++------------------- test/test_index.js | 4 ++-- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js index 6a878f0f..c7994f35 100644 --- a/test/test_cidCreation.js +++ b/test/test_cidCreation.js @@ -11,16 +11,17 @@ const storageClient = new Web3Storage({ async function cidcreation(){ console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; // Get linktree list fron localdb const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); const linktrees_list_object = JSON.parse(linktrees_list_string); - console.log("Getting linktrees list", linktrees_list_object); - const msg = new TextEncoder().encode(JSON.stringify(linktrees_list_object)); - const secretKey = nacl.sign.keyPair().secretKey; - const signature = nacl.sign.detached(msg, secretKey); - console.log('Check Signature:', bs58.encode(signature)); - const publicKey = nacl.sign.keyPair().publicKey; + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + const submission_value = { data: linktrees_list_object, publicKey: bs58.encode(publicKey), @@ -47,7 +48,6 @@ async function cidcreation(){ console.log("ERROR IN STORING test linktree", err); res.status(404).json({ message: "ERROR in storing test linktree" }); } - return cid } else { console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js index db779be1..7d551cf0 100644 --- a/test/test_cidValidation.js +++ b/test/test_cidValidation.js @@ -7,33 +7,34 @@ const nacl = require('tweetnacl'); // let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" async function test_cidValidation(submission_value) { console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); - const output = await dataFromCid(submission_value); - console.log("RESPONSE DATA", output.data); + const outputraw = await dataFromCid(submission_value); + const output = outputraw.data // for () - try { - const linktreeIndexData = output.data.data; - const publicKey = output.data.publicKey; - console.log("PUBLIC KEY", publicKey); - const signature = output.data.signature; - console.log("SIGNATURE", signature); - if (!output.data || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } + const linktrees_list_object = output.data; + console.log("RESPONSE DATA", linktrees_list_object); + const publicKey = output.publicKey; + console.log("PUBLIC KEY", publicKey); + const signature = output.signature; + console.log("SIGNATURE", signature); - // verify the signature - const linktreeIndexDataUint8Array = new TextEncoder().encode(JSON.stringify(linktreeIndexData)); - const check = await verifySignature(linktreeIndexDataUint8Array, signature, publicKey); - console.log("CHECK", check); - - - } catch { - console.log("ERROR"); + const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + if (!linktrees_list_object || !signature || !publicKey) { + console.error("No data received from web3.storage"); + return false; } + + // verify the signature + const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); + console.log(`Is the signature valid? ${isSignatureValid}`); + + return isSignatureValid; } -async function verifySignature(linktreeIndexData, signature, publicKey) { - return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); +async function verifySignature(message, signature, publicKey) { + return nacl.sign.detached.verify(message, signature, publicKey); } module.exports = test_cidValidation; diff --git a/test/test_index.js b/test/test_index.js index 648fd306..ed5c67e6 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -96,7 +96,7 @@ async function cidValidation(submission_value) { return isSignatureValid; } -async function verifySignature(linktreeIndexData, signature, publicKey) { - return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); +async function verifySignature(message, signature, publicKey) { + return nacl.sign.detached.verify(message, signature, publicKey); } test(); \ No newline at end of file From ae179d1f6918a6aad99fb3a62e3fd8e4edae11f1 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 13:15:23 -0300 Subject: [PATCH 17/61] update syed code --- test/test_cidCreation.js | 93 ++++++++++---------- test/test_cidValidation.js | 68 ++++++++------- test/test_index.js | 165 +++++++++++++++++++----------------- test/test_submitLinktree.js | 15 ---- test/unitTest.js | 27 +++++- 5 files changed, 195 insertions(+), 173 deletions(-) diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js index c7994f35..f6de80ae 100644 --- a/test/test_cidCreation.js +++ b/test/test_cidCreation.js @@ -1,58 +1,61 @@ -const createFile = require("../helpers/createFile.js"); -const deleteFile = require("../helpers/deleteFile"); +const createFile = require('../helpers/createFile.js'); +const deleteFile = require('../helpers/deleteFile'); const bs58 = require('bs58'); const nacl = require('tweetnacl'); -const { namespaceWrapper } = require("../namespaceWrapper"); -const fs = require("fs"); -const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const { namespaceWrapper } = require('../namespaceWrapper'); +const fs = require('fs'); +const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", - }); + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', +}); -async function cidcreation(){ - console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; - // Get linktree list fron localdb - const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); - const linktrees_list_object = JSON.parse(linktrees_list_string); +async function cidcreation() { + console.log('******/ TEST Linktree CID CREATION Task FUNCTION /******'); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; + // Get linktree list fron localdb + const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); + const linktrees_list_object = JSON.parse(linktrees_list_string); - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signedMessage = nacl.sign(messageUint8Array, privateKey); - const signature = signedMessage.slice(0, nacl.sign.signatureLength); + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); - const submission_value = { - data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), - } - // upload the index of the linktree on web3.storage - const path = `testLinktree/test.json`; - console.log("PATH", path); - if (!fs.existsSync("testLinktree")) fs.mkdirSync("testLinktree"); - await createFile(path, submission_value); + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + }; + // upload the index of the linktree on web3.storage + const path = `testLinktree/test.json`; + console.log('PATH', path); + if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); + await createFile(path, submission_value); - if (storageClient) { - const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log("User Linktrees uploaded to IPFS: ", cid); + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log('User Linktrees uploaded to IPFS: ', cid); - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); - // Store the cid in localdb - try { - await namespaceWrapper.storeSet("testlinktree", cid); - } catch (err) { - console.log("ERROR IN STORING test linktree", err); - res.status(404).json({ message: "ERROR in storing test linktree" }); - } - return cid - } else { - console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + // Store the cid in localdb + try { + await namespaceWrapper.storeSet('testlinktree', cid); + } catch (err) { + console.log('ERROR IN STORING test linktree', err); + res.status(404).json({ message: 'ERROR in storing test linktree' }); } + return cid; + } else { + console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); + } } -cidcreation() +cidcreation(); module.exports = cidcreation; diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js index 7d551cf0..60fa72b2 100644 --- a/test/test_cidValidation.js +++ b/test/test_cidValidation.js @@ -1,42 +1,48 @@ -const { namespaceWrapper } = require("../namespaceWrapper"); -const dataFromCid = require("../helpers/dataFromCid"); -const getKeys = require("../helpers/getKey"); -const hashCompare = require("../helpers/hashCompare"); +const { namespaceWrapper } = require('../namespaceWrapper'); +const dataFromCid = require('../helpers/dataFromCid'); +const getKeys = require('../helpers/getKey'); +const hashCompare = require('../helpers/hashCompare'); const nacl = require('tweetnacl'); // let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" async function test_cidValidation(submission_value) { - console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); - const outputraw = await dataFromCid(submission_value); - const output = outputraw.data - // for () - const linktrees_list_object = output.data; - console.log("RESPONSE DATA", linktrees_list_object); - const publicKey = output.publicKey; - console.log("PUBLIC KEY", publicKey); - const signature = output.signature; - console.log("SIGNATURE", signature); - - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); - - if (!linktrees_list_object || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } - - // verify the signature - const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); - console.log(`Is the signature valid? ${isSignatureValid}`); - - return isSignatureValid; + console.log('******/ TEST Linktree CID VALIDATION Task FUNCTION /******'); + const outputraw = await dataFromCid(submission_value); + const output = outputraw.data; + // for () + const linktrees_list_object = output.data; + console.log('RESPONSE DATA', linktrees_list_object); + const publicKey = output.publicKey; + console.log('PUBLIC KEY', publicKey); + const signature = output.signature; + console.log('SIGNATURE', signature); + + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + if (!linktrees_list_object || !signature || !publicKey) { + console.error('No data received from web3.storage'); + return false; + } + + // verify the signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log(`Is the signature valid? ${isSignatureValid}`); + + return isSignatureValid; } async function verifySignature(message, signature, publicKey) { - return nacl.sign.detached.verify(message, signature, publicKey); + return nacl.sign.detached.verify(message, signature, publicKey); } module.exports = test_cidValidation; -test_cidValidation(submission_value); \ No newline at end of file +test_cidValidation(submission_value); diff --git a/test/test_index.js b/test/test_index.js index ed5c67e6..6a103a24 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -1,102 +1,109 @@ -const { namespaceWrapper } = require("../namespaceWrapper"); -const createFile = require("../helpers/createFile.js"); -const deleteFile = require("../helpers/deleteFile"); +const { namespaceWrapper } = require('../namespaceWrapper'); +const createFile = require('../helpers/createFile.js'); +const deleteFile = require('../helpers/deleteFile'); const bs58 = require('bs58'); const nacl = require('tweetnacl'); -const fs = require("fs"); -const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const fs = require('fs'); +const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", - }); -const dataFromCid = require("../helpers/dataFromCid"); + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', +}); +const dataFromCid = require('../helpers/dataFromCid'); async function test() { - // 1 test submission - // await test_submission(); - // 2 test the cid creation (CID need to contain all of the linktree data and signature) - const cid = await cidCreation(); - // 3 test the validation of the cid - const check = await cidValidation(cid) - // 4 iterate over the cid and create distribution - // 5 audit the distribution + // 1 test submission + // await test_submission(); + // 2 test the cid creation (CID need to contain all of the linktree data and signature) + const cid = await cidCreation(); + // 3 test the validation of the cid + const check = await cidValidation(cid); + // 4 iterate over the cid and create distribution + // 5 audit the distribution } +async function cidCreation() { + console.log('******/ TEST Linktree CID CREATION Task FUNCTION /******'); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; + // Get linktree list fron localdb + const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); + const linktrees_list_object = JSON.parse(linktrees_list_string); -async function cidCreation(){ - console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; - // Get linktree list fron localdb - const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); - const linktrees_list_object = JSON.parse(linktrees_list_string); + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signedMessage = nacl.sign(messageUint8Array, privateKey); - const signature = signedMessage.slice(0, nacl.sign.signatureLength); + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + }; + // upload the index of the linktree on web3.storage + const path = `testLinktree/test.json`; + console.log('PATH', path); + if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); + await createFile(path, submission_value); - const submission_value = { - data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), - } - // upload the index of the linktree on web3.storage - const path = `testLinktree/test.json`; - console.log("PATH", path); - if (!fs.existsSync("testLinktree")) fs.mkdirSync("testLinktree"); - await createFile(path, submission_value); - - if (storageClient) { - const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log("User Linktrees uploaded to IPFS: ", cid); + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log('User Linktrees uploaded to IPFS: ', cid); - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); - // Store the cid in localdb - try { - await namespaceWrapper.storeSet("testlinktree", cid); - } catch (err) { - console.log("ERROR IN STORING test linktree", err); - res.status(404).json({ message: "ERROR in storing test linktree" }); - } - return cid - } else { - console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); + // Store the cid in localdb + try { + await namespaceWrapper.storeSet('testlinktree', cid); + } catch (err) { + console.log('ERROR IN STORING test linktree', err); + res.status(404).json({ message: 'ERROR in storing test linktree' }); } + return cid; + } else { + console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); + } } - async function cidValidation(submission_value) { - console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); - const outputraw = await dataFromCid(submission_value); - const output = outputraw.data - // for () - const linktrees_list_object = output.data; - console.log("RESPONSE DATA", linktrees_list_object); - const publicKey = output.publicKey; - console.log("PUBLIC KEY", publicKey); - const signature = output.signature; - console.log("SIGNATURE", signature); + console.log('******/ TEST Linktree CID VALIDATION Task FUNCTION /******'); + const outputraw = await dataFromCid(submission_value); + const output = outputraw.data; + // for () + const linktrees_list_object = output.data; + console.log('RESPONSE DATA', linktrees_list_object); + const publicKey = output.publicKey; + console.log('PUBLIC KEY', publicKey); + const signature = output.signature; + console.log('SIGNATURE', signature); - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); - if (!linktrees_list_object || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } + if (!linktrees_list_object || !signature || !publicKey) { + console.error('No data received from web3.storage'); + return false; + } + + // verify the signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log(`Is the signature valid? ${isSignatureValid}`); - // verify the signature - const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); - console.log(`Is the signature valid? ${isSignatureValid}`); - - return isSignatureValid; + return isSignatureValid; } async function verifySignature(message, signature, publicKey) { - return nacl.sign.detached.verify(message, signature, publicKey); + return nacl.sign.detached.verify(message, signature, publicKey); } -test(); \ No newline at end of file +test(); diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 0acbeec0..c9638f08 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -31,21 +31,6 @@ try { label: 'Twitter', redirectUrl: 'https://twitter.com/blockchainbalak', }, - { - key: 'linkedin', - label: 'LinkedIn', - redirectUrl: 'https://www.linkedin.com/in/prakarshpathak/', - }, - { - key: 'youtube', - label: 'YouTube', - redirectUrl: 'https://www.youtube.com/channel/UCIe3FlAWg06kGOrm1-c8oJg', - }, - { - key: 'discord', - label: 'Discord', - redirectUrl: 'https://discord.com/invite/ahxuCtm', - }, { key: 'github', label: 'GitHub', diff --git a/test/unitTest.js b/test/unitTest.js index 1fe46bb8..059e4c38 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -1,6 +1,27 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); - coreLogic.task(); -// const submission = coreLogic.fetchSubmission(); -// coreLogic.validateNode(submission, 1); +const submission = coreLogic.fetchSubmission(); +coreLogic.validateNode(submission, 1); + +const _dummyTaskState = { + submissions: { + 1: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', + slot: 1889700, + round: 1, + }, + }, + 1: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + submission_value: '34976272f8acef2758e794a0a8ef0032299e4339', + slot: 1890002, + round: 1, + }, + }, + }, + submissions_audit_trigger: {}, +}; +const distributionList = coreLogic.generateDistributionList(1, _dummyTaskState); +coreLogic.validateDistribution(null, 1, distributionList, _dummyTaskState); From bc044b425991e7337b77934b5814f98aa27553c3 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 13:16:47 -0300 Subject: [PATCH 18/61] updates --- .prettierrc | 12 ++++++++++++ coreLogic.js | 27 ++++++++++++++++++++++----- namespaceWrapper.js | 7 ++++++- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..7e476395 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "arrowParens": "avoid", + "endOfLine": "auto" + } diff --git a/coreLogic.js b/coreLogic.js index f7b47c6f..66afd50e 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -32,7 +32,7 @@ async fetchSubmission(){ return cid; } -async generateDistributionList(round){ +async generateDistributionList(round, _dummyTaskState){ try{ console.log("GenerateDistributionList called"); console.log("I am selected node"); @@ -44,9 +44,10 @@ async generateDistributionList(round){ let distributionList = {}; const taskAccountDataJSON = await namespaceWrapper.getTaskState(); + if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; const submissions = taskAccountDataJSON.submissions[round]; const submissions_audit_trigger = - taskAccountDataJSON.submissions_audit_trigger[round]; + taskAccountDataJSON.submissions_audit_trigger[round]; if (submissions == null) { console.log("No submisssions found in N-2 round"); return distributionList; @@ -142,16 +143,32 @@ async shallowEqual(object1, object2) { return true; } -validateDistribution = async(distributionListSubmitter, round) => { +validateDistribution = async ( + distributionListSubmitter, + round, + _dummyDistributionList, + _dummyTaskState, +) => { + // Write your logic for the validation of submission value here and return a boolean value in response // this logic can be same as generation of distribution list function and based on the comparision will final object , decision can be made try{ console.log("Distribution list Submitter", distributionListSubmitter); - const fetchedDistributionList = JSON.parse(await namespaceWrapper.getDistributionList(distributionListSubmitter,round)); + const rawDistributionList = await namespaceWrapper.getDistributionList( + distributionListSubmitter, + round, + ); + let fetchedDistributionList; + if (rawDistributionList == null) { + fetchedDistributionList = _dummyDistributionList; + } else { + fetchedDistributionList = JSON.parse(rawDistributionList); + } + console.log("FETCHED DISTRIBUTION LIST",fetchedDistributionList); - const generateDistributionList = await this.generateDistributionList(round); + const generateDistributionList = await this.generateDistributionList(round, _dummyTaskState,); // compare distribution list diff --git a/namespaceWrapper.js b/namespaceWrapper.js index 4088efc6..9f1b1dc2 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -239,7 +239,12 @@ class NamespaceWrapper { } async getDistributionList(publicKey,round) { - return await genericHandler("getDistributionList", publicKey, round); + const response = await genericHandler('getDistributionList', publicKey, round); + if (response.error) { + return null; + } + return response + } async validateAndVoteOnNodes(validate, round) { From dc2a7a5216138cf77f087aad3202c3b1ec8b0e15 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 13:46:44 -0300 Subject: [PATCH 19/61] update coreLogic --- test/test_generatedistribution.js | 0 test/test_index.js | 1 + test/unitTest.js | 60 ++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 test/test_generatedistribution.js diff --git a/test/test_generatedistribution.js b/test/test_generatedistribution.js new file mode 100644 index 00000000..e69de29b diff --git a/test/test_index.js b/test/test_index.js index 6a103a24..12c8af22 100644 --- a/test/test_index.js +++ b/test/test_index.js @@ -19,6 +19,7 @@ async function test() { // 3 test the validation of the cid const check = await cidValidation(cid); // 4 iterate over the cid and create distribution + // 5 audit the distribution } diff --git a/test/unitTest.js b/test/unitTest.js index 059e4c38..203cbba9 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -1,27 +1,45 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); -coreLogic.task(); -const submission = coreLogic.fetchSubmission(); -coreLogic.validateNode(submission, 1); -const _dummyTaskState = { - submissions: { - 1: { - '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { - submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', - slot: 1889700, - round: 1, +async function test_coreLogic() { + await coreLogic.task(); + const submission = await coreLogic.fetchSubmission(); + const vote = await coreLogic.validateNode(submission, 1); + + const _dummyTaskState = { + submissions: { + 1: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', + slot: 1889700, + round: 1, + }, }, - }, - 1: { - '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { - submission_value: '34976272f8acef2758e794a0a8ef0032299e4339', - slot: 1890002, - round: 1, + 1: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + submission_value: '34976272f8acef2758e794a0a8ef0032299e4339', + slot: 1890002, + round: 1, + }, }, }, - }, - submissions_audit_trigger: {}, -}; -const distributionList = coreLogic.generateDistributionList(1, _dummyTaskState); -coreLogic.validateDistribution(null, 1, distributionList, _dummyTaskState); + submissions_audit_trigger: {}, + }; + if (vote == true) { + console.log('Submission is valid, generating distribution list'); + const distributionList = await coreLogic.generateDistributionList( + 1, + _dummyTaskState, + ); + await coreLogic.validateDistribution( + null, + 1, + distributionList, + _dummyTaskState, + ); + } else { + console.log('Submission is invalid, not generating distribution list'); + } +} + +test_coreLogic(); From 10ca612015d00a7c56154260885071bb8da2c4b1 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 13:47:11 -0300 Subject: [PATCH 20/61] update coreLogic --- coreLogic.js | 366 ++++++++++++++++++++++--------------------- linktree_task.js | 129 +++++++-------- linktree_validate.js | 183 ++++------------------ 3 files changed, 277 insertions(+), 401 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index 66afd50e..eaebbe3c 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -1,215 +1,227 @@ -const { namespaceWrapper } = require("./namespaceWrapper"); -const linktree_task = require("./linktree_task"); -const linktree_validate = require("./linktree_validate"); +const { namespaceWrapper } = require('./namespaceWrapper'); +const linktree_task = require('./linktree_task'); +const linktree_validate = require('./linktree_validate'); const crypto = require('crypto'); -class CoreLogic{ +class CoreLogic { + async task() { + // Write the logic to do the work required for submitting the values and optionally store the result in levelDB -async task() { - // Write the logic to do the work required for submitting the values and optionally store the result in levelDB - - // run linktree task - console.log("*********task() started*********") - const cid = await linktree_task(); - if (cid) { - await namespaceWrapper.storeSet("cid", cid); // store CID in levelDB - } else { - console.log("CID NOT FOUND"); + // run linktree task + console.log('*********task() started*********'); + const cid = await linktree_task(); + if (cid) { + await namespaceWrapper.storeSet('cid', cid); // store CID in levelDB + } else { + console.log('CID NOT FOUND'); + } + console.log('*********task() completed*********'); } - console.log("*********task() completed*********") -} - -async fetchSubmission(){ - // Write the logic to fetch the submission values here and return the cid string - - // fetching round number to store work accordingly - console.log("***********IN FETCH SUBMISSION**************"); - // The code below shows how you can fetch your stored value from level DB + async fetchSubmission() { + // Write the logic to fetch the submission values here and return the cid string - const cid = await namespaceWrapper.storeGet("cid"); // retrieves the cid - console.log("Linktree CID", cid); - return cid; -} + // fetching round number to store work accordingly -async generateDistributionList(round, _dummyTaskState){ - try{ - console.log("GenerateDistributionList called"); - console.log("I am selected node"); - - // Write the logic to generate the distribution list here by introducing the rules of your choice + console.log('***********IN FETCH SUBMISSION**************'); + // The code below shows how you can fetch your stored value from level DB + const cid = await namespaceWrapper.storeGet('cid'); // retrieves the cid + console.log('Linktree CID', cid); + return cid; + } - /* **** SAMPLE LOGIC FOR GENERATING DISTRIBUTION LIST ******/ - - let distributionList = {}; - const taskAccountDataJSON = await namespaceWrapper.getTaskState(); - if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; - const submissions = taskAccountDataJSON.submissions[round]; - const submissions_audit_trigger = - taskAccountDataJSON.submissions_audit_trigger[round]; - if (submissions == null) { - console.log("No submisssions found in N-2 round"); - return distributionList; - } else { - const keys = Object.keys(submissions); - const values = Object.values(submissions); - const size = values.length; - console.log("Submissions from last round: ", keys, values, size); - for (let i = 0; i < size; i++) { - const candidatePublicKey = keys[i]; - if (submissions_audit_trigger && submissions_audit_trigger[candidatePublicKey]) { - console.log(submissions_audit_trigger[candidatePublicKey].votes, "distributions_audit_trigger votes "); - const votes = submissions_audit_trigger[candidatePublicKey].votes; - let numOfVotes = 0; - for (let index = 0; index < votes.length; index++) { - if(votes[i].is_valid) - numOfVotes++; - else numOfVotes--; + async generateDistributionList(round, _dummyTaskState) { + try { + console.log('GenerateDistributionList called'); + console.log('I am selected node'); + + // Write the logic to generate the distribution list here by introducing the rules of your choice + + /* **** SAMPLE LOGIC FOR GENERATING DISTRIBUTION LIST ******/ + + let distributionList = {}; + const taskAccountDataJSON = await namespaceWrapper.getTaskState(); + if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; + const submissions = taskAccountDataJSON.submissions[round]; + const submissions_audit_trigger = + taskAccountDataJSON.submissions_audit_trigger[round]; + if (submissions == null) { + console.log('No submisssions found in N-2 round'); + return distributionList; + } else { + const keys = Object.keys(submissions); + const values = Object.values(submissions); + const size = values.length; + console.log('Submissions from last round: ', keys, values, size); + for (let i = 0; i < size; i++) { + const candidatePublicKey = keys[i]; + if ( + submissions_audit_trigger && + submissions_audit_trigger[candidatePublicKey] + ) { + console.log( + submissions_audit_trigger[candidatePublicKey].votes, + 'distributions_audit_trigger votes ', + ); + const votes = submissions_audit_trigger[candidatePublicKey].votes; + let numOfVotes = 0; + for (let index = 0; index < votes.length; index++) { + if (votes[i].is_valid) numOfVotes++; + else numOfVotes--; + } + if (numOfVotes < 0) continue; } - if(numOfVotes < 0) - continue; + distributionList[candidatePublicKey] = 1; } - distributionList[candidatePublicKey] = 1; } + console.log('Distribution List', distributionList); + return distributionList; + } catch (err) { + console.log('ERROR IN GENERATING DISTRIBUTION LIST', err); } - console.log("Distribution List", distributionList); - return distributionList; - }catch(err){ - console.log("ERROR IN GENERATING DISTRIBUTION LIST", err); } -} + async submitDistributionList(round) { + // This function just upload your generated dustribution List and do the transaction for that -async submitDistributionList(round) { + console.log('SubmitDistributionList called'); -// This function just upload your generated dustribution List and do the transaction for that + try { + const distributionList = await this.generateDistributionList(round); - console.log("SubmitDistributionList called"); + const decider = await namespaceWrapper.uploadDistributionList( + distributionList, + round, + ); + console.log('DECIDER', decider); - try{ - - const distributionList = await this.generateDistributionList(round); - - const decider = await namespaceWrapper.uploadDistributionList( - distributionList, round - ); - console.log("DECIDER", decider); - - if (decider) { - const response = await namespaceWrapper.distributionListSubmissionOnChain(round); - console.log("RESPONSE FROM DISTRIBUTION LIST", response); + if (decider) { + const response = + await namespaceWrapper.distributionListSubmissionOnChain(round); + console.log('RESPONSE FROM DISTRIBUTION LIST', response); + } + } catch (err) { + console.log('ERROR IN SUBMIT DISTRIBUTION', err); } - }catch(err){ - console.log("ERROR IN SUBMIT DISTRIBUTION", err); } -} - -async validateNode(submission_value, round) { - -// Write your logic for the validation of submission value here and return a boolean value in response - -console.log("Received submission_value", submission_value, round); -const vote = await linktree_validate(submission_value); -// const generatedValue = await namespaceWrapper.storeGet("cid"); -// console.log("GENERATED VALUE", generatedValue); -// if(generatedValue == submission_value){ -// return true; -// }else{ -// return false; -// } -// }catch(err){ -// console.log("ERROR IN VALDIATION", err); -// return false; -// } - -// For succesfull flow we return true for now -return vote; -} - - -async shallowEqual(object1, object2) { - const keys1 = Object.keys(object1); - const keys2 = Object.keys(object2); - if (keys1.length !== keys2.length) { - return false; + async validateNode(submission_value, round) { + // Write your logic for the validation of submission value here and return a boolean value in response + + console.log('Received submission_value', submission_value, round); + const vote = await linktree_validate(submission_value); + // const generatedValue = await namespaceWrapper.storeGet("cid"); + // console.log("GENERATED VALUE", generatedValue); + // if(generatedValue == submission_value){ + // return true; + // }else{ + // return false; + // } + // }catch(err){ + // console.log("ERROR IN VALDIATION", err); + // return false; + // } + + // For succesfull flow we return true for now + return vote; } - for (let key of keys1) { - if (object1[key] !== object2[key]) { + + async shallowEqual(object1, object2) { + const keys1 = Object.keys(object1); + const keys2 = Object.keys(object2); + if (keys1.length !== keys2.length) { return false; } + for (let key of keys1) { + if (object1[key] !== object2[key]) { + return false; + } + } + return true; } - return true; -} - -validateDistribution = async ( - distributionListSubmitter, - round, - _dummyDistributionList, - _dummyTaskState, -) => { - -// Write your logic for the validation of submission value here and return a boolean value in response -// this logic can be same as generation of distribution list function and based on the comparision will final object , decision can be made - -try{ - console.log("Distribution list Submitter", distributionListSubmitter); - const rawDistributionList = await namespaceWrapper.getDistributionList( + validateDistribution = async ( distributionListSubmitter, round, - ); - let fetchedDistributionList; - if (rawDistributionList == null) { - fetchedDistributionList = _dummyDistributionList; - } else { - fetchedDistributionList = JSON.parse(rawDistributionList); - } - - console.log("FETCHED DISTRIBUTION LIST",fetchedDistributionList); - const generateDistributionList = await this.generateDistributionList(round, _dummyTaskState,); - - // compare distribution list + _dummyDistributionList, + _dummyTaskState, + ) => { + // Write your logic for the validation of submission value here and return a boolean value in response + // this logic can be same as generation of distribution list function and based on the comparision will final object , decision can be made + + try { + console.log('Distribution list Submitter', distributionListSubmitter); + const rawDistributionList = await namespaceWrapper.getDistributionList( + distributionListSubmitter, + round, + ); + let fetchedDistributionList; + if (rawDistributionList == null) { + fetchedDistributionList = _dummyDistributionList; + } else { + fetchedDistributionList = JSON.parse(rawDistributionList); + } - const parsed = JSON.parse(fetchedDistributionList); - const result = await this.shallowEqual(parsed,generateDistributionList); - console.log("RESULT", result); - return result; -}catch(err){ - console.log("ERROR IN VALIDATING DISTRIBUTION", err); - return false; + console.log('FETCHED DISTRIBUTION LIST', fetchedDistributionList); + const generateDistributionList = await this.generateDistributionList( + round, + _dummyTaskState, + ); -} + // compare distribution list -} -// Submit Address with distributioon list to K2 -async submitTask(roundNumber) { - console.log("submitTask called with round", roundNumber); - try { - console.log("inside try"); - console.log(await namespaceWrapper.getSlot(), "current slot while calling submit"); - const submission = await this.fetchSubmission(); - console.log("SUBMISSION", submission); - // submit the submission to the K2 - await namespaceWrapper.checkSubmissionAndUpdateRound(submission, roundNumber); - console.log("after the submission call"); - } catch (error) { - console.log("error in submission", error); + const parsed = JSON.parse(fetchedDistributionList); + const result = await this.shallowEqual(parsed, generateDistributionList); + console.log('RESULT', result); + return result; + } catch (err) { + console.log('ERROR IN VALIDATING DISTRIBUTION', err); + return false; + } + }; + // Submit Address with distributioon list to K2 + async submitTask(roundNumber) { + console.log('submitTask called with round', roundNumber); + try { + console.log('inside try'); + console.log( + await namespaceWrapper.getSlot(), + 'current slot while calling submit', + ); + const submission = await this.fetchSubmission(); + console.log('SUBMISSION', submission); + // submit the submission to the K2 + await namespaceWrapper.checkSubmissionAndUpdateRound( + submission, + roundNumber, + ); + console.log('after the submission call'); + } catch (error) { + console.log('error in submission', error); + } } -} -async auditTask(roundNumber) { // No need to edit this function - console.log("auditTask called with round", roundNumber); - console.log(await namespaceWrapper.getSlot(), "current slot while calling auditTask"); - await namespaceWrapper.validateAndVoteOnNodes(this.validateNode, roundNumber); -} - -async auditDistribution(roundNumber) { - console.log("auditDistribution called with round", roundNumber); - await namespaceWrapper.validateAndVoteOnDistributionList(this.validateDistribution, roundNumber); -} + async auditTask(roundNumber) { + // No need to edit this function + console.log('auditTask called with round', roundNumber); + console.log( + await namespaceWrapper.getSlot(), + 'current slot while calling auditTask', + ); + await namespaceWrapper.validateAndVoteOnNodes( + this.validateNode, + roundNumber, + ); + } + async auditDistribution(roundNumber) { + console.log('auditDistribution called with round', roundNumber); + await namespaceWrapper.validateAndVoteOnDistributionList( + this.validateDistribution, + roundNumber, + ); + } } const coreLogic = new CoreLogic(); diff --git a/linktree_task.js b/linktree_task.js index 497ff4d4..e8dcde2e 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -1,78 +1,59 @@ -const { namespaceWrapper } = require("./namespaceWrapper"); -const createFile = require("./helpers/createFile.js"); -const deleteFile = require("./helpers/deleteFile"); -const fs = require("fs"); -const { Web3Storage, getFilesFromPath } = require("web3.storage"); +const { namespaceWrapper } = require('./namespaceWrapper'); +const createFile = require('./helpers/createFile.js'); +const deleteFile = require('./helpers/deleteFile'); +const fs = require('fs'); +const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: process.env.SECRET_WEB3_STORAGE_KEY, + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', }); -const { MAIN_ACCOUNT_PUBKEY } = require("./init"); -const crypto = require("crypto"); - -module.exports = async() => { - console.log("******/ IN Linktree Task FUNCTION /******"); - // Customize linktree test data - console.log("Getting linktrees list"); - const linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); - const linktrees_list_object = JSON.parse(linktrees_list_string); - console.log("Getting linktrees list", linktrees_list_object); - - // loop through the linktrees_list to get the userIndex and upload then to web3.storage - for (let i = 0; i < linktrees_list_object.length; i++) { - console.log("i", i , "linktrees_list_object.length", linktrees_list_object.length); - const linktrees = linktrees_list_object[i]; - console.log("linktrees", linktrees); - - if (linktrees) { - const linktree_data_payload = JSON.stringify(linktrees.data); - - const hashLinktreeIndex = crypto - .createHash("sha256") - .update(linktree_data_payload) - .digest("hex"); - - console.log("HASH OF LINKTREE INDEX", hashLinktreeIndex); - - // singing the payload using the nodes private key and sending the public key along with the payload - // const signature = await namespaceWrapper.payloadSigning(hashLinktreeIndex); - // console.log("SIGNATURE ON HASH OF LINKTREE INDEX", signature); - - const indexSignature = { - data: linktree_data_payload, - pubKey: MAIN_ACCOUNT_PUBKEY, - // signature: signature, - }; - - console.log("INDEX SIGNATURE DATA", indexSignature); - - // upload the index of the linktree on web3.storage - const path = `userIndex/test.json`; - console.log("PATH", path); - if (!fs.existsSync("userIndex")) fs.mkdirSync("userIndex"); - await createFile(path, indexSignature); - - if (storageClient) { - const file = await getFilesFromPath(path); - // const cid = await storageClient.put(file); - const cid = "testingCID" + i; - console.log("User index uploaded to IPFS: ", cid); - - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); - - // Store the cid in level db - try { - await namespaceWrapper.storeSet("testlinktree", cid); - } catch (err) { - console.log("ERROR IN STORING test linktree", err); - res.status(404).json({ message: "ERROR in storing test linktree" }); - } - - return cid - - } else { - console.log("NODE DO NOT HAVE ACCESS TO WEB3.STORAGE"); - } - } +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); + +module.exports = async () => { + console.log('******/ IN Linktree Task FUNCTION /******'); + // Customize linktree test data + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; + // Get linktree list fron localdb + const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); + const linktrees_list_object = JSON.parse(linktrees_list_string); + + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + + const submission_value = { + data: linktrees_list_object, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + }; + // upload the index of the linktree on web3.storage + const path = `testLinktree/test.json`; + console.log('PATH', path); + if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); + await createFile(path, submission_value); + + if (storageClient) { + const file = await getFilesFromPath(path); + const cid = await storageClient.put(file); + console.log('User Linktrees uploaded to IPFS: ', cid); + + // deleting the file from fs once it is uploaded to IPFS + await deleteFile(path); + + // Store the cid in localdb + try { + await namespaceWrapper.storeSet('testlinktree', cid); + } catch (err) { + console.log('ERROR IN STORING test linktree', err); + res.status(404).json({ message: 'ERROR in storing test linktree' }); } + return cid; + } else { + console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); + } }; diff --git a/linktree_validate.js b/linktree_validate.js index 5667ce82..2515ea1d 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -2,159 +2,42 @@ const { namespaceWrapper } = require("./namespaceWrapper"); const dataFromCid = require("./helpers/dataFromCid"); const getKeys = require("./helpers/getKey"); const hashCompare = require("./helpers/hashCompare"); +const nacl = require('tweetnacl'); +const bs58 = require('bs58'); module.exports = async (submission_value) => { - const linktreeIndex = submission_value; - console.log("linktreeINDEX", linktreeIndex); - - try { - const output = await dataFromCid(linktreeIndex); - console.log("RESPONSE DATA", output.data); - const linktreeIndexData = output.data.data; - console.log("linktree INDEX DATA", linktreeIndexData); - const signature = output.data.signature; - console.log("SIGNATURES", signature); - const publicKey = output.data.pubKey; - console.log("PUBKEY", publicKey); - - if (!output.data || !signature || !publicKey) { - console.error("No data received from web3.storage"); - return false; - } - - // verifying the signature and getting the original data - const check = await hashCompare(linktreeIndexData, signature, publicKey); - console.log("CHECK", check); - - if (check == true) { - console.log("IN IF"); - const values = Object.values(linktreeIndexData); - const keys = Object.keys(linktreeIndexData); - const size = values.length; - - const testlinktree_string = await namespaceWrapper.storeGet("testlinktree"); - let testlinktree = JSON.parse(testlinktree_string); - console.log("Getting Linktree list", testlinktree); - if (!testlinktree) { - console.log("NEW Linktree LIST MADE"); - testlinktree = {}; - } - - let apiResponse = await dataFromCid(values[i]); - console.log("OUTPUT FROM INDEX CID", apiResponse.data); - if (apiResponse == false) { - return false; - } - let userIndexData = apiResponse.data.data; - let index = Object.values(userIndexData); - console.log("INDEX", index[0]); - - // checking the Linktree owner sigature now : P - - const index_length = Object.keys(index[0]).length; - console.log("INDEX LENGTH", index_length); - const latest_state = await getKeys(index[0], index_length); - console.log("LATEST STATE", latest_state); - - let output = await dataFromCid(latest_state); - console.log("OUTPUT FROM LATEST STATE", output.data); - if (output == false) { - return false; - } - console.log("RESPONSE DATA", output.data); - // const Pd = JSON.stringify(output.data); - const signedMessage = output.data.signedMessage; - console.log("SIGNED MESSAGE", signedMessage); - const publicKey = output.data.pubKey; - console.log("PUBLIC KEY", publicKey); - - if (!signedMessage || !publicKey) { - console.error("Signature or public Key missing from userIndex"); - return false; - } - - // verifying the signature and getting the original data - - const verifiedPayload = await namespaceWrapper.verifySignature( - signedMessage, - publicKey - ); - if (verifiedPayload.error) { - return false; - } else { - //const verifiedPayload = JSON.parse(verifiedPayloadString); - console.log("Original Data", verifiedPayload); - - const userIndexData = verifiedPayload.data; - const parsed = JSON.parse(userIndexData); - console.log("USER INDEX DATA", parsed); - const originalLinktree = parsed.data; - console.log("ORIGINAL Linktree", originalLinktree); - const userSignature = parsed.keys.signedMessage; - console.log("SIGNATURES", userSignature); - const userPublicKey = parsed.keys.pubkey; - console.log("PUBKEY", userPublicKey); - - if (!userIndexData || !userSignature || !userPublicKey) { - console.error("No data received from web3.storage"); - return false; - } - - const check_data = await hashCompare( - originalLinktree, - userSignature, - userPublicKey - ); - if (check_data == true) { - console.log("CHECK PASSED"); - // Add the Linktree to local node - - // storing linktree Index - - try { - await namespaceWrapper.storeSet( - "linktreeIndex" + `${Linktree}`, - values[i] - ); - } catch (err) { - console.log("ERROR IN STORING Linktree", err); - res.status(404).json({ message: "ERROR in storing Linktree" }); - } - - // storing the Linktree in testlinktree - - testlinktree[Linktree] = "no"; - let testlinktree_string = JSON.stringify(testlinktree); - console.log("ADDED Linktree LIST", testlinktree_string); - await namespaceWrapper.storeSet("testlinktree", testlinktree_string); - - //storting the user Index - - let cid_index_stingified = JSON.stringify(index[0]); - console.log("USER_INDEX STRINGIFIED ", cid_index_stingified); - await namespaceWrapper.storeSet(Linktree, cid_index_stingified); - - // check the user index store - - try { - const cid_index = await namespaceWrapper.storeGet(Linktree); - console.log("Getting cid index", cid_index); - } catch (err) { - console.log("CATCH IN GET", err); - } - } else { - return false; - } - } - return true; - } else { - console.log("IN ELSE"); - return false; - } - } catch (error) { - console.log("ERROR", error); + console.log('******/ Linktree CID VALIDATION Task FUNCTION /******'); + const outputraw = await dataFromCid(submission_value); + const output = outputraw.data; + const linktrees_list_object = output.data; + console.log('RESPONSE DATA', linktrees_list_object); + const publicKey = output.publicKey; + console.log('PUBLIC KEY', publicKey); + const signature = output.signature; + console.log('SIGNATURE', signature); + + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktrees_list_object)), + ); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + if (!linktrees_list_object || !signature || !publicKey) { + console.error('No data received from web3.storage'); + return false; } - //return true; + // verify the signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log(`Is the signature valid? ${isSignatureValid}`); + + return isSignatureValid; }; +async function verifySignature(message, signature, publicKey) { + return nacl.sign.detached.verify(message, signature, publicKey); +} From 585912c5aa0baa788a81f782b97de163dce57009 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 15:49:04 -0300 Subject: [PATCH 21/61] update testing code --- coreLogic.js | 10 ++++++---- test/unitTest.js | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index eaebbe3c..45b19354 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -35,14 +35,15 @@ class CoreLogic { try { console.log('GenerateDistributionList called'); console.log('I am selected node'); - + console.log('Round', round, 'Task State', _dummyTaskState); // Write the logic to generate the distribution list here by introducing the rules of your choice /* **** SAMPLE LOGIC FOR GENERATING DISTRIBUTION LIST ******/ let distributionList = {}; - const taskAccountDataJSON = await namespaceWrapper.getTaskState(); + let taskAccountDataJSON = await namespaceWrapper.getTaskState(); if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; + console.log('Task Account Data', taskAccountDataJSON); const submissions = taskAccountDataJSON.submissions[round]; const submissions_audit_trigger = taskAccountDataJSON.submissions_audit_trigger[round]; @@ -67,7 +68,7 @@ class CoreLogic { const votes = submissions_audit_trigger[candidatePublicKey].votes; let numOfVotes = 0; for (let index = 0; index < votes.length; index++) { - if (votes[i].is_valid) numOfVotes++; + if (votes[index].is_valid) numOfVotes++; else numOfVotes--; } if (numOfVotes < 0) continue; @@ -171,7 +172,8 @@ class CoreLogic { // compare distribution list - const parsed = JSON.parse(fetchedDistributionList); + const parsed = fetchedDistributionList; + console.log('compare distribution list', parsed, generateDistributionList); const result = await this.shallowEqual(parsed, generateDistributionList); console.log('RESULT', result); return result; diff --git a/test/unitTest.js b/test/unitTest.js index 203cbba9..6329e97f 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -2,10 +2,10 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); async function test_coreLogic() { - await coreLogic.task(); - const submission = await coreLogic.fetchSubmission(); - const vote = await coreLogic.validateNode(submission, 1); - + // await coreLogic.task(); + // const submission = await coreLogic.fetchSubmission(); + // const vote = await coreLogic.validateNode(submission, 1); + let vote = true; const _dummyTaskState = { submissions: { 1: { @@ -14,16 +14,35 @@ async function test_coreLogic() { slot: 1889700, round: 1, }, - }, - 1: { - '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { - submission_value: '34976272f8acef2758e794a0a8ef0032299e4339', + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { + submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cc', slot: 1890002, round: 1, }, }, }, - submissions_audit_trigger: {}, + submissions_audit_trigger: { + "1":{ // round number + "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL":{ // Data Submitter (send data to K2) + "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH", // Audit trigger + "slot":1890002, + "votes":[{ + "is_valid": false, // Submission is invalid(Slashed) + "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter + "slot":1890003 + }] + }, + "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH":{ // Data Submitter (send data to K2) + "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL", // Audit trigger + "slot":1890002, + "votes":[{ + "is_valid": false, // Submission is invalid(Slashed) + "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter + "slot":1890003 + }] + } + } + }, }; if (vote == true) { console.log('Submission is valid, generating distribution list'); From c0df130e462f912add9f112a3c17a7a3ff952665 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 31 Mar 2023 17:30:31 -0300 Subject: [PATCH 22/61] setting up log listening --- .env-local | 2 +- index.js | 16 ++++++++++++---- webpack.config.js | 3 +++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.env-local b/.env-local index 2813a4a0..0a19a361 100644 --- a/.env-local +++ b/.env-local @@ -12,7 +12,7 @@ INITIAL_STAKING_WALLET_BALANCE=15 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="false" +GLOBAL_TIMERS="true" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs diff --git a/index.js b/index.js index 6ec3d9bb..eb98ee9d 100644 --- a/index.js +++ b/index.js @@ -5,9 +5,17 @@ const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper") const {default: axios} = require('axios'); const bs58 = require('bs58'); const nacl = require('tweetnacl'); +const fs = require('fs'); async function setup() { + const logFile = fs.createWriteStream('./console.log', { flags: 'a' }); + + // Overwrite the console.log function to write to the log file + console.log = function (message) { + logFile.write(`${new Date().toISOString()} - ${message}\n`); + }; + console.log("setup function called"); // Run default setup await namespaceWrapper.defaultTaskSetup(); @@ -141,10 +149,6 @@ async function setup() { // console.log("RESPONSE TRIGGER", responsePayout); - - - - } if (taskNodeAdministered){ @@ -210,5 +214,9 @@ if (app) { allLinktrees = JSON.parse(allLinktrees || '[]'); return res.status(200).send(allLinktrees); }); + const port = process.env.SERVICE_URL || 3000; + app.listen(port, () => { + console.log(`Server is running on port ${port}`); + }); } diff --git a/webpack.config.js b/webpack.config.js index 55585067..dc5f0a1e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,5 +10,8 @@ module.exports={ }, stats:{ moduleTrace:false + }, + node:{ + __dirname: true } } \ No newline at end of file From 15c6f6b22d45ff849ee57e7a107830b9d4e881fb Mon Sep 17 00:00:00 2001 From: Syed Ghazanfer Anwar Date: Sat, 1 Apr 2023 06:45:45 +0500 Subject: [PATCH 23/61] Added the get-logs endpoint --- docker-compose.yaml | 2 ++ index.js | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index d28c15ba..33f14c5d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -19,6 +19,8 @@ services: - redis ports: - '8080:8080' + - '10000:10000' + env_file: .env-local container_name: task_node diff --git a/index.js b/index.js index eb98ee9d..c2f41a97 100644 --- a/index.js +++ b/index.js @@ -9,11 +9,11 @@ const fs = require('fs'); async function setup() { - const logFile = fs.createWriteStream('./console.log', { flags: 'a' }); + const logFile = fs.createWriteStream('./namespace/logs.txt', { flags: 'a' }); // Overwrite the console.log function to write to the log file console.log = function (message) { - logFile.write(`${new Date().toISOString()} - ${message}\n`); + logFile.write(`${new Date().toISOString()} - ${message}
\n`); }; console.log("setup function called"); @@ -214,9 +214,9 @@ if (app) { allLinktrees = JSON.parse(allLinktrees || '[]'); return res.status(200).send(allLinktrees); }); - const port = process.env.SERVICE_URL || 3000; - app.listen(port, () => { - console.log(`Server is running on port ${port}`); - }); + app.get("/get-logs", async (req, res) => { + const logs = fs.readFileSync("./namespace/logs.txt", "utf8") + res.status(200).send(logs); + }) } From acfacc62606773d7432c3f8cbad7b70497983964 Mon Sep 17 00:00:00 2001 From: soma Date: Mon, 3 Apr 2023 20:07:32 -0300 Subject: [PATCH 24/61] remove soma's web3 token key --- linktree_task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linktree_task.js b/linktree_task.js index e8dcde2e..f63045dd 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -5,7 +5,7 @@ const fs = require('fs'); const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ token: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', + '', }); const bs58 = require('bs58'); const nacl = require('tweetnacl'); From d450acccde1741993dd9579264c449470b8b1263 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 4 Apr 2023 12:45:28 -0300 Subject: [PATCH 25/61] debug task node issue --- index.js | 6 +++--- linktree_task.js | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index c2f41a97..66d70cee 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const {coreLogic} = require("./coreLogic"); +const coreLogic = require("./coreLogic"); const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const express = require('express'); const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); @@ -114,7 +114,7 @@ async function setup() { */ - // console.log("*******************TESTING*******************") + console.log("*******************TESTING*******************") // Get the task state // console.log(await namespaceWrapper.getTaskState()); @@ -127,7 +127,7 @@ async function setup() { // Call to do the work for the task - // await coreLogic.task(); + await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) // await coreLogic.submitTask(round - 1); diff --git a/linktree_task.js b/linktree_task.js index f63045dd..c6014af7 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -4,8 +4,7 @@ const deleteFile = require('./helpers/deleteFile'); const fs = require('fs'); const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: - '', + token: process.env.SECRET_WEB3_STORAGE_KEY, }); const bs58 = require('bs58'); const nacl = require('tweetnacl'); @@ -32,9 +31,9 @@ module.exports = async () => { signature: bs58.encode(signature), }; // upload the index of the linktree on web3.storage - const path = `testLinktree/test.json`; + const path = `./testLinktree/test.json`; + if (!fs.existsSync('./testLinktree')) fs.mkdirSync('./testLinktree'); console.log('PATH', path); - if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); await createFile(path, submission_value); if (storageClient) { From 6d933b683cede44c39ff7933082423e2ddc1b737 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 4 Apr 2023 14:31:02 -0300 Subject: [PATCH 26/61] comment testing timer --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 66d70cee..2a8d68e9 100644 --- a/index.js +++ b/index.js @@ -114,7 +114,7 @@ async function setup() { */ - console.log("*******************TESTING*******************") + // console.log("*******************TESTING*******************") // Get the task state // console.log(await namespaceWrapper.getTaskState()); @@ -127,7 +127,7 @@ async function setup() { // Call to do the work for the task - await coreLogic.task(); + // await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) // await coreLogic.submitTask(round - 1); From 2a7ace4ea62fe1566b7946ce8b1593ab47ab094b Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 4 Apr 2023 14:52:43 -0300 Subject: [PATCH 27/61] update path --- namespaceWrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/namespaceWrapper.js b/namespaceWrapper.js index 9f1b1dc2..0f022413 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -400,7 +400,7 @@ class NamespaceWrapper { async function instantiateLevelDb() { if(!localLevelDB){ - localLevelDB = levelup(leveldown("/home/soma/code-ie/task-template-linktree/localKOIIDB")); + localLevelDB = levelup(leveldown(__dirname + "/localKOIIDB")); } } From ed33d4e13b4d45dccace747196583457cd6d53b1 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 4 Apr 2023 16:22:11 -0300 Subject: [PATCH 28/61] update localdb get --- namespaceWrapper.js | 3 +- test/unitTest.js | 114 ++++++++++++++++++++++---------------------- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/namespaceWrapper.js b/namespaceWrapper.js index 0f022413..e5651a05 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -20,11 +20,10 @@ class NamespaceWrapper { return new Promise((resolve, reject) => { localLevelDB.get(key, { asBuffer: false }, (err, value) => { if (err) { - reject(err); + resolve(null); } else { resolve(value); } - }); }); } diff --git a/test/unitTest.js b/test/unitTest.js index 6329e97f..622a91a1 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -2,63 +2,63 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); async function test_coreLogic() { - // await coreLogic.task(); - // const submission = await coreLogic.fetchSubmission(); - // const vote = await coreLogic.validateNode(submission, 1); - let vote = true; - const _dummyTaskState = { - submissions: { - 1: { - '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { - submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', - slot: 1889700, - round: 1, - }, - '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { - submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cc', - slot: 1890002, - round: 1, - }, - }, - }, - submissions_audit_trigger: { - "1":{ // round number - "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL":{ // Data Submitter (send data to K2) - "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH", // Audit trigger - "slot":1890002, - "votes":[{ - "is_valid": false, // Submission is invalid(Slashed) - "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter - "slot":1890003 - }] - }, - "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH":{ // Data Submitter (send data to K2) - "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL", // Audit trigger - "slot":1890002, - "votes":[{ - "is_valid": false, // Submission is invalid(Slashed) - "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter - "slot":1890003 - }] - } - } - }, - }; - if (vote == true) { - console.log('Submission is valid, generating distribution list'); - const distributionList = await coreLogic.generateDistributionList( - 1, - _dummyTaskState, - ); - await coreLogic.validateDistribution( - null, - 1, - distributionList, - _dummyTaskState, - ); - } else { - console.log('Submission is invalid, not generating distribution list'); - } + await coreLogic.task(); + const submission = await coreLogic.fetchSubmission(); + const vote = await coreLogic.validateNode(submission, 1); + // let vote = true; + // const _dummyTaskState = { + // submissions: { + // 1: { + // '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + // submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', + // slot: 1889700, + // round: 1, + // }, + // '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { + // submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cc', + // slot: 1890002, + // round: 1, + // }, + // }, + // }, + // submissions_audit_trigger: { + // "1":{ // round number + // "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL":{ // Data Submitter (send data to K2) + // "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH", // Audit trigger + // "slot":1890002, + // "votes":[{ + // "is_valid": false, // Submission is invalid(Slashed) + // "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter + // "slot":1890003 + // }] + // }, + // "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH":{ // Data Submitter (send data to K2) + // "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL", // Audit trigger + // "slot":1890002, + // "votes":[{ + // "is_valid": false, // Submission is invalid(Slashed) + // "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter + // "slot":1890003 + // }] + // } + // } + // }, + // }; + // if (vote == true) { + // console.log('Submission is valid, generating distribution list'); + // const distributionList = await coreLogic.generateDistributionList( + // 1, + // _dummyTaskState, + // ); + // await coreLogic.validateDistribution( + // null, + // 1, + // distributionList, + // _dummyTaskState, + // ); + // } else { + // console.log('Submission is invalid, not generating distribution list'); + // } } test_coreLogic(); From 4bf6e4d12175c3ce03599e3e58b9413de52de665 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 4 Apr 2023 17:21:22 -0300 Subject: [PATCH 29/61] update docker code --- index.js | 13 ++++-- test/test_docker_submitlinktree.js | 69 ++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test/test_docker_submitlinktree.js diff --git a/index.js b/index.js index 2a8d68e9..567b1acc 100644 --- a/index.js +++ b/index.js @@ -9,11 +9,18 @@ const fs = require('fs'); async function setup() { - const logFile = fs.createWriteStream('./namespace/logs.txt', { flags: 'a' }); + const originalConsoleLog = console.log; + + // Create a writable stream to the log file + const logStream = fs.createWriteStream('./namespace/logs.txt', { flags: 'a' }); // Overwrite the console.log function to write to the log file - console.log = function (message) { - logFile.write(`${new Date().toISOString()} - ${message}
\n`); + console.log = function (...args) { + originalConsoleLog.apply(console, args); + const message = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg) : arg)).join(' ') + '\n'; + + // Write the message to the log file + logStream.write(message); }; console.log("setup function called"); diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js new file mode 100644 index 00000000..9297997d --- /dev/null +++ b/test/test_docker_submitlinktree.js @@ -0,0 +1,69 @@ +const {default: axios} = require('axios'); +const {v4: uuidv4} = require('uuid'); +const bs58 = require('bs58'); +const nacl = require('tweetnacl'); +const fs = require("fs") +const solanaWeb3 = require('@solana/web3.js'); +const crypto = require('crypto'); + +// This test submits linktrees from differnet publicKey to the service and stored in localdb +async function main() { +try { + for (let i = 0; i < 5; i++) { + console.log('i', i); + const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); + // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( + // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) + // ); + const publicKey = publicKeyraw.toBase58(); + console.log('publicKey', publicKey); + const payload = { + data: { + uuid: uuidv4(), + linktree: [ + { + key: 'official', + label: 'Official Website', + redirectUrl: 'https://spheron.network/', + }, + { + key: 'twitter', + label: 'Twitter', + redirectUrl: 'https://twitter.com/blockchainbalak', + }, + { + key: 'github', + label: 'GitHub', + redirectUrl: 'https://github.com/spheronFdn/', + }, + ], + timestamp: Date.now(), + }, + publicKey: publicKey, + }; + const msg = new TextEncoder().encode(JSON.stringify(payload.data)); + payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + + // Check payload + console.log(payload); + + await axios + .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/register-linktree', {payload}) + .then((e) => { + if (e.status != 200) { + console.log(e); + } + console.log(e.data); + }) + .catch((e) => { + console.error(e); + }); + } +} catch (e) { + console.error(e) +} +} + +main(); + +module.exports = main; \ No newline at end of file From e7d2d74631ab1cb99eed5f1648c816ba7759be6b Mon Sep 17 00:00:00 2001 From: soma Date: Mon, 10 Apr 2023 12:23:37 -0300 Subject: [PATCH 30/61] update testdata and apply merge data --- test/check_task-status.js | 10 +++ test/test_docker_submitlinktree.js | 2 +- test/test_mergedData.js | 99 ++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 test/check_task-status.js create mode 100644 test/test_mergedData.js diff --git a/test/check_task-status.js b/test/check_task-status.js new file mode 100644 index 00000000..7fde847e --- /dev/null +++ b/test/check_task-status.js @@ -0,0 +1,10 @@ +const { Connection, PublicKey } = require('@_koi/web3.js'); +async function main() { + const connection = new Connection('https://k2-devnet.koii.live'); + const accountInfo = await connection.getAccountInfo( + new PublicKey('HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP'), + ); + console.log(JSON.parse(accountInfo.data+"")); +} + +main(); \ No newline at end of file diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js index 9297997d..0472a0e5 100644 --- a/test/test_docker_submitlinktree.js +++ b/test/test_docker_submitlinktree.js @@ -48,7 +48,7 @@ try { console.log(payload); await axios - .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/register-linktree', {payload}) + .post('http://localhost:8080/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/register-linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); diff --git a/test/test_mergedData.js b/test/test_mergedData.js new file mode 100644 index 00000000..17014e4b --- /dev/null +++ b/test/test_mergedData.js @@ -0,0 +1,99 @@ +const dataFromCid = require("../helpers/dataFromCid"); + +async function mergedData() { + // Write the logic to fetch the submission values here and return the cid string + + // fetching round number to store work accordingly + + console.log('***********IN FETCH SUBMISSION**************'); + // The code below shows how you can fetch your stored value from level DB + let cid = 'bafybeiawmee7fohpdm7po7txii22pawjvzy374fhppdruvcckjowxs74ay'; + console.log('Linktree CID', cid); + + // fetch the cid data from IPFS + const outputraw = await dataFromCid(cid); + const output = outputraw.data; + const linktrees_list_object = output.data; + console.log('RESPONSE DATA', linktrees_list_object); + + // compare the linktrees_list_object with the data stored in levelDB + const linktrees_list_object_local = [{ + data: { + uuid: '202400b2-7c8f-420d-8215-7cf0e53dfd76', + linktree: [ + { + key: 'New data', + label: 'New data', + redirectUrl: 'New data', + }, + { + key: 'twitter', + label: 'Twitter', + redirectUrl: 'https://twitter.com/blockchainbalak', + }, + { + key: 'github', + label: 'GitHub', + redirectUrl: 'https://github.com/spheronFdn/', + }, + ], + timestamp: 1680805628220, + }, + publicKey: '7Se5mr1WyfzvXvNPu4f8Ck8WxeByACX3pfuxGQsMgsz5', + signature: + '5LQ8NBP9SFy2N9ePdkUrfqR1P6cyqLP2HjCDxcxYQN9ZxAdNQuH43oQ1MH3HtiDKMUKmqkNkZunkRHkLfg8VJVoZ', + }, + {data: { + uuid: '202400b2-7c8f-420d-8215-7cf0e53dfd76', + linktree: [ + { + key: 'New data', + label: 'New data', + redirectUrl: 'New data', + }, + { + key: 'twitter', + label: 'Twitter', + redirectUrl: 'https://twitter.com/blockchainbalak', + }, + { + key: 'github', + label: 'GitHub', + redirectUrl: 'https://github.com/spheronFdn/', + }, + ], + timestamp: 1680805628220, + }, + publicKey: 'newpublickey', + signature: + '5LQ8NBP9SFy2N9ePdkUrfqR1P6cyqLP2HjCDxcxYQN9ZxAdNQuH43oQ1MH3HtiDKMUKmqkNkZunkRHkLfg8VJVoZ', +}]; + + // if the same key is present in both the objects, the value from the first object will be taken + const mergedData = []; + + linktrees_list_object.forEach((itemCID) => { + // Check if an item with the same publicKey exists in linktrees_list_object_local + const matchingItemIndex = linktrees_list_object_local.findIndex((itemLocal) => itemLocal.publicKey === itemCID.publicKey); + if (matchingItemIndex >= 0) { + // If a matching item is found, compare timestamps + const matchingItemLocal = linktrees_list_object_local[matchingItemIndex]; + if (matchingItemLocal.data.timestamp > itemCID.data.timestamp) { + mergedData.push(matchingItemLocal); + // Remove the matching item from linktrees_list_object_local + linktrees_list_object_local.splice(matchingItemIndex, 1); + } else { + mergedData.push(itemCID); + } + } else { + mergedData.push(itemCID); + } + }); + + mergedData.push(...linktrees_list_object_local); + + console.log('mergedData', mergedData); + console.log('mergedData', mergedData[0].data.linktree); +} + +mergedData(); From b350b0d1051c53aad3fa6ddf43abafc3916b07d9 Mon Sep 17 00:00:00 2001 From: soma Date: Mon, 10 Apr 2023 12:23:57 -0300 Subject: [PATCH 31/61] remove unused test --- check_task-status.js | 10 ---------- config-task.yml | 8 ++++---- coreLogic.js | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) delete mode 100644 check_task-status.js diff --git a/check_task-status.js b/check_task-status.js deleted file mode 100644 index 9b86d620..00000000 --- a/check_task-status.js +++ /dev/null @@ -1,10 +0,0 @@ -const { Connection, PublicKey } = require('@_koi/web3.js'); -async function main() { - const connection = new Connection('https://k2-testnet.koii.live'); - const accountInfo = await connection.getAccountInfo( - new PublicKey('7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo'), - ); - console.log(JSON.parse(accountInfo.data+"")); -} - -main(); \ No newline at end of file diff --git a/config-task.yml b/config-task.yml index e280f7f8..1c691ce3 100644 --- a/config-task.yml +++ b/config-task.yml @@ -1,13 +1,13 @@ # Name and desciption sof your task -task_name: "test-task" -task_description: "This task is to test out the namespace function" +task_name: "linktree-task" +task_description: "linktree-task" # network value can be DEVELOPMENT , ARWEAVE or IPFS task_executable_network: "DEVELOPMENT" # Provide your web.storage key in case of IPFS otherwise leave blank -secret_web3_storage_key: "" +secret_web3_storage_key: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw" # Path to your executable webpack if the selected network is IPFS otherwise leave blank -task_audit_program: "" +task_audit_program: "/home/soma/code-ie/task-template-linktree/dist/main.js" # Provide your transaction ID in case of ARWEAVE and in case of DEVELOPMENT give your executable name as main otherwise leave blank task_audit_program_id: "main" diff --git a/coreLogic.js b/coreLogic.js index 45b19354..f899681f 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -28,6 +28,46 @@ class CoreLogic { const cid = await namespaceWrapper.storeGet('cid'); // retrieves the cid console.log('Linktree CID', cid); + + // fetch the cid data from IPFS + const outputraw = await dataFromCid(cid); + const output = outputraw.data; + const linktrees_list_object = output.data; + console.log('RESPONSE DATA', linktrees_list_object); + + + // compare the linktrees_list_object with the data stored in levelDB + const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); + const linktrees_list_object_local = JSON.parse(linktrees_list_string); + + // if the same key is present in both the objects, the value from the first object will be taken + const mergedData = []; + + linktrees_list_object.forEach((itemCID) => { + // Check if an item with the same publicKey exists in linktrees_list_object_local + const matchingItemIndex = linktrees_list_object_local.findIndex((itemLocal) => itemLocal.publicKey === itemCID.publicKey); + if (matchingItemIndex >= 0) { + // If a matching item is found, compare timestamps + const matchingItemLocal = linktrees_list_object_local[matchingItemIndex]; + if (matchingItemLocal.data.timestamp > itemCID.data.timestamp) { + mergedData.push(matchingItemLocal); + // Remove the matching item from linktrees_list_object_local + linktrees_list_object_local.splice(matchingItemIndex, 1); + } else { + mergedData.push(itemCID); + } + } else { + mergedData.push(itemCID); + } + }); + + mergedData.push(...linktrees_list_object_local); + + console.log('mergedData', mergedData); + + // store the data in levelDB + await namespaceWrapper.storeSet("linktrees", mergedData); + return cid; } From 154a6fe378b1b2f91b51c4ce209db63ab28575eb Mon Sep 17 00:00:00 2001 From: soma Date: Mon, 10 Apr 2023 13:51:15 -0300 Subject: [PATCH 32/61] seperate linktree and proofs --- index.js | 23 +++++++++++++++++------ test/get_local_leveldb.js | 3 +++ test/test_docker_submitlinktree.js | 4 +--- test/test_submitLinktree.js | 4 +--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 567b1acc..0f322444 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ const express = require('express'); const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); const {default: axios} = require('axios'); const bs58 = require('bs58'); +const solanaWeb3 = require('@solana/web3.js'); const nacl = require('tweetnacl'); const fs = require('fs'); @@ -183,7 +184,7 @@ if (app) { } else { console.log(linktree); } - + const { secretKey: secretKey } = solanaWeb3.Keypair.generate(); // TODO: validate the linktree structure here /* 1. Must have the following structure @@ -198,23 +199,33 @@ if (app) { timestamp:76576465, }, publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", - signature:"hjgasdjasbhmnbjhasgdkjsahjdkhgsakjdhgsajhyg" } */ // Use the code below to sign the data payload const msg = new TextEncoder().encode(JSON.stringify(linktree.data)); - const secretKey = nacl.sign.keyPair().secretKey; - const signature = nacl.sign.detached(msg, secretKey); + let signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + + let proof = { + publicKey: linktree.publicKey, + signature: signature, + } + console.log('Check Proof:', proof); - console.log('Check Signature:', bs58.encode(signature)); let allLinktrees = await namespaceWrapper.storeGet('linktrees'); allLinktrees = JSON.parse(allLinktrees || '[]'); allLinktrees.push(linktree); console.log("NEW all Linktrees: ", allLinktrees); await namespaceWrapper.storeSet('linktrees', JSON.stringify(allLinktrees)); - return res.status(200).send({message: 'Linktree registered successfully'}); + + let allproofs = await namespaceWrapper.storeGet('proofs'); + allproofs = JSON.parse(allproofs || '[]'); + allproofs.push(proof); + console.log("NEW all Proofs: ", allproofs); + await namespaceWrapper.storeSet('proofs', JSON.stringify(allproofs)); + + return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); app.get('/get-all-linktrees', async (req, res) => { let allLinktrees = await namespaceWrapper.storeGet('linktrees'); diff --git a/test/get_local_leveldb.js b/test/get_local_leveldb.js index e613d46d..2da94a2a 100644 --- a/test/get_local_leveldb.js +++ b/test/get_local_leveldb.js @@ -5,6 +5,9 @@ async function getLocalLevelDB() { // await namespaceWrapper.storeSet("linktrees", []); linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); console.log("Linktrees list string", linktrees_list_string); + + Proof_list_string = await namespaceWrapper.storeGet("proofs"); + console.log("Proofs list string", Proof_list_string); } getLocalLevelDB(); \ No newline at end of file diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js index 0472a0e5..aa72699f 100644 --- a/test/test_docker_submitlinktree.js +++ b/test/test_docker_submitlinktree.js @@ -41,11 +41,9 @@ try { }, publicKey: publicKey, }; - const msg = new TextEncoder().encode(JSON.stringify(payload.data)); - payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); // Check payload - console.log(payload); + // console.log(payload); await axios .post('http://localhost:8080/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/register-linktree', {payload}) diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index c9638f08..ee5f9a6a 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -41,11 +41,9 @@ try { }, publicKey: publicKey, }; - const msg = new TextEncoder().encode(JSON.stringify(payload.data)); - payload.signature = bs58.encode(nacl.sign.detached(msg, secretKey)); // Check payload - console.log(payload); + // console.log(payload); await axios .post('http://localhost:10000/register-linktree', {payload}) From 4132151db9ca98fb19d739f560037ed3ef3b83ab Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 02:22:25 -0300 Subject: [PATCH 33/61] update endpoint --- coreLogic.js | 6 +-- index.js | 38 +++++++++++++------ linktree_task.js | 22 ++++------- ...7fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json | 1 + package.json | 5 ++- test/test_submitLinktree.js | 8 ++-- test/unitTest.js | 4 +- 7 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json diff --git a/coreLogic.js b/coreLogic.js index f899681f..37ba2b23 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -9,9 +9,9 @@ class CoreLogic { // run linktree task console.log('*********task() started*********'); - const cid = await linktree_task(); - if (cid) { - await namespaceWrapper.storeSet('cid', cid); // store CID in levelDB + const proof_cid = await linktree_task(); + if (proof_cid) { + await namespaceWrapper.storeSet('node_proofs', proof_cid); // store CID in levelDB } else { console.log('CID NOT FOUND'); } diff --git a/index.js b/index.js index 0f322444..885a31ae 100644 --- a/index.js +++ b/index.js @@ -206,20 +206,21 @@ if (app) { const msg = new TextEncoder().encode(JSON.stringify(linktree.data)); let signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + let pubkey = linktree.publicKey let proof = { - publicKey: linktree.publicKey, + publicKey: pubkey, signature: signature, } console.log('Check Proof:', proof); + // use fs to write the linktree and proof to a file + fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); + // fs.writeFileSync('proof.json', JSON.stringify(proof)); + await namespaceWrapper.storeSet(`linktree:${pubkey}`, JSON.stringify(linktree)); - let allLinktrees = await namespaceWrapper.storeGet('linktrees'); - allLinktrees = JSON.parse(allLinktrees || '[]'); - allLinktrees.push(linktree); - console.log("NEW all Linktrees: ", allLinktrees); - await namespaceWrapper.storeSet('linktrees', JSON.stringify(allLinktrees)); + // Store all of the proofs into CID - let allproofs = await namespaceWrapper.storeGet('proofs'); + let allproofs = await namespaceWrapper.storeGet(`proofs`); allproofs = JSON.parse(allproofs || '[]'); allproofs.push(proof); console.log("NEW all Proofs: ", allproofs); @@ -227,14 +228,27 @@ if (app) { return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); - app.get('/get-all-linktrees', async (req, res) => { - let allLinktrees = await namespaceWrapper.storeGet('linktrees'); - allLinktrees = JSON.parse(allLinktrees || '[]'); - return res.status(200).send(allLinktrees); - }); + // app.get('/get-all-linktrees', async (req, res) => { + // let allLinktrees = await namespaceWrapper.storeGet('linktrees'); + // allLinktrees = JSON.parse(allLinktrees || '[]'); + // return res.status(200).send(allLinktrees); + // }); app.get("/get-logs", async (req, res) => { const logs = fs.readFileSync("./namespace/logs.txt", "utf8") res.status(200).send(logs); }) + // endpoint for specific linktree data by publicKey + app.get('/get-linktree', async (req, res) => { + const log = "Nothing to see here, check /:publicKey to get the linktree" + return res.status(200).send(log); + }); + app.get('/get-linktree/:publicKey', async (req, res) => { + const { publicKey } = req.params; + let linktree = await namespaceWrapper.storeGet(`linktree:${publicKey}`); + linktree = JSON.parse(linktree || '[]'); + return res.status(200).send(linktree); + } + ); + } diff --git a/linktree_task.js b/linktree_task.js index c6014af7..61013da7 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -4,7 +4,7 @@ const deleteFile = require('./helpers/deleteFile'); const fs = require('fs'); const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: process.env.SECRET_WEB3_STORAGE_KEY, + token: process.env.SECRET_WEB3_STORAGE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", }); const bs58 = require('bs58'); const nacl = require('tweetnacl'); @@ -26,32 +26,26 @@ module.exports = async () => { const signature = signedMessage.slice(0, nacl.sign.signatureLength); const submission_value = { - data: linktrees_list_object, + // data: linktrees_list_object, publicKey: bs58.encode(publicKey), signature: bs58.encode(signature), }; // upload the index of the linktree on web3.storage - const path = `./testLinktree/test.json`; - if (!fs.existsSync('./testLinktree')) fs.mkdirSync('./testLinktree'); + const path = `./Linktree/proofs.json`; + if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); console.log('PATH', path); await createFile(path, submission_value); if (storageClient) { const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log('User Linktrees uploaded to IPFS: ', cid); + const proof_cid = await storageClient.put(file); + console.log('User Linktrees proof uploaded to IPFS: ', proof_cid); // deleting the file from fs once it is uploaded to IPFS await deleteFile(path); - // Store the cid in localdb - try { - await namespaceWrapper.storeSet('testlinktree', cid); - } catch (err) { - console.log('ERROR IN STORING test linktree', err); - res.status(404).json({ message: 'ERROR in storing test linktree' }); - } - return cid; + return proof_cid; + } else { console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); } diff --git a/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json b/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json new file mode 100644 index 00000000..25dc662e --- /dev/null +++ b/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json @@ -0,0 +1 @@ +{"data":{"uuid":"45d97130-dcf2-498a-86c2-bb01909f67b1","linktree":[{"key":"official","label":"Official Website","redirectUrl":"https://spheron.network/"},{"key":"twitter","label":"Twitter","redirectUrl":"https://twitter.com/blockchainbalak"},{"key":"github","label":"GitHub","redirectUrl":"https://github.com/spheronFdn/"}],"timestamp":1681190191399},"publicKey":"39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui"} \ No newline at end of file diff --git a/package.json b/package.json index 12777f01..cd0ff7da 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "node test/unitTest.js", + "test:submit": "node test/submitLinktree.js", + "test:getdb": "node test/get_local_leveldb.js", + "status": "node test/check_task-status.js", "start": "node index.js", "webpack": "webpack", "webpack:prod": "webpack --mode production" diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index ee5f9a6a..bfa1ad0a 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -9,8 +9,6 @@ const crypto = require('crypto'); // This test submits linktrees from differnet publicKey to the service and stored in localdb async function main() { try { - for (let i = 0; i < 5; i++) { - console.log('i', i); const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) @@ -57,9 +55,9 @@ try { console.error(e); }); } -} catch (e) { - console.error(e) -} + catch (e) { + console.error(e); + } } main(); diff --git a/test/unitTest.js b/test/unitTest.js index 622a91a1..cef8588f 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -3,8 +3,8 @@ const index = require('../index'); async function test_coreLogic() { await coreLogic.task(); - const submission = await coreLogic.fetchSubmission(); - const vote = await coreLogic.validateNode(submission, 1); + // const submission = await coreLogic.fetchSubmission(); + // const vote = await coreLogic.validateNode(submission, 1); // let vote = true; // const _dummyTaskState = { // submissions: { From 8bbf6caacf1d0b933ecb54a3c43b87b8fb33601e Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 10:51:44 -0300 Subject: [PATCH 34/61] update gitignore --- .gitignore | 3 ++- .../linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json diff --git a/.gitignore b/.gitignore index e506791e..0d99fcd1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ config/* taskStateInfoKeypair.json localKOIIDB .env -taskStateInfoKeypair.json \ No newline at end of file +taskStateInfoKeypair.json +linktree diff --git a/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json b/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json deleted file mode 100644 index 25dc662e..00000000 --- a/linktrees/linktree_39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"uuid":"45d97130-dcf2-498a-86c2-bb01909f67b1","linktree":[{"key":"official","label":"Official Website","redirectUrl":"https://spheron.network/"},{"key":"twitter","label":"Twitter","redirectUrl":"https://twitter.com/blockchainbalak"},{"key":"github","label":"GitHub","redirectUrl":"https://github.com/spheronFdn/"}],"timestamp":1681190191399},"publicKey":"39y93G17fchhnqwxnukhF4sSved1bzfz54AGhRcEHXui"} \ No newline at end of file From 7442482c84c5a315ac02c5f7928b56199a9949c8 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 11:58:26 -0300 Subject: [PATCH 35/61] fix minor bugs --- .gitignore | 2 +- index.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0d99fcd1..9a1cb051 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,4 @@ taskStateInfoKeypair.json localKOIIDB .env taskStateInfoKeypair.json -linktree +linktrees diff --git a/index.js b/index.js index 885a31ae..e3c7e14d 100644 --- a/index.js +++ b/index.js @@ -214,6 +214,7 @@ if (app) { } console.log('Check Proof:', proof); // use fs to write the linktree and proof to a file + if (!fs.existsSync(__dirname + '/linktrees')) fs.mkdirSync(__dirname + '/linktrees'); fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); // fs.writeFileSync('proof.json', JSON.stringify(proof)); await namespaceWrapper.storeSet(`linktree:${pubkey}`, JSON.stringify(linktree)); @@ -223,7 +224,7 @@ if (app) { let allproofs = await namespaceWrapper.storeGet(`proofs`); allproofs = JSON.parse(allproofs || '[]'); allproofs.push(proof); - console.log("NEW all Proofs: ", allproofs); + // console.log("NEW all Proofs: ", allproofs); await namespaceWrapper.storeSet('proofs', JSON.stringify(allproofs)); return res.status(200).send({message: 'Proof and linktree registered successfully'}); From 0b49f30357a0c5f32e800efaca92467aaf3bfa99 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 14:06:28 -0300 Subject: [PATCH 36/61] update submit list and return cid --- coreLogic.js | 47 ++++++++-------------------------------- index.js | 2 +- linktree_task.js | 12 +++++----- test/test_cidCreation.js | 35 +++++++++++++----------------- 4 files changed, 31 insertions(+), 65 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index 37ba2b23..967e7d64 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -10,8 +10,9 @@ class CoreLogic { // run linktree task console.log('*********task() started*********'); const proof_cid = await linktree_task(); + const round = await namespaceWrapper.getRound(); if (proof_cid) { - await namespaceWrapper.storeSet('node_proofs', proof_cid); // store CID in levelDB + await namespaceWrapper.storeSet(`node_proofs:${round}`, proof_cid); // store CID in levelDB } else { console.log('CID NOT FOUND'); } @@ -25,50 +26,20 @@ class CoreLogic { console.log('***********IN FETCH SUBMISSION**************'); // The code below shows how you can fetch your stored value from level DB - - const cid = await namespaceWrapper.storeGet('cid'); // retrieves the cid - console.log('Linktree CID', cid); + const round = await namespaceWrapper.getRound(); + const proof_cid = await namespaceWrapper.storeGet(`node_proofs:${round}`); // retrieves the cid + console.log('Linktree proofs CID', proof_cid); // fetch the cid data from IPFS - const outputraw = await dataFromCid(cid); + const outputraw = await dataFromCid(proof_cid); const output = outputraw.data; - const linktrees_list_object = output.data; - console.log('RESPONSE DATA', linktrees_list_object); + const proofs_list_object = output.data; + console.log('RESPONSE DATA', proofs_list_object); - - // compare the linktrees_list_object with the data stored in levelDB - const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); - const linktrees_list_object_local = JSON.parse(linktrees_list_string); - - // if the same key is present in both the objects, the value from the first object will be taken - const mergedData = []; - - linktrees_list_object.forEach((itemCID) => { - // Check if an item with the same publicKey exists in linktrees_list_object_local - const matchingItemIndex = linktrees_list_object_local.findIndex((itemLocal) => itemLocal.publicKey === itemCID.publicKey); - if (matchingItemIndex >= 0) { - // If a matching item is found, compare timestamps - const matchingItemLocal = linktrees_list_object_local[matchingItemIndex]; - if (matchingItemLocal.data.timestamp > itemCID.data.timestamp) { - mergedData.push(matchingItemLocal); - // Remove the matching item from linktrees_list_object_local - linktrees_list_object_local.splice(matchingItemIndex, 1); - } else { - mergedData.push(itemCID); - } - } else { - mergedData.push(itemCID); - } - }); - - mergedData.push(...linktrees_list_object_local); - - console.log('mergedData', mergedData); - // store the data in levelDB await namespaceWrapper.storeSet("linktrees", mergedData); - return cid; + return proof_cid; } async generateDistributionList(round, _dummyTaskState) { diff --git a/index.js b/index.js index e3c7e14d..b8361a3a 100644 --- a/index.js +++ b/index.js @@ -224,7 +224,7 @@ if (app) { let allproofs = await namespaceWrapper.storeGet(`proofs`); allproofs = JSON.parse(allproofs || '[]'); allproofs.push(proof); - // console.log("NEW all Proofs: ", allproofs); + console.log("NEW all Proofs: ", allproofs); await namespaceWrapper.storeSet('proofs', JSON.stringify(allproofs)); return res.status(200).send({message: 'Proof and linktree registered successfully'}); diff --git a/linktree_task.js b/linktree_task.js index 61013da7..7701a3d4 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -16,19 +16,19 @@ module.exports = async () => { const publicKey = keyPair.publicKey; const privateKey = keyPair.secretKey; // Get linktree list fron localdb - const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); - const linktrees_list_object = JSON.parse(linktrees_list_string); + const proofs_list_string = await namespaceWrapper.storeGet('proofs'); + const proofs_list_object = JSON.parse(proofs_list_string); const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), + Buffer.from(JSON.stringify(proofs_list_object)), ); const signedMessage = nacl.sign(messageUint8Array, privateKey); const signature = signedMessage.slice(0, nacl.sign.signatureLength); const submission_value = { - // data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), + proofs: proofs_list_object, + node_publicKey: bs58.encode(publicKey), + node_signature: bs58.encode(signature), }; // upload the index of the linktree on web3.storage const path = `./Linktree/proofs.json`; diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js index f6de80ae..a9fdd2ff 100644 --- a/test/test_cidCreation.js +++ b/test/test_cidCreation.js @@ -11,51 +11,46 @@ const storageClient = new Web3Storage({ }); async function cidcreation() { - console.log('******/ TEST Linktree CID CREATION Task FUNCTION /******'); + console.log('******/ IN Linktree Task FUNCTION /******'); + // Customize linktree test data const keyPair = nacl.sign.keyPair(); const publicKey = keyPair.publicKey; const privateKey = keyPair.secretKey; // Get linktree list fron localdb - const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); - const linktrees_list_object = JSON.parse(linktrees_list_string); + const proofs_list_string = await namespaceWrapper.storeGet('proofs'); + const proofs_list_object = JSON.parse(proofs_list_string); const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), + Buffer.from(JSON.stringify(proofs_list_object)), ); const signedMessage = nacl.sign(messageUint8Array, privateKey); const signature = signedMessage.slice(0, nacl.sign.signatureLength); const submission_value = { - data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), + proofs: proofs_list_object, + node_publicKey: bs58.encode(publicKey), + node_signature: bs58.encode(signature), }; // upload the index of the linktree on web3.storage - const path = `testLinktree/test.json`; + const path = `./Linktree/proofs.json`; + if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); console.log('PATH', path); - if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); await createFile(path, submission_value); if (storageClient) { const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log('User Linktrees uploaded to IPFS: ', cid); + const proof_cid = await storageClient.put(file); + console.log('User Linktrees proof uploaded to IPFS: ', proof_cid); // deleting the file from fs once it is uploaded to IPFS await deleteFile(path); - // Store the cid in localdb - try { - await namespaceWrapper.storeSet('testlinktree', cid); - } catch (err) { - console.log('ERROR IN STORING test linktree', err); - res.status(404).json({ message: 'ERROR in storing test linktree' }); - } - return cid; + return proof_cid; + } else { console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); } -} +}; cidcreation(); module.exports = cidcreation; From 2acde9d206a4faea3871c988eb395595f4a7cc92 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 14:42:51 -0300 Subject: [PATCH 37/61] update localdb format --- coreLogic.js | 20 +++++++++----------- index.js | 8 ++++++-- test/get_local_leveldb.js | 14 ++++++++++---- test/test_cidCreation.js | 2 +- test/unitTest.js | 3 ++- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index 967e7d64..cfb5b6b6 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -2,6 +2,7 @@ const { namespaceWrapper } = require('./namespaceWrapper'); const linktree_task = require('./linktree_task'); const linktree_validate = require('./linktree_validate'); const crypto = require('crypto'); +const dataFromCid = require("./helpers/dataFromCid"); class CoreLogic { async task() { @@ -10,7 +11,9 @@ class CoreLogic { // run linktree task console.log('*********task() started*********'); const proof_cid = await linktree_task(); - const round = await namespaceWrapper.getRound(); + // const round = await namespaceWrapper.getRound(); + // For only testing purposes: + const round = 1000 if (proof_cid) { await namespaceWrapper.storeSet(`node_proofs:${round}`, proof_cid); // store CID in levelDB } else { @@ -26,19 +29,14 @@ class CoreLogic { console.log('***********IN FETCH SUBMISSION**************'); // The code below shows how you can fetch your stored value from level DB - const round = await namespaceWrapper.getRound(); + + // For only testing purposes: + const round = 1000 + // const round = await namespaceWrapper.getRound(); + const proof_cid = await namespaceWrapper.storeGet(`node_proofs:${round}`); // retrieves the cid console.log('Linktree proofs CID', proof_cid); - // fetch the cid data from IPFS - const outputraw = await dataFromCid(proof_cid); - const output = outputraw.data; - const proofs_list_object = output.data; - console.log('RESPONSE DATA', proofs_list_object); - - // store the data in levelDB - await namespaceWrapper.storeSet("linktrees", mergedData); - return proof_cid; } diff --git a/index.js b/index.js index b8361a3a..01ec2200 100644 --- a/index.js +++ b/index.js @@ -221,11 +221,15 @@ if (app) { // Store all of the proofs into CID + // const round = await namespaceWrapper.getRound(); + // For only testing purposes: + const round = 1000 + let allproofs = await namespaceWrapper.storeGet(`proofs`); allproofs = JSON.parse(allproofs || '[]'); allproofs.push(proof); - console.log("NEW all Proofs: ", allproofs); - await namespaceWrapper.storeSet('proofs', JSON.stringify(allproofs)); + console.log(`Round ${round} Proofs: `, allproofs); + await namespaceWrapper.storeSet(`proofs:${round}`, JSON.stringify(allproofs)); return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); diff --git a/test/get_local_leveldb.js b/test/get_local_leveldb.js index 2da94a2a..15fcd94c 100644 --- a/test/get_local_leveldb.js +++ b/test/get_local_leveldb.js @@ -1,13 +1,19 @@ +const { PublicKey } = require("@_koi/web3.js"); const { namespaceWrapper } = require("../namespaceWrapper"); async function getLocalLevelDB() { - let linktrees_list_string; + let linktree_string; // await namespaceWrapper.storeSet("linktrees", []); - linktrees_list_string = await namespaceWrapper.storeGet("linktrees"); - console.log("Linktrees list string", linktrees_list_string); + const PublicKey = 'Aw7taUvkq8dzK3gXWygB78b3UkA2XypB1rKEX256tBCG' + const round = 1000 + linktree_string = await namespaceWrapper.storeGet(`linktree:${PublicKey}`); + console.log("Linktree string", linktree_string); - Proof_list_string = await namespaceWrapper.storeGet("proofs"); + Proof_list_string = await namespaceWrapper.storeGet(`proofs:${round}`); console.log("Proofs list string", Proof_list_string); + + Node_Proof_cid = await namespaceWrapper.storeGet(`node_proofs:${round}`); + console.log("Node list string", Node_Proof_cid); } getLocalLevelDB(); \ No newline at end of file diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js index a9fdd2ff..6d19f504 100644 --- a/test/test_cidCreation.js +++ b/test/test_cidCreation.js @@ -17,7 +17,7 @@ async function cidcreation() { const publicKey = keyPair.publicKey; const privateKey = keyPair.secretKey; // Get linktree list fron localdb - const proofs_list_string = await namespaceWrapper.storeGet('proofs'); + const proofs_list_string = await namespaceWrapper.storeGet(`proofs:${round}`); const proofs_list_object = JSON.parse(proofs_list_string); const messageUint8Array = new Uint8Array( diff --git a/test/unitTest.js b/test/unitTest.js index cef8588f..21f781a6 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -3,7 +3,8 @@ const index = require('../index'); async function test_coreLogic() { await coreLogic.task(); - // const submission = await coreLogic.fetchSubmission(); + const submission = await coreLogic.fetchSubmission(); + console.log('SUBMISSION', submission); // const vote = await coreLogic.validateNode(submission, 1); // let vote = true; // const _dummyTaskState = { From 86964dcf3823dee0582509c910c5c91b292f22e3 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 20:36:34 -0300 Subject: [PATCH 38/61] update db model and testin --- .gitignore | 1 + db_model.js | 154 +++++++++++++++++++++++++++++++++++++++++ test/test_dbmodel.js | 28 ++++++++ test/test_readstram.js | 38 ++++++++++ 4 files changed, 221 insertions(+) create mode 100644 db_model.js create mode 100644 test/test_dbmodel.js create mode 100644 test/test_readstram.js diff --git a/.gitignore b/.gitignore index 9a1cb051..bfe68a21 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ localKOIIDB .env taskStateInfoKeypair.json linktrees +test/testdb \ No newline at end of file diff --git a/db_model.js b/db_model.js new file mode 100644 index 00000000..1dff25b0 --- /dev/null +++ b/db_model.js @@ -0,0 +1,154 @@ +const levelup = require('levelup'); +const leveldown = require('leveldown'); +const db = levelup(leveldown(__dirname + 'localKOIIDB')); + +// db functions for linktree +const getLinktree = async (publicKey) => { + return new Promise((resolve, reject) => { + db.get(getLinktreeId(publicKey), (err, value) => { + if (err) { + console.error("Error in getLinktree:", err); + resolve(null); + } else { + resolve(JSON.parse(value || "[]")); + } + }); + }); +} + +const setLinktree = async (publicKey, linktree) => { + db.put(getLinktreeId(publicKey), JSON.stringify(linktree)); + return console.log("Linktree set"); +} + +const getAllLinktrees = async () => { + const linktreesStream = db.createReadStream({ + lt: 'proofs:\xff', + reverse: true, + keys: true, + values: true +}) + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + }) + .on('error', function (err) { + console.log('Something went wrong in read linktreesStream!', err) + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + }) + + return linktreesStream; +} + +// db functions for proofs +const getProofs = async (round) => { + return new Promise((resolve, reject) => { + db.get(getProofsId(publicKey), (err, value) => { + if (err) { + console.error("Error in getProofs:", err); + resolve(null); + } else { + resolve(JSON.parse(value || "[]")); + } + }); + }); +} + +const setProofs = async (round, proofs) => { + db.put(getProofsId(round), JSON.stringify(proofs)); + return console.log("Proofs set"); +} + +const getAllProofs = async () => { + const proofsStream = db.createReadStream({ + lt: 'proofs:\xff', + reverse: true, + keys: true, + values: true +}) + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + }) + .on('error', function (err) { + console.log('Something went wrong in read proofsStream!', err) + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + }) + + return proofsStream; +} + +// db functions for node proofs +const getNodeProofCid = async (round) => { + return new Promise((resolve, reject) => { + db.get(getNodeProofCidid(publicKey), (err, value) => { + if (err) { + console.error("Error in getNodeProofCid:", err); + resolve(null); + } else { + resolve(JSON.parse(value || "[]")); + } + }); + }); +} + +const setNodeProofCid = async (round, cid) => { + db.put(getNodeProofCidid(round), cid); + return console.log("Node CID set"); +} + +const getAllNodeProofCids = async () => { + const cidsStream = db.createReadStream({ + lt: 'node_proofs:\xff', + reverse: true, + keys: true, + values: true +}) + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + }) + .on('error', function (err) { + console.log('Something went wrong in read cidsStream', err) + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + }) + + return cidsStream; +} + + +const getNodeProofCidid = (round) => { + return `node_proofs:${round}`; +} + +const getLinktreeId = (publicKey) => { + return `linktree:${publicKey}`; +} + +const getProofsId = (round) => { + return `proofs:${round}`; +} + +module.exports = { + getLinktree, + setLinktree, + getAllLinktrees, + getProofs, + setProofs, + getAllProofs, + getNodeProofCid, + setNodeProofCid, + getAllNodeProofCids +} \ No newline at end of file diff --git a/test/test_dbmodel.js b/test/test_dbmodel.js new file mode 100644 index 00000000..2944ea9c --- /dev/null +++ b/test/test_dbmodel.js @@ -0,0 +1,28 @@ +const dbmodel = require('../db_model'); + +const PublicKey = "testtesttesttesttesttest" + +async function testdb() { + // get linktree + // let linktree = await dbmodel.getLinktree(PublicKey); + // console.log(linktree); + + // get all linktrees + await dbmodel.getAllLinktrees(); + + // set linktree + // let linktree2 = { + // "name": "test2", + // "description": "test2", + // "avatar": "test2", + // "links": [ + // { + // "name": "test2", + // "url": "test2" + // } + // ] + // } + // await dbmodel.setLinktree(PublicKey, linktree2); +} + +testdb() \ No newline at end of file diff --git a/test/test_readstram.js b/test/test_readstram.js new file mode 100644 index 00000000..6f4509da --- /dev/null +++ b/test/test_readstram.js @@ -0,0 +1,38 @@ +const levelup = require('levelup'); +const leveldown = require('leveldown'); + +const db = levelup(leveldown('../localKOIIDB')); + +// for (let i = 0; i < 100; i++) { +// let key; +// if (i < 50) key = "proof:" + i; +// if (i >= 50) key = "linktree:" + i; +// let value = "value:" + i; +// db.put(key, value, function (err) { +// if (err) return console.log('Ooops!', err) // some kind of I/O error +// console.log('inserted + ' + i) +// } +// ) +// } + +db.createReadStream({ + // gt: 'proofs', + lt: 'linktree~', + reverse: true, + // limit: 10, + keys: true, + values: true +}) + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + + }) + .on('error', function (err) { + console.log('Oh my!', err) + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + }) \ No newline at end of file From 04c48210295b93e1b798a738e741303f100543ab Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 21:30:29 -0300 Subject: [PATCH 39/61] fix dbmodel bug --- db_model.js | 2 +- index.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/db_model.js b/db_model.js index 1dff25b0..e95daa44 100644 --- a/db_model.js +++ b/db_model.js @@ -47,7 +47,7 @@ const getAllLinktrees = async () => { // db functions for proofs const getProofs = async (round) => { return new Promise((resolve, reject) => { - db.get(getProofsId(publicKey), (err, value) => { + db.get(getProofsId(round), (err, value) => { if (err) { console.error("Error in getProofs:", err); resolve(null); diff --git a/index.js b/index.js index 01ec2200..9e2c96be 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const bs58 = require('bs58'); const solanaWeb3 = require('@solana/web3.js'); const nacl = require('tweetnacl'); const fs = require('fs'); +const db = require('./db_model'); async function setup() { @@ -68,7 +69,7 @@ async function setup() { return e.data.url; }); console.log(nodeUrlList); - let allLinktrees = await namespaceWrapper.storeGet('linktrees'); + let allLinktrees = await db.getLinktree(publicKey); allLinktrees = JSON.parse(allLinktrees || '[]'); for (let url of nodeUrlList) { console.log(url); @@ -217,7 +218,7 @@ if (app) { if (!fs.existsSync(__dirname + '/linktrees')) fs.mkdirSync(__dirname + '/linktrees'); fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); // fs.writeFileSync('proof.json', JSON.stringify(proof)); - await namespaceWrapper.storeSet(`linktree:${pubkey}`, JSON.stringify(linktree)); + await db.setLinktree(pubkey, linktree); // Store all of the proofs into CID @@ -225,7 +226,7 @@ if (app) { // For only testing purposes: const round = 1000 - let allproofs = await namespaceWrapper.storeGet(`proofs`); + let allproofs = await db.getProofs(round); allproofs = JSON.parse(allproofs || '[]'); allproofs.push(proof); console.log(`Round ${round} Proofs: `, allproofs); From 003abbef3afa9cb6efc1c8ff4d3c663b0ec0621f Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 11 Apr 2023 21:39:24 -0300 Subject: [PATCH 40/61] replace index store to db --- index.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 9e2c96be..73f752a7 100644 --- a/index.js +++ b/index.js @@ -220,25 +220,18 @@ if (app) { // fs.writeFileSync('proof.json', JSON.stringify(proof)); await db.setLinktree(pubkey, linktree); - // Store all of the proofs into CID - // const round = await namespaceWrapper.getRound(); // For only testing purposes: const round = 1000 - let allproofs = await db.getProofs(round); - allproofs = JSON.parse(allproofs || '[]'); - allproofs.push(proof); - console.log(`Round ${round} Proofs: `, allproofs); - await namespaceWrapper.storeSet(`proofs:${round}`, JSON.stringify(allproofs)); + let proofs = await db.getProofs(round); + proofs = JSON.parse(proofs || '[]'); + proofs.push(proof); + console.log(`Round ${round} Proofs: `, proofs); + await db.setProofs(round, proofs); return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); - // app.get('/get-all-linktrees', async (req, res) => { - // let allLinktrees = await namespaceWrapper.storeGet('linktrees'); - // allLinktrees = JSON.parse(allLinktrees || '[]'); - // return res.status(200).send(allLinktrees); - // }); app.get("/get-logs", async (req, res) => { const logs = fs.readFileSync("./namespace/logs.txt", "utf8") res.status(200).send(logs); @@ -250,9 +243,13 @@ if (app) { }); app.get('/get-linktree/:publicKey', async (req, res) => { const { publicKey } = req.params; - let linktree = await namespaceWrapper.storeGet(`linktree:${publicKey}`); + let linktree = await db.getLinktree(publicKey); linktree = JSON.parse(linktree || '[]'); return res.status(200).send(linktree); + }); + app.get('/get-alllinktree', async (req, res) => { + linktree = JSON.parse(await db.getAllLinktrees() || '[]'); + return res.status(200).send(linktree); } ); From d00d7e51c04919dd2d9b9488d3a3de437ee8625f Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 12:29:32 -0300 Subject: [PATCH 41/61] update dbmodel and index.js, more endpoint --- test/test_dbmodel.js | 52 +++++++++++++++++++++++++++---------- test/test_getallLinktree.js | 2 +- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/test/test_dbmodel.js b/test/test_dbmodel.js index 2944ea9c..2e6fd995 100644 --- a/test/test_dbmodel.js +++ b/test/test_dbmodel.js @@ -1,28 +1,54 @@ const dbmodel = require('../db_model'); -const PublicKey = "testtesttesttesttesttest" +const PublicKey = "test-pubkey1" async function testdb() { +const round = 1000; +const pubkey = PublicKey; + // get linktree // let linktree = await dbmodel.getLinktree(PublicKey); // console.log(linktree); // get all linktrees - await dbmodel.getAllLinktrees(); + // await dbmodel.getAllLinktrees(); // set linktree - // let linktree2 = { - // "name": "test2", - // "description": "test2", - // "avatar": "test2", - // "links": [ - // { - // "name": "test2", - // "url": "test2" - // } - // ] + let linktree2 = { + "name": "test1", + "description": "test1", + "avatar": "test1", + "links": [ + { + "name": "test1", + "url": "test1" + } + ] + } + await dbmodel.setLinktree(PublicKey, linktree2); + + // set node proofs + // let cid = "testcid" + // await dbmodel.setNodeProofCid(round, cid); + + // get node proofs + // let nodeProofs = await dbmodel.getNodeProofCid(round); + // console.log(nodeProofs); + + // set proofs + // let proofs = { + // publicKey: "test-pubkey1", + // signature: "test-signature1", // } - // await dbmodel.setLinktree(PublicKey, linktree2); + // await dbmodel.setProofs(pubkey, proofs); + + // get proofs + // let proofs = await dbmodel.getProofs(round); + // console.log(proofs); + + // get all proofs + // await dbmodel.getAllProofs(); + } testdb() \ No newline at end of file diff --git a/test/test_getallLinktree.js b/test/test_getallLinktree.js index 48d7b0f8..e6082df7 100644 --- a/test/test_getallLinktree.js +++ b/test/test_getallLinktree.js @@ -5,7 +5,7 @@ const nacl = require('tweetnacl'); const fs = require("fs") try { axios - .get('http://localhost:10000/get-all-linktrees') + .get('http://localhost:10000/get-alllinktree') .then((e) => { if (e.status != 200) { console.log(e); From 04b9d94260d334f71a9ee1c0c4153307de0e4290 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 12:29:54 -0300 Subject: [PATCH 42/61] more endpoints --- db_model.js | 140 +++++++++++++++++++++++++++++----------------------- index.js | 18 +++++-- 2 files changed, 92 insertions(+), 66 deletions(-) diff --git a/db_model.js b/db_model.js index e95daa44..33ddb8e0 100644 --- a/db_model.js +++ b/db_model.js @@ -1,6 +1,6 @@ const levelup = require('levelup'); const leveldown = require('leveldown'); -const db = levelup(leveldown(__dirname + 'localKOIIDB')); +const db = levelup(leveldown(__dirname + '/localKOIIDB')); // db functions for linktree const getLinktree = async (publicKey) => { @@ -22,32 +22,37 @@ const setLinktree = async (publicKey, linktree) => { } const getAllLinktrees = async () => { + return new Promise((resolve, reject) => { + let dataStore = []; const linktreesStream = db.createReadStream({ - lt: 'proofs:\xff', + lt: 'linktree~', reverse: true, keys: true, values: true }) - .on('data', function (data) { - console.log( data.key.toString(), '=', data.value.toString()) - }) - .on('error', function (err) { - console.log('Something went wrong in read linktreesStream!', err) - }) - .on('close', function () { - console.log('Stream closed') - }) - .on('end', function () { - console.log('Stream ended') - }) - - return linktreesStream; + linktreesStream + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString()) }); + }) + .on('error', function (err) { + console.log('Something went wrong in read linktreesStream!', err); + reject(err); + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + resolve(dataStore); + }) + }); } // db functions for proofs -const getProofs = async (round) => { +const getProofs = async (pubkey) => { return new Promise((resolve, reject) => { - db.get(getProofsId(round), (err, value) => { + db.get(getProofsId(pubkey), (err, value) => { if (err) { console.error("Error in getProofs:", err); resolve(null); @@ -58,43 +63,48 @@ const getProofs = async (round) => { }); } -const setProofs = async (round, proofs) => { - db.put(getProofsId(round), JSON.stringify(proofs)); +const setProofs = async (pubkey, proofs) => { + db.put(getProofsId(pubkey), JSON.stringify(proofs)); return console.log("Proofs set"); } const getAllProofs = async () => { - const proofsStream = db.createReadStream({ - lt: 'proofs:\xff', - reverse: true, - keys: true, - values: true -}) - .on('data', function (data) { - console.log( data.key.toString(), '=', data.value.toString()) - }) - .on('error', function (err) { - console.log('Something went wrong in read proofsStream!', err) - }) - .on('close', function () { - console.log('Stream closed') - }) - .on('end', function () { - console.log('Stream ended') + return new Promise((resolve, reject) => { + let dataStore = []; + const proofsStream = db.createReadStream({ + gte: 'proofs', + reverse: true, + keys: true, + values: true }) - - return proofsStream; + proofsStream + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString())}); + }) + .on('error', function (err) { + console.log('Something went wrong in read proofsStream!', err); + reject(err); + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + resolve(dataStore); + }) + }); } // db functions for node proofs const getNodeProofCid = async (round) => { return new Promise((resolve, reject) => { - db.get(getNodeProofCidid(publicKey), (err, value) => { + db.get(getNodeProofCidid(round), (err, value) => { if (err) { console.error("Error in getNodeProofCid:", err); resolve(null); } else { - resolve(JSON.parse(value || "[]")); + resolve(value.toString() || "[]"); } }); }); @@ -106,26 +116,32 @@ const setNodeProofCid = async (round, cid) => { } const getAllNodeProofCids = async () => { - const cidsStream = db.createReadStream({ - lt: 'node_proofs:\xff', - reverse: true, - keys: true, - values: true -}) - .on('data', function (data) { - console.log( data.key.toString(), '=', data.value.toString()) - }) - .on('error', function (err) { - console.log('Something went wrong in read cidsStream', err) - }) - .on('close', function () { - console.log('Stream closed') - }) - .on('end', function () { - console.log('Stream ended') + return new Promise((resolve, reject) => { + let dataStore = []; + const nodeProofsStream = db.createReadStream({ + gt: 'node_proofs:', + lt: 'node_proofs~', + reverse: true, + keys: true, + values: true }) - - return cidsStream; + nodeProofsStream + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + dataStore.push({ key: data.key.toString(), value: data.value.toString() }); + }) + .on('error', function (err) { + console.log('Something went wrong in read nodeProofsStream!', err); + reject(err); + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + resolve(dataStore); + }) + }); } @@ -137,8 +153,8 @@ const getLinktreeId = (publicKey) => { return `linktree:${publicKey}`; } -const getProofsId = (round) => { - return `proofs:${round}`; +const getProofsId = (pubkey) => { + return `proofs:${pubkey}`; } module.exports = { diff --git a/index.js b/index.js index 73f752a7..e1b1275c 100644 --- a/index.js +++ b/index.js @@ -224,11 +224,11 @@ if (app) { // For only testing purposes: const round = 1000 - let proofs = await db.getProofs(round); + let proofs = await db.getProofs(pubkey); proofs = JSON.parse(proofs || '[]'); proofs.push(proof); - console.log(`Round ${round} Proofs: `, proofs); - await db.setProofs(round, proofs); + console.log(`${pubkey} Proofs: `, proofs); + await db.setProofs(pubkey, proofs); return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); @@ -248,7 +248,17 @@ if (app) { return res.status(200).send(linktree); }); app.get('/get-alllinktree', async (req, res) => { - linktree = JSON.parse(await db.getAllLinktrees() || '[]'); + linktree = await db.getAllLinktrees() || '[]'; + return res.status(200).send(linktree); + } + ); + app.get('/get-allproofs', async (req, res) => { + linktree = await db.getAllProofs() || '[]'; + return res.status(200).send(linktree); + } + ); + app.get('/get-allnode-proofs', async (req, res) => { + linktree = await db.getAllNodeProofCids() || '[]'; return res.status(200).send(linktree); } ); From 546cfe812a8c8afbb6efae0647c0a1f24504afb7 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 13:19:40 -0300 Subject: [PATCH 43/61] update CoreLogic using db-model --- coreLogic.js | 7 ++++--- linktree_task.js | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index cfb5b6b6..17dc0ce4 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -3,6 +3,7 @@ const linktree_task = require('./linktree_task'); const linktree_validate = require('./linktree_validate'); const crypto = require('crypto'); const dataFromCid = require("./helpers/dataFromCid"); +const db = require('./db_model'); class CoreLogic { async task() { @@ -15,7 +16,7 @@ class CoreLogic { // For only testing purposes: const round = 1000 if (proof_cid) { - await namespaceWrapper.storeSet(`node_proofs:${round}`, proof_cid); // store CID in levelDB + await db.setNodeProofCid(round, proof_cid); // store CID in levelDB } else { console.log('CID NOT FOUND'); } @@ -34,8 +35,8 @@ class CoreLogic { const round = 1000 // const round = await namespaceWrapper.getRound(); - const proof_cid = await namespaceWrapper.storeGet(`node_proofs:${round}`); // retrieves the cid - console.log('Linktree proofs CID', proof_cid); + const proof_cid = await db.getNodeProofCid(round); // retrieves the cid + console.log('Linktree proofs CID', proof_cid, "in round", round); return proof_cid; } diff --git a/linktree_task.js b/linktree_task.js index 7701a3d4..fa9b0139 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -8,6 +8,7 @@ const storageClient = new Web3Storage({ }); const bs58 = require('bs58'); const nacl = require('tweetnacl'); +const db = require('./db_model'); module.exports = async () => { console.log('******/ IN Linktree Task FUNCTION /******'); @@ -16,8 +17,8 @@ module.exports = async () => { const publicKey = keyPair.publicKey; const privateKey = keyPair.secretKey; // Get linktree list fron localdb - const proofs_list_string = await namespaceWrapper.storeGet('proofs'); - const proofs_list_object = JSON.parse(proofs_list_string); + + const proofs_list_object = await db.getAllProofs(); const messageUint8Array = new Uint8Array( Buffer.from(JSON.stringify(proofs_list_object)), From e05524b7bdaf5a0d37d887373d961c26fe8138c8 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 13:37:25 -0300 Subject: [PATCH 44/61] remove unused test file --- test/get_local_leveldb.js | 19 --- test/test_cidCreation.js | 56 --------- ...est_getallLinktree.js => test_endpoint.js} | 0 test/test_generatedistribution.js | 0 test/test_index.js | 110 ------------------ test/test_readstram.js | 38 ------ test/test_withoutCID.js | 80 ------------- 7 files changed, 303 deletions(-) delete mode 100644 test/get_local_leveldb.js delete mode 100644 test/test_cidCreation.js rename test/{test_getallLinktree.js => test_endpoint.js} (100%) delete mode 100644 test/test_generatedistribution.js delete mode 100644 test/test_index.js delete mode 100644 test/test_readstram.js delete mode 100644 test/test_withoutCID.js diff --git a/test/get_local_leveldb.js b/test/get_local_leveldb.js deleted file mode 100644 index 15fcd94c..00000000 --- a/test/get_local_leveldb.js +++ /dev/null @@ -1,19 +0,0 @@ -const { PublicKey } = require("@_koi/web3.js"); -const { namespaceWrapper } = require("../namespaceWrapper"); - -async function getLocalLevelDB() { - let linktree_string; - // await namespaceWrapper.storeSet("linktrees", []); - const PublicKey = 'Aw7taUvkq8dzK3gXWygB78b3UkA2XypB1rKEX256tBCG' - const round = 1000 - linktree_string = await namespaceWrapper.storeGet(`linktree:${PublicKey}`); - console.log("Linktree string", linktree_string); - - Proof_list_string = await namespaceWrapper.storeGet(`proofs:${round}`); - console.log("Proofs list string", Proof_list_string); - - Node_Proof_cid = await namespaceWrapper.storeGet(`node_proofs:${round}`); - console.log("Node list string", Node_Proof_cid); -} - -getLocalLevelDB(); \ No newline at end of file diff --git a/test/test_cidCreation.js b/test/test_cidCreation.js deleted file mode 100644 index 6d19f504..00000000 --- a/test/test_cidCreation.js +++ /dev/null @@ -1,56 +0,0 @@ -const createFile = require('../helpers/createFile.js'); -const deleteFile = require('../helpers/deleteFile'); -const bs58 = require('bs58'); -const nacl = require('tweetnacl'); -const { namespaceWrapper } = require('../namespaceWrapper'); -const fs = require('fs'); -const { Web3Storage, getFilesFromPath } = require('web3.storage'); -const storageClient = new Web3Storage({ - token: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', -}); - -async function cidcreation() { - console.log('******/ IN Linktree Task FUNCTION /******'); - // Customize linktree test data - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; - // Get linktree list fron localdb - const proofs_list_string = await namespaceWrapper.storeGet(`proofs:${round}`); - const proofs_list_object = JSON.parse(proofs_list_string); - - const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(proofs_list_object)), - ); - const signedMessage = nacl.sign(messageUint8Array, privateKey); - const signature = signedMessage.slice(0, nacl.sign.signatureLength); - - const submission_value = { - proofs: proofs_list_object, - node_publicKey: bs58.encode(publicKey), - node_signature: bs58.encode(signature), - }; - // upload the index of the linktree on web3.storage - const path = `./Linktree/proofs.json`; - if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); - console.log('PATH', path); - await createFile(path, submission_value); - - if (storageClient) { - const file = await getFilesFromPath(path); - const proof_cid = await storageClient.put(file); - console.log('User Linktrees proof uploaded to IPFS: ', proof_cid); - - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); - - return proof_cid; - - } else { - console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); - } -}; - -cidcreation(); -module.exports = cidcreation; diff --git a/test/test_getallLinktree.js b/test/test_endpoint.js similarity index 100% rename from test/test_getallLinktree.js rename to test/test_endpoint.js diff --git a/test/test_generatedistribution.js b/test/test_generatedistribution.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/test_index.js b/test/test_index.js deleted file mode 100644 index 12c8af22..00000000 --- a/test/test_index.js +++ /dev/null @@ -1,110 +0,0 @@ -const { namespaceWrapper } = require('../namespaceWrapper'); -const createFile = require('../helpers/createFile.js'); -const deleteFile = require('../helpers/deleteFile'); -const bs58 = require('bs58'); -const nacl = require('tweetnacl'); -const fs = require('fs'); -const { Web3Storage, getFilesFromPath } = require('web3.storage'); -const storageClient = new Web3Storage({ - token: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw', -}); -const dataFromCid = require('../helpers/dataFromCid'); - -async function test() { - // 1 test submission - // await test_submission(); - // 2 test the cid creation (CID need to contain all of the linktree data and signature) - const cid = await cidCreation(); - // 3 test the validation of the cid - const check = await cidValidation(cid); - // 4 iterate over the cid and create distribution - - // 5 audit the distribution -} - -async function cidCreation() { - console.log('******/ TEST Linktree CID CREATION Task FUNCTION /******'); - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; - // Get linktree list fron localdb - const linktrees_list_string = await namespaceWrapper.storeGet('linktrees'); - const linktrees_list_object = JSON.parse(linktrees_list_string); - - const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), - ); - const signedMessage = nacl.sign(messageUint8Array, privateKey); - const signature = signedMessage.slice(0, nacl.sign.signatureLength); - - const submission_value = { - data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), - }; - // upload the index of the linktree on web3.storage - const path = `testLinktree/test.json`; - console.log('PATH', path); - if (!fs.existsSync('testLinktree')) fs.mkdirSync('testLinktree'); - await createFile(path, submission_value); - - if (storageClient) { - const file = await getFilesFromPath(path); - const cid = await storageClient.put(file); - console.log('User Linktrees uploaded to IPFS: ', cid); - - // deleting the file from fs once it is uploaded to IPFS - await deleteFile(path); - - // Store the cid in localdb - try { - await namespaceWrapper.storeSet('testlinktree', cid); - } catch (err) { - console.log('ERROR IN STORING test linktree', err); - res.status(404).json({ message: 'ERROR in storing test linktree' }); - } - return cid; - } else { - console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); - } -} - -async function cidValidation(submission_value) { - console.log('******/ TEST Linktree CID VALIDATION Task FUNCTION /******'); - const outputraw = await dataFromCid(submission_value); - const output = outputraw.data; - // for () - const linktrees_list_object = output.data; - console.log('RESPONSE DATA', linktrees_list_object); - const publicKey = output.publicKey; - console.log('PUBLIC KEY', publicKey); - const signature = output.signature; - console.log('SIGNATURE', signature); - - const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), - ); - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); - - if (!linktrees_list_object || !signature || !publicKey) { - console.error('No data received from web3.storage'); - return false; - } - - // verify the signature - const isSignatureValid = await verifySignature( - messageUint8Array, - signatureUint8Array, - publicKeyUint8Array, - ); - console.log(`Is the signature valid? ${isSignatureValid}`); - - return isSignatureValid; -} - -async function verifySignature(message, signature, publicKey) { - return nacl.sign.detached.verify(message, signature, publicKey); -} -test(); diff --git a/test/test_readstram.js b/test/test_readstram.js deleted file mode 100644 index 6f4509da..00000000 --- a/test/test_readstram.js +++ /dev/null @@ -1,38 +0,0 @@ -const levelup = require('levelup'); -const leveldown = require('leveldown'); - -const db = levelup(leveldown('../localKOIIDB')); - -// for (let i = 0; i < 100; i++) { -// let key; -// if (i < 50) key = "proof:" + i; -// if (i >= 50) key = "linktree:" + i; -// let value = "value:" + i; -// db.put(key, value, function (err) { -// if (err) return console.log('Ooops!', err) // some kind of I/O error -// console.log('inserted + ' + i) -// } -// ) -// } - -db.createReadStream({ - // gt: 'proofs', - lt: 'linktree~', - reverse: true, - // limit: 10, - keys: true, - values: true -}) - .on('data', function (data) { - console.log( data.key.toString(), '=', data.value.toString()) - - }) - .on('error', function (err) { - console.log('Oh my!', err) - }) - .on('close', function () { - console.log('Stream closed') - }) - .on('end', function () { - console.log('Stream ended') - }) \ No newline at end of file diff --git a/test/test_withoutCID.js b/test/test_withoutCID.js deleted file mode 100644 index a512537d..00000000 --- a/test/test_withoutCID.js +++ /dev/null @@ -1,80 +0,0 @@ -// test validation without cid -const { namespaceWrapper } = require("../namespaceWrapper"); -const createFile = require("../helpers/createFile.js"); -const deleteFile = require("../helpers/deleteFile"); -const bs58 = require('bs58'); -const nacl = require('tweetnacl'); -const fs = require("fs"); -const { Web3Storage, getFilesFromPath } = require("web3.storage"); -const storageClient = new Web3Storage({ - token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", - }); -const dataFromCid = require("../helpers/dataFromCid"); - -async function test() { - // 1 test submission - // await test_submission(); - // 2 test the cid creation (CID need to contain all of the linktree data and signature) - const submission_value = await cidCreation(); - // 3 test the validation of the cid - const check = await cidValidation(submission_value) - // 4 iterate over the cid and create distribution - // 5 audit the distribution -} - - -async function cidCreation(){ - console.log("******/ TEST Linktree CID CREATION Task FUNCTION /******"); - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; - - const linktrees_list_object = { - data: "data", - publicKey: '7AwybFMYogGa8LJ3n9i8QthUs6ybEcanC8UPejM76U7h', - signature: 'P6McSGFMniTdaH5546b8b1xuL91UtjxS9RnXMxBcg8ewuvKuFwijqJHH9BSZnEnqs1niE1xx7DreRVCNqK4ZJSE' - }; - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signedMessage = nacl.sign(messageUint8Array, privateKey); - const signature = signedMessage.slice(0, nacl.sign.signatureLength); - // console.log('Check Signature:', bs58.encode(signature)); - - const submission_value = { - data: linktrees_list_object, - publicKey: bs58.encode(publicKey), - signature: bs58.encode(signature), - } - // upload the index of the linktree on web3.storage - return submission_value -} - - -async function cidValidation(submission_value) { - console.log("******/ TEST Linktree CID VALIDATION Task FUNCTION /******"); - const output = submission_value - const linktrees_list_object = output.data; - console.log("RESPONSE DATA", linktrees_list_object); - const publicKey = output.publicKey; - console.log("PUBLIC KEY", publicKey); - const signature = output.signature; - console.log("SIGNATURE", signature); - const messageUint8Array = new Uint8Array(Buffer.from(JSON.stringify(linktrees_list_object))); - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); - // if (!output.data || !signature || !publicKey) { - // console.error("No data received from web3.storage"); - // return false; - // } - - // verify the signature - // console.log("Data wait to verify", linktreeIndexDataUint8Array); - const isSignatureValid = await verifySignature(messageUint8Array, signatureUint8Array, publicKeyUint8Array); - console.log(`Is the signature valid? ${isSignatureValid}`); - - return isSignatureValid; -} - -async function verifySignature(linktreeIndexData, signature, publicKey) { - return nacl.sign.detached.verify(linktreeIndexData, signature, publicKey); -} -test(); \ No newline at end of file From 0bfe2e6a163e7b30e5f8ec41ce005259977a7a51 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 16:36:42 -0300 Subject: [PATCH 45/61] add db for authlist, update cid validation --- coreLogic.js | 2 +- db_model.js | 58 ++++++++++++++++++++++++++++- index.js | 7 ++-- linktree_validate.js | 73 ++++++++++++++++++++++++++++++------- package.json | 2 +- test/test_cidValidation.js | 71 +++++++++++++++++++++++++++++------- test/test_submitLinktree.js | 58 ++++++++++++++++------------- test/unitTest.js | 4 +- 8 files changed, 216 insertions(+), 59 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index 17dc0ce4..3da7630c 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -121,7 +121,7 @@ class CoreLogic { // Write your logic for the validation of submission value here and return a boolean value in response console.log('Received submission_value', submission_value, round); - const vote = await linktree_validate(submission_value); + const vote = await linktree_validate(submission_value, round); // const generatedValue = await namespaceWrapper.storeGet("cid"); // console.log("GENERATED VALUE", generatedValue); // if(generatedValue == submission_value){ diff --git a/db_model.js b/db_model.js index 33ddb8e0..969c491b 100644 --- a/db_model.js +++ b/db_model.js @@ -144,6 +144,55 @@ const getAllNodeProofCids = async () => { }); } +//db functions fro Auth list +const getAuthList = async (round) => { + return new Promise((resolve, reject) => { + db.get(getAuthListId(round), (err, value) => { + if (err) { + console.error("Error in getAuthList:", err); + resolve(null); + } else { + resolve(JSON.parse(value || "[]")); + } + }); + }); +} + +const setAuthList = async (round, auth_list) => { + db.put(getAuthListId(round), JSON.stringify(auth_list)); + return console.log("Auth List set"); +} + +const getAllAuthLists = async () => { + return new Promise((resolve, reject) => { + let dataStore = []; + const authListStream = db.createReadStream({ + gt: 'auth_list:', + lt: 'auth_list~', + reverse: true, + keys: true, + values: true + }) + authListStream + .on('data', function (data) { + console.log( data.key.toString(), '=', data.value.toString()) + dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString()) }); + }) + .on('error', function (err) { + console.log('Something went wrong in read authListStream!', err); + reject(err); + }) + .on('close', function () { + console.log('Stream closed') + }) + .on('end', function () { + console.log('Stream ended') + resolve(dataStore); + }) + }); +} + + const getNodeProofCidid = (round) => { return `node_proofs:${round}`; @@ -157,6 +206,10 @@ const getProofsId = (pubkey) => { return `proofs:${pubkey}`; } +const getAuthListId = (round) => { + return `auth_list:${round}`; +} + module.exports = { getLinktree, setLinktree, @@ -166,5 +219,8 @@ module.exports = { getAllProofs, getNodeProofCid, setNodeProofCid, - getAllNodeProofCids + getAllNodeProofCids, + getAuthList, + setAuthList, + getAllAuthLists } \ No newline at end of file diff --git a/index.js b/index.js index e1b1275c..d69c86fa 100644 --- a/index.js +++ b/index.js @@ -185,7 +185,7 @@ if (app) { } else { console.log(linktree); } - const { secretKey: secretKey } = solanaWeb3.Keypair.generate(); + // TODO: validate the linktree structure here /* 1. Must have the following structure @@ -200,13 +200,12 @@ if (app) { timestamp:76576465, }, publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", + signature:"" } */ // Use the code below to sign the data payload - - const msg = new TextEncoder().encode(JSON.stringify(linktree.data)); - let signature = bs58.encode(nacl.sign.detached(msg, secretKey)); + let signature = linktree.signature; let pubkey = linktree.publicKey let proof = { diff --git a/linktree_validate.js b/linktree_validate.js index 2515ea1d..a59a6769 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -1,39 +1,86 @@ -const { namespaceWrapper } = require("./namespaceWrapper"); const dataFromCid = require("./helpers/dataFromCid"); -const getKeys = require("./helpers/getKey"); -const hashCompare = require("./helpers/hashCompare"); +const db = require('./db_model'); const nacl = require('tweetnacl'); const bs58 = require('bs58'); -module.exports = async (submission_value) => { - console.log('******/ Linktree CID VALIDATION Task FUNCTION /******'); +module.exports = async (submission_value, round) => { + console.log('******/ Linktree CID VALIDATION Task FUNCTION /******'); const outputraw = await dataFromCid(submission_value); const output = outputraw.data; - const linktrees_list_object = output.data; - console.log('RESPONSE DATA', linktrees_list_object); - const publicKey = output.publicKey; + + const proofs_list_object = output.proofs; + console.log('RESPONSE DATA', proofs_list_object); + const publicKey = output.node_publicKey; console.log('PUBLIC KEY', publicKey); - const signature = output.signature; + const signature = output.node_signature; console.log('SIGNATURE', signature); + let isNode = await verifyNode(proofs_list_object, signature, publicKey); + console.log('IS NODE True?', isNode); + + + let AuthUserList = await db.getAuthList(round); + if (typeof AuthUserList === 'string') AuthUserList = JSON.parse(AuthUserList); + else AuthUserList = AuthUserList || []; + console.log('AuthUserList', AuthUserList); + let isLinktree = await verifyLinktree(proofs_list_object, AuthUserList); + console.log('Authenticated Users List:', AuthUserList); + await db.setAuthList(round, AuthUserList); + console.log('IS LINKTREE True?', isLinktree); + + if (isNode && isLinktree) return true; // if both are true, return true + else return false; // if one of them is false, return false +} + +async function verifyLinktree(proofs_list_object, AuthUserList) { + let allSignaturesValid = true; + for (const proofs of proofs_list_object) { + const linktree_object = await db.getLinktree(proofs.value[0].publicKey); + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktree_object.data)), + ); + const signature = proofs.value[0].signature; + const publicKey = proofs.value[0].publicKey; + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + // verify the linktree signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); + + if (isSignatureValid) { + if (!AuthUserList.includes(publicKey)) { + AuthUserList.push(publicKey); + } + } else { + allSignaturesValid = false; + } + } + return allSignaturesValid; +} + +async function verifyNode(proofs_list_object, signature, publicKey) { const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), + Buffer.from(JSON.stringify(proofs_list_object)), ); const signatureUint8Array = bs58.decode(signature); const publicKeyUint8Array = bs58.decode(publicKey); - if (!linktrees_list_object || !signature || !publicKey) { + if (!proofs_list_object || !signature || !publicKey) { console.error('No data received from web3.storage'); return false; } - // verify the signature + // verify the node signature const isSignatureValid = await verifySignature( messageUint8Array, signatureUint8Array, publicKeyUint8Array, ); - console.log(`Is the signature valid? ${isSignatureValid}`); return isSignatureValid; }; diff --git a/package.json b/package.json index cd0ff7da..46d7a651 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "node test/unitTest.js", - "test:submit": "node test/submitLinktree.js", + "test:submit": "node test/test_submitLinktree.js", "test:getdb": "node test/get_local_leveldb.js", "status": "node test/check_task-status.js", "start": "node index.js", diff --git a/test/test_cidValidation.js b/test/test_cidValidation.js index 60fa72b2..90ee3e3c 100644 --- a/test/test_cidValidation.js +++ b/test/test_cidValidation.js @@ -1,40 +1,85 @@ -const { namespaceWrapper } = require('../namespaceWrapper'); const dataFromCid = require('../helpers/dataFromCid'); -const getKeys = require('../helpers/getKey'); -const hashCompare = require('../helpers/hashCompare'); const nacl = require('tweetnacl'); +const db = require('../db_model'); +const bs58 = require('bs58'); -// let submission_value = "bafybeienyavolrhhaphslyvvjkeby6kkcufnfmeigrf2xlsegoqdnj5ch4" +let submission_value = "bafybeig5322lknop4u6m4p26jd4bcp7rdbwkuqy3ifeytqrmo2ogia5kwe" +let round = 1000 async function test_cidValidation(submission_value) { console.log('******/ TEST Linktree CID VALIDATION Task FUNCTION /******'); const outputraw = await dataFromCid(submission_value); const output = outputraw.data; - // for () - const linktrees_list_object = output.data; - console.log('RESPONSE DATA', linktrees_list_object); - const publicKey = output.publicKey; + + const proofs_list_object = output.proofs; + console.log('RESPONSE DATA', proofs_list_object); + const publicKey = output.node_publicKey; console.log('PUBLIC KEY', publicKey); - const signature = output.signature; + const signature = output.node_signature; console.log('SIGNATURE', signature); + let isNode = await verifyNode(proofs_list_object, signature, publicKey); + console.log('IS NODE True?', isNode); + + const AuthUserList = []; + let isLinktree = await verifyLinktree(proofs_list_object, AuthUserList); + console.log('Authenticated Users List:', AuthUserList); + console.log('IS LINKTREE True?', isLinktree); + + if (isNode && isLinktree) return true; // if both are true, return true + else return false; // if one of them is false, return false +} + +async function verifyLinktree(proofs_list_object, AuthUserList) { + let allSignaturesValid = true; + for (const proofs of proofs_list_object) { + console.log('proofs.value.publicKey', proofs.value[0].publicKey); + const linktree_object = await db.getLinktree(proofs.value[0].publicKey); + console.log('LINKTREE OBJECT', linktree_object); + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktree_object.data)), + ); + const signature = proofs.value[0].signature; + console.log('SIGNATURE', signature); + const publicKey = proofs.value[0].publicKey; + console.log('PUBLIC KEY', publicKey); + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + // verify the linktree signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log('IS SIGNATURE VALID', isSignatureValid); + + if (isSignatureValid) { + AuthUserList.push(publicKey); + } else { + allSignaturesValid = false; + } + } + return allSignaturesValid; +} + +async function verifyNode(proofs_list_object, signature, publicKey) { const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktrees_list_object)), + Buffer.from(JSON.stringify(proofs_list_object)), ); const signatureUint8Array = bs58.decode(signature); const publicKeyUint8Array = bs58.decode(publicKey); - if (!linktrees_list_object || !signature || !publicKey) { + if (!proofs_list_object || !signature || !publicKey) { console.error('No data received from web3.storage'); return false; } - // verify the signature + // verify the node signature const isSignatureValid = await verifySignature( messageUint8Array, signatureUint8Array, publicKeyUint8Array, ); - console.log(`Is the signature valid? ${isSignatureValid}`); return isSignatureValid; } diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index bfa1ad0a..1f580180 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -9,35 +9,43 @@ const crypto = require('crypto'); // This test submits linktrees from differnet publicKey to the service and stored in localdb async function main() { try { - const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) // ); - const publicKey = publicKeyraw.toBase58(); - console.log('publicKey', publicKey); + console.log('publicKey', bs58.encode(publicKey)); + const data = { + uuid: uuidv4(), + linktree: [ + { + key: 'official', + label: 'Official Website', + redirectUrl: 'https://spheron.network/', + }, + { + key: 'twitter', + label: 'Twitter', + redirectUrl: 'https://twitter.com/blockchainbalak', + }, + { + key: 'github', + label: 'GitHub', + redirectUrl: 'https://github.com/spheronFdn/', + }, + ], + timestamp: Date.now(), + } + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(data)), + ); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); const payload = { - data: { - uuid: uuidv4(), - linktree: [ - { - key: 'official', - label: 'Official Website', - redirectUrl: 'https://spheron.network/', - }, - { - key: 'twitter', - label: 'Twitter', - redirectUrl: 'https://twitter.com/blockchainbalak', - }, - { - key: 'github', - label: 'GitHub', - redirectUrl: 'https://github.com/spheronFdn/', - }, - ], - timestamp: Date.now(), - }, - publicKey: publicKey, + data, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), }; // Check payload diff --git a/test/unitTest.js b/test/unitTest.js index 21f781a6..fef28edf 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -4,8 +4,10 @@ const index = require('../index'); async function test_coreLogic() { await coreLogic.task(); const submission = await coreLogic.fetchSubmission(); + // let submission= "bafybeih6xpbghwjrq4vryo4p6ps6vcv7zp5ng3rvuffoouzs63ri6ybqdy" console.log('SUBMISSION', submission); - // const vote = await coreLogic.validateNode(submission, 1); + const vote = await coreLogic.validateNode(submission, 1000); + console.log('VOTE', vote); // let vote = true; // const _dummyTaskState = { // submissions: { From ff06dd8d3eba7a95a199a0226d5e94c694a5a9ca Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 16:40:33 -0300 Subject: [PATCH 46/61] update endpoint for authlist --- index.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index d69c86fa..ff0d34b4 100644 --- a/index.js +++ b/index.js @@ -259,8 +259,16 @@ if (app) { app.get('/get-allnode-proofs', async (req, res) => { linktree = await db.getAllNodeProofCids() || '[]'; return res.status(200).send(linktree); - } - ); - + }); + app.get('/get-authlist/:round', async (req, res) => { + const { round } = req.params; + let authlist = await db.getAuthList(round); + authlist = authlist || '[]'; + return res.status(200).send(authlist); + }); + app.get('/get-allauthlist', async (req, res) => { + authlist = await db.getAllAuthLists() || '[]'; + return res.status(200).send(authlist); + }); } From e04b4c9c2e12353ae7aa47d5660100fe748f290a Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 17:36:03 -0300 Subject: [PATCH 47/61] update db --- db_model.js | 8 ++++---- index.js | 24 +++++++++++++++--------- linktree_validate.js | 15 ++++----------- test/test_submitLinktree.js | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/db_model.js b/db_model.js index 969c491b..456c0312 100644 --- a/db_model.js +++ b/db_model.js @@ -145,9 +145,9 @@ const getAllNodeProofCids = async () => { } //db functions fro Auth list -const getAuthList = async (round) => { +const getAuthList = async (pubkey) => { return new Promise((resolve, reject) => { - db.get(getAuthListId(round), (err, value) => { + db.get(getAuthListId(pubkey), (err, value) => { if (err) { console.error("Error in getAuthList:", err); resolve(null); @@ -158,8 +158,8 @@ const getAuthList = async (round) => { }); } -const setAuthList = async (round, auth_list) => { - db.put(getAuthListId(round), JSON.stringify(auth_list)); +const setAuthList = async (pubkey) => { + db.put(getAuthListId(pubkey), JSON.stringify(pubkey)); return console.log("Auth List set"); } diff --git a/index.js b/index.js index ff0d34b4..cd80bc30 100644 --- a/index.js +++ b/index.js @@ -176,7 +176,7 @@ if (app) { }) // API to register the linktree - app.post('/register-linktree', async (req, res) => { + app.post('/linktree', async (req, res) => { const linktree = req.body.payload; // Check req.body if (!linktree) { @@ -231,44 +231,50 @@ if (app) { return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); - app.get("/get-logs", async (req, res) => { + app.get("/logs", async (req, res) => { const logs = fs.readFileSync("./namespace/logs.txt", "utf8") res.status(200).send(logs); }) // endpoint for specific linktree data by publicKey - app.get('/get-linktree', async (req, res) => { + app.get('/linktree/get', async (req, res) => { const log = "Nothing to see here, check /:publicKey to get the linktree" return res.status(200).send(log); }); - app.get('/get-linktree/:publicKey', async (req, res) => { + app.get('/linktree/get/:publicKey', async (req, res) => { const { publicKey } = req.params; let linktree = await db.getLinktree(publicKey); linktree = JSON.parse(linktree || '[]'); return res.status(200).send(linktree); }); - app.get('/get-alllinktree', async (req, res) => { + app.get('/linktree/all', async (req, res) => { linktree = await db.getAllLinktrees() || '[]'; return res.status(200).send(linktree); } ); - app.get('/get-allproofs', async (req, res) => { + app.get('/proofs/all', async (req, res) => { linktree = await db.getAllProofs() || '[]'; return res.status(200).send(linktree); } ); - app.get('/get-allnode-proofs', async (req, res) => { + app.get('/node-proof/all', async (req, res) => { linktree = await db.getAllNodeProofCids() || '[]'; return res.status(200).send(linktree); }); - app.get('/get-authlist/:round', async (req, res) => { + app.get('/authlist/get/:round', async (req, res) => { const { round } = req.params; let authlist = await db.getAuthList(round); authlist = authlist || '[]'; return res.status(200).send(authlist); }); - app.get('/get-allauthlist', async (req, res) => { + app.get('/authlist/all', async (req, res) => { authlist = await db.getAllAuthLists() || '[]'; return res.status(200).send(authlist); }); + // app.post('/register-authlist', async (req, res) => { + // const { round, authlist } = req.body; + // await db.setAuthList(round, authlist); + // return res.status(200).send({message: 'Authlist registered successfully'}); + // } + // ) } diff --git a/linktree_validate.js b/linktree_validate.js index a59a6769..4dd29c77 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -18,21 +18,16 @@ module.exports = async (submission_value, round) => { let isNode = await verifyNode(proofs_list_object, signature, publicKey); console.log('IS NODE True?', isNode); - - let AuthUserList = await db.getAuthList(round); - if (typeof AuthUserList === 'string') AuthUserList = JSON.parse(AuthUserList); - else AuthUserList = AuthUserList || []; - console.log('AuthUserList', AuthUserList); - let isLinktree = await verifyLinktree(proofs_list_object, AuthUserList); + let isLinktree = await verifyLinktree(proofs_list_object); + let AuthUserList = await db.getAllAuthLists(); console.log('Authenticated Users List:', AuthUserList); - await db.setAuthList(round, AuthUserList); console.log('IS LINKTREE True?', isLinktree); if (isNode && isLinktree) return true; // if both are true, return true else return false; // if one of them is false, return false } -async function verifyLinktree(proofs_list_object, AuthUserList) { +async function verifyLinktree(proofs_list_object) { let allSignaturesValid = true; for (const proofs of proofs_list_object) { const linktree_object = await db.getLinktree(proofs.value[0].publicKey); @@ -53,9 +48,7 @@ async function verifyLinktree(proofs_list_object, AuthUserList) { console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); if (isSignatureValid) { - if (!AuthUserList.includes(publicKey)) { - AuthUserList.push(publicKey); - } + await db.setAuthList(publicKey); } else { allSignaturesValid = false; } diff --git a/test/test_submitLinktree.js b/test/test_submitLinktree.js index 1f580180..1088c9fb 100644 --- a/test/test_submitLinktree.js +++ b/test/test_submitLinktree.js @@ -52,7 +52,7 @@ try { // console.log(payload); await axios - .post('http://localhost:10000/register-linktree', {payload}) + .post('http://localhost:10000/linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); From d017edc5cbbeac61adb6698b950a43bb8cf70216 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 18:47:32 -0300 Subject: [PATCH 48/61] code review --- coreLogic.js | 31 ++++--- dbSharing.js | 66 +++++++++++++ db_model.js | 21 ++--- index.js | 217 ++----------------------------------------- linktree_task.js | 21 ++++- linktree_validate.js | 80 ++++++++++------ localTestingShim.js | 51 ++++++++++ routes.js | 119 ++++++++++++++++++++++++ 8 files changed, 339 insertions(+), 267 deletions(-) create mode 100644 dbSharing.js create mode 100644 localTestingShim.js create mode 100644 routes.js diff --git a/coreLogic.js b/coreLogic.js index 3da7630c..115a33a3 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -7,19 +7,23 @@ const db = require('./db_model'); class CoreLogic { async task() { + // TODO remove all of the prompts like the following line from the template version // Write the logic to do the work required for submitting the values and optionally store the result in levelDB // run linktree task console.log('*********task() started*********'); + const proof_cid = await linktree_task(); // const round = await namespaceWrapper.getRound(); // For only testing purposes: const round = 1000 + if (proof_cid) { await db.setNodeProofCid(round, proof_cid); // store CID in levelDB } else { console.log('CID NOT FOUND'); } + console.log('*********task() completed*********'); } @@ -52,14 +56,20 @@ class CoreLogic { let distributionList = {}; let taskAccountDataJSON = await namespaceWrapper.getTaskState(); + if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; + console.log('Task Account Data', taskAccountDataJSON); + const submissions = taskAccountDataJSON.submissions[round]; const submissions_audit_trigger = taskAccountDataJSON.submissions_audit_trigger[round]; + if (submissions == null) { + console.log('No submisssions found in N-2 round'); return distributionList; + } else { const keys = Object.keys(submissions); const values = Object.values(submissions); @@ -108,33 +118,24 @@ class CoreLogic { console.log('DECIDER', decider); if (decider) { + const response = await namespaceWrapper.distributionListSubmissionOnChain(round); console.log('RESPONSE FROM DISTRIBUTION LIST', response); } + } catch (err) { console.log('ERROR IN SUBMIT DISTRIBUTION', err); } } + // this function is called when a node is selected to validate the submission value async validateNode(submission_value, round) { - // Write your logic for the validation of submission value here and return a boolean value in response - console.log('Received submission_value', submission_value, round); + + // import the linktree validate module const vote = await linktree_validate(submission_value, round); - // const generatedValue = await namespaceWrapper.storeGet("cid"); - // console.log("GENERATED VALUE", generatedValue); - // if(generatedValue == submission_value){ - // return true; - // }else{ - // return false; - // } - // }catch(err){ - // console.log("ERROR IN VALDIATION", err); - // return false; - // } - - // For succesfull flow we return true for now + console.log('Vote', vote); return vote; } diff --git a/dbSharing.js b/dbSharing.js new file mode 100644 index 00000000..332dd23e --- /dev/null +++ b/dbSharing.js @@ -0,0 +1,66 @@ +const share = async () => { + try { + const nodesUrl = `${SERVICE_URL}/nodes/${TASK_ID}`; + const res = await axios.get(nodesUrl); + if (res.status != 200) { + console.error('Error', res.status); + return; + } + + if (!res.data) { + console.error('res has no valid urls'); + return; + } + let nodeUrlList = res.data.map((e) => { + return e.data.url; + }); + console.log(nodeUrlList); + let allLinktrees = await db.getLinktree(publicKey); // TODO + allLinktrees = JSON.parse(allLinktrees || '[]'); + for (let url of nodeUrlList) { + console.log(url); + const res = await axios.get(`${url}/task/${TASK_ID}/get-all-linktrees`); + if (res.status != 200) { + console.error('ERROR', res.status); + continue; + } + const payload = res.data; + /* + 1. Verify the signature + 2. Only update your db if incoming timestamp > your timestamp or you don't have the data + */ + // TODO - fix by adding linktree comparisons for each publickey - the list shared between nodes should be the public keys of all known linktrees + + // TODO2 - whenever a linktree is not found on this node, it should be added to the db + + // TODO3 - whenever a linktree is found on this node, it should be compared to the one in the db and updated if the timestamp is newer + + if (!payload || payload.length == 0) continue; + for (let linkTreePayload in payload) { + const isVerified = nacl.sign.detached.verify( + new TextEncoder().encode(JSON.stringify(linkTreePayload.data)), + bs58.decode(linkTreePayload.signature), + bs58.decode(linkTreePayload.publicKey) + ); + if (!isVerified) { + console.warn(`${url} is not able to verify the signature`); + continue; + } + let localExistingLinktree = allLinktrees.find((e) => { + e.uuid == linkTreePayload.data.uuid; + }); + if (localExistingLinktree) { + if (localExistingLinktree.data.timestamp < linkTreePayload.data.timestamp) { + allLinktrees.push(linkTreePayload); + } + } else { + allLinktrees.push(linkTreePayload); + } + } + } + } catch (error) { + console.error('Some went wrong:', error); + } + } + +module.exports = { share } \ No newline at end of file diff --git a/db_model.js b/db_model.js index 456c0312..55e5af66 100644 --- a/db_model.js +++ b/db_model.js @@ -24,14 +24,14 @@ const setLinktree = async (publicKey, linktree) => { const getAllLinktrees = async () => { return new Promise((resolve, reject) => { let dataStore = []; - const linktreesStream = db.createReadStream({ - lt: 'linktree~', - reverse: true, - keys: true, - values: true -}) - linktreesStream - .on('data', function (data) { + + db.createReadStream({ + lt: 'linktree~', + reverse: true, + keys: true, + values: true + }) + .on('data', function (data) { console.log( data.key.toString(), '=', data.value.toString()) dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString()) }); }) @@ -71,13 +71,12 @@ const setProofs = async (pubkey, proofs) => { const getAllProofs = async () => { return new Promise((resolve, reject) => { let dataStore = []; - const proofsStream = db.createReadStream({ + db.createReadStream({ gte: 'proofs', reverse: true, keys: true, values: true - }) - proofsStream + }) .on('data', function (data) { console.log( data.key.toString(), '=', data.value.toString()) dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString())}); diff --git a/index.js b/index.js index cd80bc30..009958c0 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,6 @@ const coreLogic = require("./coreLogic"); +const dbSharing = require("./db_sharing"); +// const localShim = require("./localTestingShim"); // to enable testing with K2 without round timers, enable this line and line 59 const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const express = require('express'); const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); @@ -8,7 +10,7 @@ const solanaWeb3 = require('@solana/web3.js'); const nacl = require('tweetnacl'); const fs = require('fs'); const db = require('./db_model'); - +const routes = require('./routes'); async function setup() { const originalConsoleLog = console.log; @@ -52,111 +54,9 @@ async function setup() { }); // Code for the data replication among the nodes - setInterval(async () => { - try { - const nodesUrl = `${SERVICE_URL}/nodes/${TASK_ID}`; - const res = await axios.get(nodesUrl); - if (res.status != 200) { - console.error('Error', res.status); - return; - } - - if (!res.data) { - console.error('res has no valid urls'); - return; - } - let nodeUrlList = res.data.map((e) => { - return e.data.url; - }); - console.log(nodeUrlList); - let allLinktrees = await db.getLinktree(publicKey); - allLinktrees = JSON.parse(allLinktrees || '[]'); - for (let url of nodeUrlList) { - console.log(url); - const res = await axios.get(`${url}/task/${TASK_ID}/get-all-linktrees`); - if (res.status != 200) { - console.error('ERROR', res.status); - continue; - } - const payload = res.data; - /* - 1. Verify the signature - 2. Only update your db if incoming timestamp > your timestamp or you don't have the data - */ - if (!payload || payload.length == 0) continue; - for (let linkTreePayload in payload) { - const isVerified = nacl.sign.detached.verify( - new TextEncoder().encode(JSON.stringify(linkTreePayload.data)), - bs58.decode(linkTreePayload.signature), - bs58.decode(linkTreePayload.publicKey) - ); - if (!isVerified) { - console.warn(`${url} is not able to verify the signature`); - continue; - } - let localExistingLinktree = allLinktrees.find((e) => { - e.uuid == linkTreePayload.data.uuid; - }); - if (localExistingLinktree) { - if (localExistingLinktree.data.timestamp < linkTreePayload.data.timestamp) { - allLinktrees.push(linkTreePayload); - } - } else { - allLinktrees.push(linkTreePayload); - } - } - } - } catch (error) { - console.error('Some went wrong:', error); - } - }, 20000); - - /* GUIDE TO CALLS K2 FUNCTIONS MANUALLY - - If you wish to do the development by avoiding the timers then you can do the intended calls to K2 - directly using these function calls. - - To disable timers please set the TIMERS flag in task-node ENV to disable - - NOTE : K2 will still have the windows to accept the submission value, audit, so you are expected - to make calls in the intended slots of your round time. - - */ - - // console.log("*******************TESTING*******************") - // Get the task state - // console.log(await namespaceWrapper.getTaskState()); - - // Get account public key - // console.log(MAIN_ACCOUNT_PUBKEY); - - // GET ROUND - // const round = await namespaceWrapper.getRound(); - // console.log("ROUND", round); - - - // Call to do the work for the task - // await coreLogic.task(); - - // Submission to K2 (Preferablly you should submit the cid received from IPFS) - // await coreLogic.submitTask(round - 1); - - // Audit submissions - // await coreLogic.auditTask(round - 1); - - // upload distribution list to K2 - - //await coreLogic.submitDistributionList(round - 2) - - // Audit distribution list - - //await coreLogic.auditDistribution(round - 2); - - // Payout trigger - - // const responsePayout = await namespaceWrapper.payoutTrigger(); - // console.log("RESPONSE TRIGGER", responsePayout); + setInterval(dbSharing.share(), 20000); + // localShim(); // enable this to run the localShim for testing with K2 without timers } @@ -167,114 +67,9 @@ if (taskNodeAdministered){ if (app) { app.use(express.json()); - // Sample API that return your task state - app.get('/taskState', async (req, res) => { - const state = await namespaceWrapper.getTaskState(); - console.log("TASK STATE", state); - - res.status(200).json({ taskState: state }) - }) - - // API to register the linktree - app.post('/linktree', async (req, res) => { - const linktree = req.body.payload; - // Check req.body - if (!linktree) { - res.status(400).json({ error: 'Invalid request' }); - return; - } else { - console.log(linktree); - } - - // TODO: validate the linktree structure here - /* - 1. Must have the following structure - 2. Signature must be verified by the publicKey - */ - - /* - { - data:{ - uuid:jhasjdbjhguyt23764vhyt - linktree:linktree, - timestamp:76576465, - }, - publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", - signature:"" - } - */ - - // Use the code below to sign the data payload - let signature = linktree.signature; - let pubkey = linktree.publicKey + app.use('/', routes) - let proof = { - publicKey: pubkey, - signature: signature, - } - console.log('Check Proof:', proof); - // use fs to write the linktree and proof to a file - if (!fs.existsSync(__dirname + '/linktrees')) fs.mkdirSync(__dirname + '/linktrees'); - fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); - // fs.writeFileSync('proof.json', JSON.stringify(proof)); - await db.setLinktree(pubkey, linktree); - - // const round = await namespaceWrapper.getRound(); - // For only testing purposes: - const round = 1000 - let proofs = await db.getProofs(pubkey); - proofs = JSON.parse(proofs || '[]'); - proofs.push(proof); - console.log(`${pubkey} Proofs: `, proofs); - await db.setProofs(pubkey, proofs); - return res.status(200).send({message: 'Proof and linktree registered successfully'}); - }); - app.get("/logs", async (req, res) => { - const logs = fs.readFileSync("./namespace/logs.txt", "utf8") - res.status(200).send(logs); - }) - // endpoint for specific linktree data by publicKey - app.get('/linktree/get', async (req, res) => { - const log = "Nothing to see here, check /:publicKey to get the linktree" - return res.status(200).send(log); - }); - app.get('/linktree/get/:publicKey', async (req, res) => { - const { publicKey } = req.params; - let linktree = await db.getLinktree(publicKey); - linktree = JSON.parse(linktree || '[]'); - return res.status(200).send(linktree); - }); - app.get('/linktree/all', async (req, res) => { - linktree = await db.getAllLinktrees() || '[]'; - return res.status(200).send(linktree); - } - ); - app.get('/proofs/all', async (req, res) => { - linktree = await db.getAllProofs() || '[]'; - return res.status(200).send(linktree); - } - ); - app.get('/node-proof/all', async (req, res) => { - linktree = await db.getAllNodeProofCids() || '[]'; - return res.status(200).send(linktree); - }); - app.get('/authlist/get/:round', async (req, res) => { - const { round } = req.params; - let authlist = await db.getAuthList(round); - authlist = authlist || '[]'; - return res.status(200).send(authlist); - }); - app.get('/authlist/all', async (req, res) => { - authlist = await db.getAllAuthLists() || '[]'; - return res.status(200).send(authlist); - }); - // app.post('/register-authlist', async (req, res) => { - // const { round, authlist } = req.body; - // await db.setAuthList(round, authlist); - // return res.status(200).send({message: 'Authlist registered successfully'}); - // } - // ) } diff --git a/linktree_task.js b/linktree_task.js index fa9b0139..54adb5f1 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -4,20 +4,24 @@ const deleteFile = require('./helpers/deleteFile'); const fs = require('fs'); const { Web3Storage, getFilesFromPath } = require('web3.storage'); const storageClient = new Web3Storage({ - token: process.env.SECRET_WEB3_STORAGE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", -}); + token: process.env.SECRET_WEB3_STORAGE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw", +}); // TODO remove the default web3.storage key for production const bs58 = require('bs58'); const nacl = require('tweetnacl'); const db = require('./db_model'); -module.exports = async () => { +const main = async () => { console.log('******/ IN Linktree Task FUNCTION /******'); + + // TODO - remove the new keypair generation below and use the keypairs already held on the node + // TODO - https://docs.koii.network/develop/microservices-and-tasks/task-development-kit-tdk/using-the-task-namespace/wallet-signatures + // Customize linktree test data const keyPair = nacl.sign.keyPair(); const publicKey = keyPair.publicKey; const privateKey = keyPair.secretKey; - // Get linktree list fron localdb + // Get linktree list fron localdb const proofs_list_object = await db.getAllProofs(); const messageUint8Array = new Uint8Array( @@ -31,13 +35,18 @@ module.exports = async () => { node_publicKey: bs58.encode(publicKey), node_signature: bs58.encode(signature), }; + // upload the index of the linktree on web3.storage const path = `./Linktree/proofs.json`; + if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); + console.log('PATH', path); + await createFile(path, submission_value); if (storageClient) { + const file = await getFilesFromPath(path); const proof_cid = await storageClient.put(file); console.log('User Linktrees proof uploaded to IPFS: ', proof_cid); @@ -48,6 +57,10 @@ module.exports = async () => { return proof_cid; } else { + console.log('NODE DO NOT HAVE ACCESS TO WEB3.STORAGE'); + } }; + +module.exports = main; \ No newline at end of file diff --git a/linktree_validate.js b/linktree_validate.js index 4dd29c77..3d826371 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -8,54 +8,82 @@ module.exports = async (submission_value, round) => { const outputraw = await dataFromCid(submission_value); const output = outputraw.data; - const proofs_list_object = output.proofs; - console.log('RESPONSE DATA', proofs_list_object); - const publicKey = output.node_publicKey; - console.log('PUBLIC KEY', publicKey); - const signature = output.node_signature; - console.log('SIGNATURE', signature); + console.log('RESPONSE DATA length', output.proofs.LENGTH); + console.log('PUBLIC KEY', output.publicKey); + console.log('SIGNATURE', output.signature); - let isNode = await verifyNode(proofs_list_object, signature, publicKey); - console.log('IS NODE True?', isNode); + // TODO - can we safely remove this, from a game theory perspective? + // Check that the node who submitted the proofs is a valid staked node + let isNode = await verifyNode(output.proofs, output.signature, output.publicKey); + console.log("Is the node's signature on the CID payload correct?", isNode); - let isLinktree = await verifyLinktree(proofs_list_object); - let AuthUserList = await db.getAllAuthLists(); - console.log('Authenticated Users List:', AuthUserList); - console.log('IS LINKTREE True?', isLinktree); + // check each item in the linktrees list and verify that the node is holding that payload, and the signature matches + let isLinktree = await verifyLinktree(output.proofs); if (isNode && isLinktree) return true; // if both are true, return true else return false; // if one of them is false, return false } +// verify the linktree signature by querying the other node to get it's copy of the linktree async function verifyLinktree(proofs_list_object) { let allSignaturesValid = true; + let AuthUserList = await db.getAllAuthLists(); + console.log('Authenticated Users List:', AuthUserList); + console.log('IS LINKTREE True?', isLinktree); + for (const proofs of proofs_list_object) { - const linktree_object = await db.getLinktree(proofs.value[0].publicKey); + + const linktree_object = await db.getLinktree(proofs.value[0].publicKey); // TODO - replace this with a call to the other node + // TODO #2 - once you've done this, be sure to ignore any duplicates for the same node for the same pubkey, otherwise multiple updates in one round will cause audits const messageUint8Array = new Uint8Array( Buffer.from(JSON.stringify(linktree_object.data)), ); - const signature = proofs.value[0].signature; - const publicKey = proofs.value[0].publicKey; - const signatureUint8Array = bs58.decode(signature); - const publicKeyUint8Array = bs58.decode(publicKey); - - // verify the linktree signature - const isSignatureValid = await verifySignature( - messageUint8Array, - signatureUint8Array, - publicKeyUint8Array, - ); - console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); + + // check if the user's pubkey is on the authlist + if ( !AuthUserList.contains(proofs.value[0].publicKey) ) { + // if not, check the node that supplied this proof, and verify that this user is in fact authorized + + // TODO write logic to query other node and verify registration events + /* + 1. REST API that returns a user's registration proof and accepts :pubkey + 2. Add logic here to verify 'proofs' from (1) and then add the user to the AuthUserList + */ + + // TODO - add the user to the AuthUserList (might need to be updated later) + await db.setAuthList(publicKey); + + } else { + // TODO - flush this out more, might need to add an automatic update on the AuthUserList to ensure that this node is always up to date + console.log('found invalid linktree data') + + + // TODO - fix the array structure so you don't have to do this lol + const signature = proofs.value[0].signature; + const publicKey = proofs.value[0].publicKey; + const signatureUint8Array = bs58.decode(signature); + const publicKeyUint8Array = bs58.decode(publicKey); + + // verify the linktree signature + const isSignatureValid = await verifySignature( + messageUint8Array, + signatureUint8Array, + publicKeyUint8Array, + ); + console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); + + } if (isSignatureValid) { - await db.setAuthList(publicKey); + } else { allSignaturesValid = false; } + } return allSignaturesValid; } +// verifies that a node's signature is valid, and rejects situations where CIDs from IPFS return no data or are not JSON async function verifyNode(proofs_list_object, signature, publicKey) { const messageUint8Array = new Uint8Array( Buffer.from(JSON.stringify(proofs_list_object)), diff --git a/localTestingShim.js b/localTestingShim.js new file mode 100644 index 00000000..970ce16f --- /dev/null +++ b/localTestingShim.js @@ -0,0 +1,51 @@ +const localShim = async () => { + + /* GUIDE TO CALLS K2 FUNCTIONS MANUALLY + + If you wish to do the development by avoiding the timers then you can do the intended calls to K2 + directly using these function calls. + + To disable timers please set the TIMERS flag in task-node ENV to disable + + NOTE : K2 will still have the windows to accept the submission value, audit, so you are expected + to make calls in the intended slots of your round time. + + */ + + // console.log("*******************TESTING*******************") + // Get the task state + // console.log(await namespaceWrapper.getTaskState()); + + // Get account public key + // console.log(MAIN_ACCOUNT_PUBKEY); + + // GET ROUND + // const round = await namespaceWrapper.getRound(); + // console.log("ROUND", round); + + + // Call to do the work for the task + // await coreLogic.task(); + + // Submission to K2 (Preferablly you should submit the cid received from IPFS) + // await coreLogic.submitTask(round - 1); + + // Audit submissions + // await coreLogic.auditTask(round - 1); + + // upload distribution list to K2 + + //await coreLogic.submitDistributionList(round - 2) + + // Audit distribution list + + //await coreLogic.auditDistribution(round - 2); + + // Payout trigger + + // const responsePayout = await namespaceWrapper.payoutTrigger(); + // console.log("RESPONSE TRIGGER", responsePayout); + +} + +module.exports = localShim; \ No newline at end of file diff --git a/routes.js b/routes.js new file mode 100644 index 00000000..25c1155a --- /dev/null +++ b/routes.js @@ -0,0 +1,119 @@ +const express = require('express'); +const router = express.Router(); + +// Middleware to log incoming requests +router.use((req, res, next) => { + console.log(`Incoming ${req.method} request to ${req.originalUrl}`); + next(); +}); + + router.get('/taskState', async (req, res) => { + const state = await namespaceWrrouterer.getTaskState(); + console.log("TASK STATE", state); + + res.status(200).json({ taskState: state }) + }) + + // API to register the linktree + router.post('/linktree', async (req, res) => { + const linktree = req.body.payload; + // Check req.body + if (!linktree) { + res.status(400).json({ error: 'Invalid request' }); + return; + } else { + console.log(linktree); + } + + // TODO: validate the linktree structure here + /* + 1. Must have the following structure + 2. Signature must be verified by the publicKey + */ + + /* + { + data:{ + uuid:jhasjdbjhguyt23764vhyt + linktree:linktree, + timestamp:76576465, + }, + publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", + signature:"" + } + */ + + // Use the code below to sign the data payload + let signature = linktree.signature; + let pubkey = linktree.publicKey + + let proof = { + publicKey: pubkey, + signature: signature, + } + console.log('Check Proof:', proof); + // use fs to write the linktree and proof to a file + if (!fs.existsSync(__dirname + '/linktrees')) fs.mkdirSync(__dirname + '/linktrees'); + fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); + // fs.writeFileSync('proof.json', JSON.stringify(proof)); + await db.setLinktree(pubkey, linktree); + + // const round = await namespaceWrrouterer.getRound(); + // For only testing purposes: + const round = 1000 + + let proofs = await db.getProofs(pubkey); + proofs = JSON.parse(proofs || '[]'); + proofs.push(proof); + console.log(`${pubkey} Proofs: `, proofs); + await db.setProofs(pubkey, proofs); + + return res.status(200).send({message: 'Proof and linktree registered successfully'}); + }); + router.get("/logs", async (req, res) => { + const logs = fs.readFileSync("./namespace/logs.txt", "utf8") + res.status(200).send(logs); + }) + // endpoint for specific linktree data by publicKey + router.get('/linktree/get', async (req, res) => { + const log = "Nothing to see here, check /:publicKey to get the linktree" + return res.status(200).send(log); + }); + router.get('/linktree/get/:publicKey', async (req, res) => { + const { publicKey } = req.params; + let linktree = await db.getLinktree(publicKey); + linktree = JSON.parse(linktree || '[]'); + return res.status(200).send(linktree); + }); + router.get('/linktree/all', async (req, res) => { + linktree = await db.getAllLinktrees() || '[]'; + return res.status(200).send(linktree); + } + ); + router.get('/proofs/all', async (req, res) => { + linktree = await db.getAllProofs() || '[]'; + return res.status(200).send(linktree); + } + ); + router.get('/node-proof/all', async (req, res) => { + linktree = await db.getAllNodeProofCids() || '[]'; + return res.status(200).send(linktree); + }); + router.get('/authlist/get/:round', async (req, res) => { + const { round } = req.params; + let authlist = await db.getAuthList(round); + authlist = authlist || '[]'; + return res.status(200).send(authlist); + }); + router.get('/authlist/all', async (req, res) => { + authlist = await db.getAllAuthLists() || '[]'; + return res.status(200).send(authlist); + }); + // router.post('/register-authlist', async (req, res) => { + // const pubkey = req.body.pubkey; + // await db.setAuthList(pubkey); + // return res.status(200).send({message: 'Authlist registered successfully'}); + // } + // ) + +module.exports = router; \ No newline at end of file From 8ee8b270fa8221a855e02ff487cbba0fd7fa5ec0 Mon Sep 17 00:00:00 2001 From: soma Date: Wed, 12 Apr 2023 18:56:20 -0300 Subject: [PATCH 49/61] minor fix --- db_model.js | 10 ++++++---- routes.js | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/db_model.js b/db_model.js index 55e5af66..c205f73c 100644 --- a/db_model.js +++ b/db_model.js @@ -21,15 +21,16 @@ const setLinktree = async (publicKey, linktree) => { return console.log("Linktree set"); } -const getAllLinktrees = async () => { +const getAllLinktrees = async (values) => { return new Promise((resolve, reject) => { let dataStore = []; + if (!values) values = true; db.createReadStream({ lt: 'linktree~', reverse: true, keys: true, - values: true + values: values }) .on('data', function (data) { console.log( data.key.toString(), '=', data.value.toString()) @@ -162,7 +163,8 @@ const setAuthList = async (pubkey) => { return console.log("Auth List set"); } -const getAllAuthLists = async () => { +const getAllAuthLists = async (values) => { + if (!values) values = true; return new Promise((resolve, reject) => { let dataStore = []; const authListStream = db.createReadStream({ @@ -170,7 +172,7 @@ const getAllAuthLists = async () => { lt: 'auth_list~', reverse: true, keys: true, - values: true + values: values }) authListStream .on('data', function (data) { diff --git a/routes.js b/routes.js index 25c1155a..67bd5e6e 100644 --- a/routes.js +++ b/routes.js @@ -7,6 +7,8 @@ router.use((req, res, next) => { next(); }); + + router.get('/taskState', async (req, res) => { const state = await namespaceWrrouterer.getTaskState(); console.log("TASK STATE", state); @@ -87,8 +89,15 @@ router.use((req, res, next) => { }); router.get('/linktree/all', async (req, res) => { linktree = await db.getAllLinktrees() || '[]'; - return res.status(200).send(linktree); - } + return res.status(200).send(linktree); + } + + ); + + router.get('/linktree/list', async (req, res) => { + linktree = await db.getAllLinktrees(false) || '[]'; + return res.status(200).send(linktree); + } ); router.get('/proofs/all', async (req, res) => { linktree = await db.getAllProofs() || '[]'; @@ -105,9 +114,12 @@ router.use((req, res, next) => { authlist = authlist || '[]'; return res.status(200).send(authlist); }); - router.get('/authlist/all', async (req, res) => { - authlist = await db.getAllAuthLists() || '[]'; - return res.status(200).send(authlist); + router.get('/authlist/list', async (req, res) => { + authlist = await db.getAllAuthLists(false) || '[]'; + authlist.forEach((authuser) => { + authuser = authuser.split("authlist:")[0] // TODO verify that this properly trims the 'authlist:' prefix + }); + return res.status(200).send(authlist); }); // router.post('/register-authlist', async (req, res) => { // const pubkey = req.body.pubkey; From 84cc6b9f1d2be5e8b75b6ad6af9c4697b82efc81 Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 13 Apr 2023 14:21:57 -0300 Subject: [PATCH 50/61] update testing --- .env-local | 2 +- coreLogic.js | 15 +++--- dbSharing.js | 23 ++++++++++ index.js | 10 ++-- linktree_task.js | 18 ++++---- linktree_validate.js | 73 ++++++++++++++++-------------- localTestingShim.js | 10 ++-- routes.js | 18 -------- test/test_docker_submitlinktree.js | 5 +- test/test_signature.js | 19 ++++++++ 10 files changed, 109 insertions(+), 84 deletions(-) create mode 100644 test/test_signature.js diff --git a/.env-local b/.env-local index 0a19a361..2813a4a0 100644 --- a/.env-local +++ b/.env-local @@ -12,7 +12,7 @@ INITIAL_STAKING_WALLET_BALANCE=15 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="true" +GLOBAL_TIMERS="false" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs diff --git a/coreLogic.js b/coreLogic.js index 115a33a3..d2f0265c 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -8,13 +8,14 @@ const db = require('./db_model'); class CoreLogic { async task() { // TODO remove all of the prompts like the following line from the template version - // Write the logic to do the work required for submitting the values and optionally store the result in levelDB // run linktree task console.log('*********task() started*********'); const proof_cid = await linktree_task(); + // const round = await namespaceWrapper.getRound(); + // For only testing purposes: const round = 1000 @@ -28,7 +29,7 @@ class CoreLogic { } async fetchSubmission() { - // Write the logic to fetch the submission values here and return the cid string + // The logic to fetch the submission values and return the cid string // fetching round number to store work accordingly @@ -50,9 +51,7 @@ class CoreLogic { console.log('GenerateDistributionList called'); console.log('I am selected node'); console.log('Round', round, 'Task State', _dummyTaskState); - // Write the logic to generate the distribution list here by introducing the rules of your choice - - /* **** SAMPLE LOGIC FOR GENERATING DISTRIBUTION LIST ******/ + // The logic to generate the distribution list here let distributionList = {}; let taskAccountDataJSON = await namespaceWrapper.getTaskState(); @@ -104,7 +103,7 @@ class CoreLogic { } async submitDistributionList(round) { - // This function just upload your generated dustribution List and do the transaction for that + // This upload the generated dustribution List console.log('SubmitDistributionList called'); @@ -159,8 +158,6 @@ class CoreLogic { _dummyDistributionList, _dummyTaskState, ) => { - // Write your logic for the validation of submission value here and return a boolean value in response - // this logic can be same as generation of distribution list function and based on the comparision will final object , decision can be made try { console.log('Distribution list Submitter', distributionListSubmitter); @@ -216,7 +213,7 @@ class CoreLogic { } async auditTask(roundNumber) { - // No need to edit this function + console.log('auditTask called with round', roundNumber); console.log( await namespaceWrapper.getSlot(), diff --git a/dbSharing.js b/dbSharing.js index 332dd23e..77e16d0e 100644 --- a/dbSharing.js +++ b/dbSharing.js @@ -1,6 +1,12 @@ +const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); +const {default: axios} = require('axios'); + const share = async () => { try { + // find another node const nodesUrl = `${SERVICE_URL}/nodes/${TASK_ID}`; + + // check if the node is online const res = await axios.get(nodesUrl); if (res.status != 200) { console.error('Error', res.status); @@ -11,12 +17,20 @@ const share = async () => { console.error('res has no valid urls'); return; } + let nodeUrlList = res.data.map((e) => { return e.data.url; }); + console.log(nodeUrlList); + + // fetch local linktrees let allLinktrees = await db.getLinktree(publicKey); // TODO allLinktrees = JSON.parse(allLinktrees || '[]'); + + // for each node, get all linktrees? + // TODO - get only one linktree per node, and compare them + // it will be cleaner to focus on one pubkey, and compare with many nodes (maybe 3 nodes) for (let url of nodeUrlList) { console.log(url); const res = await axios.get(`${url}/task/${TASK_ID}/get-all-linktrees`); @@ -25,6 +39,15 @@ const share = async () => { continue; } const payload = res.data; + + + // TODO - there are several things to compare + /* + 1. the list of all linktrees held by each node (the list of public keys) + 2. the linktree data for each public key + 3. the timestamp of each linktree item on each node (we should only download newer data) + */ + /* 1. Verify the signature 2. Only update your db if incoming timestamp > your timestamp or you don't have the data diff --git a/index.js b/index.js index 009958c0..38f62512 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const coreLogic = require("./coreLogic"); -const dbSharing = require("./db_sharing"); -// const localShim = require("./localTestingShim"); // to enable testing with K2 without round timers, enable this line and line 59 +const dbSharing = require("./dbSharing"); +const localShim = require("./localTestingShim"); // to enable testing with K2 without round timers, enable this line and line 59 const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const express = require('express'); const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); @@ -54,9 +54,11 @@ async function setup() { }); // Code for the data replication among the nodes - setInterval(dbSharing.share(), 20000); + setInterval(() => { + dbSharing.share(); + }, 20000); - // localShim(); // enable this to run the localShim for testing with K2 without timers + localShim(); // enable this to run the localShim for testing with K2 without timers } diff --git a/linktree_task.js b/linktree_task.js index 54adb5f1..bea1c52a 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -13,30 +13,28 @@ const db = require('./db_model'); const main = async () => { console.log('******/ IN Linktree Task FUNCTION /******'); - // TODO - remove the new keypair generation below and use the keypairs already held on the node - // TODO - https://docs.koii.network/develop/microservices-and-tasks/task-development-kit-tdk/using-the-task-namespace/wallet-signatures - - // Customize linktree test data - const keyPair = nacl.sign.keyPair(); - const publicKey = keyPair.publicKey; - const privateKey = keyPair.secretKey; + // Load node's keypair from the JSON file + // ! return error, ask Syed + const keypair = await namespaceWrapper.getSubmitterAccount(); // Get linktree list fron localdb const proofs_list_object = await db.getAllProofs(); + // Use the node's keypair to sign the linktree list const messageUint8Array = new Uint8Array( Buffer.from(JSON.stringify(proofs_list_object)), ); - const signedMessage = nacl.sign(messageUint8Array, privateKey); + + const signedMessage = nacl.sign(messageUint8Array, keypair.secretKey); const signature = signedMessage.slice(0, nacl.sign.signatureLength); const submission_value = { proofs: proofs_list_object, - node_publicKey: bs58.encode(publicKey), + node_publicKey: bs58.encode(keypair.publicKey), node_signature: bs58.encode(signature), }; - // upload the index of the linktree on web3.storage + // upload the proofs of the linktree on web3.storage const path = `./Linktree/proofs.json`; if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); diff --git a/linktree_validate.js b/linktree_validate.js index 3d826371..eb151eb1 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -2,6 +2,7 @@ const dataFromCid = require("./helpers/dataFromCid"); const db = require('./db_model'); const nacl = require('tweetnacl'); const bs58 = require('bs58'); +const { namespaceWrapper } = require("./namespaceWrapper"); module.exports = async (submission_value, round) => { console.log('******/ Linktree CID VALIDATION Task FUNCTION /******'); @@ -19,6 +20,7 @@ module.exports = async (submission_value, round) => { // check each item in the linktrees list and verify that the node is holding that payload, and the signature matches let isLinktree = await verifyLinktree(output.proofs); + console.log('IS LINKTREE True?', isLinktree); if (isNode && isLinktree) return true; // if both are true, return true else return false; // if one of them is false, return false @@ -29,41 +31,46 @@ async function verifyLinktree(proofs_list_object) { let allSignaturesValid = true; let AuthUserList = await db.getAllAuthLists(); console.log('Authenticated Users List:', AuthUserList); - console.log('IS LINKTREE True?', isLinktree); for (const proofs of proofs_list_object) { - const linktree_object = await db.getLinktree(proofs.value[0].publicKey); // TODO - replace this with a call to the other node - // TODO #2 - once you've done this, be sure to ignore any duplicates for the same node for the same pubkey, otherwise multiple updates in one round will cause audits - const messageUint8Array = new Uint8Array( - Buffer.from(JSON.stringify(linktree_object.data)), - ); + let publicKey = proofs.value[0].publicKey - // check if the user's pubkey is on the authlist - if ( !AuthUserList.contains(proofs.value[0].publicKey) ) { - // if not, check the node that supplied this proof, and verify that this user is in fact authorized + // call other nodes to get the node list + const nodeUrlList = await namespaceWrapper.getNodes(); - // TODO write logic to query other node and verify registration events - /* - 1. REST API that returns a user's registration proof and accepts :pubkey - 2. Add logic here to verify 'proofs' from (1) and then add the user to the AuthUserList - */ + // verify the signature of the linktree for each nodes + for (const nodeUrl of nodeUrlList) { + console.log("cheking linktree on ", nodeUrl) + + // get all linktree in this node + const res = await axios.get(`${url}/task/${TASK_ID}/linktree/get/${publicKey}`); + + // check node's status + if (res.status != 200) { + console.error('ERROR', res.status); + continue; + } + + // get the payload + const linktree = res.data; + + // check if the user's pubkey is on the authlist + if ( !AuthUserList.contains(linktree.publicKey) ) { - // TODO - add the user to the AuthUserList (might need to be updated later) - await db.setAuthList(publicKey); + // TODO write logic to query other node and verify registration events + /* + 1. REST API that returns a user's registration proof and accepts :pubkey + 2. Add logic here to verify 'proofs' from (1) and then add the user to the AuthUserList + */ - } else { - // TODO - flush this out more, might need to add an automatic update on the AuthUserList to ensure that this node is always up to date - console.log('found invalid linktree data') - - - // TODO - fix the array structure so you don't have to do this lol - const signature = proofs.value[0].signature; - const publicKey = proofs.value[0].publicKey; + } else { + + // Verify the signature + const signature = linktree.signature; + const publicKey = linktree.publicKey; const signatureUint8Array = bs58.decode(signature); const publicKeyUint8Array = bs58.decode(publicKey); - - // verify the linktree signature const isSignatureValid = await verifySignature( messageUint8Array, signatureUint8Array, @@ -71,15 +78,15 @@ async function verifyLinktree(proofs_list_object) { ); console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); - } + if (isSignatureValid) { + await db.setAuthList(publicKey) + } else { + allSignaturesValid = false; + } - if (isSignatureValid) { - - } else { - allSignaturesValid = false; + } + } } - - } return allSignaturesValid; } diff --git a/localTestingShim.js b/localTestingShim.js index 970ce16f..b30f6f52 100644 --- a/localTestingShim.js +++ b/localTestingShim.js @@ -12,12 +12,12 @@ const localShim = async () => { */ - // console.log("*******************TESTING*******************") + console.log("*******************TESTING*******************") // Get the task state // console.log(await namespaceWrapper.getTaskState()); // Get account public key - // console.log(MAIN_ACCOUNT_PUBKEY); + console.log(MAIN_ACCOUNT_PUBKEY); // GET ROUND // const round = await namespaceWrapper.getRound(); @@ -25,13 +25,13 @@ const localShim = async () => { // Call to do the work for the task - // await coreLogic.task(); + await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) - // await coreLogic.submitTask(round - 1); + await coreLogic.submitTask(round - 1); // Audit submissions - // await coreLogic.auditTask(round - 1); + await coreLogic.auditTask(round - 1); // upload distribution list to K2 diff --git a/routes.js b/routes.js index 67bd5e6e..54ff221f 100644 --- a/routes.js +++ b/routes.js @@ -27,24 +27,6 @@ router.use((req, res, next) => { console.log(linktree); } - // TODO: validate the linktree structure here - /* - 1. Must have the following structure - 2. Signature must be verified by the publicKey - */ - - /* - { - data:{ - uuid:jhasjdbjhguyt23764vhyt - linktree:linktree, - timestamp:76576465, - }, - publicKey:"FnQm11NXJxPSjza3fuhuQ6Cu4fKNqdaPkVSRyLSWf14d", - signature:"" - } - */ - // Use the code below to sign the data payload let signature = linktree.signature; let pubkey = linktree.publicKey diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js index aa72699f..a7aee2c0 100644 --- a/test/test_docker_submitlinktree.js +++ b/test/test_docker_submitlinktree.js @@ -9,8 +9,6 @@ const crypto = require('crypto'); // This test submits linktrees from differnet publicKey to the service and stored in localdb async function main() { try { - for (let i = 0; i < 5; i++) { - console.log('i', i); const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) @@ -46,7 +44,7 @@ try { // console.log(payload); await axios - .post('http://localhost:8080/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/register-linktree', {payload}) + .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); @@ -56,7 +54,6 @@ try { .catch((e) => { console.error(e); }); - } } catch (e) { console.error(e) } diff --git a/test/test_signature.js b/test/test_signature.js new file mode 100644 index 00000000..e7c0548a --- /dev/null +++ b/test/test_signature.js @@ -0,0 +1,19 @@ +const nacl = require('tweetnacl'); +const {namespaceWrapper} = require('../namespaceWrapper'); + +async function main() { +const keypair = await namespaceWrapper.getSubmitterAccount(); + +// Generate a signature +const message = 'Hello, Solana!'; +const messageBuffer = Buffer.from(message, 'utf8'); +const signature = nacl.sign.detached(messageBuffer, keypair.secretKey); + +console.log('Signature:', Buffer.from(signature).toString('hex')); + +// Verify the signature +const isValid = nacl.sign.detached.verify(messageBuffer, signature, keypair.publicKey); +console.log('Is the signature valid?', isValid); +} + +main() \ No newline at end of file From d5d4c9f7122c64c78f412a230c5e8f2bbfe047e0 Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 13 Apr 2023 16:20:10 -0300 Subject: [PATCH 51/61] update testing code --- db_model.js | 8 +++++--- linktree_task.js | 9 ++++++--- linktree_validate.js | 36 ++++++++++++++++++++++++------------ routes.js | 21 +++++++++++++++------ test/unitTest.js | 11 ++++++++--- 5 files changed, 58 insertions(+), 27 deletions(-) diff --git a/db_model.js b/db_model.js index c205f73c..59177e44 100644 --- a/db_model.js +++ b/db_model.js @@ -28,6 +28,7 @@ const getAllLinktrees = async (values) => { if (!values) values = true; db.createReadStream({ lt: 'linktree~', + gt: `linktree`, reverse: true, keys: true, values: values @@ -80,7 +81,7 @@ const getAllProofs = async () => { }) .on('data', function (data) { console.log( data.key.toString(), '=', data.value.toString()) - dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString())}); + dataStore.push( JSON.parse(data.value.toString())); }) .on('error', function (err) { console.log('Something went wrong in read proofsStream!', err); @@ -177,7 +178,7 @@ const getAllAuthLists = async (values) => { authListStream .on('data', function (data) { console.log( data.key.toString(), '=', data.value.toString()) - dataStore.push({ key: data.key.toString(), value: JSON.parse(data.value.toString()) }); + dataStore.push( JSON.parse(data.value.toString()) ); }) .on('error', function (err) { console.log('Something went wrong in read authListStream!', err); @@ -223,5 +224,6 @@ module.exports = { getAllNodeProofCids, getAuthList, setAuthList, - getAllAuthLists + getAllAuthLists, + getAuthListId } \ No newline at end of file diff --git a/linktree_task.js b/linktree_task.js index bea1c52a..d945e552 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -9,13 +9,16 @@ const storageClient = new Web3Storage({ const bs58 = require('bs58'); const nacl = require('tweetnacl'); const db = require('./db_model'); +const { Keypair } = require('@solana/web3.js'); // TEST For local testing const main = async () => { console.log('******/ IN Linktree Task FUNCTION /******'); // Load node's keypair from the JSON file - // ! return error, ask Syed - const keypair = await namespaceWrapper.getSubmitterAccount(); + // const keypair = await namespaceWrapper.getSubmitterAccount(); + + // TEST For local testing, hardcode the keypair + const keypair = Keypair.generate(); // Get linktree list fron localdb const proofs_list_object = await db.getAllProofs(); @@ -30,7 +33,7 @@ const main = async () => { const submission_value = { proofs: proofs_list_object, - node_publicKey: bs58.encode(keypair.publicKey), + node_publicKey: keypair.publicKey, node_signature: bs58.encode(signature), }; diff --git a/linktree_validate.js b/linktree_validate.js index eb151eb1..64642a8e 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -2,24 +2,25 @@ const dataFromCid = require("./helpers/dataFromCid"); const db = require('./db_model'); const nacl = require('tweetnacl'); const bs58 = require('bs58'); +const {default: axios} = require('axios'); const { namespaceWrapper } = require("./namespaceWrapper"); module.exports = async (submission_value, round) => { console.log('******/ Linktree CID VALIDATION Task FUNCTION /******'); const outputraw = await dataFromCid(submission_value); const output = outputraw.data; - - console.log('RESPONSE DATA length', output.proofs.LENGTH); - console.log('PUBLIC KEY', output.publicKey); - console.log('SIGNATURE', output.signature); + console.log('OUTPUT', output); + console.log('RESPONSE DATA length', output.proofs[0].LENGTH); + console.log('PUBLIC KEY', output.node_publicKey); + console.log('SIGNATURE', output.node_signature); // TODO - can we safely remove this, from a game theory perspective? // Check that the node who submitted the proofs is a valid staked node - let isNode = await verifyNode(output.proofs, output.signature, output.publicKey); + let isNode = await verifyNode(output.proofs, output.node_signature, output.node_publicKey); console.log("Is the node's signature on the CID payload correct?", isNode); // check each item in the linktrees list and verify that the node is holding that payload, and the signature matches - let isLinktree = await verifyLinktree(output.proofs); + let isLinktree = await verifyLinktrees(output.proofs); console.log('IS LINKTREE True?', isLinktree); if (isNode && isLinktree) return true; // if both are true, return true @@ -27,7 +28,7 @@ module.exports = async (submission_value, round) => { } // verify the linktree signature by querying the other node to get it's copy of the linktree -async function verifyLinktree(proofs_list_object) { +async function verifyLinktrees(proofs_list_object) { let allSignaturesValid = true; let AuthUserList = await db.getAllAuthLists(); console.log('Authenticated Users List:', AuthUserList); @@ -37,14 +38,22 @@ async function verifyLinktree(proofs_list_object) { let publicKey = proofs.value[0].publicKey // call other nodes to get the node list - const nodeUrlList = await namespaceWrapper.getNodes(); + // * const nodeUrlList = await namespaceWrapper.getNodes(); + + // TEST hardcode the node list + const nodeUrlList = [ + "http://localhost:10000", + ] // verify the signature of the linktree for each nodes for (const nodeUrl of nodeUrlList) { console.log("cheking linktree on ", nodeUrl) // get all linktree in this node - const res = await axios.get(`${url}/task/${TASK_ID}/linktree/get/${publicKey}`); + // * const res = await axios.get(`${url}/task/${TASK_ID}/linktree/get/${publicKey}`); + + // TEST hardcode the node endpoint + const res = await axios.get(`${nodeUrl}/linktree/get/${publicKey}`); // check node's status if (res.status != 200) { @@ -56,9 +65,9 @@ async function verifyLinktree(proofs_list_object) { const linktree = res.data; // check if the user's pubkey is on the authlist - if ( !AuthUserList.contains(linktree.publicKey) ) { + if (AuthUserList.hasOwnProperty(linktree.publicKey) ) { - // TODO write logic to query other node and verify registration events + // TODO write logic to quersy other node and verify registration events /* 1. REST API that returns a user's registration proof and accepts :pubkey 2. Add logic here to verify 'proofs' from (1) and then add the user to the AuthUserList @@ -67,6 +76,9 @@ async function verifyLinktree(proofs_list_object) { } else { // Verify the signature + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(linktree.data)), + ); const signature = linktree.signature; const publicKey = linktree.publicKey; const signatureUint8Array = bs58.decode(signature); @@ -79,7 +91,7 @@ async function verifyLinktree(proofs_list_object) { console.log(`IS SIGNATURE ${publicKey} VALID?`, isSignatureValid); if (isSignatureValid) { - await db.setAuthList(publicKey) + await db.setAuthList(publicKey) // TODO refactor for direct database usage and read / writes of individual authorized users by pubkey (otherwise full rewrite could risk overwriting another write if running in parallel) } else { allSignaturesValid = false; } diff --git a/routes.js b/routes.js index 54ff221f..28e797e6 100644 --- a/routes.js +++ b/routes.js @@ -1,5 +1,7 @@ const express = require('express'); const router = express.Router(); +const db = require('./db_model'); +const fs = require('fs'); // Middleware to log incoming requests router.use((req, res, next) => { @@ -66,7 +68,7 @@ router.use((req, res, next) => { router.get('/linktree/get/:publicKey', async (req, res) => { const { publicKey } = req.params; let linktree = await db.getLinktree(publicKey); - linktree = JSON.parse(linktree || '[]'); + linktree = linktree || '[]'; return res.status(200).send(linktree); }); router.get('/linktree/all', async (req, res) => { @@ -77,7 +79,7 @@ router.use((req, res, next) => { ); router.get('/linktree/list', async (req, res) => { - linktree = await db.getAllLinktrees(false) || '[]'; + linktree = await db.getAllLinktrees(true) || '[]'; return res.status(200).send(linktree); } ); @@ -86,20 +88,27 @@ router.use((req, res, next) => { return res.status(200).send(linktree); } ); + router.get('/proofs/get/:publicKey', async (req, res) => { + const { publicKey } = req.params; + let proof = await db.getProofs(publicKey); + proof = proof || '[]'; + return res.status(200).send(proof); + } + ); router.get('/node-proof/all', async (req, res) => { linktree = await db.getAllNodeProofCids() || '[]'; return res.status(200).send(linktree); }); - router.get('/authlist/get/:round', async (req, res) => { - const { round } = req.params; - let authlist = await db.getAuthList(round); + router.get('/authlist/get/:publicKey', async (req, res) => { + const { publicKey } = req.params; + let authlist = await db.getAuthList(publicKey); authlist = authlist || '[]'; return res.status(200).send(authlist); }); router.get('/authlist/list', async (req, res) => { authlist = await db.getAllAuthLists(false) || '[]'; authlist.forEach((authuser) => { - authuser = authuser.split("authlist:")[0] // TODO verify that this properly trims the 'authlist:' prefix + authuser = authuser.toString().split("auth_list:")[0] }); return res.status(200).send(authlist); }); diff --git a/test/unitTest.js b/test/unitTest.js index fef28edf..ee25c75a 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -2,12 +2,17 @@ const coreLogic = require('../coreLogic'); const index = require('../index'); async function test_coreLogic() { - await coreLogic.task(); - const submission = await coreLogic.fetchSubmission(); - // let submission= "bafybeih6xpbghwjrq4vryo4p6ps6vcv7zp5ng3rvuffoouzs63ri6ybqdy" + // await coreLogic.task(); + + // const submission = await coreLogic.fetchSubmission(); + + // TEST hardcode the submission + let submission= "bafybeiaipp6owksgigqx73putgxr7qfiuly32isubrqjc4meqwty6xu5xa" console.log('SUBMISSION', submission); + const vote = await coreLogic.validateNode(submission, 1000); console.log('VOTE', vote); + // let vote = true; // const _dummyTaskState = { // submissions: { From f7aae262f42ad3c497c150ec3519c5db4f80e5ab Mon Sep 17 00:00:00 2001 From: soma Date: Thu, 13 Apr 2023 16:56:01 -0300 Subject: [PATCH 52/61] update for compose test --- dbSharing.js | 1 + localTestingShim.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dbSharing.js b/dbSharing.js index 77e16d0e..9898bc77 100644 --- a/dbSharing.js +++ b/dbSharing.js @@ -1,5 +1,6 @@ const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const {default: axios} = require('axios'); +const db = require('./db_model'); const share = async () => { try { diff --git a/localTestingShim.js b/localTestingShim.js index b30f6f52..03ee314d 100644 --- a/localTestingShim.js +++ b/localTestingShim.js @@ -1,3 +1,6 @@ +const coreLogic = require("./coreLogic"); +// TEST Set round +let round = 1000 const localShim = async () => { /* GUIDE TO CALLS K2 FUNCTIONS MANUALLY @@ -17,7 +20,7 @@ const localShim = async () => { // console.log(await namespaceWrapper.getTaskState()); // Get account public key - console.log(MAIN_ACCOUNT_PUBKEY); + // console.log(MAIN_ACCOUNT_PUBKEY); // GET ROUND // const round = await namespaceWrapper.getRound(); From 277b4d5590125b4c3e33feec5fa746de0094ea06 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 11:10:21 -0300 Subject: [PATCH 53/61] fix some code --- coreLogic.js | 12 ++++++------ dbSharing.js | 2 +- localTestingShim.js | 5 ++++- routes.js | 6 +++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/coreLogic.js b/coreLogic.js index d2f0265c..3c4dd3e5 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -14,10 +14,10 @@ class CoreLogic { const proof_cid = await linktree_task(); - // const round = await namespaceWrapper.getRound(); + const round = await namespaceWrapper.getRound(); - // For only testing purposes: - const round = 1000 + // TEST For only testing purposes: + // const round = 1000 if (proof_cid) { await db.setNodeProofCid(round, proof_cid); // store CID in levelDB @@ -36,9 +36,9 @@ class CoreLogic { console.log('***********IN FETCH SUBMISSION**************'); // The code below shows how you can fetch your stored value from level DB - // For only testing purposes: - const round = 1000 - // const round = await namespaceWrapper.getRound(); + // TEST For only testing purposes: + // const round = 1000 + const round = await namespaceWrapper.getRound(); const proof_cid = await db.getNodeProofCid(round); // retrieves the cid console.log('Linktree proofs CID', proof_cid, "in round", round); diff --git a/dbSharing.js b/dbSharing.js index 9898bc77..9cff2a95 100644 --- a/dbSharing.js +++ b/dbSharing.js @@ -26,7 +26,7 @@ const share = async () => { console.log(nodeUrlList); // fetch local linktrees - let allLinktrees = await db.getLinktree(publicKey); // TODO + let allLinktrees = await db.getAllLinktrees(); // TODO allLinktrees = JSON.parse(allLinktrees || '[]'); // for each node, get all linktrees? diff --git a/localTestingShim.js b/localTestingShim.js index 03ee314d..c48bcb0e 100644 --- a/localTestingShim.js +++ b/localTestingShim.js @@ -1,6 +1,9 @@ const coreLogic = require("./coreLogic"); +const namespaceWrapper = require("./namespaceWrapper"); + // TEST Set round -let round = 1000 +// let round = 1000 +const round = await namespaceWrapper.getRound(); const localShim = async () => { /* GUIDE TO CALLS K2 FUNCTIONS MANUALLY diff --git a/routes.js b/routes.js index 28e797e6..4779bf9f 100644 --- a/routes.js +++ b/routes.js @@ -44,9 +44,9 @@ router.use((req, res, next) => { // fs.writeFileSync('proof.json', JSON.stringify(proof)); await db.setLinktree(pubkey, linktree); - // const round = await namespaceWrrouterer.getRound(); - // For only testing purposes: - const round = 1000 + const round = await namespaceWrrouterer.getRound(); + // TEST For only testing purposes: + // const round = 1000 let proofs = await db.getProofs(pubkey); proofs = JSON.parse(proofs || '[]'); From d12b74040259f24c3825b8cfcb68b63fb4e06094 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 12:01:04 -0300 Subject: [PATCH 54/61] fix round submission --- .env-local | 2 +- coreLogic.js | 5 +++-- dbSharing.js | 2 +- index.js | 4 ++-- linktree_task.js | 4 ++-- localTestingShim.js | 8 ++++---- routes.js | 5 +++++ 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.env-local b/.env-local index 2813a4a0..0a19a361 100644 --- a/.env-local +++ b/.env-local @@ -12,7 +12,7 @@ INITIAL_STAKING_WALLET_BALANCE=15 # Intial balance for the distribution wallet which will be used to hold the distribution list. INITIAL_DISTRIBUTION_WALLET_BALANCE=1 # Global timers which track the round time, submission window and audit window and call those functions -GLOBAL_TIMERS="false" +GLOBAL_TIMERS="true" # environment ENVIRONMENT="development" # HAVE_STATIC_IP is flag to indicate you can run tasks that host APIs diff --git a/coreLogic.js b/coreLogic.js index 3c4dd3e5..c4095ae7 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -21,6 +21,7 @@ class CoreLogic { if (proof_cid) { await db.setNodeProofCid(round, proof_cid); // store CID in levelDB + console.log('Node Proof CID stored in round', round) } else { console.log('CID NOT FOUND'); } @@ -40,8 +41,8 @@ class CoreLogic { // const round = 1000 const round = await namespaceWrapper.getRound(); - const proof_cid = await db.getNodeProofCid(round); // retrieves the cid - console.log('Linktree proofs CID', proof_cid, "in round", round); + const proof_cid = await db.getNodeProofCid(round - 1); // retrieves the cid + console.log('Linktree proofs CID', proof_cid, "in round", round - 1); return proof_cid; } diff --git a/dbSharing.js b/dbSharing.js index 9cff2a95..e2853182 100644 --- a/dbSharing.js +++ b/dbSharing.js @@ -27,7 +27,7 @@ const share = async () => { // fetch local linktrees let allLinktrees = await db.getAllLinktrees(); // TODO - allLinktrees = JSON.parse(allLinktrees || '[]'); + allLinktrees = allLinktrees || '[]'; // for each node, get all linktrees? // TODO - get only one linktree per node, and compare them diff --git a/index.js b/index.js index 38f62512..fc79d414 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const coreLogic = require("./coreLogic"); const dbSharing = require("./dbSharing"); -const localShim = require("./localTestingShim"); // to enable testing with K2 without round timers, enable this line and line 59 +// const localShim = require("./localTestingShim"); // TEST to enable testing with K2 without round timers, enable this line and line 59 const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const express = require('express'); const { namespaceWrapper, taskNodeAdministered } = require("./namespaceWrapper"); @@ -58,7 +58,7 @@ async function setup() { dbSharing.share(); }, 20000); - localShim(); // enable this to run the localShim for testing with K2 without timers + // localShim(); // TEST enable this to run the localShim for testing with K2 without timers } diff --git a/linktree_task.js b/linktree_task.js index d945e552..36ececb8 100644 --- a/linktree_task.js +++ b/linktree_task.js @@ -15,10 +15,10 @@ const main = async () => { console.log('******/ IN Linktree Task FUNCTION /******'); // Load node's keypair from the JSON file - // const keypair = await namespaceWrapper.getSubmitterAccount(); + const keypair = await namespaceWrapper.getSubmitterAccount(); // TEST For local testing, hardcode the keypair - const keypair = Keypair.generate(); + // const keypair = Keypair.generate(); // Get linktree list fron localdb const proofs_list_object = await db.getAllProofs(); diff --git a/localTestingShim.js b/localTestingShim.js index c48bcb0e..e26e627b 100644 --- a/localTestingShim.js +++ b/localTestingShim.js @@ -18,7 +18,7 @@ const localShim = async () => { */ - console.log("*******************TESTING*******************") + // console.log("*******************TESTING*******************") // Get the task state // console.log(await namespaceWrapper.getTaskState()); @@ -31,13 +31,13 @@ const localShim = async () => { // Call to do the work for the task - await coreLogic.task(); + // await coreLogic.task(); // Submission to K2 (Preferablly you should submit the cid received from IPFS) - await coreLogic.submitTask(round - 1); + // await coreLogic.submitTask(round - 1); // Audit submissions - await coreLogic.auditTask(round - 1); + // await coreLogic.auditTask(round - 1); // upload distribution list to K2 diff --git a/routes.js b/routes.js index 4779bf9f..c11d22d2 100644 --- a/routes.js +++ b/routes.js @@ -99,6 +99,11 @@ router.use((req, res, next) => { linktree = await db.getAllNodeProofCids() || '[]'; return res.status(200).send(linktree); }); + router.get('/node-proof/:round', async (req, res) => { + const { round } = req.params; + let nodeproof = await db.getNodeProofCid(round) || '[]'; + return res.status(200).send(nodeproof); + }); router.get('/authlist/get/:publicKey', async (req, res) => { const { publicKey } = req.params; let authlist = await db.getAuthList(publicKey); From f4de51224ef3d7022eb4f386b2147d3f5fa1b004 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 14:43:39 -0300 Subject: [PATCH 55/61] update namespace Wrapper --- db_model.js | 29 +-- namespaceWrapper-backup.js | 436 +++++++++++++++++++++++++++++++++++++ namespaceWrapper.js | 300 +++++++++++++------------ routes.js | 5 +- 4 files changed, 613 insertions(+), 157 deletions(-) create mode 100644 namespaceWrapper-backup.js diff --git a/db_model.js b/db_model.js index 59177e44..081c8e15 100644 --- a/db_model.js +++ b/db_model.js @@ -1,11 +1,12 @@ const levelup = require('levelup'); const leveldown = require('leveldown'); -const db = levelup(leveldown(__dirname + '/localKOIIDB')); +const { namespaceWrapper } = require('./namespaceWrapper'); +const fs = require('fs'); // db functions for linktree const getLinktree = async (publicKey) => { return new Promise((resolve, reject) => { - db.get(getLinktreeId(publicKey), (err, value) => { + namespaceWrapper.levelDB.get(getLinktreeId(publicKey), (err, value) => { if (err) { console.error("Error in getLinktree:", err); resolve(null); @@ -17,7 +18,7 @@ const getLinktree = async (publicKey) => { } const setLinktree = async (publicKey, linktree) => { - db.put(getLinktreeId(publicKey), JSON.stringify(linktree)); + namespaceWrapper.levelDB.put(getLinktreeId(publicKey), JSON.stringify(linktree)); return console.log("Linktree set"); } @@ -26,7 +27,7 @@ const getAllLinktrees = async (values) => { let dataStore = []; if (!values) values = true; - db.createReadStream({ + namespaceWrapper.levelDB.createReadStream({ lt: 'linktree~', gt: `linktree`, reverse: true, @@ -51,10 +52,10 @@ const getAllLinktrees = async (values) => { }); } -// db functions for proofs +// namespaceWrapper.levelDB functions for proofs const getProofs = async (pubkey) => { return new Promise((resolve, reject) => { - db.get(getProofsId(pubkey), (err, value) => { + namespaceWrapper.levelDB.get(getProofsId(pubkey), (err, value) => { if (err) { console.error("Error in getProofs:", err); resolve(null); @@ -66,14 +67,14 @@ const getProofs = async (pubkey) => { } const setProofs = async (pubkey, proofs) => { - db.put(getProofsId(pubkey), JSON.stringify(proofs)); + namespaceWrapper.levelDB.put(getProofsId(pubkey), JSON.stringify(proofs)); return console.log("Proofs set"); } const getAllProofs = async () => { return new Promise((resolve, reject) => { let dataStore = []; - db.createReadStream({ + namespaceWrapper.levelDB.createReadStream({ gte: 'proofs', reverse: true, keys: true, @@ -100,7 +101,7 @@ const getAllProofs = async () => { // db functions for node proofs const getNodeProofCid = async (round) => { return new Promise((resolve, reject) => { - db.get(getNodeProofCidid(round), (err, value) => { + namespaceWrapper.levelDB.get(getNodeProofCidid(round), (err, value) => { if (err) { console.error("Error in getNodeProofCid:", err); resolve(null); @@ -112,14 +113,14 @@ const getNodeProofCid = async (round) => { } const setNodeProofCid = async (round, cid) => { - db.put(getNodeProofCidid(round), cid); + namespaceWrapper.levelDB.put(getNodeProofCidid(round), cid); return console.log("Node CID set"); } const getAllNodeProofCids = async () => { return new Promise((resolve, reject) => { let dataStore = []; - const nodeProofsStream = db.createReadStream({ + const nodeProofsStream = namespaceWrapper.levelDB.createReadStream({ gt: 'node_proofs:', lt: 'node_proofs~', reverse: true, @@ -148,7 +149,7 @@ const getAllNodeProofCids = async () => { //db functions fro Auth list const getAuthList = async (pubkey) => { return new Promise((resolve, reject) => { - db.get(getAuthListId(pubkey), (err, value) => { + namespaceWrapper.levelDB.get(getAuthListId(pubkey), (err, value) => { if (err) { console.error("Error in getAuthList:", err); resolve(null); @@ -160,7 +161,7 @@ const getAuthList = async (pubkey) => { } const setAuthList = async (pubkey) => { - db.put(getAuthListId(pubkey), JSON.stringify(pubkey)); + namespaceWrapper.levelDB.put(getAuthListId(pubkey), JSON.stringify(pubkey)); return console.log("Auth List set"); } @@ -168,7 +169,7 @@ const getAllAuthLists = async (values) => { if (!values) values = true; return new Promise((resolve, reject) => { let dataStore = []; - const authListStream = db.createReadStream({ + const authListStream = namespaceWrapper.levelDB.createReadStream({ gt: 'auth_list:', lt: 'auth_list~', reverse: true, diff --git a/namespaceWrapper-backup.js b/namespaceWrapper-backup.js new file mode 100644 index 00000000..2b2b38af --- /dev/null +++ b/namespaceWrapper-backup.js @@ -0,0 +1,436 @@ +const { default: axios } = require("axios"); +const levelup = require('levelup'); +const leveldown = require('leveldown'); +const BASE_ROOT_URL = "http://localhost:8080/namespace-wrapper"; +const { TASK_ID, MAIN_ACCOUNT_PUBKEY, SECRET_KEY } = require("./init"); +const { Connection, PublicKey, Keypair } = require("@_koi/web3.js"); + +const taskNodeAdministered = !!TASK_ID; +let localLevelDB; +class NamespaceWrapper { + /** + * Namespace wrapper of storeGetAsync + * @param {string} key // Path to get + */ + async storeGet(key) { + if (taskNodeAdministered){ + return await genericHandler("storeGet", key); + } + instantiateLevelDb(); + return new Promise((resolve, reject) => { + localLevelDB.get(key, { asBuffer: false }, (err, value) => { + if (err) { + resolve(null); + } else { + resolve(value); + } + }); + }); + } + /** + * Namespace wrapper over storeSetAsync + * @param {string} key Path to set + * @param {*} value Data to set + */ + async storeSet(key, value) { + if (taskNodeAdministered){ + return await genericHandler("storeSet", key, value); + } + instantiateLevelDb(); + return new Promise((resolve, reject) => { + localLevelDB.put(key, value, {}, (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + + } + /** + * Namespace wrapper over fsPromises methods + * @param {*} method The fsPromise method to call + * @param {*} path Path for the express call + * @param {...any} args Remaining parameters for the FS call + */ + async fs(method, path, ...args) { + return await genericHandler("fs", method, path, ...args); + } + async fsStaking(method, path, ...args) { + return await genericHandler("fsStaking", method, path, ...args); + } + async fsWriteStream(imagepath) { + return await genericHandler("fsWriteStream", imagepath); + } + async fsReadStream(imagepath) { + return await genericHandler("fsReadStream", imagepath); + } + + async getSlot() { + return await genericHandler("getCurrentSlot"); + } + + async submissionOnChain(submitterKeypair, submission) { + return await genericHandler( + "submissionOnChain", + submitterKeypair, + submission + ); + } + + async stakeOnChain( + taskStateInfoPublicKey, + stakingAccKeypair, + stakePotAccount, + stakeAmount + ) { + return await genericHandler( + "stakeOnChain", + taskStateInfoPublicKey, + stakingAccKeypair, + stakePotAccount, + stakeAmount + ); + } + async claimReward(stakePotAccount, beneficiaryAccount, claimerKeypair) { + return await genericHandler( + "claimReward", + stakePotAccount, + beneficiaryAccount, + claimerKeypair + ); + } + async sendTransaction(serviceNodeAccount, beneficiaryAccount, amount) { + return await genericHandler( + "sendTransaction", + serviceNodeAccount, + beneficiaryAccount, + amount + ); + } + + async getSubmitterAccount() { + const submitterAccountResp = await genericHandler("getSubmitterAccount"); + return Keypair.fromSecretKey( + Uint8Array.from(Object.values(submitterAccountResp._keypair.secretKey)) + ); + } + + /** + * sendAndConfirmTransaction wrapper that injects mainSystemWallet as the first signer for paying the tx fees + * @param {connection} method // Receive method ["get", "post", "put", "delete"] + * @param {transaction} path // Endpoint path appended to namespace + * @param {Function} callback // Callback function on traffic receive + */ + async sendAndConfirmTransactionWrapper(transaction, signers) { + const blockhash = (await connection.getRecentBlockhash("finalized")) + .blockhash; + transaction.recentBlockhash = blockhash; + transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); + return await genericHandler( + "sendAndConfirmTransactionWrapper", + transaction.serialize({ + requireAllSignatures: false, + verifySignatures: false, + }), + signers + ); + } + + async signArweave(transaction) { + let tx = await genericHandler('signArweave',transaction.toJSON()); + return arweave.transactions.fromRaw(tx); + } + async signEth(transaction) { + return await genericHandler('signEth',transaction); + + } + async getTaskState() { + const response = await genericHandler("getTaskState"); + if(response.error){ + return null + } + return response + + } + + async auditSubmission(candidatePubkey, isValid, voterKeypair, round) { + return await genericHandler( + "auditSubmission", + candidatePubkey, + isValid, + voterKeypair, + round + ); + } + + async distributionListAuditSubmission( + candidatePubkey, + isValid, + voterKeypair, + round + ) { + return await genericHandler( + "distributionListAuditSubmission", + candidatePubkey, + isValid, + round + ); + } + + async getRound() { + return await genericHandler("getRound"); + } + + async nodeSelectionDistributionList() { + return await genericHandler("nodeSelectionDistributionList"); + } + + async payoutTrigger() { + return await genericHandler("payloadTrigger"); + } + + async uploadDistributionList(distributionList, round) { + return await genericHandler("uploadDistributionList", distributionList, round); + } + + async distributionListSubmissionOnChain(round) { + return await genericHandler("distributionListSubmissionOnChain", round); + } + + async payloadTrigger() { + return await genericHandler("payloadTrigger"); + } + + async verifySignature(signedMessage, pubKey) { + return await genericHandler("verifySignedData", signedMessage, pubKey); + } + + async payloadSigning(body) { + return await genericHandler("signData", body); + } + + async checkSubmissionAndUpdateRound(submissionValue = "default", round) { + return await genericHandler( + "checkSubmissionAndUpdateRound", + submissionValue, + round + ); + } + async getProgramAccounts() { + return await genericHandler("getProgramAccounts"); + } + async defaultTaskSetup() { + return await genericHandler("defaultTaskSetup"); + } + async getRpcUrl() { + return await genericHandler("getRpcUrl"); + } + async getNodes(url) { + return await genericHandler("getNodes", url); + } + + // Wrapper for selection of node to prepare a distribution list + + async nodeSelectionDistributionList(round) { + return await genericHandler("nodeSelectionDistributionList", round); + } + + async getDistributionList(publicKey,round) { + const response = await genericHandler('getDistributionList', publicKey, round); + if (response.error) { + return null; + } + return response + + } + + async validateAndVoteOnNodes(validate, round) { + // await this.checkVoteStatus(); + console.log("******/ IN VOTING /******"); + const taskAccountDataJSON = await this.getTaskState(); + + console.log( + "Fetching the submissions of N - 1 round", + taskAccountDataJSON.submissions[round] + ); + const submissions = taskAccountDataJSON.submissions[round]; + if (submissions == null) { + console.log("No submisssions found in N-1 round"); + return "No submisssions found in N-1 round"; + } else { + const keys = Object.keys(submissions); + const values = Object.values(submissions); + const size = values.length; + console.log("Submissions from last round: ", keys, values, size); + let isValid + const submitterAccountKeyPair = await this.getSubmitterAccount(); + const submitterPubkey = submitterAccountKeyPair.publicKey.toBase58(); + for (let i = 0; i < size; i++) { + let candidatePublicKey = keys[i]; + console.log("FOR CANDIDATE KEY", candidatePublicKey); + let candidateKeyPairPublicKey = new PublicKey(keys[i]); + if (candidatePublicKey == submitterPubkey) { + console.log("YOU CANNOT VOTE ON YOUR OWN SUBMISSIONS"); + } else { + try { + console.log( + "SUBMISSION VALUE TO CHECK", + values[i].submission_value + ); + isValid = await validate(values[i].submission_value, round); + console.log(`Voting ${isValid} to ${candidatePublicKey}`); + + if (isValid) { + // check for the submissions_audit_trigger , if it exists then vote true on that otherwise do nothing + const submissions_audit_trigger = + taskAccountDataJSON.submissions_audit_trigger[round]; + console.log("SUBMIT AUDIT TRIGGER", submissions_audit_trigger); + // console.log( + // "CANDIDATE PUBKEY CHECK IN AUDIT TRIGGER", + // submissions_audit_trigger[candidatePublicKey] + // ); + if (submissions_audit_trigger && submissions_audit_trigger[candidatePublicKey]) { + console.log("VOTING TRUE ON AUDIT"); + const response = await this.auditSubmission( + candidateKeyPairPublicKey, + isValid, + submitterAccountKeyPair, + round + ); + console.log("RESPONSE FROM AUDIT FUNCTION", response); + } + } else if (isValid == false) { + // Call auditSubmission function and isValid is passed as false + console.log("RAISING AUDIT / VOTING FALSE"); + const response = await this.auditSubmission( + candidateKeyPairPublicKey, + isValid, + submitterAccountKeyPair, + round + ); + console.log("RESPONSE FROM AUDIT FUNCTION", response); + } + } catch (err) { + console.log("ERROR IN ELSE CONDITION", err); + } + } + } + } + } + + + async validateAndVoteOnDistributionList(validateDistribution, round) { + // await this.checkVoteStatus(); + console.log("******/ IN VOTING OF DISTRIBUTION LIST /******"); + const taskAccountDataJSON = await this.getTaskState(); + console.log( + "Fetching the Distribution submissions of N - 2 round", + taskAccountDataJSON.distribution_rewards_submission[round] + ); + const submissions = + taskAccountDataJSON.distribution_rewards_submission[round]; + if (submissions == null) { + console.log("No submisssions found in N-2 round"); + return "No submisssions found in N-2 round"; + } else { + const keys = Object.keys(submissions); + const values = Object.values(submissions); + const size = values.length; + console.log("Distribution Submissions from last round: ", keys, values, size); + let isValid + const submitterAccountKeyPair = await this.getSubmitterAccount(); + const submitterPubkey = submitterAccountKeyPair.publicKey.toBase58(); + + for (let i = 0; i < size; i++) { + let candidatePublicKey = keys[i]; + console.log("FOR CANDIDATE KEY", candidatePublicKey); + let candidateKeyPairPublicKey = new PublicKey(keys[i]); + if (candidatePublicKey == submitterPubkey) { + console.log("YOU CANNOT VOTE ON YOUR OWN DISTRIBUTION SUBMISSIONS"); + } else { + try { + console.log( + "DISTRIBUTION SUBMISSION VALUE TO CHECK", + values[i].submission_value + ); + isValid = await validateDistribution(values[i].submission_value, round); + console.log(`Voting ${isValid} to ${candidatePublicKey}`); + + if (isValid) { + // check for the submissions_audit_trigger , if it exists then vote true on that otherwise do nothing + const distributions_audit_trigger = + taskAccountDataJSON.distributions_audit_trigger[round]; + console.log("SUBMIT DISTRIBUTION AUDIT TRIGGER", distributions_audit_trigger); + // console.log( + // "CANDIDATE PUBKEY CHECK IN AUDIT TRIGGER", + // distributions_audit_trigger[candidatePublicKey] + // ); + if (distributions_audit_trigger && distributions_audit_trigger[candidatePublicKey]) { + console.log("VOTING TRUE ON DISTRIBUTION AUDIT"); + const response = await this.distributionListAuditSubmission( + candidateKeyPairPublicKey, + isValid, + submitterAccountKeyPair, + round + ); + console.log("RESPONSE FROM DISTRIBUTION AUDIT FUNCTION", response); + } + } else if (isValid == false) { + // Call auditSubmission function and isValid is passed as false + console.log("RAISING AUDIT / VOTING FALSE ON DISTRIBUTION"); + const response = await this.distributionListAuditSubmission( + candidateKeyPairPublicKey, + isValid, + submitterAccountKeyPair, + round + ); + console.log("RESPONSE FROM DISTRIBUTION AUDIT FUNCTION", response); + } + } catch (err) { + console.log("ERROR IN ELSE CONDITION FOR DISTRIBUTION", err); + } + } + } + } + } +} + +async function instantiateLevelDb() { + if(!localLevelDB){ + localLevelDB = levelup(leveldown(__dirname + "/taskDB/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP")); + } +} + +async function genericHandler(...args) { + try { + let response = await axios.post(BASE_ROOT_URL, { + args, + taskId: TASK_ID, + secret: SECRET_KEY, + }); + if (response.status == 200) return response.data.response; + else { + console.error(response.status, response.data); + return null; + } + } catch (err) { + console.error(`Error in genericHandler: "${args[0]}"`,err.message); + console.error(err?.response?.data); + return {error:err}; + } +} +let connection; +const namespaceWrapper = new NamespaceWrapper(); +if(taskNodeAdministered){ + namespaceWrapper.getRpcUrl().then((rpcUrl) => { + console.log(rpcUrl, "RPC URL"); + connection = new Connection(rpcUrl, "confirmed"); + }); +} + +module.exports = { + namespaceWrapper, + taskNodeAdministered, +}; diff --git a/namespaceWrapper.js b/namespaceWrapper.js index e5651a05..a1597e10 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -1,26 +1,34 @@ -const { default: axios } = require("axios"); +const { default: axios } = require('axios'); const levelup = require('levelup'); const leveldown = require('leveldown'); -const BASE_ROOT_URL = "http://localhost:8080/namespace-wrapper"; -const { TASK_ID, MAIN_ACCOUNT_PUBKEY, SECRET_KEY } = require("./init"); -const { Connection, PublicKey, Keypair } = require("@_koi/web3.js"); - +const BASE_ROOT_URL = 'http://localhost:8080/namespace-wrapper'; +const { TASK_ID, MAIN_ACCOUNT_PUBKEY, SECRET_KEY } = require('./init'); +const { Connection, PublicKey, Keypair } = require('@_koi/web3.js'); const taskNodeAdministered = !!TASK_ID; -let localLevelDB; class NamespaceWrapper { + levelDB; + + constructor() { + if(taskNodeAdministered){ + this.getTaskLevelDBPath().then((path)=>{ + this.levelDB = levelup(leveldown(path)); + }).catch((err)=>{ + console.error(err) + this.levelDB=levelup(leveldown(`../namespace/${TASK_ID}/KOIILevelDB`)) + }) + }else{ + this.levelDB = levelup(leveldown('./localKOIIDB')); + } + } /** * Namespace wrapper of storeGetAsync * @param {string} key // Path to get */ async storeGet(key) { - if (taskNodeAdministered){ - return await genericHandler("storeGet", key); - } - instantiateLevelDb(); return new Promise((resolve, reject) => { - localLevelDB.get(key, { asBuffer: false }, (err, value) => { + this.levelDB.get(key, { asBuffer: false }, (err, value) => { if (err) { - resolve(null); + reject(err); } else { resolve(value); } @@ -33,20 +41,15 @@ class NamespaceWrapper { * @param {*} value Data to set */ async storeSet(key, value) { - if (taskNodeAdministered){ - return await genericHandler("storeSet", key, value); - } - instantiateLevelDb(); - return new Promise((resolve, reject) => { - localLevelDB.put(key, value, {}, (err) => { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); - + return new Promise((resolve, reject) => { + this.levelDB.put(key, value, {}, err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); } /** * Namespace wrapper over fsPromises methods @@ -55,27 +58,27 @@ class NamespaceWrapper { * @param {...any} args Remaining parameters for the FS call */ async fs(method, path, ...args) { - return await genericHandler("fs", method, path, ...args); + return await genericHandler('fs', method, path, ...args); } async fsStaking(method, path, ...args) { - return await genericHandler("fsStaking", method, path, ...args); + return await genericHandler('fsStaking', method, path, ...args); } async fsWriteStream(imagepath) { - return await genericHandler("fsWriteStream", imagepath); + return await genericHandler('fsWriteStream', imagepath); } async fsReadStream(imagepath) { - return await genericHandler("fsReadStream", imagepath); + return await genericHandler('fsReadStream', imagepath); } async getSlot() { - return await genericHandler("getCurrentSlot"); + return await genericHandler('getCurrentSlot'); } async submissionOnChain(submitterKeypair, submission) { return await genericHandler( - "submissionOnChain", + 'submissionOnChain', submitterKeypair, - submission + submission, ); } @@ -83,37 +86,37 @@ class NamespaceWrapper { taskStateInfoPublicKey, stakingAccKeypair, stakePotAccount, - stakeAmount + stakeAmount, ) { return await genericHandler( - "stakeOnChain", + 'stakeOnChain', taskStateInfoPublicKey, stakingAccKeypair, stakePotAccount, - stakeAmount + stakeAmount, ); } async claimReward(stakePotAccount, beneficiaryAccount, claimerKeypair) { return await genericHandler( - "claimReward", + 'claimReward', stakePotAccount, beneficiaryAccount, - claimerKeypair + claimerKeypair, ); } async sendTransaction(serviceNodeAccount, beneficiaryAccount, amount) { return await genericHandler( - "sendTransaction", + 'sendTransaction', serviceNodeAccount, beneficiaryAccount, - amount + amount, ); } async getSubmitterAccount() { - const submitterAccountResp = await genericHandler("getSubmitterAccount"); + const submitterAccountResp = await genericHandler('getSubmitterAccount'); return Keypair.fromSecretKey( - Uint8Array.from(Object.values(submitterAccountResp._keypair.secretKey)) + Uint8Array.from(Object.values(submitterAccountResp._keypair.secretKey)), ); } @@ -124,44 +127,42 @@ class NamespaceWrapper { * @param {Function} callback // Callback function on traffic receive */ async sendAndConfirmTransactionWrapper(transaction, signers) { - const blockhash = (await connection.getRecentBlockhash("finalized")) + const blockhash = (await connection.getRecentBlockhash('finalized')) .blockhash; transaction.recentBlockhash = blockhash; transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); return await genericHandler( - "sendAndConfirmTransactionWrapper", + 'sendAndConfirmTransactionWrapper', transaction.serialize({ requireAllSignatures: false, verifySignatures: false, }), - signers + signers, ); } - + async signArweave(transaction) { - let tx = await genericHandler('signArweave',transaction.toJSON()); + let tx = await genericHandler('signArweave', transaction.toJSON()); return arweave.transactions.fromRaw(tx); } async signEth(transaction) { - return await genericHandler('signEth',transaction); - + return await genericHandler('signEth', transaction); } async getTaskState() { - const response = await genericHandler("getTaskState"); - if(response.error){ - return null + const response = await genericHandler('getTaskState'); + if (response.error) { + return null; } - return response - + return response; } async auditSubmission(candidatePubkey, isValid, voterKeypair, round) { return await genericHandler( - "auditSubmission", + 'auditSubmission', candidatePubkey, isValid, - voterKeypair, - round + voterKeypair, + round, ); } @@ -169,115 +170,114 @@ class NamespaceWrapper { candidatePubkey, isValid, voterKeypair, - round + round, ) { return await genericHandler( - "distributionListAuditSubmission", + 'distributionListAuditSubmission', candidatePubkey, isValid, - round + round, ); } async getRound() { - return await genericHandler("getRound"); + return await genericHandler('getRound'); } async nodeSelectionDistributionList() { - return await genericHandler("nodeSelectionDistributionList"); + return await genericHandler('nodeSelectionDistributionList'); } async payoutTrigger() { - return await genericHandler("payloadTrigger"); + return await genericHandler('payloadTrigger'); } async uploadDistributionList(distributionList, round) { - return await genericHandler("uploadDistributionList", distributionList, round); + return await genericHandler( + 'uploadDistributionList', + distributionList, + round, + ); } async distributionListSubmissionOnChain(round) { - return await genericHandler("distributionListSubmissionOnChain", round); + return await genericHandler('distributionListSubmissionOnChain', round); } async payloadTrigger() { - return await genericHandler("payloadTrigger"); - } - - async verifySignature(signedMessage, pubKey) { - return await genericHandler("verifySignedData", signedMessage, pubKey); + return await genericHandler('payloadTrigger'); } - async payloadSigning(body) { - return await genericHandler("signData", body); - } - - async checkSubmissionAndUpdateRound(submissionValue = "default", round) { + async checkSubmissionAndUpdateRound(submissionValue = 'default', round) { return await genericHandler( - "checkSubmissionAndUpdateRound", + 'checkSubmissionAndUpdateRound', submissionValue, - round + round, ); } async getProgramAccounts() { - return await genericHandler("getProgramAccounts"); + return await genericHandler('getProgramAccounts'); } async defaultTaskSetup() { - return await genericHandler("defaultTaskSetup"); + return await genericHandler('defaultTaskSetup'); } async getRpcUrl() { - return await genericHandler("getRpcUrl"); + return await genericHandler('getRpcUrl'); } async getNodes(url) { - return await genericHandler("getNodes", url); + return await genericHandler('getNodes', url); } // Wrapper for selection of node to prepare a distribution list async nodeSelectionDistributionList(round) { - return await genericHandler("nodeSelectionDistributionList", round); + return await genericHandler('nodeSelectionDistributionList', round); } - async getDistributionList(publicKey,round) { - const response = await genericHandler('getDistributionList', publicKey, round); + async getDistributionList(publicKey, round) { + const response = await genericHandler( + 'getDistributionList', + publicKey, + round, + ); if (response.error) { return null; } - return response - + return response; } async validateAndVoteOnNodes(validate, round) { // await this.checkVoteStatus(); - console.log("******/ IN VOTING /******"); + console.log('******/ IN VOTING /******'); const taskAccountDataJSON = await this.getTaskState(); console.log( - "Fetching the submissions of N - 1 round", - taskAccountDataJSON.submissions[round] + 'Fetching the submissions of N - 1 round', + taskAccountDataJSON.submissions[round], ); const submissions = taskAccountDataJSON.submissions[round]; if (submissions == null) { - console.log("No submisssions found in N-1 round"); - return "No submisssions found in N-1 round"; + console.log('No submisssions found in N-1 round'); + return 'No submisssions found in N-1 round'; } else { const keys = Object.keys(submissions); const values = Object.values(submissions); const size = values.length; - console.log("Submissions from last round: ", keys, values, size); - let isValid + console.log('Submissions from last round: ', keys, values, size); + let isValid; const submitterAccountKeyPair = await this.getSubmitterAccount(); const submitterPubkey = submitterAccountKeyPair.publicKey.toBase58(); for (let i = 0; i < size; i++) { let candidatePublicKey = keys[i]; - console.log("FOR CANDIDATE KEY", candidatePublicKey); + console.log('FOR CANDIDATE KEY', candidatePublicKey); let candidateKeyPairPublicKey = new PublicKey(keys[i]); if (candidatePublicKey == submitterPubkey) { - console.log("YOU CANNOT VOTE ON YOUR OWN SUBMISSIONS"); + console.log('YOU CANNOT VOTE ON YOUR OWN SUBMISSIONS'); } else { try { console.log( - "SUBMISSION VALUE TO CHECK", - values[i].submission_value + 'SUBMISSION VALUE TO CHECK', + values[i].submission_value, ); isValid = await validate(values[i].submission_value, round); console.log(`Voting ${isValid} to ${candidatePublicKey}`); @@ -286,120 +286,139 @@ class NamespaceWrapper { // check for the submissions_audit_trigger , if it exists then vote true on that otherwise do nothing const submissions_audit_trigger = taskAccountDataJSON.submissions_audit_trigger[round]; - console.log("SUBMIT AUDIT TRIGGER", submissions_audit_trigger); + console.log('SUBMIT AUDIT TRIGGER', submissions_audit_trigger); // console.log( // "CANDIDATE PUBKEY CHECK IN AUDIT TRIGGER", // submissions_audit_trigger[candidatePublicKey] // ); - if (submissions_audit_trigger && submissions_audit_trigger[candidatePublicKey]) { - console.log("VOTING TRUE ON AUDIT"); + if ( + submissions_audit_trigger && + submissions_audit_trigger[candidatePublicKey] + ) { + console.log('VOTING TRUE ON AUDIT'); const response = await this.auditSubmission( candidateKeyPairPublicKey, isValid, submitterAccountKeyPair, - round + round, ); - console.log("RESPONSE FROM AUDIT FUNCTION", response); + console.log('RESPONSE FROM AUDIT FUNCTION', response); } } else if (isValid == false) { // Call auditSubmission function and isValid is passed as false - console.log("RAISING AUDIT / VOTING FALSE"); + console.log('RAISING AUDIT / VOTING FALSE'); const response = await this.auditSubmission( candidateKeyPairPublicKey, isValid, submitterAccountKeyPair, - round + round, ); - console.log("RESPONSE FROM AUDIT FUNCTION", response); + console.log('RESPONSE FROM AUDIT FUNCTION', response); } } catch (err) { - console.log("ERROR IN ELSE CONDITION", err); + console.log('ERROR IN ELSE CONDITION', err); } } } } } - async validateAndVoteOnDistributionList(validateDistribution, round) { // await this.checkVoteStatus(); - console.log("******/ IN VOTING OF DISTRIBUTION LIST /******"); + console.log('******/ IN VOTING OF DISTRIBUTION LIST /******'); const taskAccountDataJSON = await this.getTaskState(); console.log( - "Fetching the Distribution submissions of N - 2 round", - taskAccountDataJSON.distribution_rewards_submission[round] + 'Fetching the Distribution submissions of N - 2 round', + taskAccountDataJSON.distribution_rewards_submission[round], ); const submissions = taskAccountDataJSON.distribution_rewards_submission[round]; if (submissions == null) { - console.log("No submisssions found in N-2 round"); - return "No submisssions found in N-2 round"; + console.log('No submisssions found in N-2 round'); + return 'No submisssions found in N-2 round'; } else { const keys = Object.keys(submissions); const values = Object.values(submissions); const size = values.length; - console.log("Distribution Submissions from last round: ", keys, values, size); - let isValid + console.log( + 'Distribution Submissions from last round: ', + keys, + values, + size, + ); + let isValid; const submitterAccountKeyPair = await this.getSubmitterAccount(); const submitterPubkey = submitterAccountKeyPair.publicKey.toBase58(); for (let i = 0; i < size; i++) { let candidatePublicKey = keys[i]; - console.log("FOR CANDIDATE KEY", candidatePublicKey); + console.log('FOR CANDIDATE KEY', candidatePublicKey); let candidateKeyPairPublicKey = new PublicKey(keys[i]); if (candidatePublicKey == submitterPubkey) { - console.log("YOU CANNOT VOTE ON YOUR OWN DISTRIBUTION SUBMISSIONS"); + console.log('YOU CANNOT VOTE ON YOUR OWN DISTRIBUTION SUBMISSIONS'); } else { try { console.log( - "DISTRIBUTION SUBMISSION VALUE TO CHECK", - values[i].submission_value + 'DISTRIBUTION SUBMISSION VALUE TO CHECK', + values[i].submission_value, + ); + isValid = await validateDistribution( + values[i].submission_value, + round, ); - isValid = await validateDistribution(values[i].submission_value, round); console.log(`Voting ${isValid} to ${candidatePublicKey}`); if (isValid) { // check for the submissions_audit_trigger , if it exists then vote true on that otherwise do nothing const distributions_audit_trigger = taskAccountDataJSON.distributions_audit_trigger[round]; - console.log("SUBMIT DISTRIBUTION AUDIT TRIGGER", distributions_audit_trigger); + console.log( + 'SUBMIT DISTRIBUTION AUDIT TRIGGER', + distributions_audit_trigger, + ); // console.log( // "CANDIDATE PUBKEY CHECK IN AUDIT TRIGGER", // distributions_audit_trigger[candidatePublicKey] // ); - if (distributions_audit_trigger && distributions_audit_trigger[candidatePublicKey]) { - console.log("VOTING TRUE ON DISTRIBUTION AUDIT"); + if ( + distributions_audit_trigger && + distributions_audit_trigger[candidatePublicKey] + ) { + console.log('VOTING TRUE ON DISTRIBUTION AUDIT'); const response = await this.distributionListAuditSubmission( candidateKeyPairPublicKey, isValid, submitterAccountKeyPair, - round + round, + ); + console.log( + 'RESPONSE FROM DISTRIBUTION AUDIT FUNCTION', + response, ); - console.log("RESPONSE FROM DISTRIBUTION AUDIT FUNCTION", response); } } else if (isValid == false) { // Call auditSubmission function and isValid is passed as false - console.log("RAISING AUDIT / VOTING FALSE ON DISTRIBUTION"); + console.log('RAISING AUDIT / VOTING FALSE ON DISTRIBUTION'); const response = await this.distributionListAuditSubmission( candidateKeyPairPublicKey, isValid, submitterAccountKeyPair, - round + round, + ); + console.log( + 'RESPONSE FROM DISTRIBUTION AUDIT FUNCTION', + response, ); - console.log("RESPONSE FROM DISTRIBUTION AUDIT FUNCTION", response); } } catch (err) { - console.log("ERROR IN ELSE CONDITION FOR DISTRIBUTION", err); + console.log('ERROR IN ELSE CONDITION FOR DISTRIBUTION', err); } } } } } -} - -async function instantiateLevelDb() { - if(!localLevelDB){ - localLevelDB = levelup(leveldown(__dirname + "/localKOIIDB")); + async getTaskLevelDBPath() { + return await genericHandler('getTaskLevelDBPath'); } } @@ -416,21 +435,20 @@ async function genericHandler(...args) { return null; } } catch (err) { - console.error(`Error in genericHandler: "${args[0]}"`,err.message); + console.error(`Error in genericHandler: "${args[0]}"`, err.message); console.error(err?.response?.data); - return {error:err}; + return { error: err }; } } let connection; const namespaceWrapper = new NamespaceWrapper(); -if(taskNodeAdministered){ - namespaceWrapper.getRpcUrl().then((rpcUrl) => { - console.log(rpcUrl, "RPC URL"); - connection = new Connection(rpcUrl, "confirmed"); +if (taskNodeAdministered) { + namespaceWrapper.getRpcUrl().then(rpcUrl => { + console.log(rpcUrl, 'RPC URL'); + connection = new Connection(rpcUrl, 'confirmed'); }); } - module.exports = { namespaceWrapper, taskNodeAdministered, -}; +}; \ No newline at end of file diff --git a/routes.js b/routes.js index c11d22d2..f2ff99c2 100644 --- a/routes.js +++ b/routes.js @@ -2,6 +2,7 @@ const express = require('express'); const router = express.Router(); const db = require('./db_model'); const fs = require('fs'); +const { namespaceWrapper } = require('./namespaceWrapper'); // Middleware to log incoming requests router.use((req, res, next) => { @@ -12,7 +13,7 @@ router.use((req, res, next) => { router.get('/taskState', async (req, res) => { - const state = await namespaceWrrouterer.getTaskState(); + const state = await namespaceWrapper.getTaskState(); console.log("TASK STATE", state); res.status(200).json({ taskState: state }) @@ -44,7 +45,7 @@ router.use((req, res, next) => { // fs.writeFileSync('proof.json', JSON.stringify(proof)); await db.setLinktree(pubkey, linktree); - const round = await namespaceWrrouterer.getRound(); + const round = await namespaceWrapper.getRound(); // TEST For only testing purposes: // const round = 1000 From 5f57e59b114a6109351bfaf6dd2aefc0056d24df Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 15:04:49 -0300 Subject: [PATCH 56/61] update code --- linktree_validate.js | 10 +++++----- routes.js | 8 ++++---- test/test_docker_submitlinktree.js | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/linktree_validate.js b/linktree_validate.js index 64642a8e..03838ce5 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -41,19 +41,19 @@ async function verifyLinktrees(proofs_list_object) { // * const nodeUrlList = await namespaceWrapper.getNodes(); // TEST hardcode the node list - const nodeUrlList = [ - "http://localhost:10000", - ] + // const nodeUrlList = [ + // "http://localhost:10000", + // ] // verify the signature of the linktree for each nodes for (const nodeUrl of nodeUrlList) { console.log("cheking linktree on ", nodeUrl) // get all linktree in this node - // * const res = await axios.get(`${url}/task/${TASK_ID}/linktree/get/${publicKey}`); + const res = await axios.get(`${url}/task/${TASK_ID}/linktree/get/${publicKey}`); // TEST hardcode the node endpoint - const res = await axios.get(`${nodeUrl}/linktree/get/${publicKey}`); + // const res = await axios.get(`${nodeUrl}/linktree/get/${publicKey}`); // check node's status if (res.status != 200) { diff --git a/routes.js b/routes.js index f2ff99c2..651ce964 100644 --- a/routes.js +++ b/routes.js @@ -40,8 +40,8 @@ router.use((req, res, next) => { } console.log('Check Proof:', proof); // use fs to write the linktree and proof to a file - if (!fs.existsSync(__dirname + '/linktrees')) fs.mkdirSync(__dirname + '/linktrees'); - fs.writeFileSync(__dirname + "/linktrees/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); + if (!fs.existsSync('/Linktree')) fs.mkdirSync('/Linktree'); + fs.writeFileSync("/Linktree/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); // fs.writeFileSync('proof.json', JSON.stringify(proof)); await db.setLinktree(pubkey, linktree); @@ -73,14 +73,14 @@ router.use((req, res, next) => { return res.status(200).send(linktree); }); router.get('/linktree/all', async (req, res) => { - linktree = await db.getAllLinktrees() || '[]'; + linktree = await db.getAllLinktree() || '[]'; return res.status(200).send(linktree); } ); router.get('/linktree/list', async (req, res) => { - linktree = await db.getAllLinktrees(true) || '[]'; + linktree = await db.getAllLinktree(true) || '[]'; return res.status(200).send(linktree); } ); diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js index a7aee2c0..90c45209 100644 --- a/test/test_docker_submitlinktree.js +++ b/test/test_docker_submitlinktree.js @@ -44,7 +44,7 @@ try { // console.log(payload); await axios - .post('http://localhost:8080/task/7jP87G1LJzWmLrr6RqQcA8bH6spZven4RHxGCgbPFzSo/linktree', {payload}) + .post('http://localhost:8080/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); From f8ca8bc1e70c5ef79df9643d8b55ba0a4cd9e8d5 Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 18:38:46 -0300 Subject: [PATCH 57/61] debug code --- test/test_dbmodel.js | 24 ++++++++++++------------ test/test_docker_submitlinktree.js | 29 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/test/test_dbmodel.js b/test/test_dbmodel.js index 2e6fd995..0a64b60a 100644 --- a/test/test_dbmodel.js +++ b/test/test_dbmodel.js @@ -14,18 +14,18 @@ const pubkey = PublicKey; // await dbmodel.getAllLinktrees(); // set linktree - let linktree2 = { - "name": "test1", - "description": "test1", - "avatar": "test1", - "links": [ - { - "name": "test1", - "url": "test1" - } - ] - } - await dbmodel.setLinktree(PublicKey, linktree2); + // let linktree2 = { + // "name": "test1", + // "description": "test1", + // "avatar": "test1", + // "links": [ + // { + // "name": "test1", + // "url": "test1" + // } + // ] + // } + // await dbmodel.setLinktree(PublicKey, linktree2); // set node proofs // let cid = "testcid" diff --git a/test/test_docker_submitlinktree.js b/test/test_docker_submitlinktree.js index 90c45209..73376a34 100644 --- a/test/test_docker_submitlinktree.js +++ b/test/test_docker_submitlinktree.js @@ -9,14 +9,11 @@ const crypto = require('crypto'); // This test submits linktrees from differnet publicKey to the service and stored in localdb async function main() { try { - const { publicKey: publicKeyraw, secretKey: secretKey } = solanaWeb3.Keypair.generate(); - // const {publicKey, secretKey} = nacl.sign.keyPair.fromSecretKey( - // new Uint8Array(JSON.parse(fs.readFileSync("./test_wallet.json", 'utf-8'))) - // ); - const publicKey = publicKeyraw.toBase58(); - console.log('publicKey', publicKey); - const payload = { - data: { + const keyPair = nacl.sign.keyPair(); + const publicKey = keyPair.publicKey; + const privateKey = keyPair.secretKey; + + const data = { uuid: uuidv4(), linktree: [ { @@ -36,15 +33,25 @@ try { }, ], timestamp: Date.now(), - }, - publicKey: publicKey, }; + const messageUint8Array = new Uint8Array( + Buffer.from(JSON.stringify(data)), + ); + const signedMessage = nacl.sign(messageUint8Array, privateKey); + const signature = signedMessage.slice(0, nacl.sign.signatureLength); + const payload = { + data, + publicKey: bs58.encode(publicKey), + signature: bs58.encode(signature), + }; + + // Check payload // console.log(payload); await axios - .post('http://localhost:8080/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/linktree', {payload}) + .post('https://k2-tasknet-ports-2.koii.live/task/HjWJmb2gcwwm99VhyNVJZir3ToAJTfUB4j7buWnMMUEP/linktree', {payload}) .then((e) => { if (e.status != 200) { console.log(e); From 18f7716d47308909e745dd36e6ed537a2b936ccf Mon Sep 17 00:00:00 2001 From: soma Date: Fri, 14 Apr 2023 18:39:20 -0300 Subject: [PATCH 58/61] debug code --- dbSharing.js | 20 ++++++++++++-------- init.js | 2 +- linktree_validate.js | 2 +- routes.js | 12 ++++++++---- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/dbSharing.js b/dbSharing.js index e2853182..f9ed4656 100644 --- a/dbSharing.js +++ b/dbSharing.js @@ -1,6 +1,9 @@ const { app, MAIN_ACCOUNT_PUBKEY, SERVICE_URL, TASK_ID } = require("./init"); const {default: axios} = require('axios'); const db = require('./db_model'); +const nacl = require('tweetnacl'); +const bs58 = require('bs58'); + const share = async () => { try { @@ -34,7 +37,7 @@ const share = async () => { // it will be cleaner to focus on one pubkey, and compare with many nodes (maybe 3 nodes) for (let url of nodeUrlList) { console.log(url); - const res = await axios.get(`${url}/task/${TASK_ID}/get-all-linktrees`); + const res = await axios.get(`${url}/task/${TASK_ID}/linktree/all`); if (res.status != 200) { console.error('ERROR', res.status); continue; @@ -59,13 +62,14 @@ const share = async () => { // TODO3 - whenever a linktree is found on this node, it should be compared to the one in the db and updated if the timestamp is newer - if (!payload || payload.length == 0) continue; - for (let linkTreePayload in payload) { - const isVerified = nacl.sign.detached.verify( - new TextEncoder().encode(JSON.stringify(linkTreePayload.data)), - bs58.decode(linkTreePayload.signature), - bs58.decode(linkTreePayload.publicKey) - ); + if (!payload || payload.length == 0) continue; + for (let i = 0; i < payload.length; i++) { + const value = payload[i].value; + const isVerified = nacl.sign.detached.verify( + new TextEncoder().encode(JSON.stringify(value.data)), + bs58.decode(value.signature), + bs58.decode(value.publicKey) + ); if (!isVerified) { console.warn(`${url} is not able to verify the signature`); continue; diff --git a/init.js b/init.js index d54bbfda..681f7875 100644 --- a/init.js +++ b/init.js @@ -13,7 +13,7 @@ const app = express(); console.log('SETTING UP EXPRESS'); app.get('/', (req, res) => { - res.send('Hello World!'); + res.send('Linktree task running'); }); app.listen(EXPRESS_PORT, () => { diff --git a/linktree_validate.js b/linktree_validate.js index 03838ce5..9ad740df 100644 --- a/linktree_validate.js +++ b/linktree_validate.js @@ -38,7 +38,7 @@ async function verifyLinktrees(proofs_list_object) { let publicKey = proofs.value[0].publicKey // call other nodes to get the node list - // * const nodeUrlList = await namespaceWrapper.getNodes(); + const nodeUrlList = await namespaceWrapper.getNodes(); // TEST hardcode the node list // const nodeUrlList = [ diff --git a/routes.js b/routes.js index 651ce964..16ca2774 100644 --- a/routes.js +++ b/routes.js @@ -40,8 +40,8 @@ router.use((req, res, next) => { } console.log('Check Proof:', proof); // use fs to write the linktree and proof to a file - if (!fs.existsSync('/Linktree')) fs.mkdirSync('/Linktree'); - fs.writeFileSync("/Linktree/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); + if (!fs.existsSync('./Linktree')) fs.mkdirSync('./Linktree'); + fs.writeFileSync("./Linktree/" + `linktree_${pubkey}.json`, JSON.stringify(linktree)); // fs.writeFileSync('proof.json', JSON.stringify(proof)); await db.setLinktree(pubkey, linktree); @@ -73,14 +73,14 @@ router.use((req, res, next) => { return res.status(200).send(linktree); }); router.get('/linktree/all', async (req, res) => { - linktree = await db.getAllLinktree() || '[]'; + linktree = await db.getAllLinktrees() || '[]'; return res.status(200).send(linktree); } ); router.get('/linktree/list', async (req, res) => { - linktree = await db.getAllLinktree(true) || '[]'; + linktree = await db.getAllLinktrees(true) || '[]'; return res.status(200).send(linktree); } ); @@ -118,6 +118,10 @@ router.use((req, res, next) => { }); return res.status(200).send(authlist); }); + router.get('/nodeurl', async (req, res) => { + const nodeUrlList = await namespaceWrapper.getNodes(); + return res.status(200).send(nodeUrlList); + }); // router.post('/register-authlist', async (req, res) => { // const pubkey = req.body.pubkey; // await db.setAuthList(pubkey); From 0b457578f0fc796acfa28624c04c58be7cca9797 Mon Sep 17 00:00:00 2001 From: soma Date: Mon, 17 Apr 2023 18:17:57 -0300 Subject: [PATCH 59/61] update distribution list --- .env-local | 3 - README.md | 2 +- coreLogic.js | 57 ++++++++++++++++--- namespaceWrapper.js | 96 ++++++++++++++++++-------------- routes.js | 1 + test/unitTest.js | 130 +++++++++++++++++++++++++------------------- 6 files changed, 179 insertions(+), 110 deletions(-) diff --git a/.env-local b/.env-local index 0a19a361..497f5ff9 100644 --- a/.env-local +++ b/.env-local @@ -42,9 +42,6 @@ TASK_STAKES=10 # specific variables that are needed for the task to perform it's job. Some examples: # Secrets must follow this convention for task to be able to use it (SECRET_) SECRET_WEB3_STORAGE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY0ODYxMzAzOTdDNTY1QzlDYTRCOTUzZTA2RWQ4NUI4MGRBQzRkYTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NjYzNjU1OTk5MDMsIm5hbWUiOiJTb21hIn0.TU-KUFS9vjI9blN5dx6VsLLuIjJnpjPrxDHBvjXQUxw" -TWITTER_CONSUMER_KEY="" -TWITTER_CONSUMER_SECRET="" -TWITTER_BEARER_TOKEN="" diff --git a/README.md b/README.md index d862c15e..fd018136 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ There are in total 9 functions in CoreLogic which the you can modify according t 9. *auditDistribution()* - makes call to namespace of task-node to raise an audit against the distribution list if the validation fails. # Testing and Deploying -Before you begin this process, be sure to check your code and write unit tests wherever possible to verify individual core logic functions. Testing using the docker container should be mostly used for consensus flows, as it will take longer to rebuild and re-deploy the docker container. +Before you begin this process, be sure to check your code and write unit tests wherever possible to verify individual core logic functions. `unitTest.js` file helps you to mock task state parameters that are required in core logic function and test it. Testing using the docker container should be mostly used for consensus flows, as it will take longer to rebuild and re-deploy the docker container. ## Build Before deploying a task, you'll need to build it into a single file executable by running diff --git a/coreLogic.js b/coreLogic.js index c4095ae7..7555473a 100644 --- a/coreLogic.js +++ b/coreLogic.js @@ -55,6 +55,7 @@ class CoreLogic { // The logic to generate the distribution list here let distributionList = {}; + let distributionCandidates = []; let taskAccountDataJSON = await namespaceWrapper.getTaskState(); if (taskAccountDataJSON == null) taskAccountDataJSON = _dummyTaskState; @@ -75,6 +76,8 @@ class CoreLogic { const values = Object.values(submissions); const size = values.length; console.log('Submissions from last round: ', keys, values, size); + + // Logic for slashing the stake of the candidate who has been audited and found to be false for (let i = 0; i < size; i++) { const candidatePublicKey = keys[i]; if ( @@ -82,21 +85,59 @@ class CoreLogic { submissions_audit_trigger[candidatePublicKey] ) { console.log( - submissions_audit_trigger[candidatePublicKey].votes, 'distributions_audit_trigger votes ', + submissions_audit_trigger[candidatePublicKey].votes, ); const votes = submissions_audit_trigger[candidatePublicKey].votes; - let numOfVotes = 0; - for (let index = 0; index < votes.length; index++) { - if (votes[index].is_valid) numOfVotes++; - else numOfVotes--; + if (votes.length === 0) { + // slash 70% of the stake as still the audit is triggered but no votes are casted + // Note that the votes are on the basis of the submission value + // to do so we need to fetch the stakes of the candidate from the task state + const stake_list = taskAccountDataJSON.stake_list; + const candidateStake = stake_list[candidatePublicKey]; + const slashedStake = candidateStake * 0.7; + distributionList[candidatePublicKey] = -slashedStake; + console.log('Candidate Stake', candidateStake); + } else { + let numOfVotes = 0; + for (let index = 0; index < votes.length; index++) { + if (votes[index].is_valid) numOfVotes++; + else numOfVotes--; + } + + if (numOfVotes < 0) { + // slash 70% of the stake as the number of false votes are more than the number of true votes + // Note that the votes are on the basis of the submission value + // to do so we need to fetch the stakes of the candidate from the task state + const stake_list = taskAccountDataJSON.stake_list; + const candidateStake = stake_list[candidatePublicKey]; + const slashedStake = candidateStake * 0.7; + distributionList[candidatePublicKey] = -slashedStake; + console.log('Candidate Stake', candidateStake); + } + + if (numOfVotes > 0) { + distributionCandidates.push(candidatePublicKey); + } + } + } - if (numOfVotes < 0) continue; - } - distributionList[candidatePublicKey] = 1; } } + + // now distribute the rewards based on the valid submissions + // Here it is assumed that all the nodes doing valid submission gets the same reward + + const reward = + taskAccountDataJSON.bounty_amount_per_round / + distributionCandidates.length; + console.log('REWARD RECEIVED BY EACH NODE', reward); + for (let i = 0; i < distributionCandidates.length; i++) { + distributionList[distributionCandidates[i]] = reward; + } + console.log('Distribution List', distributionList); + return distributionList; } catch (err) { console.log('ERROR IN GENERATING DISTRIBUTION LIST', err); diff --git a/namespaceWrapper.js b/namespaceWrapper.js index a1597e10..cad78176 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -2,7 +2,7 @@ const { default: axios } = require('axios'); const levelup = require('levelup'); const leveldown = require('leveldown'); const BASE_ROOT_URL = 'http://localhost:8080/namespace-wrapper'; -const { TASK_ID, MAIN_ACCOUNT_PUBKEY, SECRET_KEY } = require('./init'); +const { TASK_ID, SECRET_KEY } = require('./init'); const { Connection, PublicKey, Keypair } = require('@_koi/web3.js'); const taskNodeAdministered = !!TASK_ID; class NamespaceWrapper { @@ -57,31 +57,45 @@ class NamespaceWrapper { * @param {*} path Path for the express call * @param {...any} args Remaining parameters for the FS call */ - async fs(method, path, ...args) { - return await genericHandler('fs', method, path, ...args); - } - async fsStaking(method, path, ...args) { - return await genericHandler('fsStaking', method, path, ...args); - } - async fsWriteStream(imagepath) { - return await genericHandler('fsWriteStream', imagepath); - } - async fsReadStream(imagepath) { - return await genericHandler('fsReadStream', imagepath); - } + // async fs(method, path, ...args) { + // return await genericHandler('fs', method, path, ...args); + // } + // async fsStaking(method, path, ...args) { + // return await genericHandler('fsStaking', method, path, ...args); + // } + // async fsWriteStream(imagepath) { + // return await genericHandler('fsWriteStream', imagepath); + // } + // async fsReadStream(imagepath) { + // return await genericHandler('fsReadStream', imagepath); + // } async getSlot() { return await genericHandler('getCurrentSlot'); } - async submissionOnChain(submitterKeypair, submission) { - return await genericHandler( - 'submissionOnChain', - submitterKeypair, - submission, - ); + async payloadSigning(body) { + return await genericHandler('signData', body); } + + /** + * Namespace wrapper of storeGetAsync + * @param {string} signedMessage // Path to get + */ + + async verifySignature(signedMessage, pubKey) { + return await genericHandler('verifySignedData', signedMessage, pubKey); + } + + // async submissionOnChain(submitterKeypair, submission) { + // return await genericHandler( + // 'submissionOnChain', + // submitterKeypair, + // submission, + // ); + // } + async stakeOnChain( taskStateInfoPublicKey, stakingAccKeypair, @@ -126,28 +140,28 @@ class NamespaceWrapper { * @param {transaction} path // Endpoint path appended to namespace * @param {Function} callback // Callback function on traffic receive */ - async sendAndConfirmTransactionWrapper(transaction, signers) { - const blockhash = (await connection.getRecentBlockhash('finalized')) - .blockhash; - transaction.recentBlockhash = blockhash; - transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); - return await genericHandler( - 'sendAndConfirmTransactionWrapper', - transaction.serialize({ - requireAllSignatures: false, - verifySignatures: false, - }), - signers, - ); - } + // async sendAndConfirmTransactionWrapper(transaction, signers) { + // const blockhash = (await connection.getRecentBlockhash('finalized')) + // .blockhash; + // transaction.recentBlockhash = blockhash; + // transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); + // return await genericHandler( + // 'sendAndConfirmTransactionWrapper', + // transaction.serialize({ + // requireAllSignatures: false, + // verifySignatures: false, + // }), + // signers, + // ); + // } - async signArweave(transaction) { - let tx = await genericHandler('signArweave', transaction.toJSON()); - return arweave.transactions.fromRaw(tx); - } - async signEth(transaction) { - return await genericHandler('signEth', transaction); - } + // async signArweave(transaction) { + // let tx = await genericHandler('signArweave', transaction.toJSON()); + // return arweave.transactions.fromRaw(tx); + // } + // async signEth(transaction) { + // return await genericHandler('signEth', transaction); + // } async getTaskState() { const response = await genericHandler('getTaskState'); if (response.error) { @@ -247,7 +261,7 @@ class NamespaceWrapper { } async validateAndVoteOnNodes(validate, round) { - // await this.checkVoteStatus(); + console.log('******/ IN VOTING /******'); const taskAccountDataJSON = await this.getTaskState(); diff --git a/routes.js b/routes.js index 16ca2774..bda64104 100644 --- a/routes.js +++ b/routes.js @@ -57,6 +57,7 @@ router.use((req, res, next) => { return res.status(200).send({message: 'Proof and linktree registered successfully'}); }); + router.get("/logs", async (req, res) => { const logs = fs.readFileSync("./namespace/logs.txt", "utf8") res.status(200).send(logs); diff --git a/test/unitTest.js b/test/unitTest.js index ee25c75a..4db6affd 100644 --- a/test/unitTest.js +++ b/test/unitTest.js @@ -7,66 +7,82 @@ async function test_coreLogic() { // const submission = await coreLogic.fetchSubmission(); // TEST hardcode the submission - let submission= "bafybeiaipp6owksgigqx73putgxr7qfiuly32isubrqjc4meqwty6xu5xa" - console.log('SUBMISSION', submission); + // let submission= "bafybeiaipp6owksgigqx73putgxr7qfiuly32isubrqjc4meqwty6xu5xa" + // console.log('SUBMISSION', submission); - const vote = await coreLogic.validateNode(submission, 1000); + // const vote = await coreLogic.validateNode(submission, 1000); + +let vote = true console.log('VOTE', vote); - // let vote = true; - // const _dummyTaskState = { - // submissions: { - // 1: { - // '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { - // submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', - // slot: 1889700, - // round: 1, - // }, - // '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { - // submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cc', - // slot: 1890002, - // round: 1, - // }, - // }, - // }, - // submissions_audit_trigger: { - // "1":{ // round number - // "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL":{ // Data Submitter (send data to K2) - // "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH", // Audit trigger - // "slot":1890002, - // "votes":[{ - // "is_valid": false, // Submission is invalid(Slashed) - // "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter - // "slot":1890003 - // }] - // }, - // "2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH":{ // Data Submitter (send data to K2) - // "trigger_by":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL", // Audit trigger - // "slot":1890002, - // "votes":[{ - // "is_valid": false, // Submission is invalid(Slashed) - // "voter":"2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ", // Voter - // "slot":1890003 - // }] - // } - // } - // }, - // }; - // if (vote == true) { - // console.log('Submission is valid, generating distribution list'); - // const distributionList = await coreLogic.generateDistributionList( - // 1, - // _dummyTaskState, - // ); - // await coreLogic.validateDistribution( - // null, - // 1, - // distributionList, - // _dummyTaskState, - // ); - // } else { - // console.log('Submission is invalid, not generating distribution list'); - // } + + const _dummyTaskState = { + stake_list: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': 20000000000, + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': 10000000000, + }, + bounty_amount_per_round: 1000000000, + + submissions: { + 1: { + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cd', + slot: 1889700, + round: 1, + }, + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { + submission_value: '8164bb07ee54172a184bf35f267bc3f0052a90cc', + slot: 1890002, + round: 1, + }, + }, + }, + submissions_audit_trigger: { + 1: { + // round number + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL': { + // Data Submitter (send data to K2) + trigger_by: '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH', // Audit trigger + slot: 1890002, + votes: [ + { + is_valid: false, // Submission is invalid(Slashed) + voter: '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ', // Voter + slot: 1890003, + }, + ], + + }, + '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHH': { + // Data Submitter (send data to K2) + trigger_by: '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHL', // Audit trigger + slot: 1890002, + votes: [ + { + is_valid: true, // Submission is valid + voter: '2NstaKU4kif7uytmS2PQi9P5M5bDLYSF2dhUNFhJbxHZ', // Voter + slot: 1890003, + + }] + } + } + }, + }; + if (vote == true) { + console.log('Submission is valid, generating distribution list'); + const distributionList = await coreLogic.generateDistributionList( + 1, + _dummyTaskState, + ); + await coreLogic.validateDistribution( + null, + 1, + distributionList, + _dummyTaskState, + ); + } else { + console.log('Submission is invalid, not generating distribution list'); + } } test_coreLogic(); From df9acce6aaead23e7510c561fedc7cccf28c1aa1 Mon Sep 17 00:00:00 2001 From: soma Date: Tue, 18 Apr 2023 14:06:15 -0300 Subject: [PATCH 60/61] uncommon function --- namespaceWrapper.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/namespaceWrapper.js b/namespaceWrapper.js index cad78176..54d6b145 100644 --- a/namespaceWrapper.js +++ b/namespaceWrapper.js @@ -140,20 +140,20 @@ class NamespaceWrapper { * @param {transaction} path // Endpoint path appended to namespace * @param {Function} callback // Callback function on traffic receive */ - // async sendAndConfirmTransactionWrapper(transaction, signers) { - // const blockhash = (await connection.getRecentBlockhash('finalized')) - // .blockhash; - // transaction.recentBlockhash = blockhash; - // transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); - // return await genericHandler( - // 'sendAndConfirmTransactionWrapper', - // transaction.serialize({ - // requireAllSignatures: false, - // verifySignatures: false, - // }), - // signers, - // ); - // } + async sendAndConfirmTransactionWrapper(transaction, signers) { + const blockhash = (await connection.getRecentBlockhash('finalized')) + .blockhash; + transaction.recentBlockhash = blockhash; + transaction.feePayer = new PublicKey(MAIN_ACCOUNT_PUBKEY); + return await genericHandler( + 'sendAndConfirmTransactionWrapper', + transaction.serialize({ + requireAllSignatures: false, + verifySignatures: false, + }), + signers, + ); + } // async signArweave(transaction) { // let tx = await genericHandler('signArweave', transaction.toJSON()); From ebb8d6bcad8c10dae0316c3687def958bd71333c Mon Sep 17 00:00:00 2001 From: saim Date: Wed, 19 Apr 2023 11:11:25 -0300 Subject: [PATCH 61/61] updated the readme --- README.md | 88 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index fd018136..636f84bb 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,88 @@ -# K2-Task-Template +# KOII LINKTREE TASK + +LinkTree is a koii task that creates a LinkTree page. You can add links to your favorite websites or social media profiles on your page. + Tasks run following a periodic structure of 'rounds': -![Screenshot_20230307-091958](https://user-images.githubusercontent.com/66934242/223565192-3ecce9c6-0f9a-4a58-8b02-2db19c61141f.png) +executeTask => { + 1. Do the work + 2. Audit the work of other nodes + 3. Pay the rewards or slash stake +} -Each round is set by a specific time period, and nodes participate by uploading data to IPFS, posting CIDs to the K2 settlement layer, and sending messages across REST APIs and WebSockets. -For more information on how the Task Flow works, check out [the runtime environment docs](https://docs.koii.network/microservices-and-tasks/what-are-tasks/gradual-consensus). +## The structure of the LinkTree task -If this is your first time writing a Koii Task, you might want to use the [task organizer](https://www.figma.com/community/file/1220194939977550205/Task-Outline). +## coreLogic.js -## Requirements - - [Node >=16.0.0](https://nodejs.org) - - [Docker compose](https://docs.docker.com/compose/install/docker) +The most important file in any koii task is the coreLogic.js file. It is provided in the task template and is where most of the functionality will be coded. -## What's in the template? -`index.js` is the hub of your app, and ties together the other pieces. This will be the entrypoint when your task runs on Task Nodes +In the Linktree task’s coreLogic, the first function is the task(). This function calls the linktree_task function from the linktree_task.js file. + + ## Linktree_task => this function fetches proofs from the local database, creates a submission object for those proofs, and uploads it to IPFS. IPFS gives back a reference CID of the submission, which the function returns. -`NamespaceWrappers.js` contains the interfaces to make API calls to the core of the task-node. It contains all the necessary functions required to submit and audit the work, as well as the distribution lists +The task function gets the CID from the linktree_task and stores it to the levelDB. -`coreLogic.js` is where you'll define your task, audit, and distribution logic, and controls the majority of task functionality. You can of course break out separate features into sub-files and import them into the core logic before web-packing. +The fetchSubmission function can be used to get the CID of the submission back. -## Runtime Options -There are two ways to run your task when doing development: +The generateDistributionList function generates a distribution list for rewards based on submissions made by the nodes. It takes all the votes that the nodes have made on the submission and if the false votes are higher than the true votes, this function slashes 70% of the stake of the task submitter as a penalty. If the true votes are higher than the submission is valid and it distributes the rewards. -1. With Timer ON (see .env-local)- When the timer is ON, IPC calls are made by calculating the average time slots of all the task running your node. +The submitDistributionList function submits the distribution list generated by the "generateDistributionList" function. -2. With Timer OFF - This allows you to do manual calls to K2 and disables the triggers for round managemnt on K2. Transactions are only accepted during the correct period. Guide for manual calls is in index.js +The validateNode function is called when a node is selected to validate the submission value. It calls the linktree_validate function from the linktree_validate file. + + ## Linktree_validate.js => this file verifies the validity of a Linktree CID submission. + + +The validateDistribution function validates a distribution list submitted by a node for a specific round. + +The submitTask function submits the address with a distribution list to K2. -# Modifying CoreLogic.js -Task nodes will trigger a set of predefined functions during operation. +The auditTask function checks a submission in a specific round and confirms that the task is valid -There are in total 9 functions in CoreLogic which the you can modify according to your needs: +The auditDistribution checks the distribution list is valid for a specific round -1. *task()* - The logic for what your task should do goes here. There is a window in round that is dedicated to do work. The code in task is executed in that window. +## Db_model.js -2. *fetchSubmission()* - After completing the task , the results/work will be stored somewhere like on IPFS or local levelDB. This function is the place where you can write the logic to fetch that work. It is called in submitTask() function which does the actual submission on K2. +This file contains all the functions required for storing and retrieving data related to the linktree and node proofs used in the Linktree CID Validation task as well as the authorized users list. -3. *submitTask()* - It makes the call to namespace function of task-node using the wrapper. +getLinktree: retrieves the linktree by it’s public key +setLinktree: sets the linktree associated with the given public key +getAllLinktrees: retrieves all link trees stored in the database +getProofs: retrieves the proofs associated with a given public key +setProofs: sets the proofs associated with a given public key +getAllProofs: retrieves all proofs stored in the database +getNodeProofCid: retrieves the CID associated with a given round of node proofs +setNodeProofCid: sets the CID associated with a given round of node proofs +getAllNodeProofCids: retrieves all CIDs associated with node proofs stored in the database +getAuthList: retrieves the list of the authorized users +setAuthList: sets the authorized list +getAllAuthLists: retrieves all authorized lists stored in the database +namespaceWrapper.js +contains the interfaces to make API calls to the core of the task-node. It contains all the necessary functions required to submit and audit the work, as well as the distribution lists. -4. *generateDistributionList()* - You have full freedom to prepare your reward distributions as you like and the logic for that goes here. We have provided a sample logic that rewards 1 KOII to all the needs who did the correct submission for that round. This function is called in submitDistributionList() +## Index.js -5. *submitDistributionList()* - makes call to the namesapce function of task-node to upload the list and on succesful upload does the transaction to update the state. +This is the entry point of the task. It sets the round timers and ties together all the other parts of the task -6. *validateNode()* - this function is called to verify the submission value, so based on the value received from the task-state we can vote on the submission. +## The test folder -7. *validateDistribution()* - The logic to validate the distribution list goes here and the function will receive the distribution list submitted form task-state. +This folder contains all the test files for the linktree task. -8. *auditTask()* - makes call to namespace of task-node to raise an audit against the submission value if the validation fails. +## Router.js + +This file contains a set of API endpoints for the linktree. + + +## Runtime Options +There are two ways to run your task when doing development: + +1. With Timer ON (see .env-local)- When the timer is ON, IPC calls are made by calculating the average time slots of all the task running your node. + +2. With Timer OFF - This allows you to do manual calls to K2 and disables the triggers for round managemnt on K2. Transactions are only accepted during the correct period. Guide for manual calls is in index.js -9. *auditDistribution()* - makes call to namespace of task-node to raise an audit against the distribution list if the validation fails. # Testing and Deploying Before you begin this process, be sure to check your code and write unit tests wherever possible to verify individual core logic functions. `unitTest.js` file helps you to mock task state parameters that are required in core logic function and test it. Testing using the docker container should be mostly used for consensus flows, as it will take longer to rebuild and re-deploy the docker container.