|
|
|
@ -618,6 +618,133 @@ function Database(){
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.cleanShareDBNew = function() {
|
|
|
|
|
/*
|
|
|
|
|
This function takes the difficulty of the current block, and the last PPS block. If it's 0, save everything,
|
|
|
|
|
UNLESS global.config.pps.enable is FALSE, then feel free to trash it.
|
|
|
|
|
Due to LMDB under current config, we must delete entire keys, due to this, we save diff * shareMulti * 1.3
|
|
|
|
|
|
|
|
|
|
6/29/2017 - Fixed bug with the way the system got blocks. getLastBlock gets the most recent block.
|
|
|
|
|
getOldestLockedBlock gets the oldest block in the system that's locked. This ensures that shares for that block
|
|
|
|
|
can't be destroyed, and that there's enough depth past that point to ensure the system will have the ability
|
|
|
|
|
to make payouts based on the shareMultiLog. Thanks suhz for finding this. Sorry it hit your aeon pool hard.
|
|
|
|
|
:( -- Snipa
|
|
|
|
|
|
|
|
|
|
If current_height - global.payout.blocksRequired > lastLockedBlock, then set the scan start to
|
|
|
|
|
current_height - global.payout.blocksRequired - 1 so that we have the full block in case of PPS.
|
|
|
|
|
Otherwise, use the lastPPLNSBlock as the scan start. There we go. Stupid logic!
|
|
|
|
|
|
|
|
|
|
Math check!
|
|
|
|
|
cur_height = 100, blocksRequired=20, lastPPLNSLockedBlock.height=90
|
|
|
|
|
In this case, the functional depth required for SOLO is 80 - 1, giving us 79 as our start
|
|
|
|
|
cur_height = 100, blocksRequired=20, lastPPLNSLockedBlock.height=70
|
|
|
|
|
In this case, the PPLNS locked block is older than the current height - the required amount, so start is 70.
|
|
|
|
|
|
|
|
|
|
PPS height no longer matters! Yay!
|
|
|
|
|
Solo really doesn't matter, as block finder gets everything.
|
|
|
|
|
If there is no valid locked block to start from, aka all blocks are unlocked, then scan from the current height
|
|
|
|
|
of the chain, as there's no way for the system to have older blocks. We only need to save extra in the case
|
|
|
|
|
where there's unlocked blocks. A find on the current block will have enough depth as long as the saves are
|
|
|
|
|
correct. This will cause the system to clean up shares massively when there are no unlocked blocks.
|
|
|
|
|
*/
|
|
|
|
|
let oldestLockedBlock = this.getOldestLockedBlock();
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function(callback){
|
|
|
|
|
global.coinFuncs.getLastBlockHeader(function(body){
|
|
|
|
|
if (oldestLockedBlock === null){
|
|
|
|
|
/*
|
|
|
|
|
If there's no locked blocks, then allow the system to scan from the PPS depth downwards if PPS
|
|
|
|
|
is enabled.
|
|
|
|
|
Save enough shares so that the diff * share multi * 30% for buffer.
|
|
|
|
|
*/
|
|
|
|
|
if (global.config.pps.enable){
|
|
|
|
|
// If PPS is enabled, we scan for new blocks at cur height - blocksRequired/2.
|
|
|
|
|
// We need to save shares back that far at the least.
|
|
|
|
|
callback(null, body.height - Math.floor(global.config.payout.blocksRequired/2), Math.floor(body.difficulty * global.config.pplns.shareMulti * 1.3));
|
|
|
|
|
} else {
|
|
|
|
|
// Otherwise, we can just start from the current height. Woo!
|
|
|
|
|
callback(null, body.height, Math.floor(body.difficulty * global.config.pplns.shareMulti * 1.3));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
Otherwise, start the scan from the oldest locked block downwards.
|
|
|
|
|
This protects against the blockManager being messed up and not unlocking blocks.
|
|
|
|
|
This will ensure that enough shares are in place to unlock all blocks.
|
|
|
|
|
If the block is Solo, PPLNS or PPS, it doesn't matter.
|
|
|
|
|
*/
|
|
|
|
|
if (global.config.pps.enable && oldestLockedBlock.height > body.height - Math.floor(global.config.payout.blocksRequired/2)) {
|
|
|
|
|
// If PPS is enabled, and the oldestLockedBlock.height > the PPS minimum, start from the PPS minimum.
|
|
|
|
|
callback(null, body.height - Math.floor(global.config.payout.blocksRequired/2), Math.floor(body.difficulty * global.config.pplns.shareMulti * 1.3));
|
|
|
|
|
} else {
|
|
|
|
|
// If PPS isn't enabled, or the oldestLockedBlock.height < the PPS minimum, then start from there.
|
|
|
|
|
callback(null, oldestLockedBlock.height, Math.floor(oldestLockedBlock.difficulty * global.config.pplns.shareMulti * 1.3));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
function (lastBlock, difficulty, callback) {
|
|
|
|
|
let shareCount = 0;
|
|
|
|
|
let pplnsFound = false;
|
|
|
|
|
let blockList = [];
|
|
|
|
|
debug("Scanning from: "+lastBlock + " for more than: " + difficulty + " shares");
|
|
|
|
|
range.range(0, lastBlock+1).forEach(function (blockID) {
|
|
|
|
|
blockID = (blockID - lastBlock+1) * -1;
|
|
|
|
|
if (blockID < 0){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
debug("Scanning block: " + blockID);
|
|
|
|
|
let txn = global.database.env.beginTxn({readOnly: true});
|
|
|
|
|
let cursor = new global.database.lmdb.Cursor(txn, global.database.shareDB);
|
|
|
|
|
for (let found = (cursor.goToRange(blockID) === blockID); found; found = cursor.goToNextDup()) {
|
|
|
|
|
if (pplnsFound){
|
|
|
|
|
cursor.getCurrentBinary(function(key, data) { // jshint ignore:line
|
|
|
|
|
if (blockList.indexOf(key) === -1){
|
|
|
|
|
blockList.push(key);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
cursor.getCurrentBinary(function(key, data) { // jshint ignore:line
|
|
|
|
|
try{
|
|
|
|
|
let shareData = global.protos.Share.decode(data);
|
|
|
|
|
if (shareData.poolType === global.protos.POOLTYPE.PPLNS){
|
|
|
|
|
shareCount = shareCount + shareData.shares;
|
|
|
|
|
}
|
|
|
|
|
} catch(e){
|
|
|
|
|
console.error("Invalid share");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (shareCount >= difficulty){
|
|
|
|
|
pplnsFound = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cursor.close();
|
|
|
|
|
txn.abort();
|
|
|
|
|
});
|
|
|
|
|
callback(null, blockList);
|
|
|
|
|
}
|
|
|
|
|
], function(err, data){
|
|
|
|
|
if (global.config.general.blockCleaner === true){
|
|
|
|
|
if(data.length > 0){
|
|
|
|
|
global.database.refreshEnv();
|
|
|
|
|
let totalDeleted = 0;
|
|
|
|
|
data.forEach(function(block){
|
|
|
|
|
totalDeleted += 1;
|
|
|
|
|
let txn = global.database.env.beginTxn();
|
|
|
|
|
txn.del(global.database.shareDB, block);
|
|
|
|
|
txn.commit();
|
|
|
|
|
debug("Deleted block: " + block);
|
|
|
|
|
});
|
|
|
|
|
console.log("Block cleaning enabled. Removed: " +totalDeleted+ " block share records");
|
|
|
|
|
}
|
|
|
|
|
global.database.env.sync(function(){
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.log("Block cleaning disabled. Would of removed: " + JSON.stringify(data));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.refreshEnv = function(){};
|
|
|
|
|
|
|
|
|
|