55import java .util .LinkedList ;
66import java .util .List ;
77import java .util .Map ;
8+ import org .bouncycastle .crypto .OutputLengthException ;
89import org .bouncycastle .util .Arrays ;
910import org .junit .Assert ;
1011import org .junit .Test ;
@@ -100,6 +101,91 @@ public synchronized void testEventParser() {
100101
101102 }
102103
104+ @ Test
105+ public void testParseDataBytesIntegerTypes () {
106+ // uint256 = 255
107+ byte [] uintData = ByteArray .fromHexString (
108+ "00000000000000000000000000000000000000000000000000000000000000ff" );
109+ Assert .assertEquals ("255" , ContractEventParser .parseDataBytes (uintData , "uint256" , 0 ));
110+
111+ // int256 = -1 (two's complement 0xFF..FF is signed negative one)
112+ byte [] negIntData = ByteArray .fromHexString (
113+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" );
114+ Assert .assertEquals ("-1" , ContractEventParser .parseDataBytes (negIntData , "int256" , 0 ));
115+
116+ // trcToken is classified as INT_NUMBER
117+ byte [] tokenData = ByteArray .fromHexString (
118+ "0000000000000000000000000000000000000000000000000000000000000064" );
119+ Assert .assertEquals ("100" , ContractEventParser .parseDataBytes (tokenData , "trcToken" , 0 ));
120+ }
121+
122+ @ Test
123+ public void testParseDataBytesBool () {
124+ byte [] trueData = ByteArray .fromHexString (
125+ "0000000000000000000000000000000000000000000000000000000000000001" );
126+ Assert .assertEquals ("true" , ContractEventParser .parseDataBytes (trueData , "bool" , 0 ));
127+
128+ byte [] falseData = ByteArray .fromHexString (
129+ "0000000000000000000000000000000000000000000000000000000000000000" );
130+ Assert .assertEquals ("false" , ContractEventParser .parseDataBytes (falseData , "bool" , 0 ));
131+ }
132+
133+ @ Test
134+ public void testParseDataBytesFixedBytes () {
135+ String hex = "1234567890abcdef0000000000000000000000000000000000000000000000ff" ;
136+ byte [] data = ByteArray .fromHexString (hex );
137+ Assert .assertEquals (hex , ContractEventParser .parseDataBytes (data , "bytes32" , 0 ));
138+ }
139+
140+ @ Test
141+ public void testParseDataBytesAddress () {
142+ Wallet .setAddressPreFixByte (ADD_PRE_FIX_BYTE_MAINNET );
143+ // last 20 bytes = ca35...733c => Base58Check = TUQPrDEJkV4ttkrL7cVv1p3mikWYfM7LWt
144+ byte [] data = ByteArray .fromHexString (
145+ "000000000000000000000000ca35b7d915458ef540ade6068dfe2f44e8fa733c" );
146+ Assert .assertEquals ("TUQPrDEJkV4ttkrL7cVv1p3mikWYfM7LWt" ,
147+ ContractEventParser .parseDataBytes (data , "address" , 0 ));
148+ }
149+
150+ @ Test
151+ public void testParseDataBytesDynamicBytes () {
152+ // offset 0x20 | length 3 | 0x010203 padded to 32 bytes
153+ byte [] data = ByteArray .fromHexString (
154+ "0000000000000000000000000000000000000000000000000000000000000020"
155+ + "0000000000000000000000000000000000000000000000000000000000000003"
156+ + "0102030000000000000000000000000000000000000000000000000000000000" );
157+ Assert .assertEquals ("010203" , ContractEventParser .parseDataBytes (data , "bytes" , 0 ));
158+ }
159+
160+ @ Test
161+ public void testParseDataBytesEmptyString () {
162+ // offset 0x20 | length 0
163+ byte [] data = ByteArray .fromHexString (
164+ "0000000000000000000000000000000000000000000000000000000000000020"
165+ + "0000000000000000000000000000000000000000000000000000000000000000" );
166+ Assert .assertEquals ("" , ContractEventParser .parseDataBytes (data , "string" , 0 ));
167+ }
168+
169+ @ Test
170+ public void testParseDataBytesNonEmptyString () {
171+ // "hello world" is 11 ASCII bytes (68656c6c6f20776f726c64), padded to 32 bytes.
172+ byte [] data = ByteArray .fromHexString (
173+ "0000000000000000000000000000000000000000000000000000000000000020"
174+ + "000000000000000000000000000000000000000000000000000000000000000b"
175+ + "68656c6c6f20776f726c64000000000000000000000000000000000000000000" );
176+ Assert .assertEquals ("hello world" , ContractEventParser .parseDataBytes (data , "string" , 0 ));
177+ }
178+
179+ @ Test
180+ public void testParseDataBytesMultiByteUtf8String () {
181+ // "中文" UTF-8 = e4b8ad e69687 (6 bytes), padded to 32 bytes.
182+ byte [] data = ByteArray .fromHexString (
183+ "0000000000000000000000000000000000000000000000000000000000000020"
184+ + "0000000000000000000000000000000000000000000000000000000000000006"
185+ + "e4b8ade696870000000000000000000000000000000000000000000000000000" );
186+ Assert .assertEquals ("中文" , ContractEventParser .parseDataBytes (data , "string" , 0 ));
187+ }
188+
103189 @ Test
104190 public void testParseRevert () {
105191 String dataHex = "08c379a0"
@@ -113,4 +199,87 @@ public void testParseRevert() {
113199 Assert .assertEquals (msg , "not enough input value" );
114200
115201 }
202+
203+ @ Test
204+ public void testSubBytesRejectsOversizedLength () {
205+ // Length must fit in the available source bytes. Reject instead of
206+ // truncating so oversized ABI lengths are not silently coerced.
207+ byte [] src = new byte []{1 , 2 , 3 };
208+ try {
209+ ContractEventParser .subBytes (src , 0 , Integer .MAX_VALUE );
210+ Assert .fail ("Expected OutputLengthException" );
211+ } catch (OutputLengthException e ) {
212+ Assert .assertTrue (e .getMessage ().contains ("data start:0" ));
213+ Assert .assertTrue (e .getMessage ().contains ("length:2147483647" ));
214+ Assert .assertTrue (e .getMessage ().contains ("src.length:3" ));
215+ }
216+ }
217+
218+ @ Test
219+ public void testSubBytesAcceptsExactLength () {
220+ byte [] src = new byte []{1 , 2 , 3 , 4 };
221+ byte [] result = ContractEventParser .subBytes (src , 1 , 3 );
222+ Assert .assertArrayEquals (new byte []{2 , 3 , 4 }, result );
223+ }
224+
225+ @ Test
226+ public void testSubBytesRejectsNegativeOffset () {
227+ // ABI offsets are unsigned, but BigInteger(byte[]) interprets 0xFF..FF as
228+ // -1. The guard should reject that value before System.arraycopy runs.
229+ byte [] src = new byte []{1 , 2 , 3 , 4 };
230+ try {
231+ ContractEventParser .subBytes (src , -1 , 3 );
232+ Assert .fail ("Expected OutputLengthException" );
233+ } catch (OutputLengthException e ) {
234+ Assert .assertTrue (e .getMessage ().contains ("data start:-1" ));
235+ Assert .assertTrue (e .getMessage ().contains ("length:3" ));
236+ Assert .assertTrue (e .getMessage ().contains ("src.length:4" ));
237+ }
238+ }
239+
240+ @ Test
241+ public void testSubBytesRejectsEmptySource () {
242+ try {
243+ ContractEventParser .subBytes (new byte [0 ], 0 , 0 );
244+ Assert .fail ("Expected OutputLengthException" );
245+ } catch (OutputLengthException e ) {
246+ Assert .assertTrue (e .getMessage ().contains ("source data is empty" ));
247+ }
248+ }
249+
250+ @ Test (expected = UnsupportedOperationException .class )
251+ public void testParseDataBytesRejectsNegativeOffset () {
252+ // End-to-end check: an offset field of 0xFF..FF decodes to -1 and should
253+ // be rejected through the existing UnsupportedOperationException path.
254+ String dataHex = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
255+ + "0000000000000000000000000000000000000000000000000000000000000003"
256+ + "414243" ;
257+ byte [] data = ByteArray .fromHexString (dataHex );
258+
259+ ContractEventParser .parseDataBytes (data , "string" , 0 );
260+ }
261+
262+ @ Test (expected = UnsupportedOperationException .class )
263+ public void testParseDataBytesRejectsMalformedLength () {
264+ // ABI-encoded "string" whose declared length exceeds the available payload
265+ // should be rejected via the existing UnsupportedOperationException path.
266+ String dataHex = "0000000000000000000000000000000000000000000000000000000000000020"
267+ + "000000000000000000000000000000000000000000000000000000007fffffff"
268+ + "414243" ;
269+ byte [] data = ByteArray .fromHexString (dataHex );
270+
271+ ContractEventParser .parseDataBytes (data , "string" , 0 );
272+ }
273+
274+ @ Test (expected = UnsupportedOperationException .class )
275+ public void testParseDataBytesRejectsNegativeLength () {
276+ // ABI length is an unsigned word. If 0xFF..FF is decoded as -1, reject it
277+ // instead of treating it as an empty string/bytes payload.
278+ String dataHex = "0000000000000000000000000000000000000000000000000000000000000020"
279+ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
280+ + "414243" ;
281+ byte [] data = ByteArray .fromHexString (dataHex );
282+
283+ ContractEventParser .parseDataBytes (data , "string" , 0 );
284+ }
116285}
0 commit comments