Completed
Push — master ( afec6b...f0c306 )
by thomas
43:51 queued 04:35
created

OutputScriptFactory::p2wkh()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Script\Factory;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key\PublicKey;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
9
use BitWasp\Bitcoin\Script\Opcodes;
10
use BitWasp\Bitcoin\Script\ScriptFactory;
11
use BitWasp\Bitcoin\Script\ScriptInterface;
12
use BitWasp\Buffertools\Buffer;
13
use BitWasp\Buffertools\BufferInterface;
14
use BitWasp\Buffertools\Buffertools;
15
16
class OutputScriptFactory
17
{
18
    /**
19
     * @param PublicKeyInterface $publicKey
20
     * @return ScriptInterface
21
     */
22
    public function p2pk(PublicKeyInterface $publicKey): ScriptInterface
23
    {
24 10
        return $this->payToPubKey($publicKey);
25
    }
26 10
27 4
    /**
28 10
     * @param BufferInterface $pubKeyHash
29
     * @return ScriptInterface
30
     */
31
    public function p2pkh(BufferInterface $pubKeyHash): ScriptInterface
32
    {
33
        return $this->payToPubKeyHash($pubKeyHash);
34
    }
35 1
36
    /**
37 1
     * @param BufferInterface $scriptHash
38
     * @return ScriptInterface
39
     */
40
    public function p2sh(BufferInterface $scriptHash): ScriptInterface
41
    {
42
        return $this->payToScriptHash($scriptHash);
43
    }
44 10
45
    /**
46 10
     * @param BufferInterface $witnessScriptHash
47
     * @return ScriptInterface
48
     */
49
    public function p2wsh(BufferInterface $witnessScriptHash): ScriptInterface
50
    {
51
        return $this->witnessScriptHash($witnessScriptHash);
52
    }
53 59
54
    /**
55 59
     * @param BufferInterface $witnessKeyHash
56
     * @return ScriptInterface
57
     */
58
    public function p2wkh(BufferInterface $witnessKeyHash): ScriptInterface
59
    {
60
        return $this->witnessKeyHash($witnessKeyHash);
61
    }
62 41
    /**
63
     * Create a Pay to pubkey output
64 41
     *
65
     * @param PublicKeyInterface  $publicKey
66
     * @return ScriptInterface
67
     */
68
    public function payToPubKey(PublicKeyInterface $publicKey): ScriptInterface
69
    {
70
        return ScriptFactory::sequence([$publicKey->getBuffer(), Opcodes::OP_CHECKSIG]);
71 1
    }
72
73 1
    /**
74
     * Create a P2PKH output script
75
     *
76
     * @param BufferInterface $pubKeyHash
77
     * @return ScriptInterface
78
     */
79
    public function payToPubKeyHash(BufferInterface $pubKeyHash): ScriptInterface
80
    {
81 6
        if ($pubKeyHash->getSize() !== 20) {
82
            throw new \RuntimeException('Public key hash must be exactly 20 bytes');
83 6
        }
84
85
        return ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
86
    }
87
88
    /**
89
    /**
90
     * Create a P2SH output script
91
     *
92 47
     * @param BufferInterface $scriptHash
93
     * @return ScriptInterface
94 47
     */
95
    public function payToScriptHash(BufferInterface $scriptHash): ScriptInterface
96
    {
97
        if ($scriptHash->getSize() !== 20) {
98 47
            throw new \RuntimeException('P2SH scriptHash must be exactly 20 bytes');
99
        }
100
101
        return ScriptFactory::sequence([Opcodes::OP_HASH160, $scriptHash, Opcodes::OP_EQUAL]);
102
    }
103
104
    /**
105
     * @param int $m
106
     * @param PublicKeyInterface[] $keys
107
     * @param bool|true $sort
108 76
     * @return ScriptInterface
109
     */
110 76
    public function multisig(int $m, array $keys = [], bool $sort = true): ScriptInterface
111
    {
112
        return self::multisigKeyBuffers($m, array_map(function (PublicKeyInterface $key): BufferInterface {
113
            return $key->getBuffer();
114 76
        }, $keys), $sort);
115
    }
116
117
    /**
118
     * @param int $m
119
     * @param BufferInterface[] $keys
120
     * @param bool $sort
121
     * @return ScriptInterface
122
     */
123
    public function multisigKeyBuffers(int $m, array $keys = [], bool $sort = true): ScriptInterface
124
    {
125 18
        $n = count($keys);
126 18
        if ($m < 0) {
127 18
            throw new \LogicException('Number of signatures cannot be less than zero');
128
        }
129
130
        if ($m > $n) {
131
            throw new \LogicException('Required number of sigs exceeds number of public keys');
132
        }
133
134
        if ($n > 20) {
135
            throw new \LogicException('Number of public keys is greater than 16');
136 21
        }
137
138 21
        if ($sort) {
139 21
            $keys = Buffertools::sort($keys);
140
        }
141
142
        $new = ScriptFactory::create();
143 21
        $new->int($m);
144
        foreach ($keys as $key) {
145
            if ($key->getSize() !== PublicKey::LENGTH_COMPRESSED && $key->getSize() !== PublicKey::LENGTH_UNCOMPRESSED) {
146
                throw new \RuntimeException("Invalid length for public key buffer");
147 21
            }
148
149
            $new->push($key);
150
        }
151 21
152 5
        return $new->int($n)->op('OP_CHECKMULTISIG')->getScript();
153
    }
154
155 21
    /**
156 21
     * @param BufferInterface $keyHash
157 21
     * @return ScriptInterface
158 21
     */
159
    public function witnessKeyHash(BufferInterface $keyHash): ScriptInterface
160
    {
161
        if ($keyHash->getSize() !== 20) {
162 21
            throw new \RuntimeException('witness key-hash should be 20 bytes');
163
        }
164
165 21
        return ScriptFactory::sequence([Opcodes::OP_0, $keyHash]);
166
    }
167
168
    /**
169
     * @param BufferInterface $scriptHash
170
     * @return ScriptInterface
171
     */
172 1
    public function witnessScriptHash(BufferInterface $scriptHash): ScriptInterface
173
    {
174 1
        if ($scriptHash->getSize() !== 32) {
175
            throw new \RuntimeException('witness script-hash should be 32 bytes');
176
        }
177
178 1
        return ScriptFactory::sequence([Opcodes::OP_0, $scriptHash]);
179
    }
180
181
    /**
182
     * @param BufferInterface $commitment
183
     * @return ScriptInterface
184
     */
185 42
    public function witnessCoinbaseCommitment(BufferInterface $commitment): ScriptInterface
186
    {
187 42
        if ($commitment->getSize() !== 32) {
188
            throw new \RuntimeException('Witness commitment hash must be exactly 32-bytes');
189
        }
190
191 42
        return ScriptFactory::sequence([
192
            Opcodes::OP_RETURN,
193
            new Buffer("\xaa\x21\xa9\xed" . $commitment->getBinary())
194
        ]);
195
    }
196
}
197