11package org .arkecosystem .crypto .transactions ;
22
33import java .math .BigInteger ;
4- import java .nio .ByteBuffer ;
5- import java .nio .ByteOrder ;
4+ import java .util .List ;
65import java .util .Map ;
6+ import org .arkecosystem .crypto .configuration .Network ;
77import org .arkecosystem .crypto .encoding .Hex ;
88import org .arkecosystem .crypto .enums .AbiFunction ;
99import org .arkecosystem .crypto .transactions .types .*;
1010import org .arkecosystem .crypto .utils .AbiDecoder ;
11+ import org .arkecosystem .crypto .utils .RlpDecoder ;
1112
1213public class Deserializer {
13- private static final int SIGNATURE_SIZE = 64 ;
14- private static final int RECOVERY_SIZE = 1 ;
1514
16- private final ByteBuffer buffer ;
15+ private final byte [] rawBytes ;
1716
1817 public Deserializer (String serialized ) {
19- byte [] bytes = serialized .contains ("\0 " ) ? serialized .getBytes () : Hex .decode (serialized );
20- this .buffer = ByteBuffer .wrap (bytes );
21- this .buffer .order (ByteOrder .LITTLE_ENDIAN );
18+ this .rawBytes = Hex .decode (serialized );
2219 }
2320
2421 public static Deserializer newDeserializer (String serialized ) {
2522 return new Deserializer (serialized );
2623 }
2724
2825 public AbstractTransaction deserialize () {
29- int startPosition = buffer .position ();
26+ List <byte []> fields = RlpDecoder .decode (rawBytes );
27+
28+ // Fields: [nonce, gasPrice, gasLimit, to, value, data, v, r, s]
29+ long nonce = bytesToLong (fields .get (0 ));
30+ long gasPrice = bytesToLong (fields .get (1 ));
31+ long gasLimit = bytesToLong (fields .get (2 ));
32+ String recipientAddress = fields .get (3 ).length > 0 ? "0x" + Hex .encode (fields .get (3 )) : "" ;
33+ String value = fields .get (4 ).length > 0 ? new BigInteger (1 , fields .get (4 )).toString () : "0" ;
34+ String data = fields .get (5 ).length > 0 ? Hex .encode (fields .get (5 )) : "" ;
35+
36+ // Recover signature
37+ String signature = null ;
38+ if (fields .size () >= 9 ) {
39+ int vEncoded =
40+ fields .get (6 ).length > 0 ? new BigInteger (1 , fields .get (6 )).intValue () : 0 ;
41+ byte [] r = fields .get (7 );
42+ byte [] s = fields .get (8 );
43+
44+ int chainId = Network .get ().chainId ();
45+ int v = vEncoded - (chainId * 2 + 35 );
46+
47+ if (r .length > 0 || s .length > 0 ) {
48+ byte [] rPadded = padTo32 (r );
49+ byte [] sPadded = padTo32 (s );
50+ byte [] sigBytes = new byte [65 ];
51+ System .arraycopy (rPadded , 0 , sigBytes , 0 , 32 );
52+ System .arraycopy (sPadded , 0 , sigBytes , 32 , 32 );
53+ sigBytes [64 ] = (byte ) v ;
54+ signature = Hex .encode (sigBytes );
55+ }
56+ }
3057
58+ // Create temp transaction to guess type
3159 AbstractTransaction tempTransaction = new EvmCall ();
32- deserializeCommon (tempTransaction );
33- deserializeData (tempTransaction );
60+ tempTransaction .nonce = nonce ;
61+ tempTransaction .gasPrice = gasPrice ;
62+ tempTransaction .gasLimit = gasLimit ;
63+ tempTransaction .recipientAddress = recipientAddress ;
64+ tempTransaction .value = value ;
65+ tempTransaction .data = data ;
66+ tempTransaction .network = Network .get ().version ();
3467
3568 AbstractTransaction transaction = guessTransactionFromTransactionData (tempTransaction );
36-
37- buffer .position (startPosition );
38-
39- deserializeCommon (transaction );
40- deserializeData (transaction );
41- deserializeSignatures (transaction );
42-
43- transaction .recoverSender ();
69+ transaction .nonce = nonce ;
70+ transaction .gasPrice = gasPrice ;
71+ transaction .gasLimit = gasLimit ;
72+ transaction .recipientAddress = recipientAddress ;
73+ transaction .value = value ;
74+ transaction .data = data ;
75+ transaction .network = Network .get ().version ();
76+ transaction .signature = signature ;
77+
78+ if (signature != null ) {
79+ transaction .recoverSender ();
80+ }
4481
4582 transaction .computeId ();
4683
@@ -49,7 +86,7 @@ public AbstractTransaction deserialize() {
4986
5087 private AbstractTransaction guessTransactionFromTransactionData (
5188 AbstractTransaction transactionData ) {
52- if (!"0" .equals (transactionData .value )) {
89+ if (!"0" .equals (transactionData .value ) && ! "" . equals ( transactionData . value ) ) {
5390 return new Transfer ();
5491 }
5592
@@ -87,41 +124,15 @@ private Map<String, Object> decodePayload(AbstractTransaction transaction) {
87124 }
88125 }
89126
90- private void deserializeCommon (AbstractTransaction transaction ) {
91- transaction .network = Byte .toUnsignedInt (buffer .get ());
92- transaction .nonce = buffer .getLong ();
93- transaction .gasPrice = buffer .getInt ();
94- transaction .gasLimit = buffer .getInt ();
95- }
96-
97- private void deserializeData (AbstractTransaction transaction ) {
98- byte [] valueBytes = new byte [32 ];
99- buffer .get (valueBytes );
100- transaction .value = new BigInteger (1 , valueBytes ).toString ();
101-
102- int recipientMarker = Byte .toUnsignedInt (buffer .get ());
103- if (recipientMarker == 1 ) {
104- byte [] recipientBytes = new byte [20 ];
105- buffer .get (recipientBytes );
106- transaction .recipientAddress = "0x" + Hex .encode (recipientBytes );
107- }
108-
109- int payloadLength = buffer .getInt ();
110- if (payloadLength > 0 ) {
111- byte [] payloadBytes = new byte [payloadLength ];
112- buffer .get (payloadBytes );
113- transaction .data = Hex .encode (payloadBytes );
114- } else {
115- transaction .data = "" ;
116- }
127+ private static long bytesToLong (byte [] bytes ) {
128+ if (bytes .length == 0 ) return 0 ;
129+ return new BigInteger (1 , bytes ).longValue ();
117130 }
118131
119- private void deserializeSignatures (AbstractTransaction transaction ) {
120- int signatureLength = SIGNATURE_SIZE + RECOVERY_SIZE ;
121- if (buffer .remaining () >= signatureLength ) {
122- byte [] signatureBytes = new byte [signatureLength ];
123- buffer .get (signatureBytes );
124- transaction .signature = Hex .encode (signatureBytes );
125- }
132+ private static byte [] padTo32 (byte [] input ) {
133+ if (input .length >= 32 ) return input ;
134+ byte [] padded = new byte [32 ];
135+ System .arraycopy (input , 0 , padded , 32 - input .length , input .length );
136+ return padded ;
126137 }
127138}
0 commit comments