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)
-
-
-
-
- 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
Describe the stack
[10/6 12:43] Davi Calixto: /**
*/
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: /**
*/
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;
}
createTransaction(sender, recipient, amount) {
if (this.balances[sender] < amount) {
console (
Saldo : ${this.balances[sender]} < ${amount});return true;
}
}
minePendingTransactions(minerAddress) {
const block = new Block(
this.chain.length,
this.chain[this.chain.length - 1].hash,
Date.now(),
this.pendingTransactions,
minerAddress
);
}
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];
}
}
// ========================================
// 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;
}
}
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;
}
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;
}
detectWhales(transaction) {
const isWhale = transaction.amount > 10;
}
predictFees(lookbackHours = 24) {
const recentFees = this.feeHistory.slice(-lookbackHours);
}
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');
}
Activity() {
setInterval(() => {
const addresses = [bc1qsu8z6s6wm4ue6j3sp8z403jg27jt9f5v8xhrz2
}
}
// ========================================
// 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: /**
*/
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);
}
async importWallet(mnemonic) {
if (!bip39.validateMnemonic(mnemonic)) {
throw new Error("Mnemonic invΓ‘lida");
}
}
deriveAddress(index = 0) {
const node = this.root.derivePath(
m/84'/0'/0'/0/${index});}
deriveChangeAddress(index = 0) {
const node = this.root.derivePath(
m/84'/0'/0'/1/${index});}
getXPUB() {
return this.root.neutered().toBase58();
}
exportWallet() {
const 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 DataMinerconst 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)
}
})
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'))
}, 100)
}
socket.on('error', e => console.error('Erro:', e.message))
Roda com:
POOL_URL=stratum+tcp://localhost:3333 WORKER=teste1 node mining/cpu-miner.jsVai fazer βΌ2-500 EH/s. Chance de achar bloco mainnet = 0. Mas valida que teu
submitblockfunciona.2.
mining/payout.js- Distribui o bloco achado pros minersEsse 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"
}
}/**
*/
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;
}
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;
}
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');
}
handleMessage(message) {
const { method, params, id } = message;
this.lastActivity = Date.now();
}
subscribe(params, id) {
const sessionId = crypto.randomBytes(16).toString('hex');
}
authorize(params, id) {
const [username, password] = params;
this.username = username;
this.worker = username.split('.')[1] || 'default';
}
submitShare(params, id) {
const [username, jobId, extraNonce2, ntime, nonce] = params;
this.shares++;
}
suggestDifficulty(params) {
const [suggestedDiff] = params;
const newDiff = Math.max(
CONFIG.DIFFICULTY_MIN,
Math.min(suggestedDiff, CONFIG.DIFFICULTY_MAX)
);
}
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);
}
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,
});
}
start() {β οΈ Max connections reached');
this.server = net.createServer((socket) => {
if (this.workers.size >= CONFIG.MAX_CONNECTIONS) {
console.warn('
socket.destroy();
return;
}
}
startJobBroadcaster() {
setInterval(() => {
const jobId = crypto.randomBytes(4).toString('hex');
const job = this.generateJob(jobId);
}
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;
ββββββββββββββββββββββββββββββββββββββββββ
β 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)}β
ββββββββββββββββββββββββββββββββββββββββββ
`);
}
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;
/**
*/
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);
}
getBalance(minerAddress) {
return this.balances.get(minerAddress) || 0;
}
getPayableMiners(minimumBalance) {
const 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'),
});
}
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;
}
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);
}
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');
}
}
async getRPCClient() {
const auth = Buffer.from(
${CONFIG.BITCOIN_RPC_USER}:${CONFIG.BITCOIN_RPC_PASSWORD}).toString('base64');
}
async getBalance() {
const rpc = await this.getRPCClient();
}
async getUTXOs(address) {
const rpc = await this.getRPCClient();
}
async broadcastTransaction(txHex) {
const rpc = await this.getRPCClient();
}
async processPayout() {
console.log('\nπ° Starting payout process...');
}
async createAndBroadcastBatch(batch, batchIndex) {
const payout = new PayoutTransaction(this.wallet.privateKeyWIF);
}
startAutomaticPayouts() {
console.log(
β° Automatic payouts enabled (every ${CONFIG.PAYOUT_INTERVAL / 1000 / 5} minutes));}
getStats() {
const accumulatorStats = this.accumulator.getStats();
}
}
// ========================================
// 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