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