Obyte draw airdrop - proof of randomness
const crypto = require('crypto');
const fetch = require('node-fetch');
const BigNumber = require('bignumber.js');
BigNumber.config({DECIMAL_PLACES: 30, EXPONENTIAL_AT: [-1e+9, 1e9]});
console.log('downloading snapshot...');
try {
const response = await fetch('http://draw.obyte.org/snapshot/4');
const json = await response.json();
return await validateWinner(json);
}
catch (error) {
console.error(error);
}
async function validateWinner(snapshot) {
// bitcoin_hash is the hash (in hex) of the latest Bitcoin block
// arrPoints is array of points of all addresses ordered by address [{address: "...", points: 1234}, ...]
// rows1 is array of balances of all addresses ordered by address [{address: "...", balance: 1234}, ...]
// sum_points is the sum of all points
// sum_balances is the sum of all balances
console.log('validating snapshot '+ snapshot.draw.date);
let bitcoin_hash = snapshot.draw.bitcoin_hash;
let arrPoints = [];
let rows1 = snapshot.data;
let sum_points = new BigNumber(0);
let sum_balances = 0;
for (let i = 0; i < rows1.length; i++) {
let row = rows1[i];
let points = new BigNumber(row.points);
if (points.gt(0)) {
arrPoints.push({address: row.address, points});
sum_points = sum_points.plus(points);
}
sum_balances += row.balance;
}
if (sum_points.eq(new BigNumber(0)))
return;
// 1. winner by points
let hash = crypto.createHash('sha256').update(bitcoin_hash).digest('hex');
let number = new BigNumber(hash, 16);
let random = (number.div(new BigNumber(2).pow(256))).times(sum_points);
let sum2 = new BigNumber(0);
let winner_address;
for (let i = 0; i < arrPoints.length; i++) {
sum2 = sum2.plus(arrPoints[i].points);
if (random.lte(sum2)) {
winner_address = arrPoints[i].address;
break;
}
}
// 2. winner by balances
let bal_hash = crypto.createHash('sha256').update(hash).digest('hex');
let bal_number = new BigNumber(bal_hash, 16);
let bal_random = (bal_number.div(new BigNumber(2).pow(256))).times(sum_balances);
// winner by balances used same random as winner by points until 2019-01-04
if (snapshot.draw.date < '2019-01-04') {
bal_random = (number.div(new BigNumber(2).pow(256))).times(sum_balances);
}
let bal_sum2 = 0;
let balance_winner_address;
for (let i = 0; i < rows1.length; i++) {
bal_sum2 += rows1[i].balance;
if (bal_random.lte(bal_sum2)) {
balance_winner_address = rows1[i].address;
break;
}
}
// winner by balances was drawn first time on 2018-12-28
if (snapshot.draw.date < '2018-12-28') {
balance_winner_address = null;
}
return {
"King of Goldfish": {
winner:snapshot.draw.winner_address,
valid: snapshot.draw.winner_address === winner_address
},
"Prince of Whale": {
winner:snapshot.draw.balance_winner_address,
valid:snapshot.draw.balance_winner_address === balance_winner_address
}
};
}
2 comments