Completed
Push — master ( b34b72...6ee2b1 )
by thomas
25:53
created

ProofOfWork::checkPow()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 3
nop 2
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
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));
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
introduced by
The condition $overflow is always false.
Loading history...
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);
123
    }
124
}
125