Completed
Push — master ( 319c7a...cdee94 )
by thomas
79:06 queued 75:43
created

InputClassifier::isMultisig()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 10.0863

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 34
ccs 19
cts 21
cp 0.9048
rs 4.8197
cc 10
eloc 20
nc 7
nop 0
crap 10.0863

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Classifier;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key\PublicKey;
6
use BitWasp\Bitcoin\Script\Opcodes;
7
use BitWasp\Bitcoin\Script\Parser\Operation;
8
use BitWasp\Bitcoin\Script\Script;
9
use BitWasp\Bitcoin\Script\ScriptInterface;
10
11
class InputClassifier implements ScriptClassifierInterface
12
{
13
14
    /**
15
     * @var Operation[]
16
     */
17
    private $decoded;
18
19
    const MAXSIGLEN = 0x48;
20
21
    /**
22
     * @param ScriptInterface $script
23
     */
24 48
    public function __construct(ScriptInterface $script)
25
    {
26 48
        $this->decoded = $script->getScriptParser()->decode();
27 48
    }
28
29
    /**
30
     * @return bool
31
     */
32 30
    public function isPayToPublicKey()
33
    {
34 30
        return count($this->decoded) === 1
35 30
        && $this->decoded[0]->isPush()
36 30
        && $this->decoded[0]->getDataSize() <= self::MAXSIGLEN;
37
    }
38
39
    /**
40
     * @return bool
41
     */
42 24
    public function isPayToPublicKeyHash()
43
    {
44 24
        if (count($this->decoded) !== 2) {
45 12
            return false;
46
        }
47
48 12
        $signature = $this->decoded[0];
49 12
        $publicKey = $this->decoded[1];
50
51 12
        return $signature->isPush() && $signature->getDataSize() <= self::MAXSIGLEN
52 12
            && $publicKey->isPush() && PublicKey::isCompressedOrUncompressed($publicKey->getData());
53
    }
54
55
    /**
56
     * @return bool
57
     */
58 18
    public function isPayToScriptHash()
59
    {
60 18
        if (count($this->decoded) < 1) {
61 6
            return false;
62
        }
63
64 12
        $final = end($this->decoded);
65 12
        if (!$final || !$final->isPush()) {
66 6
            return false;
67
        }
68
69 6
        $type = new OutputClassifier(new Script($final->getData()));
70 6
        return false === in_array($type->classify(), [
71 6
            self::UNKNOWN,
72
            self::PAYTOSCRIPTHASH
73 6
        ], true);
74
    }
75
76
    /**
77
     * @return bool
78
     */
79 24
    public function isMultisig()
80
    {
81 24
        if (count($this->decoded) < 3) {
82 12
            return false;
83
        }
84
85 12
        $final = end($this->decoded);
86 12
        if (!$final || !$final->isPush()) {
87 6
            return false;
88
        }
89
90 6
        $script = new Script($final->getData());
91 6
        $decoded = $script->getScriptParser()->decode();
92 6
        $count = count($decoded);
93
94 6
        $mOp = $decoded[0];
95 6
        $nOp = $decoded[$count - 2];
96 6
        if ($mOp->isPush() || $nOp->isPush()) {
97
            return false;
98
        }
99
100 6
        if ($mOp->getOp() < Opcodes::OP_0 || $nOp->getOp() > Opcodes::OP_16) {
101
            return false;
102
        }
103
104
        /** @var Operation[] $keys */
105 6
        $keys = array_slice($decoded, 1, -2);
106 6
        $keysValid = true;
107 6
        foreach ($keys as $key) {
108 6
            $keysValid &= $key->isPush() && PublicKey::isCompressedOrUncompressed($key->getData());
109 6
        }
110
111 6
        return $keysValid;
112
    }
113
114
    /**
115
     * @return string
116
     */
117 30
    public function classify()
118
    {
119 30
        if ($this->isPayToPublicKey()) {
120 6
            return self::PAYTOPUBKEY;
121 24
        } elseif ($this->isPayToPublicKeyHash()) {
122 6
            return self::PAYTOPUBKEYHASH;
123 18
        } elseif ($this->isMultisig()) {
124 6
            return self::MULTISIG;
125 12
        } elseif ($this->isPayToScriptHash()) {
126 6
            return self::PAYTOSCRIPTHASH;
127
        }
128
129 6
        return self::UNKNOWN;
130
    }
131
}
132