Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handled edge case for processing []byte in abi + Update gRPC calls #132

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions pkg/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func GetPaddedParam(param []Param) ([]byte, error) {
}
v = append(v.([]eCommon.Address), addr)
}

}

if (ty.Elem.T == eABI.IntTy || ty.Elem.T == eABI.UintTy) &&
Expand All @@ -148,6 +149,54 @@ func GetPaddedParam(param []Param) ([]byte, error) {
}
v = tmp
}

// handle bytes[]
if ty.Elem.T == eABI.BytesTy || ty.Elem.T == eABI.FixedBytesTy {
// Type handling is needed as GetPaddedParams is public and different inputs can be passed in which results in different types of v
switch v.(type) {
case []interface{}:
tmp, ok := v.([]interface{})
if !ok {
return nil, fmt.Errorf("unable to convert array of bytes %+v", p)
}
bytesSlice := make([][]byte, len(tmp))

for i := range tmp {
if tmp[i] == nil {
// Handle empty byte array
bytesSlice[i] = []byte{}
} else {
value, err := convertToBytes(*ty.Elem, tmp[i])
if err != nil {
return nil, fmt.Errorf("unable to convert bytes element %+v: %v", tmp[i], err)
}
bytesSlice[i] = value.([]byte)
}
}
v = bytesSlice
case string:
tmp := v.(string)
v, err = processJSONArray(tmp)
if err != nil {
return nil, err
}
case []uint8:
tmp, ok := v.([][]uint8)
bytesSlice := make([][]byte, len(tmp))
for i := range tmp {
if !ok {
return nil, fmt.Errorf("unable to convert array of bytes %+v", p)
}
if len(tmp[i]) == 0 {
// Handle empty byte array
bytesSlice[i] = nil
} else {
bytesSlice[i] = tmp[i]
}
}
v = bytesSlice
}
}
}
if ty.T == eABI.AddressTy {
if v, err = convetToAddress(v); err != nil {
Expand All @@ -172,6 +221,22 @@ func GetPaddedParam(param []Param) ([]byte, error) {
return arguments.PackValues(values)
}

func processJSONArray(input string) ([][]byte, error) {
var jsonArray []string
err := json.Unmarshal([]byte(input), &jsonArray)
if err != nil {
return nil, fmt.Errorf("unable to parse JSON array from string %+v: %v", input, err)
}
bytesSlice := make([][]byte, len(jsonArray))
for i, elem := range jsonArray {
bytesSlice[i], err = hex.DecodeString(strings.TrimPrefix(elem, "0x"))
if err != nil {
return nil, fmt.Errorf("error decoding byte string from element [%d] %+v: %v", i, elem, err)
}
}
return bytesSlice, nil
}

func convertToBytes(ty eABI.Type, v interface{}) (interface{}, error) {
// if string
if data, ok := v.(string); ok {
Expand Down
90 changes: 90 additions & 0 deletions pkg/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,93 @@ func TestABI_HEXuint256(t *testing.T) {
assert.Len(t, b, 64, fmt.Sprintf("Wrong length %d/%d", len(b), 256))
assert.Equal(t, "000000000000000000000000000000000000000000000000000000000000abcd000000000000000000000000000000000000000000000000000000000000abcd", hex.EncodeToString(b))
}

func TestABIParamBytesArrayString(t *testing.T) {
tests := []struct {
name string
jsonInput string
expected string
expectErr bool
expectedLen int
}{
{
name: "Empty byte array",
jsonInput: `[{"bytes[]":"[]"}]`,
// The expected value is the 32-byte padded representation of an empty bytes array,
// which consists of "0x20" (offset value) followed by "0x80" (length of dynamic data),
// and then padded with zeros to make it 32 bytes long.
expected: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
expectedLen: 64,
},
{
name: "Single byte array",
jsonInput: `[{"bytes[]":"[\"01020304\"]"}]`,
expected: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000",
expectedLen: 160,
},
{
name: "Multiple byte arrays",
jsonInput: `[{"bytes[]":"[\"01\", \"02\", \"03\"]"}]`,
expected: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000000000000000",
expectedLen: 352,
},
{
name: "Mixed content in byte array",
jsonInput: `[{"bytes[]":"[\"0102\",\"030405\"]"}]`,
expected: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002010200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030304050000000000000000000000000000000000000000000000000000000000",
expectedLen: 256,
},

{
name: "Mixed content with empty hex string",
jsonInput: `[{"bytes[]":"[\"0102\",\"\",\"030405\"]"}]`,
expected: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000020102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030304050000000000000000000000000000000000000000000000000000000000",
expectedLen: 320,
},
{
name: "Invalid hex data",
jsonInput: `[{"bytes[]":"[asdasdas]"}]`,
expectErr: true,
},
{
name: "Missing quotes around hex string",
jsonInput: `[{"bytes[]":"[01020304]"}]`,
expectErr: true,
},
{
name: "Invalid hex string in byte array",
jsonInput: `[{"bytes[]":"[\"0102\",,\"030405\"]"}]`,
expectErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
param, err := LoadFromJSON(tt.jsonInput)
require.Nil(t, err)
b, err := GetPaddedParam(param)
if tt.expectErr {
require.Error(t, err)
} else {
require.Nil(t, err)
assert.Len(t, b, tt.expectedLen, fmt.Sprintf("Wrong length %d/%d", len(b), tt.expectedLen))
if tt.expectedLen > 0 {
assert.Equal(t, tt.expected, hex.EncodeToString(b))
}
}
})
}
}

func TestGetPaddedParamInterfaceArray(t *testing.T) {
param := []Param{
{"bytes[]": []interface{}{"01", "02", "03"}},
}

expected :=
[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
result, err := GetPaddedParam(param)

assert.NoError(t, err, "Should not have an error")
assert.Equal(t, expected, result, "The byte slice should match expected output")
}
2 changes: 1 addition & 1 deletion pkg/client/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestUnfreezeV2(t *testing.T) {

func TestDelegate(t *testing.T) {
t.Skip() // Only in testnet nile
tx, err := conn.DelegateResource(testnetNileAddressExample, testnetNileAddressDelegateExample, core.ResourceCode_BANDWIDTH, 1000000, false)
tx, err := conn.DelegateResource(testnetNileAddressExample, testnetNileAddressDelegateExample, core.ResourceCode_BANDWIDTH, 1000000, false, 10000)

require.Nil(t, err)
require.NotNil(t, tx.GetTxid())
Expand Down
26 changes: 26 additions & 0 deletions pkg/client/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,32 @@ func (g *GrpcClient) estimateEnergy(ct *core.TriggerSmartContract) (*api.Estimat
return tx, err
}

// GetBandwidthPrices retrieves bandwidth prices
func (g *GrpcClient) GetBandwidthPrices() (*api.PricesResponseMessage, error) {
ctx, cancel := g.getContext()
defer cancel()

result, err := g.Client.GetBandwidthPrices(ctx, new(api.EmptyMessage))
if err != nil {
return nil, fmt.Errorf("get bandwidth prices: %v", err)
}

return result, nil
}

// GetEnergyPrices retrieves energy prices
func (g *GrpcClient) GetEnergyPrices() (*api.PricesResponseMessage, error) {
ctx, cancel := g.getContext()
defer cancel()

result, err := g.Client.GetEnergyPrices(ctx, new(api.EmptyMessage))
if err != nil {
return nil, fmt.Errorf("get energy prices: %v", err)
}

return result, nil
}

// DeployContract and return tx result
func (g *GrpcClient) DeployContract(from, contractName string,
abi *core.SmartContract_ABI, codeStr string,
Expand Down
56 changes: 56 additions & 0 deletions pkg/client/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/hex"
"fmt"
"math/big"
"strings"
"testing"

"github.com/fbsobreira/gotron-sdk/pkg/abi"
Expand Down Expand Up @@ -130,3 +131,58 @@ func TestGetAccountMigrationContract(t *testing.T) {
fmt.Println(result["amount"].(*big.Int).Int64())
require.Nil(t, err)
}

// TestGetEnergyPrices tests the GetEnergyPrices function
func TestGetEnergyPrices(t *testing.T) {
conn := client.NewGrpcClient("grpc.trongrid.io:50051")
err := conn.Start(grpc.WithInsecure())
require.Nil(t, err)

prices, err := conn.GetEnergyPrices()
require.Nil(t, err)

// Extract the last price from the prices string
pricesStr := prices.Prices
require.NotEmpty(t, pricesStr)

pricesList := strings.Split(pricesStr, ",")
require.NotEmpty(t, pricesList)

// Get the last price component
lastPriceComponent := pricesList[len(pricesList)-1]
require.NotEmpty(t, lastPriceComponent)

// Extract the price value from the last component
lastPriceParts := strings.Split(lastPriceComponent, ":")
require.Len(t, lastPriceParts, 2)

lastPriceValue := lastPriceParts[1]

// Ensure the last price value is "420"
require.Equal(t, "420", lastPriceValue)
}

// TestGetBandwidthPrices tests the GetBandwidthPrices function
func TestGetBandwidthPrices(t *testing.T) {
conn := client.NewGrpcClient("grpc.trongrid.io:50051")
err := conn.Start(grpc.WithInsecure())
require.Nil(t, err)

prices, err := conn.GetBandwidthPrices()
require.Nil(t, err)

// Assert prices are not empty
pricesStr := prices.Prices
require.NotEmpty(t, pricesStr)

// Further validation (e.g., checking format)
pricesList := strings.Split(pricesStr, ",")
require.NotEmpty(t, pricesList)

// checking that each price component has a valid format
for _, priceComponent := range pricesList {
parts := strings.Split(priceComponent, ":")
require.Len(t, parts, 2)
// We could add more checks here, like validating the timestamp and price values
}
}
Loading