Completed
Pull Request — master (#287)
by thomas
22:09
created

ScriptCreator   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 80.88%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 23
c 3
b 0
f 1
lcom 1
cbo 9
dl 0
loc 168
ccs 55
cts 68
cp 0.8088
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
B sequence() 0 22 6
A op() 0 6 1
B push() 0 30 4
A pushSerializable() 0 5 1
A pushSerializableArray() 0 8 2
A concat() 0 5 1
A getScript() 0 4 1
B int() 0 12 5
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Factory;
4
5
use BitWasp\Bitcoin\Math\Math;
6
use BitWasp\Bitcoin\Script\Interpreter\Number;
7
use BitWasp\Bitcoin\Script\Opcodes;
8
use BitWasp\Bitcoin\Script\Script;
9
use BitWasp\Bitcoin\Script\ScriptInterface;
10
use BitWasp\Bitcoin\Serializable;
11
use BitWasp\Buffertools\Buffer;
12
use BitWasp\Buffertools\BufferInterface;
13
use BitWasp\Buffertools\Buffertools;
14
use BitWasp\Buffertools\Parser;
15
16
class ScriptCreator
17
{
18
    /**
19
     * @var string
20
     */
21
    private $script = '';
22
23
    /**
24
     * @var Opcodes
25
     */
26
    private $opcodes;
27
28
    /**
29
     * @var Math
30
     */
31
    private $math;
32
33
    /**
34
     * @param Math $math
35
     * @param Opcodes $opcodes
36
     * @param BufferInterface|null $buffer
37
     */
38 1170
    public function __construct(Math $math, Opcodes $opcodes, BufferInterface $buffer = null)
39
    {
40 1170
        if ($buffer !== null) {
41 774
            $this->script = $buffer->getBinary();
42 774
        }
43
44 1170
        $this->math = $math;
45 1170
        $this->opcodes = $opcodes;
46 1170
    }
47
48
    /**
49
     * @param int[]|\BitWasp\Bitcoin\Script\Interpreter\Number[]|BufferInterface[] $sequence
50
     * @return $this
51
     */
52 300
    public function sequence(array $sequence)
53
    {
54 300
        $new = new self($this->math, $this->opcodes, null);
55 300
        foreach ($sequence as $operation) {
56 300
            if (is_int($operation)) {
57 288
                if (!$this->opcodes->offsetExists($operation)) {
58
                    throw new \RuntimeException('Unknown opcode');
59
                }
60
61 288
                $new->script .= chr($operation);
62 300
            } elseif ($operation instanceof Number) {
63
                $new->push($operation->getBuffer());
64 300
            } elseif ($operation instanceof BufferInterface) {
65 300
                $new->push($operation);
66 300
            } else {
67
                throw new \RuntimeException('Input was neither an opcode or BufferInterfacecc');
68
            }
69 300
        }
70
71 300
        $this->concat($new->getScript());
72 300
        return $this;
73
    }
74
75
    /**
76
     * Add an opcode to the script
77
     *
78
     * @param string $name
79
     * @return $this
80
     */
81 174
    public function op($name)
82
    {
83 174
        $code = $this->opcodes->getOpByName($name);
84 168
        $this->script .= chr($code);
85 168
        return $this;
86
    }
87
88
    /**
89
     * Push data into the stack.
90
     *
91
     * @param $data
92
     * @return $this
93
     * @throws \Exception
94
     */
95 390
    public function push(BufferInterface $data)
96
    {
97 390
        $length = $data->getSize();
98 390
        $parsed = new Parser('', $this->math);
99
100
        /** Note that larger integers are serialized without flipping bits - Big endian */
101
102 390
        if ($length < $this->opcodes->getOpByName('OP_PUSHDATA1')) {
103 372
            $varInt = Buffertools::numToVarInt($length);
104 372
            $data = new Buffer($varInt->getBinary() . $data->getBinary(), null, $this->math);
105 372
            $parsed->writeBytes($data->getSize(), $data);
106 372
        } else {
107 24
            if ($length <= 0xff) {
108 12
                $lengthSize = 1;
109 24
            } elseif ($length <= 0xffff) {
110 6
                $lengthSize = 2;
111 6
            } else {
112 6
                $lengthSize = 4;
113
            }
114
115 24
            $op = $this->opcodes->getOpByName('OP_PUSHDATA' . $lengthSize);
116
            $parsed
117 24
                ->writeBytes(1, Buffer::int($op))
118 24
                ->writeBytes($lengthSize, Buffer::int($length), true)
119 24
                ->writeBytes($length, $data);
120
        }
121
122 390
        $this->script .= $parsed->getBuffer()->getBinary();
123 390
        return $this;
124
    }
125
126
    /**
127
     * @param int $n
128
     * @return $this
129
     */
130 78
    public function int($n)
131
    {
132 78
        if ($n === 0) {
133
            $this->script .= chr(Opcodes::OP_0);
134 78
        } else if ($n === -1 || ($n >= 1 && $n <= 16)) {
135 78
            $this->script .= chr(\BitWasp\Bitcoin\Script\encodeOpN($n));
136 78
        } else {
137
            $this->script .= Number::int($n)->getBinary();
138
        }
139
140 78
        return $this;
141
    }
142
143
    /**
144
     * @param Serializable $object
145
     * @return $this
146
     */
147
    public function pushSerializable(Serializable $object)
148
    {
149
        $this->push($object->getBuffer());
150
        return $this;
151
    }
152
153
    /**
154
     * @param Serializable[] $serializable
155
     * @return $this
156
     */
157
    public function pushSerializableArray(array $serializable)
158
    {
159
        foreach ($serializable as $object) {
160
            $this->pushSerializable($object);
161
        }
162
163
        return $this;
164
    }
165
166
    /**
167
     * @param ScriptInterface $script
168
     * @return $this
169
     */
170 300
    public function concat(ScriptInterface $script)
171
    {
172 300
        $this->script .= $script->getBinary();
173 300
        return $this;
174
    }
175
176
    /**
177
     * @return ScriptInterface
178
     */
179 1164
    public function getScript()
180
    {
181 1164
        return new Script(new Buffer($this->script, null, $this->math), $this->opcodes);
182
    }
183
}
184