diff --git a/full-setup/README.md b/full-setup/README.md index 07a48fc..ec5998c 100644 --- a/full-setup/README.md +++ b/full-setup/README.md @@ -63,4 +63,16 @@ To stop the setup use: ``` docker compose -f docker-compose-mainnet.yml down -``` \ No newline at end of file +``` + +# Regtest + +After running the `regtest` setup a couple of blocks need to be generated: + +```bash +# create wallet +$ docker exec -it bitcoin-regtest /app/bin/bitcoin-cli -conf=/app/data/bitcoin.conf -regtest createwallet "regtestwallet" + +# generate 101 blocks +$ docker exec -it bitcoin-regtest /app/bin/bitcoin-cli -conf=/app/data/bitcoin.conf -regtest -generate 101 +``` diff --git a/full-setup/bitcoin-regtest.conf b/full-setup/bitcoin-regtest.conf new file mode 100644 index 0000000..ac1d3c8 --- /dev/null +++ b/full-setup/bitcoin-regtest.conf @@ -0,0 +1,22 @@ +[main] +[test] +[signet] +[regtest] +# allow all IPs +rpcallowip=0.0.0.0/0 + +# start RPC server +server=1 + +# bind to 0.0.0.0 +rpcbind=0.0.0.0 + +# RPC Port 28332 +rpcport=28332 + +# RPC username and password +rpcpassword=bitcoin +rpcuser=bitcoin + +# set pruning +prune=550 diff --git a/full-setup/docker-compose-regtest.yml b/full-setup/docker-compose-regtest.yml new file mode 100644 index 0000000..1b7ec10 --- /dev/null +++ b/full-setup/docker-compose-regtest.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + bitcoin-regtest: + container_name: bitcoin-regtest + build: + context: ./docker/bitcoin + dockerfile: Dockerfile + restart: unless-stopped + stop_grace_period: 30s + networks: + - bitcoin-regtest + ports: + - "127.0.0.1:28332:28332/tcp" + - "0.0.0.0:28333:28333/tcp" + command: > + -printtoconsole + -datadir=/app/data + -regtest + -blockversion=536870912 + volumes: + - "./data/regtest/bitcoin:/app/data" + - "./bitcoin-regtest.conf:/app/data/bitcoin.conf:ro" + + public-pool-regtest: + container_name: public-pool-regtest + build: + context: .. + dockerfile: Dockerfile + restart: unless-stopped + stop_grace_period: 30s + networks: + - bitcoin-regtest + ports: + - "0.0.0.0:23333:23333/tcp" + - "127.0.0.1:23334:23334/tcp" + volumes: + - "./data/regtest/public-pool:/public-pool/DB" + - "./public-pool-regtest.env:/public-pool/.env:ro" + environment: + - NODE_ENV=production + +networks: + bitcoin-regtest: diff --git a/full-setup/public-pool-regtest.env b/full-setup/public-pool-regtest.env new file mode 100644 index 0000000..d3ff69c --- /dev/null +++ b/full-setup/public-pool-regtest.env @@ -0,0 +1,34 @@ +BITCOIN_RPC_URL=http://bitcoin-regtest +BITCOIN_RPC_USER=bitcoin +BITCOIN_RPC_PASSWORD=bitcoin +BITCOIN_RPC_PORT=28332 +BITCOIN_RPC_TIMEOUT=10000 + +# Enable in bitcoin.conf with +# zmqpubrawblock=tcp://*:3000 +# BITCOIN_ZMQ_HOST="tcp://192.168.1.100:3000" + +API_PORT=23334 +STRATUM_PORT=23333 + +#optional telegram bot +#TELEGRAM_BOT_TOKEN= + +#optional discord bot +#DISCORD_BOT_CLIENTID= +#DISCORD_BOT_GUILD_ID= +#DISCORD_BOT_CHANNEL_ID= + +#optional +DEV_FEE_ADDRESS= +# mainnet | testnet +NETWORK=regtest + +API_SECURE=false + +ENABLE_SOLO=true +ENABLE_PROXY=false + +BRAIINS_ACCESS_TOKEN= + +PROXY_PORT=3333 diff --git a/src/models/MiningJob.ts b/src/models/MiningJob.ts index 8ae18d5..02bccf0 100644 --- a/src/models/MiningJob.ts +++ b/src/models/MiningJob.ts @@ -40,8 +40,19 @@ export class MiningJob { // 39th byte onwards: Optional data with no consensus meaning const extra = Buffer.from('\\public-pool\\'); + + // Encode the block height // https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki - this.coinbaseTransaction.ins[0].script = Buffer.concat([Buffer.from([jobTemplate.blockData.littleEndianBlockHeight.byteLength]), jobTemplate.blockData.littleEndianBlockHeight, extra, Buffer.alloc(8, 0)]); + const blockHeightEncoded = bitcoinjs.script.number.encode(jobTemplate.blockData.height); + + // Get the length of the block height encoding + const blockHeightLengthByte = Buffer.from([blockHeightEncoded.length]); + + // generate padding and take length of encode blockHeight into account + const padding = Buffer.alloc(8 + (3 - blockHeightEncoded.length), 0) + + // build the script + this.coinbaseTransaction.ins[0].script = Buffer.concat([blockHeightLengthByte, blockHeightEncoded, extra, padding]) this.coinbaseTransaction.addOutput(bitcoinjs.script.compile([bitcoinjs.opcodes.OP_RETURN, Buffer.concat([segwitMagicBits, jobTemplate.block.witnessCommit])]), 0); @@ -196,4 +207,4 @@ export class MiningJob { } -} \ No newline at end of file +} diff --git a/src/models/StratumV1Client.ts b/src/models/StratumV1Client.ts index be643cd..0d1edde 100644 --- a/src/models/StratumV1Client.ts +++ b/src/models/StratumV1Client.ts @@ -392,9 +392,21 @@ export class StratumV1Client { ]; } + const networkConfig = this.configService.get('NETWORK'); + let network; + + if (networkConfig === 'mainnet') { + network = bitcoinjs.networks.bitcoin; + } else if (networkConfig === 'testnet') { + network = bitcoinjs.networks.testnet; + } else if (networkConfig === 'regtest') { + network = bitcoinjs.networks.regtest; + } else { + throw new Error('Invalid network configuration'); + } const job = new MiningJob( - this.configService.get('NETWORK') === 'mainnet' ? bitcoinjs.networks.bitcoin : bitcoinjs.networks.testnet, + network, this.stratumV1JobsService.getNextId(), payoutInformation, jobTemplate diff --git a/src/services/stratum-v1-jobs.service.ts b/src/services/stratum-v1-jobs.service.ts index 864608b..a3cea4c 100644 --- a/src/services/stratum-v1-jobs.service.ts +++ b/src/services/stratum-v1-jobs.service.ts @@ -13,7 +13,6 @@ export interface IJobTemplate { merkle_branch: string[]; blockData: { id: string, - littleEndianBlockHeight: Buffer; coinbasevalue: number; networkDifficulty: number; height: number; @@ -72,7 +71,6 @@ export class StratumV1JobsService { bits: parseInt(blockTemplate.bits, 16), prevHash: this.convertToLittleEndian(blockTemplate.previousblockhash), transactions: blockTemplate.transactions.map(t => bitcoinjs.Transaction.fromHex(t.data)), - littleEndianBlockHeight: this.convertToLittleEndian(blockTemplate.height.toString(16).padStart(6, '0')), coinbasevalue: blockTemplate.coinbasevalue, timestamp: Math.floor(new Date().getTime() / 1000), networkDifficulty: this.calculateNetworkDifficulty(parseInt(blockTemplate.bits, 16)), @@ -81,7 +79,7 @@ export class StratumV1JobsService { }; }), filter(next => next != null), - map(({ version, bits, prevHash, transactions, timestamp, littleEndianBlockHeight, coinbasevalue, networkDifficulty, clearJobs, height }) => { + map(({ version, bits, prevHash, transactions, timestamp, coinbasevalue, networkDifficulty, clearJobs, height }) => { const block = new bitcoinjs.Block(); //create an empty coinbase tx @@ -115,7 +113,6 @@ export class StratumV1JobsService { merkle_branch, blockData: { id, - littleEndianBlockHeight, coinbasevalue, networkDifficulty, height, @@ -176,4 +173,4 @@ export class StratumV1JobsService { } -} \ No newline at end of file +}