Completed
Pull Request — master (#241)
by thomas
133:23 queued 63:06
created

NTransactionSerializer   C

Complexity

Total Complexity 19

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 19
c 1
b 0
f 1
lcom 1
cbo 19
dl 0
loc 138
rs 6.875

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A vinParser() 0 8 1
A voutParser() 0 8 1
A vwitParser() 0 8 1
C fromParser() 0 59 10
A parse() 0 4 1
B serialize() 0 33 4
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\ByteOrder;
14
use BitWasp\Buffertools\Parser;
15
use BitWasp\Buffertools\TemplateFactory;
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 NTransactionSerializer
23
{
24
    /**
25
     *
26
     */
27
    public function __construct()
28
    {
29
        $this->inputSerializer = new TransactionInputSerializer(new OutPointSerializer());
0 ignored issues
show
Bug introduced by
The property inputSerializer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
30
        $this->outputSerializer = new TransactionOutputSerializer;
0 ignored issues
show
Bug introduced by
The property outputSerializer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
31
        $this->witnessSerializer = new ScriptWitnessSerializer();
0 ignored issues
show
Bug introduced by
The property witnessSerializer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
32
    }
33
34
    public function vinParser()
35
    {
36
        return (new TemplateFactory())
37
            ->vector(function (Parser $parser) {
38
                return $this->inputSerializer->fromParser($parser);
39
            })
40
            ->getTemplate();
41
    }
42
43
    public function voutParser()
44
    {
45
        return (new TemplateFactory())
46
            ->vector(function (Parser $parser) {
47
                return $this->outputSerializer->fromParser($parser);
48
            })
49
            ->getTemplate();
50
    }
51
52
    public function vwitParser($inCount)
53
    {
54
        return (new TemplateFactory())
55
            ->vector(function (Parser $parser) use ($inCount) {
56
                return $this->witnessSerializer->fromParser($parser, $inCount);
57
            })
58
            ->getTemplate();
59
    }
60
61
    public function fromParser(Parser $parser)
62
    {
63
        $math = Bitcoin::getMath();
64
        $int32le = new Int32($math, ByteOrder::LE);
65
        $uint32le = new Uint32($math, ByteOrder::LE);
66
        $varint = new VarInt($math, ByteOrder::LE);
67
        $vinParser = $this->vinParser();
68
69
        $version = $int32le->read($parser);
70
        list ($vin) = $vinParser->parse($parser);
71
72
        $vout = [];
73
        $flags = 0;
74
        if (count($vin) == 0) {
75
            $flags = (int) $varint->read($parser);
76
            if ($flags != 0) {
77
                $vinCount = $varint->read($parser);
78
                for ($i = 0; $i < $vinCount; $i++) {
79
                    $vin[] = $this->inputSerializer->fromParser($parser);
80
                }
81
82
                $voutCount = $varint->read($parser);
83
                for ($i = 0; $i < $voutCount; $i++) {
84
                    $vout[] = $this->outputSerializer->fromParser($parser);
85
                }
86
            }
87
        } else {
88
            $voutCount = $varint->read($parser);
89
            for ($i = 0; $i < $voutCount; $i++) {
90
                $vout[] = $this->outputSerializer->fromParser($parser);
91
            }
92
        }
93
94
        $vwit = [];
95
        if (($flags & 1)) {
96
            echo "Check flags for witness: " . ($flags & 1 ? 'yes' : 'no') . PHP_EOL;
97
            $flags ^= 1;
98
            $witCount = count($vin);
99
            for ($i = 0; $i < $witCount; $i++) {
100
                echo "parse a witness structure\n";
101
                $vectorCount = $varint->read($parser);
102
                $vwit[] = $this->witnessSerializer->fromParser($parser, $vectorCount);
103
            }
104
        }
105
106
        if ($flags) {
107
            throw new \RuntimeException('Flags byte was 0');
108
        }
109
110
        $lockTime = $uint32le->read($parser);
111
112
        return new Transaction(
113
            $version,
114
            new TransactionInputCollection($vin),
115
            new TransactionOutputCollection($vout),
116
            new TransactionWitnessCollection($vwit),
117
            $lockTime
118
        );
119
    }
120
121
    public function parse($data)
122
    {
123
        return $this->fromParser(new Parser($data));
124
    }
125
126
    public function serialize(TransactionInterface $transaction)
127
    {
128
        $math = Bitcoin::getMath();
129
        $int8le = new Int8($math, ByteOrder::LE);
130
        $int32le = new Int32($math, ByteOrder::LE);
131
        $uint32le = new Uint32($math, ByteOrder::LE);
132
        $varint = new VarInt($math, ByteOrder::LE);
133
        $vector = new Vector($varint, function () {
134
        });
135
136
        $binary = $int32le->write($transaction->getVersion());
137
138
        $flags = 0;
139
        if (!$transaction->getWitnesses()->isNull()) {
140
            $flags |= 1;
141
        }
142
143
        if ($flags) {
144
            $binary .= $int8le->write(0);
145
            $binary .= $int8le->write($flags);
146
        }
147
148
        $binary .= $vector->write($transaction->getInputs()->all());
149
        $binary .= $vector->write($transaction->getOutputs()->all());
150
151
        if ($flags & 1) {
152
            $binary .= $vector->write($transaction->getWitnesses()->all());
153
        }
154
155
        $binary .= $uint32le->write($transaction->getLockTime());
156
157
        return new Buffer($binary);
158
    }
159
}
160