diff --git a/README b/README.md similarity index 94% rename from README rename to README.md index b3c512e..3528613 100644 --- a/README +++ b/README.md @@ -1,23 +1,13 @@ -m2pool app module code - -environment: -nodejs v16.10.0 + -express -axios -mysql2 -ioredis - -if you want to support enx, kas... -add environment: -kaspa-rpc-client - ### start common example ### node app.js # if you used pm2, you can use this command +``` pm2 start app.js --name -- +``` # config like this +``` // this file please use .conf { "master":{ @@ -148,9 +138,9 @@ pm2 start app.js --name -- "POOL_FEE": } } +``` - - +# start examples ############# pm2 start common ############# pm2 start app.js --name nexa-hashratev2 -- hashrate nexa pm2 start app.js --name nexa-reportv2 -- report nexa @@ -175,13 +165,11 @@ pm2 start app.js --name dgbs-hashratev2 -- hashrate dgbs pm2 start app.js --name dgbs-reportv2 -- report dgbs pm2 start app.js --name dgbs-confirm -- confirm dgbs pm2 start app.js --name dgbs-distributionv2 -- distribution dgbs -# pm2 start app.js --name dgbs-balance -- balance dgbs pm2 start app.js --name dgbq-hashratev2 -- hashrate dgbq pm2 start app.js --name dgbq-reportv2 -- report dgbq pm2 start app.js --name dgbq-confirm -- confirm dgbq pm2 start app.js --name dgbq-distributionv2 -- distribution dgbq -# pm2 start app.js --name dgbq-balance -- balance dgbq pm2 start app.js --name dgbo-hashratev2 -- hashrate dgbo pm2 start app.js --name dgbo-reportv2 -- report dgbo diff --git a/app.js b/app.js index 571bdac..5a506d0 100644 --- a/app.js +++ b/app.js @@ -1,12 +1,10 @@ const schedule = require("node-schedule"); -// const executeWithRetry = require("./public/retry") const Times = require("./public/times"); const HashRate = require("./src/hashrate"); const { Report, ReportEnx } = require("./src/report"); const Confirm = require("./src/confirm"); const Distribution = require("./src/distribution"); const { Balance, DGBBlance } = require("./src/blanace"); -const Stats = require("./src/stat"); const ClearDBData = require("./src/clear"); const Notice = require("./src/notice"); @@ -62,45 +60,59 @@ if (method === "report") { if (method === "confirm") { + let interval = 60000; + if (coin === "rxd") { + interval = 300000; + } else if (coin === "nexa") { + interval = 120000; + } const confirm = new Confirm(coin); - schedule.scheduleJob({ hour: [1], minute: [30], second: [0] }, async () => { + setInterval(() => { confirm.main(); - }); + }, interval); } + +// if (method === "confirm") { +// const confirm = new Confirm(coin); +// schedule.scheduleJob({ hour: [1], minute: [30], second: [0] }, async () => { +// confirm.main(); +// }); +// } + if (method === "distribution") { const distribution = new Distribution(coin); - schedule.scheduleJob({ hour: [0], minute: [1], second: [0] }, async () => { + // schedule.scheduleJob({ hour: [0], minute: [1], second: [0] }, async () => { const now_ts = Date.now().valueOf(); const last_ts = now_ts - 1000 * 60 * 60 * 24; const ymd_now = Times.utcTime(now_ts); const ymd_last = Times.utcTime(last_ts); const end_time = ymd_now.split(" ")[0] + " 00:00:00"; const start_time = ymd_last.split(" ")[0] + " 00:00:00"; - await distribution.main(start_time, end_time); - }); + distribution.main(start_time, end_time); + // }); } -if (method === "balance") { - const special_coins = ["dgbo", "dgbs", "dgbq"]; - let balance; - if (special_coins.includes(coin)) { - balance = new DGBBlance(coin); - } else { - balance = new Balance(coin); - } - balance - .main() - .then(() => { - console.log("ok"); - }) - .catch((err) => { - console.log(err); - }) - .finally(() => { - process.exit(0); - }); -} +// if (method === "balance") { +// const special_coins = ["dgbo", "dgbs", "dgbq"]; +// let balance; +// if (special_coins.includes(coin)) { +// balance = new DGBBlance(coin); +// } else { +// balance = new Balance(coin); +// } +// balance +// .main() +// .then(() => { +// console.log("ok"); +// }) +// .catch((err) => { +// console.log(err); +// }) +// .finally(() => { +// process.exit(0); +// }); +// } if (method === "balance") { const special_coins = ["dgbo", "dgbs", "dgbq"]; @@ -123,9 +135,11 @@ if (method === "balance") { // 最多执行 36 次 (6小时) const enable = await balance.query_now_height(last_height); if (enable) { - await balance.main(); - console.log(`${coin}转账已完成`); - return; // 成功执行后退出循环 + const result = await balance.main(); + if(!result){ + console.log(`${coin}转账已完成`); + return; // 成功执行后退出循环 + } } console.log(`等待中... (已等待 ${count * 10} 分钟)`); await balance.sleep(1000 * 60 * 10); // 休眠 10 分钟 @@ -138,10 +152,6 @@ if (method === "balance") { }); } -if (method === "stats") { - const stats = new Stats(coin); - stats.caculate_user_should_distribution("2024-11-28 00:00:00"); -} if (method === "clear") { const clear = new ClearDBData(coin); diff --git a/src/confirm.js b/src/confirm.js index 2de2563..88a49ed 100644 --- a/src/confirm.js +++ b/src/confirm.js @@ -41,12 +41,9 @@ class Confirm extends Init { } else { const now = Date.now().valueOf() const max_mature_time = now - this.MAX_MATURE * 60 * 1000 - console.log("MAX_MATURE:", this.MAX_MATURE); - console.log("max_mature_time: ", max_mature_time); const ymd = Times.utcTime(max_mature_time) const sql = `SELECT MAX(height) AS max_height FROM alph_blkreportprofitv2 WHERE date <= ? AND state = ?;` const data = await this.distribution.exec(sql, [ymd, 0]) - console.log("data: ", data); if(!data[0]){ console.log(`alph当前时间没有需要更新的成熟区块`); return false @@ -119,13 +116,13 @@ class Confirm extends Init { suc_heights.push(item); } } - if(err_heights.length === 0 && need_update_heights.length !== 0){ - console.log(`${mature_max_height}之前有新报块,且无孤块`); - } else if(err_heights.length !== 0 && need_update_heights.length === 0){ - console.log(`${mature_max_height}之前有新报块,但这些报块都是孤块`); - } else if(err_heights.length !== 0 && need_update_heights.length !== 0){ - console.log(`${mature_max_height}之前有新报块,且其中有孤块`); - } + // if(err_heights.length === 0 && need_update_heights.length !== 0){ + // console.log(`${mature_max_height}之前有新报块,且无孤块`); + // } else if(err_heights.length !== 0 && need_update_heights.length === 0){ + // console.log(`${mature_max_height}之前有新报块,但这些报块都是孤块`); + // } else if(err_heights.length !== 0 && need_update_heights.length !== 0){ + // console.log(`${mature_max_height}之前有新报块,且其中有孤块`); + // } await this.update_blkreporprofit_state(suc_heights, err_heights); return } catch (err) { diff --git a/src/distribution.js b/src/distribution.js index dc80088..2ab045c 100644 --- a/src/distribution.js +++ b/src/distribution.js @@ -27,7 +27,7 @@ class Distribution extends Init { const result = {}; // 计算每个用户的算力占比 for (let { user, mhs24h } of alluser_mhs24h) { - result[user] = (mhs24h / totalHashrate) * hash_percent; + result[user] = Number(((mhs24h / totalHashrate) * hash_percent).toFixed(4)); } return result; } @@ -79,7 +79,7 @@ class Distribution extends Init { * 校验昨天所有报块是否成熟 * @param {Date} start_time 采用yyyy-MM-dd hh:mm:ss格式,例如"2024-11-11 00:00:00" * @param {Date} end_time 同上 - * @returns + * @returns */ async query_last_day_if_mature(start_time, end_time) { try { @@ -93,7 +93,7 @@ class Distribution extends Init { // 动态获取当前小时 const currentHour = Number(Times.times()[4]); - if(this.coin === "rxd"){ + if (this.coin === "rxd") { if (currentHour >= 9) { console.log("已超过凌晨 9 点,停止检查。"); return false; @@ -111,10 +111,10 @@ class Distribution extends Init { throw err; } } - + /** * 查询当前挖矿账户状态,包括起付额和钱包地址 - * @returns + * @returns */ async query_users_address() { try { @@ -142,8 +142,8 @@ class Distribution extends Init { /** * 校验报块 - * @param {Number} height - * @returns + * @param {Number} height + * @returns */ async verify_block(height) { try { @@ -159,7 +159,7 @@ class Distribution extends Init { /** * 将漏掉的报块插入到数据库中 - * @param {Array} data [{time: 1708256800, height: 123456, hash: "0x1234567890", reward: 100, fees: 10}] + * @param {Array} data [{time: 1708256800, height: 123456, hash: "0x1234567890", reward: 100, fees: 10}] */ async insert_blkreportprofit(data) { try { @@ -179,8 +179,8 @@ class Distribution extends Init { /** * 校验昨日是否有漏掉报块的情况 - * @param {Date} date 当前时间 - * @returns + * @param {Date} date 当前时间 + * @returns */ async check_last_data_blk(date) { try { @@ -196,8 +196,9 @@ class Distribution extends Init { } const heights = []; const query_blk_pool_sql = `SELECT height FROM ${table_name} WHERE DATE(date) >= ?;`; - const [master_data, slave_data] = await Promise.all([this.pooldb.exec(query_blk_pool_sql, [yMd]), this.pooldb_slave.exec(`SELECT height FROM ${this.coin}_pool_blkstats WHERE DATE(date) >= ?;`, [yMd])]) - const pool_data = master_data.concat(slave_data); + // const [master_data, slave_data] = await Promise.all([this.pooldb.exec(query_blk_pool_sql, [yMd]), this.pooldb_slave.exec(`SELECT height FROM ${this.coin}_pool_blkstats WHERE DATE(date) >= ?;`, [yMd])]) + // const pool_data = master_data.concat(slave_data); + const pool_data = await this.pooldb.exec(query_blk_pool_sql, [yMd]); for (let item of pool_data) { heights.push(item.height); } @@ -235,15 +236,15 @@ class Distribution extends Init { /** * 更新wallet_in表中不满足起付额的用户状态 - * @param {Array} min_amount [{"user": amount}] - * @returns + * @param {Array} min_amount [{"user": amount}] + * @returns */ async update_state(min_amount) { try { const sql = `SELECT user, SUM(amount) AS profit FROM wallet_in WHERE coin = ? AND state = ? GROUP BY user;`; const data = await this.distributiondb.exec(sql, [this.coin, 2]); // [] if (!data || data.length === 0) { - return + return; } const need_update_state = []; for (let item of data) { @@ -268,10 +269,10 @@ class Distribution extends Init { throw err; } } - + /** * 将最终分配数据插入wallet_in表中 - * @param {Array} data [{coin, user, address, create_date, should_out_date, max_height, amount, state}] + * @param {Array} data [{coin, user, address, create_date, should_out_date, max_height, amount, state}] */ async insert_wallet_in(data) { try { @@ -294,7 +295,7 @@ class Distribution extends Init { if (!_if) { return; } - const check_result = await this.check_last_data_blk(end_time) + const check_result = await this.check_last_data_blk(end_time); if (!check_result) { return; } @@ -306,37 +307,39 @@ class Distribution extends Init { console.log("users_address:", users_address); return; } + const reward = (BigInt(last_day_reward[0].reward) * BigInt((1 - this.POOL_FEE) * 10000)) / BigInt(10000); const min_amount = {}; const score_ratio = this.score(last_day_mhs24h, 1); - const reward = Number(last_day_reward[0].reward) * (1 - this.POOL_FEE); const max_height = last_day_reward[0].max_height; let should_out_date; // 实际转账时间 let accuracy; // user保留小数位数,100为2位,以此类推 - let count // pool_account 保留小数位数 + let count; // pool_account 保留小数位数 if (this.coin === "nexa") { should_out_date = Times.utcTime(new Date(end_time).valueOf() + 1000 * 60 * 60 * 24 * 7); accuracy = 100; - count = 2 + count = 2; } else if (this.coin === "rxd") { accuracy = 100; should_out_date = end_time; - count = 2 - } else if(this.coin === "alph"){ - accuracy = 0 + count = 2; + } else if (this.coin === "alph") { + accuracy = 0; should_out_date = end_time; - count = 0 + count = 0; } else { should_out_date = end_time; accuracy = 100000000; - count = 8 + count = 8; } - let user_profit = 0; + let user_profit = BigInt(0) const result = []; let pool_account_address; for (let user in score_ratio) { - const profit = Math.floor(score_ratio[user] * reward * accuracy) / accuracy; - if(profit === 0){ - continue + // const profit = Math.floor(score_ratio[user] * reward * accuracy) / accuracy; + const ratio = Math.round(score_ratio[user] * 10000); + const profit = (reward * BigInt(ratio)) / 10000n; + if (profit === 0) { + continue; } user_profit += profit; for (let item of users_address) { @@ -377,4 +380,4 @@ class Distribution extends Init { } } -module.exports = Distribution; \ No newline at end of file +module.exports = Distribution; diff --git a/src/hashrate.js b/src/hashrate.js index 555167f..653ceb0 100644 --- a/src/hashrate.js +++ b/src/hashrate.js @@ -363,4 +363,39 @@ ON t1.user = t2.user AND t1.miner = t2.miner AND t1.date = t2.max_date;`; } } +class HashRateNew extends Init { + constructor(coin) { + const method = "distribution"; + super(coin, method); + this.count = 0 + } + async query_blk_detail_table_name() { + try{ + const sql = `SELECT \`from\`, \`to\` FROM ${this.coin}_blk_height_detail WHERE date < NOW() - INTERVAL 5 MINUTE;` + const data = await this.sharesdb.exec(sql); + let tables = [`${this.coin}_blk_detail`] + if(data.length === 0){ + return tables + } + for(let item of data){ + tables.push(`${this.coin}_block_detail_${item.from}_${Math.trunc(item.to - 1)}`) + } + return tables + } catch(err){ + throw err; + } + } + async query_blk_detail(){ + try{ + + } catch(err){ + throw err + } + } +} module.exports = HashRate + +// SELECT COUNT(*) +// FROM information_schema.tables +// WHERE table_schema = 'alphsharesdb' +// AND table_name = 'alph_blk_detail'; \ No newline at end of file diff --git a/src/stat.js b/src/stat.js deleted file mode 100644 index 0c10212..0000000 --- a/src/stat.js +++ /dev/null @@ -1,112 +0,0 @@ -const Times = require("../public/times"); -const Init = require("./init"); - -/** - * earliest date : 2024-11-26 00:00:00 - */ -class Stats extends Init { - constructor(coin) { - const method = "stats"; - super(coin, method); - } - - async query_pooldb_mhs24h(date) { - try { - const yMd = Times.utcTime(new Date(date).valueOf() - 1000 * 60 * 60 * 24).split(" ")[0]; - const table_date = yMd.replace(/\-/g, ""); - let table = `${this.coin}_miners_stats_${table_date}`; - console.log(table); - - const sql = `SELECT user, SUM(mhs24h) AS mhs24h FROM ${table} WHERE date >= ? AND date <= ? GROUP BY user;`; - const start = yMd + " 23:55:00"; - const end = yMd + " 23:59:59"; - const data = await this.pooldb.exec(sql, [start, end]); - if (data.length === 0) { - return false; - } - const result = []; - for (let item of data) { - const { user, mhs24h } = item; - result.push({ user, mhs24h: Number(mhs24h) }); - } - return result; - } catch (err) { - throw err; - } - } - - async query_hashratedb_mhs24h(date) { - try { - const sql = `SELECT user, SUM(mhs24h) AS mhs24h FROM ${this.coin}_mhsv2 WHERE date = ? GROUP BY user;`; - const data = await this.hashratedb.exec(sql, [date]); - if (!data || data.length === 0) { - return false; - } - const result = []; - for (let item of data) { - const { user, mhs24h } = item; - result.push({ user, mhs24h: Number(mhs24h) }); - } - return result; - } catch (err) { - throw err; - } - } - - async query_distribution_data(date) { - try { - const sql = `SELECT user, amount FROM wallet_in WHERE coin = ? AND create_date = ? AND user != "pool_account";`; - const data = await this.distribution.exec(sql, [this.coin, date]); - if (!data || data.length === 0) { - return false; - } - const result = []; - for (let item of data) { - const { user, amount } = item; - result.push({ user, amount: Number(amount) }); - } - return result; - } catch (err) { - throw err; - } - } - - caculate_mhs24h_percent(data) { - const totalAmount = data.reduce((acc, item) => acc + item.mhs24h, 0); - const result = data.map((item) => ({ - user: item.user, - mhs24h: item.mhs24h, - percentage: Number((item.mhs24h / totalAmount).toFixed(4)), // 保留两位小数 - })); - return result; - } - - caculate_distribution_percent(data) { - const totalAmount = data.reduce((acc, item) => acc + item.amount, 0); - const result = data.map((item) => ({ - user: item.user, - should_receive: Number((item.amount / 0.95).toFixed(8)), - actual_receive: item.amount, - percentage: Number(((item.amount / totalAmount)).toFixed(4)), // 保留两位小数 - })); - return result; - } - - async caculate_user_should_distribution(date) { - try { - const [user_mhs24h, user_distribution] = await Promise.all([this.query_hashratedb_mhs24h(date), this.query_distribution_data(date)]); - const mhs24h_percent = this.caculate_mhs24h_percent(user_mhs24h) - const distribution_percent = this.caculate_distribution_percent(user_distribution) - let fees = 0 - for(let item of distribution_percent){ - const {user, should_receive, actual_receive, percentage} = item - fees += should_receive - actual_receive - } - console.log(fees); - } catch (err) { - throw err; - } - } -} - -module.exports = Stats;