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/44'); 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; let winner_points; for (let i = 0; i < arrPoints.length; i++) { sum2 = sum2.plus(arrPoints[i].points); if (random.lte(sum2)) { winner_address = arrPoints[i].address; winner_points = arrPoints[i].points.toString(); 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; let balance_winner_gbyte; 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; balance_winner_gbyte = rows1[i].balance / 1000000000; break; } } // winner by balances was drawn first time on 2018-12-28 if (snapshot.draw.date < '2018-12-28') { balance_winner_address = null; balance_winner_gbyte = null; } return { "King of Goldfish": { winner: snapshot.draw.winner_address, valid: snapshot.draw.winner_address === winner_address, points: winner_points }, "Prince of Whale": { winner: snapshot.draw.balance_winner_address, valid: snapshot.draw.balance_winner_address === balance_winner_address, balance: balance_winner_gbyte } }; }