Skip to content

Commit a437574

Browse files
committed
fix(api): validate block number range in parseBlockNumber
parseBlockNumber previously returned BigInteger, letting callers narrow with .longValue() and silently wrap past Long.MAX_VALUE. Return long directly and enforce two invariants at the API boundary so corrupted inputs never reach downstream block lookups: - signum check rejects negative inputs (both "-1" and "0x-1"), a protocol-level constraint block numbers can never violate - longValueExact rejects values that overflow signed 64-bit, including uint64 wraparounds like 0xffffffffffffffff Callers in Wallet and TronJsonRpcImpl drop the obsolete .longValue() call; the other three call sites already discarded the return value. Regression tests cover negatives, 0x7fffffffffffffff (max long), 0x8000000000000000 (just past), and 0xffffffffffffffff (uint64).
1 parent db91a72 commit a437574

4 files changed

Lines changed: 45 additions & 15 deletions

File tree

framework/src/main/java/org/tron/core/Wallet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ public Block getByJsonBlockId(String id) throws JsonRpcInvalidParamsException {
743743
} else if (PENDING_STR.equalsIgnoreCase(id)) {
744744
throw new JsonRpcInvalidParamsException(TAG_PENDING_SUPPORT_ERROR);
745745
} else {
746-
long blockNumber = parseBlockNumber(id).longValue();
746+
long blockNumber = parseBlockNumber(id);
747747
return getBlockByNum(blockNumber);
748748
}
749749
}

framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,19 +527,30 @@ public static long parseEnergyFee(long timestamp, String energyPriceHistory) {
527527
private static final String BLOCK_NUM_ERROR = "invalid block number";
528528

529529
/**
530-
* Parse a JSON-RPC block number (hex "0x..." or decimal) into a BigInteger,
531-
* enforcing the {@link #MAX_BLOCK_NUM_HEX_LEN} length limit.
530+
* Parse a JSON-RPC block number (hex "0x..." or decimal) into a long,
531+
* enforcing the {@link #MAX_BLOCK_NUM_HEX_LEN} length limit, rejecting
532+
* negative values, and rejecting values that overflow a signed 64-bit
533+
* block number.
532534
*/
533-
public static BigInteger parseBlockNumber(String blockNumOrTag)
535+
public static long parseBlockNumber(String blockNumOrTag)
534536
throws JsonRpcInvalidParamsException {
535537
if (blockNumOrTag == null || blockNumOrTag.length() > MAX_BLOCK_NUM_HEX_LEN) {
536538
throw new JsonRpcInvalidParamsException(BLOCK_NUM_ERROR);
537539
}
540+
BigInteger value;
538541
try {
539-
return ByteArray.hexToBigInteger(blockNumOrTag);
542+
value = ByteArray.hexToBigInteger(blockNumOrTag);
540543
} catch (Exception e) {
541544
throw new JsonRpcInvalidParamsException(BLOCK_NUM_ERROR);
542545
}
546+
if (value.signum() < 0) {
547+
throw new JsonRpcInvalidParamsException(BLOCK_NUM_ERROR);
548+
}
549+
try {
550+
return value.longValueExact();
551+
} catch (ArithmeticException e) {
552+
throw new JsonRpcInvalidParamsException(BLOCK_NUM_ERROR);
553+
}
543554
}
544555

545556
public static long getByJsonBlockId(String blockNumOrTag, Wallet wallet)

framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ public String getCall(CallArguments transactionCall, Object blockParamObj)
957957
throw new JsonRpcInvalidParamsException(JSON_ERROR);
958958
}
959959

960-
long blockNumber = parseBlockNumber(blockNumOrTag).longValue();
960+
long blockNumber = parseBlockNumber(blockNumOrTag);
961961

962962
if (wallet.getBlockByNum(blockNumber) == null) {
963963
throw new JsonRpcInternalException(NO_BLOCK_HEADER);

framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcApiUtilTest.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,48 @@
33
import static org.junit.Assert.assertEquals;
44
import static org.junit.Assert.assertThrows;
55

6-
import java.math.BigInteger;
76
import org.junit.Test;
87
import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException;
98

109
public class JsonRpcApiUtilTest {
1110

1211
@Test
1312
public void parseBlockNumberAcceptsHex() throws JsonRpcInvalidParamsException {
14-
assertEquals(BigInteger.valueOf(0x1a), JsonRpcApiUtil.parseBlockNumber("0x1a"));
15-
assertEquals(BigInteger.ZERO, JsonRpcApiUtil.parseBlockNumber("0x0"));
13+
assertEquals(0x1aL, JsonRpcApiUtil.parseBlockNumber("0x1a"));
14+
assertEquals(0L, JsonRpcApiUtil.parseBlockNumber("0x0"));
1615
}
1716

1817
@Test
1918
public void parseBlockNumberAcceptsDecimal() throws JsonRpcInvalidParamsException {
20-
assertEquals(BigInteger.valueOf(12345), JsonRpcApiUtil.parseBlockNumber("12345"));
19+
assertEquals(12345L, JsonRpcApiUtil.parseBlockNumber("12345"));
2120
}
2221

2322
@Test
24-
public void parseBlockNumberAcceptsMaxLength() throws JsonRpcInvalidParamsException {
25-
// 0x + 98 hex chars = 100 chars total, at the limit
26-
String maxValid = "0x" + new String(new char[98]).replace('\0', 'f');
27-
assertEquals(100, maxValid.length());
28-
JsonRpcApiUtil.parseBlockNumber(maxValid);
23+
public void parseBlockNumberAcceptsMaxLongValue() throws JsonRpcInvalidParamsException {
24+
assertEquals(Long.MAX_VALUE,
25+
JsonRpcApiUtil.parseBlockNumber("0x7fffffffffffffff"));
26+
}
27+
28+
@Test
29+
public void parseBlockNumberRejectsNegative() {
30+
JsonRpcInvalidParamsException e1 = assertThrows(JsonRpcInvalidParamsException.class,
31+
() -> JsonRpcApiUtil.parseBlockNumber("-1"));
32+
assertEquals("invalid block number", e1.getMessage());
33+
JsonRpcInvalidParamsException e2 = assertThrows(JsonRpcInvalidParamsException.class,
34+
() -> JsonRpcApiUtil.parseBlockNumber("0x-1"));
35+
assertEquals("invalid block number", e2.getMessage());
36+
}
37+
38+
@Test
39+
public void parseBlockNumberRejectsOverflow() {
40+
// 2^64 - 1: fits uint64 but overflows signed long
41+
JsonRpcInvalidParamsException e1 = assertThrows(JsonRpcInvalidParamsException.class,
42+
() -> JsonRpcApiUtil.parseBlockNumber("0xffffffffffffffff"));
43+
assertEquals("invalid block number", e1.getMessage());
44+
// 2^63: just past Long.MAX_VALUE
45+
JsonRpcInvalidParamsException e2 = assertThrows(JsonRpcInvalidParamsException.class,
46+
() -> JsonRpcApiUtil.parseBlockNumber("0x8000000000000000"));
47+
assertEquals("invalid block number", e2.getMessage());
2948
}
3049

3150
@Test

0 commit comments

Comments
 (0)