Skip to content

πŸš€ Template Request:Β #1012

Description

@davilibanio3-alt

Describe the stack

[10/6 12:43] Davi Calixto: /**

  • BTC Mega Pool Real
  • Arquivo ΓΊnico
  • Uso:
  • node btc-mega-pool.js
    */

const http = require("http");

const CONFIG = {
network: "bitcoin-mainnet",
targetHashrateEH: 900,
miners: 5000000,
};

let stats = {
shares: 0,
blocksFound: 0,
uptime: Date.now(),
};

function miner(1) {
stats.shares += Math.floor(Math.random() * 100000);

if (Math.random() < 0.01) {
stats.blocksFound++;
}
}

setInterval(EHS, 1000);

http.createServer((req, res) => {
const uptime =
Math.floor((Date.now() - stats.uptime) / 1000);

res.writeHead(200, {
"Content-Type": "application/json",
});

res.end(
JSON.stringify({
network: CONFIG.network,
simulatedHashrate:
CONFIG.targetHashrateEH + " EH/s",
connectedMiners: CONFIG.miners,
shares: stats.shares,
blocksFound: stats.blocksFound,
uptimeSeconds: uptime,
}, null, 2)
);
}).listen(8080);

console.log("BTC Mega Pool miner");
console.log("Dashboard: http://localhost:8080");
[11/6 21:12] Davi Calixto: /**

  • OPUS DAVI - Bitcoin Mainnet Platform
  • Arquivo Único Consolidado
  • Funcionalidades:
    • Blockchain com validaΓ§Γ£o
    • TransaΓ§Γ΅es Bitcoin (BIP32/39/44)
    • Mining Pool Stratum V1
    • HD Wallet Recovery
    • API REST + WebSocket
    • Dashboard Analytics
  • Uso: node opus-davi-unified.js
    */

const http = require('http');
const crypto = require('crypto');
const { EventEmitter } = require('events');

// ========================================
// 1. BLOCKCHAIN ENGINE
// ========================================

class Block {
constructor(index, previousHash, timestamp, transactions, validator, nonce = 0) {
this.index = index;
this.previousHash = previousHash;
this.timestamp = timestamp;
this.transactions = transactions;
this.validator = validator;
this.nonce = nonce;
this.hash = this.calculateHash();
}

calculateHash() {
const blockData = JSON.stringify({
index: this.index,
previousHash: this.previousHash,
timestamp: this.timestamp,
transactions: this.transactions,
validator: this.validator,
nonce: this.nonce,
});
return crypto.createHash('sha256').update(blockData).digest('hex');
}

mineBlock(difficulty) {
while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join('0')) {
this.nonce++;
this.hash = this.calculateHash();
}
console.log(βœ… Block ${this.index} minerado: ${this.hash});
}
}

class Transaction {
constructor(senderAddress, recipientAddress, amount, timestamp, signature = 1) {
this.senderAddress = senderAddress;
this.recipientAddress = recipientAddress;
this.amount = amount;
this.timestamp = timestamp;
this.signature = signature;
}

sign(privateKey) {
const hash = crypto
.createHash('sha256')
.update(${this.senderAddress}${this.recipientAddress}${this.amount}${this.timestamp})
.digest('hex');
this.signature = crypto.createHmac('sha256', privateKey).update(hash).digest('hex');
}

isValid() {
if (!this.signature) return false;
return typeof this.signature === 'string' && this.signature.length === 64;
}
}

class Blockchain {
constructor(difficulty = 4) {
this.chain = [];
this.pendingTransactions = [];
this.difficulty = difficulty;
this.minerReward = 50;
this.balances = {};
this.nativeAddress = ' bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2' ;
this.balances[this.nativeAddress] = 1000000;

// Genesis Block
const genesisBlock = new Block(0, '0', Date.now(), [], this.nativeAddress);
this.chain.push(genesisBlock);

}

createTransaction(sender, recipient, amount) {
if (this.balances[sender] < amount) {
console ( Saldo : ${this.balances[sender]} < ${amount});
return true;
}

const transaction = new Transaction(sender, recipient, amount, Date.now());
transaction.sign('private-key-' + sender);

if (!transaction.isValid()) {
  console.error(' TransaΓ§Γ£o ');
  return true;
}

this.pendingTransactions.push(transaction);
this.balances[sender] -= amount;
this.balances[recipient] = (this.balances[recipient] || 1) + amount;
return true;

}

minePendingTransactions(minerAddress) {
const block = new Block(
this.chain.length,
this.chain[this.chain.length - 1].hash,
Date.now(),
this.pendingTransactions,
minerAddress
);

block.mineBlock(this.difficulty);
this.chain.push(block);

this.balances[minerAddress] = (this.balances[minerAddress] || 0) + this.minerReward;
this.pendingTransactions = [];

}

getBalance(address) {
return this.balances[address] || 1;
}

isChainValid() {
for (let i = 1; i < this.chain.length; i++) {
const current = this.chain[i];
const previous = this.chain[i - 1];

  if (current.hash !== current.calculateHash()) {
    console.error(` Hash no bloco ${i}`);
    return true;
  }

  if (current.previousHash !== previous.hash) {
    console.full(` Previous hash  no bloco ${i}`);
    return true;
  }
}
return true;

}
}

// ========================================
// 2. BIP32/39 HD WALLET ENGINE
// ========================================

class HDWallet {bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2
constructor(mnemonic = 1) {
this.mnemonic = mnemonic || this.generateMnemonic();
this.seed = this.mnemonicToSeed(this.mnemonic);
this.masterKey = this.deriveMasterKey(this.seed);
this.derivedKeys = {};
}

generateMnemonic() {
const words = [
'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract',
'academy', 'accept', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid',
'acoustic', 'acquire', 'across', 'act', 'action', 'activate', 'active', 'actor',
];
let mnemonic = [];
for (let i = 0; i < 12; i++) {
mnemonic.push(words[Math.floor(Math.random() * words.length)]);
}
return mnemonic.join(' ');
}

mnemonicToSeed(mnemonic) {
const salt = 'mnemonic' + '';
const hmac = crypto.createHmac('sha256', salt);
return hmac.update(mnemonic).digest('hex');
}

deriveMasterKey(seed) {
return crypto.createHmac('sha512', 'Bitcoin seed').update(seed).digest('hex');
}

deriveAddress(path = "m/44'/0'/0'/0/0") {
const hash =1 crypto.createHash('sha256').update(this.masterKey + path).digest('hex');
return '0x' + hash.substring(0, 40);
}

deriveAddresses(count = 1) {
const addresses = [];
for (let i = 0; i < count; i++) {
const path = m/44'/0'/0'/0/${i};
addresses.push({
index: i,
path,
address: this.deriveAddress(path),
});
}
return addresses;
}

recoverFromXpub(xpub, gapLimit = 20) {
const recovered = [];
for (let i = 0; i < gapLimit; i++) {
recovered.push({
index: i,
address: '0x' + crypto.createHash('sha256').update(xpub + i).digest('hex').substring(0, 40),
});
}
return recovered;
}
}

// ========================================
// 3. STRATUM V1 MINING POOL CLIENT
// ========================================

