From 47d4bf4bf6922e7a1848b995c38db731a0fc8e1d Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Thu, 8 May 2025 17:56:48 +0400 Subject: [PATCH 1/7] common: add public method to check for valid hex string --- common/hexutil/hexutil.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index 81e6804650..a8aa2a6456 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -185,6 +185,31 @@ func EncodeBig(bigint *big.Int) string { } } +// Add more comprehensive check to validate a hex string +func IsValidHexString(input string) bool { + if !has0xPrefix(input) { + return false + } + + hexPart := input[2:] + if len(hexPart) == 0 { + return false + } + + for _, c := range hexPart { + if !isHexChar(c) { + return false + } + } + return true +} + +func isHexChar(c rune) bool { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F') +} + func has0xPrefix(input string) bool { return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') } From 8d0e24b2e2d4a3919bdd3fefebc34bc885d8e060 Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Thu, 8 May 2025 17:57:46 +0400 Subject: [PATCH 2/7] api: accept both hex and decimal for block number --- rpc/types.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/rpc/types.go b/rpc/types.go index f7e8e4b867..28395a5125 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math" + "strconv" "strings" "github.com/XinFinOrg/XDPoSChain/common" @@ -99,10 +100,21 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { return nil } - blckNum, err := hexutil.DecodeUint64(input) + var blckNum uint64 + var err error + + //Check if input is valid hex string before converting. + if hexutil.IsValidHexString(input) { + blckNum, err = hexutil.DecodeUint64(input) + } else { + //Try converting input directly into uint64 value + blckNum, err = strconv.ParseUint(input, 10, 64) + } + if err != nil { return err } + if blckNum > math.MaxInt64 { return errors.New("block number larger than int64") } From 78e82ac8a9998b84a4392de9dcbf8041f27d6dbf Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Fri, 9 May 2025 14:32:01 +0400 Subject: [PATCH 3/7] test: updated test cases to cover hex and number support for XDPoS_getV2BlockByNumber --- common/hexutil/hexutil.go | 1 - common/hexutil/hexutil_test.go | 20 ++++++++++++++++++++ rpc/types_test.go | 20 ++++++++++---------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index a8aa2a6456..ca8a4ae0ef 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -185,7 +185,6 @@ func EncodeBig(bigint *big.Int) string { } } -// Add more comprehensive check to validate a hex string func IsValidHexString(input string) bool { if !has0xPrefix(input) { return false diff --git a/common/hexutil/hexutil_test.go b/common/hexutil/hexutil_test.go index f2b800d82c..5c89fa8c9d 100644 --- a/common/hexutil/hexutil_test.go +++ b/common/hexutil/hexutil_test.go @@ -22,6 +22,11 @@ import ( "testing" ) +type hexValidityTest struct { + input string + want bool +} + type marshalTest struct { input interface{} want string @@ -134,6 +139,12 @@ var ( {input: `0xbbb`, want: uint64(0xbbb)}, {input: `0xffffffffffffffff`, want: uint64(0xffffffffffffffff)}, } + + hexStringValidityTest = []hexValidityTest{ + {"0x", false}, + {"asdcc", false}, + {"0x00000102", true}, + } ) func TestEncode(t *testing.T) { @@ -202,6 +213,15 @@ func TestDecodeUint64(t *testing.T) { } } +func TestIsValidHexString(t *testing.T) { + for _, test := range hexStringValidityTest { + actual := IsValidHexString(test.input) + if actual != test.want { + t.Errorf("input %s: value mismatch: got %t, want %t", test.input, actual, test.want) + } + } +} + func BenchmarkEncodeBig(b *testing.B) { for _, bench := range encodeBigTests { b.Run(bench.want, func(b *testing.B) { diff --git a/rpc/types_test.go b/rpc/types_test.go index e48db859d4..2a895886b8 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -42,16 +42,16 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 6: {`"0x12"`, false, BlockNumber(18)}, 7: {`"0x7fffffffffffffff"`, false, BlockNumber(math.MaxInt64)}, 8: {`"0x8000000000000000"`, true, BlockNumber(0)}, - 9: {"0", true, BlockNumber(0)}, - 10: {`"ff"`, true, BlockNumber(0)}, - 11: {`"pending"`, false, PendingBlockNumber}, - 12: {`"latest"`, false, LatestBlockNumber}, - 13: {`"earliest"`, false, EarliestBlockNumber}, - 14: {`"committed"`, false, CommittedBlockNumber}, - 15: {`"finalized"`, false, CommittedBlockNumber}, - 16: {`someString`, true, BlockNumber(0)}, - 17: {`""`, true, BlockNumber(0)}, - 18: {``, true, BlockNumber(0)}, + 9: {`"ff"`, true, BlockNumber(0)}, + 10: {`"pending"`, false, PendingBlockNumber}, + 11: {`"latest"`, false, LatestBlockNumber}, + 12: {`"earliest"`, false, EarliestBlockNumber}, + 13: {`"committed"`, false, CommittedBlockNumber}, + 14: {`"finalized"`, false, CommittedBlockNumber}, + 15: {`someString`, true, BlockNumber(0)}, + 16: {`""`, true, BlockNumber(0)}, + 17: {``, true, BlockNumber(0)}, + 18: {`88439993`, false, BlockNumber(88439993)}, } for i, test := range tests { From cccfefa6699822c981554951587b628b0ccbd389 Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Mon, 12 May 2025 17:34:01 +0400 Subject: [PATCH 4/7] test: adding test condition to mustFail=false in TestBlockNumberJSONUnmarshal for valid number input --- rpc/types.go | 2 +- rpc/types_test.go | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/rpc/types.go b/rpc/types.go index 28395a5125..f2031a883a 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -107,7 +107,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { if hexutil.IsValidHexString(input) { blckNum, err = hexutil.DecodeUint64(input) } else { - //Try converting input directly into uint64 value + //Else try converting input directly into uint64 value blckNum, err = strconv.ParseUint(input, 10, 64) } diff --git a/rpc/types_test.go b/rpc/types_test.go index 2a895886b8..8ff021578f 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -42,16 +42,17 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 6: {`"0x12"`, false, BlockNumber(18)}, 7: {`"0x7fffffffffffffff"`, false, BlockNumber(math.MaxInt64)}, 8: {`"0x8000000000000000"`, true, BlockNumber(0)}, - 9: {`"ff"`, true, BlockNumber(0)}, - 10: {`"pending"`, false, PendingBlockNumber}, - 11: {`"latest"`, false, LatestBlockNumber}, - 12: {`"earliest"`, false, EarliestBlockNumber}, - 13: {`"committed"`, false, CommittedBlockNumber}, - 14: {`"finalized"`, false, CommittedBlockNumber}, - 15: {`someString`, true, BlockNumber(0)}, - 16: {`""`, true, BlockNumber(0)}, - 17: {``, true, BlockNumber(0)}, - 18: {`88439993`, false, BlockNumber(88439993)}, + 9: {"0", false, BlockNumber(0)}, + 10: {`"ff"`, true, BlockNumber(0)}, + 11: {`"pending"`, false, PendingBlockNumber}, + 12: {`"latest"`, false, LatestBlockNumber}, + 13: {`"earliest"`, false, EarliestBlockNumber}, + 14: {`"committed"`, false, CommittedBlockNumber}, + 15: {`"finalized"`, false, CommittedBlockNumber}, + 16: {`someString`, true, BlockNumber(0)}, + 17: {`""`, true, BlockNumber(0)}, + 18: {``, true, BlockNumber(0)}, + 19: {`88439993`, false, BlockNumber(88439993)}, } for i, test := range tests { From 46a301a52849343bf6a7f4256fbd23019aa28289 Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Fri, 16 May 2025 10:36:36 +0400 Subject: [PATCH 5/7] test: added more table test data for TestBlockNumberJSONUnmarshal --- rpc/types_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpc/types_test.go b/rpc/types_test.go index 8ff021578f..deb761fe2c 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -53,6 +53,10 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 17: {`""`, true, BlockNumber(0)}, 18: {``, true, BlockNumber(0)}, 19: {`88439993`, false, BlockNumber(88439993)}, + 20: {`-1`, true, BlockNumber(0)}, + 21: {`MaxInt64`, true, BlockNumber(0)}, + 22: {`MinInt64`, true, BlockNumber(0)}, + 23: {`MaxUint64`, true, BlockNumber(0)}, } for i, test := range tests { From 631be3cc0421d5df2a625c15f591682c4ce53004 Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Fri, 16 May 2025 12:33:25 +0400 Subject: [PATCH 6/7] refactor: Removed IsValidHexString and make has0xPrefix as public as per review comment --- common/hexutil/hexutil.go | 30 +++--------------------------- rpc/types.go | 2 +- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index ca8a4ae0ef..7b62045328 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -60,7 +60,7 @@ func Decode(input string) ([]byte, error) { if len(input) == 0 { return nil, ErrEmptyString } - if !has0xPrefix(input) { + if !Has0xPrefix(input) { return nil, ErrMissingPrefix } b, err := hex.DecodeString(input[2:]) @@ -185,31 +185,7 @@ func EncodeBig(bigint *big.Int) string { } } -func IsValidHexString(input string) bool { - if !has0xPrefix(input) { - return false - } - - hexPart := input[2:] - if len(hexPart) == 0 { - return false - } - - for _, c := range hexPart { - if !isHexChar(c) { - return false - } - } - return true -} - -func isHexChar(c rune) bool { - return ('0' <= c && c <= '9') || - ('a' <= c && c <= 'f') || - ('A' <= c && c <= 'F') -} - -func has0xPrefix(input string) bool { +func Has0xPrefix(input string) bool { return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') } @@ -217,7 +193,7 @@ func checkNumber(input string) (raw string, err error) { if len(input) == 0 { return "", ErrEmptyString } - if !has0xPrefix(input) { + if !Has0xPrefix(input) { return "", ErrMissingPrefix } input = input[2:] diff --git a/rpc/types.go b/rpc/types.go index f2031a883a..62384c8264 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -104,7 +104,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { var err error //Check if input is valid hex string before converting. - if hexutil.IsValidHexString(input) { + if hexutil.Has0xPrefix(input) { blckNum, err = hexutil.DecodeUint64(input) } else { //Else try converting input directly into uint64 value From c14f2e17aa2baf08856b4b5c29a269de28d55331 Mon Sep 17 00:00:00 2001 From: Tarun Sharma Date: Fri, 16 May 2025 12:55:45 +0400 Subject: [PATCH 7/7] test: Updated test cases to include MaxInt64, MinInt64 and MaxUint64, also rename testcase to TestHas0xPrefix to cover Has0xPrefix public method in hexutil package --- common/hexutil/hexutil_test.go | 6 +++--- rpc/types_test.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/hexutil/hexutil_test.go b/common/hexutil/hexutil_test.go index 5c89fa8c9d..24dce185e7 100644 --- a/common/hexutil/hexutil_test.go +++ b/common/hexutil/hexutil_test.go @@ -141,7 +141,7 @@ var ( } hexStringValidityTest = []hexValidityTest{ - {"0x", false}, + {"0x", true}, {"asdcc", false}, {"0x00000102", true}, } @@ -213,9 +213,9 @@ func TestDecodeUint64(t *testing.T) { } } -func TestIsValidHexString(t *testing.T) { +func TestHas0xPrefix(t *testing.T) { for _, test := range hexStringValidityTest { - actual := IsValidHexString(test.input) + actual := Has0xPrefix(test.input) if actual != test.want { t.Errorf("input %s: value mismatch: got %t, want %t", test.input, actual, test.want) } diff --git a/rpc/types_test.go b/rpc/types_test.go index deb761fe2c..5ace764f22 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -54,9 +54,9 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 18: {``, true, BlockNumber(0)}, 19: {`88439993`, false, BlockNumber(88439993)}, 20: {`-1`, true, BlockNumber(0)}, - 21: {`MaxInt64`, true, BlockNumber(0)}, - 22: {`MinInt64`, true, BlockNumber(0)}, - 23: {`MaxUint64`, true, BlockNumber(0)}, + 21: {`9223372036854775807`, false, BlockNumber(9223372036854775807)}, + 22: {`-9223372036854775808`, true, BlockNumber(0)}, + 23: {`18446744073709551615`, true, BlockNumber(0)}, } for i, test := range tests {