Skip to content

Commit

Permalink
Merge pull request #286 from pk910/contract-miner
Browse files Browse the repository at this point in the history
Implement nickminer algorithm for `pow` module
  • Loading branch information
pk910 authored Sep 16, 2024
2 parents 34283cd + a4f1536 commit a0f2ef1
Show file tree
Hide file tree
Showing 31 changed files with 1,206 additions and 132 deletions.
3 changes: 3 additions & 0 deletions faucet-client/build-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ function copyIfFoundOrRemove(filename, dstpath, dstname) {
copyIfFound("powfaucet-worker-a2.js", path.join(staticPath, "js"));
copyIfFoundOrRemove("powfaucet-worker-a2.js.map", path.join(staticPath, "js"));

copyIfFound("powfaucet-worker-nm.js", path.join(staticPath, "js"));
copyIfFoundOrRemove("powfaucet-worker-nm.js.map", path.join(staticPath, "js"));

console.log("finished");
});

9 changes: 8 additions & 1 deletion faucet-client/src/common/FaucetConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ export interface IPoWModuleConfig {
powIdleTimeout: number;
powParams: PoWParams;
powDifficulty: number;
powNonceCount: number;
powHashrateLimit: number;
}

Expand All @@ -94,6 +93,14 @@ export type PoWParams = {
m: number; // memoryCost
p: number; // parallelization,
l: number; // keyLength
} | {
a: PoWHashAlgo.NICKMINER;
i: string; // input hash
r: string; // sigR
v: number; // sigV
c: number; // count
s: string; // suffix
p: string; // prefix
}

export interface IPassportModuleConfig {
Expand Down
3 changes: 1 addition & 2 deletions faucet-client/src/components/mining/MiningPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export class MiningPage extends React.PureComponent<IMiningPageProps, IMiningPag
time: this.props.pageContext.faucetApi.getFaucetTime(),
session: this.powSession,
hashrateLimit: this.props.faucetConfig.modules.pow.powHashrateLimit,
nonceCount: this.props.faucetConfig.modules.pow.powNonceCount,
powParams: this.props.faucetConfig.modules.pow.powParams,
difficulty: this.props.faucetConfig.modules.pow.powDifficulty,
workerSrc: this.props.pageContext.faucetUrls.minerSrc,
Expand Down Expand Up @@ -239,7 +238,7 @@ export class MiningPage extends React.PureComponent<IMiningPageProps, IMiningPag
);
}

this.powMiner.setPoWParams(this.props.faucetConfig.modules.pow.powParams, this.props.faucetConfig.modules.pow.powDifficulty, this.props.faucetConfig.modules.pow.powNonceCount);
this.powMiner.setPoWParams(this.props.faucetConfig.modules.pow.powParams, this.props.faucetConfig.modules.pow.powDifficulty);