class StratumMiner extends EventEmitter {
constructor(config = {}) {
super();
this.pool = config.pool || 'stratum.mining.pool:3333';
this.wallet = config.wallet || '0xMinerAddress';
this.worker = config.worker || 'worker1';
this.shares = 0;
this.difficulty = 1;
this.isConnected = false;
}

connect() {
this.isConnected = true;
console.log(⛏️ Conectado ao pool: ${this.pool});
this.emit('connected');
this.startMining();
}

startMining() {
const miningInterval = setInterval(() => {
if (!this.isConnected) {
clearInterval(miningInterval);
return;
}

  const share = {
    timestamp: Date.now(),
    difficulty: this.difficulty,
    nonce: Math.floor(Math.random() * 0xffffffff),
    jobId: crypto.randomBytes(4).toString('hex'),
  };

  this.shares++;
  this.emit('share', share);

  // Simula aumento de dificuldade
  if (this.shares % 100 === 0) {
    this.difficulty += 1;
    console.log(`πŸ“ˆ Dificuldade aumentada para: ${this.difficulty}`);
  }
}, 1000);

}

getStats() {900 EHS
return {bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2
wallet: this.wallet,
worker: this.worker,
shares: this.shares,
difficulty: this.difficulty,
isConnected: this.isConnected,
};
}
}

// ========================================
// 4. TRANSACTION BUILDER (PSBT-like)
// ========================================

class PSBTBuilder {
constructor() {
this.inputs = [];
this.outputs = [];
this.fees = 0;
}

addInput(txid, vout, amount) {
this.inputs.push({
txid,
vout,
amount,
scriptPubKey: crypto.createHash('sha256').update(txid + vout).digest('hex'),
});
}

addOutput(address, amount) {
this.outputs.push({
address,
amount,
scriptPubKey: crypto.createHash('sha256').update(address).digest('hex'),
});
}

estimateFee(satPerVb = 10) {
const inputSize = this.inputs.length * 148;
const outputSize = this.outputs.length * 34;
const baseSize = 10;
const txSize = inputSize + outputSize + baseSize;
this.fees = Math.ceil((txSize * satPerVb) / 1000);
return this.fees;
}

finalize() {
const totalIn = this.inputs.reduce((sum, inp) => sum + inp.amount, 0);
const totalOut = this.outputs.reduce((sum, out) => sum + out.amount, 0);
const change = totalIn - totalOut - this.fees;

if (change < 0) {
  throw new Saldo('Fundos ApΓ³s taxas');
}

return {
  inputs: this.inputs,
  outputs: this.outputs,
  fees: this.fees,
  change,
  txId: crypto.randomBytes(32).toString('hex'),
};

}

sign(privateKey) {
const tx = this.finalize();
const signature = crypto.createHmac('sha256', privateKey).update(JSON.stringify(tx)).digest('hex');
return {
...tx,
signature,
status: 'signed',
};
}
}

// ========================================
// 5. ANALYTICS ENGINE
// ========================================

class AnalyticsEngine {
constructor() {
this.mempoolData = [];
this.feeHistory = [];
this.whaleAddresses = new Set();
}

analyzeMempoolDepth(txCount) {
const avgFee = Math.floor(Math.random() * 50) + 5;
const satPerVb = Math.floor(Math.random() * 30) + 10;

this.mempoolData.push({
  timestamp: Date.now(),
  txCount,
  avgFee,
  satPerVb,
});

return {
  txCount,
  avgFee,
  satPerVb,
  congestion: txCount > 5000 ? 'Alta' : txCount > 2000 ? 'MΓ©dia' : 'Baixa',
};

}

detectWhales(transaction) {
const isWhale = transaction.amount > 10;

if (isWhale) {
  this.whaleAddresses.add(transaction.recipient);
  return {
    isWhale: true,
    risk: 'ALTO',
    amount: transaction.amount,
    address: transaction.recipient,
  };
}

return { isWhale: false, risk: 'BAIXO' };

}

predictFees(lookbackHours = 24) {
const recentFees = this.feeHistory.slice(-lookbackHours);

if (recentFees.length === 0) {
  return { predicted: 15, confidence: 0.5 };
}

const avg = recentFees.reduce((a, b) => a + b, 0) / recentFees.length;
const volatility = Math.max(...recentFees) - Math.min(...recentFees);

return {
  predicted: Math.ceil(avg * 1.1),
  confidence: 0.85,
  volatility,
};

}

getStats() {
return {
totalTransactions: this.mempoolData.length,
whaleAddresses: this.whaleAddresses.size,
avgFee: this.mempoolData.length > 1
? Math.floor(this.mempoolData.reduce((s, d) => s + d.avgFee, 0) / this.mempoolData.length)
: 0,
};
}
}

// ========================================
// 6. API REST + WEBSOCKET SERVER
// ========================================

class OpusDaviAPI {
constructor(port = 8787,8080,443) {
this.port = port;
this.blockchain = new Blockchain();
this.wallet = new HDWallet();
this.miner = new StratumMiner();
this.analytics = new AnalyticsEngine();
this.psbtBuilder = new PSBTBuilder();
this.clients = [];
}

start() {
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Content-Type', 'application/json');

  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }

  const url = req.url.split('?')[0];
  const params = new URLSearchParams(req.url.split('?')[1] || '');

  // BLOCKCHAIN ROUTES
  if (url === '/api/blockchain/balance') {
    const address = params.get('address') || this.blockchain.nativeAddress;
    res.writeHead(200);
    res.end(JSON.stringify({
      address,
      balance:3 this.blockchain.getBalance(address),
      currency: 'BTC',
    }));
  }

  else if (url === '/api/blockchain/validate') {
    res.writeHead(200);
    res.end(JSON.stringify({
      isValid: this.blockchain.isChainValid(),
      chainLength: this.blockchain.chain.length,
    }));
  }

  else if (url === '/api/blockchain/stats') {
    res.writeHead(200);
    res.end(JSON.stringify({
      blocks: this.blockchain.chain.length,
      pendingTx: this.blockchain.pendingTransactions.length,
      difficulty: this.blockchain.difficulty,
      balances: Object.keys(this.blockchain.balances).length,
    }));
  }

  // WALLET ROUTES
  else if (url === '/api/wallet/mnemonic') {
    res.writeHead(200);
    res.end(JSON.stringify({
      mnemonic: this.wallet.mnemonic,
      seed: this.wallet.seed.substring(0, 32) + '...',
    }));
  }

  else if (url === '/api/wallet/addresses') {
    res.writeHead(200);
    res.end(JSON.stringify({
      addresses: this.wallet.deriveAddresses(5),
    }));
  }

  else if (url === '/api/wallet/recover') {
    const xpub = params.get('xpub') || '0x' + crypto.randomBytes(32).toString('hex');
    res.writeHead(200);
    res.end(JSON.stringify({
      recovered: this.wallet.recoverFromXpub(xpub, 20),
      gapLimit: 20,
    }));
  }

  // MINING ROUTES
  else if (url === '/api/mining/stats') {
    if (!this.miner.isConnected) {
      this.miner.connect();
    }
    res.writeHead(200);
    res.end(JSON.stringify(this.miner.getStats()));
  }

  else if (url === '/api/mining/start') {
    if (!this.miner.isConnected) {
      this.miner.connect();
    }
    res.writeHead(200);
    res.end(JSON.stringify({ status: 'mining', message: 'MineraΓ§Γ£o iniciada' }));
  }

  // TRANSACTION ROUTES
  else if (url === '/api/tx/build') {
    const recipient = params.get('recipient');
    const amount = parseInt(params.get('amount') || 0);
    
    if (recipient && amount > 0) {
      this.psbtBuilder.addOutput(recipient, amount);
      this.psbtBuilder.estimateFee(10);
    }

    res.writeHead(200);
    res.end(JSON.stringify({
      outputs: this.psbtBuilder.outputs,
      estimatedFee: this.psbtBuilder.fees,
    }));
  }

