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 }