Completed
Pull Request — 0.0.35 (#657)
by thomas
33:13
created

OutputScriptFactory   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Test Coverage

Coverage 85.19%

Importance

Changes 0
Metric Value
wmc 25
lcom 0
cbo 6
dl 0
loc 181
ccs 46
cts 54
cp 0.8519
rs 10
c 0
b 0
f 0

13 Methods

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