Skip to content

Commit

Permalink
AllowOverInt64 in amount.IntStringToAmount (#609)
Browse files Browse the repository at this point in the history
  • Loading branch information
bartekn committed Aug 23, 2018
1 parent 1968a7e commit ecd10bb
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 12 deletions.
27 changes: 20 additions & 7 deletions amount/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"math/big"
"regexp"
"strconv"
"strings"

"github.com/stellar/go/support/errors"
"github.com/stellar/go/xdr"
Expand All @@ -32,7 +33,8 @@ var (
// to `big.Rat.SetString` triggering long calculations.
// Note: {1,20} because the biggest amount you can use in Stellar is:
// len("922337203685.4775807") = 20.
validAmountSimple = regexp.MustCompile("^-?[.0-9]{1,20}$")
validAmountSimple = regexp.MustCompile("^-?[.0-9]{1,20}$")
negativePositiveNumberOnly = regexp.MustCompile("^-?[0-9]+$")
)

// MustParse is the panicking version of Parse.
Expand Down Expand Up @@ -85,18 +87,29 @@ func ParseInt64(v string) (int64, error) {
// and returns the string representation of that number.
// It is safe to use with values exceeding int64 limits.
func IntStringToAmount(v string) (string, error) {
if !validAmountSimple.MatchString(v) {
if !negativePositiveNumberOnly.MatchString(v) {
return "", errors.Errorf("invalid amount format: %s", v)
}

r := &big.Rat{}
if _, ok := r.SetString(v); !ok {
return "", errors.Errorf("cannot parse amount: %s", v)
negative := false
if v[0] == '-' {
negative = true
v = v[1:]
}

r.Quo(r, bigOne)
l := len(v)
var r string
if l <= 7 {
r = "0." + strings.Repeat("0", 7-l) + v
} else {
r = v[0:l-7] + "." + v[l-7:l]
}

if negative {
r = "-" + r
}

return r.FloatString(7), nil
return r, nil
}

// String returns an "amount string" from the provided raw xdr.Int64 value `v`.
Expand Down
10 changes: 8 additions & 2 deletions amount/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,15 @@ func TestIntStringToAmount(t *testing.T) {
{"-92233.7203686", "-922337203686", true},
{"1000000000000.0000000", "10000000000000000000", true},
{"0.0000000", "0", true},
// Expensive inputs when using big.Rat:
{"10000000000000.0000000", "1" + strings.Repeat("0", 20), true},
{"-10000000000000.0000000", "-1" + strings.Repeat("0", 20), true},
{"1" + strings.Repeat("0", 1000-7) + ".0000000", "1" + strings.Repeat("0", 1000), true},
{"1" + strings.Repeat("0", 1000000-7) + ".0000000", "1" + strings.Repeat("0", 1000000), true},
// Invalid inputs
{"", "nan", false},
// Expensive inputs:
{"", strings.Repeat("1", 1000000), false},
{"", "", false},
{"", "-", false},
{"", "1E9223372036854775807", false},
{"", "1e9223372036854775807", false},
{"", "Inf", false},
Expand Down
6 changes: 5 additions & 1 deletion services/horizon/internal/actions_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ func (action *AssetsAction) loadRecords() {
func (action *AssetsAction) loadPage() {
for _, record := range action.Records {
var res resource.AssetStat
res.Populate(action.Ctx, record)
err := res.Populate(action.R.Context(), record)
if err != nil {
action.Err = err
return
}
action.Page.Add(res)
}

Expand Down
4 changes: 2 additions & 2 deletions services/horizon/internal/resource/asset_stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/stellar/go/amount"
"github.com/stellar/go/services/horizon/internal/db2/assets"
"github.com/stellar/go/services/horizon/internal/render/hal"
"github.com/stellar/go/support/errors"
"github.com/stellar/go/xdr"
)

Expand All @@ -14,13 +15,12 @@ func (res *AssetStat) Populate(
ctx context.Context,
row assets.AssetStatsR,
) (err error) {

res.Asset.Type = row.Type
res.Asset.Code = row.Code
res.Asset.Issuer = row.Issuer
res.Amount, err = amount.IntStringToAmount(row.Amount)
if err != nil {
return err
return errors.Wrap(err, "Invalid amount in PopulateAssetStat")
}
res.NumAccounts = row.NumAccounts
res.Flags = AccountFlags{
Expand Down
32 changes: 32 additions & 0 deletions services/horizon/internal/resource/asset_stat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package resource

import (
"context"
"testing"

"github.com/stellar/go/services/horizon/internal/db2/assets"
"github.com/stretchr/testify/assert"
)

func TestLargeAmount(t *testing.T) {
row := assets.AssetStatsR{
SortKey: "",
Type: "credit_alphanum4",
Code: "XIM",
Issuer: "GBZ35ZJRIKJGYH5PBKLKOZ5L6EXCNTO7BKIL7DAVVDFQ2ODJEEHHJXIM",
Amount: "100000000000000000000", // 10T
NumAccounts: 429,
Flags: 0,
Toml: "https://xim.com/.well-known/stellar.toml",
}
var res AssetStat
err := res.Populate(context.Background(), row)
assert.NoError(t, err)

assert.Equal(t, "credit_alphanum4", res.Type)
assert.Equal(t, "XIM", res.Code)
assert.Equal(t, "GBZ35ZJRIKJGYH5PBKLKOZ5L6EXCNTO7BKIL7DAVVDFQ2ODJEEHHJXIM", res.Issuer)
assert.Equal(t, "10000000000000.0000000", res.Amount)
assert.Equal(t, int32(429), res.NumAccounts)
assert.Equal(t, "https://xim.com/.well-known/stellar.toml", res.Links.Toml.Href)
}

0 comments on commit ecd10bb

Please sign in to comment.