From 8f9cc334594a8c9cbeb512a105aa383509b77dd7 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Tue, 17 Sep 2024 09:41:09 -0400 Subject: [PATCH 1/2] feat: pay up to 50 mirrors per round --- package-lock.json | 8 +- package.json | 2 +- src/tasks/payouts.ts | 234 +++++++++++++------------------------------ 3 files changed, 74 insertions(+), 170 deletions(-) diff --git a/package-lock.json b/package-lock.json index 410cb69..9f24270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1-alpha.7", "license": "ISC", "dependencies": { - "@dignetwork/dig-sdk": "^0.0.1-alpha.18", + "@dignetwork/dig-sdk": "^0.0.1-alpha.23", "async-mutex": "^0.5.0", "chia-server-coin": "^0.0.5", "datalayer-driver": "^0.1.21", @@ -152,9 +152,9 @@ } }, "node_modules/@dignetwork/dig-sdk": { - "version": "0.0.1-alpha.18", - "resolved": "https://registry.npmjs.org/@dignetwork/dig-sdk/-/dig-sdk-0.0.1-alpha.18.tgz", - "integrity": "sha512-guOr60Be7q1LIEY0d44B2aVP4KizqdrcOJda6e+HVomJaA9I/tBeWdQN3Kd1VFqsJ2kri/uistNrT7VAtuTHGQ==", + "version": "0.0.1-alpha.23", + "resolved": "https://registry.npmjs.org/@dignetwork/dig-sdk/-/dig-sdk-0.0.1-alpha.23.tgz", + "integrity": "sha512-pv9l41ZUQ438C/+OV645aDWIlfMN7K/A9zAbpDVA4Jx3/BsXPbd+oaPtkXNUFyUN2G1MgT3IdTk0whasDTSBDw==", "dependencies": { "bip39": "^3.1.0", "chia-bls": "^1.0.2", diff --git a/package.json b/package.json index 3630338..682d859 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "LICENSE" ], "dependencies": { - "@dignetwork/dig-sdk": "^0.0.1-alpha.18", + "@dignetwork/dig-sdk": "^0.0.1-alpha.23", "async-mutex": "^0.5.0", "chia-server-coin": "^0.0.5", "datalayer-driver": "^0.1.21", diff --git a/src/tasks/payouts.ts b/src/tasks/payouts.ts index b73ea91..7908c2b 100644 --- a/src/tasks/payouts.ts +++ b/src/tasks/payouts.ts @@ -45,26 +45,14 @@ const runIncentiveProgram = async ( console.log(program); const dataStore = DataStore.from(program.storeId); - console.log("!!!!"); const rootHash = dataStore.Tree.getRoot(); if (process.env.DIG_DEBUG === "1") { console.log("Root hash:", rootHash); } - //const storeIntegrityCheck = await dataStore.validate(); - - //if (process.env.DIG_DEBUG === "1") { - // console.log("Store integrity check:", storeIntegrityCheck); - // } - - // if (!storeIntegrityCheck) { - // throw new Error(`Store ${program.storeId} failed integrity check.`); - // } - const rewardThisRound = - (BigInt(program.xchRewardPerEpoch) * mojosPerXch) / - BigInt(roundsPerEpoch); + (BigInt(program.xchRewardPerEpoch) * mojosPerXch) / BigInt(roundsPerEpoch); if (process.env.DIG_DEBUG === "1") { console.log(`Reward for this round: ${rewardThisRound} mojos`); @@ -77,23 +65,15 @@ const runIncentiveProgram = async ( } const serverCoin = new ServerCoin(program.storeId); - - // Get the keys from the store const storeKeys = dataStore.Tree.listKeys(rootHash); const totalKeys = storeKeys.length; - // Calculate the sample size needed for 90% confidence const sampleSize = calculateSampleSize(totalKeys); - if (process.env.DIG_DEBUG === "1") { - console.log( - `Total keys: ${totalKeys}, Sampling ${sampleSize} keys for 90% confidence` - ); + console.log(`Total keys: ${totalKeys}, Sampling ${sampleSize} keys for 90% confidence`); } - // Randomly select keys based on the calculated sample size - const randomKeysHex = - sampleSize > 0 ? _.sampleSize(storeKeys, sampleSize) : storeKeys; + const randomKeysHex = sampleSize > 0 ? _.sampleSize(storeKeys, sampleSize) : storeKeys; const randomKeys = randomKeysHex.map(hexToUtf8); if (randomKeys.length === 0) { @@ -101,177 +81,100 @@ const runIncentiveProgram = async ( } if (process.env.DIG_DEBUG === "1") { - console.log( - `Selected ${randomKeys.length} keys for challenge generation.` - ); + console.log(`Selected ${randomKeys.length} keys for challenge generation.`); } - let winningPeer: DigPeer | null = null; + let validPeers: DigPeer[] = []; + let payoutMade = false; - // Loop until a valid peer is found or no more peers are available - while (!winningPeer) { + // Loop until a payment is made or no more peers are available + while (!payoutMade) { if (process.env.DIG_DEBUG === "1") { - console.log("Sampling a peer from the current epoch..."); + console.log("Sampling up to 50 peers from the current epoch..."); } - // Sample only one peer at a time - const serverCoins = await serverCoin.sampleCurrentEpoch(1, peerBlackList); + // Sample up to 50 peers + const serverCoins = await serverCoin.sampleCurrentEpoch(50, peerBlackList); if (process.env.DIG_DEBUG === "1") { console.log("Server coins:", serverCoins); } - // Exit if no peers are available if (serverCoins.length === 0) { console.log(`No more peers available for storeId ${program.storeId}`); - return; + break; } - const peerIp = serverCoins[0]; - if (process.env.DIG_DEBUG === "1") { - console.log(`Sampled peer: ${peerIp}`); - } - - const digPeer = new DigPeer(peerIp, program.storeId); - let response; - try { - response = await digPeer.contentServer.headStore(); - } catch (error: any) { - console.error(`Failed to connect to peer ${peerIp}: ${error.message}`); - await program.addToBlacklist(peerIp); - continue; // Move to next peer - } - - if (process.env.DIG_DEBUG === "1") { - console.log(`Checking if peer ${peerIp} has the correct store...`); - } - - let valid = false; - - if (response.success) { - if (process.env.DIG_DEBUG === "1") { - console.log(`Peer ${peerIp} responded successfully.`); + for (const peerIp of serverCoins) { + const digPeer = new DigPeer(peerIp, program.storeId); + let response; + try { + response = await digPeer.contentServer.headStore(); + } catch (error: any) { + console.error(`Failed to connect to peer ${peerIp}: ${error.message}`); + await program.addToBlacklist(peerIp); + continue; } - const peerGenerationHash = response.headers?.["x-generation-hash"]; - - if ((peerGenerationHash as string) === rootHash) { - console.log( - `Peer ${peerIp} has the correct generation hash: ${peerGenerationHash}` - ); - console.log( - `Generating challenges for ${randomKeys.length} random keys for peer ${peerIp}...` - ); - - // Generate challenges for each random key - const challengePromises = randomKeysHex.map(async (hexKey) => { - try { - const digChallenge = new DigChallenge( - program.storeId, - hexKey, - rootHash - ); - - const seed = DigChallenge.generateSeed(); - const challenge = await digChallenge.generateChallenge(seed); - - const serializedChallenge = - DigChallenge.serializeChallenge(challenge); - - // Send the challenge to the peer and get their response - const peerChallengeResponse = await digPeer.contentServer.getKey( - hexToUtf8(hexKey), - rootHash, - serializedChallenge - ); - - // Compute your own challenge response (the expected response) - const expectedChallengeResponse = - await digChallenge.createChallengeResponse(challenge); - - // Compare your response with the peer's response - const isValid = - peerChallengeResponse === expectedChallengeResponse; - - console.log( - `Challenge for key ${hexKey} ${ - isValid ? "passed" : "failed" - } for peer ${peerIp}` - ); - - return isValid; - } catch (error: any) { - console.error( - `Error during challenge for peer ${peerIp}: ${error.message}` - ); - await program.addToBlacklist(peerIp); - throw error; // Exit the loop on error - } - }); + if (response.success) { + const peerGenerationHash = response.headers?.["x-generation-hash"]; + if (peerGenerationHash === rootHash) { + const challengePromises = randomKeysHex.map(async (hexKey) => { + try { + const digChallenge = new DigChallenge(program.storeId, hexKey, rootHash); + const seed = DigChallenge.generateSeed(); + const challenge = await digChallenge.generateChallenge(seed); + const serializedChallenge = DigChallenge.serializeChallenge(challenge); + const peerChallengeResponse = await digPeer.contentServer.getKey( + hexToUtf8(hexKey), + rootHash, + serializedChallenge + ); + const expectedChallengeResponse = await digChallenge.createChallengeResponse(challenge); + return peerChallengeResponse === expectedChallengeResponse; + } catch (error: any) { + console.error(`Error during challenge for peer ${peerIp}: ${error.message}`); + await program.addToBlacklist(peerIp); + return false; + } + }); - // Check if all challenges are valid - try { const challengeResults = await Promise.all(challengePromises); - valid = challengeResults.every((result) => result); - if (process.env.DIG_DEBUG === "1") { - console.log( - `Peer ${peerIp} ${ - valid - ? "passed all challenges" - : "failed one or more challenges" - }.` - ); + const valid = challengeResults.every((result) => result); + + if (valid) { + validPeers.push(digPeer); + console.log(`Peer ${peerIp} passed all challenges and is valid.`); + } else { + console.log(`Peer ${peerIp} failed one or more challenges.`); + await program.addToBlacklist(peerIp); } - } catch (error: any) { - console.error( - `Challenge validation error for peer ${peerIp}: ${error.message}` - ); - await program.addToBlacklist(peerIp); - continue; // Move to next peer + } else { + console.log(`Peer ${peerIp} has an incorrect generation hash.`); } } else { - if (process.env.DIG_DEBUG === "1") { - console.log( - `Peer ${peerIp} has an incorrect generation hash: ${peerGenerationHash}` - ); - } - } - } else { - if (process.env.DIG_DEBUG === "1") { console.log(`Peer ${peerIp} did not respond successfully.`); } } - if (valid) { - winningPeer = digPeer; - if (process.env.DIG_DEBUG === "1") { - console.log(`Valid peer found: ${peerIp}`); - } - } else { - if (process.env.DIG_DEBUG === "1") { - console.log( - `Peer ${peerIp} was not valid. Adding to blacklist and resampling...` - ); - } - await program.addToBlacklist(peerIp); - } - } + if (validPeers.length > 0) { + console.log(`Valid peers found: ${validPeers.length}`); + const paymentAddresses = await Promise.all(validPeers.map(async (peer) => await peer.contentServer.getPaymentAddress())); - // Send payout to the winning peer - if (winningPeer) { - console.log( - `Sending XCH to ${winningPeer.IpAddress} for store ${program.storeId}...` - ); + await DigPeer.sendEqualBulkPayments(program.walletName, paymentAddresses, rewardThisRound); - await winningPeer.sendPayment(program.walletName, rewardThisRound); - console.log(`Payout sent to peer: ${winningPeer.IpAddress}`); + payoutMade = true; // Mark that payment was made + await program.setLastEpochPaid(currentEpoch); + await program.incrementTotalRoundsCompleted(1); + await program.incrementPaymentTotal(rewardThisRound); + console.log(`Payout process completed for ${validPeers.length} peers.`); + } - await program.setLastEpochPaid(currentEpoch); - await program.incrementTotalRoundsCompleted(1); - await program.incrementPaymentTotal(rewardThisRound); - console.log( - `Payout process completed for peer: ${winningPeer.IpAddress}` - ); + // If no valid peers were found and more peers are available, continue sampling + if (validPeers.length === 0 && serverCoins.length === 0) { + console.log("No valid peers found and no more peers available."); + break; + } } } catch (error: any) { console.error(`Error during incentive program: ${error.message}`); @@ -279,6 +182,7 @@ const runIncentiveProgram = async ( } }; + // Function to run payouts for all stores const runPayouts = async (): Promise => { const currentEpoch = ServerCoin.getCurrentEpoch(); From 14e62cfd670aacd903c110e8045cf6f355f4b8b2 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Tue, 17 Sep 2024 09:41:49 -0400 Subject: [PATCH 2/2] chore(release): 0.0.1-alpha.8 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3e6d27..8dbddec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.0.1-alpha.8](https://github.com/DIG-Network/dig-incentive-server/compare/v0.0.1-alpha.7...v0.0.1-alpha.8) (2024-09-17) + + +### Features + +* pay up to 50 mirrors per round ([8f9cc33](https://github.com/DIG-Network/dig-incentive-server/commit/8f9cc334594a8c9cbeb512a105aa383509b77dd7)) + ### [0.0.1-alpha.7](https://github.com/DIG-Network/dig-incentive-server/compare/v0.0.1-alpha.6...v0.0.1-alpha.7) (2024-09-16) ### [0.0.1-alpha.6](https://github.com/DIG-Network/dig-incentive-server/compare/v0.0.1-alpha.5...v0.0.1-alpha.6) (2024-09-11) diff --git a/package-lock.json b/package-lock.json index 9f24270..a2b0455 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dig-incentive-server", - "version": "0.0.1-alpha.7", + "version": "0.0.1-alpha.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dig-incentive-server", - "version": "0.0.1-alpha.7", + "version": "0.0.1-alpha.8", "license": "ISC", "dependencies": { "@dignetwork/dig-sdk": "^0.0.1-alpha.23", diff --git a/package.json b/package.json index 682d859..1386037 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dig-incentive-server", - "version": "0.0.1-alpha.7", + "version": "0.0.1-alpha.8", "description": "", "type": "commonjs", "main": "./dist/index.js",