Completed
Pull Request — master (#499)
by thomas
21:08 queued 01:01
created

TransactionSerializer   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 98.33%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 149
ccs 59
cts 60
cp 0.9833
rs 10
c 2
b 0
f 0
wmc 23
lcom 1
cbo 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 4
A parse() 0 4 1
C serialize() 0 35 8
C fromParser() 0 49 10
1
<?php
2
3
namespace BitWasp\Bitcoin\Serializer\Transaction;
4
5
use BitWasp\Bitcoin\Serializer\Script\ScriptWitnessSerializer;
6
use BitWasp\Bitcoin\Serializer\Types;
7
use BitWasp\Bitcoin\Transaction\Transaction;
8
use BitWasp\Bitcoin\Transaction\TransactionInterface;
9
use BitWasp\Buffertools\BufferInterface;
10
use BitWasp\Buffertools\Parser;
11
12
class TransactionSerializer implements TransactionSerializerInterface
13
{
14
    const NO_WITNESS = 1;
15
16
    /**
17
     * @var \BitWasp\Buffertools\Types\Int32
18
     */
19
    private $int32le;
20
21
    /**
22
     * @var \BitWasp\Buffertools\Types\Uint32
23
     */
24
    private $uint32le;
25
26
    /**
27
     * @var \BitWasp\Buffertools\Types\VarInt
28
     */
29
    private $varint;
30
31
    /**
32
     * @var TransactionInputSerializer
33
     */
34
    private $inputSerializer;
35
36
    /**
37
     * @var TransactionOutputSerializer
38
     */
39
    private $outputSerializer;
40
41
    /**
42
     * @var ScriptWitnessSerializer
43
     */
44
    private $witnessSerializer;
45
46 2530
    public function __construct(TransactionInputSerializer $inputSerializer = null, TransactionOutputSerializer $outputSerializer = null, ScriptWitnessSerializer $witnessSerializer = null)
47
    {
48 2530
        $this->int32le = Types::int32le();
49 2530
        $this->uint32le = Types::uint32le();
50 2530
        $this->varint = Types::varint();
51
52 2530
        $this->inputSerializer = $inputSerializer ?: new TransactionInputSerializer(new OutPointSerializer());
53 2530
        $this->outputSerializer = $outputSerializer ?: new TransactionOutputSerializer;
54 2530
        $this->witnessSerializer = $witnessSerializer ?: new ScriptWitnessSerializer();
55 2530
    }
56
57
    /**
58
     * @param Parser $parser
59
     * @return TransactionInterface
60
     */
61 132
    public function fromParser(Parser $parser)
62
    {
63 132
        $version = $this->int32le->read($parser);
64
65 132
        $vin = [];
66 132
        $vinCount = $this->varint->read($parser);
67 132
        for ($i = 0; $i < $vinCount; $i++) {
68 110
            $vin[] = $this->inputSerializer->fromParser($parser);
69
        }
70
71 132
        $vout = [];
72 132
        $flags = 0;
73 132
        if (count($vin) === 0) {
74 22
            $flags = (int) $this->varint->read($parser);
75 22
            if ($flags !== 0) {
76 22
                $vinCount = $this->varint->read($parser);
77 22
                for ($i = 0; $i < $vinCount; $i++) {
78 22
                    $vin[] = $this->inputSerializer->fromParser($parser);
79
                }
80
81 22
                $voutCount = $this->varint->read($parser);
82 22
                for ($i = 0; $i < $voutCount; $i++) {
83 22
                    $vout[] = $this->outputSerializer->fromParser($parser);
84
                }
85
            }
86
        } else {
87 110
            $voutCount = $this->varint->read($parser);
88 110
            for ($i = 0; $i < $voutCount; $i++) {
89 110
                $vout[] = $this->outputSerializer->fromParser($parser);
90
            }
91
        }
92
93 130
        $vwit = [];
94 130
        if (($flags & 1)) {
95 22
            $flags ^= 1;
96 22
            $witCount = count($vin);
97 22
            for ($i = 0; $i < $witCount; $i++) {
98 22
                $vwit[] = $this->witnessSerializer->fromParser($parser);
99
            }
100
        }
101
102 130
        if ($flags) {
103
            throw new \RuntimeException('Flags byte was 0');
104
        }
105
106 130
        $lockTime = $this->uint32le->read($parser);
107
108 130
        return new Transaction($version, $vin, $vout, $vwit, $lockTime);
109
    }
110
111
    /**
112
     * @param string|BufferInterface $data
113
     * @return TransactionInterface
114
     */
115 110
    public function parse($data)
116
    {
117 110
        return $this->fromParser(new Parser($data));
118
    }
119
120
    /**
121
     * @param TransactionInterface $transaction
122
     * @param int $opt
123
     * @return BufferInterface
124
     */
125 2498
    public function serialize(TransactionInterface $transaction, $opt = 0)
126
    {
127 2498
        $parser = new Parser();
128 2498
        $parser->appendBinary($this->int32le->write($transaction->getVersion()));
129
130 2498
        $flags = 0;
131 2498
        $allowWitness = !($opt & self::NO_WITNESS);
132 2498
        if ($allowWitness && $transaction->hasWitness()) {
133 44
            $flags |= 1;
134
        }
135
136 2498
        if ($flags) {
137 44
            $parser->appendBinary(pack("CC", 0, $flags));
138
        }
139
140 2498
        $parser->appendBinary($this->varint->write(count($transaction->getInputs())));
141 2498
        foreach ($transaction->getInputs() as $input) {
142 2496
            $parser->appendBuffer($this->inputSerializer->serialize($input));
143
        }
144
145 2498
        $parser->appendBinary($this->varint->write(count($transaction->getOutputs())));
146 2498
        foreach ($transaction->getOutputs() as $output) {
147 2498
            $parser->appendBuffer($this->outputSerializer->serialize($output));
148
        }
149
150 2498
        if ($flags & 1) {
151 44
            foreach ($transaction->getWitnesses() as $witness) {
152 44
                $parser->appendBuffer($this->witnessSerializer->serialize($witness));
153
            }
154
        }
155
156 2498
        $parser->appendBinary($this->uint32le->write($transaction->getLockTime()));
157
158 2498
        return $parser->getBuffer();
159
    }
160
}
161