Skip to content

Commit

Permalink
pool server work
Browse files Browse the repository at this point in the history
  • Loading branch information
madMAx43v3r committed Sep 26, 2024
1 parent 93761da commit 9d0b22c
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 6 deletions.
1 change: 1 addition & 0 deletions www/pool-server/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ async function update()
await account.save(opt);
}

// Distribute rewards and update account stats
let res = [];
for(const entry of result) {
const pool_share = entry.points / total_points;
Expand Down
14 changes: 10 additions & 4 deletions www/pool-server/config.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
const config = {};

config.pool_fee = 0.01; // [%]
config.mmx_divider = 1e6;
config.challenge_delay = 6; // [blocks]
config.block_interval = 10 * 1000; // [ms]
config.max_response_time = 55 * 1000; // [ms]
config.partial_expiry = 100; // [blocks]
config.account_delay = 24; // [blocks]
config.pool_fee = 0.01; // [%]
config.share_window = 8640; // [blocks]
config.block_interval = 10 * 1000; // [ms]
config.max_response_time = 50 * 1000; // [ms]
config.share_window_hours = 24; // [hours]
config.share_interval = 5 * 60; // [sec]
config.min_difficulty = 1;
config.min_difficulty = 1; // needs to be >= 2 for mainnet
config.default_difficulty = 1;
config.space_diff_constant = 10000000000;
config.payout_interval = 8640; // [blocks]
config.payout_tx_expire = 1000; // [blocks]
config.payout_threshold = 5; // [MMX]
config.max_payout_count = 2000;

config.server_port = 8080;
config.wallet_index = 0; // for pool wallet (payout)
config.node_url = "http://localhost:11380";
config.fee_account = "mmx1e7yktu9vpeyq7hx39cmagzfp2um3kddwjf4tlt8j3kmktwc7fk6qmyc6ns";
config.pool_target = "mmx1uj2dth7r9tcn3vas42f0hzz74dkz8ygv59mpx44n7px7j7yhvv4sfmkf0d";
Expand Down
210 changes: 210 additions & 0 deletions www/pool-server/payout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@

const mongoose = require('mongoose');
const axios = require("axios");
const dbs = require('./schema.js');
const utils = require('./utils.js');
const config = require('./config.js');

var db = null;
var sync_height = null;

var check_lock = false;

async function check()
{
if(!sync_height) {
return;
}
const height = sync_height;

if(check_lock) {
return;
}
check_lock = true;
try {
const list = await dbs.Payout.find({pending: true});
for(const payout of list) {
let failed = false;
let confirmed = false;
try {
const res = await axios.get(config.node_url + '/wapi/transaction?id=' + payout.txid);
const tx = res.data;
if(tx.confirm && tx.confirm >= config.account_delay) {
if(tx.did_fail) {
failed = true;
console.log("Payout transaction failed with:", tx.message);
} else {
confirmed = true;
}
payout.tx_fee = tx.fee.value;
}
} catch(e) {
if(height - payout.height > config.payout_tx_expire + config.account_delay) {
failed = true;
console.log("Payout transaction expired:", "height", payout.height, "txid", payout.txid);
}
console.log("Failed to check payout transaction:", e.message, "txid", payout.txid);
}

if(confirmed) {
payout.valid = true;
payout.pending = false;
await payout.save();
console.log("Payout confirmed:", "height", payout.height, "total_amount", payout.total_amount, "count", payout.count, "txid", payout.txid);
}
else if(failed) {
const conn = await db.startSession();
try {
await conn.startTransaction();
const opt = {session: conn};

// TODO: rollback balances minus tx fee

payout.valid = false;
payout.pending = false;
await payout.save();
console.log("Payout failed:", "height", payout.height, "txid", payout.txid);
} catch(e) {
await conn.abortTransaction();
throw e;
} finally {
conn.endSession();
}
}
}
} catch(e) {
console.log("check() failed:", e.message);
} finally {
check_lock = false;
}
}

async function make_payout(height, outputs, opt)
{
const options = {
auto_send: false,
expire_at: height + config.payout_tx_expire,
};
let tx = null;
// TODO: create tx

let total_amount = 0;
for(const entry of outputs) {
const payout = new dbs.UserPayout({
account: entry[0],
height: height,
amount: entry[1],
txid: tx.id,
});
total_amount += payout.amount;
await payout.save(opt);
}
const payout = new dbs.Payout({
txid: tx.id,
total_amount: total_amount,
amounts: outputs,
count: outputs.length,
time: Date.now(),
height: height,
pending: true,
});
await payout.save(opt);
return tx;
}

var payout_lock = false;

async function payout()
{
if(!sync_height) {
return;
}
const height = sync_height;

if(payout_lock) {
return;
}
payout_lock = true;
try {
const pool = await dbs.Pool.findOne({id: "this"});
if(!pool) {
throw new Error("Pool state not found");
}
if(pool.last_payout && height - pool.last_payout < config.payout_interval) {
return;
}
const conn = await db.startSession();
try {
await conn.startTransaction();
const opt = {session: conn};

const list = dbs.Account.find({balance: {$gt: config.payout_threshold}});

let total_amount = 0;
let outputs = [];
let tx_list = [];

for await(const account of list)
{
const amount = Math.floor(account.balance);
account.balance -= amount;
await account.save(opt);

console.log("Payout triggered for", account.address, "amount", amount, "value", amount / config.mmx_divider, "MMX");

total_amount += amount;
outputs.push([account.address, amount]);

if(outputs.length >= config.max_payouts) {
tx_list.push(await make_payout(outputs, opt));
outputs = [];
}
}
if(outputs.length) {
tx_list.push(await make_payout(outputs, opt));
}
pool.last_payout = height;
await pool.save(opt);

await conn.commitTransaction();

// TODO: send all tx
} catch(e) {
await conn.abortTransaction();
throw e;
} finally {
conn.endSession();
}
} catch(e) {
console.log("payout() failed:", e.message);
} finally {
payout_lock = false;
}
}

async function update()
{
try {
sync_height = await utils.get_synced_height();
if(!sync_height) {
console.log('Waiting for node sync ...');
}
} catch(e) {
console.log("Failed to query sync height:", e.message);
}
}

async function main()
{
db = await mongoose.connect(config.mongodb_uri);

await update();
await payout();
await check();

setInterval(update, 10 * 1000);
setInterval(payout, 15 * 60 * 1000);
setInterval(check, 60 * 1000);
}

main();
28 changes: 26 additions & 2 deletions www/pool-server/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const partial = new mongoose.Schema({
const account = new mongoose.Schema({
address: {type: String, unique: true},
balance: {type: Number, default: 0, index: true},
total_paid: {type: String, default: '0', index: true},
total_paid: {type: Number, default: 0, index: true},
difficulty: {type: Number, default: 1, index: true},
pool_share: {type: Number, default: 0, index: true},
points_rate: {type: Number, default: 0, index: true},
Expand All @@ -45,16 +45,40 @@ const block = new mongoose.Schema({
valid: {type: Boolean, index: true},
});

const payout = new mongoose.Schema({
txid: {type: String, unique: true},
total_amount: Number,
tx_fee: Number,
amounts: Array, // [[account, amount], ...]
count: Number,
time: Date,
height: {type: Number, index: true},
pending: {type: Boolean, default: true, index: true},
valid: {type: Boolean, index: true},
});

const user_payout = new mongoose.Schema({
account: {type: String, index: true},
height: {type: Number, index: true},
amount: Number,
txid: String,
});

const pool = new mongoose.Schema({
id: {type: String, unique: true},
farmers: {type: Number, default: 0},
points_rate: {type: Number, default: 0},
partial_rate: {type: Number, default: 0},
partial_errors: {type: Object, minimize: false},
partial_errors: {type: Object},
last_update: {type: Number, default: 0},
last_payout: {type: Number, default: 0},
}, {
minimize: false,
});

exports.Partial = mongoose.model('Partial', partial);
exports.Account = mongoose.model('Account', account);
exports.Block = mongoose.model('Block', block);
exports.Payout = mongoose.model('Payout', payout);
exports.UserPayout = mongoose.model('UserPayout', user_payout);
exports.Pool = mongoose.model('Pool', pool);
6 changes: 6 additions & 0 deletions www/pool-server/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ async function get_synced_height()
return res.data;
}

function calc_eff_space(points_rate)
{
// points_rate = points per block (height)
return points_rate * config.space_diff_constant * 2.467;
}

exports.get_synced_height = get_synced_height;

0 comments on commit 9d0b22c

Please sign in to comment.