Completed
Push — 0.0.34 ( 61212b...2e9020 )
by thomas
20:55
created

ScriptCreator   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 83.93%

Importance

Changes 0
Metric Value
dl 0
loc 151
ccs 47
cts 56
cp 0.8393
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 7

8 Methods

Rating   Name   Duplication   Size   Complexity  
A op() 0 6 1
B int() 0 12 5
A __construct() 0 9 2
B push() 0 24 4
A pushSerializable() 0 5 1
A concat() 0 5 1
A getScript() 0 4 1
C sequence() 0 24 7
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
14
class ScriptCreator
15
{
16
    /**
17
     * @var string
18
     */
19
    private $script = '';
20
21
    /**
22
     * @var Opcodes
23
     */
24
    private $opcodes;
25
26
    /**
27
     * @var Math
28
     */
29
    private $math;
30
31
    /**
32
     * @param Math $math
33
     * @param Opcodes $opcodes
34
     * @param BufferInterface|null $buffer
35
     */
36 2618
    public function __construct(Math $math, Opcodes $opcodes, BufferInterface $buffer = null)
37
    {
38 2618
        if ($buffer !== null) {
39 42
            $this->script = $buffer->getBinary();
40
        }
41
42 2618
        $this->math = $math;
43 2618
        $this->opcodes = $opcodes;
44 2618
    }
45
46
    /**
47
     * @param int[]|\BitWasp\Bitcoin\Script\Interpreter\Number[]|BufferInterface[] $sequence
48
     * @return $this
49
     */
50 2554
    public function sequence(array $sequence)
51
    {
52 2554
        $new = new self($this->math, $this->opcodes, null);
53 2554
        foreach ($sequence as $operation) {
54 2548
            if (is_int($operation)) {
55 2508
                if (!$this->opcodes->offsetExists($operation)) {
56
                    throw new \RuntimeException('Unknown opcode');
57
                }
58
59 2508
                $new->script .= chr($operation);
60 286
            } elseif ($operation instanceof Number) {
61
                $new->push($operation->getBuffer());
62 286
            } elseif ($operation instanceof BufferInterface) {
63 286
                $new->push($operation);
64
            } elseif ($operation instanceof ScriptInterface) {
65
                $new->concat($operation);
66
            } else {
67 2548
                throw new \RuntimeException('Value must be an opcode/BufferInterface/Number');
68
            }
69
        }
70
71 2554
        $this->concat($new->getScript());
72 2554
        return $this;
73
    }
74
75
    /**
76
     * Add an opcode to the script
77
     *
78
     * @param string $name
79
     * @return $this
80
     */
81 66
    public function op($name)
82
    {
83 66
        $code = $this->opcodes->getOpByName($name);
84 64
        $this->script .= chr($code);
85 64
        return $this;
86
    }
87
88
    /**
89
     * Push data into the stack.
90
     *
91
     * @param $data
92
     * @return $this
93
     * @throws \Exception
94
     */
95 316
    public function push(BufferInterface $data)
96
    {
97 316
        $length = $data->getSize();
98
99 316
        if ($length < Opcodes::OP_PUSHDATA1) {
100 310
            $this->script .= pack('C', $length) . $data->getBinary();
101
        } else {
102 8
            if ($length <= 0xff) {
103 4
                $lengthSize = 1;
104 4
                $code = 'C';
105 4
            } elseif ($length <= 0xffff) {
106 2
                $lengthSize = 2;
107 2
                $code = 'S';
108
            } else {
109 2
                $lengthSize = 4;
110 2
                $code = 'V';
111
            }
112
113 8
            $opCode = constant("BitWasp\\Bitcoin\\Script\\Opcodes::OP_PUSHDATA" . $lengthSize);
114 8
            $this->script .= pack('C', $opCode) . pack($code, $length) . $data->getBinary();
115
        }
116
117 316
        return $this;
118
    }
119
120
    /**
121
     * @param int $n
122
     * @return $this
123
     */
124 32
    public function int($n)
125
    {
126 32
        if ($n === 0) {
127
            $this->script .= chr(Opcodes::OP_0);
128 32
        } else if ($n === -1 || ($n >= 1 && $n <= 16)) {
129 32
            $this->script .= chr(\BitWasp\Bitcoin\Script\encodeOpN($n));
130
        } else {
131
            $this->push(Number::int($n)->getBuffer());
132
        }
133
134 32
        return $this;
135
    }
136
137
    /**
138
     * @param Serializable $object
139
     * @return $this
140
     */
141
    public function pushSerializable(Serializable $object)
142
    {
143
        $this->push($object->getBuffer());
144
        return $this;
145
    }
146
147
    /**
148
     * @param ScriptInterface $script
149
     * @return $this
150
     */
151 2554
    public function concat(ScriptInterface $script)
152
    {
153 2554
        $this->script .= $script->getBinary();
154 2554
        return $this;
155
    }
156
157
    /**
158
     * @return ScriptInterface
159
     */
160 2616
    public function getScript()
161
    {
162 2616
        return new Script(new Buffer($this->script, null, $this->math), $this->opcodes);
163
    }
164
}
165