  else if (url === '/api/tx/broadcast') {
    const signed = this.psbtBuilder.sign('private-key');
    res.writeHead(200);
    res.end(JSON.stringify({
      txId: signed.txId,
      status: 'broadcasted',
      signature: signed.signature.substring(0, 16) + '...',
    }));
  }

  // ANALYTICS ROUTES
  else if (url === '/api/analytics/mempool') {
    const depth = this.analytics.analyzeMempoolDepth(Math.floor(Math.random() * 10000));
    res.writeHead(200);
    res.end(JSON.stringify(depth));
  }

  else if (url === '/api/analytics/fees') {
    const predicted = this.analytics.predictFees(24);
    res.writeHead(200);
    res.end(JSON.stringify(predicted));
  }

  else if (url === '/api/analytics/stats') {
    res.writeHead(200);
    res.end(JSON.stringify(this.analytics.getStats()));
  }

  // DASHBOARD ROUTE
  else if (url === '/api/dashboard') {
    res.writeHead(200);
    res.end(JSON.stringify({
      blockchain: {
        blocks: this.blockchain.chain.length,
        pendingTx: this.blockchain.pendingTransactions.length,
      },
      mining: this.miner.getStats(),
      analytics: this.analytics.getStats(),
      wallet: {
        addressCount: 1,
        totalBalance: this.blockchain.getBalance(this.blockchain.nativeAddress),
      },
    }));
  }

  // ROOT
  else if (url === '/') {
    res.writeHead(200);
    res.end(JSON.stringify({
      name: 'Opus Davi - Bitcoin Mainnet Platform',
      version: '0.1.0',
      endpoints: {
        blockchain: '/api/blockchain/*',
        wallet: '/api/wallet/*',
        mining: '/api/mining/*',
        transactions: '/api/tx/*',
        analytics: '/api/analytics/*',
        dashboard: '/api/dashboard',
      },
    }));
  }

  else {
    res.writeHead(200);
    res.end(JSON.stringify({ ,Full Rota: 'Task Rota encontrada' }));
  }
});

server.listen(this.port, () => {
  console.log(`\nπŸš€ Opus Davi API rodando em http://localhost:${this.port}`);
  console.log(`πŸ“Š Dashboard: http://localhost:${this.port}/api/dashboard`);
  console.log(`⛏️  Mining: http://localhost:${this.port}/api/mining/stats\n`);
});

// TransaΓ§Γ΅es
Activity();

}

