Completed
Pull Request — master (#411)
by thomas
142:05 queued 71:48
created

OutputScriptFactory::witnessCoinbaseCommitment()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 16
ccs 0
cts 0
cp 0
crap 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Factory;
4
5
use BitWasp\Bitcoin\Address\AddressInterface;
6
use BitWasp\Bitcoin\Address\ScriptHashAddress;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
8
use BitWasp\Bitcoin\Crypto\Hash;
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 AddressInterface $address
20 30
     * @return ScriptInterface
21
     */
22 15
    public function payToAddress(AddressInterface $address)
23 21
    {
24 30
        return $address instanceof ScriptHashAddress
25
            ? ScriptFactory::sequence([Opcodes::OP_HASH160, $address->getHash(), Opcodes::OP_EQUAL])
26
            : ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $address->getHash(), Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
27
    }
28
29
    /**
30
     * Create a Pay to pubkey output
31
     *
32
     * @param PublicKeyInterface  $publicKey
33 30
     * @return ScriptInterface
34
     */
35 30
    public function payToPubKey(PublicKeyInterface $publicKey)
36
    {
37
        return ScriptFactory::sequence([$publicKey->getBuffer(), Opcodes::OP_CHECKSIG]);
38
    }
39
40
    /**
41
     * Create a P2PKH output script
42
     *
43
     * @param BufferInterface $pubKeyHash
44 102
     * @return ScriptInterface
45
     */
46 102
    public function payToPubKeyHash(BufferInterface $pubKeyHash)
47
    {
48
        if ($pubKeyHash->getSize() !== 20) {
49
            throw new \RuntimeException('Public key hash must be exactly 20 bytes');
50 102
        }
51
52
        return ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
53
    }
54
55
    /**
56
    /**
57
     * Create a P2SH output script
58
     *
59
     * @param BufferInterface $scriptHash
60 108
     * @return ScriptInterface
61
     */
62 108
    public function payToScriptHash(BufferInterface $scriptHash)
63
    {
64
        if ($scriptHash->getSize() !== 20) {
65
            throw new \RuntimeException('P2SH scriptHash must be exactly 20 bytes');
66 108
        }
67
68
        return ScriptFactory::sequence([Opcodes::OP_HASH160, $scriptHash, Opcodes::OP_EQUAL]);
69
    }
70
71
    /**
72
     * @param int $m
73
     * @param PublicKeyInterface[] $keys
74
     * @param bool|true $sort
75 72
     * @return ScriptInterface
76
     */
77 72
    public function multisig($m, array $keys = [], $sort = true)
78 72
    {
79
        $n = count($keys);
80
        if ($m < 0) {
81
            throw new \LogicException('Number of signatures cannot be less than zero');
82 72
        }
83
84
        if ($m > $n) {
85
            throw new \LogicException('Required number of sigs exceeds number of public keys');
86 72
        }
87
88
        if ($n > 20) {
89
            throw new \LogicException('Number of public keys is greater than 16');
90 72
        }
91 36
92 18
        if ($sort) {
93
            $keys = Buffertools::sort($keys);
94 72
        }
95 72
96 72
        $new = ScriptFactory::create();
97 72
        $new->int($m);
98
        foreach ($keys as $key) {
99
            if (!$key instanceof PublicKeyInterface) {
100
                throw new \LogicException('Values in $keys[] must be a PublicKey');
101 72
            }
102 36
103
            $new->push($key->getBuffer());
104 72
        }
105
106
        return $new->int($n)->op('OP_CHECKMULTISIG')->getScript();
107
    }
108
109
    /**
110
     * @param BufferInterface $keyHash
111
     * @return ScriptInterface
112
     */
113
    public function witnessKeyHash(BufferInterface $keyHash)
114
    {
115
        if ($keyHash->getSize() !== 20) {
116
            throw new \RuntimeException('witness key-hash should be 20 bytes');
117
        }
118
119
        return ScriptFactory::sequence([Opcodes::OP_0, $keyHash]);
120
    }
121
122
    /**
123
     * @param BufferInterface $scriptHash
124
     * @return ScriptInterface
125
     */
126
    public function witnessScriptHash(BufferInterface $scriptHash)
127
    {
128
        if ($scriptHash->getSize() !== 32) {
129
            throw new \RuntimeException('witness script-hash should be 32 bytes');
130
        }
131
132
        return ScriptFactory::sequence([Opcodes::OP_0, $scriptHash]);
133
    }
134
135
    /**
136
     * @param BufferInterface $witnessMerkleRoot
137
     * @return ScriptInterface
138
     */
139
    public function witnessCoinbaseCommitment(BufferInterface $witnessMerkleRoot)
140
    {
141
        if ($witnessMerkleRoot->getSize() !== 32) {
142
            throw new \RuntimeException('Witness Merkle Root must be exactly 32-bytes');
143
        }
144
145
        static $reservedValue = null;
146
        if ($reservedValue === null) {
147
            $reservedValue = new Buffer('', 32);
148
        }
149
150
        return ScriptFactory::sequence([
151
            Opcodes::OP_RETURN,
152
            new Buffer("\xaa\x21\xa9\xed" . Hash::sha256d(new Buffer($witnessMerkleRoot->getBinary() . $reservedValue->getBinary()))->getBinary())
153
        ]);
154
    }
155
}
156