1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace BitWasp\Bitcoin\Chain; |
||||
6 | |||||
7 | use BitWasp\Bitcoin\Block\BlockHeaderInterface; |
||||
8 | use BitWasp\Bitcoin\Math\Math; |
||||
9 | use BitWasp\Buffertools\Buffer; |
||||
10 | use BitWasp\Buffertools\BufferInterface; |
||||
11 | |||||
12 | class ProofOfWork |
||||
13 | { |
||||
14 | const DIFF_PRECISION = 12; |
||||
15 | const POW_2_256 = '115792089237316195423570985008687907853269984665640564039457584007913129639936'; |
||||
16 | |||||
17 | /** |
||||
18 | * @var Math |
||||
19 | */ |
||||
20 | private $math; |
||||
21 | |||||
22 | /** |
||||
23 | * @var ParamsInterface |
||||
24 | */ |
||||
25 | private $params; |
||||
26 | |||||
27 | /** |
||||
28 | * @param Math $math |
||||
29 | * @param ParamsInterface $params |
||||
30 | */ |
||||
31 | 4 | public function __construct(Math $math, ParamsInterface $params) |
|||
32 | { |
||||
33 | 4 | $this->math = $math; |
|||
34 | 4 | $this->params = $params; |
|||
35 | 4 | } |
|||
36 | |||||
37 | /** |
||||
38 | * @param int $bits |
||||
39 | * @return \GMP |
||||
40 | */ |
||||
41 | 190 | public function getTarget(int $bits): \GMP |
|||
42 | { |
||||
43 | 190 | $negative = false; |
|||
44 | 190 | $overflow = false; |
|||
45 | 190 | return $this->math->decodeCompact($bits, $negative, $overflow); |
|||
46 | } |
||||
47 | |||||
48 | /** |
||||
49 | * @return \GMP |
||||
50 | */ |
||||
51 | 189 | public function getMaxTarget(): \GMP |
|||
52 | { |
||||
53 | 189 | return $this->getTarget($this->params->powBitsLimit()); |
|||
54 | } |
||||
55 | |||||
56 | /** |
||||
57 | * @param int $bits |
||||
58 | * @return BufferInterface |
||||
59 | */ |
||||
60 | 1 | public function getTargetHash(int $bits): BufferInterface |
|||
61 | { |
||||
62 | 1 | return Buffer::int(gmp_strval($this->getTarget($bits), 10), 32); |
|||
63 | } |
||||
64 | |||||
65 | /** |
||||
66 | * @param int $bits |
||||
67 | * @return string |
||||
68 | */ |
||||
69 | 1 | public function getDifficulty(int $bits): string |
|||
70 | { |
||||
71 | 1 | $target = $this->getTarget($bits); |
|||
72 | 1 | $lowest = $this->getMaxTarget(); |
|||
73 | 1 | $lowest = $this->math->mul($lowest, $this->math->pow(gmp_init(10, 10), self::DIFF_PRECISION)); |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
74 | |||||
75 | 1 | $difficulty = str_pad($this->math->toString($this->math->div($lowest, $target)), self::DIFF_PRECISION + 1, '0', STR_PAD_LEFT); |
|||
76 | |||||
77 | 1 | $intPart = substr($difficulty, 0, 0 - self::DIFF_PRECISION); |
|||
78 | 1 | $decPart = substr($difficulty, 0 - self::DIFF_PRECISION, self::DIFF_PRECISION); |
|||
79 | |||||
80 | 1 | return $intPart . '.' . $decPart; |
|||
81 | } |
||||
82 | |||||
83 | /** |
||||
84 | * @param BufferInterface $hash |
||||
85 | * @param int $nBits |
||||
86 | * @return bool |
||||
87 | */ |
||||
88 | 189 | public function checkPow(BufferInterface $hash, int $nBits): bool |
|||
89 | { |
||||
90 | 189 | $negative = false; |
|||
91 | 189 | $overflow = false; |
|||
92 | |||||
93 | 189 | $target = $this->math->decodeCompact($nBits, $negative, $overflow); |
|||
94 | 189 | if ($negative || $overflow || $this->math->cmp($target, gmp_init(0)) === 0 || $this->math->cmp($target, $this->getMaxTarget()) > 0) { |
|||
0 ignored issues
–
show
It seems like
gmp_init(0) can also be of type resource ; however, parameter $other of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
95 | 1 | throw new \RuntimeException('nBits below minimum work'); |
|||
96 | } |
||||
97 | |||||
98 | 188 | if ($this->math->cmp($hash->getGmp(), $target) > 0) { |
|||
99 | 1 | return false; |
|||
100 | } |
||||
101 | |||||
102 | 187 | return true; |
|||
103 | } |
||||
104 | |||||
105 | /** |
||||
106 | * @param BlockHeaderInterface $header |
||||
107 | * @return bool |
||||
108 | * @throws \Exception |
||||
109 | */ |
||||
110 | 187 | public function checkHeader(BlockHeaderInterface $header): bool |
|||
111 | { |
||||
112 | 187 | return $this->checkPow($header->getHash(), $header->getBits()); |
|||
113 | } |
||||
114 | |||||
115 | /** |
||||
116 | * @param int $bits |
||||
117 | * @return \GMP |
||||
118 | */ |
||||
119 | 1 | public function getWork(int $bits): \GMP |
|||
120 | { |
||||
121 | 1 | $target = gmp_strval($this->getTarget($bits), 10); |
|||
122 | 1 | return gmp_init(bcdiv(self::POW_2_256, $target), 10); |
|||
0 ignored issues
–
show
|
|||||
123 | } |
||||
124 | } |
||||
125 |