index.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. const express = require('express')
  2. const app = express()
  3. const port = 9700
  4. const web3operatorAddress = "http://vps.playpoolstudios.com:2015/"
  5. const apiAddress = "https://vps.playpoolstudios.com/metahunt/api/"
  6. app.get('/', (req, res) => {
  7. res.send('Validator is validating')
  8. })
  9. app.listen(port, () => {
  10. console.log(`Mhunt Validator is listening on port ${port}`)
  11. })
  12. app.get('/validateSession', async (req, res) => {
  13. const { tournamentId, address } = req.query;
  14. if (!tournamentId || !address) { res.send("invalid params"); return; }
  15. let tournament = GetTournamentById(tournamentId);
  16. if (tournament == null) {
  17. await CheckForStartedTourneys();
  18. tournament = GetTournamentById(tournamentId);
  19. }
  20. if (tournament == null) {
  21. console.log(`tourney id:${tournamentId} is not available`);
  22. //res.send("This tournament is not either started or valid");
  23. // return;
  24. }
  25. tournament.displayDetails();
  26. const found = tournament.participents.some(participant => participant == address);
  27. if (found) {
  28. return res.send("0");
  29. } else {
  30. return res.send("-1");
  31. }
  32. })
  33. app.post('/updateBlock', async (req, res) => {
  34. const jsonData = req.body;
  35. const tournamentBlock = new TournamentBlockData(jsonData);
  36. tournamentBlocks.push(tournamentBlock);
  37. console.log(tournamentBlocks);
  38. res.sendStatus(200);
  39. });
  40. /* ------------------------------------------------------------------------------- */
  41. let tournamentsList ;
  42. let startedTournaments;
  43. let tournamentBlocks = [];
  44. /* ------------------------------------------------------------------------------- */
  45. CheckForStartedTourneys();
  46. setInterval(async () => {
  47. CheckForStartedTourneys();
  48. }, 60000)
  49. async function CheckForStartedTourneys() {
  50. const tournamentsResponse = await fetch(apiAddress + "get_tournaments_raw.php");
  51. const tournaments = await tournamentsResponse.json();
  52. tournamentsList = [];
  53. startedTournaments = [];
  54. const now = new Date();
  55. const tenMinutesAgo = new Date(now.getTime() - 10 * 60000); // 10 minutes ago from now
  56. tournaments.forEach(async tournament => {
  57. const tournamentDate = new Date(tournament.start_date); // Converts the string date to a Date object
  58. // Create a new TournamentData instance using the tournament JSON data
  59. const newTournament = new TournamentData(
  60. tournament.id,
  61. tournament.name,
  62. tournament.start_date,
  63. tournament.game_mode,
  64. tournament.reward,
  65. tournament.php_reward,
  66. tournament.is_test,
  67. tournament.ticket_count,
  68. tournament.owner_id
  69. );
  70. if (tournamentDate >= tenMinutesAgo && tournamentDate <= now || true) {
  71. console.log(`Tournament "${tournament.name}" started within the last 10 minutes.`);
  72. const participentsUrl = web3operatorAddress + "getTournamentParticipants?id=" + newTournament.id;
  73. const participentsResponse = await fetch(participentsUrl);
  74. const participentsJson = await participentsResponse.json();
  75. const participents = participentsJson["wallets"].split(',');
  76. try {
  77. participents.forEach(participent => {
  78. newTournament.participents.push(participent);
  79. })
  80. //newTournament.displayDetails();
  81. } catch {
  82. console.log(`tourneyId:${newTournament.id} has no participents. ${JSON.stringify(participents)}`)
  83. }
  84. startedTournaments.push(newTournament);
  85. } else if (tournamentDate > now) {
  86. console.log(`Tournament "${tournament.name}" is yet to come`)
  87. } else {
  88. // console.log(`Tournament "${tournament.name}" is expired`)
  89. }
  90. // newTournament.displayDetails();
  91. // Push the new tournament instance into tournamentsList
  92. tournamentsList.push(newTournament);
  93. });
  94. }
  95. /* ------------------------------------------------------------------------------- */
  96. setInterval(async () => {
  97. ScanBlocks();
  98. }, 60000)
  99. function ScanBlocks(){
  100. for(let i=0; i < tournamentBlocks.length; i++){
  101. let isValid = true;
  102. for(let j=0; j < startedTournaments.length; j++){
  103. if(startedTournaments[j].id == tournamentBlocks[i].tournamentId){
  104. //Found the matching tourney for this block
  105. if(!startedTournaments[j].participents.include(tournamentBlocks[i].owner)){
  106. // isValid=false;
  107. console.log("***Block was sent by non-participent. Allowing this for now.");
  108. }
  109. break;
  110. }
  111. }
  112. }
  113. }
  114. /* ----------------------------------METHODS----------------------------------- */
  115. function GetTournamentById(tournamentId) {
  116. const tournament = startedTournaments.find(tournament => tournament.id == tournamentId);
  117. return tournament;
  118. }
  119. /* ------------------------------------------------------------------------------- */
  120. /* ------------------------------CUSTOM CLASSES------------------------------------ */
  121. class TournamentData {
  122. constructor(id, name, start_date, game_mode, reward, php_reward, is_test, ticket_count, owner_id) {
  123. this.id = id;
  124. this.name = name;
  125. this.start_date = start_date;
  126. this.game_mode = game_mode;
  127. this.reward = reward;
  128. this.php_reward = php_reward;
  129. this.is_test = is_test;
  130. this.ticket_count = ticket_count;
  131. this.owner_id = owner_id;
  132. this.participents = [];
  133. }
  134. // Method to display tournament details
  135. displayDetails() {
  136. console.log(`Tournament ID: ${this.id}`);
  137. console.log(`Name: ${this.name}`);
  138. console.log(`Date: ${this.start_date}`);
  139. console.log(`Game Mode: ${this.game_mode}`);
  140. console.log(`Reward: ${this.reward}`);
  141. console.log(`PHP Reward: ${this.php_reward}`);
  142. console.log(`Test Tournament: ${this.is_test ? "Yes" : "No"}`);
  143. console.log(`Ticket Count: ${this.ticket_count}`);
  144. console.log(`Owner ID: ${this.owner_id}`);
  145. console.log(`Participents: ${this.participents}`);
  146. }
  147. }
  148. // Define a dictionary to store tournament leaderboards after validation
  149. const confirmedLeaderboards = {};
  150. // Function to scan and analyze blocks
  151. function ScanBlocks() {
  152. const blockValidationCounts = {};
  153. // First, validate each block and count valid ones for each tournament
  154. for (let i = 0; i < tournamentBlocks.length; i++) {
  155. let isValid = true;
  156. // Loop through the started tournaments to validate the block
  157. for (let j = 0; j < startedTournaments.length; j++) {
  158. if (startedTournaments[j].id === tournamentBlocks[i].tournamentId) {
  159. // Found the matching tournament for this block
  160. if (!startedTournaments[j].participants.includes(tournamentBlocks[i].owner)) {
  161. console.log("***Block was sent by non-participant. Allowing this for now.");
  162. isValid = false;
  163. break;
  164. }
  165. // Compare blocks with the same tournamentId and minute number
  166. for (let k = 0; k < tournamentBlocks.length; k++) {
  167. if (
  168. k !== i &&
  169. tournamentBlocks[k].tournamentId === tournamentBlocks[i].tournamentId &&
  170. tournamentBlocks[k].minute === tournamentBlocks[i].minute
  171. ) {
  172. // Found another block with the same tournamentId and minute
  173. if (JSON.stringify(tournamentBlocks[k].leaderboard) !== JSON.stringify(tournamentBlocks[i].leaderboard)) {
  174. console.log(`***Mismatch detected in leaderboard for tournament ${tournamentBlocks[i].tournamentId} at minute ${tournamentBlocks[i].minute}`);
  175. isValid = false;
  176. break;
  177. }
  178. }
  179. }
  180. }
  181. }
  182. if (isValid) {
  183. console.log(`Block ${i + 1} is valid.`);
  184. // Track the valid blocks per tournament
  185. const tournamentId = tournamentBlocks[i].tournamentId;
  186. if (!blockValidationCounts[tournamentId]) {
  187. blockValidationCounts[tournamentId] = { count: 0, total: 0 };
  188. }
  189. blockValidationCounts[tournamentId].count++;
  190. } else {
  191. console.log(`Block ${i + 1} is invalid.`);
  192. }
  193. // Track total blocks per tournament for comparison later
  194. const tournamentId = tournamentBlocks[i].tournamentId;
  195. if (!blockValidationCounts[tournamentId]) {
  196. blockValidationCounts[tournamentId] = { count: 0, total: 0 };
  197. }
  198. blockValidationCounts[tournamentId].total++;
  199. }
  200. // After validation, confirm tournaments with more than 50% valid blocks
  201. for (const tournamentId in blockValidationCounts) {
  202. const { count, total } = blockValidationCounts[tournamentId];
  203. if (count > total / 2) {
  204. // More than 50% of blocks are valid, store the leaderboard
  205. const validBlock = tournamentBlocks.find(block => block.tournamentId === parseInt(tournamentId));
  206. if (validBlock) {
  207. confirmedLeaderboards[tournamentId] = validBlock.leaderboard;
  208. console.log(`*** Tournament ${tournamentId} confirmed with a valid leaderboard.`);
  209. }
  210. } else {
  211. console.log(`*** Tournament ${tournamentId} did not meet the 50% valid block requirement.`);
  212. }
  213. }
  214. }