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

R4R: Sortable Decimal Bytes #5360

Merged
merged 10 commits into from
Dec 5, 2019
23 changes: 23 additions & 0 deletions types/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,29 @@ func (d Dec) Ceil() Dec {

//___________________________________________________________________________________

// Ensures that an sdk.Dec is within the sortable bounds
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// Dec can't have precision of less than 10^-18
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// Max sortable decimal was set to the reciprocal of SmallestDec
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
func ValidSortableDec(dec Dec) bool {
return dec.LTE(OneDec().Quo(SmallestDec()))
}

// FormattingStringSortableBytes is the string used in Sprintf to left and right pad the sdk.Dec
// It adjusts based on the Precision constant
var FormattingStringSortableBytes = fmt.Sprintf("%%0%ds", Precision*2+1)
sunnya97 marked this conversation as resolved.
Show resolved Hide resolved

// Returns a byte slice representation of an sdk.Dec that can be sorted.
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// Left and right pads with 0s so there are 18 digits to left and right of decimal point
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
func SortableDecBytes(dec Dec) []byte {
if !ValidSortableDec(dec) {
panic("dec must be within bounds")
}
return []byte(fmt.Sprintf(FormattingStringSortableBytes, dec.String()))
sunnya97 marked this conversation as resolved.
Show resolved Hide resolved
}

//___________________________________________________________________________________

// reuse nil values
var (
nilAmino string
Expand Down
19 changes: 19 additions & 0 deletions types/decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,22 @@ func TestApproxSqrt(t *testing.T) {
require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input)
}
}

func TestDecSortableBytes(t *testing.T) {
tests := []struct {
d Dec
want []byte
}{
{NewDec(0), []byte("000000000000000000.000000000000000000")},
{NewDec(1), []byte("000000000000000001.000000000000000000")},
{NewDec(10), []byte("000000000000000010.000000000000000000")},
{NewDec(12340), []byte("000000000000012340.000000000000000000")},
{NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")},
{NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")},
{NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")},
{NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")},
}
for tcIndex, tc := range tests {
assert.Equal(t, tc.want, SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex)
}
}