mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2025-03-27 02:02:10 +01:00
diffs working
This commit is contained in:
parent
c3744d0d00
commit
ca0668b807
@ -1,9 +1,8 @@
|
||||
import * as crypto from 'crypto';
|
||||
import { MerkleTree } from 'merkletreejs';
|
||||
|
||||
import { IBlockTemplate } from './bitcoin-rpc/IBlockTemplate';
|
||||
import { eResponseMethod } from './enums/eResponseMethod';
|
||||
import { IBlockTemplate, IBlockTemplateTx } from './bitcoin-rpc/IBlockTemplate';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { MerkleTree } from 'merkletreejs'
|
||||
|
||||
interface AddressObject {
|
||||
address: string;
|
||||
@ -14,37 +13,39 @@ export class MiningJob {
|
||||
public method: eResponseMethod.MINING_NOTIFY;
|
||||
public params: string[];
|
||||
|
||||
public target: number;
|
||||
public target: string;
|
||||
public merkleRoot: string;
|
||||
|
||||
public job_id: string; // ID of the job. Use this ID while submitting share generated from this job.
|
||||
public job_id: number; // ID of the job. Use this ID while submitting share generated from this job.
|
||||
public prevhash: string; // The hex-encoded previous block hash.
|
||||
public coinb1: string; // The hex-encoded prefix of the coinbase transaction (to precede extra nonce 2).
|
||||
public coinb2: string; //The hex-encoded suffix of the coinbase transaction (to follow extra nonce 2).
|
||||
public merkle_branch: string[]; // List of hashes, will be used for calculation of merkle root. This is not a list of all transactions, it only contains prepared hashes of steps of merkle tree algorithm.
|
||||
public version: number; // The hex-encoded block version.
|
||||
public nbits: string; // The hex-encoded network difficulty required for the block.
|
||||
public nbits: number; // The hex-encoded network difficulty required for the block.
|
||||
public ntime: number; // 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 response: string;
|
||||
|
||||
public versionMask: number;
|
||||
public versionMask: string;
|
||||
|
||||
public tree: MerkleTree;
|
||||
|
||||
constructor(blockTemplate: IBlockTemplate) {
|
||||
|
||||
console.log(blockTemplate);
|
||||
//console.log(blockTemplate);
|
||||
|
||||
this.job_id = randomUUID();
|
||||
this.target = Number(blockTemplate.target);
|
||||
this.prevhash = blockTemplate.previousblockhash;
|
||||
this.job_id = 1;
|
||||
this.target = blockTemplate.target;
|
||||
this.prevhash = this.convertToLittleEndian(blockTemplate.previousblockhash);
|
||||
|
||||
this.version = blockTemplate.version;
|
||||
this.nbits = blockTemplate.bits;
|
||||
this.nbits = parseInt(blockTemplate.bits, 16);
|
||||
this.ntime = Math.floor(new Date().getTime() / 1000);
|
||||
this.clean_jobs = false;
|
||||
|
||||
const transactions = blockTemplate.transactions.map(tx => tx.hash);
|
||||
|
||||
const transactionFees = blockTemplate.transactions.reduce((pre, cur, i, arr) => {
|
||||
return pre + cur.fee;
|
||||
}, 0);
|
||||
@ -57,25 +58,31 @@ export class MiningJob {
|
||||
this.coinb1 = coinbasePart1;
|
||||
this.coinb2 = coinbasePart2;
|
||||
|
||||
const coinbaseHash = this.bufferToHex(this.sha256(this.coinb1 + this.coinb2));
|
||||
const coinbaseHash = this.sha256(this.coinb1 + this.coinb2).toString('hex');
|
||||
const coinbaseBuffer = Buffer.from(coinbaseHash, 'hex');
|
||||
|
||||
transactions.unshift(coinbaseHash);
|
||||
//transactions.unshift(coinbaseHash);
|
||||
|
||||
// Calculate merkle branch
|
||||
const transactionBuffers = blockTemplate.transactions.map(tx => Buffer.from(tx.hash, 'hex'));
|
||||
transactionBuffers.unshift(coinbaseBuffer);
|
||||
this.tree = new MerkleTree(transactionBuffers, this.sha256, { isBitcoinTree: true });
|
||||
|
||||
const tree = new MerkleTree(transactions, this.sha256, { isBitcoinTree: true });
|
||||
const layers = tree.getLayers();
|
||||
|
||||
const branch = [];
|
||||
// // this.merkle_branch = tree.getProof(coinbaseBuffer).map(p => p.data.toString('hex'))
|
||||
|
||||
for (const layer of layers) {
|
||||
branch.push(this.bufferToHex(layer[0]));
|
||||
}
|
||||
//console.log(branch);
|
||||
// this.merkle_branch = tree.getLayers().map(l => l.pop().toString('hex'));
|
||||
// this.merkleRoot = this.merkle_branch.pop();
|
||||
|
||||
this.merkle_branch = branch;
|
||||
const rootBuffer = this.tree.getRoot();
|
||||
this.merkleRoot = rootBuffer.toString('hex');
|
||||
this.merkle_branch = this.tree.getProof(coinbaseBuffer).map(p => p.data.toString('hex'));
|
||||
|
||||
this.merkleRoot = tree.getRoot().toString('hex')
|
||||
|
||||
// let test = this.tree.getRoot();
|
||||
// for (let i = 0; i < test.length; i++) {
|
||||
// console.log(test[i])
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@ -148,14 +155,14 @@ export class MiningJob {
|
||||
id: 0,
|
||||
method: eResponseMethod.MINING_NOTIFY,
|
||||
params: [
|
||||
this.job_id,
|
||||
this.job_id.toString(16),
|
||||
this.prevhash,
|
||||
this.coinb1,
|
||||
this.coinb2,
|
||||
this.merkle_branch,
|
||||
this.version,
|
||||
this.nbits,
|
||||
this.ntime,
|
||||
this.version.toString(16),
|
||||
this.nbits.toString(16),
|
||||
this.ntime.toString(16),
|
||||
this.clean_jobs
|
||||
]
|
||||
};
|
||||
@ -165,6 +172,12 @@ export class MiningJob {
|
||||
}
|
||||
|
||||
|
||||
private convertToLittleEndian(hash: string): string {
|
||||
const bytes = Buffer.from(hash, 'hex');
|
||||
Array.prototype.reverse.call(bytes);
|
||||
return bytes.toString('hex');
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -218,7 +218,9 @@ export class StratumV1Client extends EasyUnsubscribe {
|
||||
|
||||
private handleMiningSubmission(submission: MiningSubmitMessage) {
|
||||
const networkDifficulty = 0;
|
||||
const diff = submission.testNonceValue(this.currentJob, parseInt(submission.nonce, 16));
|
||||
const diff = submission.testNonceValue(this.currentJob, submission);
|
||||
console.log('DIFF');
|
||||
console.log(diff);
|
||||
if (networkDifficulty < diff) {
|
||||
this.blockFoundEmitter.next(true);
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
import { MiningJob } from '../MiningJob';
|
||||
import { MiningSubmitMessage } from './MiningSubmitMessage';
|
||||
|
||||
describe('MiningSubmitMessage', () => {
|
||||
|
||||
|
||||
@ -10,18 +7,48 @@ describe('MiningSubmitMessage', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
// describe('test nonce', () => {
|
||||
|
||||
const value = new MiningSubmitMessage().testNonceValue({
|
||||
version: 0x20000004,
|
||||
prevhash: "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000",
|
||||
merkleRoot: "5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb",
|
||||
ntime: 0x647025b5,
|
||||
target: 0x1705ae3a,
|
||||
} as MiningJob, 167943889);
|
||||
// const value = new MiningSubmitMessage().testNonceValue({
|
||||
// version: 0x20000004,
|
||||
// prevhash: "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000",
|
||||
// merkleRoot: "5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb",
|
||||
// ntime: 0x647025b5,
|
||||
// nbits: 0x1705ae3a,
|
||||
// } as unknown as MiningJob, 167943889);
|
||||
|
||||
it('should be correct difficulty', () => {
|
||||
expect(value).toEqual(683);
|
||||
});
|
||||
});
|
||||
// it('should be correct difficulty', () => {
|
||||
// expect(value).toEqual(683);
|
||||
// });
|
||||
// });
|
||||
|
||||
// describe('test empty version', () => {
|
||||
|
||||
// const value = new MiningSubmitMessage().testNonceValue({
|
||||
// version: 0x20000004,
|
||||
// prevhash: "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000",
|
||||
// merkleRoot: "5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb",
|
||||
// ntime: 0x647025b5,
|
||||
// nbits: 0x1705ae3a,
|
||||
// } as unknown as MiningJob, 167943889, parseInt('00000000', 16));
|
||||
|
||||
// it('should be correct difficulty', () => {
|
||||
// expect(value).toEqual(683);
|
||||
// });
|
||||
// });
|
||||
|
||||
// describe('test high value nonce', () => {
|
||||
|
||||
// const value = new MiningSubmitMessage().testNonceValue({
|
||||
// version: 0x20a00000,
|
||||
// prevhash: "00000000000000000002a7b66a599d17893cb312a8ee7bc15e4015ff52774f00",
|
||||
// merkleRoot: "210bbf45c85165aab889691056cfebbfd763e11b2623a261fb6135b6bab66ce3",
|
||||
// ntime: 1686839100,
|
||||
// target: 52350439455487,
|
||||
// } as MiningJob, 0x05d69c40,);
|
||||
|
||||
// it('should be correct difficulty', () => {
|
||||
// expect(value).toEqual(683);
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ export class MiningSubmitMessage extends StratumBaseMessage {
|
||||
|
||||
@IsArray()
|
||||
@ArrayMinSize(5)
|
||||
@ArrayMaxSize(5)
|
||||
@ArrayMaxSize(6)
|
||||
public params: string[];
|
||||
|
||||
public userId: string;
|
||||
@ -18,7 +18,7 @@ export class MiningSubmitMessage extends StratumBaseMessage {
|
||||
public extraNonce2: string;
|
||||
public ntime: string;
|
||||
public nonce: string
|
||||
|
||||
public versionMask: string;
|
||||
constructor() {
|
||||
super();
|
||||
this.method = eRequestMethod.AUTHORIZE;
|
||||
@ -31,6 +31,7 @@ export class MiningSubmitMessage extends StratumBaseMessage {
|
||||
this.extraNonce2 = this.params[2];
|
||||
this.ntime = this.params[3];
|
||||
this.nonce = this.params[4];
|
||||
this.versionMask = this.params[5];
|
||||
}
|
||||
|
||||
public response() {
|
||||
@ -42,42 +43,57 @@ export class MiningSubmitMessage extends StratumBaseMessage {
|
||||
}
|
||||
|
||||
|
||||
testNonceValue(job: MiningJob, nonce: number, midstateIndex: number = 0): number {
|
||||
public testNonceValue(job: MiningJob, submission: MiningSubmitMessage): number {
|
||||
|
||||
const nonce = parseInt(submission.nonce, 16);
|
||||
const versionMask = parseInt(submission.versionMask, 16);
|
||||
const extraNonce = 'ccc5d664';
|
||||
const extraNonce2 = submission.extraNonce2;
|
||||
|
||||
const coinbaseTx = `${job.coinb1}${extraNonce}${extraNonce2}${job.coinb2}`;
|
||||
|
||||
const newRoot = this.calculateMerkleRootHash(coinbaseTx, job.merkle_branch)
|
||||
|
||||
|
||||
const truediffone = Big('26959535291011309493156476344723991336010898738574164086137773096960');
|
||||
let s64: string;
|
||||
|
||||
const header = Buffer.alloc(80);
|
||||
|
||||
// TODO: Use the midstate hash instead of hashing the whole header
|
||||
|
||||
// Copy data from job to header
|
||||
|
||||
let rolledVersion = job.version;
|
||||
for (let i = 0; i < midstateIndex; i++) {
|
||||
rolledVersion = this.incrementBitmask(rolledVersion, job.versionMask);
|
||||
let version = job.version;
|
||||
if (versionMask !== undefined && versionMask != 0) {
|
||||
version = (version ^ versionMask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
header.writeInt32LE(rolledVersion, 0);
|
||||
header.write(this.convertStringToLE(job.prevhash), 4, 'hex')
|
||||
Buffer.from(job.merkleRoot, 'hex').copy(header, 36, 0, 32)
|
||||
header.writeInt32LE(job.ntime, 68);
|
||||
header.writeInt32LE(job.target, 72);
|
||||
header.writeInt32LE(nonce, 76);
|
||||
|
||||
header.writeUInt32LE(version, 0);
|
||||
|
||||
header.write(this.swapEndianWords(job.prevhash), 4, 'hex')
|
||||
newRoot.copy(header, 36, 0, 32)
|
||||
header.writeUInt32LE(job.ntime, 68);
|
||||
header.writeBigUint64LE(BigInt(job.nbits), 72);
|
||||
header.writeUInt32LE(nonce, 76);
|
||||
|
||||
// for (let i = 0; i < 80; i++) {
|
||||
// console.log(header[i].toString(10));
|
||||
// }
|
||||
|
||||
|
||||
const hashBuffer: Buffer = crypto.createHash('sha256').update(header).digest();
|
||||
const hashResult: Buffer = crypto.createHash('sha256').update(hashBuffer).digest();
|
||||
|
||||
|
||||
s64 = this.le256todouble(hashResult);
|
||||
let s64 = this.le256todouble(hashResult);
|
||||
|
||||
return parseInt(truediffone.div(s64).toString());
|
||||
return parseInt(truediffone.div(s64.toString()).toString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
private convertStringToLE(str: string) {
|
||||
private swapEndianWords(str: string) {
|
||||
const hexGroups = str.match(/.{1,8}/g);
|
||||
// Reverse each group and concatenate them
|
||||
const reversedHexString = hexGroups.reduce((pre, cur, indx, arr) => {
|
||||
@ -88,18 +104,37 @@ export class MiningSubmitMessage extends StratumBaseMessage {
|
||||
}
|
||||
|
||||
|
||||
private le256todouble(target: Buffer): string {
|
||||
private le256todouble(target: Buffer): bigint {
|
||||
|
||||
const number = target.reduceRight((acc, byte) => {
|
||||
// Shift the number 8 bits to the left and OR with the current byte
|
||||
return (acc << BigInt(8)) | BigInt(byte);
|
||||
}, BigInt(0));
|
||||
|
||||
return number.toString();
|
||||
return number;
|
||||
|
||||
}
|
||||
|
||||
public incrementBitmask(rolledVersion: number, versionMask: number) {
|
||||
return (rolledVersion + 1) | versionMask;
|
||||
private calculateMerkleRootHash(coinbaseTx: string, merkleBranches: string[]): Buffer {
|
||||
|
||||
let coinbaseTxBuf = Buffer.from(coinbaseTx, 'hex');
|
||||
|
||||
const bothMerkles = Buffer.alloc(64);
|
||||
let test = this.sha256(coinbaseTxBuf)
|
||||
let newRoot = this.sha256(test);
|
||||
bothMerkles.set(newRoot);
|
||||
|
||||
for (let i = 0; i < merkleBranches.length; i++) {
|
||||
bothMerkles.set(Buffer.from(merkleBranches[i], 'hex'), 32);
|
||||
newRoot = this.sha256(this.sha256(bothMerkles));
|
||||
bothMerkles.set(newRoot);
|
||||
}
|
||||
|
||||
return bothMerkles;
|
||||
}
|
||||
|
||||
private sha256(data: Buffer) {
|
||||
return crypto.createHash('sha256').update(data).digest()
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user