Completed
Push — master ( e12674...2b8220 )
by thomas
28:40
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 2738
    public function __construct(Math $math, Opcodes $opcodes, BufferInterface $buffer = null)
37
    {
38 2738
        if ($buffer !== null) {
39 42
            $this->script = $buffer->getBinary();
40
        }
41
42 2738
        $this->math = $math;
43 2738
        $this->opcodes = $opcodes;
44 2738
    }
45
46
    /**
47
     * @param int[]|\BitWasp\Bitcoin\Script\Interpreter\Number[]|BufferInterface[] $sequence
48
     * @return $this
49
     */
50 2674
    public function sequence(array $sequence)
51
    {
52 2674
        $new = new self($this->math, $this->opcodes, null);
53 2674
        foreach ($sequence as $operation) {
54 2654
            if (is_int($operation)) {
55 2610
                if (!$this->opcodes->offsetExists($operation)) {
56
                    throw new \RuntimeException('Unknown opcode');
57
                }
58
59 2610
                $new->script .= chr($operation);
60 366
            } elseif ($operation instanceof Number) {
61
                $new->push($operation->getBuffer());
62 366
            } elseif ($operation instanceof BufferInterface) {
63 366
                $new->push($operation);
64
            } elseif ($operation instanceof ScriptInterface) {
65
                $new->concat($operation);
66
            } else {
67 2654
                throw new \RuntimeException('Value must be an opcode/BufferInterface/Number');
68
            }
69
        }
70
71 2674
        $this->concat($new->getScript());
72 2674
        return $this;
73
    }
74
75
    /**
76
     * Add an opcode to the script
77
     *
78
     * @param string $name
79
     * @return $this
80
     */
81 70
    public function op($name)
82
    {
83 70
        $code = $this->opcodes->getOpByName($name);
84 68
        $this->script .= chr($code);
85 68
        return $this;
86
    }
87
88
    /**
89
     * Push data into the stack.
90
     *
91
     * @param $data
92
     * @return $this
93
     * @throws \Exception
94
     */
95 396
    public function push(BufferInterface $data)
96
    {
97 396
        $length = $data->getSize();
98
99 396
        if ($length < Opcodes::OP_PUSHDATA1) {
100 390
            $this->script .= pack('C', $length) . $data->getBinary();
101
        } else {
102 22
            if ($length <= 0xff) {
103 18
                $lengthSize = 1;
104 18
                $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 22
            $opCode = constant("BitWasp\\Bitcoin\\Script\\Opcodes::OP_PUSHDATA" . $lengthSize);
114 22
            $this->script .= pack('C', $opCode) . pack($code, $length) . $data->getBinary();
115
        }
116
117 396
        return $this;
118
    }
119
120
    /**
121
     * @param int $n
122
     * @return $this
123
     */
124 36
    public function int($n)
125
    {
126 36
        if ($n === 0) {
127
            $this->script .= chr(Opcodes::OP_0);
128 36
        } else if ($n === -1 || ($n >= 1 && $n <= 16)) {
129 36
            $this->script .= chr(\BitWasp\Bitcoin\Script\encodeOpN($n));
130
        } else {
131
            $this->push(Number::int($n)->getBuffer());
132
        }
133
134 36
        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 2674
    public function concat(ScriptInterface $script)
152
    {
153 2674
        $this->script .= $script->getBinary();
154 2674
        return $this;
155
    }
156
157
    /**
158
     * @return ScriptInterface
159
     */
160 2736
    public function getScript()
161
    {
162 2736
        return new Script(new Buffer($this->script, null, $this->math), $this->opcodes);
163
    }
164
}
165