return (
<div className='page-mining'>
Expand Down
37 changes: 22 additions & 15 deletions faucet-client/src/pow/PoWMiner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export interface IPoWMinerOptions {
workerSrc: PoWMinerWorkerSrc;
powParams: PoWParams;
difficulty: number;
nonceCount: number;
hashrateLimit: number;
}

Expand Down Expand Up @@ -41,15 +40,22 @@ export interface IPoWMinerStats {
}

export interface IPoWMinerShare {
nonces: number[];
nonce: number;
data: string;
params: string;
hashrate: number;
}

export interface IPoWMinerNonce {
nonce: number;
data: string;
}

export interface IPoWMinerVerification {
shareId: string;
preimage: string;
nonces: number[];
nonce: number;
data: string;
}

interface PoWMinerEvents {
Expand All @@ -64,7 +70,7 @@ export class PoWMiner extends TypedEmitter<PoWMinerEvents> {
private workers: IPoWMinerWorker[];
private verifyWorker: IPoWMinerWorker;
private powParamsStr: string;
private nonceQueue: number[];
private nonceQueue: IPoWMinerNonce[];
private lastSaveNonce: number;
private updateStatsTimer: NodeJS.Timeout;
private totalShares: number;
Expand Down Expand Up @@ -112,9 +118,7 @@ export class PoWMiner extends TypedEmitter<PoWMinerEvents> {
}
}

public setPoWParams(params: PoWParams, difficulty: number, nonceCount: number) {
this.options.nonceCount = nonceCount;

public setPoWParams(params: PoWParams, difficulty: number) {
let powParamsStr = getPoWParamsStr(params, difficulty);
if(this.powParamsStr === powParamsStr)
return;
Expand Down Expand Up @@ -327,9 +331,12 @@ export class PoWMiner extends TypedEmitter<PoWMinerEvents> {

let insertIdx = 0;
let queueLen = this.nonceQueue.length;
while(insertIdx < queueLen && nonce.nonce > this.nonceQueue[insertIdx])
while(insertIdx < queueLen && nonce.nonce > this.nonceQueue[insertIdx].nonce)
insertIdx++;
this.nonceQueue.splice(insertIdx, 0, nonce.nonce);
this.nonceQueue.splice(insertIdx, 0, {
nonce: nonce.nonce,
data: nonce.data,
});

this.processNonceQueue();
}
Expand All @@ -350,25 +357,25 @@ export class PoWMiner extends TypedEmitter<PoWMinerEvents> {

let saveNonces = 0;
let queueLen = this.nonceQueue.length;
if(queueLen < this.options.nonceCount)
return;

for(let i = 0; i < queueLen; i++) {
if(this.nonceQueue[i] > saveNonce)
if(this.nonceQueue[i].nonce > saveNonce)
break;
saveNonces++;
}

while(saveNonces >= this.options.nonceCount) {
while(saveNonces >= 1) {
let nonce = this.nonceQueue.splice(0, 1)[0];
let share: IPoWMinerShare = {
nonces: this.nonceQueue.splice(0, this.options.nonceCount),
nonce: nonce.nonce,
data: nonce.data,
params: this.powParamsStr,
hashrate: this.latestStats ? this.latestStats.hashRate : 0,
};

this.totalShares++;
this.lastShareTime = this.options.time.getSyncedDate();
saveNonces -= this.options.nonceCount;
saveNonces -= 1;
this.options.session.submitShare(share);
}
}
Expand Down
2 changes: 2 additions & 0 deletions faucet-client/src/types/PoWMinerSrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum PoWHashAlgo {
SCRYPT = "scrypt",
CRYPTONIGHT = "cryptonight",
ARGON2 = "argon2",
NICKMINER = "nickminer",
}

export type PoWMinerWorkerSrc = {
Expand All @@ -15,5 +16,6 @@ export function getPoWMinerDefaultSrc(baseUrl: string): PoWMinerWorkerSrc {
[PoWHashAlgo.SCRYPT]: joinUrl(baseUrl, "/js/powfaucet-worker-sc.js?" + FAUCET_CLIENT_BUILDTIME),
[PoWHashAlgo.CRYPTONIGHT]: joinUrl(baseUrl, "/js/powfaucet-worker-cn.js?" + FAUCET_CLIENT_BUILDTIME),
[PoWHashAlgo.ARGON2]: joinUrl(baseUrl, "/js/powfaucet-worker-a2.js?" + FAUCET_CLIENT_BUILDTIME),
[PoWHashAlgo.NICKMINER]: joinUrl(baseUrl, "/js/powfaucet-worker-nm.js?" + FAUCET_CLIENT_BUILDTIME),
};
}
2 changes: 2 additions & 0 deletions faucet-client/src/utils/PoWParamsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ export function getPoWParamsStr(params: PoWParams, difficulty: number): string {
return params.a+"|"+params.c + "|" + params.v + "|" + params.h + "|" + difficulty;
case PoWHashAlgo.ARGON2:
return params.a+"|"+params.t + "|" + params.v + "|" + params.i + "|" + params.m + "|" + params.p + "|" + params.l + "|" + difficulty;
case PoWHashAlgo.NICKMINER:
return params.a+"|"+params.i + "|" + params.r + "|" + params.v + "|" + params.c + "|" + params.s + "|" + params.p + "|" + difficulty;
}
}
43 changes: 35 additions & 8 deletions faucet-client/src/worker/PoWWorker.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getPoWParamsStr } from "../utils/PoWParamsHelper";
import { PoWParams } from "../common/FaucetConfig";
import { base64ToHex } from "../utils/ConvertHelpers";
import { PoWHashAlgo } from "../types/PoWMinerSrc";

export type PoWWorkerHashFn = (nonceHex: string, preimgHex: string, params: PoWParams) => string;

export interface IPoWWorkerOptions {
hashFn: PoWWorkerHashFn;
configFn?: (preimg: string, params: PoWParams) => void;
}

interface IPoWWorkerParams {
Expand Down Expand Up @@ -74,6 +76,10 @@ export class PoWWorker {
}];
this.workNonce = data.nonceStart;

if(this.options.configFn) {
this.options.configFn(this.powPreImage, this.powParams.params);
}

this.startWorkLoop();
}

Expand All @@ -89,17 +95,27 @@ export class PoWWorker {

private onCtrlSetParams(data: any) {
this.powParams = this.getWorkerParams(data.params, data.difficulty);
if(this.options.configFn) {
this.options.configFn(this.powPreImage, this.powParams.params);
}
}

private onCtrlVerify(share: any) {
let preimg = base64ToHex(share.preimage);

let isValid = (share.nonces.length > 0);
for(var i = 0; i < share.nonces.length && isValid; i++) {
if(!this.checkHash(share.nonces[i], preimg)) {
isValid = false;
break;
}
let isValid = true;
if(this.options.configFn) {
this.options.configFn(preimg, this.powParams.params);
}
let hash = this.checkHash(share.nonce, preimg);
if(!hash) {
isValid = false;
} else if(this.powParams.params.a === PoWHashAlgo.NICKMINER && hash !== share.data) {
isValid = false;
}

if(this.options.configFn) {
this.options.configFn(this.powPreImage, this.powParams.params);
}

postMessage({
Expand Down Expand Up @@ -200,6 +216,7 @@ export class PoWWorker {
action: "nonce",
data: {
nonce: nonce,
data: this.powParams.params.a === PoWHashAlgo.NICKMINER ? hash : null,
params: this.powParams.pstr,
}
});
Expand All @@ -216,8 +233,18 @@ export class PoWWorker {
this.statsCount++;
let hashHex = this.options.hashFn(nonceHex, preimg, this.powParams.params);

let startOfHash = hashHex.substring(0, this.powParams.dmask.length);
return (startOfHash <= this.powParams.dmask) ? hashHex : null;
if (this.powParams.params.a === PoWHashAlgo.NICKMINER) {
if(hashHex.substring(0, 2) != "0x") {
console.error("NickMiner error:", hashHex);
return null;
}

let difficulty = parseInt(hashHex.substring(2, 4), 16);
return (difficulty >= this.powParams.difficulty) ? hashHex : null;
} else {
let startOfHash = hashHex.substring(0, this.powParams.dmask.length);
return (startOfHash <= this.powParams.dmask) ? hashHex : null;
}
}

}
25 changes: 25 additions & 0 deletions faucet-client/src/worker/worker-nickminer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

import { PoWWorker } from "./PoWWorker";
import { getNickMiner, getNickMinerReadyPromise } from "../../../libs/nickminer_wasm.cjs";
import { PoWHashAlgo } from "../types/PoWMinerSrc";

(() => {
getNickMinerReadyPromise().then(() => {
let nickMiner = getNickMiner();
nickMiner.miner_init();

new PoWWorker({
hashFn: (nonce, preimg, params) => {
if(params.a !== PoWHashAlgo.NICKMINER)
return null;
return nickMiner.miner_run(nonce);
},
configFn: (preimg, params) => {
if(params.a !== PoWHashAlgo.NICKMINER)
return null;
nickMiner.miner_set_config(params.i, params.r, params.v, params.s, params.c, preimg);
}
});

})
})();
8 changes: 7 additions & 1 deletion faucet-client/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ var webpackModuleConfigs = [
path: path.join(__dirname, '/dist'),
filename: 'powfaucet-worker-a2.js',
},

},
{
entry: './src/worker/worker-nickminer',
output: {
path: path.join(__dirname, '/dist'),
filename: 'powfaucet-worker-nm.js',
},
},
];

Expand Down
2 changes: 1 addition & 1 deletion faucet-config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ modules:
powDifficulty: 11

# mining algorithm to use
powHashAlgo: "argon2" # scrypt / cryptonight / argon2
powHashAlgo: "argon2" # scrypt / cryptonight / argon2 / nickminer

# pow module settings have been trimmed for readability.
# you can find all available settings on https://github.com/pk910/PoWFaucet/wiki/Operator-Wiki#module-pow
Expand Down
3 changes: 3 additions & 0 deletions faucet-wasm/nickminer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

build
secp256k1
47 changes: 47 additions & 0 deletions faucet-wasm/nickminer/build_wasm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

import { encode } from "base32768";
import fs from "fs";

const base32768Module = fs.readFileSync("node_modules/base32768/src/index.js", { encoding: "utf8" }).replace(/^export .*$/m, "");
const base32768WASM = encode(fs.readFileSync("build/nickminer.wasm"));

const wasmWrappperJS = fs.readFileSync("build/nickminer.js", { encoding: "utf8" });
let lines = wasmWrappperJS.replace(/import\.meta/g, "wasmMeta").split("\n");
// filter out the "export default Module" line
lines = lines.filter(line => !line.startsWith("export default Module"));
const customWASMWrappperJS = lines.join("\n");

// --------------------------------------------------------------------------
// Output the composited webworker JS

// first, include the warning about this file being automatically generated
console.log(`
// THIS FILE IS GENERATED AUTOMATICALLY
// Don't edit this file by hand.
// Edit the build located in the faucet-wasm folder.
var nickMinerPromise, nickMiner;
module.exports = {
getNickMiner: function() { return nickMiner; },
getNickMinerReadyPromise: function() { return nickMinerPromise; }
};
function getWasmBinary() {
${base32768Module}
const base32768WASM = "${base32768WASM}";
return decode(base32768WASM);
}
(function() {
var wasmMeta = {};
if(typeof self === "undefined") {
var self = {location:{href:""}};
}
${customWASMWrappperJS}
nickMinerPromise = Module();
})();
`);
Loading

0 comments on commit a0f2ef1

Please sign in to comment.