line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
4
|
|
|
4
|
|
416701
|
use v5.26; |
|
4
|
|
|
|
|
50
|
|
2
|
4
|
|
|
4
|
|
2453
|
use Object::Pad; |
|
4
|
|
|
|
|
44726
|
|
|
4
|
|
|
|
|
17
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Blockchain::Ethereum::RLP 0.007; |
5
|
|
|
|
|
|
|
class Blockchain::Ethereum::RLP; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=encoding utf8 |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Blockchain::Ethereum::RLP - Ethereum RLP encoding/decoding utility |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Allow RLP encoding and decoding |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $rlp = Blockchain::Ethereum::RLP->new(); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $tx_params = ['0x9', '0x4a817c800', '0x5208', '0x3535353535353535353535353535353535353535', '0xde0b6b3a7640000', '0x', '0x1', '0x', '0x']; |
20
|
|
|
|
|
|
|
my $encoded = $rlp->encode($params); #ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $encoded_tx_params = 'ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080'; |
23
|
|
|
|
|
|
|
my $decoded = $rlp->decode(pack "H*", $encoded_tx_params); #['0x9', '0x4a817c800', '0x5208', '0x3535353535353535353535353535353535353535', '0xde0b6b3a7640000', '0x', '0x1', '0x', '0x'] |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=cut |
26
|
|
|
|
|
|
|
|
27
|
4
|
|
|
4
|
|
1628
|
use Carp; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
354
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use constant { |
30
|
4
|
|
|
|
|
9248
|
STRING => 'string', |
31
|
|
|
|
|
|
|
LIST => 'list', |
32
|
|
|
|
|
|
|
SINGLE_BYTE_MAX_LENGTH => 128, |
33
|
|
|
|
|
|
|
SHORT_STRING_MAX_LENGTH => 183, |
34
|
|
|
|
|
|
|
LONG_STRING_MAX_LENGTH => 192, |
35
|
|
|
|
|
|
|
LIST_MAX_LENGTH => 247, |
36
|
|
|
|
|
|
|
LONG_LIST_MAX_LENGTH => 255, |
37
|
|
|
|
|
|
|
BYTE_LENGTH_DELIMITER => 55, |
38
|
|
|
|
|
|
|
INPUT_LENGTH_DELIMITER => 256, |
39
|
4
|
|
|
4
|
|
26
|
}; |
|
4
|
|
|
|
|
8
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 encode |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Encodes the given input to RLP |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Usage: |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
encode(hex string / hex array reference) -> encoded bytes |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=over 4 |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item * C<$input> hexadecimal string or reference to an hexadecimal string array |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=back |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Return the encoded bytes |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=cut |
58
|
|
|
|
|
|
|
|
59
|
65
|
|
|
65
|
1
|
10545
|
method encode ($input) { |
|
65
|
|
|
|
|
88
|
|
|
65
|
|
|
|
|
92
|
|
|
65
|
|
|
|
|
83
|
|
60
|
|
|
|
|
|
|
|
61
|
65
|
50
|
|
|
|
135
|
croak 'No input given' unless defined $input; |
62
|
|
|
|
|
|
|
|
63
|
65
|
100
|
|
|
|
138
|
if (ref $input eq 'ARRAY') { |
64
|
16
|
|
|
|
|
27
|
my $output = ''; |
65
|
16
|
|
|
|
|
49
|
$output .= $self->encode($_) for $input->@*; |
66
|
|
|
|
|
|
|
|
67
|
16
|
|
|
|
|
33
|
return $self->_encode_length(length($output), LONG_STRING_MAX_LENGTH) . $output; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
49
|
|
|
|
|
160
|
my $hex = $input =~ s/^0x//r; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# zero will be considered empty as per RLP specification |
73
|
49
|
100
|
|
|
|
120
|
unless ($hex) { |
74
|
11
|
|
|
|
|
20
|
$hex = chr(0x80); |
75
|
11
|
|
|
|
|
33
|
return $hex; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# pack will add a null character at the end if the length is odd |
79
|
|
|
|
|
|
|
# RLP expects this to be added at the left instead. |
80
|
38
|
100
|
|
|
|
112
|
$hex = "0$hex" if length($hex) % 2 != 0; |
81
|
38
|
|
|
|
|
118
|
$hex = pack("H*", $hex); |
82
|
|
|
|
|
|
|
|
83
|
38
|
|
|
|
|
56
|
my $input_length = length $hex; |
84
|
|
|
|
|
|
|
|
85
|
38
|
100
|
100
|
|
|
116
|
return $hex if $input_length == 1 && ord $hex < SINGLE_BYTE_MAX_LENGTH; |
86
|
31
|
|
|
|
|
63
|
return $self->_encode_length($input_length, SINGLE_BYTE_MAX_LENGTH) . $hex; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
47
|
|
|
47
|
|
84
|
method _encode_length ($length, $offset) { |
|
47
|
|
|
|
|
79
|
|
|
47
|
|
|
|
|
99
|
|
|
47
|
|
|
|
|
84
|
|
|
47
|
|
|
|
|
58
|
|
90
|
|
|
|
|
|
|
|
91
|
47
|
100
|
|
|
|
220
|
return chr($length + $offset) if $length <= BYTE_LENGTH_DELIMITER; |
92
|
|
|
|
|
|
|
|
93
|
5
|
50
|
|
|
|
32
|
if ($length < INPUT_LENGTH_DELIMITER**8) { |
94
|
5
|
|
|
|
|
18
|
my $bl = $self->_to_binary($length); |
95
|
5
|
|
|
|
|
38
|
return chr(length($bl) + $offset + BYTE_LENGTH_DELIMITER) . $bl; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
0
|
croak "Input too long"; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
10
|
|
|
10
|
|
25
|
method _to_binary ($x) { |
|
10
|
|
|
|
|
14
|
|
|
10
|
|
|
|
|
18
|
|
|
10
|
|
|
|
|
15
|
|
102
|
|
|
|
|
|
|
|
103
|
10
|
100
|
|
|
|
37
|
return '' unless $x; |
104
|
5
|
|
|
|
|
24
|
return $self->_to_binary(int($x / INPUT_LENGTH_DELIMITER)) . chr($x % INPUT_LENGTH_DELIMITER); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head2 decode |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Decode the given input from RLP to the specific return type |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Usage: |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
decode(RLP encoded bytes) -> hexadecimal string / array reference |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=over 4 |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item * C<$input> RLP encoded bytes |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=back |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Returns an hexadecimals string or an array reference in case of multiple items |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=cut |
124
|
|
|
|
|
|
|
|
125
|
65
|
|
|
65
|
1
|
14971
|
method decode ($input) { |
|
65
|
|
|
|
|
98
|
|
|
65
|
|
|
|
|
114
|
|
|
65
|
|
|
|
|
116
|
|
126
|
|
|
|
|
|
|
|
127
|
65
|
50
|
|
|
|
132
|
return [] unless length $input; |
128
|
|
|
|
|
|
|
|
129
|
65
|
|
|
|
|
122
|
my ($offset, $data_length, $type) = $self->_decode_length($input); |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# string |
132
|
65
|
100
|
|
|
|
158
|
if ($type eq STRING) { |
133
|
49
|
|
|
|
|
137
|
my $hex = unpack("H*", substr($input, $offset, $data_length)); |
134
|
|
|
|
|
|
|
# same as for the encoding we do expect an prefixed 0 for |
135
|
|
|
|
|
|
|
# odd length hexadecimal values, this just removes the 0 prefix. |
136
|
49
|
100
|
66
|
|
|
183
|
$hex = substr($hex, 1) if $hex =~ /^0/ && (length($hex) - 1) % 2 != 0; |
137
|
49
|
|
|
|
|
145
|
return '0x' . $hex; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# list |
141
|
16
|
|
|
|
|
25
|
my @output; |
142
|
16
|
|
|
|
|
34
|
my $list_data = substr($input, $offset, $data_length); |
143
|
16
|
|
|
|
|
25
|
my $list_offset = 0; |
144
|
|
|
|
|
|
|
# recursive arrays |
145
|
16
|
|
|
|
|
57
|
while ($list_offset < length($list_data)) { |
146
|
51
|
|
|
|
|
124
|
my ($item_offset, $item_length, $item_type) = $self->_decode_length(substr($list_data, $list_offset)); |
147
|
51
|
|
|
|
|
163
|
my $list_item = $self->decode(substr($list_data, $list_offset, $item_offset + $item_length)); |
148
|
51
|
|
|
|
|
113
|
push @output, $list_item; |
149
|
51
|
|
|
|
|
114
|
$list_offset += $item_offset + $item_length; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
16
|
|
|
|
|
46
|
return \@output; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
116
|
|
|
116
|
|
201
|
method _decode_length ($input) { |
|
116
|
|
|
|
|
149
|
|
|
116
|
|
|
|
|
207
|
|
|
116
|
|
|
|
|
161
|
|
156
|
|
|
|
|
|
|
|
157
|
116
|
|
|
|
|
163
|
my $length = length($input); |
158
|
116
|
50
|
|
|
|
198
|
croak "Invalid empty input" unless $length; |
159
|
|
|
|
|
|
|
|
160
|
116
|
|
|
|
|
198
|
my $prefix = ord(substr($input, 0, 1)); |
161
|
|
|
|
|
|
|
|
162
|
116
|
|
|
|
|
168
|
my $short_string = $prefix - SINGLE_BYTE_MAX_LENGTH; |
163
|
116
|
|
|
|
|
153
|
my $long_string = $prefix - SHORT_STRING_MAX_LENGTH; |
164
|
116
|
|
|
|
|
157
|
my $list = $prefix - LONG_STRING_MAX_LENGTH; |
165
|
116
|
|
|
|
|
178
|
my $long_list = $prefix - LIST_MAX_LENGTH; |
166
|
|
|
|
|
|
|
|
167
|
116
|
100
|
66
|
|
|
454
|
if ($prefix < SINGLE_BYTE_MAX_LENGTH) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
168
|
|
|
|
|
|
|
# single byte |
169
|
13
|
|
|
|
|
36
|
return (0, 1, STRING); |
170
|
|
|
|
|
|
|
} elsif ($prefix <= SHORT_STRING_MAX_LENGTH && $length > $short_string) { |
171
|
|
|
|
|
|
|
# short string |
172
|
75
|
|
|
|
|
187
|
return (1, $short_string, STRING); |
173
|
|
|
|
|
|
|
} elsif ($prefix <= LONG_STRING_MAX_LENGTH |
174
|
|
|
|
|
|
|
&& $length > $long_string |
175
|
|
|
|
|
|
|
&& $length > $long_string + $self->_to_integer(substr($input, 1, $long_string))) |
176
|
|
|
|
|
|
|
{ |
177
|
|
|
|
|
|
|
# long string |
178
|
3
|
|
|
|
|
10
|
my $str_length = $self->_to_integer(substr($input, 1, $long_string)); |
179
|
3
|
|
|
|
|
11
|
return (1 + $long_string, $str_length, STRING); |
180
|
|
|
|
|
|
|
} elsif ($prefix < LIST_MAX_LENGTH && $length > $list) { |
181
|
|
|
|
|
|
|
# list |
182
|
22
|
|
|
|
|
65
|
return (1, $list, LIST); |
183
|
|
|
|
|
|
|
} elsif ($prefix <= LONG_LIST_MAX_LENGTH |
184
|
|
|
|
|
|
|
&& $length > $long_list |
185
|
|
|
|
|
|
|
&& $length > $long_list + $self->_to_integer(substr($input, 1, $long_list))) |
186
|
|
|
|
|
|
|
{ |
187
|
|
|
|
|
|
|
# long list |
188
|
3
|
|
|
|
|
9
|
my $list_length = $self->_to_integer(substr($input, 1, $long_list)); |
189
|
3
|
|
|
|
|
15
|
return (1 + $long_list, $list_length, LIST); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
croak "Invalid RLP input"; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
30
|
|
|
30
|
|
57
|
method _to_integer ($b) { |
|
30
|
|
|
|
|
44
|
|
|
30
|
|
|
|
|
59
|
|
|
30
|
|
|
|
|
40
|
|
196
|
|
|
|
|
|
|
|
197
|
30
|
|
|
|
|
48
|
my $length = length($b); |
198
|
30
|
50
|
|
|
|
54
|
croak "Invalid empty input" unless $length; |
199
|
|
|
|
|
|
|
|
200
|
30
|
100
|
|
|
|
99
|
return ord($b) if $length == 1; |
201
|
|
|
|
|
|
|
|
202
|
16
|
|
|
|
|
63
|
return ord(substr($b, -1)) + $self->_to_integer(substr($b, 0, -1)) * INPUT_LENGTH_DELIMITER; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
1; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
__END__ |