Completed
Pull Request — master (#402)
by thomas
74:17 queued 71:35
created

ScriptCreator   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 85.48%

Importance

Changes 0
Metric Value
dl 0
loc 151
ccs 53
cts 62
cp 0.8548
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 7

8 Methods

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