Completed
Branch master (b7c8d8)
by
unknown
28:56 queued 12:06
created

WalletScript::getScriptPubKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Blocktrail\SDK;
4
5
use BitWasp\Bitcoin\Address\AddressInterface;
6
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
7
use BitWasp\Bitcoin\Script\P2shScript;
8
use BitWasp\Bitcoin\Script\ScriptInterface;
9
use BitWasp\Bitcoin\Script\ScriptType;
10
use BitWasp\Bitcoin\Script\WitnessProgram;
11
use BitWasp\Bitcoin\Script\WitnessScript;
12
use BitWasp\Buffertools\BufferInterface;
13
use Blocktrail\SDK\Bitcoin\BIP32Path;
14
use Blocktrail\SDK\Exceptions\BlocktrailSDKException;
15
16
class WalletScript
17
{
18
    const DEFAULT_SHOULD_CHECK = true;
19
20
    /**
21
     * @var null|bool
22
     */
23
    protected static $checkScripts;
24
25
    /**
26
     * @var \BitWasp\Bitcoin\Address\AddressInterface|null
27
     */
28
    private $address;
29
30
    /**
31
     * @var ScriptInterface
32
     */
33
    private $spk;
34
35
    /**
36
     * @var P2shScript|null
37
     */
38
    private $redeemScript;
39
40
    /**
41
     * @var WitnessScript|null
42
     */
43
    private $witnessScript;
44
45
    /**
46
     * @var BIP32Path
47
     */
48
    private $path;
49
50
    /**
51
     * Disables script checking (procedure includes some hashing)
52
     * @param bool $setting
53
     */
54
    public static function enforceScriptChecks($setting) {
55
        static::$checkScripts = (bool) $setting;
56
    }
57
58
    /**
59
     * WalletScript constructor.
60
     * @param BIP32Path $path
61
     * @param ScriptInterface $spk
62
     * @param P2shScript|null $redeemScript
63
     * @param WitnessScript|null $witnessScript
64
     */
65 41
    public function __construct(
66
        BIP32Path $path,
67
        ScriptInterface $spk,
68
        P2shScript $redeemScript = null,
69
        WitnessScript $witnessScript = null,
70
        AddressInterface $address = null
71
    ) {
72 41
        if (static::$checkScripts || null === static::$checkScripts && self::DEFAULT_SHOULD_CHECK) {
73 41
            $this->checkScript($path[2], $spk, $redeemScript, $witnessScript);
74
        }
75
76 32
        $this->path = $path;
77 32
        $this->spk = $spk;
78 32
        $this->redeemScript = $redeemScript;
79 32
        $this->witnessScript = $witnessScript;
80
81 32
        if ($address) {
82 30
            if (!$address->getScriptPubKey()->equals($this->getScriptPubKey())) {
83 1
                throw new BlocktrailSDKException("Mismatch between scriptPubKey and address");
84
            }
85 29
            $this->address = $address;
86
        }
87 31
    }
88
89
    /**
90
     * @param OutputClassifier $classifier
91
     * @param ScriptInterface $script
92
     * @param P2shScript|null $redeemScript
93
     */
94 41
    protected function checkP2shScript(OutputClassifier $classifier, ScriptInterface $script, P2shScript $redeemScript = null) {
95 41
        $scriptHash = null;
96 41
        if (!($classifier->classify($script, $scriptHash) === ScriptType::P2SH)) {
97 1
            throw new \RuntimeException("scriptPubKey should be script-hash");
98
        }
99
        /** @var BufferInterface $scriptHash */
100 40
        if (null === $redeemScript) {
101 1
            throw new \RuntimeException("Missing redeemScript");
102
        }
103
104 39
        if (!$redeemScript->getScriptHash()->equals($scriptHash)) {
105 1
            throw new \RuntimeException("Invalid redeemScript for scriptPubKey");
106
        }
107 38
    }
108
109
    /**
110
     * @param ScriptInterface $script
111
     * @param WitnessScript|null $witnessScript
112
     */
113 7
    protected function checkWitnessScript(ScriptInterface $script, WitnessScript $witnessScript = null) {
114 7
        if (!$script->isWitness($wp)) {
115 1
            $errSuffix = $script instanceof P2shScript ? "P2SH script" : "Script";
116 1
            throw new \RuntimeException("$errSuffix should be v0_scripthash");
117
        }
118
119
        /** @var WitnessProgram $wp */
120 6
        if ($wp->getProgram()->getSize() !== 32) {
121 1
            $errSuffix = $script instanceof P2shScript ? "P2SH script" : "Script";
122 1
            throw new \RuntimeException("$errSuffix should be v0_scripthash");
123
        }
124
125 5
        if (null === $witnessScript) {
126 1
            $errSuffix = $script instanceof P2shScript ? "P2SH script" : "script";
127 1
            throw new \RuntimeException("Missing witnessScript for $errSuffix");
128
        }
129
130 4
        if (!$wp->getProgram()->equals($witnessScript->getWitnessScriptHash())) {
131 1
            throw new \RuntimeException("Invalid witnessScript for p2sh v0_scripthash");
132
        }
133 3
    }
134
135
    /**
136
     * @param int $scriptId
137
     * @param ScriptInterface $script
138
     * @param P2shScript|null $redeemScript
139
     * @param WitnessScript|null $witnessScript
140
     */
141 41
    protected function checkScript($scriptId, ScriptInterface $script, P2shScript $redeemScript = null, WitnessScript $witnessScript = null) {
142 41
        $classifier = new OutputClassifier();
143
        switch ($scriptId) {
144 41
            case 2:
145 7
                $this->checkP2shScript($classifier, $script, $redeemScript);
146 7
                $this->checkWitnessScript($redeemScript, $witnessScript);
0 ignored issues
show
Bug introduced by
It seems like $redeemScript defined by parameter $redeemScript on line 141 can be null; however, Blocktrail\SDK\WalletScript::checkWitnessScript() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
147 3
                if (!$classifier->isMultisig($witnessScript)) {
0 ignored issues
show
Bug introduced by
It seems like $witnessScript defined by parameter $witnessScript on line 141 can be null; however, BitWasp\Bitcoin\Script\C...lassifier::isMultisig() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
148 1
                    throw new \RuntimeException("Expected multisig as witnessScript");
149
                }
150 2
                break;
151
            default:
152 35
                $this->checkP2shScript($classifier, $script, $redeemScript);
153 32
                if (!$classifier->isMultisig($redeemScript)) {
0 ignored issues
show
Bug introduced by
It seems like $redeemScript defined by parameter $redeemScript on line 141 can be null; however, BitWasp\Bitcoin\Script\C...lassifier::isMultisig() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
154 1
                    throw new \RuntimeException("Expected multisig as redeemScript");
155
                }
156 31
                break;
157
        }
158 32
    }
159
160
    /**
161
     * @return ScriptInterface
162
     */
163 30
    public function getScriptPubKey() {
164 30
        return $this->spk;
165
    }
166
167
    /**
168
     * @return bool
169
     */
170 28
    public function isP2SH() {
171 28
        return $this->redeemScript instanceof P2shScript;
172
    }
173
174
    /**
175
     * @return bool
176
     */
177 28
    public function isP2WSH() {
178 28
        return $this->witnessScript instanceof WitnessScript;
179
    }
180
181
    /**
182
     * @param bool $allowNull
183
     * @return WitnessScript|null
184
     */
185 5
    public function getWitnessScript($allowNull = false) {
186 5
        if (!$allowNull && null === $this->witnessScript) {
187 1
            throw new \RuntimeException("WitnessScript not set");
188
        }
189 4
        return $this->witnessScript;
190
    }
191
192
    /**
193
     * @return P2shScript|null
194
     */
195 28
    public function getRedeemScript() {
196 28
        return $this->redeemScript;
197
    }
198
199
    /**
200
     * @return AddressInterface|null
201
     */
202 30
    public function getAddress() {
203 30
        if (null === $this->address) {
204 1
            throw new \RuntimeException("This script has no address");
205
        }
206 29
        return $this->address;
207
    }
208
}
209