Coverage Summary for Class: RLP (org.ethereum.util)
Class |
Class, %
|
Method, %
|
Line, %
|
RLP |
100%
(1/1)
|
50%
(21/42)
|
37.3%
(138/370)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.util;
21
22 import co.rsk.core.BlockDifficulty;
23 import co.rsk.core.Coin;
24 import co.rsk.core.RskAddress;
25 import co.rsk.util.RLPException;
26 import org.apache.commons.lang3.tuple.Pair;
27 import org.bouncycastle.util.BigIntegers;
28 import org.ethereum.db.ByteArrayWrapper;
29
30 import javax.annotation.CheckForNull;
31 import javax.annotation.Nonnull;
32 import javax.annotation.Nullable;
33 import java.math.BigInteger;
34 import java.nio.charset.StandardCharsets;
35 import java.util.*;
36
37 import static org.bouncycastle.util.Arrays.concatenate;
38 import static org.bouncycastle.util.BigIntegers.asUnsignedByteArray;
39 import static org.ethereum.util.ByteUtil.*;
40
41 /**
42 * Recursive Length Prefix (RLP) encoding.
43 * <p>
44 * The purpose of RLP is to encode arbitrarily nested arrays of binary data, and
45 * RLP is the main encoding method used to serialize objects in Ethereum. The
46 * only purpose of RLP is to encode structure; encoding specific atomic data
47 * types (eg. strings, integers, floats) is left up to higher-order protocols; in
48 * Ethereum the standard is that integers are represented in big endian binary
49 * form. If one wishes to use RLP to encode a dictionary, the two suggested
50 * canonical forms are to either use [[k1,v1],[k2,v2]...] with keys in
51 * lexicographic order or to use the higher-level Patricia Tree encoding as
52 * Ethereum does.
53 * <p>
54 * The RLP encoding function takes in an item. An item is defined as follows:
55 * <p>
56 * - A string (ie. byte array) is an item - A list of items is an item
57 * <p>
58 * For example, an empty string is an item, as is the string containing the word
59 * "cat", a list containing any number of strings, as well as more complex data
60 * structures like ["cat",["puppy","cow"],"horse",[[]],"pig",[""],"sheep"]. Note
61 * that in the context of the rest of this article, "string" will be used as a
62 * synonym for "a certain number of bytes of binary data"; no special encodings
63 * are used and no knowledge about the content of the strings is implied.
64 * <p>
65 * See: https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP
66 *
67 * @author Roman Mandeleil
68 * @since 01.04.2014
69 */
70 public class RLP {
71 private static final int EMPTY_MARK = 128;
72 private static final int TINY_SIZE = 55;
73
74 /**
75 * Allow for content up to size of 2^64 bytes *
76 */
77 private static final double MAX_ITEM_LENGTH = Math.pow(256, 8);
78
79 /**
80 * Reason for threshold according to Vitalik Buterin:
81 * - 56 bytes maximizes the benefit of both options
82 * - if we went with 60 then we would have only had 4 slots for long strings
83 * so RLP would not have been able to store objects above 4gb
84 * - if we went with 48 then RLP would be fine for 2^128 space, but that's way too much
85 * - so 56 and 2^64 space seems like the right place to put the cutoff
86 * - also, that's where Bitcoin's varint does the cutof
87 */
88 private static final int SIZE_THRESHOLD = 56;
89
90 /** RLP encoding rules are defined as follows: */
91
92 /*
93 * For a single byte whose value is in the [0x00, 0x7f] range, that byte is
94 * its own RLP encoding.
95 */
96
97 /**
98 * [0x80]
99 * If a string is 0-55 bytes long, the RLP encoding consists of a single
100 * byte with value 0x80 plus the length of the string followed by the
101 * string. The range of the first byte is thus [0x80, 0xb7].
102 */
103 private static final int OFFSET_SHORT_ITEM = 0x80;
104
105 /**
106 * [0xb7]
107 * If a string is more than 55 bytes long, the RLP encoding consists of a
108 * single byte with value 0xb7 plus the length of the length of the string
109 * in binary form, followed by the length of the string, followed by the
110 * string. For example, a length-1024 string would be encoded as
111 * \xb9\x04\x00 followed by the string. The range of the first byte is thus
112 * [0xb8, 0xbf].
113 */
114 private static final int OFFSET_LONG_ITEM = 0xb7;
115
116 /**
117 * [0xc0]
118 * If the total payload of a list (i.e. the combined length of all its
119 * items) is 0-55 bytes long, the RLP encoding consists of a single byte
120 * with value 0xc0 plus the length of the list followed by the concatenation
121 * of the RLP encodings of the items. The range of the first byte is thus
122 * [0xc0, 0xf7].
123 */
124 private static final int OFFSET_SHORT_LIST = 0xc0;
125
126 /**
127 * [0xf7]
128 * If the total payload of a list is more than 55 bytes long, the RLP
129 * encoding consists of a single byte with value 0xf7 plus the length of the
130 * length of the list in binary form, followed by the length of the list,
131 * followed by the concatenation of the RLP encodings of the items. The
132 * range of the first byte is thus [0xf8, 0xff].
133 */
134 private static final int OFFSET_LONG_LIST = 0xf7;
135
136
137 /* ******************************************************
138 * DECODING *
139 * ******************************************************/
140
141 private static byte decodeOneByteItem(byte[] data, int index) {
142 // null item
143 if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM) {
144 return (byte) (data[index] - OFFSET_SHORT_ITEM);
145 }
146 // single byte item
147 if ((data[index] & 0xFF) < OFFSET_SHORT_ITEM) {
148 return data[index];
149 }
150 // single byte item
151 if ((data[index] & 0xFF) == OFFSET_SHORT_ITEM + 1) {
152 return data[index + 1];
153 }
154 return 0;
155 }
156
157 public static int decodeInt(byte[] data, int index) {
158 int value = 0;
159 // NOTE: there are two ways zero can be encoded - 0x00 and OFFSET_SHORT_ITEM
160
161 if ((data[index] & 0xFF) < OFFSET_SHORT_ITEM) {
162 return data[index];
163 } else if ((data[index] & 0xFF) >= OFFSET_SHORT_ITEM
164 && (data[index] & 0xFF) < OFFSET_LONG_ITEM) {
165
166 byte length = (byte) (data[index] - OFFSET_SHORT_ITEM);
167 byte pow = (byte) (length - 1);
168 for (int i = 1; i <= length; ++i) {
169 value += (data[index + i] & 0xFF) << (8 * pow);
170 pow--;
171 }
172 } else {
173 throw new RuntimeException("wrong decode attempt");
174 }
175 return value;
176 }
177
178 public static BigInteger decodeBigInteger(byte[] data, int index) {
179 RLPElement element = RLP.decodeFirstElement(data, index);
180
181 if (element == null) {
182 return null;
183 }
184
185 byte[] bytes = element.getRLPData();
186
187 if (bytes == null || bytes.length == 0) {
188 return BigInteger.ZERO;
189 }
190
191 return BigIntegers.fromUnsignedByteArray(bytes);
192 }
193
194 public static byte[] decodeIP4Bytes(byte[] data, int index) {
195
196 int offset = 1;
197
198 final byte[] result = new byte[4];
199 for (int i = 0; i < 4; i++) {
200 result[i] = decodeOneByteItem(data, index + offset);
201 if ((data[index + offset] & 0xFF) > OFFSET_SHORT_ITEM) {
202 offset += 2;
203 } else {
204 offset += 1;
205 }
206 }
207
208 // return IP address
209 return result;
210 }
211
212 public static int getFirstListElement(byte[] payload, int pos) {
213
214 if (pos >= payload.length) {
215 return -1;
216 }
217
218 if ((payload[pos] & 0xFF) >= OFFSET_LONG_LIST) {
219 byte lengthOfLength = (byte) (payload[pos] - OFFSET_LONG_LIST);
220 return pos + lengthOfLength + 1;
221 }
222 if ((payload[pos] & 0xFF) >= OFFSET_SHORT_LIST
223 && (payload[pos] & 0xFF) < OFFSET_LONG_LIST) {
224 return pos + 1;
225 }
226 if ((payload[pos] & 0xFF) >= OFFSET_LONG_ITEM
227 && (payload[pos] & 0xFF) < OFFSET_SHORT_LIST) {
228 byte lengthOfLength = (byte) (payload[pos] - OFFSET_LONG_ITEM);
229 return pos + lengthOfLength + 1;
230 }
231 return -1;
232 }
233
234 public static int getNextElementIndex(byte[] payload, int pos) {
235
236 if (pos >= payload.length) {
237 return -1;
238 }
239
240 if ((payload[pos] & 0xFF) >= OFFSET_LONG_LIST) {
241 byte lengthOfLength = (byte) (payload[pos] - OFFSET_LONG_LIST);
242 int length = calcLength(lengthOfLength, payload, pos);
243 return pos + lengthOfLength + length + 1;
244 }
245 if ((payload[pos] & 0xFF) >= OFFSET_SHORT_LIST
246 && (payload[pos] & 0xFF) < OFFSET_LONG_LIST) {
247
248 byte length = (byte) ((payload[pos] & 0xFF) - OFFSET_SHORT_LIST);
249 return pos + 1 + length;
250 }
251 if ((payload[pos] & 0xFF) >= OFFSET_LONG_ITEM
252 && (payload[pos] & 0xFF) < OFFSET_SHORT_LIST) {
253
254 byte lengthOfLength = (byte) (payload[pos] - OFFSET_LONG_ITEM);
255 int length = calcLength(lengthOfLength, payload, pos);
256 return pos + lengthOfLength + length + 1;
257 }
258 if ((payload[pos] & 0xFF) > OFFSET_SHORT_ITEM
259 && (payload[pos] & 0xFF) < OFFSET_LONG_ITEM) {
260
261 byte length = (byte) ((payload[pos] & 0xFF) - OFFSET_SHORT_ITEM);
262 return pos + 1 + length;
263 }
264 if ((payload[pos] & 0xFF) == OFFSET_SHORT_ITEM) {
265 return pos + 1;
266 }
267 if ((payload[pos] & 0xFF) < OFFSET_SHORT_ITEM) {
268 return pos + 1;
269 }
270 return -1;
271 }
272
273 /**
274 * Get exactly one message payload
275 */
276 public static void fullTraverse(byte[] msgData, int level, int startPos,
277 int endPos, int levelToIndex, Queue<Integer> index) {
278
279 try {
280
281 if (msgData == null || msgData.length == 0) {
282 return;
283 }
284 int pos = startPos;
285
286 while (pos < endPos) {
287
288 if (level == levelToIndex) {
289 index.add(pos);
290 }
291
292 // It's a list with a payload more than 55 bytes
293 // data[0] - 0xF7 = how many next bytes allocated
294 // for the length of the list
295 if ((msgData[pos] & 0xFF) >= OFFSET_LONG_LIST) {
296
297 byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_LIST);
298 int length = calcLength(lengthOfLength, msgData, pos);
299
300 // now we can parse an item for data[1]..data[length]
301 System.out.println("-- level: [" + level
302 + "] Found big list length: " + length);
303
304 fullTraverse(msgData, level + 1, pos + lengthOfLength + 1,
305 pos + lengthOfLength + length, levelToIndex, index);
306
307 pos += lengthOfLength + length + 1;
308 continue;
309 }
310 // It's a list with a payload less than 55 bytes
311 if ((msgData[pos] & 0xFF) >= OFFSET_SHORT_LIST
312 && (msgData[pos] & 0xFF) < OFFSET_LONG_LIST) {
313
314 byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_LIST);
315
316 System.out.println("-- level: [" + level
317 + "] Found small list length: " + length);
318
319 fullTraverse(msgData, level + 1, pos + 1, pos + length + 1,
320 levelToIndex, index);
321
322 pos += 1 + length;
323 continue;
324 }
325 // It's an item with a payload more than 55 bytes
326 // data[0] - 0xB7 = how much next bytes allocated for
327 // the length of the string
328 if ((msgData[pos] & 0xFF) >= OFFSET_LONG_ITEM
329 && (msgData[pos] & 0xFF) < OFFSET_SHORT_LIST) {
330
331 byte lengthOfLength = (byte) (msgData[pos] - OFFSET_LONG_ITEM);
332 int length = calcLength(lengthOfLength, msgData, pos);
333
334 // now we can parse an item for data[1]..data[length]
335 System.out.println("-- level: [" + level
336 + "] Found big item length: " + length);
337 pos += lengthOfLength + length + 1;
338
339 continue;
340 }
341 // It's an item less than 55 bytes long,
342 // data[0] - 0x80 == length of the item
343 if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM
344 && (msgData[pos] & 0xFF) < OFFSET_LONG_ITEM) {
345
346 byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM);
347
348 System.out.println("-- level: [" + level
349 + "] Found small item length: " + length);
350 pos += 1 + length;
351 continue;
352 }
353 // null item
354 if ((msgData[pos] & 0xFF) == OFFSET_SHORT_ITEM) {
355 System.out.println("-- level: [" + level
356 + "] Found null item: ");
357 pos += 1;
358 continue;
359 }
360 // single byte item
361 if ((msgData[pos] & 0xFF) < OFFSET_SHORT_ITEM) {
362 System.out.println("-- level: [" + level
363 + "] Found single item: ");
364 pos += 1;
365 continue;
366 }
367 }
368 } catch (Throwable th) {
369 throw new RuntimeException("RLP wrong encoding",
370 th.fillInStackTrace());
371 }
372 }
373
374 private static int calcLength(int lengthOfLength, byte[] msgData, int pos) {
375 byte pow = (byte) (lengthOfLength - 1);
376 int length = 0;
377 for (int i = 1; i <= lengthOfLength; ++i) {
378 length += (msgData[pos + i] & 0xFF) << (8 * pow);
379 pow--;
380 }
381 return length;
382 }
383
384 /**
385 * Parse wire byte[] message into RLP elements
386 *
387 * @param msgData - raw RLP data
388 * @return rlpList
389 * - outcome of recursive RLP structure
390 */
391 @Nonnull
392 public static ArrayList<RLPElement> decode2(@CheckForNull byte[] msgData) {
393 ArrayList<RLPElement> elements = new ArrayList<>();
394
395 if (msgData == null) {
396 return elements;
397 }
398
399 int tlength = msgData.length;
400 int position = 0;
401
402 while (position < tlength) {
403 Pair<RLPElement, Integer> next = decodeElement(msgData, position);
404 elements.add(next.getKey());
405 position = next.getValue();
406 }
407
408 return elements;
409 }
410
411 public static RLPElement decodeFirstElement(@CheckForNull byte[] msgData, int position) {
412 if (msgData == null) {
413 return null;
414 }
415
416 return decodeElement(msgData, position).getKey();
417 }
418
419 private static Pair<RLPElement, Integer> decodeElement(byte[] msgData, int position) {
420 int b0 = msgData[position] & 0xff;
421
422 if (b0 >= 192) {
423 int length;
424 int offset;
425
426 if (b0 <= 192 + TINY_SIZE) {
427 length = b0 - 192 + 1;
428 offset = 1;
429 }
430 else {
431 int nbytes = b0 - 247;
432 length = 1 + nbytes + bytesToLength(msgData, position + 1, nbytes);
433 offset = 1 + nbytes;
434 }
435
436 if (position + length > msgData.length) {
437 throw new RLPException("The RLP byte array doesn't have enough space to hold an element with the specified length");
438 }
439
440 byte[] bytes = Arrays.copyOfRange(msgData, position, position + length);
441 RLPList list = new RLPList(bytes, offset);
442
443 return Pair.of(list, position + length);
444 }
445
446 if (b0 == EMPTY_MARK) {
447 return Pair.of(new RLPItem(ByteUtil.EMPTY_BYTE_ARRAY), position + 1);
448 }
449
450 if (b0 < EMPTY_MARK) {
451 byte[] data = new byte[1];
452 data[0] = msgData[position];
453 return Pair.of(new RLPItem(data), position + 1);
454 }
455
456 int length;
457 int offset;
458
459 if (b0 > (EMPTY_MARK + TINY_SIZE)) {
460 offset = b0 - (EMPTY_MARK + TINY_SIZE) + 1;
461 length = bytesToLength(msgData, position + 1, offset - 1);
462 }
463 else {
464 length = b0 & 0x7f;
465 offset = 1;
466 }
467
468 if (Long.compareUnsigned(length, Integer.MAX_VALUE) > 0) {
469 throw new RLPException("The current implementation doesn't support lengths longer than Integer.MAX_VALUE because that is the largest number of elements an array can have");
470 }
471
472 if (position + offset + length < 0 || position + offset + length > msgData.length) {
473 throw new RLPException("The RLP byte array doesn't have enough space to hold an element with the specified length");
474 }
475
476 byte[] decoded = new byte[length];
477
478 System.arraycopy(msgData, position + offset, decoded, 0, length);
479
480 return Pair.of(new RLPItem(decoded), position + offset + length);
481 }
482
483 private static int bytesToLength(byte[] bytes, int position, int size) {
484 if (position + size > bytes.length) {
485 throw new RLPException("The length of the RLP item length can't possibly fit the data byte array");
486 }
487
488 int length = 0;
489
490 for (int k = 0; k < size; k++) {
491 length <<= 8;
492 length += bytes[position + k] & 0xff;
493 }
494
495 return length;
496 }
497
498 /**
499 * Parse and verify that the passed data has just one list encoded as RLP
500 */
501 public static RLPList decodeList(byte[] msgData) {
502 List<RLPElement> decoded = RLP.decode2(msgData);
503 if (decoded.size() != 1) {
504 throw new IllegalArgumentException(String.format("Expected one RLP item but got %d", decoded.size()));
505 }
506
507 RLPElement element = decoded.get(0);
508 if (!(element instanceof RLPList)) {
509 throw new IllegalArgumentException("The decoded element wasn't a list");
510 }
511
512 return (RLPList) element;
513 }
514
515 @Nullable
516 public static RLPElement decode2OneItem(@CheckForNull byte[] msgData, int startPos) {
517 if (msgData == null) {
518 return null;
519 }
520
521 return RLP.decodeFirstElement(msgData, startPos);
522 }
523
524 @Nonnull
525 public static RskAddress parseRskAddress(@Nullable byte[] bytes) {
526 if (bytes == null || bytes.length == 0) {
527 return RskAddress.nullAddress();
528 } else {
529 return new RskAddress(bytes);
530 }
531 }
532
533 @Nonnull
534 public static Coin parseCoin(@Nullable byte[] bytes) {
535 if (bytes == null || isAllZeroes(bytes)) {
536 return Coin.ZERO;
537 } else {
538 return new Coin(bytes);
539 }
540 }
541
542 @Nullable
543 public static Coin parseCoinNonNullZero(byte[] bytes) {
544 if (bytes == null) {
545 return null;
546 }
547
548 return new Coin(bytes);
549 }
550
551 @Nullable
552 public static Coin parseSignedCoinNonNullZero(byte[] bytes) {
553 if (bytes == null) {
554 return null;
555 }
556
557 return new Coin(new BigInteger(bytes));
558 }
559
560 public static Coin parseCoinNullZero(@Nullable byte[] bytes) {
561 if (bytes == null) {
562 return Coin.ZERO;
563 }
564
565 return new Coin(bytes);
566 }
567
568 /**
569 * @param bytes the difficulty bytes, as expected by {@link BigInteger#BigInteger(byte[])}.
570 */
571 @Nullable
572 public static BlockDifficulty parseBlockDifficulty(@Nullable byte[] bytes) {
573 if (bytes == null) {
574 return null;
575 }
576
577 return new BlockDifficulty(new BigInteger(bytes));
578 }
579
580 /* ******************************************************
581 * ENCODING *
582 * ******************************************************/
583
584 /**
585 * Turn Object into its RLP encoded equivalent of a byte-array
586 * Support for String, Integer, BigInteger and Lists of any of these types.
587 *
588 * @param input as object or List of objects
589 * @return byte[] RLP encoded
590 */
591 public static byte[] encode(Object input) {
592 Value val = new Value(input);
593 if (val.isList()) {
594 List<Object> inputArray = val.asList();
595 if (inputArray.isEmpty()) {
596 return encodeLength(inputArray.size(), OFFSET_SHORT_LIST);
597 }
598 byte[] output = ByteUtil.EMPTY_BYTE_ARRAY;
599 for (Object object : inputArray) {
600 output = concatenate(output, encode(object));
601 }
602 byte[] prefix = encodeLength(output.length, OFFSET_SHORT_LIST);
603 return concatenate(prefix, output);
604 } else {
605 byte[] inputAsBytes = toBytes(input);
606 if (inputAsBytes.length == 1 && (inputAsBytes[0] & 0xff) < 0x80) {
607 return inputAsBytes;
608 } else {
609 byte[] firstByte = encodeLength(inputAsBytes.length, OFFSET_SHORT_ITEM);
610 return concatenate(firstByte, inputAsBytes);
611 }
612 }
613 }
614
615 /**
616 * Integer limitation goes up to 2^31-1 so length can never be bigger than MAX_ITEM_LENGTH
617 */
618 public static byte[] encodeLength(int length, int offset) {
619 if (length < SIZE_THRESHOLD) {
620 byte firstByte = (byte) (length + offset);
621 return new byte[]{firstByte};
622 } else if (length < MAX_ITEM_LENGTH) {
623 byte[] binaryLength;
624 if (length > 0xFF) {
625 binaryLength = intToBytesNoLeadZeroes(length);
626 } else {
627 binaryLength = new byte[]{(byte) length};
628 }
629 byte firstByte = (byte) (binaryLength.length + offset + SIZE_THRESHOLD - 1);
630 return concatenate(new byte[]{firstByte}, binaryLength);
631 } else {
632 throw new RuntimeException("Input too long");
633 }
634 }
635
636 public static byte[] encodeByte(byte singleByte) {
637 if ((singleByte & 0xFF) == 0) {
638 return new byte[]{(byte) OFFSET_SHORT_ITEM};
639 } else if ((singleByte & 0xFF) <= 0x7F) {
640 return new byte[]{singleByte};
641 } else {
642 return new byte[]{(byte) (OFFSET_SHORT_ITEM + 1), singleByte};
643 }
644 }
645
646 public static byte[] encodeShort(short singleShort) {
647 if ((singleShort & 0xFF) == singleShort) {
648 return encodeByte((byte) singleShort);
649 } else {
650 return new byte[]{(byte) (OFFSET_SHORT_ITEM + 2),
651 (byte) (singleShort >> 8 & 0xFF),
652 (byte) (singleShort >> 0 & 0xFF)};
653 }
654 }
655
656 public static byte[] encodeInt(int singleInt) {
657 if ((singleInt & 0xFF) == singleInt) {
658 return encodeByte((byte) singleInt);
659 } else if ((singleInt & 0xFFFF) == singleInt) {
660 return encodeShort((short) singleInt);
661 } else if ((singleInt & 0xFFFFFF) == singleInt) {
662 return new byte[]{(byte) (OFFSET_SHORT_ITEM + 3),
663 (byte) (singleInt >>> 16),
664 (byte) (singleInt >>> 8),
665 (byte) singleInt};
666 } else {
667 return new byte[]{(byte) (OFFSET_SHORT_ITEM + 4),
668 (byte) (singleInt >>> 24),
669 (byte) (singleInt >>> 16),
670 (byte) (singleInt >>> 8),
671 (byte) singleInt};
672 }
673 }
674
675 public static byte[] encodeString(String srcString) {
676 return encodeElement(srcString.getBytes(StandardCharsets.UTF_8));
677 }
678
679 public static byte[] encodeBigInteger(BigInteger srcBigInteger) {
680 if (srcBigInteger.equals(BigInteger.ZERO)) {
681 return encodeByte((byte) 0);
682 } else {
683 return encodeElement(asUnsignedByteArray(srcBigInteger));
684 }
685 }
686
687 public static byte[] encodeRskAddress(RskAddress addr) {
688 if (addr == null || RskAddress.nullAddress().equals(addr)) {
689 return encodeElement(null);
690 }
691
692 return encodeElement(addr.getBytes());
693 }
694
695 public static byte[] encodeCoin(@Nullable Coin coin) {
696 if (coin == null) {
697 return encodeBigInteger(BigInteger.ZERO);
698 }
699
700 return encodeBigInteger(coin.asBigInteger());
701 }
702
703 public static byte[] encodeCoinNonNullZero(@CheckForNull Coin coin) {
704 if (coin == null) {
705 return encodeElement(null);
706 }
707
708 if (coin.equals(Coin.ZERO)) {
709 return new byte[]{0};
710 }
711
712 return encodeElement(BigIntegers.asUnsignedByteArray(coin.asBigInteger()));
713 }
714
715 public static byte[] encodeSignedCoinNonNullZero(@CheckForNull Coin coin) {
716 if (coin == null) {
717 return encodeElement(null);
718 }
719
720 if (Coin.ZERO.equals(coin)) {
721 return new byte[]{0};
722 }
723
724 return encodeElement(coin.getBytes());
725 }
726
727 public static byte[] encodeCoinNullZero(Coin coin) {
728 if (coin.equals(Coin.ZERO)) {
729 return encodeByte((byte) 0);
730 }
731
732 return encodeCoinNonNullZero(coin);
733 }
734
735 public static byte[] encodeBlockDifficulty(BlockDifficulty difficulty) {
736 if (difficulty == null) {
737 return encodeElement(null);
738 }
739
740 return encodeElement(difficulty.getBytes());
741 }
742
743 public static byte[] encodeElement(@Nullable byte[] srcData) {
744 if (srcData == null || srcData.length == 0) {
745 return new byte[]{(byte) OFFSET_SHORT_ITEM};
746 } else if (isSingleZero(srcData)) {
747 return srcData;
748 } else if (srcData.length == 1 && (srcData[0] & 0xFF) < OFFSET_SHORT_ITEM) {
749 return srcData;
750 } else if (srcData.length < SIZE_THRESHOLD) {
751 // length = 8X
752 byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length);
753 byte[] data = Arrays.copyOf(srcData, srcData.length + 1);
754 System.arraycopy(data, 0, data, 1, srcData.length);
755 data[0] = length;
756
757 return data;
758 } else {
759 // length of length = BX
760 // prefix = [BX, [length]]
761 int tmpLength = srcData.length;
762 byte byteNum = 0;
763 while (tmpLength != 0) {
764 ++byteNum;
765 tmpLength = tmpLength >> 8;
766 }
767 byte[] lenBytes = new byte[byteNum];
768 for (int i = 0; i < byteNum; ++i) {
769 lenBytes[byteNum - 1 - i] = (byte) ((srcData.length >> (8 * i)) & 0xFF);
770 }
771 // first byte = F7 + bytes.length
772 byte[] data = Arrays.copyOf(srcData, srcData.length + 1 + byteNum);
773 System.arraycopy(data, 0, data, 1 + byteNum, srcData.length);
774 data[0] = (byte) (OFFSET_LONG_ITEM + byteNum);
775 System.arraycopy(lenBytes, 0, data, 1, lenBytes.length);
776
777 return data;
778 }
779 }
780
781 public static byte[] encodeListHeader(int size) {
782
783 if (size == 0) {
784 return new byte[]{(byte) OFFSET_SHORT_LIST};
785 }
786
787 int totalLength = size;
788
789 byte[] header;
790 if (totalLength < SIZE_THRESHOLD) {
791
792 header = new byte[1];
793 header[0] = (byte) (OFFSET_SHORT_LIST + totalLength);
794 } else {
795 // length of length = BX
796 // prefix = [BX, [length]]
797 int tmpLength = totalLength;
798 byte byteNum = 0;
799 while (tmpLength != 0) {
800 ++byteNum;
801 tmpLength = tmpLength >> 8;
802 }
803 tmpLength = totalLength;
804
805 byte[] lenBytes = new byte[byteNum];
806 for (int i = 0; i < byteNum; ++i) {
807 lenBytes[byteNum - 1 - i] = (byte) ((tmpLength >> (8 * i)) & 0xFF);
808 }
809 // first byte = F7 + bytes.length
810 header = new byte[1 + lenBytes.length];
811 header[0] = (byte) (OFFSET_LONG_LIST + byteNum);
812 System.arraycopy(lenBytes, 0, header, 1, lenBytes.length);
813
814 }
815
816 return header;
817 }
818
819 public static byte[] encodeSet(Set<ByteArrayWrapper> data) {
820
821 int dataLength = 0;
822 Set<byte[]> encodedElements = new HashSet<>();
823 for (ByteArrayWrapper element : data) {
824
825 byte[] encodedElement = RLP.encodeElement(element.getData());
826 dataLength += encodedElement.length;
827 encodedElements.add(encodedElement);
828 }
829
830 byte[] listHeader = encodeListHeader(dataLength);
831
832 byte[] output = new byte[listHeader.length + dataLength];
833
834 System.arraycopy(listHeader, 0, output, 0, listHeader.length);
835
836 int cummStart = listHeader.length;
837 for (byte[] element : encodedElements) {
838 System.arraycopy(element, 0, output, cummStart, element.length);
839 cummStart += element.length;
840 }
841
842 return output;
843 }
844
845 public static byte[] encodeList(byte[]... elements) {
846
847 if (elements == null) {
848 return new byte[]{(byte) OFFSET_SHORT_LIST};
849 }
850
851 int totalLength = 0;
852 for (byte[] element1 : elements) {
853 totalLength += element1.length;
854 }
855
856 byte[] data;
857 int copyPos;
858 if (totalLength < SIZE_THRESHOLD) {
859
860 data = new byte[1 + totalLength];
861 data[0] = (byte) (OFFSET_SHORT_LIST + totalLength);
862 copyPos = 1;
863 } else {
864 // length of length = BX
865 // prefix = [BX, [length]]
866 int tmpLength = totalLength;
867 byte byteNum = 0;
868 while (tmpLength != 0) {
869 ++byteNum;
870 tmpLength = tmpLength >> 8;
871 }
872 tmpLength = totalLength;
873 byte[] lenBytes = new byte[byteNum];
874 for (int i = 0; i < byteNum; ++i) {
875 lenBytes[byteNum - 1 - i] = (byte) ((tmpLength >> (8 * i)) & 0xFF);
876 }
877 // first byte = F7 + bytes.length
878 data = new byte[1 + lenBytes.length + totalLength];
879 data[0] = (byte) (OFFSET_LONG_LIST + byteNum);
880 System.arraycopy(lenBytes, 0, data, 1, lenBytes.length);
881
882 copyPos = lenBytes.length + 1;
883 }
884 for (byte[] element : elements) {
885 System.arraycopy(element, 0, data, copyPos, element.length);
886 copyPos += element.length;
887 }
888 return data;
889 }
890
891 /*
892 * Utility function to convert Objects into byte arrays
893 */
894 private static byte[] toBytes(Object input) {
895 if (input instanceof byte[]) {
896 return (byte[]) input;
897 } else if (input instanceof String) {
898 String inputString = (String) input;
899 return inputString.getBytes(StandardCharsets.UTF_8);
900 } else if (input instanceof Long) {
901 Long inputLong = (Long) input;
902 return (inputLong == 0) ? ByteUtil.EMPTY_BYTE_ARRAY : asUnsignedByteArray(BigInteger.valueOf(inputLong));
903 } else if (input instanceof Integer) {
904 Integer inputInt = (Integer) input;
905 return (inputInt == 0) ? ByteUtil.EMPTY_BYTE_ARRAY : asUnsignedByteArray(BigInteger.valueOf(inputInt));
906 } else if (input instanceof BigInteger) {
907 BigInteger inputBigInt = (BigInteger) input;
908 return (inputBigInt.equals(BigInteger.ZERO)) ? ByteUtil.EMPTY_BYTE_ARRAY : asUnsignedByteArray(inputBigInt);
909 } else if (input instanceof Value) {
910 Value val = (Value) input;
911 return toBytes(val.asObj());
912 }
913 throw new RuntimeException("Unsupported type: Only accepting String, Integer and BigInteger for now");
914 }
915
916 /**
917 * An encoded empty list
918 */
919 public static byte[] encodedEmptyList() {
920 return new byte[] {(byte) OFFSET_SHORT_LIST};
921 }
922
923 /**
924 * An encoded empty byte array
925 */
926 public static byte[] encodedEmptyByteArray() {
927 return new byte[] {(byte) OFFSET_SHORT_ITEM};
928 }
929 }