From 9cbc2749b940bb7d6c441a178cec64b67e7ce782 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Wed, 21 Aug 2024 12:30:18 +0200 Subject: [PATCH] refactor some parts of bech32 functions --- precompiles/prototype/prototype.go | 25 +++++++---- precompiles/prototype/prototype_test.go | 59 ++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/precompiles/prototype/prototype.go b/precompiles/prototype/prototype.go index a0747631e1..930095f32f 100644 --- a/precompiles/prototype/prototype.go +++ b/precompiles/prototype/prototype.go @@ -102,6 +102,7 @@ func (c *Contract) RequiredGas(input []byte) uint64 { return 0 } +// Bech32ToHexAddr converts a bech32 address to a hex address. func (c *Contract) Bech32ToHexAddr(method *abi.Method, args []interface{}) ([]byte, error) { if len(args) != 1 { return nil, &ptypes.ErrInvalidNumberOfArgs{ @@ -110,17 +111,24 @@ func (c *Contract) Bech32ToHexAddr(method *abi.Method, args []interface{}) ([]by } } - address, ok := args[0].(string) - if !ok || address == "" { - return nil, fmt.Errorf("invalid bech32 address: %v", args[0]) + bech32String, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("invalid argument, wanted a string, got: %T", args[0]) + } + + bech32String = strings.TrimSpace(bech32String) + if bech32String == "" { + return nil, fmt.Errorf("invalid bech32 address: %s", bech32String) } - bech32Prefix := strings.SplitN(address, "1", 2)[0] - if bech32Prefix == address { - return nil, fmt.Errorf("invalid bech32 address: %s", address) + // 1 is always the separator between the bech32 prefix and the bech32 data part. + // https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 + bech32Prefix, bech32Data, found := strings.Cut(bech32String, "1") + if !found || bech32Data == "" || bech32Prefix == "" || bech32Prefix == bech32String { + return nil, fmt.Errorf("invalid bech32 address: %s", bech32String) } - addressBz, err := sdk.GetFromBech32(address, bech32Prefix) + addressBz, err := sdk.GetFromBech32(bech32String, bech32Prefix) if err != nil { return nil, err } @@ -132,6 +140,7 @@ func (c *Contract) Bech32ToHexAddr(method *abi.Method, args []interface{}) ([]by return method.Outputs.Pack(common.BytesToAddress(addressBz)) } +// Bech32ify converts a hex address to a bech32 address. func (c *Contract) Bech32ify(method *abi.Method, args []interface{}) ([]byte, error) { if len(args) != 2 { return nil, &ptypes.ErrInvalidNumberOfArgs{ @@ -170,7 +179,7 @@ func (c *Contract) Bech32ify(method *abi.Method, args []interface{}) ([]byte, er return nil, err } - addressBz, err := sdk.GetFromBech32(bech32Str, "zeta") + addressBz, err := sdk.GetFromBech32(bech32Str, prefix) if err != nil { return nil, err } diff --git a/precompiles/prototype/prototype_test.go b/precompiles/prototype/prototype_test.go index 8b64562c80..3c0d88b642 100644 --- a/precompiles/prototype/prototype_test.go +++ b/precompiles/prototype/prototype_test.go @@ -135,6 +135,26 @@ func Test_Bech32ToHexAddress(t *testing.T) { addr, ) + // Test Bech32HexAddr method. Should fail with invalid argument type.. + args[0] = 1 + rawBytes, err = contract.Bech32ToHexAddr(&methodID, args) + require.Error(t, err, "expected invalid argument; wanted string; got: %T", args[0]) + + // Test Bech32HexAddr method. Should fail because it's not a valid bech32 address. + args[0] = "foobar" + rawBytes, err = contract.Bech32ToHexAddr(&methodID, args) + require.Error(t, err, "expected error; invalid bech32 address") + + // Test Bech32HexAddr method. Should fail with invalid prefix. + args[0] = "foobar1" + rawBytes, err = contract.Bech32ToHexAddr(&methodID, args) + require.Error(t, err, "expected error; invalid bech32 addresss") + + // Test Bech32HexAddr method. Should fail with invalid prefix. + args[0] = "foobar1foobar" + rawBytes, err = contract.Bech32ToHexAddr(&methodID, args) + require.Error(t, err, "expected error; decoding bech32 failed") + // Test Bech32HexAddr method. Should fail with invalid number of arguments. args = append(args, "second argument") _, err = contract.Bech32ToHexAddr(&methodID, args) @@ -165,14 +185,14 @@ func Test_Bech32ify(t *testing.T) { abi := contract.Abi() require.NotNil(t, abi, "contract ABI should not be nil") - // Test Bech32ify method. + // Test Bech32ify method with a zeta HRP. methodID := abi.Methods[Bech32ifyMethodName] args := make([]interface{}, 0) args = append(args, "zeta") args = append(args, common.HexToAddress("0xB9Dbc229Bf588A613C00BEE8e662727AB8121cfE")) rawBytes, err := contract.Bech32ify(&methodID, args) - require.NoError(t, err, "Bech32ify should not return an error") + require.NoError(t, err, "Bech32ify prefix zeta should not return an error") // Manually extract the address from the raw bytes. zetaAddr := string(rawBytes[64:107]) @@ -180,7 +200,21 @@ func Test_Bech32ify(t *testing.T) { t, "zeta1h8duy2dltz9xz0qqhm5wvcnj02upy887fyn43u", string(zetaAddr), - "Bech32ify should return the correct address, got: %v", + "Bech32ify prefix zeta should return the correct address, got: %v", + zetaAddr, + ) + + // Test Bech32ify method with a cosmos HRP. + args[0] = "cosmos" + rawBytes, err = contract.Bech32ify(&methodID, args) + require.NoError(t, err, "Bech32ify prefix cosmos should not return an error") + + zetaAddr = string(rawBytes[64:107]) + require.Equal( + t, + "cosmos1h8duy2dltz9xz0qqhm5wvcnj02upy887lqaq", + string(zetaAddr), + "Bech32ify prefix cosmos should return the correct address, got: %v", zetaAddr, ) @@ -207,9 +241,16 @@ func Test_Bech32ify(t *testing.T) { // Test for invalid bech32 human readable prefix. argsInvalidEmptyPrefix := make([]interface{}, 0) argsInvalidEmptyPrefix = append(argsInvalidEmptyPrefix, "") - argsInvalidEmptyPrefix = append(argsInvalidEmptyPrefix, common.HexToAddress("0xB9Dbc229Bf588A613C00BEE8e662727AB8121cfE")) + argsInvalidEmptyPrefix = append( + argsInvalidEmptyPrefix, + common.HexToAddress("0xB9Dbc229Bf588A613C00BEE8e662727AB8121cfE"), + ) _, errInvalidEmptyPrefix := contract.Bech32ify(&methodID, argsInvalidEmptyPrefix) - require.Error(t, errInvalidEmptyPrefix, "expected error invalid bech32 human readable prefix (HRP). Please provide a either an account, validator or consensus address prefix (eg: cosmos, cosmosvaloper, cosmosvalcons)") + require.Error( + t, + errInvalidEmptyPrefix, + "expected error invalid bech32 human readable prefix (HRP). Please provide a either an account, validator or consensus address prefix (eg: cosmos, cosmosvaloper, cosmosvalcons)", + ) } func Test_GetGasStabilityPoolBalance(t *testing.T) { @@ -255,7 +296,13 @@ func Test_GetGasStabilityPoolBalance(t *testing.T) { argsInvalid = append(argsInvalid, "foobar") _, errInvalid := contract.GetGasStabilityPoolBalance(ctx, &methodID, argsInvalid) require.Error(t, errInvalid, "expected int64, got: %T", argsInvalid[0]) - require.IsType(t, types.ErrInvalidArgument{}, errInvalid, "expected error type: ErrInvalidArgument, got: %T", errInvalid) + require.IsType( + t, + types.ErrInvalidArgument{}, + errInvalid, + "expected error type: ErrInvalidArgument, got: %T", + errInvalid, + ) } func Test_InvalidMethod(t *testing.T) {