diff --git a/venus-shared/actors/types/eth.go b/venus-shared/actors/types/eth.go index 53355a1e3a..3eca1272d0 100644 --- a/venus-shared/actors/types/eth.go +++ b/venus-shared/actors/types/eth.go @@ -1054,6 +1054,16 @@ func (e *EthBlockNumberOrHash) UnmarshalJSON(b []byte) error { return nil } + // check if input is a block hash (66 characters long) + if len(str) == 66 && strings.HasPrefix(str, "0x") { + hash, err := ParseEthHash(str) + if err != nil { + return err + } + e.BlockHash = &hash + return nil + } + return errors.New("invalid block param") } diff --git a/venus-shared/actors/types/eth_test.go b/venus-shared/actors/types/eth_test.go index 959590fb3f..aa4a4959f0 100644 --- a/venus-shared/actors/types/eth_test.go +++ b/venus-shared/actors/types/eth_test.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "fmt" "strings" "testing" @@ -467,3 +468,104 @@ func BenchmarkEthHashFromCid(b *testing.B) { } } } + +func TestEthBlockNumberOrHashUnmarshalJSON(t *testing.T) { + testCases := []struct { + name string + input string + expected func() EthBlockNumberOrHash + wantErr bool + }{ + { + name: "Valid block number", + input: `{"blockNumber": "0x1234"}`, + expected: func() EthBlockNumberOrHash { + v := uint64(0x1234) + return EthBlockNumberOrHash{BlockNumber: (*EthUint64)(&v)} + }, + }, + { + name: "Valid block hash", + input: `{"blockHash": "0x1234567890123456789012345678901234567890123456789012345678901234"}`, + expected: func() EthBlockNumberOrHash { + h, _ := ParseEthHash("0x1234567890123456789012345678901234567890123456789012345678901234") + return EthBlockNumberOrHash{BlockHash: &h} + }, + }, + { + name: "Valid block number as string", + input: `"0x1234"`, + expected: func() EthBlockNumberOrHash { + v := uint64(0x1234) + return EthBlockNumberOrHash{BlockNumber: (*EthUint64)(&v)} + }, + }, + { + name: "Valid block hash as string", + input: `"0x1234567890123456789012345678901234567890123456789012345678901234"`, + expected: func() EthBlockNumberOrHash { + h, _ := ParseEthHash("0x1234567890123456789012345678901234567890123456789012345678901234") + return EthBlockNumberOrHash{BlockHash: &h} + }, + }, + { + name: "Valid 'latest' string", + input: `"latest"`, + expected: func() EthBlockNumberOrHash { + return EthBlockNumberOrHash{PredefinedBlock: stringPtr("latest")} + }, + }, + { + name: "Valid 'earliest' string", + input: `"earliest"`, + expected: func() EthBlockNumberOrHash { + return EthBlockNumberOrHash{PredefinedBlock: stringPtr("earliest")} + }, + }, + { + name: "Valid 'pending' string", + input: `"pending"`, + expected: func() EthBlockNumberOrHash { + return EthBlockNumberOrHash{PredefinedBlock: stringPtr("pending")} + }, + }, + { + name: "Invalid: both block number and hash", + input: `{"blockNumber": "0x1234", "blockHash": "0x1234567890123456789012345678901234567890123456789012345678901234"}`, + wantErr: true, + }, + { + name: "Invalid block number", + input: `{"blockNumber": "invalid"}`, + wantErr: true, + }, + { + name: "Invalid block hash", + input: `{"blockHash": "invalid"}`, + wantErr: true, + }, + { + name: "Invalid string", + input: `"invalid"`, + wantErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var got EthBlockNumberOrHash + err := got.UnmarshalJSON([]byte(tc.input)) + + if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err, fmt.Sprintf("did not expect error but got %s", err)) + require.Equal(t, tc.expected(), got) + } + }) + } +} + +func stringPtr(s string) *string { + return &s +}