SenShaMart/app/miner.js
Josip Milovac b4c2a0c88d smarter store update after replacing chains
concurrent mining
validity checks for new transactions/blocks/metadata
rdf store stores quads
smarter clearing of transactions from pool when a new block is mined
change querying to be readonly and generic
moved some things around
2022-12-20 11:26:06 +11:00

90 lines
2.6 KiB
JavaScript

const Wallet = require('../wallet');
const Transaction = require('../wallet/transaction');
const Block = require('../blockchain/block');
class Miner {
static STATE_WAITING = 0;
static STATE_RUNNING = 1;
static STATE_INTERRUPTED = 2;
static STATE_RESTARTING = 3;
constructor(blockchain, transactionPool, wallet, p2pServer) {
this.blockchain = blockchain;
this.transactionPool = transactionPool;
this.wallet = wallet;
this.p2pServer = p2pServer;
this.state = Miner.STATE_WAITING;
this.mining = [[], []];
this.lastBlock = null;
}
interrupt() {
if (this.state === Miner.STATE_RUNNING) {
this.state = Miner.STATE_INTERRUPTED;
}
}
interruptIfContainsTransaction(transaction) {
if (this.state === Miner.STATE_RUNNING && this.mining[0].find(t => t.id === transaction.id)) {
this.state = Miner.STATE_INTERRUPTED;
}
}
interruptIfContainsMetadata(metadata) {
if (this.state === Miner.STATE_RUNNING && this.mining[1].find(t => t.id === metadata.id)) {
this.state = Miner.STATE_INTERRUPTED;
}
}
startMine() {
//only continue if state is waiting or restarting
if (this.state !== Miner.STATE_WAITING && this.state !== Miner.STATE_RESTARTING) {
return;
}
const validTransactions = this.transactionPool.validTransactions();
const validMetadataS = this.transactionPool.validMetadataS();
if (validTransactions.length === 0 && validMetadataS.length === 0) {
this.state = Miner.STATE_WAITING;
return;
}
validTransactions.push(
Transaction.rewardTransaction(this.wallet, Wallet.blockchainWallet())
);
this.lastBlock = this.blockchain.chain[this.blockchain.chain.length - 1];
this.state = Miner.STATE_RUNNING;
this.mining = [validTransactions, validMetadataS];
this.nonce = 0;
this.mine();
}
mine() {
if (this.state !== Miner.STATE_RUNNING) {
this.state = Miner.STATE_RESTARTING;
startMine();
return;
}
const timestamp = Date.now();
const difficulty = Block.adjustDifficulty(this.lastBlock, timestamp);
const hash = Block.hash(timestamp, this.lastBlock.hash, this.mining, this.nonce, difficulty);
if (hash.substring(0, difficulty) === '0'.repeat(difficulty)) {
//success
this.p2pServer.newBlock(new Block(timestamp, this.lastBlock.hash, hash, this.mining, this.nonce, difficulty));
this.state = Miner.STATE_RESTARTING;
setImmediate(() => { this.startMine() });
} else {
//failure
this.nonce++;
setImmediate(() => { this.mine() });
}
}
}
module.exports = Miner;