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
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@nestjs/config": "^2.3.2",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-fastify": "^9.4.2",
"big.js": "^6.2.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"merkletreejs": "^0.3.10",
@ -2856,6 +2857,18 @@
"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": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
@ -11090,6 +11103,11 @@
"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": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",

View File

@ -24,6 +24,7 @@
"@nestjs/config": "^2.3.2",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-fastify": "^9.4.2",
"big.js": "^6.2.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"merkletreejs": "^0.3.10",

View File

@ -3,6 +3,6 @@ import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!@';
return 'Hello World!';
}
}

View File

@ -14,7 +14,7 @@ export class MiningJob {
public method: eResponseMethod.MINING_NOTIFY;
public params: string[];
public target: string;
public target: number;
public merkleRoot: string;
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 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: 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 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 response: string;
public versionMask: number;
constructor(blockTemplate: IBlockTemplate) {
console.log(blockTemplate);
this.job_id = randomUUID();
this.target = blockTemplate.target;
this.target = Number(blockTemplate.target);
this.prevhash = blockTemplate.previousblockhash;
this.version = blockTemplate.version.toString();
this.version = blockTemplate.version;
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;
const transactions = blockTemplate.transactions.map(tx => tx.hash);

View File

@ -1,16 +1,16 @@
import { plainToInstance } from 'class-transformer';
import { validate, ValidatorOptions } from 'class-validator';
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 { eRequestMethod } from './enums/eRequestMethod';
import { MiningJob } from './MiningJob';
import { AuthorizationMessage } from './stratum-messages/AuthorizationMessage';
import { ConfigurationMessage } from './stratum-messages/ConfigurationMessage';
import { MiningSubmitMessage } from './stratum-messages/MiningSubmitMessage';
import { SubscriptionMessage } from './stratum-messages/SubscriptionMessage';
import { SuggestDifficulty } from './stratum-messages/SuggestDifficultyMessage';
import { MiningJob } from './MiningJob';
export class StratumV1Client extends EasyUnsubscribe {
@ -24,6 +24,7 @@ export class StratumV1Client extends EasyUnsubscribe {
public onInitialized: BehaviorSubject<void> = new BehaviorSubject(null);
public localMiningJobEmitter: BehaviorSubject<MiningJob> = new BehaviorSubject(null);
public blockFoundEmitter: BehaviorSubject<any> = new BehaviorSubject(null);
private currentJob: MiningJob;
@ -216,8 +217,11 @@ export class StratumV1Client extends EasyUnsubscribe {
private handleMiningSubmission(submission: MiningSubmitMessage) {
const diff = submission.testNonceValue(this.currentJob, submission.nonce);
console.log(diff);
const networkDifficulty = 0;
const diff = submission.testNonceValue(this.currentJob, parseInt(submission.nonce, 16));
if (networkDifficulty < diff) {
this.blockFoundEmitter.next(true);
}
}
// private miningNotify() {

View File

@ -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);
});
});
});

View File

@ -1,18 +1,17 @@
import Big from 'big.js';
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 { eRequestMethod } from '../enums/eRequestMethod';
import { MiningJob } from '../MiningJob';
import { StratumBaseMessage } from './StratumBaseMessage';
const trueDiffOne = Number('26959535291011309493156476344723991336010898738574164086137773096960');
export class MiningSubmitMessage extends StratumBaseMessage {
@IsArray()
@ArrayMinSize(5)
@ArrayMaxSize(5)
params: string[];
public params: string[];
public userId: 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);
// TODO: Use the midstate hash instead of hashing the whole header
// Copy data from job to header
header.set(Buffer.from(job.version, 'hex').subarray(0, 4), 0);
header.set(Buffer.from(job.prevhash, 'hex').subarray(0, 32), 4);
header.set(Buffer.from(job.merkleRoot, 'hex').subarray(0, 32), 36);
header.set(Buffer.from(job.ntime).subarray(0, 4), 68);
header.set(Buffer.from(job.target, 'hex').subarray(0, 4), 72);
header.set(Buffer.from(nonce, 'hex').subarray(0, 4), 76);
const hashBuffer = crypto.createHash('sha256').update(header).digest();
const hashResult = crypto.createHash('sha256').update(hashBuffer).digest();
const d64 = 1.0;
const s64 = this.littleEndianToDouble(hashResult);
const ds = d64 / s64;
return ds;
}
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
const hexString = `0x${reversedBytes.toString('hex')}`;
// Interpret the hexadecimal string as a double
const doubleValue = Number(hexString);
// Check for NaN and Infinity
if (!Number.isFinite(doubleValue)) {
throw new Error('Conversion resulted in NaN or Infinity');
let rolledVersion = job.version;
for (let i = 0; i < midstateIndex; i++) {
rolledVersion = this.incrementBitmask(rolledVersion, job.versionMask);
}
return doubleValue;
header.writeUInt32LE(rolledVersion, 0);
Buffer.from(job.prevhash, 'hex').copy(header, 4);
Buffer.from(job.merkleRoot, 'hex').copy(header, 36);
header.writeUInt32LE(job.ntime, 68);
header.writeUInt32LE(job.target, 72);
header.writeUInt32LE(nonce, 76);
console.log(header);
const hashBuffer: Buffer = crypto.createHash('sha256').update(header).digest();
const hashResult: Buffer = crypto.createHash('sha256').update(hashBuffer).digest();
s64 = this.le256todouble(hashResult);
ds = truediffone.div(s64);
return ds.toString();
}
private le256todouble(target: Buffer): Big {
const bits192 = new Big(6277101735386680763835789423207666416102355444464034512896);
const bits128 = new Big(340282366920938463463374607431768211456);
const bits64 = new Big(18446744073709551616);
const data64_3 = target.readBigUInt64LE(24);
const data64_2 = target.readBigUInt64LE(16);
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;
}
public incrementBitmask(rolledVersion: number, versionMask: number) {
return (rolledVersion + 1) | versionMask;
}
}