-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
x/stake: Limit the size of rationals from user input #1415
Changes from 1 commit
183df82
f23129b
6432fcf
7140b49
501c06c
12efe70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,8 +38,8 @@ func NewRat(Numerator int64, Denominator ...int64) Rat { | |
} | ||
|
||
// create a rational from decimal string or integer string | ||
func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { | ||
|
||
// precision is the number of values after the decimal point which should be read | ||
func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { | ||
// first extract any negative symbol | ||
neg := false | ||
if string(decimalStr[0]) == "-" { | ||
|
@@ -61,6 +61,9 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { | |
if len(str[0]) == 0 || len(str[1]) == 0 { | ||
return f, ErrUnknownRequest("not a decimal string") | ||
} | ||
if len(str[1]) > prec { | ||
str[1] = str[1][:prec] | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should actually cause an error if somebody is sending in to much precision not just truncate it - we shouldn't fail silently should let user know |
||
numStr = str[0] + str[1] | ||
len := int64(len(str[1])) | ||
denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() | ||
|
@@ -70,7 +73,17 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { | |
|
||
num, errConv := strconv.Atoi(numStr) | ||
if errConv != nil { | ||
return f, ErrUnknownRequest(errConv.Error()) | ||
// resort to big int, don't make this default option for efficiency | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like a better thing to do would be to check the specific type of error - only if it was an (overflow?) error then we would go to this next step... shouldn't have to go inside here if the user is attempting to convert "alskgndnalsg" into a rational |
||
numBig, success := new(big.Int).SetString(numStr, 10) | ||
if success != true { | ||
return f, ErrUnknownRequest("not a decimal string") | ||
} | ||
|
||
if neg { | ||
numBig.Neg(numBig) | ||
} | ||
|
||
return NewRatFromBigInt(numBig, big.NewInt(denom)), nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh whoa so now we could take in huge stuff? cool! |
||
} | ||
|
||
if neg { | ||
|
@@ -105,9 +118,9 @@ func NewRatFromInt(num Int, denom ...Int) Rat { | |
} | ||
|
||
//nolint | ||
func (r Rat) Num() int64 { return r.Rat.Num().Int64() } // Num - return the numerator | ||
func (r Rat) Denom() int64 { return r.Rat.Denom().Int64() } // Denom - return the denominator | ||
func (r Rat) IsZero() bool { return r.Num() == 0 } // IsZero - Is the Rat equal to zero | ||
func (r Rat) Num() Int { return Int{r.Rat.Num()} } // Num - return the numerator | ||
func (r Rat) Denom() Int { return Int{r.Rat.Denom()} } // Denom - return the denominator | ||
func (r Rat) IsZero() bool { return r.Num().IsZero() } // IsZero - Is the Rat equal to zero | ||
func (r Rat) Equal(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 0 } | ||
func (r Rat) GT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 1 } // greater than | ||
func (r Rat) GTE(r2 Rat) bool { return !r.LT(r2) } // greater than or equal | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ func TestNew(t *testing.T) { | |
} | ||
|
||
func TestNewFromDecimal(t *testing.T) { | ||
largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10) | ||
require.True(t, success) | ||
tests := []struct { | ||
decimalStr string | ||
expErr bool | ||
|
@@ -31,7 +33,10 @@ func TestNewFromDecimal(t *testing.T) { | |
{"1.1", false, NewRat(11, 10)}, | ||
{"0.75", false, NewRat(3, 4)}, | ||
{"0.8", false, NewRat(4, 5)}, | ||
{"0.11111", false, NewRat(11111, 100000)}, | ||
{"0.11111", false, NewRat(1111, 10000)}, | ||
{"628240629832763.5738930323617075341", false, NewRat(3141203149163817869, 5000)}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I mentioned earlier we should send an error if there are to many decimal places |
||
{"621947210595948537540277652521.5738930323617075341", | ||
false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, | ||
{".", true, Rat{}}, | ||
{".0", true, Rat{}}, | ||
{"1.", true, Rat{}}, | ||
|
@@ -41,17 +46,16 @@ func TestNewFromDecimal(t *testing.T) { | |
} | ||
|
||
for _, tc := range tests { | ||
|
||
res, err := NewRatFromDecimal(tc.decimalStr) | ||
res, err := NewRatFromDecimal(tc.decimalStr, 4) | ||
if tc.expErr { | ||
assert.NotNil(t, err, tc.decimalStr) | ||
} else { | ||
assert.Nil(t, err) | ||
assert.True(t, res.Equal(tc.exp)) | ||
require.Nil(t, err) | ||
require.True(t, res.Equal(tc.exp)) | ||
} | ||
|
||
// negative tc | ||
res, err = NewRatFromDecimal("-" + tc.decimalStr) | ||
res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) | ||
if tc.expErr { | ||
assert.NotNil(t, err, tc.decimalStr) | ||
} else { | ||
|
@@ -133,7 +137,7 @@ func TestArithmetic(t *testing.T) { | |
assert.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) | ||
assert.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) | ||
|
||
if tc.r2.Num() == 0 { // panic for divide by zero | ||
if tc.r2.Num().IsZero() { // panic for divide by zero | ||
assert.Panics(t, func() { tc.r1.Quo(tc.r2) }) | ||
} else { | ||
assert.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the tendermint-lint require a comment on this function? I don't think it does - pretty straight forward probably can remove the comment (unless this needs to be added to our linter)