Completed
Pull Request — master (#248)
by thomas
58:32 queued 33:01
created

TransactionSerializer::parse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Serializer\Transaction;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Collection\Transaction\TransactionInputCollection;
7
use BitWasp\Bitcoin\Collection\Transaction\TransactionOutputCollection;
8
use BitWasp\Bitcoin\Collection\Transaction\TransactionWitnessCollection;
9
use BitWasp\Bitcoin\Serializer\Script\ScriptWitnessSerializer;
10
use BitWasp\Bitcoin\Transaction\Transaction;
11
use BitWasp\Bitcoin\Transaction\TransactionInterface;
12
use BitWasp\Buffertools\Buffer;
13
use BitWasp\Buffertools\BufferInterface;
14
use BitWasp\Buffertools\ByteOrder;
15
use BitWasp\Buffertools\Parser;
16
use BitWasp\Buffertools\Types\Int32;
17
use BitWasp\Buffertools\Types\Int8;
18
use BitWasp\Buffertools\Types\Uint32;
19
use BitWasp\Buffertools\Types\VarInt;
20
use BitWasp\Buffertools\Types\Vector;
21
22
class TransactionSerializer
23
{
24
    /**
25
     * @var TransactionInputSerializer
26
     */
27
    private $inputSerializer;
28
29
    /**
30
     * @var TransactionOutputSerializer
31
     */
32
    private $outputSerializer;
33
34
    /**
35
     * @var ScriptWitnessSerializer
36
     */
37
    private $witnessSerializer;
38
39 300
    public function __construct()
40
    {
41 300
        $this->inputSerializer = new TransactionInputSerializer(new OutPointSerializer());
42 300
        $this->outputSerializer = new TransactionOutputSerializer;
43 300
        $this->witnessSerializer = new ScriptWitnessSerializer();
44 300
    }
45
46
    /**
47
     * @param Parser $parser
48
     * @return Transaction
49
     */
50 228
    public function fromParser(Parser $parser)
51
    {
52 228
        $math = Bitcoin::getMath();
53 228
        $int32le = new Int32($math, ByteOrder::LE);
54 228
        $uint32le = new Uint32($math, ByteOrder::LE);
55 228
        $varint = new VarInt($math, ByteOrder::LE);
56
57 228
        $version = $int32le->read($parser);
58
59 228
        $vin = [];
60 228
        $vinCount = $varint->read($parser);
61 228
        for ($i = 0; $i < $vinCount; $i++) {
62 228
            $vin[] = $this->inputSerializer->fromParser($parser);
63 228
        }
64
65 228
        $vout = [];
66 228
        $flags = 0;
67 228
        if (count($vin) == 0) {
68
            $flags = (int) $varint->read($parser);
69
            if ($flags != 0) {
70
                $vinCount = $varint->read($parser);
71
                for ($i = 0; $i < $vinCount; $i++) {
72
                    $vin[] = $this->inputSerializer->fromParser($parser);
73
                }
74
75
                $voutCount = $varint->read($parser);
76
                for ($i = 0; $i < $voutCount; $i++) {
77
                    $vout[] = $this->outputSerializer->fromParser($parser);
78
                }
79
            }
80
        } else {
81 228
            $voutCount = $varint->read($parser);
82 228
            for ($i = 0; $i < $voutCount; $i++) {
83 228
                $vout[] = $this->outputSerializer->fromParser($parser);
84 228
            }
85
        }
86
87 228
        $vwit = [];
88 228
        if (($flags & 1)) {
89
            $flags ^= 1;
90
            $witCount = count($vin);
91
            for ($i = 0; $i < $witCount; $i++) {
92
                $vectorCount = $varint->read($parser);
93
                $vwit[] = $this->witnessSerializer->fromParser($parser, $vectorCount);
94
            }
95
        }
96
97 228
        if ($flags) {
98
            throw new \RuntimeException('Flags byte was 0');
99
        }
100
101 228
        $lockTime = $uint32le->read($parser);
102
103 228
        return new Transaction(
104 228
            $version,
105 228
            new TransactionInputCollection($vin),
106 228
            new TransactionOutputCollection($vout),
107 228
            new TransactionWitnessCollection($vwit),
108
            $lockTime
109 228
        );
110
    }
111
112
    /**
113
     * @param string|BufferInterface $data
114
     * @return Transaction
115
     */
116 156
    public function parse($data)
117
    {
118 156
        return $this->fromParser(new Parser($data));
0 ignored issues
show
Bug introduced by
It seems like $data defined by parameter $data on line 116 can also be of type object<BitWasp\Buffertools\BufferInterface>; however, BitWasp\Buffertools\Parser::__construct() does only seem to accept null|string|object<BitWasp\Buffertools\Buffer>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
119
    }
120
121
    /**
122
     * @param TransactionInterface $transaction
123
     * @return BufferInterface
124
     */
125 54
    public function serialize(TransactionInterface $transaction)
126
    {
127 54
        $math = Bitcoin::getMath();
128 54
        $int8le = new Int8($math, ByteOrder::LE);
129 54
        $int32le = new Int32($math, ByteOrder::LE);
130 54
        $uint32le = new Uint32($math, ByteOrder::LE);
131 54
        $varint = new VarInt($math, ByteOrder::LE);
132 54
        $vector = new Vector($varint, function () {
133 54
        });
134
135 54
        $binary = $int32le->write($transaction->getVersion());
136 54
        $flags = 0;
137
138 54
        if (!$transaction->getWitnesses()->isNull()) {
139 54
            $flags |= 1;
140 54
        }
141
142 54
        if ($flags) {
143 54
            $binary .= $int8le->write(0);
144 54
            $binary .= $int8le->write($flags);
145 54
        }
146
147 54
        $binary .= $vector->write($transaction->getInputs()->all());
148 54
        $binary .= $vector->write($transaction->getOutputs()->all());
149
150 54
        if ($flags & 1) {
151 54
            foreach ($transaction->getWitnesses() as $witness) {
152 54
                $binary .= $witness->getBuffer()->getBinary();
153 54
            }
154 54
        }
155
156 54
        $binary .= $uint32le->write($transaction->getLockTime());
157
158 54
        return new Buffer($binary);
159
    }
160
}
161