Complete Executable Code

Putting all of the pieces together, this is the full executable in coreLogic.js file:

const puppeteer = require("puppeteer");
const cheerio = require("cheerio");
const { namespaceWrapper } = require("./namespaceWrapper");

class CoreLogic {
  async task() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto("https://www.google.com/doodles");
    let bodyHTML = await page.evaluate(
      () => document.documentElement.outerHTML
    );
    const $ = cheerio.load(bodyHTML);

    let scrapedDoodle = $(".latest-doodle.on")
      .find("div > div > a > img")
      .attr("src");
    if (scrapedDoodle.substring(0, 2) == "//") {
      scrapedDoodle = scrapedDoodle.substring(2, scrapedDoodle.length);
    }

    console.log("SUBMISSION VALUE", scrapedDoodle);
    const stringfy = JSON.stringify(scrapedDoodle);

    // store this work of fetching googleDoodle to levelDB

    try {
      await namespaceWrapper.storeSet("doodle", stringfy);
    } catch (err) {
      console.log("error", err);
    }
  }

  async fetchSubmission() {
    try {
      const scrappedDoodle = JSON.parse(
        await namespaceWrapper.storeGet("doodle")
      );
      console.log("Received Doodle", scrappedDoodle);
      return scrappedDoodle;
    } catch (err) {
      console.log("Error", err);
      return err;
    }
  }

  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 value = await this.fetchSubmission();
      console.log("value", value);
      await namespaceWrapper.checkSubmissionAndUpdateRound(value, roundNumber);
      console.log("after the submission call");
    } catch (error) {
      console.log("error in submission", error);
    }
  }

  async validateNode(submission_value) {
    let vote;
    console.log("SUBMISSION VALUE", submission_value);
    const doodle = submission_value;

    // check the google doodle

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto("https://www.google.com/doodles");
    let bodyHTML = await page.evaluate(
      () => document.documentElement.outerHTML
    );
    const $ = cheerio.load(bodyHTML);

    let scrapedDoodle = $(".latest-doodle.on")
      .find("div > div > a > img")
      .attr("src");
    if (scrapedDoodle.substring(0, 2) == "//") {
      scrapedDoodle = scrapedDoodle.substring(2, scrapedDoodle.length);
    }
    console.log({ scrapedDoodle });

    // vote based on the scrapedDoodle

    try {
      if (scrapedDoodle == doodle) {
        vote = true;
      } else {
        vote = false;
      }
    } catch (e) {
      console.error(e);
      vote = false;
    }
    browser.close();
    return vote;
  }

  async auditTask(roundNumber) {
    console.log("auditTask called with round", roundNumber);
    console.log(
      await namespaceWrapper.getSlot(),
      "current slot while calling auditTask"
    );
    await namespaceWrapper.validateAndVoteOnNodes(
      this.validateNode,
      roundNumber
    );
  }

  async generateDistributionList(round) {
    console.log("GenerateDistributionList called");
    console.log("I am selected node");

    let distributionList = {};
    const taskAccountDataJSON = await namespaceWrapper.getTaskState();
    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;
        }
        distributionList[candidatePublicKey] = 1;
      }
    }
    console.log("Distribution List", distributionList);
    return distributionList;
  }

  async submitDistributionList(round) {
    console.log("SubmitDistributionList called");

    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);
    }
  }

  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;
  }

  validateDistribution = async (distributionListSubmitter, round) => {
    try {
      round = 75;
      console.log("Distribution list Submitter", distributionListSubmitter);
      const fetchedDistributionList = JSON.parse(
        await namespaceWrapper.getDistributionList(
          distributionListSubmitter,
          round
        )
      );
      console.log("FETCHED DISTRIBUTION LIST", fetchedDistributionList);
      const generateDistributionList = await this.generateDistributionList(
        round
      );

      // compare distribution list

      const parsed = JSON.parse(fetchedDistributionList);
      const result = await this.shallowEqual(parsed, generateDistributionList);
      console.log("RESULT", result);
      return result;
    } catch (err) {
      console.log("ERROR IN CATCH", err);
      return false;
    }
  };

  async auditDistribution(roundNumber) {
    console.log("auditDistribution called with round", roundNumber);
    await namespaceWrapper.validateAndVoteOnDistributionList(
      this.validateDistribution,
      75
    );
  }
}

const coreLogic = new CoreLogic();

module.exports = {
  coreLogic,
};

Follow the instructions here to register this new task.

Last updated