mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
coinbase calculations
This commit is contained in:
Vendored
+3
@@ -3,10 +3,13 @@
|
|||||||
"coinb",
|
"coinb",
|
||||||
"Fastify",
|
"Fastify",
|
||||||
"getblocktemplate",
|
"getblocktemplate",
|
||||||
|
"getmininginfo",
|
||||||
|
"hexdata",
|
||||||
"merkle",
|
"merkle",
|
||||||
"nbits",
|
"nbits",
|
||||||
"ntime",
|
"ntime",
|
||||||
"prevhash",
|
"prevhash",
|
||||||
|
"submitblock",
|
||||||
"Tempalte"
|
"Tempalte"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Generated
+941
-16
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
|||||||
"@nestjs/platform-fastify": "^9.4.2",
|
"@nestjs/platform-fastify": "^9.4.2",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
|
"merkletreejs": "^0.3.10",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rpc-bitcoin": "^2.0.0",
|
"rpc-bitcoin": "^2.0.0",
|
||||||
"rxjs": "^7.2.0"
|
"rxjs": "^7.2.0"
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ import { CoinbaseConstructorService } from './coinbase-constructor.service';
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
constructor(private readonly bitcoinStratumProvider: BitcoinStratumProvider) {
|
constructor() {
|
||||||
this.bitcoinStratumProvider.listen(3333);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { RPCClient } from 'rpc-bitcoin';
|
import { RPCClient } from 'rpc-bitcoin';
|
||||||
|
|
||||||
import { IBlockTempalte } from './models/IBlockTempalte';
|
import { IBlockTemplate } from './models/bitcoin-rpc/IBlockTemplate';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { IMiningInfo } from './models/bitcoin-rpc/IMiningInfo';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BitcoinRpcService {
|
export class BitcoinRpcService {
|
||||||
|
|
||||||
|
private blockHeight = 0;
|
||||||
private client: RPCClient;
|
private client: RPCClient;
|
||||||
|
private newBlock$: BehaviorSubject<number> = new BehaviorSubject(0);
|
||||||
|
|
||||||
constructor(configService: ConfigService) {
|
constructor(configService: ConfigService) {
|
||||||
const url = configService.get('BITCOIN_RPC_URL');
|
const url = configService.get('BITCOIN_RPC_URL');
|
||||||
@@ -18,15 +22,35 @@ export class BitcoinRpcService {
|
|||||||
const timeout = parseInt(configService.get('BITCOIN_RPC_TIMEOUT'));
|
const timeout = parseInt(configService.get('BITCOIN_RPC_TIMEOUT'));
|
||||||
|
|
||||||
this.client = new RPCClient({ url, port, timeout, user, pass });
|
this.client = new RPCClient({ url, port, timeout, user, pass });
|
||||||
|
|
||||||
|
|
||||||
console.log('Bitcoin RPC connected');
|
console.log('Bitcoin RPC connected');
|
||||||
|
|
||||||
|
// Maybe use ZeroMQ ?
|
||||||
|
setInterval(async () => {
|
||||||
|
const miningInfo = await this.getMiningInfo();
|
||||||
|
if (miningInfo.blocks > this.blockHeight) {
|
||||||
|
console.log(miningInfo);
|
||||||
|
if (this.blockHeight != 0) {
|
||||||
|
this.newBlock$.next(miningInfo.blocks + 1);
|
||||||
|
}
|
||||||
|
this.blockHeight = miningInfo.blocks;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public newBlock(): Observable<any> {
|
||||||
|
return this.newBlock$.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async getBlockTemplate(): Promise<IBlockTempalte> {
|
public async getBlockTemplate(): Promise<IBlockTemplate> {
|
||||||
|
|
||||||
const result: IBlockTempalte = await this.client.getblocktemplate({
|
const result: IBlockTemplate = await this.client.getblocktemplate({
|
||||||
template_request: {
|
template_request: {
|
||||||
rules: ['segwit'],
|
rules: ['segwit'],
|
||||||
mode: 'template',
|
mode: 'template',
|
||||||
@@ -36,5 +60,16 @@ export class BitcoinRpcService {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getMiningInfo(): Promise<IMiningInfo> {
|
||||||
|
return await this.client.getmininginfo();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async SUBMIT_BLOCK(hexdata: string) {
|
||||||
|
await this.client.submitblock({
|
||||||
|
hexdata
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
import { Server, Socket } from 'net';
|
import { Server, Socket } from 'net';
|
||||||
import { BehaviorSubject, take } from 'rxjs';
|
import { BehaviorSubject, skip, take } from 'rxjs';
|
||||||
|
|
||||||
import { BitcoinRpcService } from './bitcoin-rpc.service';
|
import { BitcoinRpcService } from './bitcoin-rpc.service';
|
||||||
import { IBlockTempalte } from './models/IBlockTempalte';
|
import { IBlockTemplate } from './models/bitcoin-rpc/IBlockTemplate';
|
||||||
import { MiningJob } from './models/MiningJob';
|
import { MiningJob } from './models/MiningJob';
|
||||||
import { StratumV1Client } from './models/StratumV1Client';
|
import { StratumV1Client } from './models/StratumV1Client';
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ export class BitcoinStratumProvider implements OnModuleInit {
|
|||||||
|
|
||||||
private server: Server;
|
private server: Server;
|
||||||
|
|
||||||
private blockTemplate: IBlockTempalte;
|
private blockTemplate: IBlockTemplate;
|
||||||
|
|
||||||
private interval: NodeJS.Timer;
|
private interval: NodeJS.Timer;
|
||||||
|
|
||||||
@@ -25,12 +25,25 @@ export class BitcoinStratumProvider implements OnModuleInit {
|
|||||||
|
|
||||||
constructor(private readonly bitcoinRpcService: BitcoinRpcService) {
|
constructor(private readonly bitcoinRpcService: BitcoinRpcService) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async onModuleInit(): Promise<void> {
|
||||||
|
console.log('onModuleInit');
|
||||||
|
|
||||||
|
this.blockTemplate = await this.bitcoinRpcService.getBlockTemplate();
|
||||||
|
this.latestJob = new MiningJob(this.blockTemplate)
|
||||||
|
|
||||||
|
|
||||||
this.server = new Server((socket: Socket) => {
|
this.server = new Server((socket: Socket) => {
|
||||||
console.log('New client connected:', socket.remoteAddress);
|
console.log('New client connected:', socket.remoteAddress);
|
||||||
|
|
||||||
const client = new StratumV1Client(socket, this.newMiningJobEmitter.asObservable());
|
const client = new StratumV1Client(socket, this.newMiningJobEmitter.asObservable());
|
||||||
|
|
||||||
client.onInitialized.pipe(take(1)).subscribe(() => {
|
client.onInitialized.pipe(skip(1), take(1)).subscribe(() => {
|
||||||
|
console.log('Client Ready')
|
||||||
if (this.latestJob == null) {
|
if (this.latestJob == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,33 +59,25 @@ export class BitcoinStratumProvider implements OnModuleInit {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
this.server.listen(3333, () => {
|
||||||
|
console.log(`Bitcoin Stratum server is listening on port ${3333}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
async onModuleInit(): Promise<void> {
|
|
||||||
console.log('onModuleInit');
|
|
||||||
this.blockTemplate = await this.bitcoinRpcService.getBlockTemplate();
|
|
||||||
|
|
||||||
clearInterval(this.interval);
|
//clearInterval(this.interval);
|
||||||
const job = new MiningJob(this.blockTemplate).response();
|
|
||||||
this.newMiningJobEmitter.next(JSON.stringify(job));
|
|
||||||
|
|
||||||
this.interval = setInterval(() => {
|
this.newMiningJobEmitter.next(JSON.stringify(this.latestJob.response()));
|
||||||
this.latestJob = new MiningJob(this.blockTemplate);
|
|
||||||
|
|
||||||
const job = this.latestJob.response();
|
this.interval = setInterval(async () => {
|
||||||
const jobString = JSON.stringify(job);
|
this.blockTemplate = await this.bitcoinRpcService.getBlockTemplate();
|
||||||
|
|
||||||
this.newMiningJobEmitter.next(jobString);
|
this.latestJob = new MiningJob(this.blockTemplate)
|
||||||
|
this.newMiningJobEmitter.next(JSON.stringify(this.latestJob.response()));
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
listen(port: number) {
|
|
||||||
this.server.listen(port, () => {
|
|
||||||
console.log(`Bitcoin Stratum server is listening on port ${port}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
export interface IBlockTempalte {
|
|
||||||
// (json object)
|
|
||||||
version: number; // (numeric) The preferred block version
|
|
||||||
rules: string[]; // (json array) specific block rules that are to be enforced // (string) name of a rule the client must understand to some extent; see BIP 9 for format
|
|
||||||
|
|
||||||
vbavailable: { // (json object) set of pending, supported versionbit (BIP 9) softfork deployments
|
|
||||||
rulename: number, // (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule
|
|
||||||
},
|
|
||||||
vbrequired: number, // (numeric) bit mask of versionbits the server requires set in submissions
|
|
||||||
previousblockhash: string, // (string) The hash of current highest block
|
|
||||||
transactions: [ // (json array) contents of non-coinbase transactions that should be included in the next block
|
|
||||||
{ // (json object)
|
|
||||||
data: string; //'hex', // (string) transaction data encoded in hexadecimal (byte-for-byte)
|
|
||||||
txid: string; //'hex', // (string) transaction id encoded in little-endian hexadecimal
|
|
||||||
hash: string; //'hex', // (string) hash encoded in little-endian hexadecimal (including witness data)
|
|
||||||
depends: number[]; // (json array) array of numbers // (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is
|
|
||||||
fee: number, // (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one
|
|
||||||
sigops: number, // (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero
|
|
||||||
weight: number // (numeric) total transaction weight, as counted for purposes of block limits
|
|
||||||
}
|
|
||||||
],
|
|
||||||
coinbaseaux: { // (json object) data that should be included in the coinbase's scriptSig content
|
|
||||||
key: string; //'hex', // (string) values must be in the coinbase (keys may be ignored)
|
|
||||||
},
|
|
||||||
coinbasevalue: number, // (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)
|
|
||||||
longpollid: string, // (string) an id to include with a request to longpoll on an update to this template
|
|
||||||
target: string, // (string) The hash target
|
|
||||||
mintime: number, // (numeric) The minimum timestamp appropriate for the next block time, expressed in UNIX epoch time
|
|
||||||
mutable: string[]; // (json array) list of ways the block template may be changed // (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'
|
|
||||||
|
|
||||||
noncerange: string; // 'hex', // (string) A range of valid nonces
|
|
||||||
sigoplimit: number, // (numeric) limit of sigops in blocks
|
|
||||||
sizelimit: number, // (numeric) limit of block size
|
|
||||||
weightlimit: number, // (numeric) limit of block weight
|
|
||||||
curtime: number, // (numeric) current timestamp in UNIX epoch time
|
|
||||||
bits: string, // (string) compressed target of next block
|
|
||||||
height: number, // (numeric) The height of the next block
|
|
||||||
default_witness_commitment: string // (string, optional) a valid witness commitment for the unmodified block template
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
+81
-62
@@ -1,8 +1,9 @@
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
|
|
||||||
import { eResponseMethod } from './enums/eResponseMethod';
|
import { eResponseMethod } from './enums/eResponseMethod';
|
||||||
import { IBlockTempalte } from './IBlockTempalte';
|
import { IBlockTemplate, IBlockTemplateTx } from './bitcoin-rpc/IBlockTemplate';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
|
import { MerkleTree } from 'merkletreejs'
|
||||||
|
|
||||||
export class MiningJob {
|
export class MiningJob {
|
||||||
public id: number;
|
public id: number;
|
||||||
@@ -20,7 +21,7 @@ export class MiningJob {
|
|||||||
public ntime: string; // Current ntime/
|
public ntime: string; // Current ntime/
|
||||||
public clean_jobs: boolean; // When true, server indicates that submitting shares from previous jobs don't have a sense and such shares will be rejected. When this flag is set, miner should also drop all previous jobs too.
|
public clean_jobs: boolean; // When true, server indicates that submitting shares from previous jobs don't have a sense and such shares will be rejected. When this flag is set, miner should also drop all previous jobs too.
|
||||||
|
|
||||||
constructor(blockTemplate: IBlockTempalte) {
|
constructor(blockTemplate: IBlockTemplate) {
|
||||||
|
|
||||||
this.job_id = randomUUID();
|
this.job_id = randomUUID();
|
||||||
this.prevhash = blockTemplate.previousblockhash;
|
this.prevhash = blockTemplate.previousblockhash;
|
||||||
@@ -31,27 +32,97 @@ export class MiningJob {
|
|||||||
this.clean_jobs = false;
|
this.clean_jobs = false;
|
||||||
|
|
||||||
|
|
||||||
// Construct coinbase transaction
|
const { coinb1, coinb2, coinbaseData } = this.createCoinbaseTransaction('', blockTemplate.height);
|
||||||
const coinbaseTransaction = blockTemplate.transactions[0];
|
|
||||||
const coinbaseHashBin = this.buildCoinbaseHashBin(coinbaseTransaction.data);
|
console.log(coinbaseData);
|
||||||
this.coinb1 = this.coinbasePrefix(coinbaseTransaction.data, coinbaseHashBin);
|
const coinbaseHash = this.bufferToHex(this.sha256(coinbaseData));
|
||||||
this.coinb2 = ''; // Assuming no suffix is required
|
|
||||||
|
this.coinb1 = coinb1;
|
||||||
|
this.coinb2 = coinb2;
|
||||||
|
|
||||||
|
const transactions = blockTemplate.transactions.map(tx => tx.hash);
|
||||||
|
const transactionFees = blockTemplate.transactions.reduce((pre, cur, i, arr) => {
|
||||||
|
return pre + cur.fee;
|
||||||
|
}, 0);
|
||||||
|
console.log('TRANSACTION FEES', transactionFees);
|
||||||
|
console.log('MINING REWARD', this.calculateMiningReward(blockTemplate.height));
|
||||||
|
transactions.unshift(coinbaseHash);
|
||||||
|
|
||||||
// Calculate merkle branch
|
// Calculate merkle branch
|
||||||
const merkleBranch = blockTemplate.transactions.slice(1).map((transaction) => transaction.hash);
|
|
||||||
this.merkle_branch = this.buildMerkleBranch(merkleBranch, coinbaseHashBin);
|
const tree = new MerkleTree(transactions, this.sha256, { isBitcoinTree: true });
|
||||||
|
const layers = tree.getLayers();
|
||||||
|
|
||||||
|
const branch = [];
|
||||||
|
|
||||||
|
for (const layer of layers) {
|
||||||
|
branch.push(this.bufferToHex(layer[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(branch);
|
||||||
|
|
||||||
|
this.merkle_branch = branch;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private calculateMiningReward(blockHeight: number): number {
|
||||||
|
const initialBlockReward = 50 * 1e8; // Initial block reward in satoshis (1 BTC = 100 million satoshis)
|
||||||
|
const halvingInterval = 210000; // Number of blocks after which the reward halves
|
||||||
|
|
||||||
|
// Calculate the number of times the reward has been halved
|
||||||
|
const halvingCount = Math.floor(blockHeight / halvingInterval);
|
||||||
|
|
||||||
|
// Calculate the current block reward in satoshis
|
||||||
|
const currentReward = initialBlockReward / Math.pow(2, halvingCount);
|
||||||
|
|
||||||
|
return currentReward;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bufferToHex(buffer: Buffer): string {
|
||||||
|
return buffer.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
private createCoinbaseTransaction(address: string, blockHeight: number): { coinb1: string, coinb2: string, coinbaseData: any } {
|
||||||
|
// Generate coinbase script
|
||||||
|
const coinbaseScript = `03${blockHeight.toString(16).padStart(8, '0')}54696d652026204865616c74682021`;
|
||||||
|
|
||||||
|
// Create coinbase transaction
|
||||||
|
const version = '01000000';
|
||||||
|
const inputs = '01' + '0000000000000000000000000000000000000000000000000000000000000000ffffffff';
|
||||||
|
const coinbaseScriptSize = coinbaseScript.length / 2;
|
||||||
|
const coinbaseScriptBytes = coinbaseScriptSize.toString(16).padStart(2, '0');
|
||||||
|
const coinbaseTransaction = inputs + coinbaseScriptBytes + coinbaseScript + '00000000';
|
||||||
|
|
||||||
|
// Create output
|
||||||
|
const outputCount = '01';
|
||||||
|
const satoshis = '0f4240'; // 6.25 BTC in satoshis (1 BTC = 100,000,000 satoshis)
|
||||||
|
const script = '1976a914' + address + '88ac'; // Change this to your desired output script
|
||||||
|
const locktime = '00000000';
|
||||||
|
|
||||||
|
// Combine coinb1 and coinb2
|
||||||
|
const coinb1 = version + coinbaseTransaction + outputCount + satoshis;
|
||||||
|
const coinb2 = script + locktime;
|
||||||
|
|
||||||
|
const coinbaseData = version + coinbaseTransaction + outputCount + satoshis + script + locktime;
|
||||||
|
|
||||||
|
|
||||||
|
return { coinb1, coinb2, coinbaseData };
|
||||||
|
}
|
||||||
|
|
||||||
|
private sha256(data) {
|
||||||
|
return crypto.createHash('sha256').update(data).digest()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public response() {
|
public response() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: 0,
|
id: 0,
|
||||||
method: eResponseMethod.MINING_NOTIFY,
|
method: eResponseMethod.MINING_NOTIFY,
|
||||||
params: [
|
params: [
|
||||||
'123',///this.job_id,
|
this.job_id,
|
||||||
this.prevhash,
|
this.prevhash,
|
||||||
this.coinb1,
|
this.coinb1,
|
||||||
this.coinb2,
|
this.coinb2,
|
||||||
@@ -66,58 +137,6 @@ export class MiningJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private coinbasePrefix(coinbase: string, coinbaseHashBin: Buffer): string {
|
|
||||||
const coinbaseData = Buffer.from(coinbase, 'hex');
|
|
||||||
const coinbaseSize = Buffer.alloc(1, coinbaseData.length);
|
|
||||||
const extraNoncePlaceholder = Buffer.alloc(4); // Assuming 4 bytes for extra nonce
|
|
||||||
const concatenatedBuffer = Buffer.concat([coinbaseSize, coinbaseData, extraNoncePlaceholder]);
|
|
||||||
const merkleRoot = this.doubleSHA(Buffer.concat([coinbaseHashBin, concatenatedBuffer]));
|
|
||||||
|
|
||||||
return merkleRoot.toString('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private buildCoinbaseHashBin(coinbase: string): Buffer {
|
|
||||||
const sha256 = crypto.createHash('sha256');
|
|
||||||
const sha256Digest = sha256.update(Buffer.from(coinbase, 'hex')).digest();
|
|
||||||
|
|
||||||
const coinbaseHashSha256 = crypto.createHash('sha256');
|
|
||||||
const coinbaseHash = coinbaseHashSha256.update(sha256Digest).digest();
|
|
||||||
|
|
||||||
return coinbaseHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildMerkleBranch(merkleBranch: string[], coinbaseHashBin: Buffer): string[] {
|
|
||||||
const merkleRoots: string[] = [];
|
|
||||||
let merkleRoot = coinbaseHashBin;
|
|
||||||
|
|
||||||
for (const h of merkleBranch) {
|
|
||||||
const concatenatedBuffer = Buffer.concat([merkleRoot, Buffer.from(h, 'hex')]);
|
|
||||||
merkleRoot = this.doubleSHA(concatenatedBuffer);
|
|
||||||
merkleRoots.push(merkleRoot.toString('hex'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return merkleRoots.slice(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private buildMerkleRoot(merkleBranch: string[], coinbaseHashBin: Buffer): string {
|
|
||||||
// let merkleRoot = coinbaseHashBin;
|
|
||||||
// for (const h of merkleBranch) {
|
|
||||||
// const concatenatedBuffer = Buffer.concat([merkleRoot, Buffer.from(h, 'hex')]);
|
|
||||||
// merkleRoot = this.doubleSHA(concatenatedBuffer);
|
|
||||||
// }
|
|
||||||
// return merkleRoot.toString('hex');
|
|
||||||
// }
|
|
||||||
|
|
||||||
private doubleSHA(data: Buffer): Buffer {
|
|
||||||
const sha256 = crypto.createHash('sha256');
|
|
||||||
const sha256Digest = sha256.update(data).digest();
|
|
||||||
|
|
||||||
const doubleSha256 = crypto.createHash('sha256');
|
|
||||||
const doubleSha256Digest = doubleSha256.update(sha256Digest).digest();
|
|
||||||
|
|
||||||
return doubleSha256Digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
export interface IBlockTemplateTx {
|
||||||
|
data: string; //'hex', // (string) transaction data encoded in hexadecimal (byte-for-byte)
|
||||||
|
txid: string; //'hex', // (string) transaction id encoded in little-endian hexadecimal
|
||||||
|
hash: string; //'hex', // (string) hash encoded in little-endian hexadecimal (including witness data)
|
||||||
|
depends: number[]; // (json array) array of numbers // (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is
|
||||||
|
fee: number, // (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one
|
||||||
|
sigops: number, // (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero
|
||||||
|
weight: number // (numeric) total transaction weight, as counted for purposes of block limits
|
||||||
|
}
|
||||||
|
export interface IBlockTemplate {
|
||||||
|
// (json object)
|
||||||
|
version: number; // (numeric) The preferred block version
|
||||||
|
rules: string[]; // (json array) specific block rules that are to be enforced // (string) name of a rule the client must understand to some extent; see BIP 9 for format
|
||||||
|
|
||||||
|
vbavailable: { // (json object) set of pending, supported versionbit (BIP 9) softfork deployments
|
||||||
|
rulename: number, // (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule
|
||||||
|
},
|
||||||
|
vbrequired: number, // (numeric) bit mask of versionbits the server requires set in submissions
|
||||||
|
previousblockhash: string, // (string) The hash of current highest block
|
||||||
|
transactions: IBlockTemplateTx[], // (json array) contents of non-coinbase transactions that should be included in the next block
|
||||||
|
coinbaseaux: { // (json object) data that should be included in the coinbase's scriptSig content
|
||||||
|
key: string; //'hex', // (string) values must be in the coinbase (keys may be ignored)
|
||||||
|
},
|
||||||
|
coinbasevalue: number, // (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)
|
||||||
|
longpollid: string, // (string) an id to include with a request to longpoll on an update to this template
|
||||||
|
target: string, // (string) The hash target
|
||||||
|
mintime: number, // (numeric) The minimum timestamp appropriate for the next block time, expressed in UNIX epoch time
|
||||||
|
mutable: string[]; // (json array) list of ways the block template may be changed // (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'
|
||||||
|
noncerange: string; // 'hex', // (string) A range of valid nonces
|
||||||
|
sigoplimit: number, // (numeric) limit of sigops in blocks
|
||||||
|
sizelimit: number, // (numeric) limit of block size
|
||||||
|
weightlimit: number, // (numeric) limit of block weight
|
||||||
|
curtime: number, // (numeric) current timestamp in UNIX epoch time
|
||||||
|
bits: string, // (string) compressed target of next block
|
||||||
|
height: number, // (numeric) The height of the next block
|
||||||
|
default_witness_commitment: string // (string, optional) a valid witness commitment for the unmodified block template
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
export interface IMiningInfo {
|
||||||
|
blocks: number,
|
||||||
|
currentblockweight: number,
|
||||||
|
currentblocktx: number,
|
||||||
|
difficulty: number,
|
||||||
|
networkhashps: number,
|
||||||
|
pooledtx: number,
|
||||||
|
chain: 'main' | 'test' | 'regtest',
|
||||||
|
warnings: string
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user