Completed
Pull Request — master (#759)
by thomas
39:27 queued 37:07
created

ScriptFactory::sequence()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Script;
6
7
use BitWasp\Bitcoin\Bitcoin;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
9
use BitWasp\Bitcoin\Math\Math;
10
use BitWasp\Bitcoin\Script\Consensus\BitcoinConsensus;
11
use BitWasp\Bitcoin\Script\Consensus\ConsensusInterface;
12
use BitWasp\Bitcoin\Script\Consensus\NativeConsensus;
13
use BitWasp\Bitcoin\Script\Factory\OutputScriptFactory;
14
use BitWasp\Bitcoin\Script\Factory\ScriptCreator;
15
use BitWasp\Bitcoin\Script\Parser\Operation;
16
use BitWasp\Buffertools\Buffer;
17
use BitWasp\Buffertools\BufferInterface;
18
19
class ScriptFactory
20
{
21
    /**
22
     * @var OutputScriptFactory
23
     */
24
    private static $outputScriptFactory = null;
25
    private static $opcodes = null;
26
27 5396
    private static function getOpCodes(): Opcodes
28
    {
29 5396
        if (null === static::$opcodes) {
0 ignored issues
show
Bug introduced by
Since $opcodes is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $opcodes to at least protected.
Loading history...
30
            static::$opcodes = new Opcodes();
31
        }
32 5396
        return static::$opcodes;
33
    }
34
35
    /**
36
     * @param string $string
37
     * @return ScriptInterface
38
     * @throws \Exception
39
     */
40 17
    public static function fromHex(string $string): ScriptInterface
41
    {
42 17
        return self::fromBuffer(Buffer::hex($string));
43
    }
44
45
    /**
46
     * @param BufferInterface $buffer
47
     * @param Opcodes|null $opcodes
48
     * @param Math|null $math
49
     * @return ScriptInterface
50
     */
51 25
    public static function fromBuffer(BufferInterface $buffer, Opcodes $opcodes = null, Math $math = null): ScriptInterface
52
    {
53 25
        return self::create($buffer, $opcodes, $math)->getScript();
54
    }
55
56
    /**
57
     * @param BufferInterface|null $buffer
58
     * @param Opcodes|null $opcodes
59
     * @param Math|null $math
60
     * @return ScriptCreator
61
     */
62 5396
    public static function create(BufferInterface $buffer = null, Opcodes $opcodes = null, Math $math = null): ScriptCreator
63
    {
64 5396
        $opcodes = $opcodes ?: self::getOpCodes();
65 5396
        return new ScriptCreator($math ?: Bitcoin::getMath(), $opcodes, $buffer);
66
    }
67
68
    /**
69
     * Create a script consisting only of push-data operations.
70
     * Suitable for a scriptSig.
71
     *
72
     * @param BufferInterface[] $buffers
73
     * @return ScriptInterface
74
     */
75
    public static function pushAll(array $buffers): ScriptInterface
76
    {
77 93
        return self::sequence(array_map(function ($buffer) {
78 76
            if (!($buffer instanceof BufferInterface)) {
79
                throw new \RuntimeException('Script contained a non-push opcode');
80
            }
81
82 76
            $size = $buffer->getSize();
83 76
            if ($size === 0) {
84 24
                return Opcodes::OP_0;
85
            }
86
87 76
            $first = ord($buffer->getBinary()[0]);
88 76
            if ($size === 1 && $first >= 1 && $first <= 16) {
89 4
                return \BitWasp\Bitcoin\Script\encodeOpN($first);
90
            } else {
91 76
                return $buffer;
92
            }
93 93
        }, $buffers));
94
    }
95
96
    /**
97
     * @param int[]|\BitWasp\Bitcoin\Script\Interpreter\Number[]|BufferInterface[] $sequence
98
     * @return ScriptInterface
99
     */
100 5361
    public static function sequence(array $sequence): ScriptInterface
101
    {
102 5361
        return self::create()->sequence($sequence)->getScript();
103
    }
104
105
    /**
106
     * @param Operation[] $operations
107
     * @return ScriptInterface
108
     */
109 20
    public static function fromOperations(array $operations): ScriptInterface
110
    {
111 20
        $sequence = [];
112 20
        foreach ($operations as $operation) {
113 19
            if (!($operation instanceof Operation)) {
114
                throw new \RuntimeException("Invalid input to fromOperations");
115
            }
116
117 19
            $sequence[] = $operation->encode();
118
        }
119
120 20
        return self::sequence($sequence);
121
    }
122
123
    /**
124
     * @return OutputScriptFactory
125
     */
126 226
    public static function scriptPubKey(): OutputScriptFactory
127
    {
128 226
        if (self::$outputScriptFactory === null) {
129
            self::$outputScriptFactory = new OutputScriptFactory();
130
        }
131
132 226
        return self::$outputScriptFactory;
133
    }
134
135
    /**
136
     * @param EcAdapterInterface|null $ecAdapter
137
     * @return NativeConsensus
138
     */
139 1
    public static function getNativeConsensus(EcAdapterInterface $ecAdapter = null): NativeConsensus
140
    {
141 1
        return new NativeConsensus($ecAdapter ?: Bitcoin::getEcAdapter());
142
    }
143
144
    /**
145
     * @return BitcoinConsensus
146
     */
147 81
    public static function getBitcoinConsensus(): BitcoinConsensus
148
    {
149 81
        return new BitcoinConsensus();
150
    }
151
152
    /**
153
     * @param EcAdapterInterface|null $ecAdapter
154
     * @return ConsensusInterface
155
     */
156 80
    public static function consensus(EcAdapterInterface $ecAdapter = null): ConsensusInterface
157
    {
158 80
        if (extension_loaded('bitcoinconsensus')) {
159 80
            return self::getBitcoinConsensus();
160
        } else {
161
            return self::getNativeConsensus($ecAdapter);
162
        }
163
    }
164
}
165