test nonce work

This commit is contained in:
Ben Wilson
2023-06-14 21:34:40 -04:00
parent edd2845829
commit e74b2e0eb5
7 changed files with 115 additions and 52 deletions
+18
View File
@@ -13,6 +13,7 @@
"@nestjs/config": "^2.3.2", "@nestjs/config": "^2.3.2",
"@nestjs/core": "^9.0.0", "@nestjs/core": "^9.0.0",
"@nestjs/platform-fastify": "^9.4.2", "@nestjs/platform-fastify": "^9.4.2",
"big.js": "^6.2.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
@@ -2856,6 +2857,18 @@
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
}, },
"node_modules/big.js": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz",
"integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==",
"engines": {
"node": "*"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bigjs"
}
},
"node_modules/bignumber.js": { "node_modules/bignumber.js": {
"version": "9.1.1", "version": "9.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
@@ -11090,6 +11103,11 @@
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
}, },
"big.js": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz",
"integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ=="
},
"bignumber.js": { "bignumber.js": {
"version": "9.1.1", "version": "9.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
+1
View File
@@ -24,6 +24,7 @@
"@nestjs/config": "^2.3.2", "@nestjs/config": "^2.3.2",
"@nestjs/core": "^9.0.0", "@nestjs/core": "^9.0.0",
"@nestjs/platform-fastify": "^9.4.2", "@nestjs/platform-fastify": "^9.4.2",
"big.js": "^6.2.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
+1 -1
View File
@@ -3,6 +3,6 @@ import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class AppService { export class AppService {
getHello(): string { getHello(): string {
return 'Hello World!@'; return 'Hello World!';
} }
} }
+8 -6
View File
@@ -14,7 +14,7 @@ export class MiningJob {
public method: eResponseMethod.MINING_NOTIFY; public method: eResponseMethod.MINING_NOTIFY;
public params: string[]; public params: string[];
public target: string; public target: number;
public merkleRoot: 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: string; // ID of the job. Use this ID while submitting share generated from this job.
@@ -22,24 +22,26 @@ export class MiningJob {
public coinb1: string; // The hex-encoded prefix of the coinbase transaction (to precede extra nonce 2). 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 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 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: string; // The hex-encoded block version. public version: number; // The hex-encoded block version.
public nbits: string; // The hex-encoded network difficulty required for the block. public nbits: string; // The hex-encoded network difficulty required for the block.
public ntime: string; // Current ntime/ 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 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 response: string;
public versionMask: number;
constructor(blockTemplate: IBlockTemplate) { constructor(blockTemplate: IBlockTemplate) {
console.log(blockTemplate); console.log(blockTemplate);
this.job_id = randomUUID(); this.job_id = randomUUID();
this.target = blockTemplate.target; this.target = Number(blockTemplate.target);
this.prevhash = blockTemplate.previousblockhash; this.prevhash = blockTemplate.previousblockhash;
this.version = blockTemplate.version.toString(); this.version = blockTemplate.version;
this.nbits = blockTemplate.bits; this.nbits = blockTemplate.bits;
this.ntime = Math.floor(new Date().getTime() / 1000).toString(); this.ntime = Math.floor(new Date().getTime() / 1000);
this.clean_jobs = false; this.clean_jobs = false;
const transactions = blockTemplate.transactions.map(tx => tx.hash); const transactions = blockTemplate.transactions.map(tx => tx.hash);
+8 -4
View File
@@ -1,16 +1,16 @@
import { plainToInstance } from 'class-transformer'; import { plainToInstance } from 'class-transformer';
import { validate, ValidatorOptions } from 'class-validator'; import { validate, ValidatorOptions } from 'class-validator';
import { Socket } from 'net'; import { Socket } from 'net';
import { BehaviorSubject, combineLatest, concat, merge, Observable, takeUntil } from 'rxjs'; import { BehaviorSubject, merge, Observable, takeUntil } from 'rxjs';
import { EasyUnsubscribe } from '../utils/AutoUnsubscribe'; import { EasyUnsubscribe } from '../utils/AutoUnsubscribe';
import { eRequestMethod } from './enums/eRequestMethod'; import { eRequestMethod } from './enums/eRequestMethod';
import { MiningJob } from './MiningJob';
import { AuthorizationMessage } from './stratum-messages/AuthorizationMessage'; import { AuthorizationMessage } from './stratum-messages/AuthorizationMessage';
import { ConfigurationMessage } from './stratum-messages/ConfigurationMessage'; import { ConfigurationMessage } from './stratum-messages/ConfigurationMessage';
import { MiningSubmitMessage } from './stratum-messages/MiningSubmitMessage'; import { MiningSubmitMessage } from './stratum-messages/MiningSubmitMessage';
import { SubscriptionMessage } from './stratum-messages/SubscriptionMessage'; import { SubscriptionMessage } from './stratum-messages/SubscriptionMessage';
import { SuggestDifficulty } from './stratum-messages/SuggestDifficultyMessage'; import { SuggestDifficulty } from './stratum-messages/SuggestDifficultyMessage';
import { MiningJob } from './MiningJob';
export class StratumV1Client extends EasyUnsubscribe { export class StratumV1Client extends EasyUnsubscribe {
@@ -24,6 +24,7 @@ export class StratumV1Client extends EasyUnsubscribe {
public onInitialized: BehaviorSubject<void> = new BehaviorSubject(null); public onInitialized: BehaviorSubject<void> = new BehaviorSubject(null);
public localMiningJobEmitter: BehaviorSubject<MiningJob> = new BehaviorSubject(null); public localMiningJobEmitter: BehaviorSubject<MiningJob> = new BehaviorSubject(null);
public blockFoundEmitter: BehaviorSubject<any> = new BehaviorSubject(null);
private currentJob: MiningJob; private currentJob: MiningJob;
@@ -216,8 +217,11 @@ export class StratumV1Client extends EasyUnsubscribe {
private handleMiningSubmission(submission: MiningSubmitMessage) { private handleMiningSubmission(submission: MiningSubmitMessage) {
const diff = submission.testNonceValue(this.currentJob, submission.nonce); const networkDifficulty = 0;
console.log(diff); const diff = submission.testNonceValue(this.currentJob, parseInt(submission.nonce, 16));
if (networkDifficulty < diff) {
this.blockFoundEmitter.next(true);
}
} }
// private miningNotify() { // private miningNotify() {
@@ -0,0 +1,27 @@
import { MiningJob } from '../MiningJob';
import { MiningSubmitMessage } from './MiningSubmitMessage';
describe('MiningSubmitMessage', () => {
beforeEach(async () => {
});
describe('root', () => {
const value = new MiningSubmitMessage().testNonceValue({
version: 0x20000004,
prevhash: "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000",
merkleRoot: "5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb",
ntime: 0x647025b5,
target: 0x1705ae3a,
} as MiningJob, 0x0a029ed1);
it('should be correct difficulty', () => {
expect(value).toEqual(683);
});
});
});
@@ -1,18 +1,17 @@
import Big from 'big.js';
import { ArrayMaxSize, ArrayMinSize, IsArray } from 'class-validator'; import { ArrayMaxSize, ArrayMinSize, IsArray } from 'class-validator';
import { eRequestMethod } from '../enums/eRequestMethod';
import { StratumBaseMessage } from './StratumBaseMessage';
import { MiningJob } from '../MiningJob';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import { eRequestMethod } from '../enums/eRequestMethod';
import { MiningJob } from '../MiningJob';
import { StratumBaseMessage } from './StratumBaseMessage';
const trueDiffOne = Number('26959535291011309493156476344723991336010898738574164086137773096960');
export class MiningSubmitMessage extends StratumBaseMessage { export class MiningSubmitMessage extends StratumBaseMessage {
@IsArray() @IsArray()
@ArrayMinSize(5) @ArrayMinSize(5)
@ArrayMaxSize(5) @ArrayMaxSize(5)
params: string[]; public params: string[];
public userId: string; public userId: string;
public jobId: string; public jobId: string;
@@ -43,48 +42,60 @@ export class MiningSubmitMessage extends StratumBaseMessage {
} }
testNonceValue(job: MiningJob, nonce: string): number { testNonceValue(job: MiningJob, nonce: number, midstateIndex: number = 0): string {
const truediffone = Big('26959535291011309493156476344723991336010898738574164086137773096960');
let s64: Big, ds: number;
const header = Buffer.alloc(80); const header = Buffer.alloc(80);
// TODO: Use the midstate hash instead of hashing the whole header // TODO: Use the midstate hash instead of hashing the whole header
// Copy data from job to header // Copy data from job to header
let rolledVersion = job.version;
for (let i = 0; i < midstateIndex; i++) {
rolledVersion = this.incrementBitmask(rolledVersion, job.versionMask);
}
header.set(Buffer.from(job.version, 'hex').subarray(0, 4), 0); header.writeUInt32LE(rolledVersion, 0);
header.set(Buffer.from(job.prevhash, 'hex').subarray(0, 32), 4); Buffer.from(job.prevhash, 'hex').copy(header, 4);
header.set(Buffer.from(job.merkleRoot, 'hex').subarray(0, 32), 36); Buffer.from(job.merkleRoot, 'hex').copy(header, 36);
header.set(Buffer.from(job.ntime).subarray(0, 4), 68); header.writeUInt32LE(job.ntime, 68);
header.set(Buffer.from(job.target, 'hex').subarray(0, 4), 72); header.writeUInt32LE(job.target, 72);
header.set(Buffer.from(nonce, 'hex').subarray(0, 4), 76); header.writeUInt32LE(nonce, 76);
console.log(header);
const hashBuffer = crypto.createHash('sha256').update(header).digest(); const hashBuffer: Buffer = crypto.createHash('sha256').update(header).digest();
const hashResult = crypto.createHash('sha256').update(hashBuffer).digest(); const hashResult: Buffer = crypto.createHash('sha256').update(hashBuffer).digest();
const d64 = 1.0; s64 = this.le256todouble(hashResult);
const s64 = this.littleEndianToDouble(hashResult); ds = truediffone.div(s64);
const ds = d64 / s64;
return ds; return ds.toString();
} }
private littleEndianToDouble(buffer: Buffer): number {
// Reverse the byte order to big-endian
const reversedBytes = Buffer.from(buffer).reverse();
// Convert the reversed bytes to a hexadecimal string private le256todouble(target: Buffer): Big {
const hexString = `0x${reversedBytes.toString('hex')}`;
// Interpret the hexadecimal string as a double const bits192 = new Big(6277101735386680763835789423207666416102355444464034512896);
const doubleValue = Number(hexString); const bits128 = new Big(340282366920938463463374607431768211456);
const bits64 = new Big(18446744073709551616);
// Check for NaN and Infinity const data64_3 = target.readBigUInt64LE(24);
if (!Number.isFinite(doubleValue)) { const data64_2 = target.readBigUInt64LE(16);
throw new Error('Conversion resulted in NaN or Infinity'); const data64_1 = target.readBigUInt64LE(8);
const data64_0 = target.readBigUInt64LE(0);
const dcut64 = new Big(data64_3).times(bits192)
.plus(new Big(data64_2).times(bits128))
.plus(new Big(data64_1).times(bits64))
.plus(new Big(data64_0));
return dcut64;
} }
return doubleValue; public incrementBitmask(rolledVersion: number, versionMask: number) {
return (rolledVersion + 1) | versionMask;
} }
} }