-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathminer.ts
74 lines (67 loc) · 2.42 KB
/
miner.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* @license
* SKALE Metaport
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* @file miner.ts
* @copyright SKALE Labs 2023-Present
*/
import { isHexString, getNumber, randomBytes, keccak256, toBeHex, toBigInt } from 'ethers'
import { MAX_NUMBER } from './constants'
interface Params {
difficulty?: bigint
}
export default class SkalePowMiner {
public difficulty: bigint = 1n
constructor(params?: Params) {
if (params && params.difficulty) this.difficulty = params.difficulty
}
public async mineGasForTransaction(
nonce: string | number,
gas: string | number,
from: string
): Promise<any> {
let address = from
nonce = isHexString(nonce) ? getNumber(nonce) : (nonce as number)
gas = isHexString(gas) ? getNumber(gas) : (gas as number)
return await this.mineFreeGas(gas as number, address, nonce as number)
}
public async mineFreeGas(gasAmount: number, address: string, nonce: number): Promise<BigInt> {
let nonceHash = toBigInt(keccak256(toBeHex(nonce, 32)))
let addressHash = toBigInt(keccak256(address))
let nonceAddressXOR = nonceHash ^ addressHash
let divConstant = MAX_NUMBER / this.difficulty
let candidate: Uint8Array
let iterations = 0
const start = performance.now()
while (true) {
candidate = randomBytes(32)
let candidateHash = toBigInt(keccak256(candidate))
let resultHash = nonceAddressXOR ^ candidateHash
let externalGas = divConstant / resultHash
if (externalGas >= gasAmount) {
break
}
// every 2k iterations, yield to the event loop
if (iterations++ % 2_000 === 0) {
await new Promise<void>((resolve) => setTimeout(resolve, 0))
}
}
const end = performance.now()
console.log(`PoW execution time: ${end - start} ms`)
return toBigInt(candidate)
}
}