Recursive Length Prefix (RLP) encoder.
10 | * 11 | *For the specification, refer to p16 of the 12 | * yellow paper and here.
13 | */ 14 | public class RlpEncoder { 15 | 16 | private static final int STRING_OFFSET = 0x80; 17 | private static final int LIST_OFFSET = 0xc0; 18 | 19 | public static byte[] encode(RlpType value) { 20 | if (value instanceof RlpString) { 21 | return encodeString((RlpString) value); 22 | } else { 23 | return encodeList((RlpList) value); 24 | } 25 | } 26 | 27 | private static byte[] encode(byte[] bytesValue, int offset) { 28 | if (bytesValue.length == 1 29 | && offset == STRING_OFFSET 30 | && bytesValue[0] >= (byte) 0x00 31 | && bytesValue[0] <= (byte) 0x7f) { 32 | return bytesValue; 33 | } else if (bytesValue.length <= 55) { 34 | byte[] result = new byte[bytesValue.length + 1]; 35 | result[0] = (byte) (offset + bytesValue.length); 36 | System.arraycopy(bytesValue, 0, result, 1, bytesValue.length); 37 | return result; 38 | } else { 39 | byte[] encodedStringLength = toMinimalByteArray(bytesValue.length); 40 | byte[] result = new byte[bytesValue.length + encodedStringLength.length + 1]; 41 | 42 | result[0] = (byte) ((offset + 0x37) + encodedStringLength.length); 43 | System.arraycopy(encodedStringLength, 0, result, 1, encodedStringLength.length); 44 | System.arraycopy( 45 | bytesValue, 0, result, encodedStringLength.length + 1, bytesValue.length); 46 | return result; 47 | } 48 | } 49 | 50 | private static byte[] encodeString(RlpString value) { 51 | return encode(value.getBytes(), STRING_OFFSET); 52 | } 53 | 54 | private static byte[] toMinimalByteArray(int value) { 55 | byte[] encoded = toByteArray(value); 56 | 57 | for (int i = 0; i < encoded.length; i++) { 58 | if (encoded[i] != 0) { 59 | return Arrays.copyOfRange(encoded, i, encoded.length); 60 | } 61 | } 62 | 63 | return new byte[]{ }; 64 | } 65 | 66 | private static byte[] toByteArray(int value) { 67 | return new byte[] { 68 | (byte) ((value >> 24) & 0xff), 69 | (byte) ((value >> 16) & 0xff), 70 | (byte) ((value >> 8) & 0xff), 71 | (byte) (value & 0xff) 72 | }; 73 | } 74 | 75 | private static byte[] encodeList(RlpList value) { 76 | List21 | * yellow paper
. 22 | */ 23 | public class EthereumTransaction implements TransactionSigner { 24 | 25 | private BigInteger nonce; 26 | private BigInteger gasPrice; 27 | private BigInteger gasLimit; 28 | private String to; 29 | private BigInteger value; 30 | private String data; 31 | 32 | public EthereumTransaction(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, 33 | BigInteger value, String data) { 34 | this.nonce = nonce; 35 | this.gasPrice = gasPrice; 36 | this.gasLimit = gasLimit; 37 | this.to = to; 38 | this.value = value; 39 | 40 | if (data != null) { 41 | this.data = NumericUtil.cleanHexPrefix(data); 42 | } 43 | } 44 | 45 | public BigInteger getNonce() { 46 | return nonce; 47 | } 48 | 49 | public BigInteger getGasPrice() { 50 | return gasPrice; 51 | } 52 | 53 | public BigInteger getGasLimit() { 54 | return gasLimit; 55 | } 56 | 57 | public String getTo() { 58 | return to; 59 | } 60 | 61 | public BigInteger getValue() { 62 | return value; 63 | } 64 | 65 | public String getData() { 66 | return data; 67 | } 68 | 69 | @Override 70 | public TxSignResult signTransaction(String chainID, String password, Wallet wallet) { 71 | 72 | String signedTx = signTransaction(Integer.parseInt(chainID), wallet.decryptMainKey(password)); 73 | String txHash = this.calcTxHash(signedTx); 74 | return new TxSignResult(signedTx, txHash); 75 | } 76 | 77 | String signTransaction(int chainId, byte[] privateKey) { 78 | SignatureData signatureData = new SignatureData(chainId, new byte[]{}, new byte[]{}); 79 | byte[] encodedTransaction = encodeToRLP(signatureData); 80 | signatureData = EthereumSign.signMessage(encodedTransaction, privateKey); 81 | 82 | SignatureData eip155SignatureData = createEip155SignatureData(signatureData, chainId); 83 | byte[] rawSignedTx = encodeToRLP(eip155SignatureData); 84 | return NumericUtil.bytesToHex(rawSignedTx); 85 | } 86 | 87 | String calcTxHash(String signedTx) { 88 | return NumericUtil.prependHexPrefix(Hash.keccak256(signedTx)); 89 | } 90 | 91 | private static SignatureData createEip155SignatureData(SignatureData signatureData, int chainId) { 92 | int v = signatureData.getV() + (chainId * 2) + 8; 93 | 94 | return new SignatureData(v, signatureData.getR(), signatureData.getS()); 95 | } 96 | 97 | byte[] encodeToRLP(SignatureData signatureData) { 98 | List