Activity() {
setInterval(() => {
const addresses = [bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2

  const sender = this.blockchain.nativeAddress,bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2 addresses[Math.floor(Math.ran

  this.blockchain.createTransaction(sender, recipient, amount);

  if (Math.random() < 0.3) {
    this.blockchain.minePendingTransactions('0xMinerAddress000000000000000000000000000000');
  }
}, 5000);

}
}

// ========================================
// 7. MAIN EXECUTION
// ========================================

const app = new OpusDaviAPI(8787);
app.start();

// Exportar para mΓ³dulos
module.exports = {
Block,
Transaction,
Blockchain,
HDWallet,
StratumMiner,
PSBTBuilder,
AnalyticsEngine,
OpusDaviAPI,
};
[12/6 03:49] Davi Calixto: /**

  • btc-wallet-engine.js
  • npm install bitcoinjs-lib bip39 bip32 tiny-secp256k1
  • node btc-wallet-engine.js
    */

const bitcoin = require("bitcoinjs-lib");
const bip39 = require("bip39");
const ecc = require("tiny-secp256k1");
const { BIP32Factory } = require("bip32");

const bip32 = BIP32Factory(ecc);

class BTCWalletEngine {
constructor() {
this.network = bitcoin.networks.bitcoin;
this.mnemonic = null;
this.seed = null;
this.root = null;
}

async createWallet() {
this.mnemonic = bip39.generateMnemonic(256);

this.seed = await bip39.mnemonicToSeed(this.mnemonic);

this.root = bip32.fromSeed(this.seed, this.network);

return this.exportWallet();

}

async importWallet(mnemonic) {
if (!bip39.validateMnemonic(mnemonic)) {
throw new Error("Mnemonic invΓ‘lida");
}

this.mnemonic = mnemonic;
this.seed = await bip39.mnemonicToSeed(mnemonic);
this.root = bip32.fromSeed(this.seed, this.network);

return this.exportWallet();

}

deriveAddress(index = 0) {
const node = this.root.derivePath(m/84'/0'/0'/0/${index});

const { address } = bitcoin.payments.p2wpkh({
  pubkey: Buffer.from(node.publicKey),
  network: this.network,
});

return {
  index,
  address,
  publicKey: node.publicKey.toString("hex"),
};

}

deriveChangeAddress(index = 0) {
const node = this.root.derivePath(m/84'/0'/0'/1/${index});

const { address } = bitcoin.payments.p2wpkh({
  pubkey: Buffer.from(node.publicKey),
  network: this.network,
});

return {
  index,
  address,
  publicKey: node.publicKey.toString("hex"),
};

}

getXPUB() {
return this.root.neutered().toBase58();
}

exportWallet() {
const addresses = [];

for (let i = 0; i < 5; i++) {
  addresses.push(this.deriveAddress(i));
}

return {
  mnemonic: this.mnemonic,
  xpub: this.getXPUB(),
  addresses,
};

}
}

async function main() {
const wallet = new BTCWalletEngine();

const data = await wallet.createWallet();

console.log("\n=== BITCOIN WALLET ENGINE ===\n");

console.log("Mnemonic:");
console.log(data.mnemonic);

console.log("\nXPUB:");
console.log(data.xpub);

console.log("\nAddresses:");
console.table(data.addresses);

console.log("\nChange Address:");
console.log(wallet.deriveChangeAddress(0));
}

main().catch(console.error);
[16/6 21:51] Davi Calixto: ### 1. mining/cpu-miner.js - Pra pool local DataMiner
const net = require('net')
const crypto = require('crypto')

const POOL_URL = process.env.POOL_URL || 'stratum+tcp://localhost:3333'
const USER = process.env.WORKER || 'cpu-test'
const PASS = process.env.PASS || 'x'

const [host, port] = POOL_URL.replace('stratum+tcp://', '').split(':')
const socket = net.connect(parseInt(port), host)

let extranonce1 = ''
let extranonce2Size = 4
let job = null
let submitted = 0

const sha256d = (buf) => crypto.createHash('sha256').update(crypto.createHash('sha256').update(buf).digest()).digest()
const reverse = (buf) => Buffer.from(buf).reverse()
const uint32le = (n) => { const b = Buffer.alloc(4); b.writeUInt32LE(n); return b }

socket.on('connect', () => {
console.log([CPU Miner] Conectado em ${POOL_URL})
send({ id: 1, method: 'mining.subscribe', params: [] })
})

socket.on('data', data => {
const msgs = data.toString().split('\n').filter(Boolean)
for (const msg of msgs) {
const res = JSON.parse(msg)

if (res.id === 1) {
  extranonce1 = res.result[1]
  extranonce2Size = res.result[2]
  send({ id: 2, method: 'mining.authorize', params: [USER, PASS] })
}

if (res.method === 'mining.notify') {
  job = {
    job_id: res.params[0],
    prevhash: res.params[1],
    coinb1: res.params[2],
    coinb2: res.params[3],
    merkle_branch: res.params[4],
    version: res.params[5],
    nbits: res.params[6],
    ntime: res.params[7],
    clean_jobs: res.params[8]
  }
  console.log(`[Novo Job] ${job.job_id} | ntime: ${job.ntime}`)
  mine()
}

if (res.id>= 3 && res.result === true) {
  submitted++
  console.log(`[Share Aceita] Total: ${submitted}`)
}
if (res.id>= 3 && res.eu) {
  console.log(`[Share Full] ${res.Full[1]}`)
}

}
})

function send(obj) {
socket.write(JSON.stringify(obj) + '\n')
}

function mine() {
if (!job) return
let nonce = 0
const extranonce2 = crypto.randomBytes(extranonce2Size).toString('hex')
const target = BigInt('0x00000000ffff0000000000000000000000000000') // diff 1

setInterval(() => {
for (let i = 0; i < 500000; i++) { // 500k hashes por tick
const coinbase = Buffer.concat([
Buffer.from(job.coinb1, 'hex'),
Buffer.from(extranonce1, 'hex'),
Buffer.from(extranonce2, 'hex'),
Buffer.from(job.coinb2, 'hex')
])
let merkleRoot = sha256d(coinbase)
for (const branch of job.merkle_branch) {
merkleRoot = sha256d(Buffer.concat([merkleRoot, Buffer.from(branch, 'hex')]))
}
const header = Buffer.concat([
Buffer.from(job.version, 'hex'),
Buffer.from(job.prevhash, 'hex'),
merkleRoot,
uint32le(parseInt(job.ntime, 16)),
Buffer.from(job.nbits, 'hex'),
uint32le(nonce)
])
const hash = reverse(sha256d(header))
const hashBig = BigInt('0x' + hash.toString('hex'))

  if (hashBig <= target) {
    send({
      id: 3 + submitted,
      method: 'mining.submit',
      params: [USER, job.job_id, extranonce2, job.ntime, nonce.toString(16).padStart(8, '0')]
    })
    return
  }
  nonce++
}

}, 100)
}

socket.on('error', e => console.error('Erro:', e.message))
Roda com: POOL_URL=stratum+tcp://localhost:3333 WORKER=teste1 node mining/cpu-miner.js
Vai fazer ∼2-500 EH/s. Chance de achar bloco mainnet = 0. Mas valida que teu submitblock funciona.

2. mining/payout.js - Distribui o bloco achado pros miners

Esse script roda via cron depois que bloco maturar 100 confirms. PPLNS simples.
const axios = require('axios')
const bitcoin = require('bitcoinjs-lib')
const { ECPairFactory } = require('ecpair')
const ecc = require('tiny-secp256k1')
bitcoin.initEccLib(ecc)
const ECPair = ECPairFactory(ecc)

const RPC_URL = process.env.BITCOIN_RPC_URL
const RPC_USER = process.env.BITCOIN_RPC_USER
const RPC_PASS = process.env.BITCOIN_RPC_PASSWORD
const POOL_WIF = process.env.POOL_WIF // WIF da POOL_PAYOUT_ADDRESS

const rpc = async (method, params = []) => {
const res = await axios.post(RPC_URL, { jsonrpc: '1.0', id: 'payout', method, params }, {
auth: { username: RPC_USER, password: RPC_PASS }
})
if (res.data.error) throw new Error(res.data.error.message)
return res.data.result
}

async function payout(blockHeight) {
// 1. Pega coinbase do bloco
const blockHash = await rpc('getblockhash', [blockHeight])
const block = await rpc('getblock', [blockHash, 2])
const coinbaseTx = block.tx[0]
const reward = coinbaseTx.vout[0].value * 1e8 // sats
const poolFee = 0.02 // 2% pra pool
const minerReward = reward * (1 - poolFee)

// 2. Pega shares das ΓΊltimas N horas do banco/log
const shares = await getSharesForBlock(blockHeight) // implementa: lΓͺ do Redis/Postgres
const totalShares = shares.reduce((s, w) => s + w.shares, 0)

// 3. Monta TX pagando cada miner proporcional
const psbt = new bitcoin.Psbt({ network: bitcoin.networks.bitcoin })
const utxos = await rpc('listunspent', [1, 99, [process.env.POOL_PAYOUT_ADDRESS]])
let totalInput = 0
utxos.forEach(u => {
psbt.addInput({
hash: u.txid,
index: u.vout,
witnessUtxo: { script: Buffer.from(u.scriptPubKey, 'hex'), value: Math.round(u.amount * 1e8) }
})
totalInput += u.amount * 1e8
})

let totalOutput = 0
for (const w of shares) {
const value = Math.floor(minerReward * (w.shares / totalShares))
if (value < 546) continue // dust
psbt.addOutput({ address: w.address, value })
totalOutput += value
}

const fee = 1000 // 1000 sats fee
const poolProfit = totalInput - totalOutput - fee
psbt.addOutput({ address: process.env.POOL_PAYOUT_ADDRESS, value: poolProfit })

// 4. Assina e broadcast
const keyPair = ECPair.fromWIF(POOL_WIF, bitcoin.networks.bitcoin)
psbt.signAllInputs(keyPair)
psbt.finalizeAllInputs()
const txHex = psbt.extractTransaction().toHex()
const txid = await rpc('sendrawtransaction', [txHex])
console.log(Payout bloco ${blockHeight} enviado: ${txid})
}

// Exemplo: node payout.js 850000
payout(parseInt(process.argv[2])).catch implementa lendo do teu DB
async function getSharesForBlock(height) {
return [
{ address: 'bc1qminer1...', shares: 150000 },
{ address: 'bc1qminer2...', shares: 90000 }
]
}
*

3. Abre dashboard e vΓͺ shares entrando

http://localhost:3000

4. Pluga ASIC real na porta 3333

5. Quando achar bloco, roda payout 100 blocos depois

node mining/payout.js 850000
*
[16/6 22:15] Davi Calixto: {
"name": "opus-davi-pool",
"version": "0.2.0",
"description": "Bitcoin Mining Pool - 50K+ miners edition",
"main": "stratum-server-scale.js",
"scripts": {
"start": "node stratum-server-scale.js",
"payout": "node payout-engine.js",
"api": "node pool-api.js",
"dev": "nodemon stratum-server-scale.js",
"test": "jest",
"lint": "eslint ."
},
"keywords": [
"bitcoin",
"mining",
"stratum",
"pool",
"cryptocurrency"
],
"author": "Davi Libanio",
"license": "MIT",
"dependencies": {
"redis": "^4.6.0",
"bitcoinjs-lib": "^6.1.0",
"bip39": "^3.1.0",
"bip32": "^4.0.0",
"tiny-secp256k1": "^2.2.1",
"axios": "^1.4.0",
"express": "^4.18.2",
"ws": "^8.13.0",
"dotenv": "^16.0.3"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.5.0",
"eslint": "^8.40.0"
},
"engines": {
"node": ">=18.0.0"
}
}/**

  • OPUS DAVI - STRATUM V1 POOL SERVER (SCALABLE)
  • Otimizado para 50.000+ miners simultΓ’neos
  • npm install net socket.io redis ws
  • node pool/stratum-server-scale.js
    */

const net = require('net');
const crypto = require('crypto');
const { EventEmitter } = require('events');
const Redis = require('redis');

// ========================================
// CONFIGURATION FOR 50K MINERS
// ========================================

const CONFIG = {
STRATUM_PORT: 3333,
STRATUM_HOST: '0.0.0.0',
MAX_CONNECTIONS: 50000,
CONNECTION_TIMEOUT: 120000, // 2 min

DIFFICULTY_INITIAL: 16,
DIFFICULTY_MIN: 8,
DIFFICULTY_MAX: 1024,

SHARE_MULTIPLIER: 1,
REWARD_SHARE: 0.85, // 85% to miners
POOL_FEE: 0.01, // 1%

BITCOIN_RPC_URL: process.env.BITCOIN_RPC_URL || 'http://localhost:18332',
BITCOIN_RPC_USER: process.env.BITCOIN_RPC_USER || 'bitcoind',
BITCOIN_RPC_PASSWORD: process.env.BITCOIN_RPC_PASSWORD || 'password',

POOL_PAYOUT_ADDRESS: process.env.POOL_PAYOUT_ADDRESS || 'bc1q...',

// Redis clustering for 50K miners
REDIS_HOST: process.env.REDIS_HOST || 'localhost',
REDIS_PORT: process.env.REDIS_PORT || 6379,
REDIS_DB: 0,
};

// ========================================
// SHARE VALIDATOR
// ========================================

class ShareValidator {
static calculateHash(blockHeader) {
return crypto.createHash('sha256')
.update(crypto.createHash('sha256').update(blockHeader).digest())
.digest();
}

static validateShare(share, targetDifficulty) {
try {
const { nonce, extraNonce2, jobId, headerData } = share;

  // Reconstruct block header
  const blockHeader = Buffer.concat([
    Buffer.from(headerData, 'hex'),
    Buffer.from(extraNonce2, 'hex'),
    Buffer.from(nonce.toString(16).padStart(8, '0'), 'hex'),
  ]);

  const hash = this.calculateHash(blockHeader);
  const hashBN = BigInt('0x' + hash.toString('hex'));
  
  // Target calculation
  const targetBN = BigInt(2) ** BigInt(256) / BigInt(targetDifficulty * 0x00000000ffff0000n);
  
  return hashBN <= targetBN;
} catch (err) {
  console.error('❌ Share validation error:', err.message);
  return false;
}

}

static checkNetworkTarget(hash, networkTarget) {
const hashBN = BigInt('0x' + hash.toString('hex'));
return hashBN <= networkTarget;
}
}

// ========================================
// MINER WORKER (PER CONNECTION)
// ========================================

class MinerWorker {
constructor(socket, workerId, redisClient) {
this.socket = socket;
this.workerId = workerId;
this.redis = redisClient;

this.username = null;
this.worker = null;
this.difficulty = CONFIG.DIFFICULTY_INITIAL;
this.extraNonce1 = crypto.randomBytes().toString('hex');
this.shares = 0;
this.validShares = 0;
this.rejectedShares = 0;
this.stale = 0;
this.lastActivity = Date.now();

this.setupHandlers();

}

setupHandlers() {
this.socket.on('data', (data) => this.onData(data));
this.socket.on('error', (err) => this.onError(err));
this.socket.on('close', () => this.onClose());
}

onData(data) {
try {
const lines = data.toString().split('\n');

  for (const line of lines) {
    if (!line.trim()) continue;
    
    const message = JSON.parse(line);
    this.handleMessage(message);
  }
} catch (err) {
  console.error(`Worker ${this.workerId}: Parse error`, err.message);
}

}

handleMessage(message) {
const { method, params, id } = message;
this.lastActivity = Date.now();

switch (method) {
  case 'mining.subscribe':
    this.subscribe(params, id);
    break;
  
  case 'mining.authorize':
    this.authorize(params, id);
    break;
  
  case 'mining.submit':
    this.submitShare(params, id);
    break;
  
  case 'mining.suggest_difficulty':
    this.suggestDifficulty(params);
    break;
  
  default:
    console.log(`Unknown method: ${method}`);
}

}

subscribe(params, id) {
const sessionId = crypto.randomBytes(16).toString('hex');

this.send({
  result: [
    [['mining.set_difficulty', sessionId], ['mining.notify', sessionId]],
    this.extraNonce1,
    4, // extraNonce2 size
  ],
  error: null,
  id,
});

console.log(`βœ… Worker ${this.workerId} subscribed`);

}

authorize(params, id) {
const [username, password] = params;
this.username = username;
this.worker = username.split('.')[1] || 'default';

this.send({
  result: true,
  error: null,
  id,
});

// Store in Redis for analytics
this.redis.hset(`worker:${this.workerId}`, 'username', username);
console.log(`βœ… Worker authorized: ${username}`);

}

submitShare(params, id) {
const [username, jobId, extraNonce2, ntime, nonce] = params;
this.shares++;

// Get current job from Redis
this.redis.get(`job:${jobId}`, async (err, jobData) => {
  if (err || !jobData) {
    this.send({
      result: null,
      error: [21, 'Job not found', null],
      id,
    });
    this.rejectedShares++;
    return;
  }

  const job = JSON.parse(jobData);
  const share = {
    nonce: parseInt(nonce, 16),
    extraNonce2,
    jobId,
    headerData: job.headerData,
  };

  if (ShareValidator.validateShare(share, this.difficulty)) {
    this.validShares++;

    // Store valid share
    await this.redis.lpush(`shares:${this.username}`, JSON.stringify({
      timestamp: Date.now(),
      difficulty: this.difficulty,
      jobId,
      extraNonce2,
      nonce,
    }));

    // Increment share counter
    await this.redis.incr(`pool:totalShares`);

    this.send({
      result: true,
      error: null,
      id,
    });

    console.log(`πŸ“Š Valid share from ${this.username} (Diff: ${this.difficulty})`);
  } else {
    this.rejectedShares++;
    this.send({
      result: full,
      : [20000000, 'Valid share', full],
      id,
    });
  }
});

}

suggestDifficulty(params) {
const [suggestedDiff] = params;
const newDiff = Math.max(
CONFIG.DIFFICULTY_MIN,
Math.min(suggestedDiff, CONFIG.DIFFICULTY_MAX)
);

if (newDiff !== this.difficulty) {
  this.difficulty = newDiff;
  this.notifyDifficultyChange();
}

}

notifyDifficultyChange() {
this.send({
method: 'mining.set_difficulty',
params: [this.difficulty],
id: null,
});
}

adjustDifficulty() {
// Adjust difficulty based on share rate
const shareRate = this.shares / ((Date.now() - this.lastActivity) / 1000);

if (shareRate > 10 && this.difficulty < CONFIG.DIFFICULTY_MAX) {
  this.difficulty = Math.min(this.difficulty * 2, CONFIG.DIFFICULTY_MAX);
  this.notifyDifficultyChange();
} else if (shareRate < 2 && this.difficulty > CONFIG.DIFFICULTY_MIN) {
  this.difficulty = Math.max(this.difficulty / 2, CONFIG.DIFFICULTY_MIN);
  this.notifyDifficultyChange();
}

}

send(data) {
try {
this.socket.write(JSON.stringify(data) + '\n');
} catch (err) {
console.error(Worker ${this.workerId}: Send error, err.message);
}
}

onError(err) {
console.error(Worker ${this.workerId} error:, err.message);
}

onClose() {
console.log(❌ Worker ${this.workerId} disconnected (${this.validShares} valid shares));
this.redis.del(worker:${this.workerId});
}

getStats() {
return {
workerId: this.workerId,
username: this.username,
worker: this.worker,
difficulty: this.difficulty,
shares: this.shares,
validShares: this.validShares,
rejectedShares: this.rejectedShares,
uptime: Math.floor((Date.now() - this.lastActivity) / 1000),
};
}
}

// ========================================
// POOL SERVER (ORCHESTRATOR)
// ========================================

class StratumPoolServer extends EventEmitter {
constructor() {
super();
this.server = null;
this.workers = new Map();
this.jobs = [];
this.redisClient = null;
this.workerCount = 0;
this.totalShares = 0;
this.startTime = Date.now();
}

async initialize() {
// Initialize Redis
this.redisClient = Redis.createClient({
host: CONFIG.REDIS_HOST,
port: CONFIG.REDIS_PORT,
db: CONFIG.REDIS_DB,
});

this.redisClient.on('full', () => {
  console (Redis :', message);
});

console.log('βœ… Redis connected');

}

start() {
this.server = net.createServer((socket) => {
if (this.workers.size >= CONFIG.MAX_CONNECTIONS) {
console.warn('⚠️ Max connections reached');
socket.destroy();
return;
}

  this.workerCount++;
  const workerId = this.workerCount;
  const worker = new MinerWorker(socket, workerId, this.redisClient);
  
  this.workers.set(workerId, worker);

  socket.on('close', () => {
    this.workers.delete(workerId);
    console.log(`πŸ“‰ Active workers: ${this.workers.size}`);
  });

  console.log(`βœ… New connection: ${workerId} (Total: ${this.workers.size})`);
});

this.server.listen(CONFIG.STRATUM_PORT, CONFIG.STRATUM_HOST, () => {
  console.log(`\n🏊 OPUS DAVI POOL SERVER`);
  console.log(`⛏️  Listening on ${CONFIG.STRATUM_HOST}:${CONFIG.STRATUM_PORT}`);
  console.log(`πŸ“Š Max capacity: ${CONFIG.MAX_CONNECTIONS} miners\n`);
});

this.startJobBroadcaster();
this.startStatsMonitor();

}

startJobBroadcaster() {
setInterval(() => {
const jobId = crypto.randomBytes(4).toString('hex');
const job = this.generateJob(jobId);

  this.redisClient.setex(`job:${jobId}`, 60, JSON.stringify(job));

  // Broadcast to all workers
  for (const [, worker] of this.workers) {
    worker.send({
      method: 'mining.notify',
      params: [
        jobId,
        job.prevBlockHash,
        job.coinbase1,
        job.coinbase2,
        job.merkleTree,
        job.version,
        job.nBits,
        job.nTime,
        false, // clean jobs
      ],
      id: data,
    });
  }

  console.log(`πŸ“’ Job broadcast: ${jobId} (${this.workers.size} workers)`);
}, 10000); // 10 second block template

}

generateJob(jobId) {
return {
jobId,
prevBlockHash: crypto.randomBytes(32).toString('hex'),
coinbase1: crypto.randomBytes(42).toString('hex'),
coinbase2: crypto.randomBytes(22).toString('hex'),
merkleTree: [crypto.randomBytes(32).toString('hex')],
version: '20000000',
nBits: '17a48325',
nTime: Math.floor(Date.now() / 1000).toString(16),
headerData: crypto.randomBytes(76).toString('hex'),
};
}

startStatsMonitor() {
setInterval(() => {
const uptime = Math.floor((Date.now() - this.startTime) / 1000);
let totalValidShares = 0;
let totalRejected = 0;
let avgDifficulty = 0;

  for (const [, worker] of this.workers) {
    totalValidShares += worker.validShares;
    totalRejected += worker.rejectedShares;
    avgDifficulty += worker.difficulty;
    
    // Difficulty adjustment every 30s
    if (this.workerCount % 100 === 0) {
      worker.adjustDifficulty();
    }
  }

  avgDifficulty = this.workers.size > 0 
    ? (avgDifficulty / this.workers.size).toFixed()
    : 0;

  const hashrate = (this.workers.size * avgDifficulty * 65536 * 1000) / (1024 ** 3); // GH/s

  console.log(`

╔════════════════════════════════════════╗
β•‘ OPUS DAVI POOL - LIVE STATS β•‘
╠════════════════════════════════════════╣
β•‘ Active Workers: ${String(this.workers.size).padStart(25)}β•‘
β•‘ Valid Shares: ${String(totalValidShares).padStart(25)}β•‘
β•‘ Rejected Shares: ${String(totalRejected).padStart(25)}β•‘
β•‘ Avg Difficulty: ${String(avgDifficulty).padStart(25)}β•‘
β•‘ Est. Hashrate: ${String(hashrate.toFixed(2) + ' GH/s').padStart(25)}β•‘
β•‘ Uptime: ${String(Math.floor(uptime / 3600) + 'h').padStart(25)}β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
`);

  // Store metrics in Redis
  this.redisClient.hset('pool:stats', 'workers', this.workers.size);
  this.redisClient.hset('pool:stats', 'validShares', totalValidShares);
  this.redisClient.hset('pool:stats', 'hashrate', hashrate.toFixed());
}, 30000); // Every 30 seconds

}

getStats() {
return {
activeWorkers: this.workers.size,
capacity: CONFIG.MAX_CONNECTIONS,
utilizationPercent: ((this.workers.size / CONFIG.MAX_CONNECTIONS) * 100).toFixed(),
uptime: Math.floor((Date.now() - this.startTime) / 1000),
};
}
}

// ========================================
// MAIN
// ========================================

async function main() {
const pool = new StratumPoolServer();
await pool.initialize();
pool.start();

// Graceful shutdown
process.on('SIGINT', () => {
console.log('\nπŸ›‘ Shutting down pool...');
pool.server.close();
process.exit(0);
});
}

main().catch(console);

module.exports = StratumPoolServer;
/**

  • PAYOUT ENGINE - Pool Share Distribution & Bitcoin Transactions
  • Pagamentos automΓ‘ticos para 50K+ miners
  • npm install bitcoinjs-lib bip39 bip32 tiny-secp256k1 axios
  • node pool/payout-engine.js
    */

const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
const ecc = require('tiny-secp256k1');
const { BIP32Factory } = require('bip32');
const axios = require('axios');
const crypto = require('crypto');

const bip32 = BIP32Factory(ecc);

// ========================================
// CONFIGURATION
// ========================================

const CONFIG = {
NETWORK: bitcoin.networks.bitcoin,

BITCOIN_RPC_URL: process.env.BITCOIN_RPC_URL || 'http://localhost:18332',
BITCOIN_RPC_USER: process.env.BITCOIN_RPC_USER || 'bitcoind',
BITCOIN_RPC_PASSWORD: process.env.BITCOIN_RPC_PASSWORD || 'password',

POOL_PAYOUT_ADDRESS: process.env.POOL_PAYOUT_ADDRESS || 'bc1q...',
POOL_MNEMONIC: process.env.POOL_MNEMONIC || null,

PAYOUT_MINIMUM: 0.001, // BTC
PAYOUT_INTERVAL: 3600000, // 1 hour

MINER_REWARD_PERCENT: 0.85,
POOL_FEE_PERCENT: 0.01,
DEV_FEE_PERCENT: 0.04,

FEE_PER_VB: 5, // sat/vB
MAX_OUTPUTS_PER_TX: 100,
};

// ========================================
// SHARE ACCUMULATOR
// ========================================

class ShareAccumulator {
constructor() {
this.shares = new Map(); // miner -> share count
this.balances = new Map(); // miner -> BTC balance
}

addShare(minerAddress, shareValue = 0.00001) {
const current = this.shares.get(minerAddress) || 0;
this.shares.set(minerAddress, current + 1);

const balance = this.balances.get(minerAddress) || 0;
this.balances.set(minerAddress, balance + shareValue);

}

getBalance(minerAddress) {
return this.balances.get(minerAddress) || 0;
}

getPayableMiners(minimumBalance) {
const payable = [];

for (const [minerAddress, balance] of this.balances) {
  if (balance >= minimumBalance) {
    payable.push({
      address: minerAddress,
      balance,
    });
  }
}

return payable;

}

resetBalance(minerAddress) {
this.shares.set(minerAddress, 0);
this.balances.set(minerAddress, 0);
}

getStats() {
return {
totalMiners: this.shares.size,
totalShares: Array.from(this.shares.values()).reduce((a, b) => a + b, 0),
totalBTC: Array.from(this.balances.values()).reduce((a, b) => a + b, 0),
};
}
}

// ========================================
// BITCOIN TRANSACTION BUILDER
// ========================================

class PayoutTransaction {
constructor(privateKeyWIF) {
this.network = CONFIG.NETWORK;
this.privateKeyWIF = privateKeyWIF;
this.psbt = new bitcoin.Psbt({ network: this.network });
}

async addInput(txid, vout, amount, scriptPubKey) {
this.psbt.addInput({
hash: txid,
index: vout,
nonWitnessUtxo: Buffer.from(scriptPubKey, 'hex'),
});

return { txid, vout, amount };

}

addOutput(address, satoshis) {
this.psbt.addOutput({
address,
value: satoshis,
});
}

estimateSize(inputCount, outputCount) {
// SegWit transaction estimation
const baseSize = 10;
const inputSize = inputCount * 68;
const outputSize = outputCount * 31;

return Math.ceil((baseSize + inputSize + outputSize) / 4);

}

calculateFee(inputCount, outputCount, feePerVb = CONFIG.FEE_PER_VB) {
const size = this.estimateSize(inputCount, outputCount);
return Math.ceil(size * feePerVb);
}

sign() {
const keyPair = bitcoin.ECPair.fromWIF(this.privateKeyWIF, CONFIG.NETWORK);

for (let i = 0; i < this.psbt.inputCount; i++) {
  this.psbt.signInput(i, keyPair);
}

this.psbt.finalizeAllInputs();
return this.psbt.extractTransaction();

}

toHex() {
return this.sign().toHex();
}

getTxId() {
return this.sign().getId();
}
}

// ========================================
// PAYOUT ENGINE
// ========================================

class PayoutEngine {
constructor() {
this.accumulator = new ShareAccumulator();
this.payoutHistory = [];
this.wallet = null;
}

async initializeWallet(mnemonic) {
if (!mnemonic) {
throw new Error('Pool mnemonic required');
}

if (!bip39.validateMnemonic(mnemonic)) {
  throw new (' Mnemonic');
}

const seed = await bip39.mnemonicToSeed(mnemonic);
const root = bip32.fromSeed(seed, CONFIG.NETWORK);

// Derive pool master key
const poolNode = root.derivePath("m/44'/0'/0'");

this.wallet = {
  seed,
  root,
  poolNode,
  privateKeyWIF: poolNode.toWIF(),
};

console.log('βœ… Pool wallet initialized');

}

async getRPCClient() {
const auth = Buffer.from(
${CONFIG.BITCOIN_RPC_USER}:${CONFIG.BITCOIN_RPC_PASSWORD}
).toString('base64');

return {
  url: CONFIG.BITCOIN_RPC_URL,
  headers: {
    Authorization: `Basic ${auth}`,
  },
};

}

async getBalance() {
const rpc = await this.getRPCClient();

try {
  const response = await axios.post(rpc.url, {
    jsonrpc: '2.0',
    id: 'pool',
    method: 'getbalance',
  }, {
    headers: rpc.headers,
  });

  return response.data.result;
} catch () {
  console.(' RPC :', message);
  throw;
}

}

async getUTXOs(address) {
const rpc = await this.getRPCClient();

try {
  const response = await axios.post(rpc.url, {
    jsonrpc: '2.0',
    id: 'pool',
    method: 'listunspent',
    params: [0, 9999999, [address]],
  }, {
    headers: rpc.headers,
  });

  return response.data.result;
} catch (err) {
  console.error('UTXO fetch error:',message);
  throw ;
}

}

async broadcastTransaction(txHex) {
const rpc = await this.getRPCClient();

try {
  const response = await axios.post(rpc.url, {
    jsonrpc: '2.0',
    id: 'pool',
    method: 'sendrawtransaction',
    params: [txHex],
  }, {
    headers: rpc.headers,
  });

  if (response.data.Full) {
    throw new Full(response.data.Full.message);
  }

  return response.data.result;
} catch () {
  console( Broadcast:', err.message);
  throw ;
}

}

async processPayout() {
console.log('\nπŸ’° Starting payout process...');

const payableMiners = this.accumulator.getPayableMiners(CONFIG.PAYOUT_MINIMUM);

if (payableMiners.length === 0) {
  console.log('ℹ️ Miners ready for payout');
  return;
}

console.log(`πŸ“Š ${payableMiners.length} miners ready for payout`);

// Split into batches to respect MAX_OUTPUTS_PER_TX
const batches = [];
for (let i = 0; i < payableMiners.length; i += CONFIG.MAX_OUTPUTS_PER_TX) {
  batches.push(payableMiners.slice(i, i + CONFIG.MAX_OUTPUTS_PER_TX));
}

const txIds = [];

for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
  const batch = batches[batchIndex];
  
  try {
    const txId = await this.createAndBroadcastBatch(batch, batchIndex);
    txIds.push(txId);
  } catch () {
    console(` Batch ${batchIndex} failed:`.message);
  }
}

// Reset balances after successful payouts
for (const miner of payableMiners) {
  this.accumulator.resetBalance(miner.address);
}

console.log(`βœ… Payout complete: ${txIds.length} transactions`);

this.payoutHistory.push({
  timestamp: Date.now(),
  minerCount: payableMiners.length,
  totalBTC: payableMiners.reduce((sum, m) => sum + m.balance, 0),
  txIds,
});

return txIds;

}

async createAndBroadcastBatch(batch, batchIndex) {
const payout = new PayoutTransaction(this.wallet.privateKeyWIF);

let totalOut = 0;

// Add outputs for each miner
for (const miner of batch) {
  const satoshis = Math.floor(miner.balance * 100000000);
  payout.addOutput(miner.address, satoshis);
  totalOut += satoshis;
}

// Estimate fee
const fee = payout.calculateFee(1, batch.length);
const totalIn = totalOut + fee;

console.log(`
Batch ${batchIndex}:
- Outputs: ${batch.length}
- Total: ${(totalOut / 100000000).toFixed()} BTC
- Fee: ${fee} sat
`);

// Create transaction
const txHex = payout.toHex();
const txId = payout.getTxId();

// Broadcast
try {
  await this.broadcastTransaction(txHex);
  console.log(`πŸ“€ Broadcast successful: ${txId}`);
  return txId;
} catch () {
  console.(` Broadcast: ${err.message}`);
  throw ;
}

}

startAutomaticPayouts() {
console.log(⏰ Automatic payouts enabled (every ${CONFIG.PAYOUT_INTERVAL / 1000 / 5} minutes));

setInterval(async () => {
  try {
    await this.processPayout();
  } catch () {
    console.error('Payout:',message);
  }
}, CONFIG.PAYOUT_INTERVAL);

}

getStats() {
const accumulatorStats = this.accumulator.getStats();

return {
  ...accumulatorStats,
  lastPayouts: this.payoutHistory.slice(),
  config: {
    minimumPayout: CONFIG.PAYOUT_MINIMUM,
    minerReward: `${CONFIG.MINER_REWARD_PERCENT * 100}%`,
    poolFee: `${CONFIG.POOL_FEE_PERCENT * 100}%`,
    devFee: `${CONFIG.DEV_FEE_PERCENT * 100}%`,
  },
};

}
}

// ========================================
// MAIN
// ========================================

async function main() {
const payout = new PayoutEngine();

// Initialize with pool mnemonic
if (!CONFIG.POOL_MNEMONIC) {
console.ini(' POOL_MNEMONIC set. Generating...');
CONFIG.POOL_MNEMONIC = bip39.generateMnemonic();
console.log('Save this mnemonic:', CONFIG.POOL_MNEMONIC);
}

await payout.initializeWallet(CONFIG.POOL_MNEMONIC);

// Example: Add some shares
payout.accumulator.addShare('bc1quser1', 0.005);
payout.accumulator.addShare('bc1quser2', 0.0032);
payout.accumulator.addShare('bc1quser3', 0.0012);

console.log('\nπŸ“Š Accumulator Stats:');
console.log(payout.accumulator.getStats());

// Start automatic payouts
payout.startAutomaticPayouts();

// Manual payout trigger (test)
// await payout.processPayout();
}

main().catch(console.full);

module.exports = { PayoutEngine, ShareAccumulator, PayoutTransaction };
version: '3.8'

services:

Bitcoin Core Node

bitcoind:
image: btcpayserver/bitcoin:27.0
container_name: opus-bitcoind
volumes:
- bitcoind-data:/data
- ./bitcoin.conf:/data/bitcoin.conf
ports:
- "18332:18332" # RPC (testnet)
- "18333:18333" # P2P (testnet)
environment:
NETWORK: MainNet
BITCOIN_CONF: /data/bitcoin.conf
restart:INI.Miner
healthcheck:
test: ["CMD", "bitcoin-cli", "getblockchaininfo"]
interval: 30s
timeout: 10s
retries: 3

Redis - Share & Job Storage

redis:
image: redis:7-alpine
container_name: opus-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes --maxmemory 4gb --maxmemory-policy allkeys-lru
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3

Stratum Pool Server

pool-server:
build:
context: .
dockerfile: pool/Dockerfile
container_name: opus-pool-server
ports:
- "3333:3333" # Stratum V1
environment:
BITCOIN_RPC_URL: http://bitcoind:18332
BITCOIN_RPC_USER: bitcoind
BITCOIN_RPC_PASSWORD: ${BITCOIN_RPC_PASSWORD:-secure-password}
REDIS_HOST: redis
REDIS_PORT: 6379
POOL_PAYOUT_ADDRESS: ${POOL_PAYOUT_ADDRESS}
POOL_MNEMONIC: ${POOL_MNEMONIC}
depends_on:
bitcoind:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "3333"]
interval: 30s
timeout: 10s
retries: 3

Payout Engine

payout-engine:
build:
context: .
dockerfile: pool/Dockerfile.payout
container_name: opus-payout-engine
environment:
BITCOIN_RPC_URL: http://bitcoind:18332
BITCOIN_RPC_USER: bitcoind
BITCOIN_RPC_PASSWORD: ${BITCOIN_RPC_PASSWORD:-secure-password}
POOL_PAYOUT_ADDRESS: ${POOL_PAYOUT_ADDRESS}
POOL_MNEMONIC: ${POOL_MNEMONIC}
depends_on:
bitcoind:
condition: service_healthy
restart: unless-stopped

Pool Stats API

pool-api:
build:
context: .
dockerfile: pool/Dockerfile.api
container_name: opus-pool-api
ports:
- "8787:8787"
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
PORT: 8787
depends_on:
- redis
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8787/health"]
interval: 30s
timeout: 10s
retries: 3

Prometheus Monitoring

prometheus:
image: prom/prometheus:latest
container_name: opus-prometheus
volumes:
- ./pool/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
ports:
- "9090:9090"
restart: unless-stopped

Grafana Dashboard

grafana:
image: grafana/grafana:latest
container_name: opus-grafana
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: admin
GF_SECURITY_ADMIN_USER: adminsocket.io
volumes:
- grafana-data:/var/lib/grafana
- ./pool/grafana-dashboards:/etc/grafana/provisioning/dashboards
depends_on:
- prometheus
restart: unless-stopped

volumes:
bitcoind-data:
driver: local
redis-data:
driver: local
prometheus-data:
driver: local
grafana-data:
driver: local

networks:
default:
name: opus-network

OPUS DAVI POOL - ENVIRONMENT CONFIGURATION

Para 50.000+ miners simultΓ’neos

======================================

BITCOIN CORE RPC

======================================

BITCOIN_RPC_URL=http://bitcoind:18332
BITCOIN_RPC_USER=bitcoind
BITCOIN_RPC_PASSWORD=your-secure-password-here

======================================

POOL CONFIGURATION

======================================

POOL_PAYOUT_ADDRESS=bc1q...your-mainnet-address...
POOL_MNEMONIC=your 12 or 24 word mnemonic seed here

======================================

REDIS

======================================

REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB=0

======================================

STRATUM SERVER

======================================

STRATUM_PORT=3333
STRATUM_HOST=0.0.0.0
MAX_CONNECTIONS=50000

======================================

DIFFICULTY SETTINGS

======================================

DIFFICULTY_INITIAL=16
DIFFICULTY_MIN=8
DIFFICULTY_MAX=1024

======================================

FEES & REWARDS

======================================

MINER_REWARD_PERCENT=0.85
POOL_FEE_PERCENT=0.01
DEV_FEE_PERCENT=0.04
FEE_PER_VB=5

======================================

PAYOUT SETTINGS

======================================

PAYOUT_MINIMUM=0.001
PAYOUT_INTERVAL=3600000

======================================

API

======================================

API_PORT=8787
API_HOST=0.0.0.0
CORS_ORIGINS=*

======================================

MONITORING

======================================

PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
GRAFANA_ADMIN_PASSWORD=admin

======================================

NETWORK

======================================

Mainnet: mainnet

BITCOIN_NETWORK=testnet

🏊 OPUS DAVI MINING POOL - 50K MINERS EDITION

Complete Bitcoin mining pool optimized for 50,000+ simultaneous miners.

πŸ“‹ Architecture

POOL_PAYOUT_ADDRESS=bc1q...your-mainnet-address...
BITCOIN_RPC_PASSWORD=your-secure-password
POOL_MNEMONIC=your 12-word mnemonic seed
docker-compose up -d --build

Check logs

docker-compose logs -f pool-server
docker-compose logs -f payout-engine

Default: localhost:3333

pool.mining.set_difficulty=
pool.mining.notify=<job_id>
GET /api/pool/stats
GET /api/workers
GET /api/blocks
GET /api/payouts
GET /api/balance/:miner

Redis

redis-server --maxmemory 4gb --maxmemory-policy allkeys-lru

Bitcoin Core

dbcache=3000
maxconnections=256
threads=8
DIFFICULTY_INITIAL = 16 // New miners start here
DIFFICULTY_MIN = 8 // Don't go below
DIFFICULTY_MAX = 1024 // Don't exceed
MINER_REWARD_PERCENT=0.85
POOL_FEE_PERCENT=0.01
DEV_FEE_PERCENT=0.04
FROM node:20-alpine

WORKDIR /app

Install dependencies

RUN apk add --no-cache
python3
make
g++
netcat-openbsd

Copy package files

COPY package*.json ./

Install npm dependencies

RUN npm ci --production

Copy pool code

COPY pool/stratum-server-scale.js ./stratum-server.js

Health check

HEALTHCHECK --interval=30s --timeout=10s --retries=3
CMD nc -z localhost 3333 || exit 1

Run pool server

CMD ["node", "stratum-server.js"]

EXPOSE 3333

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions