Validate Node
The validate node function is passed to a helper function called validateAndVoteOnNodes
where it will be run for each node that has submitted. The validate node function will return true if the node is valid. The validate node function will be given the following params to validate a node:
- K2 Submission data
- Node Service URL (if present)
Types of Audits
- Checking signed and uploaded data on IPFS using a CID submitted to K2
- Checking the status of API endpoints on the node
- Checking proof stored on nodes provided API endpoint
Example
One of the most common methods of validating other nodes is calling the other nodes "/proofs" endpoint to validate the data that they are providing. This is a simplified example of how an API endpoint validation would work:
// Executable File
validateNode(node) {
axios({
method: 'get',
url: `${node.url}/proofs`
}).then(async (response) => {
if (
response.data &&
response.data == "EXAMPLE CORRECT DATA"
) {
return true;
} else {
return false;
}
}).catch(err => {
return false;
})
}
// Abbreviated executable function
async function execute() {
cronArray.push(
cron.schedule(
'*/1 * * * *',
() => { namespace.validateAndVoteOnNodes(validateNode) }
));
return cronArray;
}
For reference, this is what the validateAndVoteOnNodes
function does
// validateAndVoteOnNodes found in namespaced helper file
async validateAndVoteOnNodes(validate: (node: any) => boolean) {
await this.checkVoteStatus();
const taskAccountDataJSON = await this.getTaskState();
const current_round = taskAccountDataJSON.current_round;
const expected_round = current_round - 1;
const status = taskAccountDataJSON.status;
const stat_val = Object.keys(status)[0];
const voteStatus = await this.redisGet('voteStatus');
if (!process.env.SERVICE_URL) console.warn('SERVICE_URL not set');
const nodes = await getNodes(process.env.SERVICE_URL || '');
if (
voteStatus == 'true' &&
stat_val == 'Voting' &&
Object.keys(taskAccountDataJSON.submissions).length > 0
) {
const submissions = {};
for (const id in taskAccountDataJSON.submissions) {
console.log(
'round - expected',
taskAccountDataJSON.submissions[id].round,
expected_round,
);
if (taskAccountDataJSON.submissions[id].round == expected_round) {
submissions[id] = taskAccountDataJSON.submissions[id];
}
}
const values: any = Object.values(submissions);
const keys = Object.keys(submissions);
const size = values.length;
for (let i = 0; i < size; i++) {
const candidatePublicKey = keys[i];
const candidateKeyPairPublicKey = new PublicKey(keys[i]);
if (candidatePublicKey == this.submitterPubkey) {
console.log('YOU CANNOT VOTE ON YOUR OWN SUBMISSIONS');
} else {
// LOGIC for voting function
const node = nodes.find((e: any) => e.submitterPubkey == keys[i]);
const nodeData = node
? {
url: node.data.url,
...values[i],
}
: values[i];
const isValid = validate(nodeData);
console.log(`Voting ${isValid} to ${candidatePublicKey}`);
try {
const response = await this.voteOnChain(
this.connection,
this.taskStateInfoPublicKey,
candidateKeyPairPublicKey,
this.submitterAccountKeyPair,
isValid,
);
} catch (error) {
console.warn('ERROR FROM VOTING FUNCTION', error);
}
}
}