From abf9a65c79ddcaafd03a96a0d356f5376d6ef8e6 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Jul 2018 12:46:41 -0400 Subject: [PATCH 01/50] changelog --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index e1010eb99068..88e47427bca7 100644 --- a/PENDING.md +++ b/PENDING.md @@ -20,6 +20,7 @@ BREAKING CHANGES * `gaiacli gov deposit --depositer` * `gaiacli gov vote --voter` * [x/gov] Added tags sub-package, changed tags to use dash-case +* \#1807 Switch from use of rational to decimal FEATURES * [lcd] Can now query governance proposals by ProposalStatus From 84c7fab3d9a305e632177e1285683a71f5a3c234 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Jul 2018 16:20:48 -0400 Subject: [PATCH 02/50] ... --- types/decimal/decimal.go | 256 +++++++++++++++++++++++++++ types/decimal/decimal_test.go | 319 ++++++++++++++++++++++++++++++++++ types/types.go | 4 + 3 files changed, 579 insertions(+) create mode 100644 types/decimal/decimal.go create mode 100644 types/decimal/decimal_test.go create mode 100644 types/types.go diff --git a/types/decimal/decimal.go b/types/decimal/decimal.go new file mode 100644 index 000000000000..df5ab54db2bc --- /dev/null +++ b/types/decimal/decimal.go @@ -0,0 +1,256 @@ +package decimal + +import ( + "fmt" + "math/big" + "strconv" + "strings" + "testing" +) + +// NOTE: never use new(Rat) or else +// we will panic unmarshalling into the +// nil embedded big.Rat +type Rat struct { + *big.Rat `json:"rat"` +} + +// nolint - common values +func ZeroRat() Rat { return Rat{big.NewRat(0, 1)} } +func OneRat() Rat { return Rat{big.NewRat(1, 1)} } + +// New - create a new Rat from integers +func NewRat(Numerator int64, Denominator ...int64) Rat { + switch len(Denominator) { + case 0: + return Rat{big.NewRat(Numerator, 1)} + case 1: + return Rat{big.NewRat(Numerator, Denominator[0])} + default: + panic("improper use of New, can only have one denominator") + } +} + +func getNumeratorDenominator(str []string, prec int) (numerator string, denom int64, err Error) { + switch len(str) { + case 1: + if len(str[0]) == 0 { + return "", 0, ErrUnknownRequest("not a decimal string") + } + numerator = str[0] + return numerator, 1, nil + case 2: + if len(str[0]) == 0 || len(str[1]) == 0 { + return "", 0, ErrUnknownRequest("not a decimal string") + } + if len(str[1]) > prec { + return "", 0, ErrUnknownRequest("string has too many decimals") + } + numerator = str[0] + str[1] + len := int64(len(str[1])) + denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() + return numerator, denom, nil + default: + return "", 0, ErrUnknownRequest("not a decimal string") + } +} + +// create a rational from decimal string or integer string +// 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 + if len(decimalStr) == 0 { + return f, ErrUnknownRequest("decimal string is empty") + } + + neg := false + if string(decimalStr[0]) == "-" { + neg = true + decimalStr = decimalStr[1:] + } + + str := strings.Split(decimalStr, ".") + + numStr, denom, err := getNumeratorDenominator(str, prec) + if err != nil { + return f, err + } + + num, errConv := strconv.Atoi(numStr) + if errConv != nil && strings.HasSuffix(errConv.Error(), "value out of range") { + // resort to big int, don't make this default option for efficiency + 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 + } else if errConv != nil { + return f, ErrUnknownRequest("not a decimal string") + } + + if neg { + num *= -1 + } + + return NewRat(int64(num), denom), nil +} + +// NewRatFromBigInt constructs Rat from big.Int +func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat { + switch len(denom) { + case 0: + return Rat{new(big.Rat).SetInt(num)} + case 1: + return Rat{new(big.Rat).SetFrac(num, denom[0])} + default: + panic("improper use of NewRatFromBigInt, can only have one denominator") + } +} + +// NewRatFromInt constructs Rat from Int +func NewRatFromInt(num Int, denom ...Int) Rat { + switch len(denom) { + case 0: + return Rat{new(big.Rat).SetInt(num.BigInt())} + case 1: + return Rat{new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())} + default: + panic("improper use of NewRatFromBigInt, can only have one denominator") + } +} + +//nolint +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 +func (r Rat) LT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == -1 } // less than +func (r Rat) LTE(r2 Rat) bool { return !r.GT(r2) } // less than or equal +func (r Rat) Mul(r2 Rat) Rat { return Rat{new(big.Rat).Mul(r.Rat, r2.Rat)} } // Mul - multiplication +func (r Rat) Quo(r2 Rat) Rat { return Rat{new(big.Rat).Quo(r.Rat, r2.Rat)} } // Quo - quotient +func (r Rat) Add(r2 Rat) Rat { return Rat{new(big.Rat).Add(r.Rat, r2.Rat)} } // Add - addition +func (r Rat) Sub(r2 Rat) Rat { return Rat{new(big.Rat).Sub(r.Rat, r2.Rat)} } // Sub - subtraction +func (r Rat) String() string { return r.Rat.String() } +func (r Rat) FloatString() string { return r.Rat.FloatString(10) } // a human-friendly string format. The last digit is rounded to nearest, with halves rounded away from zero. + +var ( + zero = big.NewInt(0) + one = big.NewInt(1) + two = big.NewInt(2) + five = big.NewInt(5) + nFive = big.NewInt(-5) + ten = big.NewInt(10) +) + +// evaluate the rational using bankers rounding +func (r Rat) EvaluateBig() *big.Int { + + num := r.Rat.Num() + denom := r.Rat.Denom() + + d, rem := new(big.Int), new(big.Int) + d.QuoRem(num, denom, rem) + if rem.Cmp(zero) == 0 { // is the remainder zero + return d + } + + // evaluate the remainder using bankers rounding + tenNum := new(big.Int).Mul(num, ten) + tenD := new(big.Int).Mul(d, ten) + remainderDigit := new(big.Int).Sub(new(big.Int).Quo(tenNum, denom), tenD) // get the first remainder digit + isFinalDigit := (new(big.Int).Rem(tenNum, denom).Cmp(zero) == 0) // is this the final digit in the remainder? + + switch { + case isFinalDigit && (remainderDigit.Cmp(five) == 0 || remainderDigit.Cmp(nFive) == 0): + dRem2 := new(big.Int).Rem(d, two) + return new(big.Int).Add(d, dRem2) // always rounds to the even number + case remainderDigit.Cmp(five) != -1: //remainderDigit >= 5: + d.Add(d, one) + case remainderDigit.Cmp(nFive) != 1: //remainderDigit <= -5: + d.Sub(d, one) + } + return d +} + +// RoundInt64 rounds the rational using bankers rounding +func (r Rat) RoundInt64() int64 { + return r.EvaluateBig().Int64() +} + +// RoundInt round the rational using bankers rounding +func (r Rat) RoundInt() Int { + return NewIntFromBigInt(r.EvaluateBig()) +} + +// round Rat with the provided precisionFactor +func (r Rat) Round(precisionFactor int64) Rat { + rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))} + return Rat{big.NewRat(rTen.RoundInt64(), precisionFactor)} +} + +// TODO panic if negative or if totalDigits < len(initStr)??? +// evaluate as an integer and return left padded string +func (r Rat) ToLeftPadded(totalDigits int8) string { + intStr := r.EvaluateBig().String() + fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` + return fmt.Sprintf(fcode, intStr) +} + +//___________________________________________________________________________________ + +//Wraps r.MarshalText(). +func (r Rat) MarshalAmino() (string, error) { + if r.Rat == nil { + r.Rat = new(big.Rat) + } + bz, err := r.Rat.MarshalText() + return string(bz), err +} + +// Requires a valid JSON string - strings quotes and calls UnmarshalText +func (r *Rat) UnmarshalAmino(text string) (err error) { + tempRat := big.NewRat(0, 1) + err = tempRat.UnmarshalText([]byte(text)) + if err != nil { + return err + } + r.Rat = tempRat + return nil +} + +//___________________________________________________________________________________ +// helpers + +// test if two rat arrays are equal +func RatsEqual(r1s, r2s []Rat) bool { + if len(r1s) != len(r2s) { + return false + } + + for i, r1 := range r1s { + if !r1.Equal(r2s[i]) { + return false + } + } + return true +} + +// intended to be used with require/assert: require.True(RatEq(...)) +func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got +} + +// minimum rational between two +func MinRat(r1, r2 Rat) Rat { + if r1.LT(r2) { + return r1 + } + return r2 +} diff --git a/types/decimal/decimal_test.go b/types/decimal/decimal_test.go new file mode 100644 index 000000000000..8b02559720e3 --- /dev/null +++ b/types/decimal/decimal_test.go @@ -0,0 +1,319 @@ +package decimal + +import ( + "math/big" + "testing" + + wire "github.com/cosmos/cosmos-sdk/wire" + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + require.Equal(t, NewRat(1), NewRat(1, 1)) + require.Equal(t, NewRat(100), NewRat(100, 1)) + require.Equal(t, NewRat(-1), NewRat(-1, 1)) + require.Equal(t, NewRat(-100), NewRat(-100, 1)) + require.Equal(t, NewRat(0), NewRat(0, 1)) + + // do not allow for more than 2 variables + require.Panics(t, func() { NewRat(1, 1, 1) }) +} + +func TestNewFromDecimal(t *testing.T) { + largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10) + require.True(t, success) + tests := []struct { + decimalStr string + expErr bool + exp Rat + }{ + {"", true, Rat{}}, + {"0", false, NewRat(0)}, + {"1", false, NewRat(1)}, + {"1.1", false, NewRat(11, 10)}, + {"0.75", false, NewRat(3, 4)}, + {"0.8", false, NewRat(4, 5)}, + {"0.11111", true, NewRat(1111, 10000)}, + {"628240629832763.5738930323617075341", true, NewRat(3141203149163817869, 5000)}, + {"621947210595948537540277652521.5738930323617075341", + true, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, + {"628240629832763.5738", false, NewRat(3141203149163817869, 5000)}, + {"621947210595948537540277652521.5738", + false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, + {".", true, Rat{}}, + {".0", true, Rat{}}, + {"1.", true, Rat{}}, + {"foobar", true, Rat{}}, + {"0.foobar", true, Rat{}}, + {"0.foobar.", true, Rat{}}, + } + + for tcIndex, tc := range tests { + res, err := NewRatFromDecimal(tc.decimalStr, 4) + if tc.expErr { + require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex) + } else { + require.Nil(t, err, tc.decimalStr, "unexpected error, tc #%d", tcIndex) + require.True(t, res.Equal(tc.exp), tc.decimalStr, "equality was incorrect, tc #%d", tcIndex) + } + + // negative tc + res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) + if tc.expErr { + require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex) + } else { + require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex) + require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex) + } + } +} + +func TestEqualities(t *testing.T) { + tests := []struct { + r1, r2 Rat + gt, lt, eq bool + }{ + {NewRat(0), NewRat(0), false, false, true}, + {NewRat(0, 100), NewRat(0, 10000), false, false, true}, + {NewRat(100), NewRat(100), false, false, true}, + {NewRat(-100), NewRat(-100), false, false, true}, + {NewRat(-100, -1), NewRat(100), false, false, true}, + {NewRat(-1, 1), NewRat(1, -1), false, false, true}, + {NewRat(1, -1), NewRat(-1, 1), false, false, true}, + {NewRat(3, 7), NewRat(3, 7), false, false, true}, + + {NewRat(0), NewRat(3, 7), false, true, false}, + {NewRat(0), NewRat(100), false, true, false}, + {NewRat(-1), NewRat(3, 7), false, true, false}, + {NewRat(-1), NewRat(100), false, true, false}, + {NewRat(1, 7), NewRat(100), false, true, false}, + {NewRat(1, 7), NewRat(3, 7), false, true, false}, + {NewRat(-3, 7), NewRat(-1, 7), false, true, false}, + + {NewRat(3, 7), NewRat(0), true, false, false}, + {NewRat(100), NewRat(0), true, false, false}, + {NewRat(3, 7), NewRat(-1), true, false, false}, + {NewRat(100), NewRat(-1), true, false, false}, + {NewRat(100), NewRat(1, 7), true, false, false}, + {NewRat(3, 7), NewRat(1, 7), true, false, false}, + {NewRat(-1, 7), NewRat(-3, 7), true, false, false}, + } + + for tcIndex, tc := range tests { + require.Equal(t, tc.gt, tc.r1.GT(tc.r2), "GT result is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.lt, tc.r1.LT(tc.r2), "LT result is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.eq, tc.r1.Equal(tc.r2), "equality result is incorrect, tc #%d", tcIndex) + } + +} + +func TestArithmetic(t *testing.T) { + tests := []struct { + r1, r2 Rat + resMul, resDiv, resAdd, resSub Rat + }{ + // r1 r2 MUL DIV ADD SUB + {NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0)}, + {NewRat(1), NewRat(0), NewRat(0), NewRat(0), NewRat(1), NewRat(1)}, + {NewRat(0), NewRat(1), NewRat(0), NewRat(0), NewRat(1), NewRat(-1)}, + {NewRat(0), NewRat(-1), NewRat(0), NewRat(0), NewRat(-1), NewRat(1)}, + {NewRat(-1), NewRat(0), NewRat(0), NewRat(0), NewRat(-1), NewRat(-1)}, + + {NewRat(1), NewRat(1), NewRat(1), NewRat(1), NewRat(2), NewRat(0)}, + {NewRat(-1), NewRat(-1), NewRat(1), NewRat(1), NewRat(-2), NewRat(0)}, + {NewRat(1), NewRat(-1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(2)}, + {NewRat(-1), NewRat(1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(-2)}, + + {NewRat(3), NewRat(7), NewRat(21), NewRat(3, 7), NewRat(10), NewRat(-4)}, + {NewRat(2), NewRat(4), NewRat(8), NewRat(1, 2), NewRat(6), NewRat(-2)}, + {NewRat(100), NewRat(100), NewRat(10000), NewRat(1), NewRat(200), NewRat(0)}, + + {NewRat(3, 2), NewRat(3, 2), NewRat(9, 4), NewRat(1), NewRat(3), NewRat(0)}, + {NewRat(3, 7), NewRat(7, 3), NewRat(1), NewRat(9, 49), NewRat(58, 21), NewRat(-40, 21)}, + {NewRat(1, 21), NewRat(11, 5), NewRat(11, 105), NewRat(5, 231), NewRat(236, 105), NewRat(-226, 105)}, + {NewRat(-21), NewRat(3, 7), NewRat(-9), NewRat(-49), NewRat(-144, 7), NewRat(-150, 7)}, + {NewRat(100), NewRat(1, 7), NewRat(100, 7), NewRat(700), NewRat(701, 7), NewRat(699, 7)}, + } + + for tcIndex, tc := range tests { + require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) + require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) + require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) + + if tc.r2.Num().IsZero() { // panic for divide by zero + require.Panics(t, func() { tc.r1.Quo(tc.r2) }) + } else { + require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) + } + } +} + +func TestEvaluate(t *testing.T) { + tests := []struct { + r1 Rat + res int64 + }{ + {NewRat(0), 0}, + {NewRat(1), 1}, + {NewRat(1, 4), 0}, + {NewRat(1, 2), 0}, + {NewRat(3, 4), 1}, + {NewRat(5, 6), 1}, + {NewRat(3, 2), 2}, + {NewRat(5, 2), 2}, + {NewRat(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {NewRat(17, 11), 2}, // 1.545 + {NewRat(5, 11), 0}, + {NewRat(16, 11), 1}, + {NewRat(113, 12), 9}, + } + + for tcIndex, tc := range tests { + require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v. tc #%d", tc.r1, tcIndex) + require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v. tc #%d", tc.r1.Mul(NewRat(-1)), tcIndex) + } +} + +func TestRound(t *testing.T) { + many3 := "333333333333333333333333333333333333333333333" + many7 := "777777777777777777777777777777777777777777777" + big3, worked := new(big.Int).SetString(many3, 10) + require.True(t, worked) + big7, worked := new(big.Int).SetString(many7, 10) + require.True(t, worked) + + tests := []struct { + r, res Rat + precFactor int64 + }{ + {NewRat(333, 777), NewRat(429, 1000), 1000}, + {Rat{new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000}, + {Rat{new(big.Rat).SetFrac(big3, big7)}, Rat{big.NewRat(4285714286, 10000000000)}, 10000000000}, + {NewRat(1, 2), NewRat(1, 2), 1000}, + } + + for tcIndex, tc := range tests { + require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r, "incorrect rounding, tc #%d", tcIndex) + negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1)) + require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex) + } +} + +func TestToLeftPadded(t *testing.T) { + tests := []struct { + rat Rat + digits int8 + res string + }{ + {NewRat(100, 3), 8, "00000033"}, + {NewRat(1, 3), 8, "00000000"}, + {NewRat(100, 2), 8, "00000050"}, + {NewRat(1000, 3), 8, "00000333"}, + {NewRat(1000, 3), 12, "000000000333"}, + } + for tcIndex, tc := range tests { + require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex) + } +} + +var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec + +func TestZeroSerializationJSON(t *testing.T) { + r := NewRat(0, 1) + err := cdc.UnmarshalJSON([]byte(`"0/1"`), &r) + require.Nil(t, err) + err = cdc.UnmarshalJSON([]byte(`"0/0"`), &r) + require.NotNil(t, err) + err = cdc.UnmarshalJSON([]byte(`"1/0"`), &r) + require.NotNil(t, err) + err = cdc.UnmarshalJSON([]byte(`"{}"`), &r) + require.NotNil(t, err) +} + +func TestSerializationText(t *testing.T) { + r := NewRat(1, 3) + + bz, err := r.MarshalText() + require.NoError(t, err) + + var r2 = Rat{new(big.Rat)} + err = r2.UnmarshalText(bz) + require.NoError(t, err) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) +} + +func TestSerializationGoWireJSON(t *testing.T) { + r := NewRat(1, 3) + bz, err := cdc.MarshalJSON(r) + require.NoError(t, err) + + var r2 Rat + err = cdc.UnmarshalJSON(bz, &r2) + require.NoError(t, err) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) +} + +func TestSerializationGoWireBinary(t *testing.T) { + r := NewRat(1, 3) + bz, err := cdc.MarshalBinary(r) + require.NoError(t, err) + + var r2 Rat + err = cdc.UnmarshalBinary(bz, &r2) + require.NoError(t, err) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) +} + +type testEmbedStruct struct { + Field1 string `json:"f1"` + Field2 int `json:"f2"` + Field3 Rat `json:"f3"` +} + +func TestEmbeddedStructSerializationGoWire(t *testing.T) { + obj := testEmbedStruct{"foo", 10, NewRat(1, 3)} + bz, err := cdc.MarshalJSON(obj) + require.Nil(t, err) + + var obj2 testEmbedStruct + err = cdc.UnmarshalJSON(bz, &obj2) + require.Nil(t, err) + + require.Equal(t, obj.Field1, obj2.Field1) + require.Equal(t, obj.Field2, obj2.Field2) + require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) +} + +func TestRatsEqual(t *testing.T) { + tests := []struct { + r1s, r2s []Rat + eq bool + }{ + {[]Rat{NewRat(0)}, []Rat{NewRat(0)}, true}, + {[]Rat{NewRat(0)}, []Rat{NewRat(1)}, false}, + {[]Rat{NewRat(0)}, []Rat{}, false}, + {[]Rat{NewRat(0), NewRat(1)}, []Rat{NewRat(0), NewRat(1)}, true}, + {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1), NewRat(0)}, true}, + {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(0), NewRat(1)}, false}, + {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1)}, false}, + {[]Rat{NewRat(1), NewRat(2)}, []Rat{NewRat(2), NewRat(4)}, false}, + {[]Rat{NewRat(3), NewRat(18)}, []Rat{NewRat(1), NewRat(6)}, false}, + } + + for tcIndex, tc := range tests { + require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s), "equality of rational arrays is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s), "equality of rational arrays is incorrect (converse), tc #%d", tcIndex) + } + +} + +func TestStringOverflow(t *testing.T) { + // two random 64 bit primes + rat1 := NewRat(5164315003622678713, 4389711697696177267) + rat2 := NewRat(-3179849666053572961, 8459429845579852627) + rat3 := rat1.Add(rat2) + require.Equal(t, + "29728537197630860939575850336935951464/37134458148982045574552091851127630409", + rat3.String(), + ) +} diff --git a/types/types.go b/types/types.go new file mode 100644 index 000000000000..bb320d902185 --- /dev/null +++ b/types/types.go @@ -0,0 +1,4 @@ +// nolint +package types + +// aliases From c9ed6685054e4469a5099cfbd632a2a2586b63c4 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Jul 2018 21:53:16 -0400 Subject: [PATCH 03/50] decimal func working --- types/decimal/decimal.go | 252 +++++++++++++++++++++++---------------- 1 file changed, 148 insertions(+), 104 deletions(-) diff --git a/types/decimal/decimal.go b/types/decimal/decimal.go index df5ab54db2bc..de8649c81b10 100644 --- a/types/decimal/decimal.go +++ b/types/decimal/decimal.go @@ -8,29 +8,32 @@ import ( "testing" ) -// NOTE: never use new(Rat) or else -// we will panic unmarshalling into the -// nil embedded big.Rat -type Rat struct { - *big.Rat `json:"rat"` +// NOTE: never use new(Decimal) or else we will panic unmarshalling into the +// nil embedded big.Int +type Decimal struct { + *big.Int `json:Int""` +} + +// number of decimal places +const Precision = 10 + +func precisionInt() big.Int { + p := big.NewInt(1) + return *p.Exp(big.NewInt(1), big.NewInt(precision), nil) } // nolint - common values -func ZeroRat() Rat { return Rat{big.NewRat(0, 1)} } -func OneRat() Rat { return Rat{big.NewRat(1, 1)} } +func ZeroDec() Decimal { return Decimal{big.NewInt(0)} } +func OneDec() Decimal { return Decimal{&precisionInt} } -// New - create a new Rat from integers -func NewRat(Numerator int64, Denominator ...int64) Rat { - switch len(Denominator) { - case 0: - return Rat{big.NewRat(Numerator, 1)} - case 1: - return Rat{big.NewRat(Numerator, Denominator[0])} - default: - panic("improper use of New, can only have one denominator") +// create a new Decimal from integer assuming whole numbers +func NewDecimalFromInt(i int64) Decimal { + return Decimal{ + new(big.Int).Mul(big.NewInt(i), precisionInt()), } } +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxx XXX func getNumeratorDenominator(str []string, prec int) (numerator string, denom int64, err Error) { switch len(str) { case 1: @@ -55,14 +58,15 @@ func getNumeratorDenominator(str []string, prec int) (numerator string, denom in } } -// create a rational from decimal string or integer string +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxx XXX +// create a decimal from decimal string or integer string // 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 +func NewDecimalFromStr(str string) (f Decimal, err Error) { if len(decimalStr) == 0 { return f, ErrUnknownRequest("decimal string is empty") } + // first extract any negative symbol neg := false if string(decimalStr[0]) == "-" { neg = true @@ -70,6 +74,17 @@ func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { } str := strings.Split(decimalStr, ".") + lenDecimals := 0 + combinedStr := str[0] + if len(str) == 2 { + lenDecimals = len(str[1]) + } else if len(str) > 2 { + return f, ErrUnknownRequest("too many periods to be a decimal string") + } + + if lenDecimals > precision { + return f, ErrUnknownRequest("too much precision in decimal") + } numStr, denom, err := getNumeratorDenominator(str, prec) if err != nil { @@ -88,7 +103,7 @@ func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { numBig.Neg(numBig) } - return NewRatFromBigInt(numBig, big.NewInt(denom)), nil + return NewDecFromBigInt(numBig, big.NewInt(denom)), nil } else if errConv != nil { return f, ErrUnknownRequest("not a decimal string") } @@ -97,48 +112,65 @@ func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { num *= -1 } - return NewRat(int64(num), denom), nil + return NewInt(int64(num), denom), nil } -// NewRatFromBigInt constructs Rat from big.Int -func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat { +// NewDecFromBigInt constructs Decimal from big.Int +func NewDecFromBigInt(num *big.Int, denom ...*big.Int) Decimal { switch len(denom) { case 0: - return Rat{new(big.Rat).SetInt(num)} + return Decimal{new(big.Int).SetInt(num)} case 1: - return Rat{new(big.Rat).SetFrac(num, denom[0])} + return Decimal{new(big.Int).SetFrac(num, denom[0])} default: - panic("improper use of NewRatFromBigInt, can only have one denominator") + panic("improper use of NewDecFromBigInt, can only have one denominator") } } -// NewRatFromInt constructs Rat from Int -func NewRatFromInt(num Int, denom ...Int) Rat { +// NewDecFromInt constructs Decimal from Int +func NewDecFromInt(num Int, denom ...Int) Decimal { switch len(denom) { case 0: - return Rat{new(big.Rat).SetInt(num.BigInt())} + return Decimal{new(big.Int).SetInt(num.BigInt())} case 1: - return Rat{new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())} + return Decimal{new(big.Int).SetFrac(num.BigInt(), denom[0].BigInt())} default: - panic("improper use of NewRatFromBigInt, can only have one denominator") + panic("improper use of NewDecFromBigInt, can only have one denominator") } } //nolint -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 -func (r Rat) LT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == -1 } // less than -func (r Rat) LTE(r2 Rat) bool { return !r.GT(r2) } // less than or equal -func (r Rat) Mul(r2 Rat) Rat { return Rat{new(big.Rat).Mul(r.Rat, r2.Rat)} } // Mul - multiplication -func (r Rat) Quo(r2 Rat) Rat { return Rat{new(big.Rat).Quo(r.Rat, r2.Rat)} } // Quo - quotient -func (r Rat) Add(r2 Rat) Rat { return Rat{new(big.Rat).Add(r.Rat, r2.Rat)} } // Add - addition -func (r Rat) Sub(r2 Rat) Rat { return Rat{new(big.Rat).Sub(r.Rat, r2.Rat)} } // Sub - subtraction -func (r Rat) String() string { return r.Rat.String() } -func (r Rat) FloatString() string { return r.Rat.FloatString(10) } // a human-friendly string format. The last digit is rounded to nearest, with halves rounded away from zero. +func (d Decimal) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero +func (d Decimal) Equal(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 0 } +func (d Decimal) GT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than +func (d Decimal) GTE(d2.Int) bool { return !d.LT(d2) } // greater than or equal +func (d Decimal) LT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than +func (d Decimal) LTE(d2.Int) bool { return !d.GT(d2) } // less than or equal +func (d Decimal) Add(d2.Int) Decimal { return Decimal{new(big.Int).Add(d.Int, d2.Int)} } // addition +func (d Decimal) Sub(d2.Int) Decimal { return Decimal{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction + +// multiplication +func (d Decimal) Mul(d2.Int) Decimal { + mul := new(big.Int).Mul(d.Int, d2.Int) + chopped := BankerRoundChop(mul, Precision) + return Decimal{chopped} +} + +// quotient +func (d Decimal) Quo(d2.Int) Decimal { + mul := new(big.Int).Mul(new(big.Int).Mul( // multiple precision twice + d.Int, *precisionInt), *precisionInt) + + quo := Decimal{new(big.Int).Quo(mul, d2.Int)} + chopped := BankerRoundChop(quo, Precision) + return Decimal{chopped} +} + +func (d Decimal) String() string { + str := d.Int.String() + placement := len(str) - precision + return str[:placement] + "." + str[placement:] +} var ( zero = big.NewInt(0) @@ -149,93 +181,105 @@ var ( ten = big.NewInt(10) ) -// evaluate the rational using bankers rounding -func (r Rat) EvaluateBig() *big.Int { +// ____ +// __| |__ "chop 'em +// ` \ round!" +// ___|| ~ _ -bankers +// | | __ +// | | | __|__|__ +// |_____: / | $$$ | +// |________| + +// chop of n digits, and banker round the digits being chopped off +// Examples: +// BankerRoundChop(1005, 1) = 100 +// BankerRoundChop(1015, 1) = 102 +// BankerRoundChop(1500, 3) = 2 +func BankerRoundChop(d *big.Int, n int64) *big.Int { + + // get the trucated quotient and remainder + quo, rem, prec := big.NewInt(0), big.NewInt(0), *precisionInt() + quo, rem := quo.Int.QuoRem(d, prec, rem) + + if rem.Sign == 0 { // remainder is zero + return Decimal{quo} + } - num := r.Rat.Num() - denom := r.Rat.Denom() + fiveLine := big.NewInt(5 * len(rem.String())) // ex. 1234 -> 5000 - d, rem := new(big.Int), new(big.Int) - d.QuoRem(num, denom, rem) - if rem.Cmp(zero) == 0 { // is the remainder zero - return d - } + switch rem.Cmp(fiveLine) { + case -1: + return Decimal{quo} + case 1: + return Decimal{quo.Add(big.NewInt(1))} - // evaluate the remainder using bankers rounding - tenNum := new(big.Int).Mul(num, ten) - tenD := new(big.Int).Mul(d, ten) - remainderDigit := new(big.Int).Sub(new(big.Int).Quo(tenNum, denom), tenD) // get the first remainder digit - isFinalDigit := (new(big.Int).Rem(tenNum, denom).Cmp(zero) == 0) // is this the final digit in the remainder? - - switch { - case isFinalDigit && (remainderDigit.Cmp(five) == 0 || remainderDigit.Cmp(nFive) == 0): - dRem2 := new(big.Int).Rem(d, two) - return new(big.Int).Add(d, dRem2) // always rounds to the even number - case remainderDigit.Cmp(five) != -1: //remainderDigit >= 5: - d.Add(d, one) - case remainderDigit.Cmp(nFive) != 1: //remainderDigit <= -5: - d.Sub(d, one) - } - return d -} + default: // bankers rounding must take place + str := quo.String() + finalDig, err := strconv.Atoi(string(str[len(str)])) + if err != nil { + panic(err) + } -// RoundInt64 rounds the rational using bankers rounding -func (r Rat) RoundInt64() int64 { - return r.EvaluateBig().Int64() + // always round to an even number + if finalDig == 0 || finalDig == 2 || finalDig == 4 || + finalDig == 6 || finalDig == 8 { + return Decimal{quo} + } + return Decimal{quo.Add(big.NewInt(1))} + } } -// RoundInt round the rational using bankers rounding -func (r Rat) RoundInt() Int { - return NewIntFromBigInt(r.EvaluateBig()) +// RoundInt64 rounds the decimal using bankers rounding +func (d Decimal) RoundInt64() int64 { + return d.BankerRoundChop(precision).Int64() } -// round Rat with the provided precisionFactor -func (r Rat) Round(precisionFactor int64) Rat { - rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))} - return Rat{big.NewRat(rTen.RoundInt64(), precisionFactor)} +// RoundInt round the decimal using bankers rounding +func (d Decimal) RoundInt() Int { + return d.BankerRoundChop(precision).Int } // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string -func (r Rat) ToLeftPadded(totalDigits int8) string { - intStr := r.EvaluateBig().String() +func (d Decimal) ToLeftPadded(totalDigits int8) string { + intStr := d.Int.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) } //___________________________________________________________________________________ -//Wraps r.MarshalText(). -func (r Rat) MarshalAmino() (string, error) { - if r.Rat == nil { - r.Rat = new(big.Rat) +// wraps d.MarshalText() +func (d Decimal) MarshalAmino() (string, error) { + if d.Int == nil { + d.Int = new(big.Int) } - bz, err := r.Rat.MarshalText() + bz, err := d.Int.MarshalText() return string(bz), err } -// Requires a valid JSON string - strings quotes and calls UnmarshalText -func (r *Rat) UnmarshalAmino(text string) (err error) { - tempRat := big.NewRat(0, 1) - err = tempRat.UnmarshalText([]byte(text)) +// requires a valid JSON string - strings quotes and calls UnmarshalText +func (d *Decimal) UnmarshalAmino(text string) (err error) { + tempInt := big.NewInt(0) + err = tempInt.UnmarshalText([]byte(text)) if err != nil { return err } - r.Rat = tempRat + d.Int = tempInt return nil } //___________________________________________________________________________________ // helpers -// test if two rat arrays are equal -func RatsEqual(r1s, r2s []Rat) bool { - if len(r1s) != len(r2s) { +// test if two decimal arrays are equal +func DecsEqual(d1s, d2s []Decimal) bool { + if len(d1s) != len(d2s) { return false } - for i, r1 := range r1s { - if !r1.Equal(r2s[i]) { + for i, d1 := range d1s { + if !d1.Equal(d2s[i]) { return false } } @@ -243,14 +287,14 @@ func RatsEqual(r1s, r2s []Rat) bool { } // intended to be used with require/assert: require.True(RatEq(...)) -func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { +func DecEq(t *testing.T, exp, got Decimal) (*testing.T, bool, string, Decimal, Decimal) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } -// minimum rational between two -func MinRat(r1, r2 Rat) Rat { - if r1.LT(r2) { - return r1 +// minimum decimal between two +func MinDec(d1, d2.Int) Decimal { + if d1.LT(d2) { + return d1 } - return r2 + return d2 } From e4e78b467266301463da04df5c15921d81d948a7 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Jul 2018 22:54:23 -0400 Subject: [PATCH 04/50] decimal complete, untested --- types/{decimal => }/decimal.go | 101 +++++++--------------------- types/{decimal => }/decimal_test.go | 2 +- types/types.go | 4 -- 3 files changed, 24 insertions(+), 83 deletions(-) rename types/{decimal => }/decimal.go (69%) rename types/{decimal => }/decimal_test.go (99%) delete mode 100644 types/types.go diff --git a/types/decimal/decimal.go b/types/decimal.go similarity index 69% rename from types/decimal/decimal.go rename to types/decimal.go index de8649c81b10..6f404e91015e 100644 --- a/types/decimal/decimal.go +++ b/types/decimal.go @@ -1,4 +1,4 @@ -package decimal +package types import ( "fmt" @@ -18,8 +18,7 @@ type Decimal struct { const Precision = 10 func precisionInt() big.Int { - p := big.NewInt(1) - return *p.Exp(big.NewInt(1), big.NewInt(precision), nil) + return new(big.Int).Exp(big.NewInt(1), big.NewInt(precision), nil) } // nolint - common values @@ -27,40 +26,27 @@ func ZeroDec() Decimal { return Decimal{big.NewInt(0)} } func OneDec() Decimal { return Decimal{&precisionInt} } // create a new Decimal from integer assuming whole numbers -func NewDecimalFromInt(i int64) Decimal { +func NewDecimalFromInt64(i int64) Decimal { return Decimal{ new(big.Int).Mul(big.NewInt(i), precisionInt()), } } -// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxx XXX -func getNumeratorDenominator(str []string, prec int) (numerator string, denom int64, err Error) { - switch len(str) { - case 1: - if len(str[0]) == 0 { - return "", 0, ErrUnknownRequest("not a decimal string") - } - numerator = str[0] - return numerator, 1, nil - case 2: - if len(str[0]) == 0 || len(str[1]) == 0 { - return "", 0, ErrUnknownRequest("not a decimal string") - } - if len(str[1]) > prec { - return "", 0, ErrUnknownRequest("string has too many decimals") - } - numerator = str[0] + str[1] - len := int64(len(str[1])) - denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() - return numerator, denom, nil - default: - return "", 0, ErrUnknownRequest("not a decimal string") +// create a new Decimal from big integer assuming whole numbers +func NewDecFromBigInt(i *big.Int) Decimal { + return Decimal{ + new(big.Int).Mul(i, precisionInt()), } } -// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxx XXX -// create a decimal from decimal string or integer string -// precision is the number of values after the decimal point which should be read +// create a new Decimal from big integer assuming whole numbers +func NewDecFromInt(i Int) Decimal { + return Decimal{ + new(big.Int).Mul(i.BigInt(), precisionInt()), + } +} + +// create a decimal from a decimal string (ex. "1234.5678") func NewDecimalFromStr(str string) (f Decimal, err Error) { if len(decimalStr) == 0 { return f, ErrUnknownRequest("decimal string is empty") @@ -86,57 +72,16 @@ func NewDecimalFromStr(str string) (f Decimal, err Error) { return f, ErrUnknownRequest("too much precision in decimal") } - numStr, denom, err := getNumeratorDenominator(str, prec) - if err != nil { - return f, err - } - - num, errConv := strconv.Atoi(numStr) - if errConv != nil && strings.HasSuffix(errConv.Error(), "value out of range") { - // resort to big int, don't make this default option for efficiency - numBig, success := new(big.Int).SetString(numStr, 10) - if success != true { - return f, ErrUnknownRequest("not a decimal string") - } - - if neg { - numBig.Neg(numBig) - } - - return NewDecFromBigInt(numBig, big.NewInt(denom)), nil - } else if errConv != nil { - return f, ErrUnknownRequest("not a decimal string") - } - - if neg { - num *= -1 - } + // add some extra zero's to correct to the precision factor + zerosToAdd := precision - lenDecimals + zeros := fmt.Sprintf(`%0s`+zerosToAdd, "") + combinedStr = combinedStr + zeros - return NewInt(int64(num), denom), nil -} - -// NewDecFromBigInt constructs Decimal from big.Int -func NewDecFromBigInt(num *big.Int, denom ...*big.Int) Decimal { - switch len(denom) { - case 0: - return Decimal{new(big.Int).SetInt(num)} - case 1: - return Decimal{new(big.Int).SetFrac(num, denom[0])} - default: - panic("improper use of NewDecFromBigInt, can only have one denominator") - } -} - -// NewDecFromInt constructs Decimal from Int -func NewDecFromInt(num Int, denom ...Int) Decimal { - switch len(denom) { - case 0: - return Decimal{new(big.Int).SetInt(num.BigInt())} - case 1: - return Decimal{new(big.Int).SetFrac(num.BigInt(), denom[0].BigInt())} - default: - panic("improper use of NewDecFromBigInt, can only have one denominator") + combined, ok := new(big.Int).SetString(combinedStr, 10) + if !ok { + return f, ErrUnknownRequest("bad string to integer conversion") } + return combined } //nolint diff --git a/types/decimal/decimal_test.go b/types/decimal_test.go similarity index 99% rename from types/decimal/decimal_test.go rename to types/decimal_test.go index 8b02559720e3..5ca1ac9c6e5a 100644 --- a/types/decimal/decimal_test.go +++ b/types/decimal_test.go @@ -1,4 +1,4 @@ -package decimal +package types import ( "math/big" diff --git a/types/types.go b/types/types.go deleted file mode 100644 index bb320d902185..000000000000 --- a/types/types.go +++ /dev/null @@ -1,4 +0,0 @@ -// nolint -package types - -// aliases From 206ed8b66fd254208c38f8c7d587fe5d0d4a0759 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Jul 2018 23:38:53 -0400 Subject: [PATCH 05/50] fixing tests --- types/decimal.go | 126 +++++----- types/decimal_test.go | 560 +++++++++++++++++++++--------------------- 2 files changed, 345 insertions(+), 341 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 6f404e91015e..fe56982d1a65 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -8,9 +8,9 @@ import ( "testing" ) -// NOTE: never use new(Decimal) or else we will panic unmarshalling into the +// NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int -type Decimal struct { +type Dec struct { *big.Int `json:Int""` } @@ -18,36 +18,49 @@ type Decimal struct { const Precision = 10 func precisionInt() big.Int { - return new(big.Int).Exp(big.NewInt(1), big.NewInt(precision), nil) + return new(big.Int).Exp(big.NewInt(1), big.NewInt(Precision), nil) } // nolint - common values -func ZeroDec() Decimal { return Decimal{big.NewInt(0)} } -func OneDec() Decimal { return Decimal{&precisionInt} } +func ZeroDec() Dec { return Dec{big.NewInt(0)} } +func OneDec() Dec { return Dec{&precisionInt} } -// create a new Decimal from integer assuming whole numbers -func NewDecimalFromInt64(i int64) Decimal { - return Decimal{ - new(big.Int).Mul(big.NewInt(i), precisionInt()), +// get the precision multiplier +func precisionMultiplier(prec int64) *big.Int { + if prec > Precision { + panic("too much precision") } + zerosToAdd := Precision - prec + multplier := new(big.Int).Exp(big.NewInt(1), big.NewInt(zerosToAdd), nil) + return multiplier } -// create a new Decimal from big integer assuming whole numbers -func NewDecFromBigInt(i *big.Int) Decimal { - return Decimal{ - new(big.Int).Mul(i, precisionInt()), +// create a new Dec from integer assuming whole numbers +// CONTRACT: prec !> Precision +func NewDec(i, prec int64) Dec { + return Dec{ + new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), } } -// create a new Decimal from big integer assuming whole numbers -func NewDecFromInt(i Int) Decimal { - return Decimal{ - new(big.Int).Mul(i.BigInt(), precisionInt()), +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec !> Precision +func NewDecFromBigInt(i *big.Int, prec int64) Dec { + return Dec{ + new(big.Int).Mul(i, precisionMultiplier(prec)), + } +} + +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec !> Precision +func NewDecFromInt(i Int, prec int64) Dec { + return Dec{ + new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), } } // create a decimal from a decimal string (ex. "1234.5678") -func NewDecimalFromStr(str string) (f Decimal, err Error) { +func NewDecFromStr(str string) (f Dec, err Error) { if len(decimalStr) == 0 { return f, ErrUnknownRequest("decimal string is empty") } @@ -60,20 +73,20 @@ func NewDecimalFromStr(str string) (f Decimal, err Error) { } str := strings.Split(decimalStr, ".") - lenDecimals := 0 + lenDecs := 0 combinedStr := str[0] if len(str) == 2 { - lenDecimals = len(str[1]) + lenDecs = len(str[1]) } else if len(str) > 2 { return f, ErrUnknownRequest("too many periods to be a decimal string") } - if lenDecimals > precision { - return f, ErrUnknownRequest("too much precision in decimal") + if lenDecs > Precision { + return f, ErrUnknownRequest("too much Precision in decimal") } - // add some extra zero's to correct to the precision factor - zerosToAdd := precision - lenDecimals + // add some extra zero's to correct to the Precision factor + zerosToAdd := Precision - lenDecs zeros := fmt.Sprintf(`%0s`+zerosToAdd, "") combinedStr = combinedStr + zeros @@ -85,35 +98,38 @@ func NewDecimalFromStr(str string) (f Decimal, err Error) { } //nolint -func (d Decimal) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero -func (d Decimal) Equal(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 0 } -func (d Decimal) GT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than -func (d Decimal) GTE(d2.Int) bool { return !d.LT(d2) } // greater than or equal -func (d Decimal) LT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than -func (d Decimal) LTE(d2.Int) bool { return !d.GT(d2) } // less than or equal -func (d Decimal) Add(d2.Int) Decimal { return Decimal{new(big.Int).Add(d.Int, d2.Int)} } // addition -func (d Decimal) Sub(d2.Int) Decimal { return Decimal{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction +func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero +func (d Dec) Equal(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 0 } +func (d Dec) GT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than +func (d Dec) GTE(d2.Int) bool { return !d.LT(d2) } // greater than or equal +func (d Dec) LT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than +func (d Dec) LTE(d2.Int) bool { return !d.GT(d2) } // less than or equal +func (d Dec) Add(d2.Int) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition +func (d Dec) Sub(d2.Int) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction // multiplication -func (d Decimal) Mul(d2.Int) Decimal { +func (d Dec) Mul(d2.Int) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) chopped := BankerRoundChop(mul, Precision) - return Decimal{chopped} + return Dec{chopped} } // quotient -func (d Decimal) Quo(d2.Int) Decimal { - mul := new(big.Int).Mul(new(big.Int).Mul( // multiple precision twice +func (d Dec) Quo(d2.Int) Dec { + mul := new(big.Int).Mul(new(big.Int).Mul( // multiple Precision twice d.Int, *precisionInt), *precisionInt) - quo := Decimal{new(big.Int).Quo(mul, d2.Int)} + quo := Dec{new(big.Int).Quo(mul, d2.Int)} chopped := BankerRoundChop(quo, Precision) - return Decimal{chopped} + return Dec{chopped} } -func (d Decimal) String() string { +func (d Dec) String() string { str := d.Int.String() - placement := len(str) - precision + placement := len(str) - Precision + if placement < 0 { + panic("too few decimal digits") + } return str[:placement] + "." + str[placement:] } @@ -147,16 +163,16 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { quo, rem := quo.Int.QuoRem(d, prec, rem) if rem.Sign == 0 { // remainder is zero - return Decimal{quo} + return Dec{quo} } fiveLine := big.NewInt(5 * len(rem.String())) // ex. 1234 -> 5000 switch rem.Cmp(fiveLine) { case -1: - return Decimal{quo} + return Dec{quo} case 1: - return Decimal{quo.Add(big.NewInt(1))} + return Dec{quo.Add(big.NewInt(1))} default: // bankers rounding must take place str := quo.String() @@ -168,25 +184,25 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { // always round to an even number if finalDig == 0 || finalDig == 2 || finalDig == 4 || finalDig == 6 || finalDig == 8 { - return Decimal{quo} + return Dec{quo} } - return Decimal{quo.Add(big.NewInt(1))} + return Dec{quo.Add(big.NewInt(1))} } } // RoundInt64 rounds the decimal using bankers rounding -func (d Decimal) RoundInt64() int64 { - return d.BankerRoundChop(precision).Int64() +func (d Dec) RoundInt64() int64 { + return d.BankerRoundChop(Precision).Int64() } // RoundInt round the decimal using bankers rounding -func (d Decimal) RoundInt() Int { - return d.BankerRoundChop(precision).Int +func (d Dec) RoundInt() Int { + return d.BankerRoundChop(Precision).Int } // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string -func (d Decimal) ToLeftPadded(totalDigits int8) string { +func (d Dec) ToLeftPadded(totalDigits int8) string { intStr := d.Int.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) @@ -195,7 +211,7 @@ func (d Decimal) ToLeftPadded(totalDigits int8) string { //___________________________________________________________________________________ // wraps d.MarshalText() -func (d Decimal) MarshalAmino() (string, error) { +func (d Dec) MarshalAmino() (string, error) { if d.Int == nil { d.Int = new(big.Int) } @@ -204,7 +220,7 @@ func (d Decimal) MarshalAmino() (string, error) { } // requires a valid JSON string - strings quotes and calls UnmarshalText -func (d *Decimal) UnmarshalAmino(text string) (err error) { +func (d *Dec) UnmarshalAmino(text string) (err error) { tempInt := big.NewInt(0) err = tempInt.UnmarshalText([]byte(text)) if err != nil { @@ -218,7 +234,7 @@ func (d *Decimal) UnmarshalAmino(text string) (err error) { // helpers // test if two decimal arrays are equal -func DecsEqual(d1s, d2s []Decimal) bool { +func DecsEqual(d1s, d2s []Dec) bool { if len(d1s) != len(d2s) { return false } @@ -232,12 +248,12 @@ func DecsEqual(d1s, d2s []Decimal) bool { } // intended to be used with require/assert: require.True(RatEq(...)) -func DecEq(t *testing.T, exp, got Decimal) (*testing.T, bool, string, Decimal, Decimal) { +func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } // minimum decimal between two -func MinDec(d1, d2.Int) Decimal { +func MinDec(d1, d2.Int) Dec { if d1.LT(d2) { return d1 } diff --git a/types/decimal_test.go b/types/decimal_test.go index 5ca1ac9c6e5a..aaac6b488309 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -4,52 +4,40 @@ import ( "math/big" "testing" - wire "github.com/cosmos/cosmos-sdk/wire" "github.com/stretchr/testify/require" ) -func TestNew(t *testing.T) { - require.Equal(t, NewRat(1), NewRat(1, 1)) - require.Equal(t, NewRat(100), NewRat(100, 1)) - require.Equal(t, NewRat(-1), NewRat(-1, 1)) - require.Equal(t, NewRat(-100), NewRat(-100, 1)) - require.Equal(t, NewRat(0), NewRat(0, 1)) - - // do not allow for more than 2 variables - require.Panics(t, func() { NewRat(1, 1, 1) }) -} - -func TestNewFromDecimal(t *testing.T) { - largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10) +func TestNewDecFromStr(t *testing.T) { + largeBigInt, success := new(big.Int).SetString("3144605511029693144278234343371835", 10) require.True(t, success) tests := []struct { decimalStr string expErr bool - exp Rat + exp Dec }{ - {"", true, Rat{}}, - {"0", false, NewRat(0)}, - {"1", false, NewRat(1)}, - {"1.1", false, NewRat(11, 10)}, - {"0.75", false, NewRat(3, 4)}, - {"0.8", false, NewRat(4, 5)}, - {"0.11111", true, NewRat(1111, 10000)}, - {"628240629832763.5738930323617075341", true, NewRat(3141203149163817869, 5000)}, - {"621947210595948537540277652521.5738930323617075341", - true, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, - {"628240629832763.5738", false, NewRat(3141203149163817869, 5000)}, - {"621947210595948537540277652521.5738", - false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, - {".", true, Rat{}}, - {".0", true, Rat{}}, - {"1.", true, Rat{}}, - {"foobar", true, Rat{}}, - {"0.foobar", true, Rat{}}, - {"0.foobar.", true, Rat{}}, + {"", true, Dec{}}, + {"0", false, NewDec(0, 0)}, + {"1", false, NewDec(1, 0)}, + {"1.1", false, NewDec(11, 2)}, + {"0.75", false, NewDec(75, 2)}, + {"0.8", false, NewDec(8, 1)}, + {"0.11111", true, NewDec(1111, 5)}, + {"314460551102969.3144278234343371835", true, NewDec(3141203149163817869, 0)}, + {"314460551102969314427823434337.1835718092488231350", + true, NewDecFromBigInt(largeBigInt, big.NewInt(4))}, + {"314460551102969.3144", false, NewDec(31412031491638178693144, 4)}, + {"314460551102969314427823434337.1835", + false, NewDecFromBigInt(largeBigInt, 4)}, + {".", true, Dec{}}, + {".0", false, NewDec(0, 0)}, + {"1.", false, NewDec(1, 0)}, + {"foobar", true, Dec{}}, + {"0.foobar", true, Dec{}}, + {"0.foobar.", true, Dec{}}, } for tcIndex, tc := range tests { - res, err := NewRatFromDecimal(tc.decimalStr, 4) + res, err := NewDecFromDec(tc.decimalStr, 4) if tc.expErr { require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex) } else { @@ -58,262 +46,262 @@ func TestNewFromDecimal(t *testing.T) { } // negative tc - res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) + res, err = NewDecFromDec("-"+tc.decimalStr, 4) if tc.expErr { require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex) } else { require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex) - require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex) - } - } -} - -func TestEqualities(t *testing.T) { - tests := []struct { - r1, r2 Rat - gt, lt, eq bool - }{ - {NewRat(0), NewRat(0), false, false, true}, - {NewRat(0, 100), NewRat(0, 10000), false, false, true}, - {NewRat(100), NewRat(100), false, false, true}, - {NewRat(-100), NewRat(-100), false, false, true}, - {NewRat(-100, -1), NewRat(100), false, false, true}, - {NewRat(-1, 1), NewRat(1, -1), false, false, true}, - {NewRat(1, -1), NewRat(-1, 1), false, false, true}, - {NewRat(3, 7), NewRat(3, 7), false, false, true}, - - {NewRat(0), NewRat(3, 7), false, true, false}, - {NewRat(0), NewRat(100), false, true, false}, - {NewRat(-1), NewRat(3, 7), false, true, false}, - {NewRat(-1), NewRat(100), false, true, false}, - {NewRat(1, 7), NewRat(100), false, true, false}, - {NewRat(1, 7), NewRat(3, 7), false, true, false}, - {NewRat(-3, 7), NewRat(-1, 7), false, true, false}, - - {NewRat(3, 7), NewRat(0), true, false, false}, - {NewRat(100), NewRat(0), true, false, false}, - {NewRat(3, 7), NewRat(-1), true, false, false}, - {NewRat(100), NewRat(-1), true, false, false}, - {NewRat(100), NewRat(1, 7), true, false, false}, - {NewRat(3, 7), NewRat(1, 7), true, false, false}, - {NewRat(-1, 7), NewRat(-3, 7), true, false, false}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.gt, tc.r1.GT(tc.r2), "GT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.lt, tc.r1.LT(tc.r2), "LT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.eq, tc.r1.Equal(tc.r2), "equality result is incorrect, tc #%d", tcIndex) - } - -} - -func TestArithmetic(t *testing.T) { - tests := []struct { - r1, r2 Rat - resMul, resDiv, resAdd, resSub Rat - }{ - // r1 r2 MUL DIV ADD SUB - {NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0)}, - {NewRat(1), NewRat(0), NewRat(0), NewRat(0), NewRat(1), NewRat(1)}, - {NewRat(0), NewRat(1), NewRat(0), NewRat(0), NewRat(1), NewRat(-1)}, - {NewRat(0), NewRat(-1), NewRat(0), NewRat(0), NewRat(-1), NewRat(1)}, - {NewRat(-1), NewRat(0), NewRat(0), NewRat(0), NewRat(-1), NewRat(-1)}, - - {NewRat(1), NewRat(1), NewRat(1), NewRat(1), NewRat(2), NewRat(0)}, - {NewRat(-1), NewRat(-1), NewRat(1), NewRat(1), NewRat(-2), NewRat(0)}, - {NewRat(1), NewRat(-1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(2)}, - {NewRat(-1), NewRat(1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(-2)}, - - {NewRat(3), NewRat(7), NewRat(21), NewRat(3, 7), NewRat(10), NewRat(-4)}, - {NewRat(2), NewRat(4), NewRat(8), NewRat(1, 2), NewRat(6), NewRat(-2)}, - {NewRat(100), NewRat(100), NewRat(10000), NewRat(1), NewRat(200), NewRat(0)}, - - {NewRat(3, 2), NewRat(3, 2), NewRat(9, 4), NewRat(1), NewRat(3), NewRat(0)}, - {NewRat(3, 7), NewRat(7, 3), NewRat(1), NewRat(9, 49), NewRat(58, 21), NewRat(-40, 21)}, - {NewRat(1, 21), NewRat(11, 5), NewRat(11, 105), NewRat(5, 231), NewRat(236, 105), NewRat(-226, 105)}, - {NewRat(-21), NewRat(3, 7), NewRat(-9), NewRat(-49), NewRat(-144, 7), NewRat(-150, 7)}, - {NewRat(100), NewRat(1, 7), NewRat(100, 7), NewRat(700), NewRat(701, 7), NewRat(699, 7)}, - } - - for tcIndex, tc := range tests { - require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - - if tc.r2.Num().IsZero() { // panic for divide by zero - require.Panics(t, func() { tc.r1.Quo(tc.r2) }) - } else { - require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) + require.True(t, res.Equal(tc.exp.Mul(NewDec(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex) } } } -func TestEvaluate(t *testing.T) { - tests := []struct { - r1 Rat - res int64 - }{ - {NewRat(0), 0}, - {NewRat(1), 1}, - {NewRat(1, 4), 0}, - {NewRat(1, 2), 0}, - {NewRat(3, 4), 1}, - {NewRat(5, 6), 1}, - {NewRat(3, 2), 2}, - {NewRat(5, 2), 2}, - {NewRat(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {NewRat(17, 11), 2}, // 1.545 - {NewRat(5, 11), 0}, - {NewRat(16, 11), 1}, - {NewRat(113, 12), 9}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v. tc #%d", tc.r1, tcIndex) - require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v. tc #%d", tc.r1.Mul(NewRat(-1)), tcIndex) - } -} - -func TestRound(t *testing.T) { - many3 := "333333333333333333333333333333333333333333333" - many7 := "777777777777777777777777777777777777777777777" - big3, worked := new(big.Int).SetString(many3, 10) - require.True(t, worked) - big7, worked := new(big.Int).SetString(many7, 10) - require.True(t, worked) - - tests := []struct { - r, res Rat - precFactor int64 - }{ - {NewRat(333, 777), NewRat(429, 1000), 1000}, - {Rat{new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000}, - {Rat{new(big.Rat).SetFrac(big3, big7)}, Rat{big.NewRat(4285714286, 10000000000)}, 10000000000}, - {NewRat(1, 2), NewRat(1, 2), 1000}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r, "incorrect rounding, tc #%d", tcIndex) - negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1)) - require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex) - } -} - -func TestToLeftPadded(t *testing.T) { - tests := []struct { - rat Rat - digits int8 - res string - }{ - {NewRat(100, 3), 8, "00000033"}, - {NewRat(1, 3), 8, "00000000"}, - {NewRat(100, 2), 8, "00000050"}, - {NewRat(1000, 3), 8, "00000333"}, - {NewRat(1000, 3), 12, "000000000333"}, - } - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex) - } -} - -var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec - -func TestZeroSerializationJSON(t *testing.T) { - r := NewRat(0, 1) - err := cdc.UnmarshalJSON([]byte(`"0/1"`), &r) - require.Nil(t, err) - err = cdc.UnmarshalJSON([]byte(`"0/0"`), &r) - require.NotNil(t, err) - err = cdc.UnmarshalJSON([]byte(`"1/0"`), &r) - require.NotNil(t, err) - err = cdc.UnmarshalJSON([]byte(`"{}"`), &r) - require.NotNil(t, err) -} - -func TestSerializationText(t *testing.T) { - r := NewRat(1, 3) - - bz, err := r.MarshalText() - require.NoError(t, err) - - var r2 = Rat{new(big.Rat)} - err = r2.UnmarshalText(bz) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -func TestSerializationGoWireJSON(t *testing.T) { - r := NewRat(1, 3) - bz, err := cdc.MarshalJSON(r) - require.NoError(t, err) - - var r2 Rat - err = cdc.UnmarshalJSON(bz, &r2) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -func TestSerializationGoWireBinary(t *testing.T) { - r := NewRat(1, 3) - bz, err := cdc.MarshalBinary(r) - require.NoError(t, err) - - var r2 Rat - err = cdc.UnmarshalBinary(bz, &r2) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -type testEmbedStruct struct { - Field1 string `json:"f1"` - Field2 int `json:"f2"` - Field3 Rat `json:"f3"` -} - -func TestEmbeddedStructSerializationGoWire(t *testing.T) { - obj := testEmbedStruct{"foo", 10, NewRat(1, 3)} - bz, err := cdc.MarshalJSON(obj) - require.Nil(t, err) - - var obj2 testEmbedStruct - err = cdc.UnmarshalJSON(bz, &obj2) - require.Nil(t, err) - - require.Equal(t, obj.Field1, obj2.Field1) - require.Equal(t, obj.Field2, obj2.Field2) - require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) -} - -func TestRatsEqual(t *testing.T) { - tests := []struct { - r1s, r2s []Rat - eq bool - }{ - {[]Rat{NewRat(0)}, []Rat{NewRat(0)}, true}, - {[]Rat{NewRat(0)}, []Rat{NewRat(1)}, false}, - {[]Rat{NewRat(0)}, []Rat{}, false}, - {[]Rat{NewRat(0), NewRat(1)}, []Rat{NewRat(0), NewRat(1)}, true}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1), NewRat(0)}, true}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(0), NewRat(1)}, false}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1)}, false}, - {[]Rat{NewRat(1), NewRat(2)}, []Rat{NewRat(2), NewRat(4)}, false}, - {[]Rat{NewRat(3), NewRat(18)}, []Rat{NewRat(1), NewRat(6)}, false}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s), "equality of rational arrays is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s), "equality of rational arrays is incorrect (converse), tc #%d", tcIndex) - } - -} - -func TestStringOverflow(t *testing.T) { - // two random 64 bit primes - rat1 := NewRat(5164315003622678713, 4389711697696177267) - rat2 := NewRat(-3179849666053572961, 8459429845579852627) - rat3 := rat1.Add(rat2) - require.Equal(t, - "29728537197630860939575850336935951464/37134458148982045574552091851127630409", - rat3.String(), - ) -} +//func TestEqualities(t *testing.T) { +//tests := []struct { +//d1, d2 Dec +//gt, lt, eq bool +//}{ +//{NewDec(0), NewDec(0), false, false, true}, +//{NewDec(0, 100), NewDec(0, 10000), false, false, true}, +//{NewDec(100), NewDec(100), false, false, true}, +//{NewDec(-100), NewDec(-100), false, false, true}, +//{NewDec(-100, -1), NewDec(100), false, false, true}, +//{NewDec(-1, 1), NewDec(1, -1), false, false, true}, +//{NewDec(1, -1), NewDec(-1, 1), false, false, true}, +//{NewDec(3, 7), NewDec(3, 7), false, false, true}, + +//{NewDec(0), NewDec(3, 7), false, true, false}, +//{NewDec(0), NewDec(100), false, true, false}, +//{NewDec(-1), NewDec(3, 7), false, true, false}, +//{NewDec(-1), NewDec(100), false, true, false}, +//{NewDec(1, 7), NewDec(100), false, true, false}, +//{NewDec(1, 7), NewDec(3, 7), false, true, false}, +//{NewDec(-3, 7), NewDec(-1, 7), false, true, false}, + +//{NewDec(3, 7), NewDec(0), true, false, false}, +//{NewDec(100), NewDec(0), true, false, false}, +//{NewDec(3, 7), NewDec(-1), true, false, false}, +//{NewDec(100), NewDec(-1), true, false, false}, +//{NewDec(100), NewDec(1, 7), true, false, false}, +//{NewDec(3, 7), NewDec(1, 7), true, false, false}, +//{NewDec(-1, 7), NewDec(-3, 7), true, false, false}, +//} + +//for tcIndex, tc := range tests { +//require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc #%d", tcIndex) +//require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc #%d", tcIndex) +//require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc #%d", tcIndex) +//} + +//} + +//func TestArithmetic(t *testing.T) { +//tests := []struct { +//d1, d2 Dec +//resMul, resDiv, resAdd, resSub Dec +//}{ +//// d1 d2 MUL DIV ADD SUB +//{NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0)}, +//{NewDec(1), NewDec(0), NewDec(0), NewDec(0), NewDec(1), NewDec(1)}, +//{NewDec(0), NewDec(1), NewDec(0), NewDec(0), NewDec(1), NewDec(-1)}, +//{NewDec(0), NewDec(-1), NewDec(0), NewDec(0), NewDec(-1), NewDec(1)}, +//{NewDec(-1), NewDec(0), NewDec(0), NewDec(0), NewDec(-1), NewDec(-1)}, + +//{NewDec(1), NewDec(1), NewDec(1), NewDec(1), NewDec(2), NewDec(0)}, +//{NewDec(-1), NewDec(-1), NewDec(1), NewDec(1), NewDec(-2), NewDec(0)}, +//{NewDec(1), NewDec(-1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(2)}, +//{NewDec(-1), NewDec(1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(-2)}, + +//{NewDec(3), NewDec(7), NewDec(21), NewDec(3, 7), NewDec(10), NewDec(-4)}, +//{NewDec(2), NewDec(4), NewDec(8), NewDec(1, 2), NewDec(6), NewDec(-2)}, +//{NewDec(100), NewDec(100), NewDec(10000), NewDec(1), NewDec(200), NewDec(0)}, + +//{NewDec(3, 2), NewDec(3, 2), NewDec(9, 4), NewDec(1), NewDec(3), NewDec(0)}, +//{NewDec(3, 7), NewDec(7, 3), NewDec(1), NewDec(9, 49), NewDec(58, 21), NewDec(-40, 21)}, +//{NewDec(1, 21), NewDec(11, 5), NewDec(11, 105), NewDec(5, 231), NewDec(236, 105), NewDec(-226, 105)}, +//{NewDec(-21), NewDec(3, 7), NewDec(-9), NewDec(-49), NewDec(-144, 7), NewDec(-150, 7)}, +//{NewDec(100), NewDec(1, 7), NewDec(100, 7), NewDec(700), NewDec(701, 7), NewDec(699, 7)}, +//} + +//for tcIndex, tc := range tests { +//require.True(t, tc.resMul.Equal(tc.d1.Mul(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) +//require.True(t, tc.resAdd.Equal(tc.d1.Add(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) +//require.True(t, tc.resSub.Equal(tc.d1.Sub(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) + +//if tc.d2.Num().IsZero() { // panic for divide by zero +//require.Panics(t, func() { tc.d1.Quo(tc.d2) }) +//} else { +//require.True(t, tc.resDiv.Equal(tc.d1.Quo(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) +//} +//} +//} + +//func TestEvaluate(t *testing.T) { +//tests := []struct { +//d1 Dec +//res int64 +//}{ +//{NewDec(0), 0}, +//{NewDec(1), 1}, +//{NewDec(1, 4), 0}, +//{NewDec(1, 2), 0}, +//{NewDec(3, 4), 1}, +//{NewDec(5, 6), 1}, +//{NewDec(3, 2), 2}, +//{NewDec(5, 2), 2}, +//{NewDec(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even +//{NewDec(17, 11), 2}, // 1.545 +//{NewDec(5, 11), 0}, +//{NewDec(16, 11), 1}, +//{NewDec(113, 12), 9}, +//} + +//for tcIndex, tc := range tests { +//require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc #%d", tc.d1, tcIndex) +//require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1)).RoundInt64(), "%v. tc #%d", tc.d1.Mul(NewDec(-1)), tcIndex) +//} +//} + +//func TestRound(t *testing.T) { +//many3 := "333333333333333333333333333333333333333333333" +//many7 := "777777777777777777777777777777777777777777777" +//big3, worked := new(big.Int).SetString(many3, 10) +//require.True(t, worked) +//big7, worked := new(big.Int).SetString(many7, 10) +//require.True(t, worked) + +//tests := []struct { +//d, res Dec +//precFactor int64 +//}{ +//{NewDec(333, 777), NewDec(429, 1000), 1000}, +//{Dec{new(big.Dec).SetFrac(big3, big7)}, NewDec(429, 1000), 1000}, +//{Dec{new(big.Dec).SetFrac(big3, big7)}, Dec{big.NewDec(4285714286, 10000000000)}, 10000000000}, +//{NewDec(1, 2), NewDec(1, 2), 1000}, +//} + +//for tcIndex, tc := range tests { +//require.Equal(t, tc.res, tc.d.Round(tc.precFactor), "%v", tc.d, "incorrect rounding, tc #%d", tcIndex) +//negR1, negRes := tc.d.Mul(NewDec(-1)), tc.res.Mul(NewDec(-1)) +//require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex) +//} +//} + +//func TestToLeftPadded(t *testing.T) { +//tests := []struct { +//dec Dec +//digits int8 +//res string +//}{ +//{NewDec(100, 3), 8, "00000033"}, +//{NewDec(1, 3), 8, "00000000"}, +//{NewDec(100, 2), 8, "00000050"}, +//{NewDec(1000, 3), 8, "00000333"}, +//{NewDec(1000, 3), 12, "000000000333"}, +//} +//for tcIndex, tc := range tests { +//require.Equal(t, tc.res, tc.dec.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex) +//} +//} + +//var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec + +//func TestZeroSerializationJSON(t *testing.T) { +//d := NewDec(0, 1) +//err := cdc.UnmarshalJSON([]byte(`"0/1"`), &d) +//require.Nil(t, err) +//err = cdc.UnmarshalJSON([]byte(`"0/0"`), &d) +//require.NotNil(t, err) +//err = cdc.UnmarshalJSON([]byte(`"1/0"`), &d) +//require.NotNil(t, err) +//err = cdc.UnmarshalJSON([]byte(`"{}"`), &d) +//require.NotNil(t, err) +//} + +//func TestSerializationText(t *testing.T) { +//d := NewDec(1, 3) + +//bz, err := d.MarshalText() +//require.NoError(t, err) + +//var d2 = Dec{new(big.Dec)} +//err = d2.UnmarshalText(bz) +//require.NoError(t, err) +//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +//} + +//func TestSerializationGoWireJSON(t *testing.T) { +//d := NewDec(1, 3) +//bz, err := cdc.MarshalJSON(d) +//require.NoError(t, err) + +//var d2 Dec +//err = cdc.UnmarshalJSON(bz, &d2) +//require.NoError(t, err) +//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +//} + +//func TestSerializationGoWireBinary(t *testing.T) { +//d := NewDec(1, 3) +//bz, err := cdc.MarshalBinary(d) +//require.NoError(t, err) + +//var d2 Dec +//err = cdc.UnmarshalBinary(bz, &d2) +//require.NoError(t, err) +//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +//} + +//type testEmbedStruct struct { +//Field1 string `json:"f1"` +//Field2 int `json:"f2"` +//Field3 Dec `json:"f3"` +//} + +//func TestEmbeddedStructSerializationGoWire(t *testing.T) { +//obj := testEmbedStruct{"foo", 10, NewDec(1, 3)} +//bz, err := cdc.MarshalJSON(obj) +//require.Nil(t, err) + +//var obj2 testEmbedStruct +//err = cdc.UnmarshalJSON(bz, &obj2) +//require.Nil(t, err) + +//require.Equal(t, obj.Field1, obj2.Field1) +//require.Equal(t, obj.Field2, obj2.Field2) +//require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) +//} + +//func TestDecsEqual(t *testing.T) { +//tests := []struct { +//d1s, d2s []Dec +//eq bool +//}{ +//{[]Dec{NewDec(0)}, []Dec{NewDec(0)}, true}, +//{[]Dec{NewDec(0)}, []Dec{NewDec(1)}, false}, +//{[]Dec{NewDec(0)}, []Dec{}, false}, +//{[]Dec{NewDec(0), NewDec(1)}, []Dec{NewDec(0), NewDec(1)}, true}, +//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1), NewDec(0)}, true}, +//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(0), NewDec(1)}, false}, +//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1)}, false}, +//{[]Dec{NewDec(1), NewDec(2)}, []Dec{NewDec(2), NewDec(4)}, false}, +//{[]Dec{NewDec(3), NewDec(18)}, []Dec{NewDec(1), NewDec(6)}, false}, +//} + +//for tcIndex, tc := range tests { +//require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc #%d", tcIndex) +//require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc #%d", tcIndex) +//} + +//} + +//func TestStringOverflow(t *testing.T) { +//// two random 64 bit primes +//dec1 := NewDec(5164315003622678713, 4389711697696177267) +//dec2 := NewDec(-3179849666053572961, 8459429845579852627) +//dec3 := dec1.Add(dec2) +//require.Equal(t, +//"29728537197630860939575850336935951464/37134458148982045574552091851127630409", +//dec3.String(), +//) +//} From ee627ede7729bee00cae5b7c5fa74f94eaca37d9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 00:46:11 -0400 Subject: [PATCH 06/50] decimal compile errors resolved --- types/decimal.go | 95 +++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index fe56982d1a65..722039d6149b 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -17,13 +17,13 @@ type Dec struct { // number of decimal places const Precision = 10 -func precisionInt() big.Int { +func precisionInt() *big.Int { return new(big.Int).Exp(big.NewInt(1), big.NewInt(Precision), nil) } // nolint - common values func ZeroDec() Dec { return Dec{big.NewInt(0)} } -func OneDec() Dec { return Dec{&precisionInt} } +func OneDec() Dec { return Dec{precisionInt()} } // get the precision multiplier func precisionMultiplier(prec int64) *big.Int { @@ -31,7 +31,7 @@ func precisionMultiplier(prec int64) *big.Int { panic("too much precision") } zerosToAdd := Precision - prec - multplier := new(big.Int).Exp(big.NewInt(1), big.NewInt(zerosToAdd), nil) + multiplier := new(big.Int).Exp(big.NewInt(1), big.NewInt(zerosToAdd), nil) return multiplier } @@ -61,23 +61,23 @@ func NewDecFromInt(i Int, prec int64) Dec { // create a decimal from a decimal string (ex. "1234.5678") func NewDecFromStr(str string) (f Dec, err Error) { - if len(decimalStr) == 0 { + if len(str) == 0 { return f, ErrUnknownRequest("decimal string is empty") } // first extract any negative symbol neg := false - if string(decimalStr[0]) == "-" { + if string(str[0]) == "-" { neg = true - decimalStr = decimalStr[1:] + str = str[1:] } - str := strings.Split(decimalStr, ".") + strs := strings.Split(str, ".") lenDecs := 0 - combinedStr := str[0] - if len(str) == 2 { - lenDecs = len(str[1]) - } else if len(str) > 2 { + combinedStr := strs[0] + if len(strs) == 2 { + lenDecs = len(strs[1]) + } else if len(strs) > 2 { return f, ErrUnknownRequest("too many periods to be a decimal string") } @@ -85,41 +85,44 @@ func NewDecFromStr(str string) (f Dec, err Error) { return f, ErrUnknownRequest("too much Precision in decimal") } - // add some extra zero's to correct to the Precision factor + // add some extra dzero's to correct to the Precision factor zerosToAdd := Precision - lenDecs - zeros := fmt.Sprintf(`%0s`+zerosToAdd, "") + zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "") combinedStr = combinedStr + zeros combined, ok := new(big.Int).SetString(combinedStr, 10) if !ok { return f, ErrUnknownRequest("bad string to integer conversion") } - return combined + if neg { + combined = new(big.Int).Neg(combined) + } + return Dec{combined}, nil } //nolint -func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero -func (d Dec) Equal(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 0 } -func (d Dec) GT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than -func (d Dec) GTE(d2.Int) bool { return !d.LT(d2) } // greater than or equal -func (d Dec) LT(d2.Int) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than -func (d Dec) LTE(d2.Int) bool { return !d.GT(d2) } // less than or equal -func (d Dec) Add(d2.Int) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition -func (d Dec) Sub(d2.Int) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction +func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to dzero +func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } +func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than +func (d Dec) GTE(d2 Dec) bool { return !d.LT(d2) } // greater than or equal +func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than +func (d Dec) LTE(d2 Dec) bool { return !d.GT(d2) } // less than or equal +func (d Dec) Add(d2 Dec) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition +func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction // multiplication -func (d Dec) Mul(d2.Int) Dec { +func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) chopped := BankerRoundChop(mul, Precision) return Dec{chopped} } // quotient -func (d Dec) Quo(d2.Int) Dec { +func (d Dec) Quo(d2 Dec) Dec { mul := new(big.Int).Mul(new(big.Int).Mul( // multiple Precision twice - d.Int, *precisionInt), *precisionInt) + d.Int, precisionInt()), precisionInt()) - quo := Dec{new(big.Int).Quo(mul, d2.Int)} + quo := new(big.Int).Quo(mul, d2.Int) chopped := BankerRoundChop(quo, Precision) return Dec{chopped} } @@ -134,12 +137,12 @@ func (d Dec) String() string { } var ( - zero = big.NewInt(0) - one = big.NewInt(1) - two = big.NewInt(2) - five = big.NewInt(5) - nFive = big.NewInt(-5) - ten = big.NewInt(10) + dzero = big.NewInt(0) + done = big.NewInt(1) + dtwo = big.NewInt(2) + dfive = big.NewInt(5) + dnFive = big.NewInt(-5) + dten = big.NewInt(10) ) // ____ @@ -159,20 +162,20 @@ var ( func BankerRoundChop(d *big.Int, n int64) *big.Int { // get the trucated quotient and remainder - quo, rem, prec := big.NewInt(0), big.NewInt(0), *precisionInt() - quo, rem := quo.Int.QuoRem(d, prec, rem) + quo, rem, prec := big.NewInt(0), big.NewInt(0), precisionInt() + quo, rem = quo.QuoRem(d, prec, rem) - if rem.Sign == 0 { // remainder is zero - return Dec{quo} + if rem.Sign() == 0 { // remainder is dzero + return quo } - fiveLine := big.NewInt(5 * len(rem.String())) // ex. 1234 -> 5000 + fiveLine := big.NewInt(int64(5 * len(rem.String()))) // ex. 1234 -> 5000 switch rem.Cmp(fiveLine) { case -1: - return Dec{quo} + return quo case 1: - return Dec{quo.Add(big.NewInt(1))} + return new(big.Int).Add(quo, big.NewInt(1)) default: // bankers rounding must take place str := quo.String() @@ -184,20 +187,20 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { // always round to an even number if finalDig == 0 || finalDig == 2 || finalDig == 4 || finalDig == 6 || finalDig == 8 { - return Dec{quo} + return quo } - return Dec{quo.Add(big.NewInt(1))} } + return new(big.Int).Add(quo, big.NewInt(1)) } // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - return d.BankerRoundChop(Precision).Int64() + return BankerRoundChop(d.Int, Precision).Int64() } // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return d.BankerRoundChop(Precision).Int + return NewIntFromBigInt(BankerRoundChop(d.Int, Precision)) } // TODO panic if negative or if totalDigits < len(initStr)??? @@ -233,7 +236,7 @@ func (d *Dec) UnmarshalAmino(text string) (err error) { //___________________________________________________________________________________ // helpers -// test if two decimal arrays are equal +// test if dtwo decimal arrays are equal func DecsEqual(d1s, d2s []Dec) bool { if len(d1s) != len(d2s) { return false @@ -252,8 +255,8 @@ func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } -// minimum decimal between two -func MinDec(d1, d2.Int) Dec { +// minimum decimal between dtwo +func MinDec(d1, d2 Dec) Dec { if d1.LT(d2) { return d1 } From 2f130bb731b170bb993f439b85c7fe967b199d89 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 00:54:16 -0400 Subject: [PATCH 07/50] test compile errors --- types/decimal_test.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/types/decimal_test.go b/types/decimal_test.go index aaac6b488309..0c5ae8fe9287 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -24,8 +24,7 @@ func TestNewDecFromStr(t *testing.T) { {"0.11111", true, NewDec(1111, 5)}, {"314460551102969.3144278234343371835", true, NewDec(3141203149163817869, 0)}, {"314460551102969314427823434337.1835718092488231350", - true, NewDecFromBigInt(largeBigInt, big.NewInt(4))}, - {"314460551102969.3144", false, NewDec(31412031491638178693144, 4)}, + true, NewDecFromBigInt(largeBigInt, 4)}, {"314460551102969314427823434337.1835", false, NewDecFromBigInt(largeBigInt, 4)}, {".", true, Dec{}}, @@ -37,21 +36,21 @@ func TestNewDecFromStr(t *testing.T) { } for tcIndex, tc := range tests { - res, err := NewDecFromDec(tc.decimalStr, 4) + res, err := NewDecFromStr(tc.decimalStr) if tc.expErr { - require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex) + require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { - require.Nil(t, err, tc.decimalStr, "unexpected error, tc #%d", tcIndex) - require.True(t, res.Equal(tc.exp), tc.decimalStr, "equality was incorrect, tc #%d", tcIndex) + require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + require.True(t, res.Equal(tc.exp), "equality was incorrect, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } // negative tc - res, err = NewDecFromDec("-"+tc.decimalStr, 4) + res, err = NewDecFromStr("-" + tc.decimalStr) if tc.expErr { - require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex) + require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { - require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex) - require.True(t, res.Equal(tc.exp.Mul(NewDec(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex) + require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + require.True(t, res.Equal(tc.exp), "equality was incorrect, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } } } From a2ced746cb9a5db0dd5c220f9f7f88fffc6cc8ae Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 01:13:36 -0400 Subject: [PATCH 08/50] precision multiplier test --- types/decimal.go | 7 +++++++ types/decimal_test.go | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 722039d6149b..828dee300240 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -72,11 +72,18 @@ func NewDecFromStr(str string) (f Dec, err Error) { str = str[1:] } + if len(str) == 0 { + return f, ErrUnknownRequest("decimal string is empty") + } + strs := strings.Split(str, ".") lenDecs := 0 combinedStr := strs[0] if len(strs) == 2 { lenDecs = len(strs[1]) + if lenDecs == 0 || len(combinedStr) == 0 { + return f, ErrUnknownRequest("bad decimal length") + } } else if len(strs) > 2 { return f, ErrUnknownRequest("too many periods to be a decimal string") } diff --git a/types/decimal_test.go b/types/decimal_test.go index 0c5ae8fe9287..1b12b50b3361 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,12 +1,19 @@ package types import ( + "fmt" "math/big" "testing" "github.com/stretchr/testify/require" ) +func TestPrecisionMultiplier(t *testing.T) { + res := precisionMultiplier(5) + exp := big.NewInt(100000) + require.Equal(t, 0, res.Cmp(exp), "equality was incorrect, res %v, exp %v", res, exp) +} + func TestNewDecFromStr(t *testing.T) { largeBigInt, success := new(big.Int).SetString("3144605511029693144278234343371835", 10) require.True(t, success) @@ -18,7 +25,7 @@ func TestNewDecFromStr(t *testing.T) { {"", true, Dec{}}, {"0", false, NewDec(0, 0)}, {"1", false, NewDec(1, 0)}, - {"1.1", false, NewDec(11, 2)}, + {"1.1", false, NewDec(11, 1)}, {"0.75", false, NewDec(75, 2)}, {"0.8", false, NewDec(8, 1)}, {"0.11111", true, NewDec(1111, 5)}, @@ -28,20 +35,21 @@ func TestNewDecFromStr(t *testing.T) { {"314460551102969314427823434337.1835", false, NewDecFromBigInt(largeBigInt, 4)}, {".", true, Dec{}}, - {".0", false, NewDec(0, 0)}, - {"1.", false, NewDec(1, 0)}, + {".0", true, NewDec(0, 0)}, + {"1.", true, NewDec(1, 0)}, {"foobar", true, Dec{}}, {"0.foobar", true, Dec{}}, {"0.foobar.", true, Dec{}}, } for tcIndex, tc := range tests { + fmt.Printf("debug tcIndex: %v\n", tcIndex) res, err := NewDecFromStr(tc.decimalStr) if tc.expErr { require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - require.True(t, res.Equal(tc.exp), "equality was incorrect, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + require.True(t, res.Equal(tc.exp), "equality was incorrect, res %v, exp %v, tc %v", res, tc.exp, tcIndex) } // negative tc From 1aa00b74b380a7b1376d6d65203a0a5723c2b75d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 01:19:54 -0400 Subject: [PATCH 09/50] 1% laptop battery --- types/decimal.go | 4 ++-- types/decimal_test.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 828dee300240..5234214b10a6 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -18,7 +18,7 @@ type Dec struct { const Precision = 10 func precisionInt() *big.Int { - return new(big.Int).Exp(big.NewInt(1), big.NewInt(Precision), nil) + return new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) } // nolint - common values @@ -31,7 +31,7 @@ func precisionMultiplier(prec int64) *big.Int { panic("too much precision") } zerosToAdd := Precision - prec - multiplier := new(big.Int).Exp(big.NewInt(1), big.NewInt(zerosToAdd), nil) + multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) return multiplier } diff --git a/types/decimal_test.go b/types/decimal_test.go index 1b12b50b3361..cfdecf1dff53 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -58,7 +58,8 @@ func TestNewDecFromStr(t *testing.T) { require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - require.True(t, res.Equal(tc.exp), "equality was incorrect, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + exp := tc.exp.Mul(NewDec(-1, 1)) + require.True(t, res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) } } } From 9ffbf401092eadd5e78582fba45c5dde98d6085b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 12:06:42 -0400 Subject: [PATCH 10/50] fixed TestNewDecFromStr --- types/decimal.go | 1 + types/decimal_test.go | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 5234214b10a6..cd63d9026aed 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -84,6 +84,7 @@ func NewDecFromStr(str string) (f Dec, err Error) { if lenDecs == 0 || len(combinedStr) == 0 { return f, ErrUnknownRequest("bad decimal length") } + combinedStr = combinedStr + strs[1] } else if len(strs) > 2 { return f, ErrUnknownRequest("too many periods to be a decimal string") } diff --git a/types/decimal_test.go b/types/decimal_test.go index cfdecf1dff53..e8207d53a65a 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,7 +1,6 @@ package types import ( - "fmt" "math/big" "testing" @@ -28,7 +27,7 @@ func TestNewDecFromStr(t *testing.T) { {"1.1", false, NewDec(11, 1)}, {"0.75", false, NewDec(75, 2)}, {"0.8", false, NewDec(8, 1)}, - {"0.11111", true, NewDec(1111, 5)}, + {"0.11111", false, NewDec(11111, 5)}, {"314460551102969.3144278234343371835", true, NewDec(3141203149163817869, 0)}, {"314460551102969314427823434337.1835718092488231350", true, NewDecFromBigInt(largeBigInt, 4)}, @@ -43,7 +42,6 @@ func TestNewDecFromStr(t *testing.T) { } for tcIndex, tc := range tests { - fmt.Printf("debug tcIndex: %v\n", tcIndex) res, err := NewDecFromStr(tc.decimalStr) if tc.expErr { require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) @@ -58,7 +56,7 @@ func TestNewDecFromStr(t *testing.T) { require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - exp := tc.exp.Mul(NewDec(-1, 1)) + exp := tc.exp.Mul(NewDec(-1, 0)) require.True(t, res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) } } From f8be905ffd7d10247feca4a4cab3bd9f1a93150c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 12:18:48 -0400 Subject: [PATCH 11/50] equalities working --- types/decimal_test.go | 70 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/types/decimal_test.go b/types/decimal_test.go index e8207d53a65a..df34053a1162 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -62,44 +62,42 @@ func TestNewDecFromStr(t *testing.T) { } } -//func TestEqualities(t *testing.T) { -//tests := []struct { -//d1, d2 Dec -//gt, lt, eq bool -//}{ -//{NewDec(0), NewDec(0), false, false, true}, -//{NewDec(0, 100), NewDec(0, 10000), false, false, true}, -//{NewDec(100), NewDec(100), false, false, true}, -//{NewDec(-100), NewDec(-100), false, false, true}, -//{NewDec(-100, -1), NewDec(100), false, false, true}, -//{NewDec(-1, 1), NewDec(1, -1), false, false, true}, -//{NewDec(1, -1), NewDec(-1, 1), false, false, true}, -//{NewDec(3, 7), NewDec(3, 7), false, false, true}, - -//{NewDec(0), NewDec(3, 7), false, true, false}, -//{NewDec(0), NewDec(100), false, true, false}, -//{NewDec(-1), NewDec(3, 7), false, true, false}, -//{NewDec(-1), NewDec(100), false, true, false}, -//{NewDec(1, 7), NewDec(100), false, true, false}, -//{NewDec(1, 7), NewDec(3, 7), false, true, false}, -//{NewDec(-3, 7), NewDec(-1, 7), false, true, false}, - -//{NewDec(3, 7), NewDec(0), true, false, false}, -//{NewDec(100), NewDec(0), true, false, false}, -//{NewDec(3, 7), NewDec(-1), true, false, false}, -//{NewDec(100), NewDec(-1), true, false, false}, -//{NewDec(100), NewDec(1, 7), true, false, false}, -//{NewDec(3, 7), NewDec(1, 7), true, false, false}, -//{NewDec(-1, 7), NewDec(-3, 7), true, false, false}, -//} +func TestDEqualities(t *testing.T) { + tests := []struct { + d1, d2 Dec + gt, lt, eq bool + }{ + {NewDec(0, 0), NewDec(0, 0), false, false, true}, + {NewDec(0, 2), NewDec(0, 4), false, false, true}, + {NewDec(100, 0), NewDec(100, 0), false, false, true}, + {NewDec(-100, 0), NewDec(-100, 0), false, false, true}, + {NewDec(-1, 1), NewDec(-1, 1), false, false, true}, + {NewDec(3333, 3), NewDec(3333, 3), false, false, true}, + + {NewDec(0, 0), NewDec(3333, 3), false, true, false}, + {NewDec(0, 0), NewDec(100, 0), false, true, false}, + {NewDec(-1, 0), NewDec(3333, 3), false, true, false}, + {NewDec(-1, 0), NewDec(100, 0), false, true, false}, + {NewDec(1111, 3), NewDec(100, 0), false, true, false}, + {NewDec(1111, 3), NewDec(3333, 3), false, true, false}, + {NewDec(-3333, 3), NewDec(-1111, 3), false, true, false}, + + {NewDec(3333, 3), NewDec(0, 0), true, false, false}, + {NewDec(100, 0), NewDec(0, 0), true, false, false}, + {NewDec(3333, 3), NewDec(-1, 0), true, false, false}, + {NewDec(100, 0), NewDec(-1, 0), true, false, false}, + {NewDec(100, 0), NewDec(1111, 3), true, false, false}, + {NewDec(3333, 3), NewDec(1111, 3), true, false, false}, + {NewDec(-1111, 3), NewDec(-3333, 3), true, false, false}, + } -//for tcIndex, tc := range tests { -//require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc #%d", tcIndex) -//require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc #%d", tcIndex) -//require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc #%d", tcIndex) -//} + for tcIndex, tc := range tests { + require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc #%d", tcIndex) + } -//} +} //func TestArithmetic(t *testing.T) { //tests := []struct { From a598efbfafb881394affc0fb5d69cb860d746aaf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 13:58:45 -0400 Subject: [PATCH 12/50] fix bankers round chop --- types/decimal.go | 14 ++++- types/decimal_test.go | 130 ++++++++++++++++++++++-------------------- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index cd63d9026aed..c8810a32d224 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -129,14 +129,17 @@ func (d Dec) Mul(d2 Dec) Dec { func (d Dec) Quo(d2 Dec) Dec { mul := new(big.Int).Mul(new(big.Int).Mul( // multiple Precision twice d.Int, precisionInt()), precisionInt()) + fmt.Printf("debug mul: %v\n", mul.String()) quo := new(big.Int).Quo(mul, d2.Int) + fmt.Printf("debug quo: %v\n", quo.String()) chopped := BankerRoundChop(quo, Precision) + fmt.Printf("debug chopped: %v\n", chopped.String()) return Dec{chopped} } func (d Dec) String() string { - str := d.Int.String() + str := d.ToLeftPadded(Precision) placement := len(str) - Precision if placement < 0 { panic("too few decimal digits") @@ -177,7 +180,14 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { return quo } - fiveLine := big.NewInt(int64(5 * len(rem.String()))) // ex. 1234 -> 5000 + lenWhole := len(d.String()) + lenQuo := len(quo.String()) + lenRem := len(rem.String()) + leadingZeros := lenWhole - (lenQuo + lenRem) // leading zeros removed from the remainder + + zerosToAdd := int64(lenRem - 1 + leadingZeros) + multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) + fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier) switch rem.Cmp(fiveLine) { case -1: diff --git a/types/decimal_test.go b/types/decimal_test.go index df34053a1162..533500b80246 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" "testing" @@ -92,66 +93,71 @@ func TestDEqualities(t *testing.T) { } for tcIndex, tc := range tests { - require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc #%d", tcIndex) + require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex) + require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex) + require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex) } } -//func TestArithmetic(t *testing.T) { -//tests := []struct { -//d1, d2 Dec -//resMul, resDiv, resAdd, resSub Dec -//}{ -//// d1 d2 MUL DIV ADD SUB -//{NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0)}, -//{NewDec(1), NewDec(0), NewDec(0), NewDec(0), NewDec(1), NewDec(1)}, -//{NewDec(0), NewDec(1), NewDec(0), NewDec(0), NewDec(1), NewDec(-1)}, -//{NewDec(0), NewDec(-1), NewDec(0), NewDec(0), NewDec(-1), NewDec(1)}, -//{NewDec(-1), NewDec(0), NewDec(0), NewDec(0), NewDec(-1), NewDec(-1)}, - -//{NewDec(1), NewDec(1), NewDec(1), NewDec(1), NewDec(2), NewDec(0)}, -//{NewDec(-1), NewDec(-1), NewDec(1), NewDec(1), NewDec(-2), NewDec(0)}, -//{NewDec(1), NewDec(-1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(2)}, -//{NewDec(-1), NewDec(1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(-2)}, - -//{NewDec(3), NewDec(7), NewDec(21), NewDec(3, 7), NewDec(10), NewDec(-4)}, -//{NewDec(2), NewDec(4), NewDec(8), NewDec(1, 2), NewDec(6), NewDec(-2)}, -//{NewDec(100), NewDec(100), NewDec(10000), NewDec(1), NewDec(200), NewDec(0)}, - -//{NewDec(3, 2), NewDec(3, 2), NewDec(9, 4), NewDec(1), NewDec(3), NewDec(0)}, -//{NewDec(3, 7), NewDec(7, 3), NewDec(1), NewDec(9, 49), NewDec(58, 21), NewDec(-40, 21)}, -//{NewDec(1, 21), NewDec(11, 5), NewDec(11, 105), NewDec(5, 231), NewDec(236, 105), NewDec(-226, 105)}, -//{NewDec(-21), NewDec(3, 7), NewDec(-9), NewDec(-49), NewDec(-144, 7), NewDec(-150, 7)}, -//{NewDec(100), NewDec(1, 7), NewDec(100, 7), NewDec(700), NewDec(701, 7), NewDec(699, 7)}, -//} +func TestDArithmetic(t *testing.T) { + tests := []struct { + d1, d2 Dec + expMul, expDiv, expAdd, expSub Dec + }{ + // d1 d2 MUL DIV ADD SUB + {NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0)}, + {NewDec(1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(1, 0), NewDec(1, 0)}, + {NewDec(0, 0), NewDec(1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(1, 0), NewDec(-1, 0)}, + {NewDec(0, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(-1, 0), NewDec(1, 0)}, + {NewDec(-1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(-1, 0), NewDec(-1, 0)}, + + {NewDec(1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(2, 0), NewDec(0, 0)}, + {NewDec(-1, 0), NewDec(-1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(-2, 0), NewDec(0, 0)}, + {NewDec(1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(2, 0)}, + {NewDec(-1, 0), NewDec(1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(-2, 0)}, + + {NewDec(3, 0), NewDec(7, 0), NewDec(21, 0), NewDec(4285714286, 10), NewDec(10, 0), NewDec(-4, 0)}, + {NewDec(2, 0), NewDec(4, 0), NewDec(8, 0), NewDec(5, 1), NewDec(6, 0), NewDec(-2, 0)}, + {NewDec(100, 0), NewDec(100, 0), NewDec(10000, 0), NewDec(1, 0), NewDec(200, 0), NewDec(0, 0)}, + + {NewDec(15, 1), NewDec(15, 1), NewDec(225, 2), NewDec(1, 0), NewDec(3, 0), NewDec(0, 0)}, + {NewDec(3333, 4), NewDec(333, 4), NewDec(1109889, 8), NewDec(10009009009, 9), NewDec(3666, 4), NewDec(3, 1)}, + //{NewDec(1, 21), NewDec(11, 5), NewDec(11, 105), NewDec(5, 231), NewDec(236, 105), NewDec(-226, 105)}, + //{NewDec(-21), NewDec(3333, 3), NewDec(-9), NewDec(-49), NewDec(-144, 7), NewDec(-150, 7)}, + //{NewDec(100), NewDec(1, 7), NewDec(100, 7), NewDec(700), NewDec(701, 7), NewDec(699, 7)}, + } -//for tcIndex, tc := range tests { -//require.True(t, tc.resMul.Equal(tc.d1.Mul(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) -//require.True(t, tc.resAdd.Equal(tc.d1.Add(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) -//require.True(t, tc.resSub.Equal(tc.d1.Sub(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) - -//if tc.d2.Num().IsZero() { // panic for divide by zero -//require.Panics(t, func() { tc.d1.Quo(tc.d2) }) -//} else { -//require.True(t, tc.resDiv.Equal(tc.d1.Quo(tc.d2)), "d1 %v, d2 %v. tc #%d", tc.d1.Dec, tc.d2.Dec, tcIndex) -//} -//} -//} + for tcIndex, tc := range tests { + fmt.Printf("debug tcIndex: %v\n", tcIndex) + resAdd := tc.d1.Add(tc.d2) + resSub := tc.d1.Sub(tc.d2) + resMul := tc.d1.Mul(tc.d2) + require.True(t, tc.expAdd.Equal(resAdd), "exp %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex) + require.True(t, tc.expSub.Equal(resSub), "exp %v, res %v, tc %d", tc.expSub, resSub, tcIndex) + require.True(t, tc.expMul.Equal(resMul), "exp %v, res %v, tc %d", tc.expMul, resMul, tcIndex) + + if tc.d2.IsZero() { // panic for divide by zero + require.Panics(t, func() { tc.d1.Quo(tc.d2) }) + } else { + resDiv := tc.d1.Quo(tc.d2) + require.True(t, tc.expDiv.Equal(resDiv), "exp %v, res %v, tc %d", tc.expDiv.String(), resDiv.String(), tcIndex) + } + } +} //func TestEvaluate(t *testing.T) { //tests := []struct { //d1 Dec //res int64 //}{ -//{NewDec(0), 0}, -//{NewDec(1), 1}, +//{NewDec(0, 0), 0}, +//{NewDec(1, 0), 1}, //{NewDec(1, 4), 0}, //{NewDec(1, 2), 0}, //{NewDec(3, 4), 1}, //{NewDec(5, 6), 1}, -//{NewDec(3, 2), 2}, +//{NewDec(15, 1), 2}, //{NewDec(5, 2), 2}, //{NewDec(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even //{NewDec(17, 11), 2}, // 1.545 @@ -161,8 +167,8 @@ func TestDEqualities(t *testing.T) { //} //for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc #%d", tc.d1, tcIndex) -//require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1)).RoundInt64(), "%v. tc #%d", tc.d1.Mul(NewDec(-1)), tcIndex) +//require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) +//require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) //} //} @@ -185,9 +191,9 @@ func TestDEqualities(t *testing.T) { //} //for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.d.Round(tc.precFactor), "%v", tc.d, "incorrect rounding, tc #%d", tcIndex) -//negR1, negRes := tc.d.Mul(NewDec(-1)), tc.res.Mul(NewDec(-1)) -//require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex) +//require.Equal(t, tc.res, tc.d.Round(tc.precFactor), "%v", tc.d, "incorrect rounding, tc %d", tcIndex) +//negR1, negRes := tc.d.Mul(NewDec(-1, 0)), tc.res.Mul(NewDec(-1, 0)) +//require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc %d", tcIndex) //} //} @@ -204,7 +210,7 @@ func TestDEqualities(t *testing.T) { //{NewDec(1000, 3), 12, "000000000333"}, //} //for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.dec.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex) +//require.Equal(t, tc.res, tc.dec.ToLeftPadded(tc.digits), "incorrect left padding, tc %d", tcIndex) //} //} @@ -281,20 +287,20 @@ func TestDEqualities(t *testing.T) { //d1s, d2s []Dec //eq bool //}{ -//{[]Dec{NewDec(0)}, []Dec{NewDec(0)}, true}, -//{[]Dec{NewDec(0)}, []Dec{NewDec(1)}, false}, -//{[]Dec{NewDec(0)}, []Dec{}, false}, -//{[]Dec{NewDec(0), NewDec(1)}, []Dec{NewDec(0), NewDec(1)}, true}, -//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1), NewDec(0)}, true}, -//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(0), NewDec(1)}, false}, -//{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1)}, false}, -//{[]Dec{NewDec(1), NewDec(2)}, []Dec{NewDec(2), NewDec(4)}, false}, -//{[]Dec{NewDec(3), NewDec(18)}, []Dec{NewDec(1), NewDec(6)}, false}, +//{[]Dec{NewDec(0, 0)}, []Dec{NewDec(0, 0)}, true}, +//{[]Dec{NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, +//{[]Dec{NewDec(0, 0)}, []Dec{}, false}, +//{[]Dec{NewDec(0, 0), NewDec(1, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, true}, +//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0), NewDec(0, 0)}, true}, +//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, false}, +//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, +//{[]Dec{NewDec(1, 0), NewDec(2, 0)}, []Dec{NewDec(2, 0), NewDec(4, 0)}, false}, +//{[]Dec{NewDec(3, 0), NewDec(18)}, []Dec{NewDec(1, 0), NewDec(6)}, false}, //} //for tcIndex, tc := range tests { -//require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc #%d", tcIndex) -//require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc #%d", tcIndex) +//require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) +//require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) //} //} From 697bb2ec2b6d89843aa5aad6272a471194ab8c15 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 14:17:38 -0400 Subject: [PATCH 13/50] ... --- types/decimal_test.go | 74 +++++++++++++------------------------------ 1 file changed, 22 insertions(+), 52 deletions(-) diff --git a/types/decimal_test.go b/types/decimal_test.go index 533500b80246..34de87c58400 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -123,9 +123,6 @@ func TestDArithmetic(t *testing.T) { {NewDec(15, 1), NewDec(15, 1), NewDec(225, 2), NewDec(1, 0), NewDec(3, 0), NewDec(0, 0)}, {NewDec(3333, 4), NewDec(333, 4), NewDec(1109889, 8), NewDec(10009009009, 9), NewDec(3666, 4), NewDec(3, 1)}, - //{NewDec(1, 21), NewDec(11, 5), NewDec(11, 105), NewDec(5, 231), NewDec(236, 105), NewDec(-226, 105)}, - //{NewDec(-21), NewDec(3333, 3), NewDec(-9), NewDec(-49), NewDec(-144, 7), NewDec(-150, 7)}, - //{NewDec(100), NewDec(1, 7), NewDec(100, 7), NewDec(700), NewDec(701, 7), NewDec(699, 7)}, } for tcIndex, tc := range tests { @@ -146,56 +143,29 @@ func TestDArithmetic(t *testing.T) { } } -//func TestEvaluate(t *testing.T) { -//tests := []struct { -//d1 Dec -//res int64 -//}{ -//{NewDec(0, 0), 0}, -//{NewDec(1, 0), 1}, -//{NewDec(1, 4), 0}, -//{NewDec(1, 2), 0}, -//{NewDec(3, 4), 1}, -//{NewDec(5, 6), 1}, -//{NewDec(15, 1), 2}, -//{NewDec(5, 2), 2}, -//{NewDec(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even -//{NewDec(17, 11), 2}, // 1.545 -//{NewDec(5, 11), 0}, -//{NewDec(16, 11), 1}, -//{NewDec(113, 12), 9}, -//} - -//for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) -//require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) -//} -//} - -//func TestRound(t *testing.T) { -//many3 := "333333333333333333333333333333333333333333333" -//many7 := "777777777777777777777777777777777777777777777" -//big3, worked := new(big.Int).SetString(many3, 10) -//require.True(t, worked) -//big7, worked := new(big.Int).SetString(many7, 10) -//require.True(t, worked) - -//tests := []struct { -//d, res Dec -//precFactor int64 -//}{ -//{NewDec(333, 777), NewDec(429, 1000), 1000}, -//{Dec{new(big.Dec).SetFrac(big3, big7)}, NewDec(429, 1000), 1000}, -//{Dec{new(big.Dec).SetFrac(big3, big7)}, Dec{big.NewDec(4285714286, 10000000000)}, 10000000000}, -//{NewDec(1, 2), NewDec(1, 2), 1000}, -//} +func TestRoundInt64(t *testing.T) { + tests := []struct { + d1 Dec + resInt64 int64 + }{ + {NewDec(0, 0), 0}, + {NewDec(1, 0), 1}, + {NewDec(25, 2), 0}, + {NewDec(5, 1), 0}, + {NewDec(75, 2), 1}, + {NewDec(75, 1), 8}, + {NewDec(8333, 4), 1}, + {NewDec(15, 0), 2}, + {NewDec(25, 1), 2}, + {NewDec(545, 3), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {NewDec(1545, 3), 2}, // 1.545 + } -//for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.d.Round(tc.precFactor), "%v", tc.d, "incorrect rounding, tc %d", tcIndex) -//negR1, negRes := tc.d.Mul(NewDec(-1, 0)), tc.res.Mul(NewDec(-1, 0)) -//require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc %d", tcIndex) -//} -//} + for tcIndex, tc := range tests { + require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) + require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) + } +} //func TestToLeftPadded(t *testing.T) { //tests := []struct { From 20486a9153274b8e63c1efb17c1030b23260a0ae Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 27 Jul 2018 15:07:00 -0400 Subject: [PATCH 14/50] working, some decimal issues resolved --- types/decimal.go | 16 ++-- types/decimal_test.go | 177 +++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 98 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index c8810a32d224..c498e3a6f2bb 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -147,6 +147,14 @@ func (d Dec) String() string { return str[:placement] + "." + str[placement:] } +// TODO panic if negative or if totalDigits < len(initStr)??? +// evaluate as an integer and return left padded string +func (d Dec) ToLeftPadded(totalDigits int8) string { + intStr := d.Int.String() + fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` + return fmt.Sprintf(fcode, intStr) +} + var ( dzero = big.NewInt(0) done = big.NewInt(1) @@ -221,14 +229,6 @@ func (d Dec) RoundInt() Int { return NewIntFromBigInt(BankerRoundChop(d.Int, Precision)) } -// TODO panic if negative or if totalDigits < len(initStr)??? -// evaluate as an integer and return left padded string -func (d Dec) ToLeftPadded(totalDigits int8) string { - intStr := d.Int.String() - fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` - return fmt.Sprintf(fcode, intStr) -} - //___________________________________________________________________________________ // wraps d.MarshalText() diff --git a/types/decimal_test.go b/types/decimal_test.go index 34de87c58400..92258e394db4 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -100,6 +100,28 @@ func TestDEqualities(t *testing.T) { } +func TestDecsEqual(t *testing.T) { + tests := []struct { + d1s, d2s []Dec + eq bool + }{ + {[]Dec{NewDec(0, 0)}, []Dec{NewDec(0, 0)}, true}, + {[]Dec{NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, + {[]Dec{NewDec(0, 0)}, []Dec{}, false}, + {[]Dec{NewDec(0, 0), NewDec(1, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, true}, + {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0), NewDec(0, 0)}, true}, + {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, false}, + {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, + {[]Dec{NewDec(1, 0), NewDec(2, 0)}, []Dec{NewDec(2, 0), NewDec(4, 0)}, false}, + {[]Dec{NewDec(3, 0), NewDec(18, 0)}, []Dec{NewDec(1, 0), NewDec(6, 0)}, false}, + } + + for tcIndex, tc := range tests { + require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) + require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) + } +} + func TestDArithmetic(t *testing.T) { tests := []struct { d1, d2 Dec @@ -143,29 +165,29 @@ func TestDArithmetic(t *testing.T) { } } -func TestRoundInt64(t *testing.T) { - tests := []struct { - d1 Dec - resInt64 int64 - }{ - {NewDec(0, 0), 0}, - {NewDec(1, 0), 1}, - {NewDec(25, 2), 0}, - {NewDec(5, 1), 0}, - {NewDec(75, 2), 1}, - {NewDec(75, 1), 8}, - {NewDec(8333, 4), 1}, - {NewDec(15, 0), 2}, - {NewDec(25, 1), 2}, - {NewDec(545, 3), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {NewDec(1545, 3), 2}, // 1.545 - } +//func TestRoundInt64(t *testing.T) { +//tests := []struct { +//d1 Dec +//resInt64 int64 +//}{ +//{NewDec(0, 0), 0}, +//{NewDec(1, 0), 1}, +//{NewDec(25, 2), 0}, +//{NewDec(5, 1), 0}, +//{NewDec(75, 2), 1}, +//{NewDec(75, 1), 8}, +//{NewDec(8333, 4), 1}, +//{NewDec(15, 0), 2}, +//{NewDec(25, 1), 2}, +//{NewDec(545, 3), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even +//{NewDec(1545, 3), 2}, // 1.545 +//} - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) - require.Equal(t, tc.res*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) - } -} +//for tcIndex, tc := range tests { +//require.Equal(t, tc.resInt64, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) +//require.Equal(t, tc.resInt64*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) +//} +//} //func TestToLeftPadded(t *testing.T) { //tests := []struct { @@ -185,32 +207,28 @@ func TestRoundInt64(t *testing.T) { //} //var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec +func TestDZeroSerializationJSON(t *testing.T) { + d := NewDec(0, 0) + err := cdc.UnmarshalJSON([]byte(`0`), &d) + require.Nil(t, err) + err = cdc.UnmarshalJSON([]byte(`{}`), &d) + require.NotNil(t, err) +} -//func TestZeroSerializationJSON(t *testing.T) { -//d := NewDec(0, 1) -//err := cdc.UnmarshalJSON([]byte(`"0/1"`), &d) -//require.Nil(t, err) -//err = cdc.UnmarshalJSON([]byte(`"0/0"`), &d) -//require.NotNil(t, err) -//err = cdc.UnmarshalJSON([]byte(`"1/0"`), &d) -//require.NotNil(t, err) -//err = cdc.UnmarshalJSON([]byte(`"{}"`), &d) -//require.NotNil(t, err) -//} - -//func TestSerializationText(t *testing.T) { -//d := NewDec(1, 3) +func TestDSerializationText(t *testing.T) { + d := NewDec(1, 3) -//bz, err := d.MarshalText() -//require.NoError(t, err) + bz, err := d.MarshalText() + require.NoError(t, err) + fmt.Printf("debug bz: %s\n", bz) -//var d2 = Dec{new(big.Dec)} -//err = d2.UnmarshalText(bz) -//require.NoError(t, err) -//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -//} + var d2 = Dec{new(big.Int)} + err = d2.UnmarshalText(bz) + require.NoError(t, err) + require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +} -//func TestSerializationGoWireJSON(t *testing.T) { +//func TestDSerializationGoWireJSON(t *testing.T) { //d := NewDec(1, 3) //bz, err := cdc.MarshalJSON(d) //require.NoError(t, err) @@ -221,29 +239,29 @@ func TestRoundInt64(t *testing.T) { //require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) //} -//func TestSerializationGoWireBinary(t *testing.T) { -//d := NewDec(1, 3) -//bz, err := cdc.MarshalBinary(d) -//require.NoError(t, err) +func TestDSerializationGoWireBinary(t *testing.T) { + d := NewDec(1, 3) + bz, err := cdc.MarshalBinary(d) + require.NoError(t, err) -//var d2 Dec -//err = cdc.UnmarshalBinary(bz, &d2) -//require.NoError(t, err) -//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -//} + var d2 Dec + err = cdc.UnmarshalBinary(bz, &d2) + require.NoError(t, err) + require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +} -//type testEmbedStruct struct { +//type testDEmbedStruct struct { //Field1 string `json:"f1"` //Field2 int `json:"f2"` //Field3 Dec `json:"f3"` //} -//func TestEmbeddedStructSerializationGoWire(t *testing.T) { -//obj := testEmbedStruct{"foo", 10, NewDec(1, 3)} +//func TestDEmbeddedStructSerializationGoWire(t *testing.T) { +//obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} //bz, err := cdc.MarshalJSON(obj) //require.Nil(t, err) -//var obj2 testEmbedStruct +//var obj2 testDEmbedStruct //err = cdc.UnmarshalJSON(bz, &obj2) //require.Nil(t, err) @@ -252,36 +270,15 @@ func TestRoundInt64(t *testing.T) { //require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) //} -//func TestDecsEqual(t *testing.T) { -//tests := []struct { -//d1s, d2s []Dec -//eq bool -//}{ -//{[]Dec{NewDec(0, 0)}, []Dec{NewDec(0, 0)}, true}, -//{[]Dec{NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, -//{[]Dec{NewDec(0, 0)}, []Dec{}, false}, -//{[]Dec{NewDec(0, 0), NewDec(1, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, true}, -//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0), NewDec(0, 0)}, true}, -//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, false}, -//{[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, -//{[]Dec{NewDec(1, 0), NewDec(2, 0)}, []Dec{NewDec(2, 0), NewDec(4, 0)}, false}, -//{[]Dec{NewDec(3, 0), NewDec(18)}, []Dec{NewDec(1, 0), NewDec(6)}, false}, -//} - -//for tcIndex, tc := range tests { -//require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) -//require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) -//} - -//} - -//func TestStringOverflow(t *testing.T) { -//// two random 64 bit primes -//dec1 := NewDec(5164315003622678713, 4389711697696177267) -//dec2 := NewDec(-3179849666053572961, 8459429845579852627) -//dec3 := dec1.Add(dec2) -//require.Equal(t, -//"29728537197630860939575850336935951464/37134458148982045574552091851127630409", -//dec3.String(), -//) -//} +func TestDStringOverflow(t *testing.T) { + // two random 64 bit primes + dec1, err := NewDecFromStr("51643150036226787134389711697696177267") + require.NoError(t, err) + dec2, err := NewDecFromStr("-31798496660535729618459429845579852627") + require.NoError(t, err) + dec3 := dec1.Add(dec2) + require.Equal(t, + "19844653375691057515930281852116324640.0000000000", + dec3.String(), + ) +} From 173acc9713f0b0bc0e62daca79a82a770d418115 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 09:29:46 -0400 Subject: [PATCH 15/50] fix rounding error --- types/decimal.go | 42 +++++++++++++++++++++++++++++++++--------- types/decimal_test.go | 33 +++++++++++++++++---------------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index c498e3a6f2bb..d5c0c2b712e4 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -60,9 +60,9 @@ func NewDecFromInt(i Int, prec int64) Dec { } // create a decimal from a decimal string (ex. "1234.5678") -func NewDecFromStr(str string) (f Dec, err Error) { +func NewDecFromStr(str string) (d Dec, err Error) { if len(str) == 0 { - return f, ErrUnknownRequest("decimal string is empty") + return d, ErrUnknownRequest("decimal string is empty") } // first extract any negative symbol @@ -73,7 +73,7 @@ func NewDecFromStr(str string) (f Dec, err Error) { } if len(str) == 0 { - return f, ErrUnknownRequest("decimal string is empty") + return d, ErrUnknownRequest("decimal string is empty") } strs := strings.Split(str, ".") @@ -82,15 +82,15 @@ func NewDecFromStr(str string) (f Dec, err Error) { if len(strs) == 2 { lenDecs = len(strs[1]) if lenDecs == 0 || len(combinedStr) == 0 { - return f, ErrUnknownRequest("bad decimal length") + return d, ErrUnknownRequest("bad decimal length") } combinedStr = combinedStr + strs[1] } else if len(strs) > 2 { - return f, ErrUnknownRequest("too many periods to be a decimal string") + return d, ErrUnknownRequest("too many periods to be a decimal string") } if lenDecs > Precision { - return f, ErrUnknownRequest("too much Precision in decimal") + return d, ErrUnknownRequest("too much Precision in decimal") } // add some extra dzero's to correct to the Precision factor @@ -100,7 +100,7 @@ func NewDecFromStr(str string) (f Dec, err Error) { combined, ok := new(big.Int).SetString(combinedStr, 10) if !ok { - return f, ErrUnknownRequest("bad string to integer conversion") + return d, ErrUnknownRequest("bad string to integer conversion") } if neg { combined = new(big.Int).Neg(combined) @@ -108,6 +108,15 @@ func NewDecFromStr(str string) (f Dec, err Error) { return Dec{combined}, nil } +// create a decimal from a decimal string (ex. "1234.5678") +func MustNewDecFromStr(str string) (d Dec) { + d, err := NewDecFromStr(str) + if err != nil { + panic(err) + } + return d +} + //nolint func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to dzero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } @@ -139,7 +148,7 @@ func (d Dec) Quo(d2 Dec) Dec { } func (d Dec) String() string { - str := d.ToLeftPadded(Precision) + str := d.ToLeftPaddedWithDecimals(Precision) placement := len(str) - Precision if placement < 0 { panic("too few decimal digits") @@ -149,12 +158,24 @@ func (d Dec) String() string { // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string -func (d Dec) ToLeftPadded(totalDigits int8) string { +func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { intStr := d.Int.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) } +// TODO panic if negative or if totalDigits < len(initStr)??? +// evaluate as an integer and return left padded string +func (d Dec) ToLeftPadded(totalDigits int8) string { + fmt.Printf("debug d: %v\n", d.String()) + chopped := BankerRoundChop(d.Int, Precision) + fmt.Printf("debug chopped: %v\n", chopped) + intStr := chopped.String() + fmt.Printf("debug intStr: %v\n", intStr) + fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` + return fmt.Sprintf(fcode, intStr) +} + var ( dzero = big.NewInt(0) done = big.NewInt(1) @@ -189,6 +210,9 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { } lenWhole := len(d.String()) + if quo.Sign() == 0 { // only the decimal places (ex. 0.1234) + lenWhole++ + } lenQuo := len(quo.String()) lenRem := len(rem.String()) leadingZeros := lenWhole - (lenQuo + lenRem) // leading zeros removed from the remainder diff --git a/types/decimal_test.go b/types/decimal_test.go index 92258e394db4..14e0cbaa3ba6 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -189,22 +189,23 @@ func TestDArithmetic(t *testing.T) { //} //} -//func TestToLeftPadded(t *testing.T) { -//tests := []struct { -//dec Dec -//digits int8 -//res string -//}{ -//{NewDec(100, 3), 8, "00000033"}, -//{NewDec(1, 3), 8, "00000000"}, -//{NewDec(100, 2), 8, "00000050"}, -//{NewDec(1000, 3), 8, "00000333"}, -//{NewDec(1000, 3), 12, "000000000333"}, -//} -//for tcIndex, tc := range tests { -//require.Equal(t, tc.res, tc.dec.ToLeftPadded(tc.digits), "incorrect left padding, tc %d", tcIndex) -//} -//} +func TestDToLeftPadded(t *testing.T) { + tests := []struct { + dec Dec + digits int8 + exp string + }{ + {MustNewDecFromStr("33.3"), 8, "00000033"}, + {MustNewDecFromStr("50"), 8, "00000050"}, + {MustNewDecFromStr("333"), 8, "00000333"}, + {MustNewDecFromStr("333"), 12, "000000000333"}, + {MustNewDecFromStr("0.3333"), 8, "00000000"}, + } + for tcIndex, tc := range tests { + res := tc.dec.ToLeftPadded(tc.digits) + require.Equal(t, tc.exp, res, "incorrect left padding, tc %d", tcIndex) + } +} //var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec func TestDZeroSerializationJSON(t *testing.T) { From 44f24acc26e4a926a96a39a8173ce52b03c19ca3 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 10:41:49 -0400 Subject: [PATCH 16/50] rounding works --- types/decimal.go | 27 ++++++++++++++++++------- types/decimal_test.go | 46 ++++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index d5c0c2b712e4..6cb46cca73e7 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -124,6 +124,7 @@ func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } func (d Dec) GTE(d2 Dec) bool { return !d.LT(d2) } // greater than or equal func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than func (d Dec) LTE(d2 Dec) bool { return !d.GT(d2) } // less than or equal +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to dzero func (d Dec) Add(d2 Dec) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction @@ -199,7 +200,15 @@ var ( // BankerRoundChop(1005, 1) = 100 // BankerRoundChop(1015, 1) = 102 // BankerRoundChop(1500, 3) = 2 -func BankerRoundChop(d *big.Int, n int64) *big.Int { +func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { + + // remove the negative and add it back when returning + if d.Sign() == -1 { + d = new(big.Int).Neg(d) + defer func() { + chopped = new(big.Int).Neg(chopped) + }() + } // get the trucated quotient and remainder quo, rem, prec := big.NewInt(0), big.NewInt(0), precisionInt() @@ -223,13 +232,14 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { switch rem.Cmp(fiveLine) { case -1: - return quo + chopped = quo + return case 1: - return new(big.Int).Add(quo, big.NewInt(1)) - + chopped = new(big.Int).Add(quo, big.NewInt(1)) + return default: // bankers rounding must take place str := quo.String() - finalDig, err := strconv.Atoi(string(str[len(str)])) + finalDig, err := strconv.Atoi(string(str[len(str)-1])) if err != nil { panic(err) } @@ -237,10 +247,13 @@ func BankerRoundChop(d *big.Int, n int64) *big.Int { // always round to an even number if finalDig == 0 || finalDig == 2 || finalDig == 4 || finalDig == 6 || finalDig == 8 { - return quo + + chopped = quo + return } + chopped = new(big.Int).Add(quo, big.NewInt(1)) + return } - return new(big.Int).Add(quo, big.NewInt(1)) } // RoundInt64 rounds the decimal using bankers rounding diff --git a/types/decimal_test.go b/types/decimal_test.go index 14e0cbaa3ba6..77e14ffde9ae 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -165,29 +165,31 @@ func TestDArithmetic(t *testing.T) { } } -//func TestRoundInt64(t *testing.T) { -//tests := []struct { -//d1 Dec -//resInt64 int64 -//}{ -//{NewDec(0, 0), 0}, -//{NewDec(1, 0), 1}, -//{NewDec(25, 2), 0}, -//{NewDec(5, 1), 0}, -//{NewDec(75, 2), 1}, -//{NewDec(75, 1), 8}, -//{NewDec(8333, 4), 1}, -//{NewDec(15, 0), 2}, -//{NewDec(25, 1), 2}, -//{NewDec(545, 3), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even -//{NewDec(1545, 3), 2}, // 1.545 -//} +func TestRoundInt64(t *testing.T) { + tests := []struct { + d1 Dec + expInt64 int64 + }{ + {MustNewDecFromStr("0.25"), 0}, + {MustNewDecFromStr("0"), 0}, + {MustNewDecFromStr("1"), 1}, + {MustNewDecFromStr("0.75"), 1}, + {MustNewDecFromStr("0.5"), 0}, + {MustNewDecFromStr("7.5"), 8}, + {MustNewDecFromStr("1.5"), 2}, + {MustNewDecFromStr("2.5"), 2}, + {MustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {MustNewDecFromStr("1.545"), 2}, + } -//for tcIndex, tc := range tests { -//require.Equal(t, tc.resInt64, tc.d1.RoundInt64(), "%v. tc %d", tc.d1, tcIndex) -//require.Equal(t, tc.resInt64*-1, tc.d1.Mul(NewDec(-1, 0)).RoundInt64(), "%v. tc %d", tc.d1.Mul(NewDec(-1, 0)), tcIndex) -//} -//} + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().RoundInt64() + require.Equal(t, -1*tc.expInt64, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.RoundInt64() + require.Equal(t, tc.expInt64, resPos, "positive tc %d", tcIndex) + } +} func TestDToLeftPadded(t *testing.T) { tests := []struct { From 34a997848c3b837b0fac5b71d5bc0ae17055f8f1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:22:31 -0400 Subject: [PATCH 17/50] decimal works --- types/decimal.go | 11 ++---- types/decimal_test.go | 88 ++++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 6cb46cca73e7..1668fd64d3a3 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -11,7 +11,7 @@ import ( // NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int type Dec struct { - *big.Int `json:Int""` + *big.Int `"json:Int"` } // number of decimal places @@ -139,12 +139,9 @@ func (d Dec) Mul(d2 Dec) Dec { func (d Dec) Quo(d2 Dec) Dec { mul := new(big.Int).Mul(new(big.Int).Mul( // multiple Precision twice d.Int, precisionInt()), precisionInt()) - fmt.Printf("debug mul: %v\n", mul.String()) quo := new(big.Int).Quo(mul, d2.Int) - fmt.Printf("debug quo: %v\n", quo.String()) chopped := BankerRoundChop(quo, Precision) - fmt.Printf("debug chopped: %v\n", chopped.String()) return Dec{chopped} } @@ -168,11 +165,8 @@ func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string func (d Dec) ToLeftPadded(totalDigits int8) string { - fmt.Printf("debug d: %v\n", d.String()) chopped := BankerRoundChop(d.Int, Precision) - fmt.Printf("debug chopped: %v\n", chopped) intStr := chopped.String() - fmt.Printf("debug intStr: %v\n", intStr) fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) } @@ -279,7 +273,8 @@ func (d Dec) MarshalAmino() (string, error) { // requires a valid JSON string - strings quotes and calls UnmarshalText func (d *Dec) UnmarshalAmino(text string) (err error) { - tempInt := big.NewInt(0) + fmt.Printf("debug hoot") + tempInt := new(big.Int) err = tempInt.UnmarshalText([]byte(text)) if err != nil { return err diff --git a/types/decimal_test.go b/types/decimal_test.go index 77e14ffde9ae..b73b825c1200 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + wire "github.com/cosmos/cosmos-sdk/wire" "github.com/stretchr/testify/require" ) @@ -165,10 +166,10 @@ func TestDArithmetic(t *testing.T) { } } -func TestRoundInt64(t *testing.T) { +func TestBankerRoundChop(t *testing.T) { tests := []struct { - d1 Dec - expInt64 int64 + d1 Dec + exp int64 }{ {MustNewDecFromStr("0.25"), 0}, {MustNewDecFromStr("0"), 0}, @@ -184,10 +185,10 @@ func TestRoundInt64(t *testing.T) { for tcIndex, tc := range tests { resNeg := tc.d1.Neg().RoundInt64() - require.Equal(t, -1*tc.expInt64, resNeg, "negative tc %d", tcIndex) + require.Equal(t, -1*tc.exp, resNeg, "negative tc %d", tcIndex) resPos := tc.d1.RoundInt64() - require.Equal(t, tc.expInt64, resPos, "positive tc %d", tcIndex) + require.Equal(t, tc.exp, resPos, "positive tc %d", tcIndex) } } @@ -209,42 +210,45 @@ func TestDToLeftPadded(t *testing.T) { } } -//var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec -func TestDZeroSerializationJSON(t *testing.T) { - d := NewDec(0, 0) - err := cdc.UnmarshalJSON([]byte(`0`), &d) +var dcdc = wire.NewCodec() + +func TestZeroDeserializationJSON(t *testing.T) { + d := Dec{new(big.Int)} + err := dcdc.UnmarshalJSON([]byte("0"), &d) require.Nil(t, err) - err = cdc.UnmarshalJSON([]byte(`{}`), &d) + err = dcdc.UnmarshalJSON([]byte("{}"), &d) require.NotNil(t, err) } func TestDSerializationText(t *testing.T) { - d := NewDec(1, 3) + d := MustNewDecFromStr("0.333") bz, err := d.MarshalText() require.NoError(t, err) fmt.Printf("debug bz: %s\n", bz) - var d2 = Dec{new(big.Int)} + d2 := Dec{new(big.Int)} err = d2.UnmarshalText(bz) require.NoError(t, err) require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -//func TestDSerializationGoWireJSON(t *testing.T) { -//d := NewDec(1, 3) -//bz, err := cdc.MarshalJSON(d) -//require.NoError(t, err) +func TestDSerializationGoWireJSON(t *testing.T) { + d := MustNewDecFromStr("0.333") -//var d2 Dec -//err = cdc.UnmarshalJSON(bz, &d2) -//require.NoError(t, err) -//require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -//} + bz, err := dcdc.MarshalJSON(d) + require.NoError(t, err) + + d2 := Dec{new(big.Int)} + err = dcdc.UnmarshalJSON(bz, &d2) + require.NoError(t, err) + require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) +} func TestDSerializationGoWireBinary(t *testing.T) { - d := NewDec(1, 3) - bz, err := cdc.MarshalBinary(d) + d := MustNewDecFromStr("0.333") + + bz, err := dcdc.MarshalBinary(d) require.NoError(t, err) var d2 Dec @@ -253,25 +257,25 @@ func TestDSerializationGoWireBinary(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -//type testDEmbedStruct struct { -//Field1 string `json:"f1"` -//Field2 int `json:"f2"` -//Field3 Dec `json:"f3"` -//} - -//func TestDEmbeddedStructSerializationGoWire(t *testing.T) { -//obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} -//bz, err := cdc.MarshalJSON(obj) -//require.Nil(t, err) - -//var obj2 testDEmbedStruct -//err = cdc.UnmarshalJSON(bz, &obj2) -//require.Nil(t, err) - -//require.Equal(t, obj.Field1, obj2.Field1) -//require.Equal(t, obj.Field2, obj2.Field2) -//require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) -//} +type testDEmbedStruct struct { + Field1 string `json:"f1"` + Field2 int `json:"f2"` + Field3 Dec `json:"f3"` +} + +func TestDEmbeddedStructSerializationGoWire(t *testing.T) { + obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} + bz, err := cdc.MarshalBinary(obj) + require.Nil(t, err) + + var obj2 testDEmbedStruct + err = dcdc.UnmarshalBinary(bz, &obj2) + require.Nil(t, err) + + require.Equal(t, obj.Field1, obj2.Field1) + require.Equal(t, obj.Field2, obj2.Field2) + require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) +} func TestDStringOverflow(t *testing.T) { // two random 64 bit primes From 6b2dab7be95e1a55df4cf58319be207626cdbc4c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:25:20 -0400 Subject: [PATCH 18/50] ... --- types/decimal_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/types/decimal_test.go b/types/decimal_test.go index b73b825c1200..c55780adedee 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -263,6 +263,7 @@ type testDEmbedStruct struct { Field3 Dec `json:"f3"` } +// TODO make work for UnmarshalJSON func TestDEmbeddedStructSerializationGoWire(t *testing.T) { obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} bz, err := cdc.MarshalBinary(obj) From ee0e1795a69cf9af1ee16df1a6754dc6f3c4c585 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:26:06 -0400 Subject: [PATCH 19/50] deleted rational --- types/rational.go | 262 --------------------------------- types/rational_test.go | 319 ----------------------------------------- 2 files changed, 581 deletions(-) delete mode 100644 types/rational.go delete mode 100644 types/rational_test.go diff --git a/types/rational.go b/types/rational.go deleted file mode 100644 index 89cc76968ae8..000000000000 --- a/types/rational.go +++ /dev/null @@ -1,262 +0,0 @@ -package types - -import ( - "fmt" - "math/big" - "strconv" - "strings" - "testing" -) - -// "that's one big rat!" -// ______ -// / / /\ \____oo -// __ /___...._____ _\o -// __| |_ |_ - -// NOTE: never use new(Rat) or else -// we will panic unmarshalling into the -// nil embedded big.Rat -type Rat struct { - *big.Rat `json:"rat"` -} - -// nolint - common values -func ZeroRat() Rat { return Rat{big.NewRat(0, 1)} } -func OneRat() Rat { return Rat{big.NewRat(1, 1)} } - -// New - create a new Rat from integers -func NewRat(Numerator int64, Denominator ...int64) Rat { - switch len(Denominator) { - case 0: - return Rat{big.NewRat(Numerator, 1)} - case 1: - return Rat{big.NewRat(Numerator, Denominator[0])} - default: - panic("improper use of New, can only have one denominator") - } -} - -func getNumeratorDenominator(str []string, prec int) (numerator string, denom int64, err Error) { - switch len(str) { - case 1: - if len(str[0]) == 0 { - return "", 0, ErrUnknownRequest("not a decimal string") - } - numerator = str[0] - return numerator, 1, nil - case 2: - if len(str[0]) == 0 || len(str[1]) == 0 { - return "", 0, ErrUnknownRequest("not a decimal string") - } - if len(str[1]) > prec { - return "", 0, ErrUnknownRequest("string has too many decimals") - } - numerator = str[0] + str[1] - len := int64(len(str[1])) - denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() - return numerator, denom, nil - default: - return "", 0, ErrUnknownRequest("not a decimal string") - } -} - -// create a rational from decimal string or integer string -// 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 - if len(decimalStr) == 0 { - return f, ErrUnknownRequest("decimal string is empty") - } - - neg := false - if string(decimalStr[0]) == "-" { - neg = true - decimalStr = decimalStr[1:] - } - - str := strings.Split(decimalStr, ".") - - numStr, denom, err := getNumeratorDenominator(str, prec) - if err != nil { - return f, err - } - - num, errConv := strconv.Atoi(numStr) - if errConv != nil && strings.HasSuffix(errConv.Error(), "value out of range") { - // resort to big int, don't make this default option for efficiency - 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 - } else if errConv != nil { - return f, ErrUnknownRequest("not a decimal string") - } - - if neg { - num *= -1 - } - - return NewRat(int64(num), denom), nil -} - -// NewRatFromBigInt constructs Rat from big.Int -func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat { - switch len(denom) { - case 0: - return Rat{new(big.Rat).SetInt(num)} - case 1: - return Rat{new(big.Rat).SetFrac(num, denom[0])} - default: - panic("improper use of NewRatFromBigInt, can only have one denominator") - } -} - -// NewRatFromInt constructs Rat from Int -func NewRatFromInt(num Int, denom ...Int) Rat { - switch len(denom) { - case 0: - return Rat{new(big.Rat).SetInt(num.BigInt())} - case 1: - return Rat{new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())} - default: - panic("improper use of NewRatFromBigInt, can only have one denominator") - } -} - -//nolint -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 -func (r Rat) LT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == -1 } // less than -func (r Rat) LTE(r2 Rat) bool { return !r.GT(r2) } // less than or equal -func (r Rat) Mul(r2 Rat) Rat { return Rat{new(big.Rat).Mul(r.Rat, r2.Rat)} } // Mul - multiplication -func (r Rat) Quo(r2 Rat) Rat { return Rat{new(big.Rat).Quo(r.Rat, r2.Rat)} } // Quo - quotient -func (r Rat) Add(r2 Rat) Rat { return Rat{new(big.Rat).Add(r.Rat, r2.Rat)} } // Add - addition -func (r Rat) Sub(r2 Rat) Rat { return Rat{new(big.Rat).Sub(r.Rat, r2.Rat)} } // Sub - subtraction -func (r Rat) String() string { return r.Rat.String() } -func (r Rat) FloatString() string { return r.Rat.FloatString(10) } // a human-friendly string format. The last digit is rounded to nearest, with halves rounded away from zero. - -var ( - zero = big.NewInt(0) - one = big.NewInt(1) - two = big.NewInt(2) - five = big.NewInt(5) - nFive = big.NewInt(-5) - ten = big.NewInt(10) -) - -// evaluate the rational using bankers rounding -func (r Rat) EvaluateBig() *big.Int { - - num := r.Rat.Num() - denom := r.Rat.Denom() - - d, rem := new(big.Int), new(big.Int) - d.QuoRem(num, denom, rem) - if rem.Cmp(zero) == 0 { // is the remainder zero - return d - } - - // evaluate the remainder using bankers rounding - tenNum := new(big.Int).Mul(num, ten) - tenD := new(big.Int).Mul(d, ten) - remainderDigit := new(big.Int).Sub(new(big.Int).Quo(tenNum, denom), tenD) // get the first remainder digit - isFinalDigit := (new(big.Int).Rem(tenNum, denom).Cmp(zero) == 0) // is this the final digit in the remainder? - - switch { - case isFinalDigit && (remainderDigit.Cmp(five) == 0 || remainderDigit.Cmp(nFive) == 0): - dRem2 := new(big.Int).Rem(d, two) - return new(big.Int).Add(d, dRem2) // always rounds to the even number - case remainderDigit.Cmp(five) != -1: //remainderDigit >= 5: - d.Add(d, one) - case remainderDigit.Cmp(nFive) != 1: //remainderDigit <= -5: - d.Sub(d, one) - } - return d -} - -// RoundInt64 rounds the rational using bankers rounding -func (r Rat) RoundInt64() int64 { - return r.EvaluateBig().Int64() -} - -// RoundInt round the rational using bankers rounding -func (r Rat) RoundInt() Int { - return NewIntFromBigInt(r.EvaluateBig()) -} - -// round Rat with the provided precisionFactor -func (r Rat) Round(precisionFactor int64) Rat { - rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))} - return Rat{big.NewRat(rTen.RoundInt64(), precisionFactor)} -} - -// TODO panic if negative or if totalDigits < len(initStr)??? -// evaluate as an integer and return left padded string -func (r Rat) ToLeftPadded(totalDigits int8) string { - intStr := r.EvaluateBig().String() - fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` - return fmt.Sprintf(fcode, intStr) -} - -//___________________________________________________________________________________ - -//Wraps r.MarshalText(). -func (r Rat) MarshalAmino() (string, error) { - if r.Rat == nil { - r.Rat = new(big.Rat) - } - bz, err := r.Rat.MarshalText() - return string(bz), err -} - -// Requires a valid JSON string - strings quotes and calls UnmarshalText -func (r *Rat) UnmarshalAmino(text string) (err error) { - tempRat := big.NewRat(0, 1) - err = tempRat.UnmarshalText([]byte(text)) - if err != nil { - return err - } - r.Rat = tempRat - return nil -} - -//___________________________________________________________________________________ -// helpers - -// test if two rat arrays are equal -func RatsEqual(r1s, r2s []Rat) bool { - if len(r1s) != len(r2s) { - return false - } - - for i, r1 := range r1s { - if !r1.Equal(r2s[i]) { - return false - } - } - return true -} - -// intended to be used with require/assert: require.True(RatEq(...)) -func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) { - return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got -} - -// minimum rational between two -func MinRat(r1, r2 Rat) Rat { - if r1.LT(r2) { - return r1 - } - return r2 -} diff --git a/types/rational_test.go b/types/rational_test.go deleted file mode 100644 index 5ca1ac9c6e5a..000000000000 --- a/types/rational_test.go +++ /dev/null @@ -1,319 +0,0 @@ -package types - -import ( - "math/big" - "testing" - - wire "github.com/cosmos/cosmos-sdk/wire" - "github.com/stretchr/testify/require" -) - -func TestNew(t *testing.T) { - require.Equal(t, NewRat(1), NewRat(1, 1)) - require.Equal(t, NewRat(100), NewRat(100, 1)) - require.Equal(t, NewRat(-1), NewRat(-1, 1)) - require.Equal(t, NewRat(-100), NewRat(-100, 1)) - require.Equal(t, NewRat(0), NewRat(0, 1)) - - // do not allow for more than 2 variables - require.Panics(t, func() { NewRat(1, 1, 1) }) -} - -func TestNewFromDecimal(t *testing.T) { - largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10) - require.True(t, success) - tests := []struct { - decimalStr string - expErr bool - exp Rat - }{ - {"", true, Rat{}}, - {"0", false, NewRat(0)}, - {"1", false, NewRat(1)}, - {"1.1", false, NewRat(11, 10)}, - {"0.75", false, NewRat(3, 4)}, - {"0.8", false, NewRat(4, 5)}, - {"0.11111", true, NewRat(1111, 10000)}, - {"628240629832763.5738930323617075341", true, NewRat(3141203149163817869, 5000)}, - {"621947210595948537540277652521.5738930323617075341", - true, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, - {"628240629832763.5738", false, NewRat(3141203149163817869, 5000)}, - {"621947210595948537540277652521.5738", - false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, - {".", true, Rat{}}, - {".0", true, Rat{}}, - {"1.", true, Rat{}}, - {"foobar", true, Rat{}}, - {"0.foobar", true, Rat{}}, - {"0.foobar.", true, Rat{}}, - } - - for tcIndex, tc := range tests { - res, err := NewRatFromDecimal(tc.decimalStr, 4) - if tc.expErr { - require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex) - } else { - require.Nil(t, err, tc.decimalStr, "unexpected error, tc #%d", tcIndex) - require.True(t, res.Equal(tc.exp), tc.decimalStr, "equality was incorrect, tc #%d", tcIndex) - } - - // negative tc - res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) - if tc.expErr { - require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex) - } else { - require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex) - require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex) - } - } -} - -func TestEqualities(t *testing.T) { - tests := []struct { - r1, r2 Rat - gt, lt, eq bool - }{ - {NewRat(0), NewRat(0), false, false, true}, - {NewRat(0, 100), NewRat(0, 10000), false, false, true}, - {NewRat(100), NewRat(100), false, false, true}, - {NewRat(-100), NewRat(-100), false, false, true}, - {NewRat(-100, -1), NewRat(100), false, false, true}, - {NewRat(-1, 1), NewRat(1, -1), false, false, true}, - {NewRat(1, -1), NewRat(-1, 1), false, false, true}, - {NewRat(3, 7), NewRat(3, 7), false, false, true}, - - {NewRat(0), NewRat(3, 7), false, true, false}, - {NewRat(0), NewRat(100), false, true, false}, - {NewRat(-1), NewRat(3, 7), false, true, false}, - {NewRat(-1), NewRat(100), false, true, false}, - {NewRat(1, 7), NewRat(100), false, true, false}, - {NewRat(1, 7), NewRat(3, 7), false, true, false}, - {NewRat(-3, 7), NewRat(-1, 7), false, true, false}, - - {NewRat(3, 7), NewRat(0), true, false, false}, - {NewRat(100), NewRat(0), true, false, false}, - {NewRat(3, 7), NewRat(-1), true, false, false}, - {NewRat(100), NewRat(-1), true, false, false}, - {NewRat(100), NewRat(1, 7), true, false, false}, - {NewRat(3, 7), NewRat(1, 7), true, false, false}, - {NewRat(-1, 7), NewRat(-3, 7), true, false, false}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.gt, tc.r1.GT(tc.r2), "GT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.lt, tc.r1.LT(tc.r2), "LT result is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.eq, tc.r1.Equal(tc.r2), "equality result is incorrect, tc #%d", tcIndex) - } - -} - -func TestArithmetic(t *testing.T) { - tests := []struct { - r1, r2 Rat - resMul, resDiv, resAdd, resSub Rat - }{ - // r1 r2 MUL DIV ADD SUB - {NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0)}, - {NewRat(1), NewRat(0), NewRat(0), NewRat(0), NewRat(1), NewRat(1)}, - {NewRat(0), NewRat(1), NewRat(0), NewRat(0), NewRat(1), NewRat(-1)}, - {NewRat(0), NewRat(-1), NewRat(0), NewRat(0), NewRat(-1), NewRat(1)}, - {NewRat(-1), NewRat(0), NewRat(0), NewRat(0), NewRat(-1), NewRat(-1)}, - - {NewRat(1), NewRat(1), NewRat(1), NewRat(1), NewRat(2), NewRat(0)}, - {NewRat(-1), NewRat(-1), NewRat(1), NewRat(1), NewRat(-2), NewRat(0)}, - {NewRat(1), NewRat(-1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(2)}, - {NewRat(-1), NewRat(1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(-2)}, - - {NewRat(3), NewRat(7), NewRat(21), NewRat(3, 7), NewRat(10), NewRat(-4)}, - {NewRat(2), NewRat(4), NewRat(8), NewRat(1, 2), NewRat(6), NewRat(-2)}, - {NewRat(100), NewRat(100), NewRat(10000), NewRat(1), NewRat(200), NewRat(0)}, - - {NewRat(3, 2), NewRat(3, 2), NewRat(9, 4), NewRat(1), NewRat(3), NewRat(0)}, - {NewRat(3, 7), NewRat(7, 3), NewRat(1), NewRat(9, 49), NewRat(58, 21), NewRat(-40, 21)}, - {NewRat(1, 21), NewRat(11, 5), NewRat(11, 105), NewRat(5, 231), NewRat(236, 105), NewRat(-226, 105)}, - {NewRat(-21), NewRat(3, 7), NewRat(-9), NewRat(-49), NewRat(-144, 7), NewRat(-150, 7)}, - {NewRat(100), NewRat(1, 7), NewRat(100, 7), NewRat(700), NewRat(701, 7), NewRat(699, 7)}, - } - - for tcIndex, tc := range tests { - require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - - if tc.r2.Num().IsZero() { // panic for divide by zero - require.Panics(t, func() { tc.r1.Quo(tc.r2) }) - } else { - require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex) - } - } -} - -func TestEvaluate(t *testing.T) { - tests := []struct { - r1 Rat - res int64 - }{ - {NewRat(0), 0}, - {NewRat(1), 1}, - {NewRat(1, 4), 0}, - {NewRat(1, 2), 0}, - {NewRat(3, 4), 1}, - {NewRat(5, 6), 1}, - {NewRat(3, 2), 2}, - {NewRat(5, 2), 2}, - {NewRat(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {NewRat(17, 11), 2}, // 1.545 - {NewRat(5, 11), 0}, - {NewRat(16, 11), 1}, - {NewRat(113, 12), 9}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v. tc #%d", tc.r1, tcIndex) - require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v. tc #%d", tc.r1.Mul(NewRat(-1)), tcIndex) - } -} - -func TestRound(t *testing.T) { - many3 := "333333333333333333333333333333333333333333333" - many7 := "777777777777777777777777777777777777777777777" - big3, worked := new(big.Int).SetString(many3, 10) - require.True(t, worked) - big7, worked := new(big.Int).SetString(many7, 10) - require.True(t, worked) - - tests := []struct { - r, res Rat - precFactor int64 - }{ - {NewRat(333, 777), NewRat(429, 1000), 1000}, - {Rat{new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000}, - {Rat{new(big.Rat).SetFrac(big3, big7)}, Rat{big.NewRat(4285714286, 10000000000)}, 10000000000}, - {NewRat(1, 2), NewRat(1, 2), 1000}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r, "incorrect rounding, tc #%d", tcIndex) - negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1)) - require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex) - } -} - -func TestToLeftPadded(t *testing.T) { - tests := []struct { - rat Rat - digits int8 - res string - }{ - {NewRat(100, 3), 8, "00000033"}, - {NewRat(1, 3), 8, "00000000"}, - {NewRat(100, 2), 8, "00000050"}, - {NewRat(1000, 3), 8, "00000333"}, - {NewRat(1000, 3), 12, "000000000333"}, - } - for tcIndex, tc := range tests { - require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex) - } -} - -var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec - -func TestZeroSerializationJSON(t *testing.T) { - r := NewRat(0, 1) - err := cdc.UnmarshalJSON([]byte(`"0/1"`), &r) - require.Nil(t, err) - err = cdc.UnmarshalJSON([]byte(`"0/0"`), &r) - require.NotNil(t, err) - err = cdc.UnmarshalJSON([]byte(`"1/0"`), &r) - require.NotNil(t, err) - err = cdc.UnmarshalJSON([]byte(`"{}"`), &r) - require.NotNil(t, err) -} - -func TestSerializationText(t *testing.T) { - r := NewRat(1, 3) - - bz, err := r.MarshalText() - require.NoError(t, err) - - var r2 = Rat{new(big.Rat)} - err = r2.UnmarshalText(bz) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -func TestSerializationGoWireJSON(t *testing.T) { - r := NewRat(1, 3) - bz, err := cdc.MarshalJSON(r) - require.NoError(t, err) - - var r2 Rat - err = cdc.UnmarshalJSON(bz, &r2) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -func TestSerializationGoWireBinary(t *testing.T) { - r := NewRat(1, 3) - bz, err := cdc.MarshalBinary(r) - require.NoError(t, err) - - var r2 Rat - err = cdc.UnmarshalBinary(bz, &r2) - require.NoError(t, err) - require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) -} - -type testEmbedStruct struct { - Field1 string `json:"f1"` - Field2 int `json:"f2"` - Field3 Rat `json:"f3"` -} - -func TestEmbeddedStructSerializationGoWire(t *testing.T) { - obj := testEmbedStruct{"foo", 10, NewRat(1, 3)} - bz, err := cdc.MarshalJSON(obj) - require.Nil(t, err) - - var obj2 testEmbedStruct - err = cdc.UnmarshalJSON(bz, &obj2) - require.Nil(t, err) - - require.Equal(t, obj.Field1, obj2.Field1) - require.Equal(t, obj.Field2, obj2.Field2) - require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) -} - -func TestRatsEqual(t *testing.T) { - tests := []struct { - r1s, r2s []Rat - eq bool - }{ - {[]Rat{NewRat(0)}, []Rat{NewRat(0)}, true}, - {[]Rat{NewRat(0)}, []Rat{NewRat(1)}, false}, - {[]Rat{NewRat(0)}, []Rat{}, false}, - {[]Rat{NewRat(0), NewRat(1)}, []Rat{NewRat(0), NewRat(1)}, true}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1), NewRat(0)}, true}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(0), NewRat(1)}, false}, - {[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1)}, false}, - {[]Rat{NewRat(1), NewRat(2)}, []Rat{NewRat(2), NewRat(4)}, false}, - {[]Rat{NewRat(3), NewRat(18)}, []Rat{NewRat(1), NewRat(6)}, false}, - } - - for tcIndex, tc := range tests { - require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s), "equality of rational arrays is incorrect, tc #%d", tcIndex) - require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s), "equality of rational arrays is incorrect (converse), tc #%d", tcIndex) - } - -} - -func TestStringOverflow(t *testing.T) { - // two random 64 bit primes - rat1 := NewRat(5164315003622678713, 4389711697696177267) - rat2 := NewRat(-3179849666053572961, 8459429845579852627) - rat3 := rat1.Add(rat2) - require.Equal(t, - "29728537197630860939575850336935951464/37134458148982045574552091851127630409", - rat3.String(), - ) -} From 546a4ca49ab3c69347f6cd8d58b3f964fdb6446b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:45:01 -0400 Subject: [PATCH 20/50] rational conversion working --- CHANGELOG.md | 4 +- client/lcd/test_helpers.go | 2 +- cmd/gaia/app/genesis.go | 6 +- cmd/gaia/app/sim_test.go | 2 +- cmd/gaia/cli_test/cli_test.go | 2 +- docs/resources/whitepaper.md | 2 +- docs/sdk/core/app3.md | 2 +- docs/spec/governance/state.md | 14 +-- docs/spec/ibc/appendices.md | 4 +- docs/spec/ibc/overview.md | 2 +- docs/spec/provisioning/overview.md | 10 +- docs/spec/staking/end_block.md | 8 +- docs/spec/staking/state.md | 32 +++--- docs/spec/staking/transactions.md | 12 +- examples/democoin/mock/validator.go | 18 +-- .../democoin/x/assoc/validator_set_test.go | 4 +- examples/democoin/x/oracle/README.md | 2 +- examples/democoin/x/oracle/handler.go | 2 +- examples/democoin/x/oracle/keeper.go | 8 +- examples/democoin/x/oracle/oracle_test.go | 10 +- server/util.go | 4 +- types/decimal.go | 32 ++---- types/decimal_test.go | 61 +++++----- types/stake.go | 12 +- x/fee_distribution/keeper.go | 4 +- x/fee_distribution/keeper_test.go | 8 +- x/fee_distribution/movement.go | 22 ++-- x/fee_distribution/types.go | 22 ++-- x/gov/genesis.go | 6 +- x/gov/procedures.go | 6 +- x/gov/tally.go | 22 ++-- x/gov/test_common.go | 2 +- x/ibc/mapper.go | 2 +- x/params/keeper.go | 12 +- x/params/keeper_test.go | 16 +-- x/slashing/app_test.go | 4 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper_test.go | 10 +- x/slashing/params.go | 18 +-- x/slashing/test_common.go | 6 +- x/slashing/tick_test.go | 2 +- x/stake/app_test.go | 18 +-- x/stake/client/cli/tx.go | 12 +- x/stake/client/rest/tx.go | 4 +- x/stake/genesis_test.go | 20 ++-- x/stake/handler_test.go | 70 ++++++------ x/stake/keeper/delegation.go | 10 +- x/stake/keeper/delegation_test.go | 32 +++--- x/stake/keeper/keeper_test.go | 2 +- x/stake/keeper/sdk_types.go | 2 +- x/stake/keeper/slash.go | 24 ++-- x/stake/keeper/slash_test.go | 58 +++++----- x/stake/keeper/test_common.go | 10 +- x/stake/keeper/validator_test.go | 96 ++++++++-------- x/stake/simulation/invariants.go | 4 +- x/stake/simulation/msgs.go | 6 +- x/stake/types/delegation.go | 14 +-- x/stake/types/delegation_test.go | 16 +-- x/stake/types/errors.go | 7 -- x/stake/types/inflation_test.go | 74 ++++++------ x/stake/types/msg.go | 26 +---- x/stake/types/msg_test.go | 26 ++--- x/stake/types/params.go | 16 +-- x/stake/types/pool.go | 56 ++++----- x/stake/types/pool_test.go | 22 ++-- x/stake/types/validator.go | 106 +++++++++--------- x/stake/types/validator_test.go | 78 ++++++------- 67 files changed, 601 insertions(+), 627 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29d753a6dc43..41e068c5adca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,7 +134,7 @@ FEATURES * gocyclo * [tools] Added `make format` command to automate fixing misspell and gofmt errors. * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates -* [types] Switches internal representation of Int/Uint/Rat to use pointers +* [types] Switches internal representation of Int/Uint/Dec to use pointers * [types] Added MinInt and MinUint functions * [gaiad] `unsafe_reset_all` now resets addrbook.json * [democoin] add x/oracle, x/assoc @@ -383,7 +383,7 @@ BREAKING CHANGES * Removed SealedAccountMapper * gaiad init now requires use of `--name` flag * Removed Get from Msg interface -* types/rational now extends big.Rat +* types/rational now extends big.Dec FEATURES: diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 49ffc441b33a..7c3bac5dbb6f 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -147,7 +147,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewCoin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewRat(100)) + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index af547e844620..b80150208789 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -160,7 +160,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState } acc := NewGenesisAccount(&accAuth) genaccs[i] = acc - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionsAcc)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc)) // increase the supply // add the validator if len(genTx.Name) > 0 { @@ -168,10 +168,10 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState validator := stake.NewValidator(genTx.Address, sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc) - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionVal)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply // add some new shares to the validator - var issuedDelShares sdk.Rat + var issuedDelShares sdk.Dec validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, freeFermionVal) stakeData.Validators = append(stakeData.Validators, validator) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index f0bea1e177fc..6369b4ca66fc 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -48,7 +48,7 @@ func appStateFn(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage { // Default genesis state stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(1000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(1000) genesis := GenesisState{ Accounts: genesisAccounts, StakeData: stakeGenesis, diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7fa438e9dcb1..7db80c9cc832 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -132,7 +132,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.True(sdk.RatEq(t, sdk.NewRat(2), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens)) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) diff --git a/docs/resources/whitepaper.md b/docs/resources/whitepaper.md index 62707c08040f..3b7b08d23ebb 100644 --- a/docs/resources/whitepaper.md +++ b/docs/resources/whitepaper.md @@ -821,7 +821,7 @@ in the case of a successful double-spend attack. Building on an approach pioneered by Ripple, Stellar [\[13\]][13] refined a model of Federated Byzantine Agreement wherein the processes participating in -consensus do not constitute a fixed and globally known set. Rather, each +consensus do not constitute a fixed and globally known set. Decher, each process node curates one or more "quorum slices", each constituting a set of trusted processes. A "quorum" in Stellar is defined to be a set of nodes that contain at least one quorum slice for each node in the set, such that agreement diff --git a/docs/sdk/core/app3.md b/docs/sdk/core/app3.md index 66bb05521b78..c933315589a4 100644 --- a/docs/sdk/core/app3.md +++ b/docs/sdk/core/app3.md @@ -312,7 +312,7 @@ accounts. We use this `Keeper` paradigm extensively in the SDK as the way to define what kind of functionality each module gets access to. In particular, we try to follow the *principle of least authority*. -Rather than providing full blown access to the `KVStore` or the `AccountMapper`, +Decher than providing full blown access to the `KVStore` or the `AccountMapper`, we restrict access to a small number of functions that do very specific things. ## App3 diff --git a/docs/spec/governance/state.md b/docs/spec/governance/state.md index c61fd1e3f29c..9c848bb0c479 100644 --- a/docs/spec/governance/state.md +++ b/docs/spec/governance/state.md @@ -27,7 +27,7 @@ type VotingProcedure struct { type TallyingProcedure struct { Threshold rational.Rational // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 Veto rational.Rational // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 - GovernancePenalty sdk.Rat // Penalty if validator does not vote + GovernancePenalty sdk.Dec // Penalty if validator does not vote GracePeriod int64 // If validator entered validator set in this period of blocks before vote ended, governance penalty does not apply } ``` @@ -81,7 +81,7 @@ This type is used in a temp map when tallying ```go type ValidatorGovInfo struct { - Minus sdk.Rat + Minus sdk.Dec Vote Vote } ``` @@ -103,17 +103,17 @@ type Proposal struct { VotingStartBlock int64 // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached CurrentStatus ProposalStatus // Current status of the proposal - YesVotes sdk.Rat - NoVotes sdk.Rat - NoWithVetoVotes sdk.Rat - AbstainVotes sdk.Rat + YesVotes sdk.Dec + NoVotes sdk.Dec + NoWithVetoVotes sdk.Dec + AbstainVotes sdk.Dec } ``` We also mention a method to update the tally for a given proposal: ```go - func (proposal Proposal) updateTally(vote byte, amount sdk.Rat) + func (proposal Proposal) updateTally(vote byte, amount sdk.Dec) ``` ### Stores diff --git a/docs/spec/ibc/appendices.md b/docs/spec/ibc/appendices.md index 751924f4692d..933ba73128d4 100644 --- a/docs/spec/ibc/appendices.md +++ b/docs/spec/ibc/appendices.md @@ -31,11 +31,11 @@ See [binary format as protobuf specification](./protobuf/queue.proto) A Merkle tree (or a trie) generates a single hash that can be used to prove any element of the tree. In order to generate this hash, we first hash the leaf nodes, then hash multiple leaf nodes together to get the hash of an inner node (two or more, based on degree k of the k-ary tree), and repeat for each level of the tree until we end up with one root hash. With a known root hash (which is included in the block headers), the existence of a particular key/value in the tree can be proven by tracing the path to the value and revealing the (k-1) hashes for the paths not taken on each level ([[10](./references.md#10)]). -There are a number of different implementations of this basic idea, using different hash functions, as well as prefixes to prevent second preimage attacks (differentiating leaf nodes from inner nodes). Rather than force all chains that wish to participate in IBC to use the same data store, we provide a data structure that can represent Merkle proofs from a variety of data stores, and provide for chaining proofs to allow for subtrees. While searching for a solution, we did find the chainpoint proof format[[11](./references.md#11)], which inspired this design significantly, but didn't (yet) offer the flexibility we needed. +There are a number of different implementations of this basic idea, using different hash functions, as well as prefixes to prevent second preimage attacks (differentiating leaf nodes from inner nodes). Decher than force all chains that wish to participate in IBC to use the same data store, we provide a data structure that can represent Merkle proofs from a variety of data stores, and provide for chaining proofs to allow for subtrees. While searching for a solution, we did find the chainpoint proof format[[11](./references.md#11)], which inspired this design significantly, but didn't (yet) offer the flexibility we needed. We generalize the left/right idiom to the concatenation a (possibly empty) fixed prefix, the (just calculated) last hash, and a (possibly empty) fixed suffix. We must only define two fields on each level and can represent any type, even a 16-ary Patricia tree, with this structure. One must only translate from the store's native proof to this format, and it can be verified by any chain, providing compatibility with arbitrary data stores. -The proof format also allows for chaining of trees, combining multiple Merkle stores into a "multi-store". Many applications (such as the EVM) define a data store with a large proof size for internal use. Rather than force them to change the store (impossible), or live with huge proofs (inefficient), we provide the possibility to express Merkle proofs connecting multiple subtrees. Thus, one could have one subtree for data, and a second for IBC. Each tree produces its own Merkle root, and these are then hashed together to produce the root hash that is stored in the block header. +The proof format also allows for chaining of trees, combining multiple Merkle stores into a "multi-store". Many applications (such as the EVM) define a data store with a large proof size for internal use. Decher than force them to change the store (impossible), or live with huge proofs (inefficient), we provide the possibility to express Merkle proofs connecting multiple subtrees. Thus, one could have one subtree for data, and a second for IBC. Each tree produces its own Merkle root, and these are then hashed together to produce the root hash that is stored in the block header. A valid Merkle proof for IBC must either consist of a proof of one tree, and prepend `ibc` to all key names as defined above, or use a subtree named `ibc` in the first section, and store the key names as above in the second tree. diff --git a/docs/spec/ibc/overview.md b/docs/spec/ibc/overview.md index 344f69c7d721..e59559deac57 100644 --- a/docs/spec/ibc/overview.md +++ b/docs/spec/ibc/overview.md @@ -8,7 +8,7 @@ The IBC protocol creates a mechanism by which two replicated fault-tolerant stat The IBC protocol assumes that multiple applications are running on their own blockchain with their own state and own logic. Communication is achieved over an ordered message queue primitive, allowing the creation of complex inter-chain processes without trusted third parties. -The message packets are not signed by one psuedonymous account, or even multiple, as in multi-signature sidechain implementations. Rather, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains. +The message packets are not signed by one psuedonymous account, or even multiple, as in multi-signature sidechain implementations. Decher, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains. In this paper, we define a process of posting block headers and Merkle tree proofs to enable secure verification of individual packets. We then describe how to combine these packets into a messaging queue to guarantee ordered delivery. We then explain how to handle packet receipts (response/error) on the source chain, which enables the creation of asynchronous RPC-like protocols on top of IBC. Finally, we detail some optimizations and how to handle Byzantine blockchains. diff --git a/docs/spec/provisioning/overview.md b/docs/spec/provisioning/overview.md index 046223a4b06d..958243658ed6 100644 --- a/docs/spec/provisioning/overview.md +++ b/docs/spec/provisioning/overview.md @@ -113,8 +113,8 @@ occur on an epoch basis. ```golang type powerChange struct { height int64 // block height at change - power rational.Rat // total power at change - prevpower rational.Rat // total power at previous height-1 + power rational.Dec // total power at change + prevpower rational.Dec // total power at previous height-1 feesin coins.Coin // fees in at block height prevFeePool coins.Coin // total fees in at previous block height } @@ -205,13 +205,13 @@ defined to be 13% per year, however the annual inflation is capped as between 7% and 20%. ```go -inflationRateChange(0) = 0 +inflationDeceChange(0) = 0 Inflation(0) = 0.07 bondedRatio = Pool.BondedTokens / Pool.TotalSupplyTokens -AnnualInflationRateChange = (1 - bondedRatio / 0.67) * 0.13 +AnnualInflationDeceChange = (1 - bondedRatio / 0.67) * 0.13 -annualInflation += AnnualInflationRateChange +annualInflation += AnnualInflationDeceChange if annualInflation > 0.20 then Inflation = 0.20 if annualInflation < 0.07 then Inflation = 0.07 diff --git a/docs/spec/staking/end_block.md b/docs/spec/staking/end_block.md index 61643f52665f..04cc98e1a638 100644 --- a/docs/spec/staking/end_block.md +++ b/docs/spec/staking/end_block.md @@ -42,16 +42,16 @@ processProvisions(): setPool(pool) -nextInflation(hrsPerYr rational.Rat): +nextInflation(hrsPerYr rational.Dec): if pool.TotalSupply > 0 bondedRatio = pool.BondedPool / pool.TotalSupply else bondedRation = 0 - inflationRateChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationRateChange - inflationRateChange = inflationRateChangePerYear / hrsPerYr + inflationDeceChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationDeceChange + inflationDeceChange = inflationDeceChangePerYear / hrsPerYr - inflation = pool.Inflation + inflationRateChange + inflation = pool.Inflation + inflationDeceChange if inflation > params.InflationMax then inflation = params.InflationMax if inflation < params.InflationMin then inflation = params.InflationMin diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 76101e609750..143a6da90aa8 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -14,7 +14,7 @@ type Pool struct { LooseTokens int64 // tokens not associated with any bonded validator BondedTokens int64 // reserve of bonded tokens InflationLastTime int64 // block which the last inflation was processed // TODO make time - Inflation sdk.Rat // current annual inflation rate + Inflation sdk.Dec // current annual inflation rate DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily) } @@ -29,10 +29,10 @@ overall functioning of the stake module. ```golang type Params struct { - InflationRateChange sdk.Rat // maximum annual change in inflation rate - InflationMax sdk.Rat // maximum inflation rate - InflationMin sdk.Rat // minimum inflation rate - GoalBonded sdk.Rat // Goal of percent bonded atoms + InflationDeceChange sdk.Dec // maximum annual change in inflation rate + InflationMax sdk.Dec // maximum inflation rate + InflationMin sdk.Dec // minimum inflation rate + GoalBonded sdk.Dec // Goal of percent bonded atoms MaxValidators uint16 // maximum number of validators BondDenom string // bondable coin denomination @@ -75,9 +75,9 @@ type Validator struct { Revoked bool // has the validator been revoked? Status sdk.BondStatus // validator status (bonded/unbonding/unbonded) - Tokens sdk.Rat // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Rat // total shares issued to a validator's delegators - SlashRatio sdk.Rat // increases each time the validator is slashed + Tokens sdk.Dec // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Dec // total shares issued to a validator's delegators + SlashRatio sdk.Dec // increases each time the validator is slashed Description Description // description terms for the validator @@ -90,14 +90,14 @@ type Validator struct { ProposerRewardPool sdk.Coins // reward pool collected from being the proposer // TODO: maybe this belongs in distribution module ? - LastBondedTokens sdk.Rat // last bonded token amount + LastBondedTokens sdk.Dec // last bonded token amount } type CommissionInfo struct { - Rate sdk.Rat // the commission rate of fees charged to any delegators - Max sdk.Rat // maximum commission rate which this validator can ever charge - ChangeRate sdk.Rat // maximum daily increase of the validator commission - ChangeToday sdk.Rat // commission rate change today, reset each day (UTC time) + Dece sdk.Dec // the commission rate of fees charged to any delegators + Max sdk.Dec // maximum commission rate which this validator can ever charge + ChangeDece sdk.Dec // maximum daily increase of the validator commission + ChangeToday sdk.Dec // commission rate change today, reset each day (UTC time) LastChange int64 // unix timestamp of last commission change } @@ -123,7 +123,7 @@ the transaction is the owner of the bond. ```golang type Delegation struct { - Shares sdk.Rat // delegation shares recieved + Shares sdk.Dec // delegation shares recieved Height int64 // last height bond updated } ``` @@ -184,8 +184,8 @@ the original redelegation has been completed. ```golang type Redelegation struct { - SourceShares sdk.Rat // amount of source shares redelegating - DestinationShares sdk.Rat // amount of destination shares created at redelegation + SourceShares sdk.Dec // amount of source shares redelegating + DestinationShares sdk.Dec // amount of destination shares created at redelegation CompleteTime int64 // unix time to complete redelegation } ``` diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md index 55b1a8ed12c9..5fd574de6af4 100644 --- a/docs/spec/staking/transactions.md +++ b/docs/spec/staking/transactions.md @@ -19,7 +19,7 @@ Other notes: - `sender` denotes the address of the sender of the transaction - `getXxx`, `setXxx`, and `removeXxx` functions are used to retrieve and modify objects from the store - - `sdk.Rat` refers to a rational numeric type specified by the SDK. + - `sdk.Dec` refers to a rational numeric type specified by the SDK. ### TxCreateValidator @@ -33,9 +33,9 @@ type TxCreateValidator struct { SelfDelegation coin.Coin Description Description - Commission sdk.Rat - CommissionMax sdk.Rat - CommissionMaxChange sdk.Rat + Commission sdk.Dec + CommissionMax sdk.Dec + CommissionMaxChange sdk.Dec } @@ -64,7 +64,7 @@ If either the `Description` (excluding `DateBonded` which is constant), ```golang type TxEditCandidacy struct { GovernancePubKey crypto.PubKey - Commission sdk.Rat + Commission sdk.Dec Description Description } @@ -196,7 +196,7 @@ type TxRedelegate struct { DelegatorAddr Address ValidatorFrom Validator ValidatorTo Validator - Shares sdk.Rat + Shares sdk.Dec CompletedTime int64 } diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index 0ef0a23911eb..789a1cb6a7a8 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -10,7 +10,7 @@ import ( // Validator implements sdk.Validator type Validator struct { Address sdk.AccAddress - Power sdk.Rat + Power sdk.Dec } // Implements sdk.Validator @@ -29,18 +29,18 @@ func (v Validator) GetPubKey() crypto.PubKey { } // Implements sdk.Validator -func (v Validator) GetTokens() sdk.Rat { - return sdk.ZeroRat() +func (v Validator) GetTokens() sdk.Dec { + return sdk.ZeroDec() } // Implements sdk.Validator -func (v Validator) GetPower() sdk.Rat { +func (v Validator) GetPower() sdk.Dec { return v.Power } // Implements sdk.Validator -func (v Validator) GetDelegatorShares() sdk.Rat { - return sdk.ZeroRat() +func (v Validator) GetDelegatorShares() sdk.Dec { + return sdk.ZeroDec() } // Implements sdk.Validator @@ -93,8 +93,8 @@ func (vs *ValidatorSet) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) } // TotalPower implements sdk.ValidatorSet -func (vs *ValidatorSet) TotalPower(ctx sdk.Context) sdk.Rat { - res := sdk.ZeroRat() +func (vs *ValidatorSet) TotalPower(ctx sdk.Context) sdk.Dec { + res := sdk.ZeroDec() for _, val := range vs.Validators { res = res.Add(val.Power) } @@ -122,7 +122,7 @@ func (vs *ValidatorSet) RemoveValidator(addr sdk.AccAddress) { } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Rat) { +func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Dec) { panic("not implemented") } diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index 2fead3ad2660..eac23b25e221 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -32,8 +32,8 @@ func TestValidatorSet(t *testing.T) { addr2 := []byte("addr2") base := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewRat(1)}, - {addr2, sdk.NewRat(2)}, + {addr1, sdk.NewDec(1)}, + {addr2, sdk.NewDec(2)}, }} valset := NewValidatorSet(wire.NewCodec(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5) diff --git a/examples/democoin/x/oracle/README.md b/examples/democoin/x/oracle/README.md index eec02d72498d..0cfcb820d5b8 100644 --- a/examples/democoin/x/oracle/README.md +++ b/examples/democoin/x/oracle/README.md @@ -38,7 +38,7 @@ func NewHandler(keeper Keeper) sdk.Handler { In the previous example, the keeper has an `oracle.Keeper`. `oracle.Keeper`s are generated by `NewKeeper`. ```go -func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper { +func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper { return Keeper { cdc: cdc, key: key, diff --git a/examples/democoin/x/oracle/handler.go b/examples/democoin/x/oracle/handler.go index 079f7680f4cd..3c78fc566be6 100644 --- a/examples/democoin/x/oracle/handler.go +++ b/examples/democoin/x/oracle/handler.go @@ -23,7 +23,7 @@ func (keeper Keeper) update(ctx sdk.Context, val sdk.Validator, valset sdk.Valid // and recalculate voted power hash := ctx.BlockHeader().ValidatorsHash if !bytes.Equal(hash, info.Hash) { - info.Power = sdk.ZeroRat() + info.Power = sdk.ZeroDec() info.Hash = hash prefix := GetSignPrefix(p, keeper.cdc) store := ctx.KVStore(keeper.key) diff --git a/examples/democoin/x/oracle/keeper.go b/examples/democoin/x/oracle/keeper.go index 25554faa814b..0406f560a050 100644 --- a/examples/democoin/x/oracle/keeper.go +++ b/examples/democoin/x/oracle/keeper.go @@ -13,12 +13,12 @@ type Keeper struct { valset sdk.ValidatorSet - supermaj sdk.Rat + supermaj sdk.Dec timeout int64 } // NewKeeper constructs a new keeper -func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper { +func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper { if timeout < 0 { panic("Timeout should not be negative") } @@ -46,7 +46,7 @@ const ( // Info for each payload type Info struct { - Power sdk.Rat + Power sdk.Dec Hash []byte LastSigned int64 Status InfoStatus @@ -55,7 +55,7 @@ type Info struct { // EmptyInfo construct an empty Info func EmptyInfo(ctx sdk.Context) Info { return Info{ - Power: sdk.ZeroRat(), + Power: sdk.ZeroDec(), Hash: ctx.BlockHeader().ValidatorsHash, LastSigned: ctx.BlockHeight(), Status: Pending, diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index c476290f8adc..ac3a45695696 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -107,9 +107,9 @@ func TestOracle(t *testing.T) { addr3 := []byte("addr3") addr4 := []byte("addr4") valset := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewRat(7)}, - {addr2, sdk.NewRat(7)}, - {addr3, sdk.NewRat(1)}, + {addr1, sdk.NewDec(7)}, + {addr2, sdk.NewDec(7)}, + {addr3, sdk.NewDec(1)}, }} key := sdk.NewKVStoreKey("testkey") @@ -119,7 +119,7 @@ func TestOracle(t *testing.T) { require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) - ork := NewKeeper(key, cdc, valset, sdk.NewRat(2, 3), 100) + ork := NewKeeper(key, cdc, valset, sdk.NewDec(2, 3), 100) h := seqHandler(ork, key, sdk.CodespaceRoot) // Nonmock.Validator signed, transaction failed @@ -171,7 +171,7 @@ func TestOracle(t *testing.T) { require.Equal(t, 1, getSequence(ctx, key)) // Should handle mock.Validator set change - valset.AddValidator(mock.Validator{addr4, sdk.NewRat(12)}) + valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12)}) bz, err = json.Marshal(valset) require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) diff --git a/server/util.go b/server/util.go index 51547d116b2a..d3d5726e27d6 100644 --- a/server/util.go +++ b/server/util.go @@ -82,8 +82,8 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { // the following parse config is needed to create directories conf, _ = tcmd.ParseConfig() conf.ProfListenAddress = "localhost:6060" - conf.P2P.RecvRate = 5120000 - conf.P2P.SendRate = 5120000 + conf.P2P.RecvDece = 5120000 + conf.P2P.SendDece = 5120000 conf.Consensus.TimeoutCommit = 5000 cfg.WriteConfigFile(configFilePath, conf) // Fall through, just so that its parsed into memory. diff --git a/types/decimal.go b/types/decimal.go index 1668fd64d3a3..a81fa3ca852c 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -93,7 +93,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { return d, ErrUnknownRequest("too much Precision in decimal") } - // add some extra dzero's to correct to the Precision factor + // add some extra zero's to correct to the Precision factor zerosToAdd := Precision - lenDecs zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "") combinedStr = combinedStr + zeros @@ -108,23 +108,14 @@ func NewDecFromStr(str string) (d Dec, err Error) { return Dec{combined}, nil } -// create a decimal from a decimal string (ex. "1234.5678") -func MustNewDecFromStr(str string) (d Dec) { - d, err := NewDecFromStr(str) - if err != nil { - panic(err) - } - return d -} - //nolint -func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to dzero +func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than func (d Dec) GTE(d2 Dec) bool { return !d.LT(d2) } // greater than or equal func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than func (d Dec) LTE(d2 Dec) bool { return !d.GT(d2) } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to dzero +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to zero func (d Dec) Add(d2 Dec) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction @@ -171,15 +162,6 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { return fmt.Sprintf(fcode, intStr) } -var ( - dzero = big.NewInt(0) - done = big.NewInt(1) - dtwo = big.NewInt(2) - dfive = big.NewInt(5) - dnFive = big.NewInt(-5) - dten = big.NewInt(10) -) - // ____ // __| |__ "chop 'em // ` \ round!" @@ -208,7 +190,7 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { quo, rem, prec := big.NewInt(0), big.NewInt(0), precisionInt() quo, rem = quo.QuoRem(d, prec, rem) - if rem.Sign() == 0 { // remainder is dzero + if rem.Sign() == 0 { // remainder is zero return quo } @@ -286,7 +268,7 @@ func (d *Dec) UnmarshalAmino(text string) (err error) { //___________________________________________________________________________________ // helpers -// test if dtwo decimal arrays are equal +// test if two decimal arrays are equal func DecsEqual(d1s, d2s []Dec) bool { if len(d1s) != len(d2s) { return false @@ -300,12 +282,12 @@ func DecsEqual(d1s, d2s []Dec) bool { return true } -// intended to be used with require/assert: require.True(RatEq(...)) +// intended to be used with require/assert: require.True(DecEq(...)) func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got } -// minimum decimal between dtwo +// minimum decimal between two func MinDec(d1, d2 Dec) Dec { if d1.LT(d2) { return d1 diff --git a/types/decimal_test.go b/types/decimal_test.go index c55780adedee..8c1662b3a897 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -9,6 +9,15 @@ import ( "github.com/stretchr/testify/require" ) +// create a decimal from a decimal string (ex. "1234.5678") +func mustNewDecFromStr(t *testing.T, str string) (d Dec) { + d, err := NewDecFromStr(str) + require.NoError(t, err) + return d +} + +//_______________________________________ + func TestPrecisionMultiplier(t *testing.T) { res := precisionMultiplier(5) exp := big.NewInt(100000) @@ -64,7 +73,7 @@ func TestNewDecFromStr(t *testing.T) { } } -func TestDEqualities(t *testing.T) { +func TestEqualities(t *testing.T) { tests := []struct { d1, d2 Dec gt, lt, eq bool @@ -123,7 +132,7 @@ func TestDecsEqual(t *testing.T) { } } -func TestDArithmetic(t *testing.T) { +func TestArithmetic(t *testing.T) { tests := []struct { d1, d2 Dec expMul, expDiv, expAdd, expSub Dec @@ -171,16 +180,16 @@ func TestBankerRoundChop(t *testing.T) { d1 Dec exp int64 }{ - {MustNewDecFromStr("0.25"), 0}, - {MustNewDecFromStr("0"), 0}, - {MustNewDecFromStr("1"), 1}, - {MustNewDecFromStr("0.75"), 1}, - {MustNewDecFromStr("0.5"), 0}, - {MustNewDecFromStr("7.5"), 8}, - {MustNewDecFromStr("1.5"), 2}, - {MustNewDecFromStr("2.5"), 2}, - {MustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {MustNewDecFromStr("1.545"), 2}, + {mustNewDecFromStr(t, "0.25"), 0}, + {mustNewDecFromStr(t, "0"), 0}, + {mustNewDecFromStr(t, "1"), 1}, + {mustNewDecFromStr(t, "0.75"), 1}, + {mustNewDecFromStr(t, "0.5"), 0}, + {mustNewDecFromStr(t, "7.5"), 8}, + {mustNewDecFromStr(t, "1.5"), 2}, + {mustNewDecFromStr(t, "2.5"), 2}, + {mustNewDecFromStr(t, "0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {mustNewDecFromStr(t, "1.545"), 2}, } for tcIndex, tc := range tests { @@ -192,17 +201,17 @@ func TestBankerRoundChop(t *testing.T) { } } -func TestDToLeftPadded(t *testing.T) { +func TestToLeftPadded(t *testing.T) { tests := []struct { dec Dec digits int8 exp string }{ - {MustNewDecFromStr("33.3"), 8, "00000033"}, - {MustNewDecFromStr("50"), 8, "00000050"}, - {MustNewDecFromStr("333"), 8, "00000333"}, - {MustNewDecFromStr("333"), 12, "000000000333"}, - {MustNewDecFromStr("0.3333"), 8, "00000000"}, + {mustNewDecFromStr(t, "33.3"), 8, "00000033"}, + {mustNewDecFromStr(t, "50"), 8, "00000050"}, + {mustNewDecFromStr(t, "333"), 8, "00000333"}, + {mustNewDecFromStr(t, "333"), 12, "000000000333"}, + {mustNewDecFromStr(t, "0.3333"), 8, "00000000"}, } for tcIndex, tc := range tests { res := tc.dec.ToLeftPadded(tc.digits) @@ -220,8 +229,8 @@ func TestZeroDeserializationJSON(t *testing.T) { require.NotNil(t, err) } -func TestDSerializationText(t *testing.T) { - d := MustNewDecFromStr("0.333") +func TestSerializationText(t *testing.T) { + d := mustNewDecFromStr(t, "0.333") bz, err := d.MarshalText() require.NoError(t, err) @@ -233,8 +242,8 @@ func TestDSerializationText(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -func TestDSerializationGoWireJSON(t *testing.T) { - d := MustNewDecFromStr("0.333") +func TestSerializationGoWireJSON(t *testing.T) { + d := mustNewDecFromStr(t, "0.333") bz, err := dcdc.MarshalJSON(d) require.NoError(t, err) @@ -245,8 +254,8 @@ func TestDSerializationGoWireJSON(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -func TestDSerializationGoWireBinary(t *testing.T) { - d := MustNewDecFromStr("0.333") +func TestSerializationGoWireBinary(t *testing.T) { + d := mustNewDecFromStr(t, "0.333") bz, err := dcdc.MarshalBinary(d) require.NoError(t, err) @@ -264,7 +273,7 @@ type testDEmbedStruct struct { } // TODO make work for UnmarshalJSON -func TestDEmbeddedStructSerializationGoWire(t *testing.T) { +func TestEmbeddedStructSerializationGoWire(t *testing.T) { obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} bz, err := cdc.MarshalBinary(obj) require.Nil(t, err) @@ -278,7 +287,7 @@ func TestDEmbeddedStructSerializationGoWire(t *testing.T) { require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) } -func TestDStringOverflow(t *testing.T) { +func TestStringOverflow(t *testing.T) { // two random 64 bit primes dec1, err := NewDecFromStr("51643150036226787134389711697696177267") require.NoError(t, err) diff --git a/types/stake.go b/types/stake.go index 4e3cf38a3233..acd24a154184 100644 --- a/types/stake.go +++ b/types/stake.go @@ -42,9 +42,9 @@ type Validator interface { GetStatus() BondStatus // status of the validator GetOwner() AccAddress // owner AccAddress to receive/return validators coins GetPubKey() crypto.PubKey // validation pubkey - GetPower() Rat // validation power - GetTokens() Rat // validation tokens - GetDelegatorShares() Rat // Total out standing delegator shares + GetPower() Dec // validation power + GetTokens() Dec // validation tokens + GetDelegatorShares() Dec // Total out standing delegator shares GetBondHeight() int64 // height in which the validator became active } @@ -68,10 +68,10 @@ type ValidatorSet interface { Validator(Context, AccAddress) Validator // get a particular validator by owner AccAddress ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by signing PubKey - TotalPower(Context) Rat // total power of the validator set + TotalPower(Context) Dec // total power of the validator set // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction - Slash(Context, crypto.PubKey, int64, int64, Rat) + Slash(Context, crypto.PubKey, int64, int64, Dec) Revoke(Context, crypto.PubKey) // revoke a validator Unrevoke(Context, crypto.PubKey) // unrevoke a validator } @@ -82,7 +82,7 @@ type ValidatorSet interface { type Delegation interface { GetDelegator() AccAddress // delegator AccAddress for the bond GetValidator() AccAddress // validator owner AccAddress for the bond - GetBondShares() Rat // amount of validator's shares + GetBondShares() Dec // amount of validator's shares } // properties for the set of all delegations for a particular diff --git a/x/fee_distribution/keeper.go b/x/fee_distribution/keeper.go index 1450717193bb..aba07eaca1c1 100644 --- a/x/fee_distribution/keeper.go +++ b/x/fee_distribution/keeper.go @@ -23,13 +23,13 @@ package stake ////_________________________________________________________________________ //// cummulative power of the non-absent prevotes -//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat { +//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Dec { //store := ctx.KVStore(k.storeKey) //// get absent prevote indexes //absents := ctx.AbsentValidators() -//TotalPower := sdk.ZeroRat() +//TotalPower := sdk.ZeroDec() //i := int32(0) //iterator := store.SubspaceIterator(ValidatorsBondedKey) //for ; iterator.Valid(); iterator.Next() { diff --git a/x/fee_distribution/keeper_test.go b/x/fee_distribution/keeper_test.go index 0d732f8a1917..8902680604e7 100644 --- a/x/fee_distribution/keeper_test.go +++ b/x/fee_distribution/keeper_test.go @@ -8,8 +8,8 @@ package stake //var candidatesIn [5]Candidate //for i, amt := range amts { //candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) -//candidatesIn[i].BondedShares = sdk.NewRat(amt) -//candidatesIn[i].DelegatorShares = sdk.NewRat(amt) +//candidatesIn[i].BondedShares = sdk.NewDec(amt) +//candidatesIn[i].DelegatorShares = sdk.NewDec(amt) //keeper.setCandidate(ctx, candidatesIn[i]) //} @@ -18,7 +18,7 @@ package stake //require.Equal(t, 5, len(gotValidators)) //totPow := keeper.GetTotalPrecommitVotingPower(ctx) -//exp := sdk.NewRat(11111) +//exp := sdk.NewDec(11111) //require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address @@ -26,6 +26,6 @@ package stake //totPow = keeper.GetTotalPrecommitVotingPower(ctx) //// XXX verify that this order should infact exclude these two records -//exp = sdk.NewRat(11100) +//exp = sdk.NewDec(11100) //require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //} diff --git a/x/fee_distribution/movement.go b/x/fee_distribution/movement.go index 03c4de72cb05..2b8732c4a36a 100644 --- a/x/fee_distribution/movement.go +++ b/x/fee_distribution/movement.go @@ -17,10 +17,10 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //// calculate the proposer reward //precommitPower := k.GetTotalPrecommitVotingPower(ctx) -//toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) +//toProposer := coinsMulDec(collectedFees, (sdk.NewDec(1, 100).Add(sdk.NewDec(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) //candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) -//toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee) +//toReservePool := coinsMulDec(collectedFees, params.ReservePoolFee) //pool.FeeReservePool = pool.FeeReservePool.Plus(toReservePool) //distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool) @@ -34,10 +34,10 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //k.setPool(ctx, pool) //} -//func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins { +//func coinsMulDec(coins sdk.Coins, rat sdk.Dec) sdk.Coins { //var res sdk.Coins //for _, coin := range coins { -//coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate() +//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount)).Evaluate() //coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} //res = res.Plus(coinMul) //} @@ -49,17 +49,17 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //// calculate adjustment changes for a candidate at a height //func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { -//heightRat := sdk.NewRat(height) -//lastHeightRat := sdk.NewRat(height - 1) -//candidateFeeCount := candidate.BondedShares.Mul(heightRat) -//poolFeeCount := pool.BondedShares.Mul(heightRat) +//heightDec := sdk.NewDec(height) +//lastHeightDec := sdk.NewDec(height - 1) +//candidateFeeCount := candidate.BondedShares.Mul(heightDec) +//poolFeeCount := pool.BondedShares.Mul(heightDec) //for i, denom := range denoms { -//poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom)) -//poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom)) +//poolFeeSumReceived := sdk.NewDec(pool.FeeSumReceived.AmountOf(denom)) +//poolFeeRecent := sdk.NewDec(pool.FeeRecent.AmountOf(denom)) //// calculate simple and projected pools //simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) -//calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent) +//calc1 := candidate.PrevBondedShares.Mul(lastHeightDec).Quo(pool.PrevBondedShares.Mul(lastHeightDec)).Mul(poolFeeRecent) //calc2 := candidate.BondedShares.Quo(pool.BondedShares).Mul(poolFeeRecent) //projectedPool := calc1.Add(calc2) diff --git a/x/fee_distribution/types.go b/x/fee_distribution/types.go index f9d4f905f6bc..2234104717c0 100644 --- a/x/fee_distribution/types.go +++ b/x/fee_distribution/types.go @@ -23,8 +23,8 @@ package stake //// fee information for a validator //type Validator struct { -//Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +//Adjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // total shares of a global hold pools //} ////_________________________________________________________________________ @@ -32,7 +32,7 @@ package stake //// Params defines the high level settings for staking //type Params struct { //FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms -//ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool +//ReservePoolFee sdk.Dec `json:"reserve_pool_fee"` // percent of fees which go to reserve pool //} //func (p Params) equal(p2 Params) bool { @@ -43,7 +43,7 @@ package stake //func defaultParams() Params { //return Params{ //FeeDenoms: []string{"steak"}, -//ReservePoolFee: sdk.NewRat(5, 100), +//ReservePoolFee: sdk.NewDec(5, 100), //} //} @@ -55,8 +55,8 @@ package stake //FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed //FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` //FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected -//FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares +//FeeAdjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // XXX last recorded bonded shares //} //func (p Pool) equal(p2 Pool) bool { @@ -64,7 +64,7 @@ package stake //p.FeePool.IsEqual(p2.FeePool) && //p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && //p.FeeRecent.IsEqual(p2.FeeRecent) && -//sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) && +//sdk.DecsEqual(p.FeeAdjustments, p2.FeeAdjustments) && //p.PrevBondedShares.Equal(p2.PrevBondedShares) //} @@ -75,8 +75,8 @@ package stake //FeePool: sdk.Coins(nil), //FeeSumReceived: sdk.Coins(nil), //FeeRecent: sdk.Coins(nil), -//FeeAdjustments: []sdk.Rat{sdk.ZeroRat()}, -//PrevBondedShares: sdk.ZeroRat(), +//FeeAdjustments: []sdk.Dec{sdk.ZeroDec()}, +//PrevBondedShares: sdk.ZeroDec(), //} //} @@ -85,8 +85,8 @@ package stake //// Used in calculation of fee shares, added to a queue for each block where a power change occures //type PowerChange struct { //Height int64 `json:"height"` // block height at change -//Power sdk.Rat `json:"power"` // total power at change -//PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1 +//Power sdk.Dec `json:"power"` // total power at change +//PrevPower sdk.Dec `json:"prev_power"` // total power at previous height-1 //FeesIn sdk.Coins `json:"fees_in"` // fees in at block height //PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height //} diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 950f3c9ef96d..af82dc4ac4f2 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewRat(1, 2), - Veto: sdk.NewRat(1, 3), - GovernancePenalty: sdk.NewRat(1, 100), + Threshold: sdk.NewDec(1, 2), + Veto: sdk.NewDec(1, 3), + GovernancePenalty: sdk.NewDec(1, 100), }, } } diff --git a/x/gov/procedures.go b/x/gov/procedures.go index f46c2149fa6b..f74091c74fda 100644 --- a/x/gov/procedures.go +++ b/x/gov/procedures.go @@ -12,9 +12,9 @@ type DepositProcedure struct { // Procedure around Tallying votes in governance type TallyingProcedure struct { - Threshold sdk.Rat `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 - Veto sdk.Rat `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 - GovernancePenalty sdk.Rat `json:"governance_penalty"` // Penalty if validator does not vote + Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 + Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 + GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote } // Procedure around Voting in governance diff --git a/x/gov/tally.go b/x/gov/tally.go index 4246b244d21e..35c9f1514779 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -7,20 +7,20 @@ import ( // validatorGovInfo used for tallying type validatorGovInfo struct { Address sdk.AccAddress // sdk.AccAddress of the validator owner - Power sdk.Rat // Power of a Validator - DelegatorShares sdk.Rat // Total outstanding delegator shares - Minus sdk.Rat // Minus of validator, used to compute validator's voting power + Power sdk.Dec // Power of a Validator + DelegatorShares sdk.Dec // Total outstanding delegator shares + Minus sdk.Dec // Minus of validator, used to compute validator's voting power Vote VoteOption // Vote of the validator } func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonVoting []sdk.AccAddress) { - results := make(map[VoteOption]sdk.Rat) - results[OptionYes] = sdk.ZeroRat() - results[OptionAbstain] = sdk.ZeroRat() - results[OptionNo] = sdk.ZeroRat() - results[OptionNoWithVeto] = sdk.ZeroRat() + results := make(map[VoteOption]sdk.Dec) + results[OptionYes] = sdk.ZeroDec() + results[OptionAbstain] = sdk.ZeroDec() + results[OptionNo] = sdk.ZeroDec() + results[OptionNoWithVeto] = sdk.ZeroDec() - totalVotingPower := sdk.ZeroRat() + totalVotingPower := sdk.ZeroDec() currValidators := make(map[string]validatorGovInfo) keeper.vs.IterateValidatorsBonded(ctx, func(index int64, validator sdk.Validator) (stop bool) { @@ -28,7 +28,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV Address: validator.GetOwner(), Power: validator.GetPower(), DelegatorShares: validator.GetDelegatorShares(), - Minus: sdk.ZeroRat(), + Minus: sdk.ZeroDec(), Vote: OptionEmpty, } return false @@ -84,7 +84,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV tallyingProcedure := keeper.GetTallyingProcedure(ctx) // If no one votes, proposal fails - if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroRat()) { + if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroDec()) { return false, nonVoting } // If more than 1/3 of voters veto, proposal fails diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 6c418f683887..6e38e29eee43 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) validators, err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { diff --git a/x/ibc/mapper.go b/x/ibc/mapper.go index 25169961708d..836c347a868d 100644 --- a/x/ibc/mapper.go +++ b/x/ibc/mapper.go @@ -14,7 +14,7 @@ type Mapper struct { codespace sdk.CodespaceType } -// XXX: The Mapper should not take a CoinKeeper. Rather have the CoinKeeper +// XXX: The Mapper should not take a CoinKeeper. Decher have the CoinKeeper // take an Mapper. func NewMapper(cdc *wire.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Mapper { // XXX: How are these codecs supposed to work? diff --git a/x/params/keeper.go b/x/params/keeper.go index 8817b7c6c8de..30bdcaa39c0d 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -183,8 +183,8 @@ func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) { return } -// GetRat is helper function for rat params -func (k Getter) GetRat(ctx sdk.Context, key string) (res sdk.Rat, err error) { +// GetDec is helper function for rat params +func (k Getter) GetDec(ctx sdk.Context, key string) (res sdk.Dec, err error) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) err = k.k.cdc.UnmarshalBinary(bz, &res) @@ -301,8 +301,8 @@ func (k Getter) GetUintWithDefault(ctx sdk.Context, key string, def sdk.Uint) (r return } -// GetRatWithDefault is helper function for sdk.Rat params with default value -func (k Getter) GetRatWithDefault(ctx sdk.Context, key string, def sdk.Rat) (res sdk.Rat) { +// GetDecWithDefault is helper function for sdk.Dec params with default value +func (k Getter) GetDecWithDefault(ctx sdk.Context, key string, def sdk.Dec) (res sdk.Dec) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) if bz == nil { @@ -397,8 +397,8 @@ func (k Setter) SetUint(ctx sdk.Context, key string, param sdk.Uint) { } } -// SetRat is helper function for rat params -func (k Setter) SetRat(ctx sdk.Context, key string, param sdk.Rat) { +// SetDec is helper function for rat params +func (k Setter) SetDec(ctx sdk.Context, key string, param sdk.Dec) { if err := k.k.set(ctx, key, param); err != nil { panic(err) } diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 4bb5744ea458..63f6e5da9a46 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -94,7 +94,7 @@ func TestGetter(t *testing.T) { {"uint64", uint64(1)}, {"int", sdk.NewInt(1)}, {"uint", sdk.NewUint(1)}, - {"rat", sdk.NewRat(1)}, + {"rat", sdk.NewDec(1)}, } assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewRat(1)) }) + assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1)) }) var res interface{} var err error @@ -262,19 +262,19 @@ func TestGetter(t *testing.T) { res = g.GetUintWithDefault(ctx, "invalid", def9) assert.Equal(t, def9, res) - // Rat - def10 := sdk.NewRat(0) - res, err = g.GetRat(ctx, kvs[10].key) + // Dec + def10 := sdk.NewDec(0) + res, err = g.GetDec(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) - _, err = g.GetRat(ctx, "invalid") + _, err = g.GetDec(ctx, "invalid") assert.NotNil(t, err) - res = g.GetRatWithDefault(ctx, kvs[10].key, def10) + res = g.GetDecWithDefault(ctx, kvs[10].key, def10) assert.Equal(t, kvs[10].param, res) - res = g.GetRatWithDefault(ctx, "invalid", def10) + res = g.GetDecWithDefault(ctx, "invalid", def10) assert.Equal(t, def10, res) } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index cd37dd96172f..269329e86a10 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -58,7 +58,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -109,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 89c1e11a604b..41cb5d19968c 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // assert non-revoked validator can't be unrevoked got = slh(ctx, NewMsgUnrevoke(addr)) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index fc60c5029561..74b33f7c2f8d 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -31,7 +31,7 @@ func TestHandleDoubleSign(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info keeper.handleValidatorSignature(ctx, val, amtInt, true) @@ -44,12 +44,12 @@ func TestHandleDoubleSign(t *testing.T) { // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) - require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, @@ -66,7 +66,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -172,7 +172,7 @@ func TestHandleNewValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) diff --git a/x/slashing/params.go b/x/slashing/params.go index 45d2833ce854..e501ad390d0f 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -28,9 +28,9 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { // Downtime slashing thershold - default 50% func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { - minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) + minSignedPerWindow := k.params.GetDecWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) signedBlocksWindow := k.SignedBlocksWindow(ctx) - return sdk.NewRat(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() + return sdk.NewDec(signedBlocksWindow, 0).Mul(minSignedPerWindow).RoundInt64() } // Double-sign unbond duration @@ -44,13 +44,13 @@ func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) int64 { } // SlashFractionDoubleSign - currently default 5% -func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Rat { - return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) +func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec { + return k.params.GetDecWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) } // SlashFractionDowntime - currently default 1% -func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Rat { - return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) +func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec { + return k.params.GetDecWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) } // declared as var because of keeper_test.go @@ -70,9 +70,9 @@ var ( // TODO Temporarily set to 10 minutes for testnets defaultDowntimeUnbondDuration int64 = 60 * 10 - defaultMinSignedPerWindow = sdk.NewRat(1, 2) + defaultMinSignedPerWindow = sdk.NewDec(5, 1) // 0.5 - defaultSlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) + defaultSlashFractionDoubleSign = sdk.NewDec(1, 0).Quo(sdk.NewDec(20, 0)) - defaultSlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) + defaultSlashFractionDowntime = sdk.NewDec(1, 0).Quo(sdk.NewDec(100, 0)) ) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 7b3ab04362c5..3699a83d4169 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -69,7 +69,11 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - genesis.Pool.LooseTokens = sdk.NewRat(initCoins.MulRaw(int64(len(addrs))).Int64()) + genesis.Pool.LooseTokens = sdk.NewDec( + initCoins.MulRaw( + int64(len(addrs)), + ).Int64(), + 0) _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 38e339e590b1..9540745bb9ce 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -21,7 +21,7 @@ func TestBeginBlocker(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) val := abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(pk), diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 353e1553eff7..1de76ba14bd9 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -90,14 +90,14 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, func checkDelegation( t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, - validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Rat, + validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Dec, ) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { require.True(t, found) - require.True(sdk.RatEq(t, expShares, delegation.Shares)) + require.True(sdk.DecEq(t, expShares, delegation.Shares)) return } @@ -138,7 +138,7 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) // addr1 create validator on behalf of addr2 createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) @@ -150,10 +150,10 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) // edit the validator description = NewDescription("bar_moniker", "", "", "") @@ -169,14 +169,14 @@ func TestStakeMsgs(t *testing.T) { mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10)) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore - checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{}) + checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Dec{}) // balance should be the same because bonding not yet complete mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 218c1f5567b5..4d94c3bbea5a 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -220,7 +220,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // nolint: gocyclo // TODO: Make this pass gocyclo linting func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercentStr string, - delegatorAddr, validatorAddr sdk.AccAddress) (sharesAmount sdk.Rat, err error) { + delegatorAddr, validatorAddr sdk.AccAddress) (sharesAmount sdk.Dec, err error) { switch { case sharesAmountStr != "" && sharesPercentStr != "": @@ -228,20 +228,20 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) + sharesAmount, err = sdk.NewDecFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesAmount.GT(sdk.ZeroRat()) { + if !sharesAmount.GT(sdk.ZeroDec()) { return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)") } case sharesPercentStr != "": - var sharesPercent sdk.Rat - sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) + var sharesPercent sdk.Dec + sharesPercent, err = sdk.NewDecFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesPercent.GT(sdk.ZeroRat()) || !sharesPercent.LTE(sdk.OneRat()) { + if !sharesPercent.GT(sdk.ZeroDec()) || !sharesPercent.LTE(sdk.OneDec()) { return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)") } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index a0f0416549d3..73c850eb6f12 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -148,7 +148,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) @@ -213,7 +213,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index ec061ea3c368..2d3e35f2317e 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -17,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewRat(2) + pool.BondedTokens = sdk.NewDec(2) params := keeper.GetParams(ctx) var delegations []Delegation @@ -32,11 +32,11 @@ func TestInitGenesis(t *testing.T) { // initialize the validators validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.OneRat() - validators[0].DelegatorShares = sdk.OneRat() + validators[0].Tokens = sdk.OneDec() + validators[0].DelegatorShares = sdk.OneDec() validators[1].Status = sdk.Bonded - validators[1].Tokens = sdk.OneRat() - validators[1].DelegatorShares = sdk.OneRat() + validators[1].Tokens = sdk.OneDec() + validators[1].DelegatorShares = sdk.OneDec() genesisState = types.NewGenesisState(pool, params, validators, delegations) vals, err := InitGenesis(ctx, keeper, genesisState) @@ -67,7 +67,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewRat(int64(200 + (size - 100))) + pool.BondedTokens = sdk.NewDec(int64(200 + (size - 100))) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -78,11 +78,11 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators[i].Status = sdk.Bonded if i < 100 { - validators[i].Tokens = sdk.NewRat(2) - validators[i].DelegatorShares = sdk.NewRat(2) + validators[i].Tokens = sdk.NewDec(2) + validators[i].DelegatorShares = sdk.NewDec(2) } else { - validators[i].Tokens = sdk.OneRat() - validators[i].DelegatorShares = sdk.OneRat() + validators[i].Tokens = sdk.OneDec() + validators[i].DelegatorShares = sdk.OneDec() } } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index f183b279a640..956b8e6700f0 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -80,7 +80,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(1, 2)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -109,7 +109,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(1000000)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -137,8 +137,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) - assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) + assert.Equal(t, sdk.NewDec(10), validator.BondedTokens()) + assert.Equal(t, sdk.NewDec(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) // two validators can't have the same owner address @@ -161,8 +161,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -181,8 +181,8 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Owner) assert.Equal(t, pk, validator.PubKey) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator @@ -219,8 +219,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.Equal(t, bondAmount, bond.Shares.RoundInt64()) pool := keeper.GetPool(ctx) - exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) + exDece := validator.DelegatorShareExDece() + require.True(t, exDece.Equal(sdk.OneDec()), "expected exDece 1 got %v", exDece) require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64()) // just send the same msgbond multiple times @@ -238,8 +238,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.True(t, found) - exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v, i = %v", exRate, i) + exDece := validator.DelegatorShareExDece() + require.True(t, exDece.Equal(sdk.OneDec()), "expected exDece 1 got %v, i = %v", exDece, i) expBond := int64(i+1) * bondAmount expDelegatorShares := int64(i+2) * bondAmount // (1 self delegation) @@ -294,7 +294,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here - unbondShares := sdk.NewRat(10) + unbondShares := sdk.NewDec(10) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) numUnbonds := 5 @@ -338,7 +338,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } for _, c := range errorCases { - unbondShares := sdk.NewRat(int64(c)) + unbondShares := sdk.NewDec(int64(c)) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "expected unbond msg to fail") @@ -347,14 +347,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have - unbondShares = sdk.NewRat(leftBonded + 1) + unbondShares = sdk.NewDec(leftBonded + 1) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have - unbondShares = sdk.NewRat(leftBonded) + unbondShares = sdk.NewDec(leftBonded) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), @@ -390,7 +390,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewRat(10)) // remove delegation + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -435,7 +435,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -466,7 +466,7 @@ func TestRevokeValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -482,7 +482,7 @@ func TestRevokeValidator(t *testing.T) { require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds - msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -509,7 +509,7 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") @@ -564,7 +564,7 @@ func TestRedelegationPeriod(t *testing.T) { bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) @@ -616,12 +616,12 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewRat(10)) + msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) @@ -662,7 +662,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -784,7 +784,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -797,7 +797,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewRat(50)) + msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -831,22 +831,22 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx = ctx.WithBlockHeight(1) // begin unbonding 4 stake - msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewRat(4)) + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // begin redelegate 6 stake - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewRat(6)) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(6), delegation.Shares) + require.Equal(t, sdk.NewDec(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(1, 2)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -861,16 +861,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced by half validator, found := keeper.GetValidator(ctx, valA) require.True(t, found) - require.Equal(t, sdk.NewRat(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(1, 2)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) @@ -885,7 +885,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced to zero // ergo validator should have been removed from the store diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 23b58108f85c..892ef81a31fb 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -218,7 +218,7 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { // Perform a delegation, set/update everything necessary within the store. func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt sdk.Coin, - validator types.Validator, subtractAccount bool) (newShares sdk.Rat, err sdk.Error) { + validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { // Get or create the delegator delegation delegation, found := k.GetDelegation(ctx, delegatorAddr, validator.Owner) @@ -226,7 +226,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt delegation = types.Delegation{ DelegatorAddr: delegatorAddr, ValidatorAddr: validator.Owner, - Shares: sdk.ZeroRat(), + Shares: sdk.ZeroDec(), } } @@ -254,7 +254,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt // unbond the the delegation return func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, - shares sdk.Rat) (amount sdk.Rat, err sdk.Error) { + shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { // check if delegation has any shares in it unbond delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -312,7 +312,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr //______________________________________________________________________________________________________ // complete unbonding an unbonding record -func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { +func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 _, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) @@ -365,7 +365,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr // complete unbonding an unbonding record func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delegatorAddr, validatorSrcAddr) { diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 01c764d8278e..92bc29d519c4 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -31,7 +31,7 @@ func TestDelegation(t *testing.T) { bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], - Shares: sdk.NewRat(9), + Shares: sdk.NewDec(9), } // check the empty keeper first @@ -45,18 +45,18 @@ func TestDelegation(t *testing.T) { require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewRat(99) + bond1to1.Shares = sdk.NewDec(99) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} - bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewRat(9), 1} - bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewRat(9), 2} - bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewRat(9), 3} - bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewRat(9), 4} + bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9), 0} + bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9), 1} + bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9), 2} + bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9), 3} + bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9), 4} keeper.SetDelegation(ctx, bond1to2) keeper.SetDelegation(ctx, bond1to3) keeper.SetDelegation(ctx, bond2to1) @@ -141,7 +141,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -162,8 +162,8 @@ func TestUnbondDelegation(t *testing.T) { keeper.SetDelegation(ctx, delegation) var err error - var amount sdk.Rat - amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewRat(6)) + var amount sdk.Dec + amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) require.NoError(t, err) require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation @@ -189,8 +189,8 @@ func TestGetRedelegationsFromValidator(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewRat(5), - SharesDst: sdk.NewRat(5), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // set and retrieve a record @@ -219,8 +219,8 @@ func TestRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewRat(5), - SharesDst: sdk.NewRat(5), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // test shouldn't have and redelegations @@ -241,8 +241,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewRat(21) - rd.SharesDst = sdk.NewRat(21) + rd.SharesSrc = sdk.NewDec(21) + rd.SharesDst = sdk.NewDec(21) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 3f763ea25efa..9307ddddf252 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = sdk.NewRat(777) + expPool.BondedTokens = sdk.NewDec(777) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 9c331147447e..aeec44fae959 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -69,7 +69,7 @@ func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Val } // total power from the bond -func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { +func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec { pool := k.GetPool(ctx) return pool.BondedTokens } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index fb9297e9cae5..e919a0629851 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -20,15 +20,15 @@ import ( // CONTRACT: // Infraction committed at the current height or at a past height, // not at a height in the future -func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Rat) { +func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) { logger := ctx.Logger().With("module", "x/stake") - if slashFactor.LT(sdk.ZeroRat()) { + if slashFactor.LT(sdk.ZeroDec()) { panic(fmt.Errorf("attempted to slash with a negative slashFactor: %v", slashFactor)) } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewRat(power).Mul(slashFactor) + slashAmount := sdk.NewDec(power, 0).Mul(slashFactor) // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -89,7 +89,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Cannot decrease balance below zero - tokensToBurn := sdk.MinRat(remainingSlashAmount, validator.Tokens) + tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens) // Get the current pool pool := k.GetPool(ctx) @@ -150,23 +150,23 @@ func (k Keeper) setRevoked(ctx sdk.Context, pubkey crypto.PubKey, revoked bool) // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, - infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { now := ctx.BlockHeader().Time // If unbonding started before this height, stake didn't contribute to infraction if unbondingDelegation.CreationHeight < infractionHeight { - return sdk.ZeroRat() + return sdk.ZeroDec() } if unbondingDelegation.MinTime < now { // Unbonding delegation no longer eligible for slashing, skip it // TODO Settle and delete it automatically? - return sdk.ZeroRat() + return sdk.ZeroDec() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount, 0).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -194,23 +194,23 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, - infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { now := ctx.BlockHeader().Time // If redelegation started before this height, stake didn't contribute to infraction if redelegation.CreationHeight < infractionHeight { - return sdk.ZeroRat() + return sdk.ZeroDec() } if redelegation.MinTime < now { // Redelegation no longer eligible for slashing, skip it // TODO Delete it automatically? - return sdk.ZeroRat() + return sdk.ZeroDec() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount, 0).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index a9f5e888c9f1..a4ed7fe7ed31 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -18,7 +18,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewRat(amt * int64(numVals)) + pool.LooseTokens = sdk.NewDec(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { @@ -62,7 +62,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -105,7 +105,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rd := types.Redelegation{ @@ -115,8 +115,8 @@ func TestSlashRedelegation(t *testing.T) { CreationHeight: 0, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewRat(10), - SharesDst: sdk.NewRat(10), + SharesSrc: sdk.NewDec(10), + SharesDst: sdk.NewDec(10), InitialBalance: sdk.NewCoin(params.BondDenom, 10), Balance: sdk.NewCoin(params.BondDenom, 10), } @@ -126,7 +126,7 @@ func TestSlashRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(10), + Shares: sdk.NewDec(10), } keeper.SetDelegation(ctx, del) @@ -171,7 +171,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -179,7 +179,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -192,16 +192,16 @@ func TestSlashAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // power decreased - require.Equal(t, sdk.NewRat(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + require.Equal(t, sdk.NewDec(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -238,7 +238,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewRat(7), validator.GetPower()) + require.Equal(t, sdk.NewDec(7), validator.GetPower()) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -255,7 +255,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewRat(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -275,7 +275,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewRat(1), validator.GetPower()) + require.Equal(t, sdk.NewDec(1), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -302,7 +302,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rd := types.Redelegation{ @@ -311,8 +311,8 @@ func TestSlashWithRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 11, MinTime: 0, - SharesSrc: sdk.NewRat(6), - SharesDst: sdk.NewRat(6), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewCoin(params.BondDenom, 6), Balance: sdk.NewCoin(params.BondDenom, 6), } @@ -322,13 +322,13 @@ func TestSlashWithRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(6), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, del) // update bonded tokens pool := keeper.GetPool(ctx) - pool.BondedTokens = pool.BondedTokens.Add(sdk.NewRat(6)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6)) keeper.SetPool(ctx, pool) // slash validator @@ -354,13 +354,13 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewRat(8), validator.GetPower()) + require.Equal(t, sdk.NewDec(8), validator.GetPower()) // slash the validator again ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) }) + require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -375,13 +375,13 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 4 - require.Equal(t, sdk.NewRat(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -403,7 +403,7 @@ func TestSlashWithRedelegation(t *testing.T) { // validator no longer in the store _, found = keeper.GetValidatorByPubKey(ctx, pk) require.False(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -423,7 +423,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rdA := types.Redelegation{ @@ -433,8 +433,8 @@ func TestSlashBoth(t *testing.T) { CreationHeight: 11, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewRat(6), - SharesDst: sdk.NewRat(6), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewCoin(params.BondDenom, 6), Balance: sdk.NewCoin(params.BondDenom, 6), } @@ -444,7 +444,7 @@ func TestSlashBoth(t *testing.T) { delA := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(6), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, delA) @@ -482,5 +482,5 @@ func TestSlashBoth(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, sdk.NewRat(10), validator.GetPower()) + require.Equal(t, sdk.NewDec(10), validator.GetPower()) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 010963034982..e49ee1adf829 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -77,10 +77,10 @@ func MakeTestCodec() *wire.Codec { // default params without inflation func ParamsNoInflation() types.Params { return types.Params{ - InflationRateChange: sdk.ZeroRat(), - InflationMax: sdk.ZeroRat(), - InflationMin: sdk.ZeroRat(), - GoalBonded: sdk.NewRat(67, 100), + InflationDeceChange: sdk.ZeroDec(), + InflationMax: sdk.ZeroDec(), + InflationMin: sdk.ZeroDec(), + GoalBonded: sdk.NewDec(67, 100), MaxValidators: 100, BondDenom: "steak", } @@ -119,7 +119,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(initCoins)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins, 0)) keeper.SetPool(ctx, pool) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 06273d6af77c..0c84052df4bd 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -19,8 +19,8 @@ func TestSetValidator(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -28,8 +28,8 @@ func TestSetValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -55,8 +55,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewRat(10000) - pool.BondedTokens = sdk.NewRat(1234) + pool.LooseTokens = sdk.NewDec(10000) + pool.BondedTokens = sdk.NewDec(1234) keeper.SetPool(ctx, pool) // add a validator @@ -75,7 +75,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares - validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2))) + validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out @@ -104,7 +104,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% - keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneRat()) + keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneDec()) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) @@ -121,13 +121,13 @@ func TestValidatorBasics(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) validators[i].Status = sdk.Unbonded - validators[i].Tokens = sdk.ZeroRat() + validators[i].Tokens = sdk.ZeroDec() validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) } - assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(8), validators[1].Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(7), validators[2].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(8), validators[1].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(7), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -136,7 +136,7 @@ func TestValidatorBasics(t *testing.T) { assert.Zero(t, len(resVals)) pool = keeper.GetPool(ctx) - assert.True(sdk.RatEq(t, sdk.ZeroRat(), pool.BondedTokens)) + assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) // set and retrieve a record validators[0] = keeper.UpdateValidator(ctx, validators[0]) @@ -148,15 +148,15 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].BondedTokens())) pool = keeper.GetPool(ctx) - assert.True(sdk.RatEq(t, pool.BondedTokens, validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(10) - validators[0].DelegatorShares = sdk.NewRat(10) + validators[0].Tokens = sdk.NewDec(10) + validators[0].DelegatorShares = sdk.NewDec(10) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -199,19 +199,19 @@ func GetValidatorSortingUnmixed(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewRat(amt) - validators[i].DelegatorShares = sdk.NewRat(amt) + validators[i].Tokens = sdk.NewDec(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) keeper.UpdateValidator(ctx, validators[i]) } // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -219,14 +219,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewRat(500) + validators[3].Tokens = sdk.NewDec(500) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewRat(300) + validators[3].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -234,7 +234,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewRat(200) + validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -253,8 +253,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewRat(300) - validators[4].Tokens = sdk.NewRat(300) + validators[3].Tokens = sdk.NewDec(300) + validators[4].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -281,20 +281,20 @@ func GetValidatorSortingMixed(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewRat(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) } validators[0].Status = sdk.Bonded validators[1].Status = sdk.Bonded validators[2].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(amts[0]) - validators[1].Tokens = sdk.NewRat(amts[1]) - validators[2].Tokens = sdk.NewRat(amts[2]) + validators[0].Tokens = sdk.NewDec(amts[0]) + validators[1].Tokens = sdk.NewDec(amts[1]) + validators[2].Tokens = sdk.NewDec(amts[2]) validators[3].Status = sdk.Bonded validators[4].Status = sdk.Bonded - validators[3].Tokens = sdk.NewRat(amts[3]) - validators[4].Tokens = sdk.NewRat(amts[4]) + validators[3].Tokens = sdk.NewDec(amts[3]) + validators[4].Tokens = sdk.NewDec(amts[4]) for i := range amts { keeper.UpdateValidator(ctx, validators[i]) @@ -318,11 +318,11 @@ func GetValidatorSortingMixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -387,7 +387,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewRat(201)) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -599,7 +599,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(600) + validators[0].Tokens = sdk.NewDec(600) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -737,21 +737,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power - require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[1].GetPower().RoundInt64()) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} pool := keeper.GetPool(ctx) - validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20)) - validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30)) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) // power has changed - require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index e4869693cfa0..654d5560b0ac 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -31,7 +31,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim pool := k.GetPool(ctx) loose := sdk.ZeroInt() - bonded := sdk.ZeroRat() + bonded := sdk.ZeroDec() am.IterateAccounts(ctx, func(acc auth.Account) bool { loose = loose.Add(acc.GetCoins().AmountOf("steak")) return false @@ -67,7 +67,7 @@ func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { return func(t *testing.T, app *baseapp.BaseApp, log string) { ctx := app.NewContext(false, abci.Header{}) k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { - require.True(t, validator.GetPower().GT(sdk.ZeroRat()), "validator with non-positive power stored") + require.True(t, validator.GetPower().GT(sdk.ZeroDec()), "validator with non-positive power stored") return false }) } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 87324eed720e..7032535091fc 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -132,7 +132,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewRatFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -191,7 +191,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation DelegatorAddr: delegatorAddress, ValidatorSrcAddr: sourceValidatorAddress, ValidatorDstAddr: destValidatorAddress, - SharesAmount: sdk.NewRatFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(loose.Int64(), 1)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 1)) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 2ceedd5f314a..f09cd8f4c098 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -15,12 +15,12 @@ import ( type Delegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - Shares sdk.Rat `json:"shares"` + Shares sdk.Dec `json:"shares"` Height int64 `json:"height"` // Last height bond updated } type delegationValue struct { - Shares sdk.Rat + Shares sdk.Dec Height int64 } @@ -80,7 +80,7 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr } func (d Delegation) GetValidator() sdk.AccAddress { return d.ValidatorAddr } -func (d Delegation) GetBondShares() sdk.Rat { return d.Shares } +func (d Delegation) GetBondShares() sdk.Dec { return d.Shares } // HumanReadableString returns a human readable string representation of a // Delegation. An error is returned if the Delegation's delegator or validator @@ -189,8 +189,8 @@ type Redelegation struct { MinTime int64 `json:"min_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating + SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } type redValue struct { @@ -198,8 +198,8 @@ type redValue struct { MinTime int64 InitialBalance sdk.Coin Balance sdk.Coin - SharesSrc sdk.Rat - SharesDst sdk.Rat + SharesSrc sdk.Dec + SharesDst sdk.Dec } // return the redelegation without fields contained within the key for the store diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index 640f5d9791aa..db4dd77233b1 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -11,19 +11,19 @@ func TestDelegationEqual(t *testing.T) { d1 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } d2 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } ok := d1.Equal(d2) require.True(t, ok) d2.ValidatorAddr = addr3 - d2.Shares = sdk.NewRat(200) + d2.Shares = sdk.NewDec(200) ok = d1.Equal(d2) require.False(t, ok) @@ -33,7 +33,7 @@ func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } // NOTE: Being that the validator's keypair is random, we cannot test the @@ -91,8 +91,8 @@ func TestRedelegationEqual(t *testing.T) { ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewRat(10) - r2.SharesSrc = sdk.NewRat(20) + r2.SharesDst = sdk.NewDec(10) + r2.SharesSrc = sdk.NewDec(20) r2.MinTime = 20 * 20 * 2 ok = r1.Equal(r2) @@ -104,8 +104,8 @@ func TestRedelegationHumanReadableString(t *testing.T) { DelegatorAddr: addr1, ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, - SharesDst: sdk.NewRat(10), - SharesSrc: sdk.NewRat(20), + SharesDst: sdk.NewDec(10), + SharesSrc: sdk.NewDec(20), } // NOTE: Being that the validator's keypair is random, we cannot test the diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index 2ef747bae63e..b34aeeefb1e9 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -99,13 +99,6 @@ func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") } -func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", - maximumBondingRationalDenominator.String()), - ) -} - func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index 0114b1e05729..242b5ffaf5e2 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -18,35 +18,35 @@ func TestGetInflation(t *testing.T) { // Governing Mechanism: // BondedRatio = BondedTokens / TotalSupply - // inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange + // inflationDeceChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationDeceChange tests := []struct { name string setBondedTokens, setLooseTokens, - setInflation, expectedChange sdk.Rat + setInflation, expectedChange sdk.Dec }{ - // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, + // with 0% bonded atom supply the inflation should increase by InflationDeceChange + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 100), params.InflationDeceChange.Quo(hrsPerYrDec).Round(precision)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), - sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 100), + sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), - sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 100), + sdk.OneDec().Sub(sdk.NewDec(1, 2).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, - {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000)}, + {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 100), sdk.ZeroDec()}, + {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(70001, 1000000), sdk.NewDec(-1, 1000000)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, - {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000)}, + {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(20, 100), sdk.ZeroDec()}, + {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(199999, 1000000), sdk.NewDec(1, 1000000)}, // perfect balance shouldn't change inflation - {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, + {"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDec(15, 100), sdk.ZeroDec()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -67,77 +67,77 @@ func TestProcessProvisions(t *testing.T) { var ( initialTotalTokens int64 = 550000000 - cumulativeExpProvs = sdk.ZeroRat() + cumulativeExpProvs = sdk.ZeroDec() ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) + pool.LooseTokens = sdk.NewDec(initialTotalTokens) // process the provisions for a year for hr := 0; hr < 100; hr++ { - var expProvisions sdk.Rat + var expProvisions sdk.Dec _, expProvisions, pool = updateProvisions(t, pool, params, hr) cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) } //get the pool and do the final value checks from checkFinalPoolValues - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs) } //_________________________________________________________________________________________ ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions -func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { +func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Dec) { calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) - require.True(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) + require.True(sdk.DecEq(t, calculatedTotalTokens, pool.TokenSupply())) } // Processes provisions are added to the pool correctly every hour // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Rat, sdk.Rat, Pool) { +func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Dec, sdk.Dec, Pool) { expInflation := pool.NextInflation(params) - expProvisions := expInflation.Mul(pool.TokenSupply().Round(precision)).Quo(hrsPerYrRat) + expProvisions := expInflation.Mul(pool.TokenSupply().Round(precision)).Quo(hrsPerYrDec) startTotalSupply := pool.TokenSupply() pool = pool.ProcessProvisions(params) //check provisions were added to pool - require.True(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) + require.True(sdk.DecEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) return expInflation, expProvisions, pool } // Checks that The inflation will correctly increase or decrease after an update to the pool // nolint: gocyclo -func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { +func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Dec, msg string) { inflationChange := updatedInflation.Sub(previousInflation) switch { - //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + //BELOW 67% - Dece of change positive and increasing, while we are between 7% <= and < 20% inflation + case pool.BondedRatio().LT(sdk.NewDec(67, 100)) && updatedInflation.LT(sdk.NewDec(20, 100)): + require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) - //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): - if previousInflation.Equal(sdk.NewRat(20, 100)) { + //BELOW 67% - Dece of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio + case pool.BondedRatio().LT(sdk.NewDec(67, 100)) && updatedInflation.Equal(sdk.NewDec(20, 100)): + if previousInflation.Equal(sdk.NewDec(20, 100)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) } else { - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) } - //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + //ABOVE 67% - Dece of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% + case pool.BondedRatio().GT(sdk.NewDec(67, 100)) && updatedInflation.LT(sdk.NewDec(20, 100)) && updatedInflation.GT(sdk.NewDec(7, 100)): + require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) - //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): - if previousInflation.Equal(sdk.NewRat(7, 100)) { + //ABOVE 67% - Dece of change should be 0 while inflation continually stays at 7%. + case pool.BondedRatio().GT(sdk.NewDec(67, 100)) && updatedInflation.Equal(sdk.NewDec(7, 100)): + if previousInflation.Equal(sdk.NewDec(7, 100)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) } else { - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) } } } diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 27edad5dd28b..282000294bce 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -1,7 +1,6 @@ package types import ( - "math" "reflect" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,18 +10,11 @@ import ( // name to idetify transaction types const MsgType = "stake" -// Maximum amount of decimal points in the decimal representation of rationals -// used in MsgBeginUnbonding / MsgBeginRedelegate -const MaxBondDenominatorPrecision = 8 - // Verify interface at compile time var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{} var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{} var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{} -// Initialize Int for the denominator -var maximumBondingRationalDenominator = sdk.NewInt(int64(math.Pow10(MaxBondDenominatorPrecision))) - //______________________________________________________________________ // MsgCreateValidator - struct for unbonding transactions @@ -211,11 +203,11 @@ type MsgBeginRedelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` - SharesAmount sdk.Rat `json:"shares_amount"` + SharesAmount sdk.Dec `json:"shares_amount"` } func NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginRedelegate { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginRedelegate { return MsgBeginRedelegate{ DelegatorAddr: delegatorAddr, @@ -261,12 +253,9 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.ValidatorDstAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroRat()) { + if msg.SharesAmount.LTE(sdk.ZeroDec()) { return ErrBadSharesAmount(DefaultCodespace) } - if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { - return ErrBadSharesPrecision(DefaultCodespace) - } return nil } @@ -322,10 +311,10 @@ func (msg MsgCompleteRedelegate) ValidateBasic() sdk.Error { type MsgBeginUnbonding struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - SharesAmount sdk.Rat `json:"shares_amount"` + SharesAmount sdk.Dec `json:"shares_amount"` } -func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginUnbonding { +func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginUnbonding { return MsgBeginUnbonding{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, @@ -362,12 +351,9 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroRat()) { + if msg.SharesAmount.LTE(sdk.ZeroDec()) { return ErrBadSharesAmount(DefaultCodespace) } - if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { - return ErrBadSharesPrecision(DefaultCodespace) - } return nil } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 73eef084a2ee..d3bf6f427bd1 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -143,15 +143,15 @@ func TestMsgBeginRedelegate(t *testing.T) { delegatorAddr sdk.AccAddress validatorSrcAddr sdk.AccAddress validatorDstAddr sdk.AccAddress - sharesAmount sdk.Rat + sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewRat(1, 10), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewRat(-1, 10), false}, - {"zero amount", addr1, addr2, addr3, sdk.ZeroRat(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewRat(1, 10), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewRat(1, 10), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewRat(1, 10), false}, + {"regular", addr1, addr2, addr3, sdk.NewDec(1, 10), true}, + {"negative decimal", addr1, addr2, addr3, sdk.NewDec(-1, 10), false}, + {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, + {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDec(1, 10), false}, + {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDec(1, 10), false}, + {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDec(1, 10), false}, } for _, tc := range tests { @@ -195,14 +195,14 @@ func TestMsgBeginUnbonding(t *testing.T) { name string delegatorAddr sdk.AccAddress validatorAddr sdk.AccAddress - sharesAmount sdk.Rat + sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, sdk.NewRat(1, 10), true}, - {"negative decimal", addr1, addr2, sdk.NewRat(-1, 10), false}, - {"zero amount", addr1, addr2, sdk.ZeroRat(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewRat(1, 10), false}, - {"empty validator", addr1, emptyAddr, sdk.NewRat(1, 10), false}, + {"regular", addr1, addr2, sdk.NewDec(1, 10), true}, + {"negative decimal", addr1, addr2, sdk.NewDec(-1, 10), false}, + {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, + {"empty delegator", emptyAddr, addr1, sdk.NewDec(1, 10), false}, + {"empty validator", addr1, emptyAddr, sdk.NewDec(1, 10), false}, } for _, tc := range tests { diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 5a7dd6ef5565..927df1682c95 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -12,10 +12,10 @@ const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 // Params defines the high level settings for staking type Params struct { - InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate - InflationMax sdk.Rat `json:"inflation_max"` // maximum inflation rate - InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate - GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms + InflationDeceChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate + InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate + InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate + GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms UnbondingTime int64 `json:"unbonding_time"` @@ -33,10 +33,10 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationRateChange: sdk.NewRat(13, 100), - InflationMax: sdk.NewRat(20, 100), - InflationMin: sdk.NewRat(7, 100), - GoalBonded: sdk.NewRat(67, 100), + InflationDeceChange: sdk.NewDec(13, 100), + InflationMax: sdk.NewDec(20, 100), + InflationMin: sdk.NewDec(7, 100), + GoalBonded: sdk.NewDec(67, 100), UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 6ddadf94b55f..d884cff34d36 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -9,15 +9,15 @@ import ( // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator - BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens + LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time - Inflation sdk.Rat `json:"inflation"` // current annual inflation rate + Inflation sdk.Dec `json:"inflation"` // current annual inflation rate DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily) // Fee Related - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations + PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations } // nolint @@ -30,48 +30,48 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - LooseTokens: sdk.ZeroRat(), - BondedTokens: sdk.ZeroRat(), + LooseTokens: sdk.ZeroDec(), + BondedTokens: sdk.ZeroDec(), InflationLastTime: 0, - Inflation: sdk.NewRat(7, 100), + Inflation: sdk.NewDec(7, 100), DateLastCommissionReset: 0, - PrevBondedShares: sdk.ZeroRat(), + PrevBondedShares: sdk.ZeroDec(), } } //____________________________________________________________________ // Sum total of all staking tokens in the pool -func (p Pool) TokenSupply() sdk.Rat { +func (p Pool) TokenSupply() sdk.Dec { return p.LooseTokens.Add(p.BondedTokens) } //____________________________________________________________________ // get the bond ratio of the global state -func (p Pool) BondedRatio() sdk.Rat { +func (p Pool) BondedRatio() sdk.Dec { supply := p.TokenSupply() - if supply.GT(sdk.ZeroRat()) { + if supply.GT(sdk.ZeroDec()) { return p.BondedTokens.Quo(supply) } - return sdk.ZeroRat() + return sdk.ZeroDec() } //_______________________________________________________________________ -func (p Pool) looseTokensToBonded(bondedTokens sdk.Rat) Pool { +func (p Pool) looseTokensToBonded(bondedTokens sdk.Dec) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) p.LooseTokens = p.LooseTokens.Sub(bondedTokens) - if p.LooseTokens.LT(sdk.ZeroRat()) { + if p.LooseTokens.LT(sdk.ZeroDec()) { panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) } return p } -func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { +func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) p.LooseTokens = p.LooseTokens.Add(bondedTokens) - if p.BondedTokens.LT(sdk.ZeroRat()) { + if p.BondedTokens.LT(sdk.ZeroDec()) { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } return p @@ -80,15 +80,15 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { //_______________________________________________________________________ // Inflation -const precision = 10000 // increased to this precision for accuracy -var hrsPerYrRat = sdk.NewRat(8766) // as defined by a julian year of 365.25 days +const precision = 10000 // increased to this precision for accuracy +var hrsPerYrDec = sdk.NewDec(8766, 0) // as defined by a julian year of 365.25 days // process provisions for an hour period func (p Pool) ProcessProvisions(params Params) Pool { p.Inflation = p.NextInflation(params) provisions := p.Inflation. - Mul(p.TokenSupply().Round(precision)). - Quo(hrsPerYrRat) + Mul(p.TokenSupply()). + Quo(hrsPerYrDec) // TODO add to the fees provisions p.LooseTokens = p.LooseTokens.Add(provisions) @@ -96,7 +96,7 @@ func (p Pool) ProcessProvisions(params Params) Pool { } // get the next inflation rate for the hour -func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { +func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { // The target annual inflation rate is recalculated for each previsions cycle. The // inflation is also subject to a rate change (positive or negative) depending on @@ -104,15 +104,15 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { // defined to be 13% per year, however the annual inflation is capped as between // 7% and 20%. - // (1 - bondedRatio/GoalBonded) * InflationRateChange - inflationRateChangePerYear := sdk.OneRat(). - Sub(p.BondedRatio().Round(precision). + // (1 - bondedRatio/GoalBonded) * InflationDeceChange + inflationDeceChangePerYear := sdk.OneDec(). + Sub(p.BondedRatio(). Quo(params.GoalBonded)). - Mul(params.InflationRateChange) - inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrRat) + Mul(params.InflationDeceChange) + inflationDeceChange := inflationDeceChangePerYear.Quo(hrsPerYrDec) // increase the new annual inflation for this next cycle - inflation = p.Inflation.Add(inflationRateChange) + inflation = p.Inflation.Add(inflationDeceChange) if inflation.GT(params.InflationMax) { inflation = params.InflationMax } @@ -120,5 +120,5 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { inflation = params.InflationMin } - return inflation.Round(precision) + return inflation } diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 43a2eac065a4..4541edd3d9c7 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -11,28 +11,28 @@ func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() require.True(t, p1.Equal(p2)) - p2.BondedTokens = sdk.NewRat(3) + p2.BondedTokens = sdk.NewDec(3) require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) - pool.BondedTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.looseTokensToBonded(sdk.NewRat(10)) + pool = pool.looseTokensToBonded(sdk.NewDec(10)) - require.True(sdk.RatEq(t, sdk.NewRat(20), pool.BondedTokens)) - require.True(sdk.RatEq(t, sdk.NewRat(0), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(20), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) - pool.BondedTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.bondedTokensToLoose(sdk.NewRat(5)) + pool = pool.bondedTokensToLoose(sdk.NewDec(5)) - require.True(sdk.RatEq(t, sdk.NewRat(5), pool.BondedTokens)) - require.True(sdk.RatEq(t, sdk.NewRat(15), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(5), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(15), pool.LooseTokens)) } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 837b8f8e8a02..02b676e06c4e 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -26,21 +26,21 @@ type Validator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeDece sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Rat `json:"prev_bonded_tokens"` // Previous bonded tokens held + LastBondedTokens sdk.Dec `json:"prev_bonded_tokens"` // Previous bonded tokens held } // NewValidator - initialize a new validator @@ -50,17 +50,17 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri PubKey: pubKey, Revoked: false, Status: sdk.Unbonded, - Tokens: sdk.ZeroRat(), - DelegatorShares: sdk.ZeroRat(), + Tokens: sdk.ZeroDec(), + DelegatorShares: sdk.ZeroDec(), Description: description, BondHeight: int64(0), BondIntraTxCounter: int16(0), ProposerRewardPool: sdk.Coins{}, - Commission: sdk.ZeroRat(), - CommissionMax: sdk.ZeroRat(), - CommissionChangeRate: sdk.ZeroRat(), - CommissionChangeToday: sdk.ZeroRat(), - LastBondedTokens: sdk.ZeroRat(), + Commission: sdk.ZeroDec(), + CommissionMax: sdk.ZeroDec(), + CommissionChangeDece: sdk.ZeroDec(), + CommissionChangeToday: sdk.ZeroDec(), + LastBondedTokens: sdk.ZeroDec(), } } @@ -69,17 +69,17 @@ type validatorValue struct { PubKey crypto.PubKey Revoked bool Status sdk.BondStatus - Tokens sdk.Rat - DelegatorShares sdk.Rat + Tokens sdk.Dec + DelegatorShares sdk.Dec Description Description BondHeight int64 BondIntraTxCounter int16 ProposerRewardPool sdk.Coins - Commission sdk.Rat - CommissionMax sdk.Rat - CommissionChangeRate sdk.Rat - CommissionChangeToday sdk.Rat - LastBondedTokens sdk.Rat + Commission sdk.Dec + CommissionMax sdk.Dec + CommissionChangeDece sdk.Dec + CommissionChangeToday sdk.Dec + LastBondedTokens sdk.Dec } // return the redelegation without fields contained within the key for the store @@ -96,7 +96,7 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { ProposerRewardPool: validator.ProposerRewardPool, Commission: validator.Commission, CommissionMax: validator.CommissionMax, - CommissionChangeRate: validator.CommissionChangeRate, + CommissionChangeDece: validator.CommissionChangeDece, CommissionChangeToday: validator.CommissionChangeToday, LastBondedTokens: validator.LastBondedTokens, } @@ -139,7 +139,7 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val ProposerRewardPool: storeValue.ProposerRewardPool, Commission: storeValue.Commission, CommissionMax: storeValue.CommissionMax, - CommissionChangeRate: storeValue.CommissionChangeRate, + CommissionChangeDece: storeValue.CommissionChangeDece, CommissionChangeToday: storeValue.CommissionChangeToday, LastBondedTokens: storeValue.LastBondedTokens, }, nil @@ -159,14 +159,14 @@ func (v Validator) HumanReadableString() (string, error) { resp += fmt.Sprintf("Validator: %s\n", bechVal) resp += fmt.Sprintf("Revoked: %v\n", v.Revoked) resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) - resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.FloatString()) - resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.FloatString()) + resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.String()) + resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String()) resp += fmt.Sprintf("Description: %s\n", v.Description) resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) resp += fmt.Sprintf("Proposer Reward Pool: %s\n", v.ProposerRewardPool.String()) resp += fmt.Sprintf("Commission: %s\n", v.Commission.String()) - resp += fmt.Sprintf("Max Commission Rate: %s\n", v.CommissionMax.String()) - resp += fmt.Sprintf("Commission Change Rate: %s\n", v.CommissionChangeRate.String()) + resp += fmt.Sprintf("Max Commission Dece: %s\n", v.CommissionMax.String()) + resp += fmt.Sprintf("Commission Change Dece: %s\n", v.CommissionChangeDece.String()) resp += fmt.Sprintf("Commission Change Today: %s\n", v.CommissionChangeToday.String()) resp += fmt.Sprintf("Previous Bonded Tokens: %s\n", v.LastBondedTokens.String()) @@ -182,21 +182,21 @@ type BechValidator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeDece sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Rat `json:"prev_bonded_shares"` // last bonded token amount + LastBondedTokens sdk.Dec `json:"prev_bonded_shares"` // last bonded token amount } // get the bech validator from the the regular validator @@ -222,7 +222,7 @@ func (v Validator) Bech32Validator() (BechValidator, error) { Commission: v.Commission, CommissionMax: v.CommissionMax, - CommissionChangeRate: v.CommissionChangeRate, + CommissionChangeDece: v.CommissionChangeDece, CommissionChangeToday: v.CommissionChangeToday, LastBondedTokens: v.LastBondedTokens, @@ -243,7 +243,7 @@ func (v Validator) Equal(c2 Validator) bool { v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && v.Commission.Equal(c2.Commission) && v.CommissionMax.Equal(c2.CommissionMax) && - v.CommissionChangeRate.Equal(c2.CommissionChangeRate) && + v.CommissionChangeDece.Equal(c2.CommissionChangeDece) && v.CommissionChangeToday.Equal(c2.CommissionChangeToday) && v.LastBondedTokens.Equal(c2.LastBondedTokens) } @@ -364,7 +364,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, } // removes tokens from a validator -func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { +func (v Validator) RemoveTokens(pool Pool, tokens sdk.Dec) (Validator, Pool) { if v.Status == sdk.Bonded { pool = pool.bondedTokensToLoose(tokens) } @@ -376,26 +376,26 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Dec) { // bondedShare/delegatedShare - exRate := v.DelegatorShareExRate() - amountRat := sdk.NewRat(amount) + exDece := v.DelegatorShareExDece() + amountDec := sdk.NewDec(amount, 0) if v.Status == sdk.Bonded { - pool = pool.looseTokensToBonded(amountRat) + pool = pool.looseTokensToBonded(amountDec) } - v.Tokens = v.Tokens.Add(amountRat) - issuedShares := amountRat.Quo(exRate) + v.Tokens = v.Tokens.Add(amountDec) + issuedShares := amountDec.Quo(exDece) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedShares } // RemoveDelShares removes delegator shares from a validator. -func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { - issuedTokens := v.DelegatorShareExRate().Mul(delShares) +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Pool, sdk.Dec) { + issuedTokens := v.DelegatorShareExDece().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) @@ -406,21 +406,21 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Poo return v, pool, issuedTokens } -// DelegatorShareExRate gets the exchange rate of tokens over delegator shares. +// DelegatorShareExDece gets the exchange rate of tokens over delegator shares. // UNITS: tokens/delegator-shares -func (v Validator) DelegatorShareExRate() sdk.Rat { +func (v Validator) DelegatorShareExDece() sdk.Dec { if v.DelegatorShares.IsZero() { - return sdk.OneRat() + return sdk.OneDec() } return v.Tokens.Quo(v.DelegatorShares) } // Get the bonded tokens which the validator holds -func (v Validator) BondedTokens() sdk.Rat { +func (v Validator) BondedTokens() sdk.Dec { if v.Status == sdk.Bonded { return v.Tokens } - return sdk.ZeroRat() + return sdk.ZeroDec() } //______________________________________________________________________ @@ -434,7 +434,7 @@ func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOwner() sdk.AccAddress { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Rat { return v.BondedTokens() } -func (v Validator) GetTokens() sdk.Rat { return v.Tokens } -func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares } +func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } +func (v Validator) GetTokens() sdk.Dec { return v.Tokens } +func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 536f44849ccc..d2dca54de9ea 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -74,19 +74,19 @@ func TestRemoveTokens(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewRat(100), - DelegatorShares: sdk.NewRat(100), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) // remove tokens and test check everything - validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) @@ -97,7 +97,7 @@ func TestRemoveTokens(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) - validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) @@ -105,43 +105,43 @@ func TestRemoveTokens(t *testing.T) { func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -150,16 +150,16 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewRat(100), - DelegatorShares: sdk.NewRat(100), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewRat(10) + poolA.LooseTokens = sdk.NewDec(10) poolA.BondedTokens = valA.BondedTokens() - require.Equal(t, valA.DelegatorShareExRate(), sdk.OneRat()) + require.Equal(t, valA.DelegatorShareExDece(), sdk.OneDec()) // Remove delegator shares - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10)) assert.Equal(t, int64(10), coinsB.RoundInt64()) assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) @@ -167,13 +167,13 @@ func TestRemoveDelShares(t *testing.T) { assert.Equal(t, int64(20), poolB.LooseTokens.RoundInt64()) // conservation of tokens - require.True(sdk.RatEq(t, + require.True(sdk.DecEq(t, poolB.LooseTokens.Add(poolB.BondedTokens), poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests - poolTokens := sdk.NewRat(5102) - delShares := sdk.NewRat(115) + poolTokens := sdk.NewDec(5102) + delShares := sdk.NewDec(115) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -182,22 +182,22 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - BondedTokens: sdk.NewRat(248305), - LooseTokens: sdk.NewRat(232147), + BondedTokens: sdk.NewDec(248305), + LooseTokens: sdk.NewDec(232147), InflationLastTime: 0, - Inflation: sdk.NewRat(7, 100), + Inflation: sdk.NewDec(7, 100), } - shares := sdk.NewRat(29) + shares := sdk.NewDec(29) _, newPool, tokens := validator.RemoveDelShares(pool, shares) - require.True(sdk.RatEq(t, sdk.NewRat(147958, 115), tokens)) - require.True(sdk.RatEq(t, + require.True(sdk.DecEq(t, sdk.NewDec(147958, 115), tokens)) + require.True(sdk.DecEq(t, newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) } func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(100) + pool.LooseTokens = sdk.NewDec(100) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) @@ -220,8 +220,8 @@ func TestUpdateStatus(t *testing.T) { } func TestPossibleOverflow(t *testing.T) { - poolTokens := sdk.NewRat(2159) - delShares := sdk.NewRat(391432570689183511).Quo(sdk.NewRat(40113011844664)) + poolTokens := sdk.NewDec(2159) + delShares := sdk.NewDec(391432570689183511).Quo(sdk.NewDec(40113011844664)) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -230,19 +230,19 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewRat(100), + LooseTokens: sdk.NewDec(100), BondedTokens: poolTokens, InflationLastTime: 0, - Inflation: sdk.NewRat(7, 100), + Inflation: sdk.NewDec(7, 100), } tokens := int64(71) msg := fmt.Sprintf("validator %#v", validator) newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroRat()), - "Applying operation \"%s\" resulted in negative DelegatorShareExRate(): %v", - msg, newValidator.DelegatorShareExRate()) + require.False(t, newValidator.DelegatorShareExDece().LT(sdk.ZeroDec()), + "Applying operation \"%s\" resulted in negative DelegatorShareExDece(): %v", + msg, newValidator.DelegatorShareExDece()) } func TestHumanReadableString(t *testing.T) { From 5015fd487a9300f6eed17ed0885eb3c36bbfd34d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:45:40 -0400 Subject: [PATCH 21/50] revert changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e068c5adca..29d753a6dc43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,7 +134,7 @@ FEATURES * gocyclo * [tools] Added `make format` command to automate fixing misspell and gofmt errors. * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates -* [types] Switches internal representation of Int/Uint/Dec to use pointers +* [types] Switches internal representation of Int/Uint/Rat to use pointers * [types] Added MinInt and MinUint functions * [gaiad] `unsafe_reset_all` now resets addrbook.json * [democoin] add x/oracle, x/assoc @@ -383,7 +383,7 @@ BREAKING CHANGES * Removed SealedAccountMapper * gaiad init now requires use of `--name` flag * Removed Get from Msg interface -* types/rational now extends big.Dec +* types/rational now extends big.Rat FEATURES: From d2bf108425bf7c87531cb5a6164ef5371eac5359 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 11:49:32 -0400 Subject: [PATCH 22/50] code compiles (not tests) --- client/lcd/test_helpers.go | 2 +- cmd/gaia/app/genesis.go | 4 ++-- server/util.go | 4 ++-- x/stake/client/cli/tx.go | 4 ++-- x/stake/client/rest/tx.go | 5 ++--- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 7c3bac5dbb6f..9989085e7fd9 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -147,7 +147,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewCoin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100, 0)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index b80150208789..558e7c725f6a 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -160,7 +160,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState } acc := NewGenesisAccount(&accAuth) genaccs[i] = acc - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc, 0)) // increase the supply // add the validator if len(genTx.Name) > 0 { @@ -168,7 +168,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState validator := stake.NewValidator(genTx.Address, sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc) - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal, 0)) // increase the supply // add some new shares to the validator var issuedDelShares sdk.Dec diff --git a/server/util.go b/server/util.go index d3d5726e27d6..51547d116b2a 100644 --- a/server/util.go +++ b/server/util.go @@ -82,8 +82,8 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { // the following parse config is needed to create directories conf, _ = tcmd.ParseConfig() conf.ProfListenAddress = "localhost:6060" - conf.P2P.RecvDece = 5120000 - conf.P2P.SendDece = 5120000 + conf.P2P.RecvRate = 5120000 + conf.P2P.SendRate = 5120000 conf.Consensus.TimeoutCommit = 5000 cfg.WriteConfigFile(configFilePath, conf) // Fall through, just so that its parsed into memory. diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 4d94c3bbea5a..12786706c271 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -228,7 +228,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewDecFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) + sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr) if err != nil { return sharesAmount, err } @@ -237,7 +237,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent } case sharesPercentStr != "": var sharesPercent sdk.Dec - sharesPercent, err = sdk.NewDecFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) + sharesPercent, err = sdk.NewDecFromStr(sharesPercentStr) if err != nil { return sharesAmount, err } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 73c850eb6f12..c1c30e0c0a97 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -14,7 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/cosmos/cosmos-sdk/x/stake/types" ) func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { @@ -148,7 +147,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) @@ -213,7 +212,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) From 3f4bb2ebea266a2259b32de689da929c4b0bdcc9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 12:31:48 -0400 Subject: [PATCH 23/50] went through all NewDec, made sure they were converted from NewRat properly --- cmd/gaia/app/sim_test.go | 2 +- cmd/gaia/cli_test/cli_test.go | 2 +- .../democoin/x/assoc/validator_set_test.go | 4 +- examples/democoin/x/oracle/oracle_test.go | 10 +-- x/fee_distribution/movement.go | 2 +- x/gov/genesis.go | 6 +- x/params/keeper_test.go | 6 +- x/slashing/app_test.go | 4 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper_test.go | 10 +-- x/slashing/tick_test.go | 2 +- x/stake/app_test.go | 12 +-- x/stake/genesis_test.go | 8 +- x/stake/handler_test.go | 62 ++++++------- x/stake/keeper/delegation_test.go | 30 +++---- x/stake/keeper/keeper_test.go | 2 +- x/stake/keeper/slash_test.go | 52 +++++------ x/stake/keeper/test_common.go | 2 +- x/stake/keeper/validator_test.go | 88 +++++++++---------- x/stake/simulation/msgs.go | 2 +- x/stake/types/delegation_test.go | 16 ++-- x/stake/types/inflation_test.go | 34 +++---- x/stake/types/msg_test.go | 18 ++-- x/stake/types/params.go | 8 +- x/stake/types/pool.go | 2 +- x/stake/types/pool_test.go | 22 ++--- x/stake/types/validator_test.go | 62 ++++++------- 27 files changed, 236 insertions(+), 234 deletions(-) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 6369b4ca66fc..b2fafd68f04b 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -48,7 +48,7 @@ func appStateFn(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage { // Default genesis state stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(1000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(1000, 0) genesis := GenesisState{ Accounts: genesisAccounts, StakeData: stakeGenesis, diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7db80c9cc832..80cce9a305f5 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -132,7 +132,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(2, 0), validator.Tokens)) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index eac23b25e221..e4f04401698e 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -32,8 +32,8 @@ func TestValidatorSet(t *testing.T) { addr2 := []byte("addr2") base := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewDec(1)}, - {addr2, sdk.NewDec(2)}, + {addr1, sdk.NewDec(1, 0)}, + {addr2, sdk.NewDec(2, 0)}, }} valset := NewValidatorSet(wire.NewCodec(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5) diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index ac3a45695696..a5c7420e626f 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -107,9 +107,9 @@ func TestOracle(t *testing.T) { addr3 := []byte("addr3") addr4 := []byte("addr4") valset := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewDec(7)}, - {addr2, sdk.NewDec(7)}, - {addr3, sdk.NewDec(1)}, + {addr1, sdk.NewDec(7, 0)}, + {addr2, sdk.NewDec(7, 0)}, + {addr3, sdk.NewDec(1, 0)}, }} key := sdk.NewKVStoreKey("testkey") @@ -119,7 +119,7 @@ func TestOracle(t *testing.T) { require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) - ork := NewKeeper(key, cdc, valset, sdk.NewDec(2, 3), 100) + ork := NewKeeper(key, cdc, valset, sdk.NewDec(667, 3), 100) // 66.7% h := seqHandler(ork, key, sdk.CodespaceRoot) // Nonmock.Validator signed, transaction failed @@ -171,7 +171,7 @@ func TestOracle(t *testing.T) { require.Equal(t, 1, getSequence(ctx, key)) // Should handle mock.Validator set change - valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12)}) + valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12, 0)}) bz, err = json.Marshal(valset) require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) diff --git a/x/fee_distribution/movement.go b/x/fee_distribution/movement.go index 2b8732c4a36a..ebd3e3714851 100644 --- a/x/fee_distribution/movement.go +++ b/x/fee_distribution/movement.go @@ -37,7 +37,7 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //func coinsMulDec(coins sdk.Coins, rat sdk.Dec) sdk.Coins { //var res sdk.Coins //for _, coin := range coins { -//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount)).Evaluate() +//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount, 0)).Evaluate() //coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} //res = res.Plus(coinMul) //} diff --git a/x/gov/genesis.go b/x/gov/genesis.go index af82dc4ac4f2..add12dca511b 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewDec(1, 2), - Veto: sdk.NewDec(1, 3), - GovernancePenalty: sdk.NewDec(1, 100), + Threshold: sdk.NewDec(5, 1), + Veto: sdk.NewDec(333, 3), // 33.3% + GovernancePenalty: sdk.NewDec(1, 2), // 1% }, } } diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 63f6e5da9a46..f98e15f1c07e 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -94,7 +94,7 @@ func TestGetter(t *testing.T) { {"uint64", uint64(1)}, {"int", sdk.NewInt(1)}, {"uint", sdk.NewUint(1)}, - {"rat", sdk.NewDec(1)}, + {"rat", sdk.NewDec(1, 1)}, } assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1)) }) + assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1, 1)) }) var res interface{} var err error @@ -263,7 +263,7 @@ func TestGetter(t *testing.T) { assert.Equal(t, def9, res) // Dec - def10 := sdk.NewDec(0) + def10 := sdk.NewDec(0, 0) res, err = g.GetDec(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 269329e86a10..af15930e10ad 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -58,7 +58,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -109,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 41cb5d19968c..3c04ffc1a9ba 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) // assert non-revoked validator can't be unrevoked got = slh(ctx, NewMsgUnrevoke(addr)) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 74b33f7c2f8d..99de2e7ed452 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -31,7 +31,7 @@ func TestHandleDoubleSign(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info keeper.handleValidatorSignature(ctx, val, amtInt, true) @@ -44,12 +44,12 @@ func TestHandleDoubleSign(t *testing.T) { // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, @@ -66,7 +66,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -172,7 +172,7 @@ func TestHandleNewValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDec(amt, 0), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 9540745bb9ce..dc1d2229be25 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -21,7 +21,7 @@ func TestBeginBlocker(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) val := abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(pk), diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 1de76ba14bd9..39e2c9a2bc98 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -138,7 +138,7 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) // addr1 create validator on behalf of addr2 createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) @@ -150,10 +150,10 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10, 0)) // edit the validator description = NewDescription("bar_moniker", "", "", "") @@ -169,10 +169,10 @@ func TestStakeMsgs(t *testing.T) { mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10, 0)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10, 0)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 2d3e35f2317e..ff7900289f39 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -17,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(2) + pool.BondedTokens = sdk.NewDec(2, 0) params := keeper.GetParams(ctx) var delegations []Delegation @@ -67,7 +67,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(int64(200 + (size - 100))) + pool.BondedTokens = sdk.NewDec(int64(200+(size-100)), 0) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -78,8 +78,8 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators[i].Status = sdk.Bonded if i < 100 { - validators[i].Tokens = sdk.NewDec(2) - validators[i].DelegatorShares = sdk.NewDec(2) + validators[i].Tokens = sdk.NewDec(2, 0) + validators[i].DelegatorShares = sdk.NewDec(2, 0) } else { validators[i].Tokens = sdk.OneDec() validators[i].DelegatorShares = sdk.OneDec() diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 956b8e6700f0..d26528f92b68 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -80,7 +80,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(5, 1)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -109,7 +109,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000, 0)) msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -137,8 +137,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewDec(10), validator.BondedTokens()) - assert.Equal(t, sdk.NewDec(10), validator.DelegatorShares) + assert.Equal(t, sdk.NewDec(10, 0), validator.BondedTokens()) + assert.Equal(t, sdk.NewDec(10, 0), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) // two validators can't have the same owner address @@ -161,8 +161,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -181,8 +181,8 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Owner) assert.Equal(t, pk, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator @@ -294,7 +294,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here - unbondShares := sdk.NewDec(10) + unbondShares := sdk.NewDec(10, 0) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) numUnbonds := 5 @@ -338,7 +338,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } for _, c := range errorCases { - unbondShares := sdk.NewDec(int64(c)) + unbondShares := sdk.NewDec(int64(c), 0) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "expected unbond msg to fail") @@ -347,14 +347,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have - unbondShares = sdk.NewDec(leftBonded + 1) + unbondShares = sdk.NewDec(leftBonded+1, 0) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have - unbondShares = sdk.NewDec(leftBonded) + unbondShares = sdk.NewDec(leftBonded, 0) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), @@ -390,7 +390,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10, 0)) // remove delegation msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -435,7 +435,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10, 0)) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -466,7 +466,7 @@ func TestRevokeValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10, 0)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -482,7 +482,7 @@ func TestRevokeValidator(t *testing.T) { require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds - msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10, 0)) msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -509,7 +509,7 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10, 0)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") @@ -564,7 +564,7 @@ func TestRedelegationPeriod(t *testing.T) { bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10, 0)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) @@ -616,12 +616,12 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10, 0)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) + msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10, 0)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) @@ -662,7 +662,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30, 0)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -784,7 +784,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30, 0)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -797,7 +797,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) + msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50, 0)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -831,22 +831,22 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx = ctx.WithBlockHeight(1) // begin unbonding 4 stake - msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4)) + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4, 0)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // begin redelegate 6 stake - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6)) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6, 0)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(6), delegation.Shares) + require.Equal(t, sdk.NewDec(6, 0), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(5, 1)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -861,16 +861,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3, 0), delegation.Shares) // validator power should have been reduced by half validator, found := keeper.GetValidator(ctx, valA) require.True(t, found) - require.Equal(t, sdk.NewDec(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5, 0), validator.GetPower()) // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(5, 1)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) @@ -885,7 +885,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3, 0), delegation.Shares) // validator power should have been reduced to zero // ergo validator should have been removed from the store diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 92bc29d519c4..a6b71997789c 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -31,7 +31,7 @@ func TestDelegation(t *testing.T) { bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], - Shares: sdk.NewDec(9), + Shares: sdk.NewDec(9, 0), } // check the empty keeper first @@ -45,18 +45,18 @@ func TestDelegation(t *testing.T) { require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewDec(99) + bond1to1.Shares = sdk.NewDec(99, 0) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9), 0} - bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9), 1} - bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9), 2} - bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9), 3} - bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9), 4} + bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9, 0), 0} + bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9, 0), 1} + bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9, 0), 2} + bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9, 0), 3} + bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9, 0), 4} keeper.SetDelegation(ctx, bond1to2) keeper.SetDelegation(ctx, bond1to3) keeper.SetDelegation(ctx, bond2to1) @@ -141,7 +141,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -163,7 +163,7 @@ func TestUnbondDelegation(t *testing.T) { var err error var amount sdk.Dec - amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) + amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6, 0)) require.NoError(t, err) require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation @@ -189,8 +189,8 @@ func TestGetRedelegationsFromValidator(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), + SharesSrc: sdk.NewDec(5, 0), + SharesDst: sdk.NewDec(5, 0), } // set and retrieve a record @@ -219,8 +219,8 @@ func TestRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), + SharesSrc: sdk.NewDec(5, 0), + SharesDst: sdk.NewDec(5, 0), } // test shouldn't have and redelegations @@ -241,8 +241,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewDec(21) - rd.SharesDst = sdk.NewDec(21) + rd.SharesSrc = sdk.NewDec(21, 0) + rd.SharesDst = sdk.NewDec(21, 0) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 9307ddddf252..c29c75f86604 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = sdk.NewDec(777) + expPool.BondedTokens = sdk.NewDec(777, 0) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index a4ed7fe7ed31..54cef435456e 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -18,7 +18,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewDec(amt * int64(numVals)) + pool.LooseTokens = sdk.NewDec(amt*int64(numVals), 0) // add numVals validators for i := 0; i < numVals; i++ { @@ -62,7 +62,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -105,7 +105,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -115,8 +115,8 @@ func TestSlashRedelegation(t *testing.T) { CreationHeight: 0, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewDec(10), - SharesDst: sdk.NewDec(10), + SharesSrc: sdk.NewDec(10, 0), + SharesDst: sdk.NewDec(10, 0), InitialBalance: sdk.NewCoin(params.BondDenom, 10), Balance: sdk.NewCoin(params.BondDenom, 10), } @@ -126,7 +126,7 @@ func TestSlashRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(10), + Shares: sdk.NewDec(10, 0), } keeper.SetDelegation(ctx, del) @@ -171,7 +171,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -179,7 +179,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -192,16 +192,16 @@ func TestSlashAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // power decreased - require.Equal(t, sdk.NewDec(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5, 0), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewDec(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + require.Equal(t, sdk.NewDec(5, 0).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -238,7 +238,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(7), validator.GetPower()) + require.Equal(t, sdk.NewDec(7, 0), validator.GetPower()) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -255,7 +255,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4, 0), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -275,7 +275,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(1), validator.GetPower()) + require.Equal(t, sdk.NewDec(1, 1), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -302,7 +302,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -311,8 +311,8 @@ func TestSlashWithRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 11, MinTime: 0, - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), + SharesSrc: sdk.NewDec(6, 0), + SharesDst: sdk.NewDec(6, 0), InitialBalance: sdk.NewCoin(params.BondDenom, 6), Balance: sdk.NewCoin(params.BondDenom, 6), } @@ -322,13 +322,13 @@ func TestSlashWithRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6), + Shares: sdk.NewDec(6, 0), } keeper.SetDelegation(ctx, del) // update bonded tokens pool := keeper.GetPool(ctx) - pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6, 0)) keeper.SetPool(ctx, pool) // slash validator @@ -354,7 +354,7 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(8), validator.GetPower()) + require.Equal(t, sdk.NewDec(8, 0), validator.GetPower()) // slash the validator again ctx = ctx.WithBlockHeight(12) @@ -375,7 +375,7 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 4 - require.Equal(t, sdk.NewDec(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4, 0), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) @@ -423,7 +423,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDec(5, 1) // set a redelegation rdA := types.Redelegation{ @@ -433,8 +433,8 @@ func TestSlashBoth(t *testing.T) { CreationHeight: 11, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), + SharesSrc: sdk.NewDec(6, 0), + SharesDst: sdk.NewDec(6, 0), InitialBalance: sdk.NewCoin(params.BondDenom, 6), Balance: sdk.NewCoin(params.BondDenom, 6), } @@ -444,7 +444,7 @@ func TestSlashBoth(t *testing.T) { delA := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6), + Shares: sdk.NewDec(6, 0), } keeper.SetDelegation(ctx, delA) @@ -482,5 +482,5 @@ func TestSlashBoth(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, sdk.NewDec(10), validator.GetPower()) + require.Equal(t, sdk.NewDec(10, 0), validator.GetPower()) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index e49ee1adf829..9769dd073a26 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -80,7 +80,7 @@ func ParamsNoInflation() types.Params { InflationDeceChange: sdk.ZeroDec(), InflationMax: sdk.ZeroDec(), InflationMin: sdk.ZeroDec(), - GoalBonded: sdk.NewDec(67, 100), + GoalBonded: sdk.NewDec(67, 2), MaxValidators: 100, BondDenom: "steak", } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 0c84052df4bd..31dbb4a83e54 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -19,8 +19,8 @@ func TestSetValidator(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -28,8 +28,8 @@ func TestSetValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -55,8 +55,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewDec(10000) - pool.BondedTokens = sdk.NewDec(1234) + pool.LooseTokens = sdk.NewDec(10000, 0) + pool.BondedTokens = sdk.NewDec(1234, 0) keeper.SetPool(ctx, pool) // add a validator @@ -75,7 +75,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares - validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) + validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2, 0))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out @@ -125,9 +125,9 @@ func TestValidatorBasics(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) } - assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(8), validators[1].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(7), validators[2].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(9, 0), validators[0].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(8, 0), validators[1].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(7, 0), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -148,15 +148,15 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(9, 0), validators[0].BondedTokens())) pool = keeper.GetPool(ctx) assert.True(sdk.DecEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(10) - validators[0].DelegatorShares = sdk.NewDec(10) + validators[0].Tokens = sdk.NewDec(10, 0) + validators[0].DelegatorShares = sdk.NewDec(10, 0) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -199,19 +199,19 @@ func GetValidatorSortingUnmixed(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewDec(amt) - validators[i].DelegatorShares = sdk.NewDec(amt) + validators[i].Tokens = sdk.NewDec(amt, 0) + validators[i].DelegatorShares = sdk.NewDec(amt, 0) keeper.UpdateValidator(ctx, validators[i]) } // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400, 0), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200, 0), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100, 0), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0, 0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -219,14 +219,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewDec(500) + validators[3].Tokens = sdk.NewDec(500, 0) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewDec(300) + validators[3].Tokens = sdk.NewDec(300, 0) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -234,7 +234,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewDec(200) + validators[3].Tokens = sdk.NewDec(200, 0) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -253,8 +253,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewDec(300) - validators[4].Tokens = sdk.NewDec(300) + validators[3].Tokens = sdk.NewDec(300, 0) + validators[4].Tokens = sdk.NewDec(300, 0) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -281,20 +281,20 @@ func GetValidatorSortingMixed(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewDec(amt) + validators[i].DelegatorShares = sdk.NewDec(amt, 0) } validators[0].Status = sdk.Bonded validators[1].Status = sdk.Bonded validators[2].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(amts[0]) - validators[1].Tokens = sdk.NewDec(amts[1]) - validators[2].Tokens = sdk.NewDec(amts[2]) + validators[0].Tokens = sdk.NewDec(amts[0], 0) + validators[1].Tokens = sdk.NewDec(amts[1], 0) + validators[2].Tokens = sdk.NewDec(amts[2], 0) validators[3].Status = sdk.Bonded validators[4].Status = sdk.Bonded - validators[3].Tokens = sdk.NewDec(amts[3]) - validators[4].Tokens = sdk.NewDec(amts[4]) + validators[3].Tokens = sdk.NewDec(amts[3], 0) + validators[4].Tokens = sdk.NewDec(amts[4], 0) for i := range amts { keeper.UpdateValidator(ctx, validators[i]) @@ -318,11 +318,11 @@ func GetValidatorSortingMixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400, 0), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200, 0), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100, 0), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0, 0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -387,7 +387,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201, 0)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -599,7 +599,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(600) + validators[0].Tokens = sdk.NewDec(600, 0) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -737,21 +737,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power - require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100, 0).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100, 0).RoundInt64(), validators[1].GetPower().RoundInt64()) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} pool := keeper.GetPool(ctx) - validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) - validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20, 0)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30, 0)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) // power has changed - require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(80, 0).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(70, 0).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 7032535091fc..7f3b15058ed4 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 1)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 0)) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index db4dd77233b1..9c10e78c5105 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -11,19 +11,19 @@ func TestDelegationEqual(t *testing.T) { d1 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewDec(100, 0), } d2 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewDec(100, 0), } ok := d1.Equal(d2) require.True(t, ok) d2.ValidatorAddr = addr3 - d2.Shares = sdk.NewDec(200) + d2.Shares = sdk.NewDec(200, 0) ok = d1.Equal(d2) require.False(t, ok) @@ -33,7 +33,7 @@ func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewDec(100, 0), } // NOTE: Being that the validator's keypair is random, we cannot test the @@ -91,8 +91,8 @@ func TestRedelegationEqual(t *testing.T) { ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewDec(10) - r2.SharesSrc = sdk.NewDec(20) + r2.SharesDst = sdk.NewDec(10, 0) + r2.SharesSrc = sdk.NewDec(20, 0) r2.MinTime = 20 * 20 * 2 ok = r1.Equal(r2) @@ -104,8 +104,8 @@ func TestRedelegationHumanReadableString(t *testing.T) { DelegatorAddr: addr1, ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, - SharesDst: sdk.NewDec(10), - SharesSrc: sdk.NewDec(20), + SharesDst: sdk.NewDec(10, 0), + SharesSrc: sdk.NewDec(20, 0), } // NOTE: Being that the validator's keypair is random, we cannot test the diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index 242b5ffaf5e2..7d664b7c78ee 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -26,27 +26,27 @@ func TestGetInflation(t *testing.T) { setInflation, expectedChange sdk.Dec }{ // with 0% bonded atom supply the inflation should increase by InflationDeceChange - {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 100), params.InflationDeceChange.Quo(hrsPerYrDec).Round(precision)}, + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationDeceChange.Quo(hrsPerYrDec).Round(precision)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 100), + {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 100), - sdk.OneDec().Sub(sdk.NewDec(1, 2).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, + {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 2), + sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 100), sdk.ZeroDec()}, - {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(70001, 1000000), sdk.NewDec(-1, 1000000)}, + {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), sdk.ZeroDec()}, + {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(70001, 6), sdk.NewDec(-1, 6)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(20, 100), sdk.ZeroDec()}, - {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(199999, 1000000), sdk.NewDec(1, 1000000)}, + {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), sdk.ZeroDec()}, + {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(199999, 6), sdk.NewDec(1, 6)}, // perfect balance shouldn't change inflation - {"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDec(15, 100), sdk.ZeroDec()}, + {"test 8", sdk.NewDec(67, 0), sdk.NewDec(33, 0), sdk.NewDec(15, 2), sdk.ZeroDec()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -69,7 +69,7 @@ func TestProcessProvisions(t *testing.T) { initialTotalTokens int64 = 550000000 cumulativeExpProvs = sdk.ZeroDec() ) - pool.LooseTokens = sdk.NewDec(initialTotalTokens) + pool.LooseTokens = sdk.NewDec(initialTotalTokens, 0) // process the provisions for a year for hr := 0; hr < 100; hr++ { @@ -79,7 +79,7 @@ func TestProcessProvisions(t *testing.T) { } //get the pool and do the final value checks from checkFinalPoolValues - checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens, 0), cumulativeExpProvs) } //_________________________________________________________________________________________ @@ -113,12 +113,12 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation switch { //BELOW 67% - Dece of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewDec(67, 100)) && updatedInflation.LT(sdk.NewDec(20, 100)): + case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)): require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) //BELOW 67% - Dece of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewDec(67, 100)) && updatedInflation.Equal(sdk.NewDec(20, 100)): - if previousInflation.Equal(sdk.NewDec(20, 100)) { + case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(20, 2)): + if previousInflation.Equal(sdk.NewDec(20, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) @@ -127,12 +127,12 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation } //ABOVE 67% - Dece of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewDec(67, 100)) && updatedInflation.LT(sdk.NewDec(20, 100)) && updatedInflation.GT(sdk.NewDec(7, 100)): + case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)) && updatedInflation.GT(sdk.NewDec(7, 2)): require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) //ABOVE 67% - Dece of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewDec(67, 100)) && updatedInflation.Equal(sdk.NewDec(7, 100)): - if previousInflation.Equal(sdk.NewDec(7, 100)) { + case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(7, 2)): + if previousInflation.Equal(sdk.NewDec(7, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index d3bf6f427bd1..a9490909e775 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -146,12 +146,12 @@ func TestMsgBeginRedelegate(t *testing.T) { sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewDec(1, 10), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewDec(-1, 10), false}, + {"regular", addr1, addr2, addr3, sdk.NewDec(1, 1), true}, + {"negative decimal", addr1, addr2, addr3, sdk.NewDec(-1, 1), false}, {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDec(1, 10), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDec(1, 10), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDec(1, 10), false}, + {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDec(1, 1), false}, + {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDec(1, 1), false}, + {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDec(1, 1), false}, } for _, tc := range tests { @@ -198,11 +198,11 @@ func TestMsgBeginUnbonding(t *testing.T) { sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, sdk.NewDec(1, 10), true}, - {"negative decimal", addr1, addr2, sdk.NewDec(-1, 10), false}, + {"regular", addr1, addr2, sdk.NewDec(1, 1), true}, + {"negative decimal", addr1, addr2, sdk.NewDec(-1, 1), false}, {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewDec(1, 10), false}, - {"empty validator", addr1, emptyAddr, sdk.NewDec(1, 10), false}, + {"empty delegator", emptyAddr, addr1, sdk.NewDec(1, 1), false}, + {"empty validator", addr1, emptyAddr, sdk.NewDec(1, 1), false}, } for _, tc := range tests { diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 927df1682c95..eb2c91e2b0a8 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -33,10 +33,10 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationDeceChange: sdk.NewDec(13, 100), - InflationMax: sdk.NewDec(20, 100), - InflationMin: sdk.NewDec(7, 100), - GoalBonded: sdk.NewDec(67, 100), + InflationDeceChange: sdk.NewDec(13, 2), + InflationMax: sdk.NewDec(20, 2), + InflationMin: sdk.NewDec(7, 2), + GoalBonded: sdk.NewDec(67, 2), UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index d884cff34d36..7d87eb57eacf 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -33,7 +33,7 @@ func InitialPool() Pool { LooseTokens: sdk.ZeroDec(), BondedTokens: sdk.ZeroDec(), InflationLastTime: 0, - Inflation: sdk.NewDec(7, 100), + Inflation: sdk.NewDec(7, 2), DateLastCommissionReset: 0, PrevBondedShares: sdk.ZeroDec(), } diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 4541edd3d9c7..c2c99327bc44 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -11,28 +11,28 @@ func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() require.True(t, p1.Equal(p2)) - p2.BondedTokens = sdk.NewDec(3) + p2.BondedTokens = sdk.NewDec(3, 0) require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) - pool.BondedTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) + pool.BondedTokens = sdk.NewDec(10, 0) - pool = pool.looseTokensToBonded(sdk.NewDec(10)) + pool = pool.looseTokensToBonded(sdk.NewDec(10, 0)) - require.True(sdk.DecEq(t, sdk.NewDec(20), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(0), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(20, 0), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(0, 0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) - pool.BondedTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) + pool.BondedTokens = sdk.NewDec(10, 0) - pool = pool.bondedTokensToLoose(sdk.NewDec(5)) + pool = pool.bondedTokensToLoose(sdk.NewDec(5, 0)) - require.True(sdk.DecEq(t, sdk.NewDec(5), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(15), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(5, 0), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(15, 0), pool.LooseTokens)) } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index d2dca54de9ea..8ce29c16d343 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -74,19 +74,19 @@ func TestRemoveTokens(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100), - DelegatorShares: sdk.NewDec(100), + Tokens: sdk.NewDec(100, 0), + DelegatorShares: sdk.NewDec(100, 0), } pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) // remove tokens and test check everything - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) @@ -97,7 +97,7 @@ func TestRemoveTokens(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) @@ -105,43 +105,43 @@ func TestRemoveTokens(t *testing.T) { func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) - assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -150,16 +150,16 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100), - DelegatorShares: sdk.NewDec(100), + Tokens: sdk.NewDec(100, 0), + DelegatorShares: sdk.NewDec(100, 0), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewDec(10) + poolA.LooseTokens = sdk.NewDec(10, 0) poolA.BondedTokens = valA.BondedTokens() require.Equal(t, valA.DelegatorShareExDece(), sdk.OneDec()) // Remove delegator shares - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10)) + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10, 0)) assert.Equal(t, int64(10), coinsB.RoundInt64()) assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) @@ -172,8 +172,8 @@ func TestRemoveDelShares(t *testing.T) { poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests - poolTokens := sdk.NewDec(5102) - delShares := sdk.NewDec(115) + poolTokens := sdk.NewDec(5102, 0) + delShares := sdk.NewDec(115, 0) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -182,14 +182,16 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - BondedTokens: sdk.NewDec(248305), - LooseTokens: sdk.NewDec(232147), + BondedTokens: sdk.NewDec(248305, 0), + LooseTokens: sdk.NewDec(232147, 0), InflationLastTime: 0, - Inflation: sdk.NewDec(7, 100), + Inflation: sdk.NewDec(7, 2), } - shares := sdk.NewDec(29) + shares := sdk.NewDec(29, 0) _, newPool, tokens := validator.RemoveDelShares(pool, shares) - require.True(sdk.DecEq(t, sdk.NewDec(147958, 115), tokens)) + exp, err := sdk.NewDecFromStr("1286.5913043478") + require.NoError(t, err) + require.True(sdk.DecEq(t, exp, tokens)) require.True(sdk.DecEq(t, newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) @@ -197,7 +199,7 @@ func TestRemoveDelShares(t *testing.T) { func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(100) + pool.LooseTokens = sdk.NewDec(100, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) @@ -220,8 +222,8 @@ func TestUpdateStatus(t *testing.T) { } func TestPossibleOverflow(t *testing.T) { - poolTokens := sdk.NewDec(2159) - delShares := sdk.NewDec(391432570689183511).Quo(sdk.NewDec(40113011844664)) + poolTokens := sdk.NewDec(2159, 0) + delShares := sdk.NewDec(391432570689183511, 0).Quo(sdk.NewDec(40113011844664, 0)) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -230,10 +232,10 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewDec(100), + LooseTokens: sdk.NewDec(100, 0), BondedTokens: poolTokens, InflationLastTime: 0, - Inflation: sdk.NewDec(7, 100), + Inflation: sdk.NewDec(7, 2), } tokens := int64(71) msg := fmt.Sprintf("validator %#v", validator) From 12e40222c7b1a7b5adf8c9d38ed00eded2a8c9af Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 28 Jul 2018 12:40:32 -0400 Subject: [PATCH 24/50] test debugging --- types/decimal.go | 1 - types/decimal_test.go | 14 +++++++------- x/slashing/keeper_test.go | 4 ++-- x/stake/simulation/msgs.go | 4 ++-- x/stake/types/inflation_test.go | 8 ++++---- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index a81fa3ca852c..f69e4e871dd2 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -255,7 +255,6 @@ func (d Dec) MarshalAmino() (string, error) { // requires a valid JSON string - strings quotes and calls UnmarshalText func (d *Dec) UnmarshalAmino(text string) (err error) { - fmt.Printf("debug hoot") tempInt := new(big.Int) err = tempInt.UnmarshalText([]byte(text)) if err != nil { diff --git a/types/decimal_test.go b/types/decimal_test.go index 8c1662b3a897..b9f9c0892616 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -219,13 +219,13 @@ func TestToLeftPadded(t *testing.T) { } } -var dcdc = wire.NewCodec() +var cdc = wire.NewCodec() func TestZeroDeserializationJSON(t *testing.T) { d := Dec{new(big.Int)} - err := dcdc.UnmarshalJSON([]byte("0"), &d) + err := cdc.UnmarshalJSON([]byte("0"), &d) require.Nil(t, err) - err = dcdc.UnmarshalJSON([]byte("{}"), &d) + err = cdc.UnmarshalJSON([]byte("{}"), &d) require.NotNil(t, err) } @@ -245,11 +245,11 @@ func TestSerializationText(t *testing.T) { func TestSerializationGoWireJSON(t *testing.T) { d := mustNewDecFromStr(t, "0.333") - bz, err := dcdc.MarshalJSON(d) + bz, err := cdc.MarshalJSON(d) require.NoError(t, err) d2 := Dec{new(big.Int)} - err = dcdc.UnmarshalJSON(bz, &d2) + err = cdc.UnmarshalJSON(bz, &d2) require.NoError(t, err) require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } @@ -257,7 +257,7 @@ func TestSerializationGoWireJSON(t *testing.T) { func TestSerializationGoWireBinary(t *testing.T) { d := mustNewDecFromStr(t, "0.333") - bz, err := dcdc.MarshalBinary(d) + bz, err := cdc.MarshalBinary(d) require.NoError(t, err) var d2 Dec @@ -279,7 +279,7 @@ func TestEmbeddedStructSerializationGoWire(t *testing.T) { require.Nil(t, err) var obj2 testDEmbedStruct - err = dcdc.UnmarshalBinary(bz, &obj2) + err = cdc.UnmarshalBinary(bz, &obj2) require.Nil(t, err) require.Equal(t, obj.Field1, obj2.Field1) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 99de2e7ed452..831b14a32529 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -44,12 +44,12 @@ func TestHandleDoubleSign(t *testing.T) { // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19, 0).Quo(sdk.NewDec(20, 0))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) - require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19, 0).Quo(sdk.NewDec(20, 0))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 7f3b15058ed4..9d8e4ba0c3ec 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -132,7 +132,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewDecFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount, 0), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -191,7 +191,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation DelegatorAddr: delegatorAddress, ValidatorSrcAddr: sourceValidatorAddress, ValidatorDstAddr: destValidatorAddress, - SharesAmount: sdk.NewDecFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount, 0), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index 7d664b7c78ee..00787ecfcbd9 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -26,16 +26,16 @@ func TestGetInflation(t *testing.T) { setInflation, expectedChange sdk.Dec }{ // with 0% bonded atom supply the inflation should increase by InflationDeceChange - {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationDeceChange.Quo(hrsPerYrDec).Round(precision)}, + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationDeceChange.Quo(hrsPerYrDec)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), - sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, + sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec)}, // 50% bonded, starting at 10% inflation and being increased {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 2), - sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec).Round(precision)}, + sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec)}, // test 7% minimum stop (testing with 100% bonded) {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), sdk.ZeroDec()}, @@ -96,7 +96,7 @@ func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativ func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Dec, sdk.Dec, Pool) { expInflation := pool.NextInflation(params) - expProvisions := expInflation.Mul(pool.TokenSupply().Round(precision)).Quo(hrsPerYrDec) + expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrDec) startTotalSupply := pool.TokenSupply() pool = pool.ProcessProvisions(params) From d605058dbd69de202298fadc1c235253a7835d58 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 1 Aug 2018 00:36:03 -0400 Subject: [PATCH 25/50] all testing bugs besides the json marshalling fixed --- x/stake/keeper/slash_test.go | 2 +- x/stake/types/validator_test.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 54cef435456e..899826ed5f78 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -275,7 +275,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(1, 1), validator.GetPower()) + require.Equal(t, sdk.NewDec(1, 0), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 8ce29c16d343..613b658efff8 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -189,9 +189,12 @@ func TestRemoveDelShares(t *testing.T) { } shares := sdk.NewDec(29, 0) _, newPool, tokens := validator.RemoveDelShares(pool, shares) - exp, err := sdk.NewDecFromStr("1286.5913043478") + + exp, err := sdk.NewDecFromStr("1286.5913043477") require.NoError(t, err) + require.True(sdk.DecEq(t, exp, tokens)) + require.True(sdk.DecEq(t, newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) From 0a247fd2cb45a7ea48d4ce82fb793dededd38ddf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 1 Aug 2018 00:58:18 -0400 Subject: [PATCH 26/50] json unmarshal --- types/decimal.go | 28 ++++++++++++++++++++++++++++ types/decimal_test.go | 7 ++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index f69e4e871dd2..c52d20d215a6 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "fmt" "math/big" "strconv" @@ -264,6 +265,33 @@ func (d *Dec) UnmarshalAmino(text string) (err error) { return nil } +// MarshalJSON defines custom encoding scheme +func (d Dec) MarshalJSON() ([]byte, error) { + if d.Int == nil { + d.Int = new(big.Int) + } + + text, err := d.Int.MarshalText() + if err != nil { + return nil, err + } + return json.Marshal(string(text)) +} + +// UnmarshalJSON defines custom decoding scheme +func (d *Dec) UnmarshalJSON(bz []byte) error { + if d.Int == nil { + d.Int = new(big.Int) + } + + var text string + err := json.Unmarshal(bz, &text) + if err != nil { + return err + } + return d.Int.UnmarshalText([]byte(text)) +} + //___________________________________________________________________________________ // helpers diff --git a/types/decimal_test.go b/types/decimal_test.go index b9f9c0892616..6ec6cf18a480 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,7 +1,6 @@ package types import ( - "fmt" "math/big" "testing" @@ -158,7 +157,6 @@ func TestArithmetic(t *testing.T) { } for tcIndex, tc := range tests { - fmt.Printf("debug tcIndex: %v\n", tcIndex) resAdd := tc.d1.Add(tc.d2) resSub := tc.d1.Sub(tc.d2) resMul := tc.d1.Mul(tc.d2) @@ -223,9 +221,9 @@ var cdc = wire.NewCodec() func TestZeroDeserializationJSON(t *testing.T) { d := Dec{new(big.Int)} - err := cdc.UnmarshalJSON([]byte("0"), &d) + err := cdc.UnmarshalJSON([]byte(`"0"`), &d) require.Nil(t, err) - err = cdc.UnmarshalJSON([]byte("{}"), &d) + err = cdc.UnmarshalJSON([]byte(`"{}"`), &d) require.NotNil(t, err) } @@ -234,7 +232,6 @@ func TestSerializationText(t *testing.T) { bz, err := d.MarshalText() require.NoError(t, err) - fmt.Printf("debug bz: %s\n", bz) d2 := Dec{new(big.Int)} err = d2.UnmarshalText(bz) From 40d49bf0d5cdfdb715447a2803992b1c9f51aaae Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 1 Aug 2018 01:09:56 -0400 Subject: [PATCH 27/50] lint --- types/decimal.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/decimal.go b/types/decimal.go index c52d20d215a6..2fdfe3116d81 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -12,7 +12,7 @@ import ( // NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int type Dec struct { - *big.Int `"json:Int"` + *big.Int `json:"int"` } // number of decimal places @@ -172,6 +172,7 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // |_____: / | $$$ | // |________| +// nolint - go-cyclo // chop of n digits, and banker round the digits being chopped off // Examples: // BankerRoundChop(1005, 1) = 100 From 89dd6e436b4caeea5224b8f4f4de2a849df9a23a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 1 Aug 2018 01:27:06 -0400 Subject: [PATCH 28/50] document update --- docs/spec/governance/state.md | 4 ++-- docs/spec/provisioning/overview.md | 4 ++-- docs/spec/staking/end_block.md | 2 +- docs/spec/staking/transactions.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/spec/governance/state.md b/docs/spec/governance/state.md index 9c848bb0c479..728ded37130c 100644 --- a/docs/spec/governance/state.md +++ b/docs/spec/governance/state.md @@ -25,8 +25,8 @@ type VotingProcedure struct { ```go type TallyingProcedure struct { - Threshold rational.Rational // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 - Veto rational.Rational // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 + Threshold sdk.Dec // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 + Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 GovernancePenalty sdk.Dec // Penalty if validator does not vote GracePeriod int64 // If validator entered validator set in this period of blocks before vote ended, governance penalty does not apply } diff --git a/docs/spec/provisioning/overview.md b/docs/spec/provisioning/overview.md index 958243658ed6..b18559679960 100644 --- a/docs/spec/provisioning/overview.md +++ b/docs/spec/provisioning/overview.md @@ -113,8 +113,8 @@ occur on an epoch basis. ```golang type powerChange struct { height int64 // block height at change - power rational.Dec // total power at change - prevpower rational.Dec // total power at previous height-1 + power sdk.Dec // total power at change + prevpower sdk.Dec // total power at previous height-1 feesin coins.Coin // fees in at block height prevFeePool coins.Coin // total fees in at previous block height } diff --git a/docs/spec/staking/end_block.md b/docs/spec/staking/end_block.md index 04cc98e1a638..80002779d3da 100644 --- a/docs/spec/staking/end_block.md +++ b/docs/spec/staking/end_block.md @@ -42,7 +42,7 @@ processProvisions(): setPool(pool) -nextInflation(hrsPerYr rational.Dec): +nextInflation(hrsPerYr sdk.Dec): if pool.TotalSupply > 0 bondedRatio = pool.BondedPool / pool.TotalSupply else diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md index 5fd574de6af4..f1d2a75d2cd0 100644 --- a/docs/spec/staking/transactions.md +++ b/docs/spec/staking/transactions.md @@ -19,7 +19,7 @@ Other notes: - `sender` denotes the address of the sender of the transaction - `getXxx`, `setXxx`, and `removeXxx` functions are used to retrieve and modify objects from the store - - `sdk.Dec` refers to a rational numeric type specified by the SDK. + - `sdk.Dec` refers to a decimal type specified by the SDK. ### TxCreateValidator From e5f2faf7448e0b0a978e3b25b54ae29ca6fdb257 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 2 Aug 2018 20:47:45 -0400 Subject: [PATCH 29/50] fix lcd test --- client/lcd/lcd_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index ee9ff96f9b56..564702a42753 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -374,6 +374,7 @@ func TestValidatorsQuery(t *testing.T) { require.True(t, foundVal, "pkBech %v, owner %v", pkBech, validators[0].Owner) } +//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxx func TestBonding(t *testing.T) { name, password, denom := "test", "1234567890", "steak" addr, seed := CreateAddr(t, "test", password, GetKeyBase(t)) @@ -398,7 +399,7 @@ func TestBonding(t *testing.T) { // query validator bond := getDelegation(t, port, addr, validator1Owner) - require.Equal(t, "60/1", bond.Shares.String()) + require.Equal(t, "60.0000000000", bond.Shares.String()) ////////////////////// // testing unbonding @@ -409,7 +410,7 @@ func TestBonding(t *testing.T) { // query validator bond = getDelegation(t, port, addr, validator1Owner) - require.Equal(t, "30/1", bond.Shares.String()) + require.Equal(t, "30.0000000000", bond.Shares.String()) // check if tx was committed require.Equal(t, uint32(0), resultTx.CheckTx.Code) From 09e7e2572708547b448ac291f528ac87aff3a7c9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 2 Aug 2018 20:54:16 -0400 Subject: [PATCH 30/50] cli test fix --- cmd/gaia/cli_test/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index c8fb108922e0..dd8b244dfc66 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -149,7 +149,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) */ validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) - require.Equal(t, "1/1", validator.Tokens.String()) + require.Equal(t, "1.0000000000", validator.Tokens.String()) } func TestGaiaCLISubmitProposal(t *testing.T) { From 196fccec4e77bdc7cba82a62cbdd16036c726d71 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 3 Aug 2018 14:52:52 -0400 Subject: [PATCH 31/50] mostly undo Dece -> Rate --- client/lcd/lcd_test.go | 1 - docs/resources/whitepaper.md | 2 +- docs/sdk/core/app3.md | 2 +- docs/spec/ibc/appendices.md | 4 ++-- docs/spec/ibc/overview.md | 2 +- docs/spec/provisioning/overview.md | 6 +++--- docs/spec/staking/end_block.md | 6 +++--- docs/spec/staking/state.md | 6 +++--- types/decimal.go | 6 +++--- x/ibc/mapper.go | 2 +- x/stake/handler_test.go | 8 ++++---- x/stake/keeper/test_common.go | 2 +- x/stake/types/inflation_test.go | 18 +++++++++--------- x/stake/types/params.go | 4 ++-- x/stake/types/pool.go | 10 +++++----- x/stake/types/validator.go | 30 +++++++++++++++--------------- x/stake/types/validator_test.go | 14 +++++++------- 17 files changed, 61 insertions(+), 62 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 564702a42753..b21f483dacf6 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -374,7 +374,6 @@ func TestValidatorsQuery(t *testing.T) { require.True(t, foundVal, "pkBech %v, owner %v", pkBech, validators[0].Owner) } -//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxx func TestBonding(t *testing.T) { name, password, denom := "test", "1234567890", "steak" addr, seed := CreateAddr(t, "test", password, GetKeyBase(t)) diff --git a/docs/resources/whitepaper.md b/docs/resources/whitepaper.md index 3b7b08d23ebb..62707c08040f 100644 --- a/docs/resources/whitepaper.md +++ b/docs/resources/whitepaper.md @@ -821,7 +821,7 @@ in the case of a successful double-spend attack. Building on an approach pioneered by Ripple, Stellar [\[13\]][13] refined a model of Federated Byzantine Agreement wherein the processes participating in -consensus do not constitute a fixed and globally known set. Decher, each +consensus do not constitute a fixed and globally known set. Rather, each process node curates one or more "quorum slices", each constituting a set of trusted processes. A "quorum" in Stellar is defined to be a set of nodes that contain at least one quorum slice for each node in the set, such that agreement diff --git a/docs/sdk/core/app3.md b/docs/sdk/core/app3.md index c933315589a4..66bb05521b78 100644 --- a/docs/sdk/core/app3.md +++ b/docs/sdk/core/app3.md @@ -312,7 +312,7 @@ accounts. We use this `Keeper` paradigm extensively in the SDK as the way to define what kind of functionality each module gets access to. In particular, we try to follow the *principle of least authority*. -Decher than providing full blown access to the `KVStore` or the `AccountMapper`, +Rather than providing full blown access to the `KVStore` or the `AccountMapper`, we restrict access to a small number of functions that do very specific things. ## App3 diff --git a/docs/spec/ibc/appendices.md b/docs/spec/ibc/appendices.md index 933ba73128d4..751924f4692d 100644 --- a/docs/spec/ibc/appendices.md +++ b/docs/spec/ibc/appendices.md @@ -31,11 +31,11 @@ See [binary format as protobuf specification](./protobuf/queue.proto) A Merkle tree (or a trie) generates a single hash that can be used to prove any element of the tree. In order to generate this hash, we first hash the leaf nodes, then hash multiple leaf nodes together to get the hash of an inner node (two or more, based on degree k of the k-ary tree), and repeat for each level of the tree until we end up with one root hash. With a known root hash (which is included in the block headers), the existence of a particular key/value in the tree can be proven by tracing the path to the value and revealing the (k-1) hashes for the paths not taken on each level ([[10](./references.md#10)]). -There are a number of different implementations of this basic idea, using different hash functions, as well as prefixes to prevent second preimage attacks (differentiating leaf nodes from inner nodes). Decher than force all chains that wish to participate in IBC to use the same data store, we provide a data structure that can represent Merkle proofs from a variety of data stores, and provide for chaining proofs to allow for subtrees. While searching for a solution, we did find the chainpoint proof format[[11](./references.md#11)], which inspired this design significantly, but didn't (yet) offer the flexibility we needed. +There are a number of different implementations of this basic idea, using different hash functions, as well as prefixes to prevent second preimage attacks (differentiating leaf nodes from inner nodes). Rather than force all chains that wish to participate in IBC to use the same data store, we provide a data structure that can represent Merkle proofs from a variety of data stores, and provide for chaining proofs to allow for subtrees. While searching for a solution, we did find the chainpoint proof format[[11](./references.md#11)], which inspired this design significantly, but didn't (yet) offer the flexibility we needed. We generalize the left/right idiom to the concatenation a (possibly empty) fixed prefix, the (just calculated) last hash, and a (possibly empty) fixed suffix. We must only define two fields on each level and can represent any type, even a 16-ary Patricia tree, with this structure. One must only translate from the store's native proof to this format, and it can be verified by any chain, providing compatibility with arbitrary data stores. -The proof format also allows for chaining of trees, combining multiple Merkle stores into a "multi-store". Many applications (such as the EVM) define a data store with a large proof size for internal use. Decher than force them to change the store (impossible), or live with huge proofs (inefficient), we provide the possibility to express Merkle proofs connecting multiple subtrees. Thus, one could have one subtree for data, and a second for IBC. Each tree produces its own Merkle root, and these are then hashed together to produce the root hash that is stored in the block header. +The proof format also allows for chaining of trees, combining multiple Merkle stores into a "multi-store". Many applications (such as the EVM) define a data store with a large proof size for internal use. Rather than force them to change the store (impossible), or live with huge proofs (inefficient), we provide the possibility to express Merkle proofs connecting multiple subtrees. Thus, one could have one subtree for data, and a second for IBC. Each tree produces its own Merkle root, and these are then hashed together to produce the root hash that is stored in the block header. A valid Merkle proof for IBC must either consist of a proof of one tree, and prepend `ibc` to all key names as defined above, or use a subtree named `ibc` in the first section, and store the key names as above in the second tree. diff --git a/docs/spec/ibc/overview.md b/docs/spec/ibc/overview.md index e59559deac57..344f69c7d721 100644 --- a/docs/spec/ibc/overview.md +++ b/docs/spec/ibc/overview.md @@ -8,7 +8,7 @@ The IBC protocol creates a mechanism by which two replicated fault-tolerant stat The IBC protocol assumes that multiple applications are running on their own blockchain with their own state and own logic. Communication is achieved over an ordered message queue primitive, allowing the creation of complex inter-chain processes without trusted third parties. -The message packets are not signed by one psuedonymous account, or even multiple, as in multi-signature sidechain implementations. Decher, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains. +The message packets are not signed by one psuedonymous account, or even multiple, as in multi-signature sidechain implementations. Rather, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains. In this paper, we define a process of posting block headers and Merkle tree proofs to enable secure verification of individual packets. We then describe how to combine these packets into a messaging queue to guarantee ordered delivery. We then explain how to handle packet receipts (response/error) on the source chain, which enables the creation of asynchronous RPC-like protocols on top of IBC. Finally, we detail some optimizations and how to handle Byzantine blockchains. diff --git a/docs/spec/provisioning/overview.md b/docs/spec/provisioning/overview.md index b18559679960..bb011bdaf795 100644 --- a/docs/spec/provisioning/overview.md +++ b/docs/spec/provisioning/overview.md @@ -205,13 +205,13 @@ defined to be 13% per year, however the annual inflation is capped as between 7% and 20%. ```go -inflationDeceChange(0) = 0 +inflationRateChange(0) = 0 Inflation(0) = 0.07 bondedRatio = Pool.BondedTokens / Pool.TotalSupplyTokens -AnnualInflationDeceChange = (1 - bondedRatio / 0.67) * 0.13 +AnnualInflationRateChange = (1 - bondedRatio / 0.67) * 0.13 -annualInflation += AnnualInflationDeceChange +annualInflation += AnnualInflationRateChange if annualInflation > 0.20 then Inflation = 0.20 if annualInflation < 0.07 then Inflation = 0.07 diff --git a/docs/spec/staking/end_block.md b/docs/spec/staking/end_block.md index 80002779d3da..6114b193802e 100644 --- a/docs/spec/staking/end_block.md +++ b/docs/spec/staking/end_block.md @@ -48,10 +48,10 @@ nextInflation(hrsPerYr sdk.Dec): else bondedRation = 0 - inflationDeceChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationDeceChange - inflationDeceChange = inflationDeceChangePerYear / hrsPerYr + inflationRateChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationRateChange + inflationRateChange = inflationRateChangePerYear / hrsPerYr - inflation = pool.Inflation + inflationDeceChange + inflation = pool.Inflation + inflationRateChange if inflation > params.InflationMax then inflation = params.InflationMax if inflation < params.InflationMin then inflation = params.InflationMin diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 143a6da90aa8..a9134325c85d 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -29,7 +29,7 @@ overall functioning of the stake module. ```golang type Params struct { - InflationDeceChange sdk.Dec // maximum annual change in inflation rate + InflationRateChange sdk.Dec // maximum annual change in inflation rate InflationMax sdk.Dec // maximum inflation rate InflationMin sdk.Dec // minimum inflation rate GoalBonded sdk.Dec // Goal of percent bonded atoms @@ -94,9 +94,9 @@ type Validator struct { } type CommissionInfo struct { - Dece sdk.Dec // the commission rate of fees charged to any delegators + Rate sdk.Dec // the commission rate of fees charged to any delegators Max sdk.Dec // maximum commission rate which this validator can ever charge - ChangeDece sdk.Dec // maximum daily increase of the validator commission + ChangeRate sdk.Dec // maximum daily increase of the validator commission ChangeToday sdk.Dec // commission rate change today, reset each day (UTC time) LastChange int64 // unix timestamp of last commission change } diff --git a/types/decimal.go b/types/decimal.go index 2fdfe3116d81..a869daac5c49 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -37,7 +37,7 @@ func precisionMultiplier(prec int64) *big.Int { } // create a new Dec from integer assuming whole numbers -// CONTRACT: prec !> Precision +// CONTRACT: prec <= Precision func NewDec(i, prec int64) Dec { return Dec{ new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), @@ -113,9 +113,9 @@ func NewDecFromStr(str string) (d Dec, err Error) { func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than -func (d Dec) GTE(d2 Dec) bool { return !d.LT(d2) } // greater than or equal +func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than -func (d Dec) LTE(d2 Dec) bool { return !d.GT(d2) } // less than or equal +func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to zero func (d Dec) Add(d2 Dec) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction diff --git a/x/ibc/mapper.go b/x/ibc/mapper.go index 836c347a868d..25169961708d 100644 --- a/x/ibc/mapper.go +++ b/x/ibc/mapper.go @@ -14,7 +14,7 @@ type Mapper struct { codespace sdk.CodespaceType } -// XXX: The Mapper should not take a CoinKeeper. Decher have the CoinKeeper +// XXX: The Mapper should not take a CoinKeeper. Rather have the CoinKeeper // take an Mapper. func NewMapper(cdc *wire.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Mapper { // XXX: How are these codecs supposed to work? diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index d26528f92b68..e4e1c0e7c42e 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -219,8 +219,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.Equal(t, bondAmount, bond.Shares.RoundInt64()) pool := keeper.GetPool(ctx) - exDece := validator.DelegatorShareExDece() - require.True(t, exDece.Equal(sdk.OneDec()), "expected exDece 1 got %v", exDece) + exRate := validator.DelegatorShareExRate() + require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v", exRate) require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64()) // just send the same msgbond multiple times @@ -238,8 +238,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.True(t, found) - exDece := validator.DelegatorShareExDece() - require.True(t, exDece.Equal(sdk.OneDec()), "expected exDece 1 got %v, i = %v", exDece, i) + exRate := validator.DelegatorShareExRate() + require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v, i = %v", exRate, i) expBond := int64(i+1) * bondAmount expDelegatorShares := int64(i+2) * bondAmount // (1 self delegation) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 9769dd073a26..f7ef32cf4d41 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -77,7 +77,7 @@ func MakeTestCodec() *wire.Codec { // default params without inflation func ParamsNoInflation() types.Params { return types.Params{ - InflationDeceChange: sdk.ZeroDec(), + InflationRateChange: sdk.ZeroDec(), InflationMax: sdk.ZeroDec(), InflationMin: sdk.ZeroDec(), GoalBonded: sdk.NewDec(67, 2), diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index 00787ecfcbd9..fea05f9af3fa 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -18,24 +18,24 @@ func TestGetInflation(t *testing.T) { // Governing Mechanism: // BondedRatio = BondedTokens / TotalSupply - // inflationDeceChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationDeceChange + // inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange tests := []struct { name string setBondedTokens, setLooseTokens, setInflation, expectedChange sdk.Dec }{ - // with 0% bonded atom supply the inflation should increase by InflationDeceChange - {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationDeceChange.Quo(hrsPerYrDec)}, + // with 0% bonded atom supply the inflation should increase by InflationRateChange + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), - sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec)}, + sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // 50% bonded, starting at 10% inflation and being increased {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 2), - sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationDeceChange).Quo(hrsPerYrDec)}, + sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // test 7% minimum stop (testing with 100% bonded) {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), sdk.ZeroDec()}, @@ -112,11 +112,11 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation inflationChange := updatedInflation.Sub(previousInflation) switch { - //BELOW 67% - Dece of change positive and increasing, while we are between 7% <= and < 20% inflation + //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)): require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) - //BELOW 67% - Dece of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio + //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(20, 2)): if previousInflation.Equal(sdk.NewDec(20, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) @@ -126,11 +126,11 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) } - //ABOVE 67% - Dece of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% + //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)) && updatedInflation.GT(sdk.NewDec(7, 2)): require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) - //ABOVE 67% - Dece of change should be 0 while inflation continually stays at 7%. + //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(7, 2)): if previousInflation.Equal(sdk.NewDec(7, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) diff --git a/x/stake/types/params.go b/x/stake/types/params.go index eb2c91e2b0a8..979f1aa99b16 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -12,7 +12,7 @@ const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 // Params defines the high level settings for staking type Params struct { - InflationDeceChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate + InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms @@ -33,7 +33,7 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationDeceChange: sdk.NewDec(13, 2), + InflationRateChange: sdk.NewDec(13, 2), InflationMax: sdk.NewDec(20, 2), InflationMin: sdk.NewDec(7, 2), GoalBonded: sdk.NewDec(67, 2), diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 7d87eb57eacf..95e2141a41cc 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -104,15 +104,15 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { // defined to be 13% per year, however the annual inflation is capped as between // 7% and 20%. - // (1 - bondedRatio/GoalBonded) * InflationDeceChange - inflationDeceChangePerYear := sdk.OneDec(). + // (1 - bondedRatio/GoalBonded) * InflationRateChange + inflationRateChangePerYear := sdk.OneDec(). Sub(p.BondedRatio(). Quo(params.GoalBonded)). - Mul(params.InflationDeceChange) - inflationDeceChange := inflationDeceChangePerYear.Quo(hrsPerYrDec) + Mul(params.InflationRateChange) + inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrDec) // increase the new annual inflation for this next cycle - inflation = p.Inflation.Add(inflationDeceChange) + inflation = p.Inflation.Add(inflationRateChange) if inflation.GT(params.InflationMax) { inflation = params.InflationMax } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 02b676e06c4e..ae55f930055a 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -36,7 +36,7 @@ type Validator struct { Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeDece sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related @@ -58,7 +58,7 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri ProposerRewardPool: sdk.Coins{}, Commission: sdk.ZeroDec(), CommissionMax: sdk.ZeroDec(), - CommissionChangeDece: sdk.ZeroDec(), + CommissionChangeRate: sdk.ZeroDec(), CommissionChangeToday: sdk.ZeroDec(), LastBondedTokens: sdk.ZeroDec(), } @@ -77,7 +77,7 @@ type validatorValue struct { ProposerRewardPool sdk.Coins Commission sdk.Dec CommissionMax sdk.Dec - CommissionChangeDece sdk.Dec + CommissionChangeRate sdk.Dec CommissionChangeToday sdk.Dec LastBondedTokens sdk.Dec } @@ -96,7 +96,7 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { ProposerRewardPool: validator.ProposerRewardPool, Commission: validator.Commission, CommissionMax: validator.CommissionMax, - CommissionChangeDece: validator.CommissionChangeDece, + CommissionChangeRate: validator.CommissionChangeRate, CommissionChangeToday: validator.CommissionChangeToday, LastBondedTokens: validator.LastBondedTokens, } @@ -139,7 +139,7 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Val ProposerRewardPool: storeValue.ProposerRewardPool, Commission: storeValue.Commission, CommissionMax: storeValue.CommissionMax, - CommissionChangeDece: storeValue.CommissionChangeDece, + CommissionChangeRate: storeValue.CommissionChangeRate, CommissionChangeToday: storeValue.CommissionChangeToday, LastBondedTokens: storeValue.LastBondedTokens, }, nil @@ -165,8 +165,8 @@ func (v Validator) HumanReadableString() (string, error) { resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) resp += fmt.Sprintf("Proposer Reward Pool: %s\n", v.ProposerRewardPool.String()) resp += fmt.Sprintf("Commission: %s\n", v.Commission.String()) - resp += fmt.Sprintf("Max Commission Dece: %s\n", v.CommissionMax.String()) - resp += fmt.Sprintf("Commission Change Dece: %s\n", v.CommissionChangeDece.String()) + resp += fmt.Sprintf("Max Commission Rate: %s\n", v.CommissionMax.String()) + resp += fmt.Sprintf("Commission Change Rate: %s\n", v.CommissionChangeRate.String()) resp += fmt.Sprintf("Commission Change Today: %s\n", v.CommissionChangeToday.String()) resp += fmt.Sprintf("Previous Bonded Tokens: %s\n", v.LastBondedTokens.String()) @@ -192,7 +192,7 @@ type BechValidator struct { Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeDece sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related @@ -222,7 +222,7 @@ func (v Validator) Bech32Validator() (BechValidator, error) { Commission: v.Commission, CommissionMax: v.CommissionMax, - CommissionChangeDece: v.CommissionChangeDece, + CommissionChangeRate: v.CommissionChangeRate, CommissionChangeToday: v.CommissionChangeToday, LastBondedTokens: v.LastBondedTokens, @@ -243,7 +243,7 @@ func (v Validator) Equal(c2 Validator) bool { v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && v.Commission.Equal(c2.Commission) && v.CommissionMax.Equal(c2.CommissionMax) && - v.CommissionChangeDece.Equal(c2.CommissionChangeDece) && + v.CommissionChangeRate.Equal(c2.CommissionChangeRate) && v.CommissionChangeToday.Equal(c2.CommissionChangeToday) && v.LastBondedTokens.Equal(c2.LastBondedTokens) } @@ -379,7 +379,7 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Dec) (Validator, Pool) { func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Dec) { // bondedShare/delegatedShare - exDece := v.DelegatorShareExDece() + exRate := v.DelegatorShareExRate() amountDec := sdk.NewDec(amount, 0) if v.Status == sdk.Bonded { @@ -387,7 +387,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s } v.Tokens = v.Tokens.Add(amountDec) - issuedShares := amountDec.Quo(exDece) + issuedShares := amountDec.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedShares @@ -395,7 +395,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // RemoveDelShares removes delegator shares from a validator. func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Pool, sdk.Dec) { - issuedTokens := v.DelegatorShareExDece().Mul(delShares) + issuedTokens := v.DelegatorShareExRate().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) @@ -406,9 +406,9 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Poo return v, pool, issuedTokens } -// DelegatorShareExDece gets the exchange rate of tokens over delegator shares. +// DelegatorShareExRate gets the exchange rate of tokens over delegator shares. // UNITS: tokens/delegator-shares -func (v Validator) DelegatorShareExDece() sdk.Dec { +func (v Validator) DelegatorShareExRate() sdk.Dec { if v.DelegatorShares.IsZero() { return sdk.OneDec() } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 613b658efff8..690628f5b348 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -110,7 +110,7 @@ func TestAddTokensValidatorBonded(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) @@ -123,7 +123,7 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) @@ -137,7 +137,7 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExDece()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) @@ -156,7 +156,7 @@ func TestRemoveDelShares(t *testing.T) { poolA := InitialPool() poolA.LooseTokens = sdk.NewDec(10, 0) poolA.BondedTokens = valA.BondedTokens() - require.Equal(t, valA.DelegatorShareExDece(), sdk.OneDec()) + require.Equal(t, valA.DelegatorShareExRate(), sdk.OneDec()) // Remove delegator shares valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10, 0)) @@ -245,9 +245,9 @@ func TestPossibleOverflow(t *testing.T) { newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - require.False(t, newValidator.DelegatorShareExDece().LT(sdk.ZeroDec()), - "Applying operation \"%s\" resulted in negative DelegatorShareExDece(): %v", - msg, newValidator.DelegatorShareExDece()) + require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroDec()), + "Applying operation \"%s\" resulted in negative DelegatorShareExRate(): %v", + msg, newValidator.DelegatorShareExRate()) } func TestHumanReadableString(t *testing.T) { From f43bf90388de01b435e83077c5bceaf0b427bf33 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 3 Aug 2018 15:54:07 -0400 Subject: [PATCH 32/50] val comments --- types/decimal.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index a869daac5c49..5170b4c014d0 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -18,8 +18,14 @@ type Dec struct { // number of decimal places const Precision = 10 +var ( + precisionExpReuse = big.NewInt(Precision) + ten = big.NewInt(10) + precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) +) + func precisionInt() *big.Int { - return new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + return precisionReuse.Exp(ten, precisionExpReuse, nil) } // nolint - common values @@ -124,13 +130,19 @@ func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) chopped := BankerRoundChop(mul, Precision) + + if chopped.BitLen() > 255 { + panic("Int overflow") + } return Dec{chopped} } // quotient func (d Dec) Quo(d2 Dec) Dec { - mul := new(big.Int).Mul(new(big.Int).Mul( // multiple Precision twice - d.Int, precisionInt()), precisionInt()) + + // multiply precision twice + mul := new(big.Int).Mul(d.Int, precisionInt()) + mul.Mul(mul, precisionInt()) quo := new(big.Int).Quo(mul, d2.Int) chopped := BankerRoundChop(quo, Precision) @@ -236,6 +248,9 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { + if !d.Int.IsInt64() { + panic("Int64() out of bound") + } return BankerRoundChop(d.Int, Precision).Int64() } From 16bc41ea4c55c4bc1dae8b08c0d69dcd35a71e17 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sat, 4 Aug 2018 09:27:42 -0700 Subject: [PATCH 33/50] Efficiency improvements This now caches all of the precision multipliers (as they were all used in non-mutative functions), and caches the precisionInt calculation. (Now it just copies the already calculated value) --- types/decimal.go | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 5170b4c014d0..899369687d76 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -19,21 +19,30 @@ type Dec struct { const Precision = 10 var ( - precisionExpReuse = big.NewInt(Precision) - ten = big.NewInt(10) - precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + precisionExpReuse = big.NewInt(Precision) + ten = big.NewInt(10) + precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + precisionMultipliers []*big.Int ) +// Set precision multipliers +func init() { + precisionMultipliers = make([]*big.Int, Precision+1) + for i := 0; i <= Precision; i++ { + precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) + } +} + func precisionInt() *big.Int { - return precisionReuse.Exp(ten, precisionExpReuse, nil) + return new(big.Int).Set(precisionReuse) } // nolint - common values func ZeroDec() Dec { return Dec{big.NewInt(0)} } func OneDec() Dec { return Dec{precisionInt()} } -// get the precision multiplier -func precisionMultiplier(prec int64) *big.Int { +// calculate the precision multiplier +func calcPrecisionMultiplier(prec int64) *big.Int { if prec > Precision { panic("too much precision") } @@ -42,6 +51,14 @@ func precisionMultiplier(prec int64) *big.Int { return multiplier } +// get the precision multiplier. Do not mutate result. +func precisionMultiplier(prec int64) *big.Int { + if prec > Precision { + panic("too much precision") + } + return precisionMultipliers[prec] +} + // create a new Dec from integer assuming whole numbers // CONTRACT: prec <= Precision func NewDec(i, prec int64) Dec { @@ -141,8 +158,8 @@ func (d Dec) Mul(d2 Dec) Dec { func (d Dec) Quo(d2 Dec) Dec { // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionInt()) - mul.Mul(mul, precisionInt()) + mul := new(big.Int).Mul(d.Int, precisionReuse) + mul.Mul(mul, precisionReuse) quo := new(big.Int).Quo(mul, d2.Int) chopped := BankerRoundChop(quo, Precision) From 9c954ce4ac05151f9d7fb6c879113af8ca35f2c2 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sat, 4 Aug 2018 09:32:22 -0700 Subject: [PATCH 34/50] Cache another precisionInt() call. --- types/decimal.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 899369687d76..8d7d6dd897fc 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -218,8 +218,8 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { } // get the trucated quotient and remainder - quo, rem, prec := big.NewInt(0), big.NewInt(0), precisionInt() - quo, rem = quo.QuoRem(d, prec, rem) + quo, rem := big.NewInt(0), big.NewInt(0) + quo, rem = quo.QuoRem(d, precisionReuse, rem) if rem.Sign() == 0 { // remainder is zero return quo From 985947614f835b726e8031a73be707752d5dedd1 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sun, 5 Aug 2018 12:29:56 -0500 Subject: [PATCH 35/50] Improve banker rounding efficiency --- types/decimal.go | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 8d7d6dd897fc..f315ed0730bd 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -23,6 +23,8 @@ var ( ten = big.NewInt(10) precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) precisionMultipliers []*big.Int + zeroInt = big.NewInt(0) + tenInt = big.NewInt(10) ) // Set precision multipliers @@ -38,7 +40,7 @@ func precisionInt() *big.Int { } // nolint - common values -func ZeroDec() Dec { return Dec{big.NewInt(0)} } +func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} } func OneDec() Dec { return Dec{precisionInt()} } // calculate the precision multiplier @@ -47,7 +49,7 @@ func calcPrecisionMultiplier(prec int64) *big.Int { panic("too much precision") } zerosToAdd := Precision - prec - multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) + multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) return multiplier } @@ -68,7 +70,7 @@ func NewDec(i, prec int64) Dec { } // create a new Dec from big integer assuming whole numbers -// CONTRACT: prec !> Precision +// CONTRACT: prec <= Precision func NewDecFromBigInt(i *big.Int, prec int64) Dec { return Dec{ new(big.Int).Mul(i, precisionMultiplier(prec)), @@ -76,7 +78,7 @@ func NewDecFromBigInt(i *big.Int, prec int64) Dec { } // create a new Dec from big integer assuming whole numbers -// CONTRACT: prec !> Precision +// CONTRACT: prec <= Precision func NewDecFromInt(i Int, prec int64) Dec { return Dec{ new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), @@ -209,11 +211,12 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // BankerRoundChop(1500, 3) = 2 func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { + negated := (d.Sign() == -1) // remove the negative and add it back when returning - if d.Sign() == -1 { + if negated { d = new(big.Int).Neg(d) defer func() { - chopped = new(big.Int).Neg(chopped) + chopped.Neg(chopped) }() } @@ -242,23 +245,15 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { chopped = quo return case 1: - chopped = new(big.Int).Add(quo, big.NewInt(1)) + chopped = quo.Add(quo, big.NewInt(1)) return default: // bankers rounding must take place - str := quo.String() - finalDig, err := strconv.Atoi(string(str[len(str)-1])) - if err != nil { - panic(err) - } - // always round to an even number - if finalDig == 0 || finalDig == 2 || finalDig == 4 || - finalDig == 6 || finalDig == 8 { - + if quo.Bit(0) == 0 { chopped = quo return } - chopped = new(big.Int).Add(quo, big.NewInt(1)) + chopped = quo.Add(quo, big.NewInt(1)) return } } From 348cb1d8ba3bdd3412ef2fb40e9fbf7db2cb6ed9 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sun, 5 Aug 2018 12:39:20 -0500 Subject: [PATCH 36/50] remove defer, make negation in-place. --- types/decimal.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index f315ed0730bd..e8307c6e0c8d 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -210,14 +210,14 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // BankerRoundChop(1015, 1) = 102 // BankerRoundChop(1500, 3) = 2 func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { - - negated := (d.Sign() == -1) // remove the negative and add it back when returning - if negated { - d = new(big.Int).Neg(d) - defer func() { - chopped.Neg(chopped) - }() + if d.Sign() == -1 { + // make d positive, compute chopped value, and then un-mutate d + d = d.Neg(d) + chopped = BankerRoundChop(d, n) + d = d.Neg(d) + chopped.Neg(chopped) + return chopped } // get the trucated quotient and remainder From e26a87dc38d9751ccc13435dde53296f197b9c4a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Aug 2018 22:59:36 -0400 Subject: [PATCH 37/50] chris val comments --- types/decimal.go | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index e8307c6e0c8d..7dee18ea5003 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -16,7 +16,13 @@ type Dec struct { } // number of decimal places -const Precision = 10 +const ( + Precision = 10 + + // bytes required to represent the above precision + // ceil(log2(9999999999)) + DecimalPrecisionBytes = 34 +) var ( precisionExpReuse = big.NewInt(Precision) @@ -137,20 +143,38 @@ func NewDecFromStr(str string) (d Dec, err Error) { //nolint func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } -func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than -func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than -func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to zero -func (d Dec) Add(d2 Dec) Dec { return Dec{new(big.Int).Add(d.Int, d2.Int)} } // addition -func (d Dec) Sub(d2 Dec) Dec { return Dec{new(big.Int).Sub(d.Int, d2.Int)} } // subtraction +func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than +func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal +func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than +func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to zero + +// addition +func (d Dec) Add(d2 Dec) Dec { + res := new(big.Int).Add(d.Int, d2.Int) + + if res.BitLen() > 255+DecimalPrecisionBytes { + panic("Int overflow") + } + return Dec{res} +} + +// subtraction +func (d Dec) Sub(d2 Dec) Dec { + res := new(big.Int).Sub(d.Int, d2.Int) + + if res.BitLen() > 255+DecimalPrecisionBytes { + panic("Int overflow") + } + return Dec{res} +} // multiplication func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) chopped := BankerRoundChop(mul, Precision) - if chopped.BitLen() > 255 { + if chopped.BitLen() > 255+DecimalPrecisionBytes { panic("Int overflow") } return Dec{chopped} @@ -210,6 +234,7 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // BankerRoundChop(1015, 1) = 102 // BankerRoundChop(1500, 3) = 2 func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { + // remove the negative and add it back when returning if d.Sign() == -1 { // make d positive, compute chopped value, and then un-mutate d @@ -260,10 +285,11 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - if !d.Int.IsInt64() { + chopped := BankerRoundChop(d.Int, Precision) + if !chopped.IsInt64() { panic("Int64() out of bound") } - return BankerRoundChop(d.Int, Precision).Int64() + return chopped.Int64() } // RoundInt round the decimal using bankers rounding From 1e5780731bea6353ce3fe61c104cbed9cc5cd647 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Aug 2018 23:25:38 -0400 Subject: [PATCH 38/50] bez comments --- types/decimal.go | 45 ++++++------- types/decimal_test.go | 5 ++ x/fee_distribution/keeper.go | 91 ------------------------- x/fee_distribution/keeper_test.go | 31 --------- x/fee_distribution/movement.go | 72 -------------------- x/fee_distribution/types.go | 107 ------------------------------ x/slashing/test_common.go | 7 +- 7 files changed, 29 insertions(+), 329 deletions(-) delete mode 100644 x/fee_distribution/keeper.go delete mode 100644 x/fee_distribution/keeper_test.go delete mode 100644 x/fee_distribution/movement.go delete mode 100644 x/fee_distribution/types.go diff --git a/types/decimal.go b/types/decimal.go index 7dee18ea5003..f58f303c9bb6 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -6,7 +6,6 @@ import ( "math/big" "strconv" "strings" - "testing" ) // NOTE: never use new(Dec) or else we will panic unmarshalling into the @@ -25,8 +24,6 @@ const ( ) var ( - precisionExpReuse = big.NewInt(Precision) - ten = big.NewInt(10) precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) precisionMultipliers []*big.Int zeroInt = big.NewInt(0) @@ -52,7 +49,7 @@ func OneDec() Dec { return Dec{precisionInt()} } // calculate the precision multiplier func calcPrecisionMultiplier(prec int64) *big.Int { if prec > Precision { - panic("too much precision") + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) } zerosToAdd := Precision - prec multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) @@ -62,7 +59,7 @@ func calcPrecisionMultiplier(prec int64) *big.Int { // get the precision multiplier. Do not mutate result. func precisionMultiplier(prec int64) *big.Int { if prec > Precision { - panic("too much precision") + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) } return precisionMultipliers[prec] } @@ -91,7 +88,17 @@ func NewDecFromInt(i Int, prec int64) Dec { } } -// create a decimal from a decimal string (ex. "1234.5678") +// create a decimal from an input decimal string. +// valid must come in the form: +// (-) whole integers (.) decimal integers +// examples of acceptable input include: +// -123.456 +// 456.7890 +// 345 +// -456789 +// +// NOTE an error will return if more decimal places +// are provided in the string than the constant Precision func NewDecFromStr(str string) (d Dec, err Error) { if len(str) == 0 { return d, ErrUnknownRequest("decimal string is empty") @@ -172,7 +179,7 @@ func (d Dec) Sub(d2 Dec) Dec { // multiplication func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) - chopped := BankerRoundChop(mul, Precision) + chopped := BankerRoundChopPrecision(mul) if chopped.BitLen() > 255+DecimalPrecisionBytes { panic("Int overflow") @@ -188,7 +195,7 @@ func (d Dec) Quo(d2 Dec) Dec { mul.Mul(mul, precisionReuse) quo := new(big.Int).Quo(mul, d2.Int) - chopped := BankerRoundChop(quo, Precision) + chopped := BankerRoundChopPrecision(quo) return Dec{chopped} } @@ -212,7 +219,7 @@ func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string func (d Dec) ToLeftPadded(totalDigits int8) string { - chopped := BankerRoundChop(d.Int, Precision) + chopped := BankerRoundChopPrecision(d.Int) intStr := chopped.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) @@ -228,18 +235,15 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // |________| // nolint - go-cyclo -// chop of n digits, and banker round the digits being chopped off -// Examples: -// BankerRoundChop(1005, 1) = 100 -// BankerRoundChop(1015, 1) = 102 -// BankerRoundChop(1500, 3) = 2 -func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { +// Remove a Precision amount of rightmost digits and perform bankers rounding +// on the remainder (gaussian rounding) on the digits which have been removed. +func BankerRoundChopPrecision(d *big.Int) (chopped *big.Int) { // remove the negative and add it back when returning if d.Sign() == -1 { // make d positive, compute chopped value, and then un-mutate d d = d.Neg(d) - chopped = BankerRoundChop(d, n) + chopped = BankerRoundChopPrecision(d) d = d.Neg(d) chopped.Neg(chopped) return chopped @@ -285,7 +289,7 @@ func BankerRoundChop(d *big.Int, n int64) (chopped *big.Int) { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - chopped := BankerRoundChop(d.Int, Precision) + chopped := BankerRoundChopPrecision(d.Int) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -294,7 +298,7 @@ func (d Dec) RoundInt64() int64 { // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return NewIntFromBigInt(BankerRoundChop(d.Int, Precision)) + return NewIntFromBigInt(BankerRoundChopPrecision(d.Int)) } //___________________________________________________________________________________ @@ -363,11 +367,6 @@ func DecsEqual(d1s, d2s []Dec) bool { return true } -// intended to be used with require/assert: require.True(DecEq(...)) -func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { - return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got -} - // minimum decimal between two func MinDec(d1, d2 Dec) Dec { if d1.LT(d2) { diff --git a/types/decimal_test.go b/types/decimal_test.go index 6ec6cf18a480..faed10c69d26 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -15,6 +15,11 @@ func mustNewDecFromStr(t *testing.T, str string) (d Dec) { return d } +// intended to be used with require/assert: require.True(DecEq(...)) +func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got +} + //_______________________________________ func TestPrecisionMultiplier(t *testing.T) { diff --git a/x/fee_distribution/keeper.go b/x/fee_distribution/keeper.go deleted file mode 100644 index aba07eaca1c1..000000000000 --- a/x/fee_distribution/keeper.go +++ /dev/null @@ -1,91 +0,0 @@ -package stake - -//// keeper of the staking store -//type Keeper struct { -//storeKey sdk.StoreKey -//cdc *wire.Codec -//coinKeeper bank.Keeper - -//// codespace -//codespace sdk.CodespaceType -//} - -//func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { -//keeper := Keeper{ -//storeKey: key, -//cdc: cdc, -//coinKeeper: ck, -//codespace: codespace, -//} -//return keeper -//} - -////_________________________________________________________________________ - -//// cummulative power of the non-absent prevotes -//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Dec { -//store := ctx.KVStore(k.storeKey) - -//// get absent prevote indexes -//absents := ctx.AbsentValidators() - -//TotalPower := sdk.ZeroDec() -//i := int32(0) -//iterator := store.SubspaceIterator(ValidatorsBondedKey) -//for ; iterator.Valid(); iterator.Next() { - -//skip := false -//for j, absentIndex := range absents { -//if absentIndex > i { -//break -//} - -//// if non-voting validator found, skip adding its power -//if absentIndex == i { -//absents = append(absents[:j], absents[j+1:]...) // won't need again -//skip = true -//break -//} -//} -//if skip { -//continue -//} - -//bz := iterator.Value() -//var validator Validator -//k.cdc.MustUnmarshalBinary(bz, &validator) -//TotalPower = TotalPower.Add(validator.Power) -//i++ -//} -//iterator.Close() -//return TotalPower -//} - -////_______________________________________________________________________ - -//// XXX TODO trim functionality - -//// retrieve all the power changes which occur after a height -//func (k Keeper) GetPowerChangesAfterHeight(ctx sdk.Context, earliestHeight int64) (pcs []PowerChange) { -//store := ctx.KVStore(k.storeKey) - -//iterator := store.SubspaceIterator(PowerChangeKey) //smallest to largest -//for ; iterator.Valid(); iterator.Next() { -//pcBytes := iterator.Value() -//var pc PowerChange -//k.cdc.MustUnmarshalBinary(pcBytes, &pc) -//if pc.Height < earliestHeight { -//break -//} -//pcs = append(pcs, pc) -//} -//iterator.Close() -//return -//} - -//// set a power change -//func (k Keeper) setPowerChange(ctx sdk.Context, pc PowerChange) { -//store := ctx.KVStore(k.storeKey) -//b := k.cdc.MustMarshalBinary(pc) -//store.Set(GetPowerChangeKey(pc.Height), b) -//} diff --git a/x/fee_distribution/keeper_test.go b/x/fee_distribution/keeper_test.go deleted file mode 100644 index 8902680604e7..000000000000 --- a/x/fee_distribution/keeper_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package stake - -//// test if is a gotValidator from the last update -//func TestGetTotalPrecommitVotingPower(t *testing.T) { -//ctx, _, keeper := createTestInput(t, false, 0) - -//amts := []int64{10000, 1000, 100, 10, 1} -//var candidatesIn [5]Candidate -//for i, amt := range amts { -//candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) -//candidatesIn[i].BondedShares = sdk.NewDec(amt) -//candidatesIn[i].DelegatorShares = sdk.NewDec(amt) -//keeper.setCandidate(ctx, candidatesIn[i]) -//} - -//// test that an empty gotValidator set doesn't have any gotValidators -//gotValidators := keeper.GetValidators(ctx) -//require.Equal(t, 5, len(gotValidators)) - -//totPow := keeper.GetTotalPrecommitVotingPower(ctx) -//exp := sdk.NewDec(11111) -//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) - -//// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address -//ctx = ctx.WithAbsentValidators([]int32{1, 3}) -//totPow = keeper.GetTotalPrecommitVotingPower(ctx) - -//// XXX verify that this order should infact exclude these two records -//exp = sdk.NewDec(11100) -//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) -//} diff --git a/x/fee_distribution/movement.go b/x/fee_distribution/movement.go deleted file mode 100644 index ebd3e3714851..000000000000 --- a/x/fee_distribution/movement.go +++ /dev/null @@ -1,72 +0,0 @@ -package stake - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// burn burn burn -func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} - -//// Handle fee distribution to the validators and delegators -//func (k Keeper) FeeHandler(ctx sdk.Context, collectedFees sdk.Coins) { -//pool := k.GetPool(ctx) -//params := k.GetParams(ctx) - -//// XXX determine -//candidate := NewCandidate(addrs[0], pks[0], Description{}) - -//// calculate the proposer reward -//precommitPower := k.GetTotalPrecommitVotingPower(ctx) -//toProposer := coinsMulDec(collectedFees, (sdk.NewDec(1, 100).Add(sdk.NewDec(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) -//candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) - -//toReservePool := coinsMulDec(collectedFees, params.ReservePoolFee) -//pool.FeeReservePool = pool.FeeReservePool.Plus(toReservePool) - -//distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool) -//pool.FeePool = pool.FeePool.Plus(distributedReward) -//pool.FeeSumReceived = pool.FeeSumReceived.Plus(distributedReward) -//pool.FeeRecent = distributedReward - -//// lastly update the FeeRecent term -//pool.FeeRecent = collectedFees - -//k.setPool(ctx, pool) -//} - -//func coinsMulDec(coins sdk.Coins, rat sdk.Dec) sdk.Coins { -//var res sdk.Coins -//for _, coin := range coins { -//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount, 0)).Evaluate() -//coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} -//res = res.Plus(coinMul) -//} -//return res -//} - -////____________________________________________________________________________- - -//// calculate adjustment changes for a candidate at a height -//func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { - -//heightDec := sdk.NewDec(height) -//lastHeightDec := sdk.NewDec(height - 1) -//candidateFeeCount := candidate.BondedShares.Mul(heightDec) -//poolFeeCount := pool.BondedShares.Mul(heightDec) - -//for i, denom := range denoms { -//poolFeeSumReceived := sdk.NewDec(pool.FeeSumReceived.AmountOf(denom)) -//poolFeeRecent := sdk.NewDec(pool.FeeRecent.AmountOf(denom)) -//// calculate simple and projected pools -//simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) -//calc1 := candidate.PrevBondedShares.Mul(lastHeightDec).Quo(pool.PrevBondedShares.Mul(lastHeightDec)).Mul(poolFeeRecent) -//calc2 := candidate.BondedShares.Quo(pool.BondedShares).Mul(poolFeeRecent) -//projectedPool := calc1.Add(calc2) - -//AdjustmentChange := simplePool.Sub(projectedPool) -//candidate.FeeAdjustments[i] = candidate.FeeAdjustments[i].Add(AdjustmentChange) -//pool.FeeAdjustments[i] = pool.FeeAdjustments[i].Add(AdjustmentChange) -//} - -//return candidate, pool -//} diff --git a/x/fee_distribution/types.go b/x/fee_distribution/types.go deleted file mode 100644 index 2234104717c0..000000000000 --- a/x/fee_distribution/types.go +++ /dev/null @@ -1,107 +0,0 @@ -package stake - -//// GenesisState - all staking state that must be provided at genesis -//type GenesisState struct { -//Pool Pool `json:"pool"` -//Params Params `json:"params"` -//} - -//func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []Delegation) GenesisState { -//return GenesisState{ -//Pool: pool, -//Params: params, -//} -//} - -//// get raw genesis raw message for testing -//func DefaultGenesisState() GenesisState { -//return GenesisState{ -//Pool: initialPool(), -//Params: defaultParams(), -//} -//} - -//// fee information for a validator -//type Validator struct { -//Adjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // total shares of a global hold pools -//} - -////_________________________________________________________________________ - -//// Params defines the high level settings for staking -//type Params struct { -//FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms -//ReservePoolFee sdk.Dec `json:"reserve_pool_fee"` // percent of fees which go to reserve pool -//} - -//func (p Params) equal(p2 Params) bool { -//return p.BondDenom == p2.BondDenom && -//p.ReservePoolFee.Equal(p2.ReservePoolFee) -//} - -//func defaultParams() Params { -//return Params{ -//FeeDenoms: []string{"steak"}, -//ReservePoolFee: sdk.NewDec(5, 100), -//} -//} - -////_________________________________________________________________________ - -//// Pool - dynamic parameters of the current state -//type Pool struct { -//FeeReservePool sdk.Coins `json:"fee_reserve_pool"` // XXX reserve pool of collected fees for use by governance -//FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed -//FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` -//FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected -//FeeAdjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // XXX last recorded bonded shares -//} - -//func (p Pool) equal(p2 Pool) bool { -//return p.FeeReservePool.IsEqual(p2.FeeReservePool) && -//p.FeePool.IsEqual(p2.FeePool) && -//p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && -//p.FeeRecent.IsEqual(p2.FeeRecent) && -//sdk.DecsEqual(p.FeeAdjustments, p2.FeeAdjustments) && -//p.PrevBondedShares.Equal(p2.PrevBondedShares) -//} - -//// initial pool for testing -//func initialPool() Pool { -//return Pool{ -//FeeReservePool: sdk.Coins(nil), -//FeePool: sdk.Coins(nil), -//FeeSumReceived: sdk.Coins(nil), -//FeeRecent: sdk.Coins(nil), -//FeeAdjustments: []sdk.Dec{sdk.ZeroDec()}, -//PrevBondedShares: sdk.ZeroDec(), -//} -//} - -////_________________________________________________________________________ - -//// Used in calculation of fee shares, added to a queue for each block where a power change occures -//type PowerChange struct { -//Height int64 `json:"height"` // block height at change -//Power sdk.Dec `json:"power"` // total power at change -//PrevPower sdk.Dec `json:"prev_power"` // total power at previous height-1 -//FeesIn sdk.Coins `json:"fees_in"` // fees in at block height -//PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height -//} - -////_________________________________________________________________________ -//// KEY MANAGEMENT - -//var ( -//// Keys for store prefixes -//PowerChangeKey = []byte{0x09} // prefix for power change object -//) - -//// get the key for the accumulated update validators -//func GetPowerChangeKey(height int64) []byte { -//heightBytes := make([]byte, binary.MaxVarintLen64) -//binary.BigEndian.PutUint64(heightBytes, ^uint64(height)) // invert height (older validators first) -//return append(PowerChangeKey, heightBytes...) -//} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 3699a83d4169..db945a9d3043 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -69,11 +69,8 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - genesis.Pool.LooseTokens = sdk.NewDec( - initCoins.MulRaw( - int64(len(addrs)), - ).Int64(), - 0) + ic := initCoins.MulRaw(int64(len(addrs))) + genesis.Pool.LooseTokens = sdk.NewDec(ic.Int64(), 0) _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) From 609e07d2d5d8fc66b4cb2fac08e5f416933c433c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Aug 2018 23:36:33 -0400 Subject: [PATCH 39/50] Aditya comments --- types/decimal.go | 9 +++++++-- types/decimal_test.go | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index f58f303c9bb6..f8132a6ab779 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -64,9 +64,14 @@ func precisionMultiplier(prec int64) *big.Int { return precisionMultipliers[prec] } -// create a new Dec from integer assuming whole numbers +// create a new Dec from integer assuming whole number +func NewDec(i int64) Dec { + return NewDecWithPrec(i, 0) +} + +// create a new Dec from integer with decimal place at prec // CONTRACT: prec <= Precision -func NewDec(i, prec int64) Dec { +func NewDecWithPrec(i, prec int64) Dec { return Dec{ new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), } diff --git a/types/decimal_test.go b/types/decimal_test.go index faed10c69d26..4215555eab27 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -37,6 +37,7 @@ func TestNewDecFromStr(t *testing.T) { exp Dec }{ {"", true, Dec{}}, + {"0.-75", true, Dec{}}, {"0", false, NewDec(0, 0)}, {"1", false, NewDec(1, 0)}, {"1.1", false, NewDec(11, 1)}, From 81e96e89eb7bf9698501131a939292452ecb2ee6 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 11 Aug 2018 18:46:45 -0400 Subject: [PATCH 40/50] ... --- client/lcd/test_helpers.go | 2 +- cmd/gaia/app/genesis.go | 4 +- cmd/gaia/app/sim_test.go | 2 +- .../democoin/x/assoc/validator_set_test.go | 4 +- examples/democoin/x/oracle/oracle_test.go | 10 +- types/decimal.go | 62 ++++++--- types/decimal_test.go | 129 +++++++++--------- x/gov/genesis.go | 6 +- x/gov/test_common.go | 2 +- x/params/keeper_test.go | 6 +- x/slashing/app_test.go | 4 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper_test.go | 10 +- x/slashing/params.go | 8 +- x/slashing/test_common.go | 2 +- x/slashing/tick_test.go | 2 +- x/stake/app_test.go | 12 +- x/stake/genesis_test.go | 8 +- x/stake/handler_test.go | 62 ++++----- x/stake/keeper/delegation_test.go | 30 ++-- x/stake/keeper/keeper_test.go | 2 +- x/stake/keeper/slash.go | 6 +- x/stake/keeper/slash_test.go | 52 +++---- x/stake/keeper/test_common.go | 4 +- x/stake/keeper/validator_test.go | 86 ++++++------ x/stake/simulation/msgs.go | 6 +- x/stake/types/delegation_test.go | 16 +-- x/stake/types/inflation_test.go | 37 ++--- x/stake/types/msg_test.go | 18 +-- x/stake/types/params.go | 8 +- x/stake/types/pool.go | 6 +- x/stake/types/pool_test.go | 22 +-- x/stake/types/validator.go | 2 +- x/stake/types/validator_test.go | 12 +- 34 files changed, 333 insertions(+), 311 deletions(-) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 9c6826e9c2dd..be8b6ddf2c18 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -173,7 +173,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100, 0)) + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 0be42d81ab1e..e35b21c4b093 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -185,7 +185,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState } acc := NewGenesisAccount(&accAuth) genaccs[i] = acc - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc, 0)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc)) // increase the supply // add the validator if len(genTx.Name) > 0 { @@ -193,7 +193,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState validator := stake.NewValidator(genTx.Address, sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc) - stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal, 0)) // increase the supply + stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply // add some new shares to the validator var issuedDelShares sdk.Dec diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index b2fafd68f04b..6369b4ca66fc 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -48,7 +48,7 @@ func appStateFn(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage { // Default genesis state stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(1000, 0) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(1000) genesis := GenesisState{ Accounts: genesisAccounts, StakeData: stakeGenesis, diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index e4f04401698e..eac23b25e221 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -32,8 +32,8 @@ func TestValidatorSet(t *testing.T) { addr2 := []byte("addr2") base := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewDec(1, 0)}, - {addr2, sdk.NewDec(2, 0)}, + {addr1, sdk.NewDec(1)}, + {addr2, sdk.NewDec(2)}, }} valset := NewValidatorSet(wire.NewCodec(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5) diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index a5c7420e626f..f4971c8b1484 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -107,9 +107,9 @@ func TestOracle(t *testing.T) { addr3 := []byte("addr3") addr4 := []byte("addr4") valset := &mock.ValidatorSet{[]mock.Validator{ - {addr1, sdk.NewDec(7, 0)}, - {addr2, sdk.NewDec(7, 0)}, - {addr3, sdk.NewDec(1, 0)}, + {addr1, sdk.NewDec(7)}, + {addr2, sdk.NewDec(7)}, + {addr3, sdk.NewDec(1)}, }} key := sdk.NewKVStoreKey("testkey") @@ -119,7 +119,7 @@ func TestOracle(t *testing.T) { require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) - ork := NewKeeper(key, cdc, valset, sdk.NewDec(667, 3), 100) // 66.7% + ork := NewKeeper(key, cdc, valset, sdk.NewDecWithPrec(667, 3), 100) // 66.7% h := seqHandler(ork, key, sdk.CodespaceRoot) // Nonmock.Validator signed, transaction failed @@ -171,7 +171,7 @@ func TestOracle(t *testing.T) { require.Equal(t, 1, getSequence(ctx, key)) // Should handle mock.Validator set change - valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12, 0)}) + valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12)}) bz, err = json.Marshal(valset) require.Nil(t, err) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) diff --git a/types/decimal.go b/types/decimal.go index f8132a6ab779..128b3b17b247 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -6,6 +6,7 @@ import ( "math/big" "strconv" "strings" + "testing" ) // NOTE: never use new(Dec) or else we will panic unmarshalling into the @@ -25,6 +26,7 @@ const ( var ( precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + fivePrecision = new(big.Int).Mul(big.NewInt(5), precisionReuse) precisionMultipliers []*big.Int zeroInt = big.NewInt(0) tenInt = big.NewInt(10) @@ -64,6 +66,8 @@ func precisionMultiplier(prec int64) *big.Int { return precisionMultipliers[prec] } +//______________________________________________________________________________________________ + // create a new Dec from integer assuming whole number func NewDec(i int64) Dec { return NewDecWithPrec(i, 0) @@ -79,7 +83,13 @@ func NewDecWithPrec(i, prec int64) Dec { // create a new Dec from big integer assuming whole numbers // CONTRACT: prec <= Precision -func NewDecFromBigInt(i *big.Int, prec int64) Dec { +func NewDecFromBigInt(i *big.Int) Dec { + return NewDecFromBigIntWithPrec(i, 0) +} + +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func NewDecFromBigIntWithPrec(i *big.Int, prec int64) Dec { return Dec{ new(big.Int).Mul(i, precisionMultiplier(prec)), } @@ -87,7 +97,13 @@ func NewDecFromBigInt(i *big.Int, prec int64) Dec { // create a new Dec from big integer assuming whole numbers // CONTRACT: prec <= Precision -func NewDecFromInt(i Int, prec int64) Dec { +func NewDecFromInt(i Int) Dec { + return NewDecFromIntWithPrec(i, 0) +} + +// create a new Dec from big integer with decimal place at prec +// CONTRACT: prec <= Precision +func NewDecFromIntWithPrec(i Int, prec int64) Dec { return Dec{ new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), } @@ -152,6 +168,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { return Dec{combined}, nil } +//______________________________________________________________________________________________ //nolint func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } @@ -184,7 +201,7 @@ func (d Dec) Sub(d2 Dec) Dec { // multiplication func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) - chopped := BankerRoundChopPrecision(mul) + chopped := ChopPrecisionAndRound(mul) if chopped.BitLen() > 255+DecimalPrecisionBytes { panic("Int overflow") @@ -200,7 +217,7 @@ func (d Dec) Quo(d2 Dec) Dec { mul.Mul(mul, precisionReuse) quo := new(big.Int).Quo(mul, d2.Int) - chopped := BankerRoundChopPrecision(quo) + chopped := ChopPrecisionAndRound(quo) return Dec{chopped} } @@ -224,7 +241,7 @@ func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string func (d Dec) ToLeftPadded(totalDigits int8) string { - chopped := BankerRoundChopPrecision(d.Int) + chopped := ChopPrecisionAndRound(d.Int) intStr := chopped.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) @@ -242,13 +259,13 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // nolint - go-cyclo // Remove a Precision amount of rightmost digits and perform bankers rounding // on the remainder (gaussian rounding) on the digits which have been removed. -func BankerRoundChopPrecision(d *big.Int) (chopped *big.Int) { +func ChopPrecisionAndRound(d *big.Int) (chopped *big.Int) { // remove the negative and add it back when returning if d.Sign() == -1 { // make d positive, compute chopped value, and then un-mutate d d = d.Neg(d) - chopped = BankerRoundChopPrecision(d) + chopped = ChopPrecisionAndRound(d) d = d.Neg(d) chopped.Neg(chopped) return chopped @@ -262,19 +279,19 @@ func BankerRoundChopPrecision(d *big.Int) (chopped *big.Int) { return quo } - lenWhole := len(d.String()) - if quo.Sign() == 0 { // only the decimal places (ex. 0.1234) - lenWhole++ - } - lenQuo := len(quo.String()) - lenRem := len(rem.String()) - leadingZeros := lenWhole - (lenQuo + lenRem) // leading zeros removed from the remainder + //lenWhole := len(d.String()) + //if quo.Sign() == 0 { // only the decimal places (ex. 0.1234) + //lenWhole++ + //} + //lenQuo := len(quo.String()) + //lenRem := len(rem.String()) + //leadingZeros := lenWhole - (lenQuo + lenRem) // leading zeros removed from the remainder - zerosToAdd := int64(lenRem - 1 + leadingZeros) - multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) - fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier) + //zerosToAdd := int64(lenRem - 1 + leadingZeros) + //multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) + //fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier) - switch rem.Cmp(fiveLine) { + switch rem.Cmp(fivePrecision) { case -1: chopped = quo return @@ -294,7 +311,7 @@ func BankerRoundChopPrecision(d *big.Int) (chopped *big.Int) { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - chopped := BankerRoundChopPrecision(d.Int) + chopped := ChopPrecisionAndRound(d.Int) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -303,7 +320,7 @@ func (d Dec) RoundInt64() int64 { // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return NewIntFromBigInt(BankerRoundChopPrecision(d.Int)) + return NewIntFromBigInt(ChopPrecisionAndRound(d.Int)) } //___________________________________________________________________________________ @@ -379,3 +396,8 @@ func MinDec(d1, d2 Dec) Dec { } return d2 } + +// intended to be used with require/assert: require.True(DecEq(...)) +func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got +} diff --git a/types/decimal_test.go b/types/decimal_test.go index 4215555eab27..115eeacb019b 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -15,11 +15,6 @@ func mustNewDecFromStr(t *testing.T, str string) (d Dec) { return d } -// intended to be used with require/assert: require.True(DecEq(...)) -func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { - return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got -} - //_______________________________________ func TestPrecisionMultiplier(t *testing.T) { @@ -38,20 +33,20 @@ func TestNewDecFromStr(t *testing.T) { }{ {"", true, Dec{}}, {"0.-75", true, Dec{}}, - {"0", false, NewDec(0, 0)}, - {"1", false, NewDec(1, 0)}, - {"1.1", false, NewDec(11, 1)}, - {"0.75", false, NewDec(75, 2)}, - {"0.8", false, NewDec(8, 1)}, - {"0.11111", false, NewDec(11111, 5)}, - {"314460551102969.3144278234343371835", true, NewDec(3141203149163817869, 0)}, + {"0", false, NewDec(0)}, + {"1", false, NewDec(1)}, + {"1.1", false, NewDecWithPrec(11, 1)}, + {"0.75", false, NewDecWithPrec(75, 2)}, + {"0.8", false, NewDecWithPrec(8, 1)}, + {"0.11111", false, NewDecWithPrec(11111, 5)}, + {"314460551102969.3144278234343371835", true, NewDec(3141203149163817869)}, {"314460551102969314427823434337.1835718092488231350", - true, NewDecFromBigInt(largeBigInt, 4)}, + true, NewDecFromBigIntWithPrec(largeBigInt, 4)}, {"314460551102969314427823434337.1835", - false, NewDecFromBigInt(largeBigInt, 4)}, + false, NewDecFromBigIntWithPrec(largeBigInt, 4)}, {".", true, Dec{}}, - {".0", true, NewDec(0, 0)}, - {"1.", true, NewDec(1, 0)}, + {".0", true, NewDec(0)}, + {"1.", true, NewDec(1)}, {"foobar", true, Dec{}}, {"0.foobar", true, Dec{}}, {"0.foobar.", true, Dec{}}, @@ -72,7 +67,7 @@ func TestNewDecFromStr(t *testing.T) { require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - exp := tc.exp.Mul(NewDec(-1, 0)) + exp := tc.exp.Mul(NewDec(-1)) require.True(t, res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) } } @@ -83,28 +78,28 @@ func TestEqualities(t *testing.T) { d1, d2 Dec gt, lt, eq bool }{ - {NewDec(0, 0), NewDec(0, 0), false, false, true}, - {NewDec(0, 2), NewDec(0, 4), false, false, true}, - {NewDec(100, 0), NewDec(100, 0), false, false, true}, - {NewDec(-100, 0), NewDec(-100, 0), false, false, true}, - {NewDec(-1, 1), NewDec(-1, 1), false, false, true}, - {NewDec(3333, 3), NewDec(3333, 3), false, false, true}, - - {NewDec(0, 0), NewDec(3333, 3), false, true, false}, - {NewDec(0, 0), NewDec(100, 0), false, true, false}, - {NewDec(-1, 0), NewDec(3333, 3), false, true, false}, - {NewDec(-1, 0), NewDec(100, 0), false, true, false}, - {NewDec(1111, 3), NewDec(100, 0), false, true, false}, - {NewDec(1111, 3), NewDec(3333, 3), false, true, false}, - {NewDec(-3333, 3), NewDec(-1111, 3), false, true, false}, - - {NewDec(3333, 3), NewDec(0, 0), true, false, false}, - {NewDec(100, 0), NewDec(0, 0), true, false, false}, - {NewDec(3333, 3), NewDec(-1, 0), true, false, false}, - {NewDec(100, 0), NewDec(-1, 0), true, false, false}, - {NewDec(100, 0), NewDec(1111, 3), true, false, false}, - {NewDec(3333, 3), NewDec(1111, 3), true, false, false}, - {NewDec(-1111, 3), NewDec(-3333, 3), true, false, false}, + {NewDec(0), NewDec(0), false, false, true}, + {NewDecWithPrec(0, 2), NewDecWithPrec(0, 4), false, false, true}, + {NewDecWithPrec(100, 0), NewDecWithPrec(100, 0), false, false, true}, + {NewDecWithPrec(-100, 0), NewDecWithPrec(-100, 0), false, false, true}, + {NewDecWithPrec(-1, 1), NewDecWithPrec(-1, 1), false, false, true}, + {NewDecWithPrec(3333, 3), NewDecWithPrec(3333, 3), false, false, true}, + + {NewDecWithPrec(0, 0), NewDecWithPrec(3333, 3), false, true, false}, + {NewDecWithPrec(0, 0), NewDecWithPrec(100, 0), false, true, false}, + {NewDecWithPrec(-1, 0), NewDecWithPrec(3333, 3), false, true, false}, + {NewDecWithPrec(-1, 0), NewDecWithPrec(100, 0), false, true, false}, + {NewDecWithPrec(1111, 3), NewDecWithPrec(100, 0), false, true, false}, + {NewDecWithPrec(1111, 3), NewDecWithPrec(3333, 3), false, true, false}, + {NewDecWithPrec(-3333, 3), NewDecWithPrec(-1111, 3), false, true, false}, + + {NewDecWithPrec(3333, 3), NewDecWithPrec(0, 0), true, false, false}, + {NewDecWithPrec(100, 0), NewDecWithPrec(0, 0), true, false, false}, + {NewDecWithPrec(3333, 3), NewDecWithPrec(-1, 0), true, false, false}, + {NewDecWithPrec(100, 0), NewDecWithPrec(-1, 0), true, false, false}, + {NewDecWithPrec(100, 0), NewDecWithPrec(1111, 3), true, false, false}, + {NewDecWithPrec(3333, 3), NewDecWithPrec(1111, 3), true, false, false}, + {NewDecWithPrec(-1111, 3), NewDecWithPrec(-3333, 3), true, false, false}, } for tcIndex, tc := range tests { @@ -120,15 +115,15 @@ func TestDecsEqual(t *testing.T) { d1s, d2s []Dec eq bool }{ - {[]Dec{NewDec(0, 0)}, []Dec{NewDec(0, 0)}, true}, - {[]Dec{NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, - {[]Dec{NewDec(0, 0)}, []Dec{}, false}, - {[]Dec{NewDec(0, 0), NewDec(1, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, true}, - {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0), NewDec(0, 0)}, true}, - {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(0, 0), NewDec(1, 0)}, false}, - {[]Dec{NewDec(1, 0), NewDec(0, 0)}, []Dec{NewDec(1, 0)}, false}, - {[]Dec{NewDec(1, 0), NewDec(2, 0)}, []Dec{NewDec(2, 0), NewDec(4, 0)}, false}, - {[]Dec{NewDec(3, 0), NewDec(18, 0)}, []Dec{NewDec(1, 0), NewDec(6, 0)}, false}, + {[]Dec{NewDec(0)}, []Dec{NewDec(0)}, true}, + {[]Dec{NewDec(0)}, []Dec{NewDec(1)}, false}, + {[]Dec{NewDec(0)}, []Dec{}, false}, + {[]Dec{NewDec(0), NewDec(1)}, []Dec{NewDec(0), NewDec(1)}, true}, + {[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1), NewDec(0)}, true}, + {[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(0), NewDec(1)}, false}, + {[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1)}, false}, + {[]Dec{NewDec(1), NewDec(2)}, []Dec{NewDec(2), NewDec(4)}, false}, + {[]Dec{NewDec(3), NewDec(18)}, []Dec{NewDec(1), NewDec(6)}, false}, } for tcIndex, tc := range tests { @@ -143,23 +138,25 @@ func TestArithmetic(t *testing.T) { expMul, expDiv, expAdd, expSub Dec }{ // d1 d2 MUL DIV ADD SUB - {NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0)}, - {NewDec(1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(1, 0), NewDec(1, 0)}, - {NewDec(0, 0), NewDec(1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(1, 0), NewDec(-1, 0)}, - {NewDec(0, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(-1, 0), NewDec(1, 0)}, - {NewDec(-1, 0), NewDec(0, 0), NewDec(0, 0), NewDec(0, 0), NewDec(-1, 0), NewDec(-1, 0)}, - - {NewDec(1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(2, 0), NewDec(0, 0)}, - {NewDec(-1, 0), NewDec(-1, 0), NewDec(1, 0), NewDec(1, 0), NewDec(-2, 0), NewDec(0, 0)}, - {NewDec(1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(2, 0)}, - {NewDec(-1, 0), NewDec(1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(0, 0), NewDec(-2, 0)}, - - {NewDec(3, 0), NewDec(7, 0), NewDec(21, 0), NewDec(4285714286, 10), NewDec(10, 0), NewDec(-4, 0)}, - {NewDec(2, 0), NewDec(4, 0), NewDec(8, 0), NewDec(5, 1), NewDec(6, 0), NewDec(-2, 0)}, - {NewDec(100, 0), NewDec(100, 0), NewDec(10000, 0), NewDec(1, 0), NewDec(200, 0), NewDec(0, 0)}, - - {NewDec(15, 1), NewDec(15, 1), NewDec(225, 2), NewDec(1, 0), NewDec(3, 0), NewDec(0, 0)}, - {NewDec(3333, 4), NewDec(333, 4), NewDec(1109889, 8), NewDec(10009009009, 9), NewDec(3666, 4), NewDec(3, 1)}, + {NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0)}, + {NewDec(1), NewDec(0), NewDec(0), NewDec(0), NewDec(1), NewDec(1)}, + {NewDec(0), NewDec(1), NewDec(0), NewDec(0), NewDec(1), NewDec(-1)}, + {NewDec(0), NewDec(-1), NewDec(0), NewDec(0), NewDec(-1), NewDec(1)}, + {NewDec(-1), NewDec(0), NewDec(0), NewDec(0), NewDec(-1), NewDec(-1)}, + + {NewDec(1), NewDec(1), NewDec(1), NewDec(1), NewDec(2), NewDec(0)}, + {NewDec(-1), NewDec(-1), NewDec(1), NewDec(1), NewDec(-2), NewDec(0)}, + {NewDec(1), NewDec(-1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(2)}, + {NewDec(-1), NewDec(1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(-2)}, + + {NewDec(3), NewDec(7), NewDec(21), NewDecWithPrec(4285714286, 10), NewDec(10), NewDec(-4)}, + {NewDec(2), NewDec(4), NewDec(8), NewDecWithPrec(5, 1), NewDec(6), NewDec(-2)}, + {NewDec(100), NewDec(100), NewDec(10000), NewDec(1), NewDec(200), NewDec(0)}, + + {NewDecWithPrec(15, 1), NewDecWithPrec(15, 1), NewDecWithPrec(225, 2), + NewDec(1), NewDec(3), NewDec(0)}, + {NewDecWithPrec(3333, 4), NewDecWithPrec(333, 4), NewDecWithPrec(1109889, 8), + NewDecWithPrec(10009009009, 9), NewDecWithPrec(3666, 4), NewDecWithPrec(3, 1)}, } for tcIndex, tc := range tests { @@ -277,7 +274,7 @@ type testDEmbedStruct struct { // TODO make work for UnmarshalJSON func TestEmbeddedStructSerializationGoWire(t *testing.T) { - obj := testDEmbedStruct{"foo", 10, NewDec(1, 3)} + obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)} bz, err := cdc.MarshalBinary(obj) require.Nil(t, err) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 36ab5fb896bf..e232094114c5 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewDec(5, 1), - Veto: sdk.NewDec(333, 3), // 33.3% - GovernancePenalty: sdk.NewDec(1, 2), // 1% + Threshold: sdk.NewDecWithPrec(5, 1), + Veto: sdk.NewDecWithPrec(333, 3), // 33.3% + GovernancePenalty: sdk.NewDecWithPrec(1, 2), // 1% }, } } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 14ca276bf69b..5e7977b50c34 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -64,7 +64,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index f98e15f1c07e..22348f8a44a0 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -94,7 +94,7 @@ func TestGetter(t *testing.T) { {"uint64", uint64(1)}, {"int", sdk.NewInt(1)}, {"uint", sdk.NewUint(1)}, - {"rat", sdk.NewDec(1, 1)}, + {"rat", sdk.NewDecWithPrec(1, 1)}, } assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1, 1)) }) + assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDecWithPrec(1, 1)) }) var res interface{} var err error @@ -263,7 +263,7 @@ func TestGetter(t *testing.T) { assert.Equal(t, def9, res) // Dec - def10 := sdk.NewDec(0, 0) + def10 := sdk.NewDec(0) res, err = g.GetDec(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 8644829e07e1..1e6a4e89d4b4 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -58,7 +58,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -109,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 3c04ffc1a9ba..41cb5d19968c 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // assert non-revoked validator can't be unrevoked got = slh(ctx, NewMsgUnrevoke(addr)) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 831b14a32529..74b33f7c2f8d 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -31,7 +31,7 @@ func TestHandleDoubleSign(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info keeper.handleValidatorSignature(ctx, val, amtInt, true) @@ -44,12 +44,12 @@ func TestHandleDoubleSign(t *testing.T) { // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19, 0).Quo(sdk.NewDec(20, 0))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) - require.Equal(t, sdk.NewDecFromInt(amt, 0).Mul(sdk.NewDec(19, 0).Quo(sdk.NewDec(20, 0))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, @@ -66,7 +66,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -172,7 +172,7 @@ func TestHandleNewValidator(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewDec(amt, 0), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) diff --git a/x/slashing/params.go b/x/slashing/params.go index e501ad390d0f..3480de28fd76 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -30,7 +30,7 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { minSignedPerWindow := k.params.GetDecWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) signedBlocksWindow := k.SignedBlocksWindow(ctx) - return sdk.NewDec(signedBlocksWindow, 0).Mul(minSignedPerWindow).RoundInt64() + return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() } // Double-sign unbond duration @@ -70,9 +70,9 @@ var ( // TODO Temporarily set to 10 minutes for testnets defaultDowntimeUnbondDuration int64 = 60 * 10 - defaultMinSignedPerWindow = sdk.NewDec(5, 1) // 0.5 + defaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1) // 0.5 - defaultSlashFractionDoubleSign = sdk.NewDec(1, 0).Quo(sdk.NewDec(20, 0)) + defaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20)) - defaultSlashFractionDowntime = sdk.NewDec(1, 0).Quo(sdk.NewDec(100, 0)) + defaultSlashFractionDowntime = sdk.NewDec(1).Quo(sdk.NewDec(100)) ) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index db945a9d3043..089bdca3c878 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -70,7 +70,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para genesis := stake.DefaultGenesisState() ic := initCoins.MulRaw(int64(len(addrs))) - genesis.Pool.LooseTokens = sdk.NewDec(ic.Int64(), 0) + genesis.Pool.LooseTokens = sdk.NewDec(ic.Int64()) _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index dc1d2229be25..9540745bb9ce 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -21,7 +21,7 @@ func TestBeginBlocker(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt, 0).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) val := abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(pk), diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 42311d3e1eb1..9847ed2904b6 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000, 0) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -138,7 +138,7 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) // addr1 create validator on behalf of addr2 createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) @@ -150,10 +150,10 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10, 0)) + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) // edit the validator description = NewDescription("bar_moniker", "", "", "") @@ -169,10 +169,10 @@ func TestStakeMsgs(t *testing.T) { mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10, 0)) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10, 0)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 2bcdfa1035fa..9cdbe19826bc 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -17,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(2, 0) + pool.BondedTokens = sdk.NewDec(2) params := keeper.GetParams(ctx) var delegations []Delegation @@ -69,7 +69,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(int64(200+(size-100)), 0) + pool.BondedTokens = sdk.NewDec(int64(200 + (size - 100))) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -80,8 +80,8 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators[i].Status = sdk.Bonded if i < 100 { - validators[i].Tokens = sdk.NewDec(2, 0) - validators[i].DelegatorShares = sdk.NewDec(2, 0) + validators[i].Tokens = sdk.NewDec(2) + validators[i].DelegatorShares = sdk.NewDec(2) } else { validators[i].Tokens = sdk.OneDec() validators[i].DelegatorShares = sdk.OneDec() diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index e4e1c0e7c42e..cebe28885887 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -80,7 +80,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDecWithPrec(5, 1)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -109,7 +109,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -137,8 +137,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewDec(10, 0), validator.BondedTokens()) - assert.Equal(t, sdk.NewDec(10, 0), validator.DelegatorShares) + assert.Equal(t, sdk.NewDec(10), validator.BondedTokens()) + assert.Equal(t, sdk.NewDec(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) // two validators can't have the same owner address @@ -161,8 +161,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -181,8 +181,8 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Owner) assert.Equal(t, pk, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator @@ -294,7 +294,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here - unbondShares := sdk.NewDec(10, 0) + unbondShares := sdk.NewDec(10) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) numUnbonds := 5 @@ -338,7 +338,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } for _, c := range errorCases { - unbondShares := sdk.NewDec(int64(c), 0) + unbondShares := sdk.NewDec(int64(c)) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "expected unbond msg to fail") @@ -347,14 +347,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have - unbondShares = sdk.NewDec(leftBonded+1, 0) + unbondShares = sdk.NewDec(leftBonded + 1) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have - unbondShares = sdk.NewDec(leftBonded, 0) + unbondShares = sdk.NewDec(leftBonded) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), @@ -390,7 +390,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10, 0)) // remove delegation + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -435,7 +435,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -466,7 +466,7 @@ func TestRevokeValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10, 0)) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -482,7 +482,7 @@ func TestRevokeValidator(t *testing.T) { require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds - msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10, 0)) + msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -509,7 +509,7 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") @@ -564,7 +564,7 @@ func TestRedelegationPeriod(t *testing.T) { bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10, 0)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) @@ -616,12 +616,12 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10, 0)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10, 0)) + msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) @@ -662,7 +662,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -784,7 +784,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -797,7 +797,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50, 0)) + msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -831,22 +831,22 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx = ctx.WithBlockHeight(1) // begin unbonding 4 stake - msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4, 0)) + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // begin redelegate 6 stake - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6, 0)) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(6, 0), delegation.Shares) + require.Equal(t, sdk.NewDec(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -861,16 +861,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3, 0), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced by half validator, found := keeper.GetValidator(ctx, valA) require.True(t, found) - require.Equal(t, sdk.NewDec(5, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) @@ -885,7 +885,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3, 0), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced to zero // ergo validator should have been removed from the store diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 1a05ec1cee53..79d50ac18fcc 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -31,7 +31,7 @@ func TestDelegation(t *testing.T) { bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], - Shares: sdk.NewDec(9, 0), + Shares: sdk.NewDec(9), } // check the empty keeper first @@ -45,18 +45,18 @@ func TestDelegation(t *testing.T) { require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewDec(99, 0) + bond1to1.Shares = sdk.NewDec(99) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9, 0), 0} - bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9, 0), 1} - bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9, 0), 2} - bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9, 0), 3} - bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9, 0), 4} + bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9), 0} + bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9), 1} + bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9), 2} + bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9), 3} + bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9), 4} keeper.SetDelegation(ctx, bond1to2) keeper.SetDelegation(ctx, bond1to3) keeper.SetDelegation(ctx, bond2to1) @@ -141,7 +141,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -163,7 +163,7 @@ func TestUnbondDelegation(t *testing.T) { var err error var amount sdk.Dec - amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6, 0)) + amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) require.NoError(t, err) require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation @@ -189,8 +189,8 @@ func TestGetRedelegationsFromValidator(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewDec(5, 0), - SharesDst: sdk.NewDec(5, 0), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // set and retrieve a record @@ -219,8 +219,8 @@ func TestRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: 0, - SharesSrc: sdk.NewDec(5, 0), - SharesDst: sdk.NewDec(5, 0), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // test shouldn't have and redelegations @@ -241,8 +241,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewDec(21, 0) - rd.SharesDst = sdk.NewDec(21, 0) + rd.SharesSrc = sdk.NewDec(21) + rd.SharesDst = sdk.NewDec(21) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index c29c75f86604..9307ddddf252 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = sdk.NewDec(777, 0) + expPool.BondedTokens = sdk.NewDec(777) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index e919a0629851..856c43531fc8 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -28,7 +28,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewDec(power, 0).Mul(slashFactor) + slashAmount := sdk.NewDec(power).Mul(slashFactor) // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -166,7 +166,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount, 0).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -210,7 +210,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount, 0).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index ab6f4b86e89f..05b98a05f5cb 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -18,7 +18,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewDec(amt*int64(numVals), 0) + pool.LooseTokens = sdk.NewDec(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { @@ -62,7 +62,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -105,7 +105,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -115,8 +115,8 @@ func TestSlashRedelegation(t *testing.T) { CreationHeight: 0, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewDec(10, 0), - SharesDst: sdk.NewDec(10, 0), + SharesSrc: sdk.NewDec(10), + SharesDst: sdk.NewDec(10), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), Balance: sdk.NewInt64Coin(params.BondDenom, 10), } @@ -126,7 +126,7 @@ func TestSlashRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(10, 0), + Shares: sdk.NewDec(10), } keeper.SetDelegation(ctx, del) @@ -171,7 +171,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -179,7 +179,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -192,16 +192,16 @@ func TestSlashAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // power decreased - require.Equal(t, sdk.NewDec(5, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewDec(5, 0).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + require.Equal(t, sdk.NewDec(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -238,7 +238,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(7, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(7), validator.GetPower()) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -255,7 +255,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(4, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -275,7 +275,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(1, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(1), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -302,7 +302,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -311,8 +311,8 @@ func TestSlashWithRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 11, MinTime: 0, - SharesSrc: sdk.NewDec(6, 0), - SharesDst: sdk.NewDec(6, 0), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -322,13 +322,13 @@ func TestSlashWithRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6, 0), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, del) // update bonded tokens pool := keeper.GetPool(ctx) - pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6, 0)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6)) keeper.SetPool(ctx, pool) // slash validator @@ -354,7 +354,7 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(8, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(8), validator.GetPower()) // slash the validator again ctx = ctx.WithBlockHeight(12) @@ -375,7 +375,7 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 4 - require.Equal(t, sdk.NewDec(4, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) @@ -423,7 +423,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(5, 1) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rdA := types.Redelegation{ @@ -433,8 +433,8 @@ func TestSlashBoth(t *testing.T) { CreationHeight: 11, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: 0, - SharesSrc: sdk.NewDec(6, 0), - SharesDst: sdk.NewDec(6, 0), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -444,7 +444,7 @@ func TestSlashBoth(t *testing.T) { delA := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6, 0), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, delA) @@ -482,5 +482,5 @@ func TestSlashBoth(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, sdk.NewDec(10, 0), validator.GetPower()) + require.Equal(t, sdk.NewDec(10), validator.GetPower()) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index f7ef32cf4d41..0470c28988a4 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -80,7 +80,7 @@ func ParamsNoInflation() types.Params { InflationRateChange: sdk.ZeroDec(), InflationMax: sdk.ZeroDec(), InflationMin: sdk.ZeroDec(), - GoalBonded: sdk.NewDec(67, 2), + GoalBonded: sdk.NewDecWithPrec(67, 2), MaxValidators: 100, BondDenom: "steak", } @@ -119,7 +119,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins, 0)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins)) keeper.SetPool(ctx, pool) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 31dbb4a83e54..7d5fec95ad5c 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -19,8 +19,8 @@ func TestSetValidator(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -28,8 +28,8 @@ func TestSetValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -55,8 +55,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewDec(10000, 0) - pool.BondedTokens = sdk.NewDec(1234, 0) + pool.LooseTokens = sdk.NewDec(10000) + pool.BondedTokens = sdk.NewDec(1234) keeper.SetPool(ctx, pool) // add a validator @@ -75,7 +75,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares - validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2, 0))) + validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out @@ -125,9 +125,9 @@ func TestValidatorBasics(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) } - assert.True(sdk.DecEq(t, sdk.NewDec(9, 0), validators[0].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(8, 0), validators[1].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(7, 0), validators[2].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(8), validators[1].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(7), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -148,15 +148,15 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.DecEq(t, sdk.NewDec(9, 0), validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].BondedTokens())) pool = keeper.GetPool(ctx) assert.True(sdk.DecEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(10, 0) - validators[0].DelegatorShares = sdk.NewDec(10, 0) + validators[0].Tokens = sdk.NewDec(10) + validators[0].DelegatorShares = sdk.NewDec(10) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -199,19 +199,19 @@ func GetValidatorSortingUnmixed(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewDec(amt, 0) - validators[i].DelegatorShares = sdk.NewDec(amt, 0) + validators[i].Tokens = sdk.NewDec(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) keeper.UpdateValidator(ctx, validators[i]) } // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400, 0), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200, 0), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100, 0), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0, 0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDecWithPrec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -219,14 +219,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewDec(500, 0) + validators[3].Tokens = sdk.NewDec(500) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewDec(300, 0) + validators[3].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -234,7 +234,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewDec(200, 0) + validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -253,8 +253,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewDec(300, 0) - validators[4].Tokens = sdk.NewDec(300, 0) + validators[3].Tokens = sdk.NewDec(300) + validators[4].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -287,14 +287,14 @@ func GetValidatorSortingMixed(t *testing.T) { validators[0].Status = sdk.Bonded validators[1].Status = sdk.Bonded validators[2].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(amts[0], 0) - validators[1].Tokens = sdk.NewDec(amts[1], 0) - validators[2].Tokens = sdk.NewDec(amts[2], 0) + validators[0].Tokens = sdk.NewDec(amts[0]) + validators[1].Tokens = sdk.NewDec(amts[1]) + validators[2].Tokens = sdk.NewDec(amts[2]) validators[3].Status = sdk.Bonded validators[4].Status = sdk.Bonded - validators[3].Tokens = sdk.NewDec(amts[3], 0) - validators[4].Tokens = sdk.NewDec(amts[4], 0) + validators[3].Tokens = sdk.NewDec(amts[3]) + validators[4].Tokens = sdk.NewDec(amts[4]) for i := range amts { keeper.UpdateValidator(ctx, validators[i]) @@ -318,11 +318,11 @@ func GetValidatorSortingMixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400, 0), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200, 0), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100, 0), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0, 0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDecWithPrec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -387,7 +387,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201, 0)) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -599,7 +599,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(600, 0) + validators[0].Tokens = sdk.NewDec(600) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -737,21 +737,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power - require.Equal(t, sdk.NewDec(100, 0).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(100, 0).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[1].GetPower().RoundInt64()) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} pool := keeper.GetPool(ctx) - validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20, 0)) - validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30, 0)) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) // power has changed - require.Equal(t, sdk.NewDec(80, 0).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(70, 0).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 209239745017..f402d765fc0e 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -132,7 +132,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewDecFromInt(amount, 0), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -191,7 +191,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation DelegatorAddr: delegatorAddress, ValidatorSrcAddr: sourceValidatorAddress, ValidatorDstAddr: destValidatorAddress, - SharesAmount: sdk.NewDecFromInt(amount, 0), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 0)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64())) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index 9c10e78c5105..db4dd77233b1 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -11,19 +11,19 @@ func TestDelegationEqual(t *testing.T) { d1 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100, 0), + Shares: sdk.NewDec(100), } d2 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100, 0), + Shares: sdk.NewDec(100), } ok := d1.Equal(d2) require.True(t, ok) d2.ValidatorAddr = addr3 - d2.Shares = sdk.NewDec(200, 0) + d2.Shares = sdk.NewDec(200) ok = d1.Equal(d2) require.False(t, ok) @@ -33,7 +33,7 @@ func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100, 0), + Shares: sdk.NewDec(100), } // NOTE: Being that the validator's keypair is random, we cannot test the @@ -91,8 +91,8 @@ func TestRedelegationEqual(t *testing.T) { ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewDec(10, 0) - r2.SharesSrc = sdk.NewDec(20, 0) + r2.SharesDst = sdk.NewDec(10) + r2.SharesSrc = sdk.NewDec(20) r2.MinTime = 20 * 20 * 2 ok = r1.Equal(r2) @@ -104,8 +104,8 @@ func TestRedelegationHumanReadableString(t *testing.T) { DelegatorAddr: addr1, ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, - SharesDst: sdk.NewDec(10, 0), - SharesSrc: sdk.NewDec(20, 0), + SharesDst: sdk.NewDec(10), + SharesSrc: sdk.NewDec(20), } // NOTE: Being that the validator's keypair is random, we cannot test the diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index fea05f9af3fa..fd181af3c927 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -26,27 +26,27 @@ func TestGetInflation(t *testing.T) { setInflation, expectedChange sdk.Dec }{ // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)}, + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), + {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDec(10, 2), - sdk.OneDec().Sub(sdk.NewDec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, + {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDecWithPrec(10, 2), + sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(7, 2), sdk.ZeroDec()}, - {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDec(70001, 6), sdk.NewDec(-1, 6)}, + {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()}, + {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(20, 2), sdk.ZeroDec()}, - {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDec(199999, 6), sdk.NewDec(1, 6)}, + {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()}, + {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)}, // perfect balance shouldn't change inflation - {"test 8", sdk.NewDec(67, 0), sdk.NewDec(33, 0), sdk.NewDec(15, 2), sdk.ZeroDec()}, + {"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -69,7 +69,7 @@ func TestProcessProvisions(t *testing.T) { initialTotalTokens int64 = 550000000 cumulativeExpProvs = sdk.ZeroDec() ) - pool.LooseTokens = sdk.NewDec(initialTotalTokens, 0) + pool.LooseTokens = sdk.NewDec(initialTotalTokens) // process the provisions for a year for hr := 0; hr < 100; hr++ { @@ -79,7 +79,7 @@ func TestProcessProvisions(t *testing.T) { } //get the pool and do the final value checks from checkFinalPoolValues - checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens, 0), cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs) } //_________________________________________________________________________________________ @@ -113,12 +113,12 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation switch { //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)): + case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.LT(sdk.NewDecWithPrec(20, 2)): require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(20, 2)): - if previousInflation.Equal(sdk.NewDec(20, 2)) { + case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.Equal(sdk.NewDecWithPrec(20, 2)): + if previousInflation.Equal(sdk.NewDecWithPrec(20, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) @@ -127,12 +127,15 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation } //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.LT(sdk.NewDec(20, 2)) && updatedInflation.GT(sdk.NewDec(7, 2)): + case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && + updatedInflation.LT(sdk.NewDecWithPrec(20, 2)) && updatedInflation.GT(sdk.NewDecWithPrec(7, 2)): require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewDec(67, 2)) && updatedInflation.Equal(sdk.NewDec(7, 2)): - if previousInflation.Equal(sdk.NewDec(7, 2)) { + case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && + updatedInflation.Equal(sdk.NewDecWithPrec(7, 2)): + + if previousInflation.Equal(sdk.NewDecWithPrec(7, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 1831a47ebdb4..2be34fb20754 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -146,12 +146,12 @@ func TestMsgBeginRedelegate(t *testing.T) { sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewDec(1, 1), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewDec(-1, 1), false}, + {"regular", addr1, addr2, addr3, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", addr1, addr2, addr3, sdk.NewDecWithPrec(-1, 1), false}, {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDec(1, 1), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDec(1, 1), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDec(1, 1), false}, + {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { @@ -198,11 +198,11 @@ func TestMsgBeginUnbonding(t *testing.T) { sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, sdk.NewDec(1, 1), true}, - {"negative decimal", addr1, addr2, sdk.NewDec(-1, 1), false}, + {"regular", addr1, addr2, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", addr1, addr2, sdk.NewDecWithPrec(-1, 1), false}, {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewDec(1, 1), false}, - {"empty validator", addr1, emptyAddr, sdk.NewDec(1, 1), false}, + {"empty delegator", emptyAddr, addr1, sdk.NewDecWithPrec(1, 1), false}, + {"empty validator", addr1, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 979f1aa99b16..c2e28bbddfc1 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -33,10 +33,10 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationRateChange: sdk.NewDec(13, 2), - InflationMax: sdk.NewDec(20, 2), - InflationMin: sdk.NewDec(7, 2), - GoalBonded: sdk.NewDec(67, 2), + InflationRateChange: sdk.NewDecWithPrec(13, 2), + InflationMax: sdk.NewDecWithPrec(20, 2), + InflationMin: sdk.NewDecWithPrec(7, 2), + GoalBonded: sdk.NewDecWithPrec(67, 2), UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 95e2141a41cc..04325a4fbf52 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -33,7 +33,7 @@ func InitialPool() Pool { LooseTokens: sdk.ZeroDec(), BondedTokens: sdk.ZeroDec(), InflationLastTime: 0, - Inflation: sdk.NewDec(7, 2), + Inflation: sdk.NewDecWithPrec(7, 2), DateLastCommissionReset: 0, PrevBondedShares: sdk.ZeroDec(), } @@ -80,8 +80,8 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool { //_______________________________________________________________________ // Inflation -const precision = 10000 // increased to this precision for accuracy -var hrsPerYrDec = sdk.NewDec(8766, 0) // as defined by a julian year of 365.25 days +const precision = 10000 // increased to this precision for accuracy +var hrsPerYrDec = sdk.NewDec(8766) // as defined by a julian year of 365.25 days // process provisions for an hour period func (p Pool) ProcessProvisions(params Params) Pool { diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index c2c99327bc44..4541edd3d9c7 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -11,28 +11,28 @@ func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() require.True(t, p1.Equal(p2)) - p2.BondedTokens = sdk.NewDec(3, 0) + p2.BondedTokens = sdk.NewDec(3) require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) - pool.BondedTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.looseTokensToBonded(sdk.NewDec(10, 0)) + pool = pool.looseTokensToBonded(sdk.NewDec(10)) - require.True(sdk.DecEq(t, sdk.NewDec(20, 0), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(0, 0), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(20), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) - pool.BondedTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.bondedTokensToLoose(sdk.NewDec(5, 0)) + pool = pool.bondedTokensToLoose(sdk.NewDec(5)) - require.True(sdk.DecEq(t, sdk.NewDec(5, 0), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(15, 0), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(5), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(15), pool.LooseTokens)) } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index ae55f930055a..c9626b5ec5ca 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -380,7 +380,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, s // bondedShare/delegatedShare exRate := v.DelegatorShareExRate() - amountDec := sdk.NewDec(amount, 0) + amountDec := sdk.NewDec(amount) if v.Status == sdk.Bonded { pool = pool.looseTokensToBonded(amountDec) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 690628f5b348..e92e02b96ede 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -74,8 +74,8 @@ func TestRemoveTokens(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100, 0), - DelegatorShares: sdk.NewDec(100, 0), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } pool := InitialPool() @@ -150,8 +150,8 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100, 0), - DelegatorShares: sdk.NewDec(100, 0), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } poolA := InitialPool() poolA.LooseTokens = sdk.NewDec(10, 0) @@ -202,7 +202,7 @@ func TestRemoveDelShares(t *testing.T) { func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(100, 0) + pool.LooseTokens = sdk.NewDec(100) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) @@ -235,7 +235,7 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewDec(100, 0), + LooseTokens: sdk.NewDec(100), BondedTokens: poolTokens, InflationLastTime: 0, Inflation: sdk.NewDec(7, 2), From fd526031b7edda4ad35cc7fb9d5a51e6b201f27a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 14:18:51 -0400 Subject: [PATCH 41/50] val comments --- types/decimal.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 128b3b17b247..a6a7362488ee 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -26,7 +26,7 @@ const ( var ( precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) - fivePrecision = new(big.Int).Mul(big.NewInt(5), precisionReuse) + fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) precisionMultipliers []*big.Int zeroInt = big.NewInt(0) tenInt = big.NewInt(10) @@ -176,7 +176,7 @@ func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // great func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // Is equal to zero +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // reverse the decimal sign // addition func (d Dec) Add(d2 Dec) Dec { From b7aaac54a72e7eb5483f8dddd679987c0d2c7a87 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 14:22:01 -0400 Subject: [PATCH 42/50] rebasing start --- client/context/context.go | 115 ++++++++ client/context/errors.go | 13 + client/context/query.go | 311 ++++++++++++++++++++++ client/flags.go | 1 - client/keys/utils.go | 51 +++- client/lcd/lcd_test.go | 128 +++++++-- client/lcd/root.go | 20 +- client/lcd/test_helpers.go | 7 +- client/lcd/version.go | 5 +- client/rpc/block.go | 28 +- client/rpc/root.go | 14 +- client/rpc/status.go | 18 +- client/rpc/validators.go | 25 +- client/tx/broadcast.go | 4 +- client/tx/query.go | 35 +-- client/tx/root.go | 6 +- client/tx/search.go | 37 ++- client/tx/sign.go | 4 +- client/utils/utils.go | 60 +++++ x/auth/client/cli/account.go | 34 +-- x/auth/client/context/context.go | 152 +++++++++++ x/auth/client/context/utils.go | 25 ++ x/auth/client/rest/query.go | 15 +- x/auth/stdtx.go | 8 +- x/bank/app_test.go | 24 +- x/bank/client/cli/sendtx.go | 47 ++-- x/bank/client/rest/sendtx.go | 32 +-- x/distribution/keeper.go | 91 +++++++ x/distribution/keeper_test.go | 31 +++ x/distribution/movement.go | 72 ++++++ x/distribution/types.go | 107 ++++++++ x/gov/client/cli/tx.go | 120 ++++----- x/gov/client/rest/rest.go | 96 ++++--- x/gov/client/rest/util.go | 25 +- x/gov/endblocker_test.go | 4 + x/gov/genesis.go | 6 +- x/gov/handler.go | 6 +- x/gov/keeper.go | 1 + x/gov/procedures.go | 6 +- x/gov/proposals.go | 65 ++++- x/gov/tally.go | 39 +-- x/gov/tally_test.go | 38 ++- x/gov/test_common.go | 2 +- x/ibc/client/cli/ibctx.go | 31 ++- x/ibc/client/cli/relay.go | 42 +-- x/ibc/client/rest/transfer.go | 32 +-- x/params/keeper.go | 12 +- x/params/keeper_test.go | 16 +- x/slashing/app_test.go | 4 +- x/slashing/client/cli/query.go | 10 +- x/slashing/client/cli/tx.go | 24 +- x/slashing/client/rest/query.go | 15 +- x/slashing/client/rest/rest.go | 10 +- x/slashing/client/rest/tx.go | 26 +- x/slashing/genesis.go | 14 + x/slashing/handler.go | 2 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper.go | 69 ++++- x/slashing/keeper_test.go | 70 ++--- x/slashing/params.go | 32 +-- x/slashing/signing_info.go | 13 +- x/slashing/signing_info_test.go | 5 +- x/slashing/test_common.go | 3 +- x/slashing/tick.go | 8 +- x/slashing/tick_test.go | 43 +-- x/stake/app_test.go | 18 +- x/stake/client/cli/query.go | 117 ++++++--- x/stake/client/cli/tx.go | 197 ++++++++------ x/stake/client/rest/query.go | 417 ++++++++++++++++++++++++------ x/stake/client/rest/rest.go | 12 +- x/stake/client/rest/tx.go | 67 +++-- x/stake/client/rest/utils.go | 228 ++++++++++++++++ x/stake/genesis_test.go | 20 +- x/stake/handler.go | 4 +- x/stake/handler_test.go | 83 +++--- x/stake/keeper/delegation.go | 18 +- x/stake/keeper/delegation_test.go | 39 +-- x/stake/keeper/keeper_test.go | 2 +- x/stake/keeper/key.go | 49 ++-- x/stake/keeper/sdk_types.go | 2 +- x/stake/keeper/slash.go | 28 +- x/stake/keeper/slash_test.go | 79 +++--- x/stake/keeper/test_common.go | 10 +- x/stake/keeper/validator.go | 100 ++++++- x/stake/keeper/validator_test.go | 153 +++++++---- x/stake/simulation/invariants.go | 4 +- x/stake/simulation/msgs.go | 6 +- x/stake/types/delegation.go | 23 +- x/stake/types/delegation_test.go | 21 +- x/stake/types/errors.go | 10 +- x/stake/types/inflation_test.go | 65 +++-- x/stake/types/msg.go | 26 +- x/stake/types/msg_test.go | 26 +- x/stake/types/params.go | 21 +- x/stake/types/pool.go | 53 ++-- x/stake/types/pool_test.go | 22 +- x/stake/types/validator.go | 88 +++---- x/stake/types/validator_test.go | 84 +++--- 98 files changed, 3288 insertions(+), 1215 deletions(-) create mode 100644 client/context/context.go create mode 100644 client/context/errors.go create mode 100644 client/context/query.go create mode 100644 client/utils/utils.go create mode 100644 x/auth/client/context/context.go create mode 100644 x/auth/client/context/utils.go create mode 100644 x/distribution/keeper.go create mode 100644 x/distribution/keeper_test.go create mode 100644 x/distribution/movement.go create mode 100644 x/distribution/types.go create mode 100644 x/slashing/genesis.go create mode 100644 x/stake/client/rest/utils.go diff --git a/client/context/context.go b/client/context/context.go new file mode 100644 index 000000000000..1b0443b0c7c7 --- /dev/null +++ b/client/context/context.go @@ -0,0 +1,115 @@ +package context + +import ( + "io" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + + "github.com/spf13/viper" + + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +const ctxAccStoreName = "acc" + +// CLIContext implements a typical CLI context created in SDK modules for +// transaction handling and queries. +type CLIContext struct { + Codec *wire.Codec + AccDecoder auth.AccountDecoder + Client rpcclient.Client + Logger io.Writer + Height int64 + NodeURI string + FromAddressName string + AccountStore string + TrustNode bool + UseLedger bool + Async bool + JSON bool + PrintResponse bool +} + +// NewCLIContext returns a new initialized CLIContext with parameters from the +// command line using Viper. +func NewCLIContext() CLIContext { + var rpc rpcclient.Client + + nodeURI := viper.GetString(client.FlagNode) + if nodeURI != "" { + rpc = rpcclient.NewHTTP(nodeURI, "/websocket") + } + + return CLIContext{ + Client: rpc, + NodeURI: nodeURI, + AccountStore: ctxAccStoreName, + FromAddressName: viper.GetString(client.FlagFrom), + Height: viper.GetInt64(client.FlagHeight), + TrustNode: viper.GetBool(client.FlagTrustNode), + UseLedger: viper.GetBool(client.FlagUseLedger), + Async: viper.GetBool(client.FlagAsync), + JSON: viper.GetBool(client.FlagJson), + PrintResponse: viper.GetBool(client.FlagPrintResponse), + } +} + +// WithCodec returns a copy of the context with an updated codec. +func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext { + ctx.Codec = cdc + return ctx +} + +// WithAccountDecoder returns a copy of the context with an updated account +// decoder. +func (ctx CLIContext) WithAccountDecoder(decoder auth.AccountDecoder) CLIContext { + ctx.AccDecoder = decoder + return ctx +} + +// WithLogger returns a copy of the context with an updated logger. +func (ctx CLIContext) WithLogger(w io.Writer) CLIContext { + ctx.Logger = w + return ctx +} + +// WithAccountStore returns a copy of the context with an updated AccountStore. +func (ctx CLIContext) WithAccountStore(accountStore string) CLIContext { + ctx.AccountStore = accountStore + return ctx +} + +// WithFromAddressName returns a copy of the context with an updated from +// address. +func (ctx CLIContext) WithFromAddressName(addrName string) CLIContext { + ctx.FromAddressName = addrName + return ctx +} + +// WithTrustNode returns a copy of the context with an updated TrustNode flag. +func (ctx CLIContext) WithTrustNode(trustNode bool) CLIContext { + ctx.TrustNode = trustNode + return ctx +} + +// WithNodeURI returns a copy of the context with an updated node URI. +func (ctx CLIContext) WithNodeURI(nodeURI string) CLIContext { + ctx.NodeURI = nodeURI + ctx.Client = rpcclient.NewHTTP(nodeURI, "/websocket") + return ctx +} + +// WithClient returns a copy of the context with an updated RPC client +// instance. +func (ctx CLIContext) WithClient(client rpcclient.Client) CLIContext { + ctx.Client = client + return ctx +} + +// WithUseLedger returns a copy of the context with an updated UseLedger flag. +func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { + ctx.UseLedger = useLedger + return ctx +} diff --git a/client/context/errors.go b/client/context/errors.go new file mode 100644 index 000000000000..9c611494a5b3 --- /dev/null +++ b/client/context/errors.go @@ -0,0 +1,13 @@ +package context + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pkg/errors" +) + +// ErrInvalidAccount returns a standardized error reflecting that a given +// account address does not exist. +func ErrInvalidAccount(addr sdk.AccAddress) error { + return errors.Errorf(`No account with address %s was found in the state. +Are you sure there has been a transaction involving it?`, addr) +} diff --git a/client/context/query.go b/client/context/query.go new file mode 100644 index 000000000000..081f723b5c9c --- /dev/null +++ b/client/context/query.go @@ -0,0 +1,311 @@ +package context + +import ( + "fmt" + "io" + + "github.com/cosmos/cosmos-sdk/client/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + + "github.com/pkg/errors" + + "github.com/tendermint/tendermint/libs/common" + cmn "github.com/tendermint/tendermint/libs/common" + rpcclient "github.com/tendermint/tendermint/rpc/client" + ctypes "github.com/tendermint/tendermint/rpc/core/types" +) + +// GetNode returns an RPC client. If the context's client is not defined, an +// error is returned. +func (ctx CLIContext) GetNode() (rpcclient.Client, error) { + if ctx.Client == nil { + return nil, errors.New("no RPC client defined") + } + + return ctx.Client, nil +} + +// Query performs a query for information about the connected node. +func (ctx CLIContext) Query(path string) (res []byte, err error) { + return ctx.query(path, nil) +} + +// QueryStore performs a query from a Tendermint node with the provided key and +// store name. +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) { + return ctx.queryStore(key, storeName, "key") +} + +// QuerySubspace performs a query from a Tendermint node with the provided +// store name and subspace. +func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, err error) { + resRaw, err := ctx.queryStore(subspace, storeName, "subspace") + if err != nil { + return res, err + } + + ctx.Codec.MustUnmarshalBinary(resRaw, &res) + return +} + +// GetAccount queries for an account given an address and a block height. An +// error is returned if the query or decoding fails. +func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) { + if ctx.AccDecoder == nil { + return nil, errors.New("account decoder required but not provided") + } + + res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore) + if err != nil { + return nil, err + } else if len(res) == 0 { + return nil, err + } + + account, err := ctx.AccDecoder(res) + if err != nil { + return nil, err + } + + return account, nil +} + +// GetFromAddress returns the from address from the context's name. +func (ctx CLIContext) GetFromAddress() (from sdk.AccAddress, err error) { + if ctx.FromAddressName == "" { + return nil, errors.Errorf("must provide a from address name") + } + + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + info, err := keybase.Get(ctx.FromAddressName) + if err != nil { + return nil, errors.Errorf("no key for: %s", ctx.FromAddressName) + } + + return sdk.AccAddress(info.GetPubKey().Address()), nil +} + +// GetAccountNumber returns the next account number for the given account +// address. +func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) { + account, err := ctx.GetAccount(address) + if err != nil { + return 0, err + } + + return account.GetAccountNumber(), nil +} + +// GetAccountSequence returns the sequence number for the given account +// address. +func (ctx CLIContext) GetAccountSequence(address []byte) (int64, error) { + account, err := ctx.GetAccount(address) + if err != nil { + return 0, err + } + + return account.GetSequence(), nil +} + +// BroadcastTx broadcasts transaction bytes to a Tendermint node. +func (ctx CLIContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, err + } + + res, err := node.BroadcastTxCommit(tx) + if err != nil { + return res, err + } + + if !res.CheckTx.IsOK() { + return res, errors.Errorf("checkTx failed: (%d) %s", + res.CheckTx.Code, + res.CheckTx.Log) + } + + if !res.DeliverTx.IsOK() { + return res, errors.Errorf("deliverTx failed: (%d) %s", + res.DeliverTx.Code, + res.DeliverTx.Log) + } + + return res, err +} + +// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node +// asynchronously. +func (ctx CLIContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, err + } + + res, err := node.BroadcastTxAsync(tx) + if err != nil { + return res, err + } + + return res, err +} + +// EnsureAccountExists ensures that an account exists for a given context. An +// error is returned if it does not. +func (ctx CLIContext) EnsureAccountExists() error { + addr, err := ctx.GetFromAddress() + if err != nil { + return err + } + + accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore) + if err != nil { + return err + } + + if len(accountBytes) == 0 { + return ErrInvalidAccount(addr) + } + + return nil +} + +// EnsureAccountExistsFromAddr ensures that an account exists for a given +// address. Instead of using the context's from name, a direct address is +// given. An error is returned if it does not. +func (ctx CLIContext) EnsureAccountExistsFromAddr(addr sdk.AccAddress) error { + accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore) + if err != nil { + return err + } + + if len(accountBytes) == 0 { + return ErrInvalidAccount(addr) + } + + return nil +} + +// EnsureBroadcastTx broadcasts a transactions either synchronously or +// asynchronously based on the context parameters. The result of the broadcast +// is parsed into an intermediate structure which is logged if the context has +// a logger defined. +func (ctx CLIContext) EnsureBroadcastTx(txBytes []byte) error { + if ctx.Async { + return ctx.ensureBroadcastTxAsync(txBytes) + } + + return ctx.ensureBroadcastTx(txBytes) +} + +func (ctx CLIContext) ensureBroadcastTxAsync(txBytes []byte) error { + res, err := ctx.BroadcastTxAsync(txBytes) + if err != nil { + return err + } + + if ctx.JSON { + type toJSON struct { + TxHash string + } + + if ctx.Logger != nil { + resJSON := toJSON{res.Hash.String()} + bz, err := ctx.Codec.MarshalJSON(resJSON) + if err != nil { + return err + } + + ctx.Logger.Write(bz) + io.WriteString(ctx.Logger, "\n") + } + } else { + if ctx.Logger != nil { + io.WriteString(ctx.Logger, fmt.Sprintf("Async tx sent (tx hash: %s)\n", res.Hash)) + } + } + + return nil +} + +func (ctx CLIContext) ensureBroadcastTx(txBytes []byte) error { + res, err := ctx.BroadcastTx(txBytes) + if err != nil { + return err + } + + if ctx.JSON { + // since JSON is intended for automated scripts, always include + // response in JSON mode. + type toJSON struct { + Height int64 + TxHash string + Response string + } + + if ctx.Logger != nil { + resJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", res.DeliverTx)} + bz, err := ctx.Codec.MarshalJSON(resJSON) + if err != nil { + return err + } + + ctx.Logger.Write(bz) + io.WriteString(ctx.Logger, "\n") + } + + return nil + } + + if ctx.Logger != nil { + resStr := fmt.Sprintf("Committed at block %d (tx hash: %s)\n", res.Height, res.Hash.String()) + + if ctx.PrintResponse { + resStr = fmt.Sprintf("Committed at block %d (tx hash: %s, response: %+v)\n", + res.Height, res.Hash.String(), res.DeliverTx, + ) + } + + io.WriteString(ctx.Logger, resStr) + } + + return nil +} + +// query performs a query from a Tendermint node with the provided store name +// and path. +func (ctx CLIContext) query(path string, key common.HexBytes) (res []byte, err error) { + node, err := ctx.GetNode() + if err != nil { + return res, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: ctx.Height, + Trusted: ctx.TrustNode, + } + + result, err := node.ABCIQueryWithOptions(path, key, opts) + if err != nil { + return res, err + } + + resp := result.Response + if !resp.IsOK() { + return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log) + } + + return resp.Value, nil +} + +// queryStore performs a query from a Tendermint node with the provided a store +// name and path. +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) { + path := fmt.Sprintf("/store/%s/%s", storeName, endPath) + return ctx.query(path, key) +} diff --git a/client/flags.go b/client/flags.go index b96012da7daf..8616f9e78d4a 100644 --- a/client/flags.go +++ b/client/flags.go @@ -42,7 +42,6 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { func PostCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { c.Flags().String(FlagFrom, "", "Name of private key with which to sign") - c.Flags().String(FlagName, "", "DEPRECATED - Name of private key with which to sign") c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx") c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") c.Flags().String(FlagMemo, "", "Memo to send along with transaction") diff --git a/client/keys/utils.go b/client/keys/utils.go index 5462597bac66..907f9eda807c 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -29,6 +29,55 @@ func GetKeyBase() (keys.Keybase, error) { return GetKeyBaseFromDir(rootDir) } +// GetKeyInfo returns key info for a given name. An error is returned if the +// keybase cannot be retrieved or getting the info fails. +func GetKeyInfo(name string) (keys.Info, error) { + keybase, err := GetKeyBase() + if err != nil { + return nil, err + } + + return keybase.Get(name) +} + +// GetPassphrase returns a passphrase for a given name. It will first retrieve +// the key info for that name if the type is local, it'll fetch input from +// STDIN. Otherwise, an empty passphrase is returned. An error is returned if +// the key info cannot be fetched or reading from STDIN fails. +func GetPassphrase(name string) (string, error) { + var passphrase string + + keyInfo, err := GetKeyInfo(name) + if err != nil { + return passphrase, err + } + + // we only need a passphrase for locally stored keys + // TODO: (ref: #864) address security concerns + if keyInfo.GetType() == keys.TypeLocal { + passphrase, err = ReadPassphraseFromStdin(name) + if err != nil { + return passphrase, err + } + } + + return passphrase, nil +} + +// ReadPassphraseFromStdin attempts to read a passphrase from STDIN return an +// error upon failure. +func ReadPassphraseFromStdin(name string) (string, error) { + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password to sign with '%s':", name) + + passphrase, err := client.GetPassword(prompt, buf) + if err != nil { + return passphrase, fmt.Errorf("Error reading passphrase: %v", err) + } + + return passphrase, nil +} + // initialize a keybase based on the configuration func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) { if keybase == nil { @@ -77,7 +126,7 @@ func Bech32KeyOutput(info keys.Info) (KeyOutput, error) { } return KeyOutput{ Name: info.GetName(), - Type: info.GetType(), + Type: info.GetType().String(), Address: account, PubKey: bechPubKey, }, nil diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index b21f483dacf6..cbc1a2c20d7c 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -6,14 +6,15 @@ import ( "net/http" "regexp" "testing" + "time" + + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/common" p2p "github.com/tendermint/tendermint/p2p" ctypes "github.com/tendermint/tendermint/rpc/core/types" @@ -27,6 +28,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) func init() { @@ -316,13 +318,7 @@ func TestTxs(t *testing.T) { res, body = Request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - type txInfo struct { - Hash common.HexBytes `json:"hash"` - Height int64 `json:"height"` - Tx sdk.Tx `json:"tx"` - Result abci.ResponseDeliverTx `json:"result"` - } - var indexedTxs []txInfo + var indexedTxs []tx.Info // check if tx is queryable res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil) @@ -374,6 +370,19 @@ func TestValidatorsQuery(t *testing.T) { require.True(t, foundVal, "pkBech %v, owner %v", pkBech, validators[0].Owner) } +func TestValidatorQuery(t *testing.T) { + cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}) + defer cleanup() + require.Equal(t, 1, len(pks)) + + validator1Owner := sdk.AccAddress(pks[0].Address()) + + validator := getValidator(t, port, validator1Owner) + bech32ValAddress, err := sdk.Bech32ifyValPub(pks[0]) + require.NoError(t, err) + assert.Equal(t, validator.PubKey, bech32ValAddress, "The returned validator does not hold the correct data") +} + func TestBonding(t *testing.T) { name, password, denom := "test", "1234567890", "steak" addr, seed := CreateAddr(t, "test", password, GetKeyBase(t)) @@ -398,7 +407,7 @@ func TestBonding(t *testing.T) { // query validator bond := getDelegation(t, port, addr, validator1Owner) - require.Equal(t, "60.0000000000", bond.Shares.String()) + require.Equal(t, "60.0000000000", bond.Shares) ////////////////////// // testing unbonding @@ -409,7 +418,7 @@ func TestBonding(t *testing.T) { // query validator bond = getDelegation(t, port, addr, validator1Owner) - require.Equal(t, "30.0000000000", bond.Shares.String()) + require.Equal(t, "30.0000000000", bond.Shares) // check if tx was committed require.Equal(t, uint32(0), resultTx.CheckTx.Code) @@ -421,7 +430,33 @@ func TestBonding(t *testing.T) { coins = acc.GetCoins() require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) + // query unbonding delegation + validatorAddr := sdk.AccAddress(pks[0].Address()) + unbondings := getUndelegations(t, port, addr, validatorAddr) + assert.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations") + assert.Equal(t, "30", unbondings[0].Balance.Amount.String()) + + // query summary + summary := getDelegationSummary(t, port, addr) + + assert.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations") + assert.Equal(t, "30.0000000000", summary.Delegations[0].Shares) + assert.Len(t, summary.UnbondingDelegations, 1, "Delegation summary holds all unbonding-delegations") + assert.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String()) + // TODO add redelegation, need more complex capabilities such to mock context and + // TODO check summary for redelegation + // assert.Len(t, summary.Redelegations, 1, "Delegation summary holds all redelegations") + + // query txs + txs := getBondingTxs(t, port, addr, "") + assert.Len(t, txs, 2, "All Txs found") + + txs = getBondingTxs(t, port, addr, "bond") + assert.Len(t, txs, 1, "All bonding txs found") + + txs = getBondingTxs(t, port, addr, "unbond") + assert.Len(t, txs, 1, "All unbonding txs found") } func TestSubmitProposal(t *testing.T) { @@ -530,7 +565,7 @@ func TestUnrevoke(t *testing.T) { signingInfo := getSigningInfo(t, port, pkString) tests.WaitForHeight(4, port) require.Equal(t, true, signingInfo.IndexOffset > 0) - require.Equal(t, int64(0), signingInfo.JailedUntil) + require.Equal(t, time.Unix(0, 0).UTC(), signingInfo.JailedUntil) require.Equal(t, true, signingInfo.SignedBlocksCounter > 0) } @@ -647,7 +682,6 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - // send coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin("steak", 1)) if err != nil { @@ -693,7 +727,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc "account_number":"%d", "sequence": "%d", "gas": "100000", - "chain_id": "%s", + "src_chain_id": "%s", "amount":[ { "denom": "%s", @@ -701,6 +735,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc } ] }`, name, password, accnum, sequence, chainID, "steak")) + res, body := Request(t, port, "POST", fmt.Sprintf("/ibc/testchain/%s/send", receiveAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -719,17 +754,58 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing. return signingInfo } -func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) stake.Delegation { +// ============= Stake Module ================ + +func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) rest.DelegationWithoutRat { // get the account to get the sequence - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/%s/delegation/%s", delegatorAddr, validatorAddr), nil) + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var bond stake.Delegation + var bond rest.DelegationWithoutRat err := cdc.UnmarshalJSON([]byte(body), &bond) require.Nil(t, err) return bond } +func getUndelegations(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) []stake.UnbondingDelegation { + + // get the account to get the sequence + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var unbondings []stake.UnbondingDelegation + err := cdc.UnmarshalJSON([]byte(body), &unbondings) + require.Nil(t, err) + return unbondings +} + +func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) rest.DelegationSummary { + + // get the account to get the sequence + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s", delegatorAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var summary rest.DelegationSummary + err := cdc.UnmarshalJSON([]byte(body), &summary) + require.Nil(t, err) + return summary +} + +func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, query string) []tx.Info { + + // get the account to get the sequence + var res *http.Response + var body string + if len(query) > 0 { + res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs?type=%s", delegatorAddr, query), nil) + } else { + res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs", delegatorAddr), nil) + } + require.Equal(t, http.StatusOK, res.StatusCode, body) + var txs []tx.Info + err := cdc.UnmarshalJSON([]byte(body), &txs) + require.Nil(t, err) + return txs +} + func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { // get the account to get the sequence acc := getAccount(t, port, delegatorAddr) @@ -758,7 +834,7 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, "begin_redelegates": [], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak")) - res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -798,7 +874,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, "begin_redelegates": [], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr)) - res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -839,7 +915,7 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, ], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorSrcAddr, validatorDstAddr)) - res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -859,6 +935,18 @@ func getValidators(t *testing.T, port string) []stake.BechValidator { return validators } +func getValidator(t *testing.T, port string, validatorAddr sdk.AccAddress) stake.BechValidator { + // get the account to get the sequence + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var validator stake.BechValidator + err := cdc.UnmarshalJSON([]byte(body), &validator) + require.Nil(t, err) + return validator +} + +// ============= Governance Module ================ + func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal { res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d", proposalID), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/client/lcd/root.go b/client/lcd/root.go index 7406a30568d4..bfa62f1cf0aa 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -78,21 +78,21 @@ func createHandler(cdc *wire.Codec) http.Handler { panic(err) } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc).WithLogger(os.Stdout) // TODO: make more functional? aka r = keys.RegisterRoutes(r) r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET") - r.HandleFunc("/node_version", NodeVersionRequestHandler(ctx)).Methods("GET") + r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET") keys.RegisterRoutes(r) - rpc.RegisterRoutes(ctx, r) - tx.RegisterRoutes(ctx, r, cdc) - auth.RegisterRoutes(ctx, r, cdc, "acc") - bank.RegisterRoutes(ctx, r, cdc, kb) - ibc.RegisterRoutes(ctx, r, cdc, kb) - stake.RegisterRoutes(ctx, r, cdc, kb) - slashing.RegisterRoutes(ctx, r, cdc, kb) - gov.RegisterRoutes(ctx, r, cdc) + rpc.RegisterRoutes(cliCtx, r) + tx.RegisterRoutes(cliCtx, r, cdc) + auth.RegisterRoutes(cliCtx, r, cdc, "acc") + bank.RegisterRoutes(cliCtx, r, cdc, kb) + ibc.RegisterRoutes(cliCtx, r, cdc, kb) + stake.RegisterRoutes(cliCtx, r, cdc, kb) + slashing.RegisterRoutes(cliCtx, r, cdc, kb) + gov.RegisterRoutes(cliCtx, r, cdc) return r } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index be8b6ddf2c18..ee46b267dd08 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -121,7 +121,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress config.TxIndex.IndexAllTags = true logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - logger = log.NewFilter(logger, log.AllowDebug()) + logger = log.NewFilter(logger, log.AllowError()) privValidatorFile := config.PrivValidatorFile() privVal := pvm.LoadOrGenFilePV(privValidatorFile) @@ -173,7 +173,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewRat(100)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) @@ -223,7 +223,7 @@ func startTM( proxy.NewLocalClientCreator(app), genDocProvider, dbProvider, - nm.DefaultMetricsProvider, + nm.DefaultMetricsProvider(tmcfg.Instrumentation), logger.With("module", "node"), ) if err != nil { @@ -256,6 +256,7 @@ func Request(t *testing.T, port, method, path string, payload []byte) (*http.Res res *http.Response ) url := fmt.Sprintf("http://localhost:%v%v", port, path) + fmt.Println("REQUEST " + method + " " + url) req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) require.Nil(t, err) diff --git a/client/lcd/version.go b/client/lcd/version.go index 4e328b7a0bf2..377d7ca2681f 100644 --- a/client/lcd/version.go +++ b/client/lcd/version.go @@ -15,14 +15,15 @@ func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) { } // connected node version REST handler endpoint -func NodeVersionRequestHandler(ctx context.CoreContext) http.HandlerFunc { +func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - version, err := ctx.Query("/app/version") + version, err := cliCtx.Query("/app/version") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Could't query version. Error: %s", err.Error()))) return } + w.Write(version) } } diff --git a/client/rpc/block.go b/client/rpc/block.go index 3244e8d122a3..fb4376bc1ad5 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -5,11 +5,11 @@ import ( "net/http" "strconv" - "github.com/gorilla/mux" - "github.com/spf13/cobra" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" ) const ( @@ -31,9 +31,9 @@ func BlockCommand() *cobra.Command { return cmd } -func getBlock(ctx context.CoreContext, height *int64) ([]byte, error) { +func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) { // get the node - node, err := ctx.GetNode() + node, err := cliCtx.GetNode() if err != nil { return nil, err } @@ -57,8 +57,8 @@ func getBlock(ctx context.CoreContext, height *int64) ([]byte, error) { } // get the current blockchain height -func GetChainHeight(ctx context.CoreContext) (int64, error) { - node, err := ctx.GetNode() +func GetChainHeight(cliCtx context.CLIContext) (int64, error) { + node, err := cliCtx.GetNode() if err != nil { return -1, err } @@ -86,7 +86,7 @@ func printBlock(cmd *cobra.Command, args []string) error { } } - output, err := getBlock(context.NewCoreContextFromViper(), height) + output, err := getBlock(context.NewCLIContext(), height) if err != nil { return err } @@ -97,7 +97,7 @@ func printBlock(cmd *cobra.Command, args []string) error { // REST // REST handler to get a block -func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) height, err := strconv.ParseInt(vars["height"], 10, 64) @@ -106,13 +106,13 @@ func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'.")) return } - chainHeight, err := GetChainHeight(ctx) + chainHeight, err := GetChainHeight(cliCtx) if height > chainHeight { w.WriteHeader(404) w.Write([]byte("ERROR: Requested block height is bigger then the chain length.")) return } - output, err := getBlock(ctx, &height) + output, err := getBlock(cliCtx, &height) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) @@ -123,15 +123,15 @@ func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { } // REST handler to get the latest block -func LatestBlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - height, err := GetChainHeight(ctx) + height, err := GetChainHeight(cliCtx) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) return } - output, err := getBlock(ctx, &height) + output, err := getBlock(cliCtx, &height) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) diff --git a/client/rpc/root.go b/client/rpc/root.go index bb5a162a7f5c..a8171a293aa3 100644 --- a/client/rpc/root.go +++ b/client/rpc/root.go @@ -44,11 +44,11 @@ func initClientCommand() *cobra.Command { } // Register REST endpoints -func RegisterRoutes(ctx context.CoreContext, r *mux.Router) { - r.HandleFunc("/node_info", NodeInfoRequestHandlerFn(ctx)).Methods("GET") - r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(ctx)).Methods("GET") - r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(ctx)).Methods("GET") - r.HandleFunc("/blocks/{height}", BlockRequestHandlerFn(ctx)).Methods("GET") - r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(ctx)).Methods("GET") - r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(ctx)).Methods("GET") +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/node_info", NodeInfoRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/blocks/{height}", BlockRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(cliCtx)).Methods("GET") } diff --git a/client/rpc/status.go b/client/rpc/status.go index 0c1f415930cf..ea090d32f997 100644 --- a/client/rpc/status.go +++ b/client/rpc/status.go @@ -18,23 +18,25 @@ func statusCommand() *cobra.Command { Short: "Query remote node for status", RunE: printNodeStatus, } + cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") return cmd } -func getNodeStatus(ctx context.CoreContext) (*ctypes.ResultStatus, error) { +func getNodeStatus(cliCtx context.CLIContext) (*ctypes.ResultStatus, error) { // get the node - node, err := ctx.GetNode() + node, err := cliCtx.GetNode() if err != nil { return &ctypes.ResultStatus{}, err } + return node.Status() } // CMD func printNodeStatus(cmd *cobra.Command, args []string) error { - status, err := getNodeStatus(context.NewCoreContextFromViper()) + status, err := getNodeStatus(context.NewCLIContext()) if err != nil { return err } @@ -52,9 +54,9 @@ func printNodeStatus(cmd *cobra.Command, args []string) error { // REST // REST handler for node info -func NodeInfoRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - status, err := getNodeStatus(ctx) + status, err := getNodeStatus(cliCtx) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) @@ -68,14 +70,15 @@ func NodeInfoRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { w.Write([]byte(err.Error())) return } + w.Write(output) } } // REST handler for node syncing -func NodeSyncingRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - status, err := getNodeStatus(ctx) + status, err := getNodeStatus(cliCtx) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) @@ -88,6 +91,7 @@ func NodeSyncingRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { w.Write([]byte(err.Error())) return } + w.Write([]byte(strconv.FormatBool(syncing))) } } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index b8a6c4cc2023..d2daa4ec5cab 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -58,9 +58,9 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error }, nil } -func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { +func getValidators(cliCtx context.CLIContext, height *int64) ([]byte, error) { // get the node - node, err := ctx.GetNode() + node, err := cliCtx.GetNode() if err != nil { return nil, err } @@ -74,6 +74,7 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { BlockHeight: validatorsRes.BlockHeight, Validators: make([]ValidatorOutput, len(validatorsRes.Validators)), } + for i := 0; i < len(validatorsRes.Validators); i++ { outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i]) if err != nil { @@ -85,6 +86,7 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { if err != nil { return nil, err } + return output, nil } @@ -104,7 +106,7 @@ func printValidators(cmd *cobra.Command, args []string) error { } } - output, err := getValidators(context.NewCoreContextFromViper(), height) + output, err := getValidators(context.NewCLIContext(), height) if err != nil { return err } @@ -116,22 +118,25 @@ func printValidators(cmd *cobra.Command, args []string) error { // REST // Validator Set at a height REST handler -func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) + height, err := strconv.ParseInt(vars["height"], 10, 64) if err != nil { w.WriteHeader(400) w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'.")) return } - chainHeight, err := GetChainHeight(ctx) + + chainHeight, err := GetChainHeight(cliCtx) if height > chainHeight { w.WriteHeader(404) w.Write([]byte("ERROR: Requested block height is bigger then the chain length.")) return } - output, err := getValidators(ctx, &height) + + output, err := getValidators(cliCtx, &height) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) @@ -143,20 +148,22 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { } // Latest Validator Set REST handler -func LatestValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - height, err := GetChainHeight(ctx) + height, err := GetChainHeight(cliCtx) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) return } - output, err := getValidators(ctx, &height) + + output, err := getValidators(cliCtx, &height) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) return } + w.Write(output) } } diff --git a/client/tx/broadcast.go b/client/tx/broadcast.go index 21f576db419f..89ad48f43f81 100644 --- a/client/tx/broadcast.go +++ b/client/tx/broadcast.go @@ -13,7 +13,7 @@ type BroadcastTxBody struct { } // BroadcastTx REST Handler -func BroadcastTxRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { +func BroadcastTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var m BroadcastTxBody @@ -25,7 +25,7 @@ func BroadcastTxRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { return } - res, err := ctx.BroadcastTx([]byte(m.TxBytes)) + res, err := cliCtx.BroadcastTx([]byte(m.TxBytes)) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) diff --git a/client/tx/query.go b/client/tx/query.go index dfe626c38cb8..f95776b1092f 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -21,24 +21,25 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" ) -// Get the default command for a tx query +// QueryTxCmd implements the default command for a tx query. func QueryTxCmd(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "tx [hash]", Short: "Matches this txhash over all committed blocks", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // find the key to look up the account hashHexStr := args[0] trustNode := viper.GetBool(client.FlagTrustNode) - output, err := queryTx(cdc, context.NewCoreContextFromViper(), hashHexStr, trustNode) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode) if err != nil { return err } - fmt.Println(string(output)) + fmt.Println(string(output)) return nil }, } @@ -50,14 +51,13 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command { return cmd } -func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustNode bool) ([]byte, error) { +func queryTx(cdc *wire.Codec, cliCtx context.CLIContext, hashHexStr string, trustNode bool) ([]byte, error) { hash, err := hex.DecodeString(hashHexStr) if err != nil { return nil, err } - // get the node - node, err := ctx.GetNode() + node, err := cliCtx.GetNode() if err != nil { return nil, err } @@ -66,6 +66,7 @@ func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustN if err != nil { return nil, err } + info, err := formatTxResult(cdc, res) if err != nil { return nil, err @@ -74,24 +75,23 @@ func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustN return wire.MarshalJSONIndent(cdc, info) } -func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (txInfo, error) { +func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (Info, error) { // TODO: verify the proof if requested tx, err := parseTx(cdc, res.Tx) if err != nil { - return txInfo{}, err + return Info{}, err } - info := txInfo{ + return Info{ Hash: res.Hash, Height: res.Height, Tx: tx, Result: res.TxResult, - } - return info, nil + }, nil } -// txInfo is used to prepare info to display -type txInfo struct { +// Info is used to prepare info to display +type Info struct { Hash common.HexBytes `json:"hash"` Height int64 `json:"height"` Tx sdk.Tx `json:"tx"` @@ -100,17 +100,19 @@ type txInfo struct { func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) { var tx auth.StdTx + err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { return nil, err } + return tx, nil } // REST // transaction query REST handler -func QueryTxRequestHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func QueryTxRequestHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) hashHexStr := vars["hash"] @@ -120,12 +122,13 @@ func QueryTxRequestHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.Hand trustNode = true } - output, err := queryTx(cdc, ctx, hashHexStr, trustNode) + output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) return } + w.Write(output) } } diff --git a/client/tx/root.go b/client/tx/root.go index 5def5a544091..7e18d5aae126 100644 --- a/client/tx/root.go +++ b/client/tx/root.go @@ -17,9 +17,9 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) { } // register REST routes -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { - r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, ctx)).Methods("GET") - r.HandleFunc("/txs", SearchTxRequestHandlerFn(ctx, cdc)).Methods("GET") +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) { + r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, cliCtx)).Methods("GET") + r.HandleFunc("/txs", SearchTxRequestHandlerFn(cliCtx, cdc)).Methods("GET") // r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST") // r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST") } diff --git a/client/tx/search.go b/client/tx/search.go index 76c394f92855..adad29d7dd9d 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -7,15 +7,15 @@ import ( "net/url" "strings" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) const ( @@ -31,14 +31,18 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { tags := viper.GetStringSlice(flagTags) - txs, err := searchTxs(context.NewCoreContextFromViper(), cdc, tags) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + txs, err := searchTxs(cliCtx, cdc, tags) if err != nil { return err } + output, err := cdc.MarshalJSON(txs) if err != nil { return err } + fmt.Println(string(output)) return nil }, @@ -53,19 +57,22 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command { return cmd } -func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInfo, error) { +func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Info, error) { if len(tags) == 0 { return nil, errors.New("must declare at least one tag to search") } + // XXX: implement ANY query := strings.Join(tags, " AND ") + // get the node - node, err := ctx.GetNode() + node, err := cliCtx.GetNode() if err != nil { return nil, err } prove := !viper.GetBool(client.FlagTrustNode) + // TODO: take these as args page := 0 perPage := 100 @@ -74,7 +81,7 @@ func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInf return nil, err } - info, err := formatTxResults(cdc, res.Txs) + info, err := FormatTxResults(cdc, res.Txs) if err != nil { return nil, err } @@ -82,9 +89,10 @@ func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInf return info, nil } -func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) { +// parse the indexed txs into an array of Info +func FormatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]Info, error) { var err error - out := make([]txInfo, len(res)) + out := make([]Info, len(res)) for i := range res { out[i], err = formatTxResult(cdc, res[i]) if err != nil { @@ -98,7 +106,7 @@ func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) // REST // Search Tx REST Handler -func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { +func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tag := r.FormValue("tag") if tag == "" { @@ -106,14 +114,17 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han w.Write([]byte("You need to provide at least a tag as a key=value pair to search for. Postfix the key with _bech32 to search bech32-encoded addresses or public keys")) return } + keyValue := strings.Split(tag, "=") key := keyValue[0] + value, err := url.QueryUnescape(keyValue[1]) if err != nil { w.WriteHeader(400) w.Write([]byte("Could not decode address: " + err.Error())) return } + if strings.HasSuffix(key, "_bech32") { bech32address := strings.Trim(value, "'") prefix := strings.Split(bech32address, "1")[0] @@ -127,7 +138,7 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han tag = strings.TrimRight(key, "_bech32") + "='" + sdk.AccAddress(bz).String() + "'" } - txs, err := searchTxs(ctx, cdc, []string{tag}) + txs, err := searchTxs(cliCtx, cdc, []string{tag}) if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) diff --git a/client/tx/sign.go b/client/tx/sign.go index bedd202b48b3..786c7fa0bd63 100644 --- a/client/tx/sign.go +++ b/client/tx/sign.go @@ -8,7 +8,7 @@ import ( keys "github.com/cosmos/cosmos-sdk/crypto/keys" ) -// REST request body +// REST request body for signed txs // TODO does this need to be exposed? type SignTxBody struct { Name string `json:"name"` @@ -44,5 +44,5 @@ func SignTxRequstHandler(w http.ResponseWriter, r *http.Request) { return } - w.Write(sig.Bytes()) + w.Write(sig) } diff --git a/client/utils/utils.go b/client/utils/utils.go new file mode 100644 index 000000000000..8a058b56fda0 --- /dev/null +++ b/client/utils/utils.go @@ -0,0 +1,60 @@ +package utils + +import ( + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" +) + +// SendTx implements a auxiliary handler that facilitates sending a series of +// messages in a signed transaction given a TxContext and a QueryContext. It +// ensures that the account exists, has a proper number and sequence set. In +// addition, it builds and signs a transaction with the supplied messages. +// Finally, it broadcasts the signed transaction to a node. +func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error { + if err := cliCtx.EnsureAccountExists(); err != nil { + return err + } + + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + // TODO: (ref #1903) Allow for user supplied account number without + // automatically doing a manual lookup. + if txCtx.AccountNumber == 0 { + accNum, err := cliCtx.GetAccountNumber(from) + if err != nil { + return err + } + + txCtx = txCtx.WithAccountNumber(accNum) + } + + // TODO: (ref #1903) Allow for user supplied account sequence without + // automatically doing a manual lookup. + if txCtx.Sequence == 0 { + accSeq, err := cliCtx.GetAccountSequence(from) + if err != nil { + return err + } + + txCtx = txCtx.WithSequence(accSeq) + } + + passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName) + if err != nil { + return err + } + + // build and sign the transaction + txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs) + if err != nil { + return err + } + + // broadcast to a Tendermint node + return cliCtx.EnsureBroadcastTx(txBytes) +} diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index 5fc8545b954c..3b93798a0dc1 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -1,7 +1,6 @@ package cli import ( - "errors" "fmt" "github.com/spf13/cobra" @@ -12,32 +11,31 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" ) -// GetAccountCmd for the auth.BaseAccount type +// GetAccountCmdDefault invokes the GetAccountCmd for the auth.BaseAccount type. func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command { return GetAccountCmd(storeName, cdc, GetAccountDecoder(cdc)) } -// Get account decoder for auth.DefaultAccount +// GetAccountDecoder gets the account decoder for auth.DefaultAccount. func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { return func(accBytes []byte) (acct auth.Account, err error) { - // acct := new(auth.BaseAccount) err = cdc.UnmarshalBinaryBare(accBytes, &acct) if err != nil { panic(err) } + return acct, err } } -// GetAccountCmd returns a query account that will display the -// state of the account at a given address +// GetAccountCmd returns a query account that will display the state of the +// account at a given address. func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command { return &cobra.Command{ Use: "account [address]", Short: "Query account balance", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // find the key to look up the account addr := args[0] @@ -46,30 +44,24 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode return err } - // perform query - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(auth.AddressStoreKey(key), storeName) - if err != nil { - return err - } + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(decoder) - // Check if account was found - if res == nil { - return errors.New("No account with address " + addr + - " was found in the state.\nAre you sure there has been a transaction involving it?") + if err := cliCtx.EnsureAccountExistsFromAddr(key); err != nil { + return err } - // decode the value - account, err := decoder(res) + acc, err := cliCtx.GetAccount(key) if err != nil { return err } - // print out whole account - output, err := wire.MarshalJSONIndent(cdc, account) + output, err := wire.MarshalJSONIndent(cdc, acc) if err != nil { return err } + fmt.Println(string(output)) return nil }, diff --git a/x/auth/client/context/context.go b/x/auth/client/context/context.go new file mode 100644 index 000000000000..1cfa435ee516 --- /dev/null +++ b/x/auth/client/context/context.go @@ -0,0 +1,152 @@ +package context + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + + "github.com/pkg/errors" + "github.com/spf13/viper" +) + +// TxContext implements a transaction context created in SDK modules. +type TxContext struct { + Codec *wire.Codec + AccountNumber int64 + Sequence int64 + Gas int64 + ChainID string + Memo string + Fee string +} + +// NewTxContextFromCLI returns a new initialized TxContext with parameters from +// the command line using Viper. +func NewTxContextFromCLI() TxContext { + // if chain ID is not specified manually, read default chain ID + chainID := viper.GetString(client.FlagChainID) + if chainID == "" { + defaultChainID, err := defaultChainID() + if err != nil { + chainID = defaultChainID + } + } + + return TxContext{ + ChainID: chainID, + Gas: viper.GetInt64(client.FlagGas), + AccountNumber: viper.GetInt64(client.FlagAccountNumber), + Sequence: viper.GetInt64(client.FlagSequence), + Fee: viper.GetString(client.FlagFee), + Memo: viper.GetString(client.FlagMemo), + } +} + +// WithCodec returns a copy of the context with an updated codec. +func (ctx TxContext) WithCodec(cdc *wire.Codec) TxContext { + ctx.Codec = cdc + return ctx +} + +// WithChainID returns a copy of the context with an updated chainID. +func (ctx TxContext) WithChainID(chainID string) TxContext { + ctx.ChainID = chainID + return ctx +} + +// WithGas returns a copy of the context with an updated gas. +func (ctx TxContext) WithGas(gas int64) TxContext { + ctx.Gas = gas + return ctx +} + +// WithFee returns a copy of the context with an updated fee. +func (ctx TxContext) WithFee(fee string) TxContext { + ctx.Fee = fee + return ctx +} + +// WithSequence returns a copy of the context with an updated sequence number. +func (ctx TxContext) WithSequence(sequence int64) TxContext { + ctx.Sequence = sequence + return ctx +} + +// WithMemo returns a copy of the context with an updated memo. +func (ctx TxContext) WithMemo(memo string) TxContext { + ctx.Memo = memo + return ctx +} + +// WithAccountNumber returns a copy of the context with an account number. +func (ctx TxContext) WithAccountNumber(accnum int64) TxContext { + ctx.AccountNumber = accnum + return ctx +} + +// Build builds a single message to be signed from a TxContext given a set of +// messages. It returns an error if a fee is supplied but cannot be parsed. +func (ctx TxContext) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) { + chainID := ctx.ChainID + if chainID == "" { + return auth.StdSignMsg{}, errors.Errorf("chain ID required but not specified") + } + + fee := sdk.Coin{} + if ctx.Fee != "" { + parsedFee, err := sdk.ParseCoin(ctx.Fee) + if err != nil { + return auth.StdSignMsg{}, err + } + + fee = parsedFee + } + + return auth.StdSignMsg{ + ChainID: ctx.ChainID, + AccountNumber: ctx.AccountNumber, + Sequence: ctx.Sequence, + Memo: ctx.Memo, + Msgs: msgs, + + // TODO: run simulate to estimate gas? + Fee: auth.NewStdFee(ctx.Gas, fee), + }, nil +} + +// Sign signs a transaction given a name, passphrase, and a single message to +// signed. An error is returned if signing fails. +func (ctx TxContext) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) { + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + sig, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes()) + if err != nil { + return nil, err + } + + sigs := []auth.StdSignature{{ + AccountNumber: msg.AccountNumber, + Sequence: msg.Sequence, + PubKey: pubkey, + Signature: sig, + }} + + return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo)) +} + +// BuildAndSign builds a single message to be signed, and signs a transaction +// with the built message given a name, passphrase, and a set of +// messages. +func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]byte, error) { + msg, err := ctx.Build(msgs) + if err != nil { + return nil, err + } + + return ctx.Sign(name, passphrase, msg) +} diff --git a/x/auth/client/context/utils.go b/x/auth/client/context/utils.go new file mode 100644 index 000000000000..22cc8220bb83 --- /dev/null +++ b/x/auth/client/context/utils.go @@ -0,0 +1,25 @@ +package context + +import ( + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + tmtypes "github.com/tendermint/tendermint/types" +) + +// defaultChainID returns the chain ID from the genesis file if present. An +// error is returned if the file cannot be read or parsed. +// +// TODO: This should be removed and the chainID should always be provided by +// the end user. +func defaultChainID() (string, error) { + cfg, err := tcmd.ParseConfig() + if err != nil { + return "", err + } + + doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile()) + if err != nil { + return "", err + } + + return doc.ChainID, nil +} diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 5cdc2ee2571e..431d3d27d53f 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -4,25 +4,28 @@ import ( "fmt" "net/http" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + + "github.com/gorilla/mux" ) // register REST routes -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, storeName string) { +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, storeName string) { r.HandleFunc( "/accounts/{address}", - QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), ctx), + QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx), ).Methods("GET") } // query accountREST Handler -func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { +func QueryAccountRequestHandlerFn( + storeName string, cdc *wire.Codec, + decoder auth.AccountDecoder, cliCtx context.CLIContext, +) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bech32addr := vars["address"] @@ -34,7 +37,7 @@ func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder aut return } - res, err := ctx.QueryStore(auth.AddressStoreKey(addr), storeName) + res, err := cliCtx.QueryStore(auth.AddressStoreKey(addr), storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query account. Error: %s", err.Error()))) diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index bebd24623426..c6e280157b2f 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -158,10 +158,10 @@ func (msg StdSignMsg) Bytes() []byte { // Standard Signature type StdSignature struct { - crypto.PubKey `json:"pub_key"` // optional - crypto.Signature `json:"signature"` - AccountNumber int64 `json:"account_number"` - Sequence int64 `json:"sequence"` + crypto.PubKey `json:"pub_key"` // optional + Signature []byte `json:"signature"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` } // logic for standard transaction decoding diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 0822a26b7e5a..c8d0a417dc0b 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -113,8 +113,8 @@ func TestMsgSendWithAccounts(t *testing.T) { expPass: true, privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ - expectedBalance{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}}, - expectedBalance{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, }, }, { @@ -169,9 +169,9 @@ func TestMsgSendMultipleOut(t *testing.T) { expPass: true, privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ - expectedBalance{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, - expectedBalance{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}}, - expectedBalance{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}}, + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}}, + {addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}}, }, }, } @@ -211,10 +211,10 @@ func TestSengMsgMultipleInOut(t *testing.T) { expPass: true, privKeys: []crypto.PrivKey{priv1, priv4}, expectedBalances: []expectedBalance{ - expectedBalance{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, - expectedBalance{addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, - expectedBalance{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 52)}}, - expectedBalance{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 52)}}, + {addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, }, }, } @@ -246,8 +246,8 @@ func TestMsgSendDependent(t *testing.T) { expPass: true, privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ - expectedBalance{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, - expectedBalance{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, }, }, { @@ -257,7 +257,7 @@ func TestMsgSendDependent(t *testing.T) { expPass: true, privKeys: []crypto.PrivKey{priv2}, expectedBalances: []expectedBalance{ - expectedBalance{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}}, + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}}, }, }, } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index b294e8cc74aa..92ac37c1e973 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -1,14 +1,17 @@ package cli import ( - "github.com/pkg/errors" + "os" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/bank/client" + + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -18,36 +21,29 @@ const ( flagAmount = "amount" ) -// SendTxCmd will create a send tx and sign it with the given key +// SendTxCmd will create a send tx and sign it with the given key. func SendTxCmd(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "send", Short: "Create and sign a send tx", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - // get the from/to address - from, err := ctx.GetFromAddress() - if err != nil { + if err := cliCtx.EnsureAccountExists(); err != nil { return err } - fromAcc, err := ctx.QueryStore(auth.AddressStoreKey(from), ctx.AccountStore) - if err != nil { - return err - } - - // Check if account was found - if fromAcc == nil { - return errors.Errorf("No account with address %s was found in the state.\nAre you sure there has been a transaction involving it?", from) - } - toStr := viper.GetString(flagTo) to, err := sdk.AccAddressFromBech32(toStr) if err != nil { return err } + // parse coins trying to be sent amount := viper.GetString(flagAmount) coins, err := sdk.ParseCoins(amount) @@ -55,11 +51,17 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { return err } - // ensure account has enough coins - account, err := ctx.Decoder(fromAcc) + from, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + account, err := cliCtx.GetAccount(from) if err != nil { return err } + + // ensure account has enough coins if !account.GetCoins().IsGTE(coins) { return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from) } @@ -67,12 +69,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil - + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 872b3cfe360c..e060a3bb4fd1 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -4,19 +4,20 @@ import ( "io/ioutil" "net/http" - "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank/client" + + "github.com/gorilla/mux" ) // RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/accounts/{address}/send", SendRequestHandlerFn(cdc, kb, ctx)).Methods("POST") +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + r.HandleFunc("/accounts/{address}/send", SendRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST") } type sendBody struct { @@ -38,7 +39,7 @@ func init() { } // SendRequestHandlerFn - http request handler to send coins to a address -func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // collect data vars := mux.Vars(r) @@ -80,23 +81,22 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont return } - // add gas to context - ctx = ctx.WithGas(m.Gas) - // add chain-id to context - ctx = ctx.WithChainID(m.ChainID) + txCtx := authctx.TxContext{ + Codec: cdc, + Gas: m.Gas, + ChainID: m.ChainID, + AccountNumber: m.AccountNumber, + Sequence: m.Sequence, + } - // sign - ctx = ctx.WithAccountNumber(m.AccountNumber) - ctx = ctx.WithSequence(m.Sequence) - txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc) + txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(err.Error())) return } - // send - res, err := ctx.BroadcastTx(txBytes) + res, err := cliCtx.BroadcastTx(txBytes) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/x/distribution/keeper.go b/x/distribution/keeper.go new file mode 100644 index 000000000000..1450717193bb --- /dev/null +++ b/x/distribution/keeper.go @@ -0,0 +1,91 @@ +package stake + +//// keeper of the staking store +//type Keeper struct { +//storeKey sdk.StoreKey +//cdc *wire.Codec +//coinKeeper bank.Keeper + +//// codespace +//codespace sdk.CodespaceType +//} + +//func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { +//keeper := Keeper{ +//storeKey: key, +//cdc: cdc, +//coinKeeper: ck, +//codespace: codespace, +//} +//return keeper +//} + +////_________________________________________________________________________ + +//// cummulative power of the non-absent prevotes +//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat { +//store := ctx.KVStore(k.storeKey) + +//// get absent prevote indexes +//absents := ctx.AbsentValidators() + +//TotalPower := sdk.ZeroRat() +//i := int32(0) +//iterator := store.SubspaceIterator(ValidatorsBondedKey) +//for ; iterator.Valid(); iterator.Next() { + +//skip := false +//for j, absentIndex := range absents { +//if absentIndex > i { +//break +//} + +//// if non-voting validator found, skip adding its power +//if absentIndex == i { +//absents = append(absents[:j], absents[j+1:]...) // won't need again +//skip = true +//break +//} +//} +//if skip { +//continue +//} + +//bz := iterator.Value() +//var validator Validator +//k.cdc.MustUnmarshalBinary(bz, &validator) +//TotalPower = TotalPower.Add(validator.Power) +//i++ +//} +//iterator.Close() +//return TotalPower +//} + +////_______________________________________________________________________ + +//// XXX TODO trim functionality + +//// retrieve all the power changes which occur after a height +//func (k Keeper) GetPowerChangesAfterHeight(ctx sdk.Context, earliestHeight int64) (pcs []PowerChange) { +//store := ctx.KVStore(k.storeKey) + +//iterator := store.SubspaceIterator(PowerChangeKey) //smallest to largest +//for ; iterator.Valid(); iterator.Next() { +//pcBytes := iterator.Value() +//var pc PowerChange +//k.cdc.MustUnmarshalBinary(pcBytes, &pc) +//if pc.Height < earliestHeight { +//break +//} +//pcs = append(pcs, pc) +//} +//iterator.Close() +//return +//} + +//// set a power change +//func (k Keeper) setPowerChange(ctx sdk.Context, pc PowerChange) { +//store := ctx.KVStore(k.storeKey) +//b := k.cdc.MustMarshalBinary(pc) +//store.Set(GetPowerChangeKey(pc.Height), b) +//} diff --git a/x/distribution/keeper_test.go b/x/distribution/keeper_test.go new file mode 100644 index 000000000000..0d732f8a1917 --- /dev/null +++ b/x/distribution/keeper_test.go @@ -0,0 +1,31 @@ +package stake + +//// test if is a gotValidator from the last update +//func TestGetTotalPrecommitVotingPower(t *testing.T) { +//ctx, _, keeper := createTestInput(t, false, 0) + +//amts := []int64{10000, 1000, 100, 10, 1} +//var candidatesIn [5]Candidate +//for i, amt := range amts { +//candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) +//candidatesIn[i].BondedShares = sdk.NewRat(amt) +//candidatesIn[i].DelegatorShares = sdk.NewRat(amt) +//keeper.setCandidate(ctx, candidatesIn[i]) +//} + +//// test that an empty gotValidator set doesn't have any gotValidators +//gotValidators := keeper.GetValidators(ctx) +//require.Equal(t, 5, len(gotValidators)) + +//totPow := keeper.GetTotalPrecommitVotingPower(ctx) +//exp := sdk.NewRat(11111) +//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) + +//// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address +//ctx = ctx.WithAbsentValidators([]int32{1, 3}) +//totPow = keeper.GetTotalPrecommitVotingPower(ctx) + +//// XXX verify that this order should infact exclude these two records +//exp = sdk.NewRat(11100) +//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) +//} diff --git a/x/distribution/movement.go b/x/distribution/movement.go new file mode 100644 index 000000000000..03c4de72cb05 --- /dev/null +++ b/x/distribution/movement.go @@ -0,0 +1,72 @@ +package stake + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// burn burn burn +func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} + +//// Handle fee distribution to the validators and delegators +//func (k Keeper) FeeHandler(ctx sdk.Context, collectedFees sdk.Coins) { +//pool := k.GetPool(ctx) +//params := k.GetParams(ctx) + +//// XXX determine +//candidate := NewCandidate(addrs[0], pks[0], Description{}) + +//// calculate the proposer reward +//precommitPower := k.GetTotalPrecommitVotingPower(ctx) +//toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) +//candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) + +//toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee) +//pool.FeeReservePool = pool.FeeReservePool.Plus(toReservePool) + +//distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool) +//pool.FeePool = pool.FeePool.Plus(distributedReward) +//pool.FeeSumReceived = pool.FeeSumReceived.Plus(distributedReward) +//pool.FeeRecent = distributedReward + +//// lastly update the FeeRecent term +//pool.FeeRecent = collectedFees + +//k.setPool(ctx, pool) +//} + +//func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins { +//var res sdk.Coins +//for _, coin := range coins { +//coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate() +//coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} +//res = res.Plus(coinMul) +//} +//return res +//} + +////____________________________________________________________________________- + +//// calculate adjustment changes for a candidate at a height +//func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { + +//heightRat := sdk.NewRat(height) +//lastHeightRat := sdk.NewRat(height - 1) +//candidateFeeCount := candidate.BondedShares.Mul(heightRat) +//poolFeeCount := pool.BondedShares.Mul(heightRat) + +//for i, denom := range denoms { +//poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom)) +//poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom)) +//// calculate simple and projected pools +//simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) +//calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent) +//calc2 := candidate.BondedShares.Quo(pool.BondedShares).Mul(poolFeeRecent) +//projectedPool := calc1.Add(calc2) + +//AdjustmentChange := simplePool.Sub(projectedPool) +//candidate.FeeAdjustments[i] = candidate.FeeAdjustments[i].Add(AdjustmentChange) +//pool.FeeAdjustments[i] = pool.FeeAdjustments[i].Add(AdjustmentChange) +//} + +//return candidate, pool +//} diff --git a/x/distribution/types.go b/x/distribution/types.go new file mode 100644 index 000000000000..f9d4f905f6bc --- /dev/null +++ b/x/distribution/types.go @@ -0,0 +1,107 @@ +package stake + +//// GenesisState - all staking state that must be provided at genesis +//type GenesisState struct { +//Pool Pool `json:"pool"` +//Params Params `json:"params"` +//} + +//func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []Delegation) GenesisState { +//return GenesisState{ +//Pool: pool, +//Params: params, +//} +//} + +//// get raw genesis raw message for testing +//func DefaultGenesisState() GenesisState { +//return GenesisState{ +//Pool: initialPool(), +//Params: defaultParams(), +//} +//} + +//// fee information for a validator +//type Validator struct { +//Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +//} + +////_________________________________________________________________________ + +//// Params defines the high level settings for staking +//type Params struct { +//FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms +//ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool +//} + +//func (p Params) equal(p2 Params) bool { +//return p.BondDenom == p2.BondDenom && +//p.ReservePoolFee.Equal(p2.ReservePoolFee) +//} + +//func defaultParams() Params { +//return Params{ +//FeeDenoms: []string{"steak"}, +//ReservePoolFee: sdk.NewRat(5, 100), +//} +//} + +////_________________________________________________________________________ + +//// Pool - dynamic parameters of the current state +//type Pool struct { +//FeeReservePool sdk.Coins `json:"fee_reserve_pool"` // XXX reserve pool of collected fees for use by governance +//FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed +//FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` +//FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected +//FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares +//} + +//func (p Pool) equal(p2 Pool) bool { +//return p.FeeReservePool.IsEqual(p2.FeeReservePool) && +//p.FeePool.IsEqual(p2.FeePool) && +//p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && +//p.FeeRecent.IsEqual(p2.FeeRecent) && +//sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) && +//p.PrevBondedShares.Equal(p2.PrevBondedShares) +//} + +//// initial pool for testing +//func initialPool() Pool { +//return Pool{ +//FeeReservePool: sdk.Coins(nil), +//FeePool: sdk.Coins(nil), +//FeeSumReceived: sdk.Coins(nil), +//FeeRecent: sdk.Coins(nil), +//FeeAdjustments: []sdk.Rat{sdk.ZeroRat()}, +//PrevBondedShares: sdk.ZeroRat(), +//} +//} + +////_________________________________________________________________________ + +//// Used in calculation of fee shares, added to a queue for each block where a power change occures +//type PowerChange struct { +//Height int64 `json:"height"` // block height at change +//Power sdk.Rat `json:"power"` // total power at change +//PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1 +//FeesIn sdk.Coins `json:"fees_in"` // fees in at block height +//PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height +//} + +////_________________________________________________________________________ +//// KEY MANAGEMENT + +//var ( +//// Keys for store prefixes +//PowerChangeKey = []byte{0x09} // prefix for power change object +//) + +//// get the key for the accumulated update validators +//func GetPowerChangeKey(height int64) []byte { +//heightBytes := make([]byte, binary.MaxVarintLen64) +//binary.BigEndian.PutUint64(heightBytes, ^uint64(height)) // invert height (older validators first) +//return append(PowerChangeKey, heightBytes...) +//} diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 968c66de7c18..d19de9f07fb1 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -2,16 +2,19 @@ package cli import ( "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" + "os" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) const ( @@ -27,21 +30,24 @@ const ( flagLatestProposalIDs = "latest" ) -// submit a proposal tx +// GetCmdSubmitProposal implements submitting a proposal transaction command. func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "submit-proposal", Short: "Submit a proposal along with an initial deposit", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - title := viper.GetString(flagTitle) description := viper.GetString(flagDescription) strProposalType := viper.GetString(flagProposalType) initialDeposit := viper.GetString(flagDeposit) - // get the from address from the name flag - fromAddr, err := ctx.GetFromAddress() + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + fromAddr, err := cliCtx.GetFromAddress() if err != nil { return err } @@ -56,7 +62,6 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { return err } - // create the message msg := gov.NewMsgSubmitProposal(title, description, proposalType, fromAddr, amount) err = msg.ValidateBasic() @@ -64,14 +69,10 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { return err } - // build and sign the transaction, then broadcast to Tendermint - // proposalID must be returned, and it is a part of response - ctx.PrintResponse = true - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + // Build and sign the transaction, then broadcast to Tendermint + // proposalID must be returned, and it is a part of response. + cliCtx.PrintResponse = true + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } @@ -83,16 +84,19 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { return cmd } -// set a new Deposit transaction +// GetCmdDeposit implements depositing tokens for an active proposal. func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "deposit", Short: "deposit tokens for activing proposal", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - // get the from address from the name flag - depositerAddr, err := ctx.GetFromAddress() + depositerAddr, err := cliCtx.GetFromAddress() if err != nil { return err } @@ -104,7 +108,6 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { return err } - // create the message msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount) err = msg.ValidateBasic() @@ -112,12 +115,9 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { return err } - // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + // Build and sign the transaction, then broadcast to a Tendermint + // node. + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } @@ -127,21 +127,24 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { return cmd } -// set a new Vote transaction +// GetCmdVote implements creating a new vote command. func GetCmdVote(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "vote", Short: "vote for an active proposal, options: Yes/No/NoWithVeto/Abstain", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - voterAddr, err := ctx.GetFromAddress() + voterAddr, err := cliCtx.GetFromAddress() if err != nil { return err } proposalID := viper.GetInt64(flagProposalID) - option := viper.GetString(flagOption) byteVoteOption, err := gov.VoteOptionFromString(option) @@ -149,7 +152,6 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { return err } - // create the message msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption) err = msg.ValidateBasic() @@ -158,14 +160,12 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { } fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", - voterAddr.String(), msg.ProposalID, msg.Option.String()) + voterAddr.String(), msg.ProposalID, msg.Option.String(), + ) - // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + // Build and sign the transaction, then broadcast to a Tendermint + // node. + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } @@ -175,27 +175,28 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { return cmd } -// Command to Get a Proposal Information +// GetCmdQueryProposal implements the query proposal command. func GetCmdQueryProposal(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "query-proposal", Short: "query proposal details", RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) proposalID := viper.GetInt64(flagProposalID) - ctx := context.NewCoreContextFromViper() - - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if len(res) == 0 || err != nil { return errors.Errorf("proposalID [%d] is not existed", proposalID) } var proposal gov.Proposal cdc.MustUnmarshalBinary(res, &proposal) + output, err := wire.MarshalJSONIndent(cdc, proposal) if err != nil { return err } + fmt.Println(string(output)) return nil }, @@ -207,7 +208,7 @@ func GetCmdQueryProposal(storeName string, cdc *wire.Codec) *cobra.Command { } // nolint: gocyclo -// Command to Query Proposals +// GetCmdQueryProposals implements a query proposals command. func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "query-proposals", @@ -244,9 +245,9 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command { } } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyNextProposalID, storeName) + res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName) if err != nil { return err } @@ -261,20 +262,20 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command { for proposalID := maxProposalID - latestProposalsIDs; proposalID < maxProposalID; proposalID++ { if voterAddr != nil { - res, err = ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) if err != nil || len(res) == 0 { continue } } if depositerAddr != nil { - res, err = ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) + res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) if err != nil || len(res) == 0 { continue } } - res, err = ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { continue } @@ -299,6 +300,7 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command { for _, proposal := range matchingProposals { fmt.Printf(" %d - %s\n", proposal.GetProposalID(), proposal.GetTitle()) } + return nil }, } @@ -312,11 +314,13 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command { } // Command to Get a Proposal Information +// GetCmdQueryVote implements the query proposal vote command. func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "query-vote", Short: "query vote", RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) proposalID := viper.GetInt64(flagProposalID) voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter)) @@ -324,19 +328,19 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command { return err } - ctx := context.NewCoreContextFromViper() - - res, err := ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) if len(res) == 0 || err != nil { return errors.Errorf("proposalID [%d] does not exist", proposalID) } var vote gov.Vote cdc.MustUnmarshalBinary(res, &vote) + output, err := wire.MarshalJSONIndent(cdc, vote) if err != nil { return err } + fmt.Println(string(output)) return nil }, @@ -348,17 +352,16 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command { return cmd } -// Command to Get a Proposal Information +// GetCmdQueryVotes implements the command to query for proposal votes. func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "query-votes", Short: "query votes on a proposal", RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) proposalID := viper.GetInt64(flagProposalID) - ctx := context.NewCoreContextFromViper() - - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if len(res) == 0 || err != nil { return errors.Errorf("proposalID [%d] does not exist", proposalID) } @@ -371,7 +374,7 @@ func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command { return nil } - res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName) + res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName) if err != nil { return err } @@ -389,7 +392,6 @@ func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command { } fmt.Println(string(output)) - return nil }, } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 7efce9f0b48e..a410c7791e91 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/gorilla/mux" "github.com/pkg/errors" ) @@ -24,10 +25,10 @@ const ( ) // RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { - r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, ctx)).Methods("POST") +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) { + r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc)).Methods("GET") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET") @@ -59,7 +60,7 @@ type voteReq struct { Option gov.VoteOption `json:"option"` // option from OptionSet chosen by the voter } -func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req postProposalReq err := buildReq(w, r, cdc, &req) @@ -79,12 +80,11 @@ func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.Handle return } - // sign - signAndBuild(w, ctx, req.BaseReq, msg, cdc) + signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) } } -func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -93,6 +93,7 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc w.WriteHeader(http.StatusBadRequest) err := errors.New("proposalId required but not specified") w.Write([]byte(err.Error())) + return } @@ -100,6 +101,7 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc if err != nil { err := errors.Errorf("proposalID [%d] is not positive", proposalID) w.Write([]byte(err.Error())) + return } @@ -120,12 +122,11 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc return } - // sign - signAndBuild(w, ctx, req.BaseReq, msg, cdc) + signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) } } -func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -134,6 +135,7 @@ func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.New("proposalId required but not specified") w.Write([]byte(err.Error())) + return } @@ -161,8 +163,7 @@ func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return } - // sign - signAndBuild(w, ctx, req.BaseReq, msg, cdc) + signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) } } @@ -175,6 +176,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.New("proposalId required but not specified") w.Write([]byte(err.Error())) + return } @@ -182,26 +184,31 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { if err != nil { err := errors.Errorf("proposalID [%d] is not positive", proposalID) w.Write([]byte(err.Error())) + return } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) + return } var proposal gov.Proposal cdc.MustUnmarshalBinary(res, &proposal) + output, err := wire.MarshalJSONIndent(cdc, proposal) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) + return } + w.Write(output) } } @@ -216,6 +223,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.New("proposalId required but not specified") w.Write([]byte(err.Error())) + return } @@ -224,6 +232,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("proposalID [%d] is not positive", proposalID) w.Write([]byte(err.Error())) + return } @@ -231,6 +240,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.New("depositer address required but not specified") w.Write([]byte(err.Error())) + return } @@ -239,34 +249,41 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) w.Write([]byte(err.Error())) + return } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) + res, err := cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) if err != nil || len(res) == 0 { - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { w.WriteHeader(http.StatusNotFound) err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) + return } + w.WriteHeader(http.StatusNotFound) err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID) w.Write([]byte(err.Error())) + return } var deposit gov.Deposit cdc.MustUnmarshalBinary(res, &deposit) + output, err := wire.MarshalJSONIndent(cdc, deposit) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) + return } + w.Write(output) } } @@ -289,6 +306,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("proposalID [%s] is not positive", proposalID) w.Write([]byte(err.Error())) + return } @@ -304,35 +322,41 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter) w.Write([]byte(err.Error())) + return } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) if err != nil || len(res) == 0 { - - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { w.WriteHeader(http.StatusNotFound) err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) + return } + w.WriteHeader(http.StatusNotFound) err = errors.Errorf("voter [%s] did not vote on proposalID [%d]", bechVoterAddr, proposalID) w.Write([]byte(err.Error())) + return } var vote gov.Vote cdc.MustUnmarshalBinary(res, &vote) + output, err := wire.MarshalJSONIndent(cdc, vote) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) + return } + w.Write(output) } } @@ -348,6 +372,7 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.New("proposalId required but not specified") w.Write([]byte(err.Error())) + return } @@ -356,15 +381,17 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("proposalID [%s] is not positive", proposalID) w.Write([]byte(err.Error())) + return } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) + return } @@ -374,10 +401,11 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { if proposal.GetStatus() != gov.StatusVotingPeriod { err := errors.Errorf("proposal is not in Voting Period", proposalID) w.Write([]byte(err.Error())) + return } - res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName) + res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName) if err != nil { err = errors.New("ProposalID doesn't exist") w.Write([]byte(err.Error())) @@ -396,8 +424,10 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) + return } + w.Write(output) } } @@ -431,6 +461,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) w.Write([]byte(err.Error())) + return } } @@ -441,18 +472,21 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus) w.Write([]byte(err.Error())) + return } } - ctx := context.NewCoreContextFromViper() + cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := ctx.QueryStore(gov.KeyNextProposalID, storeName) + res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName) if err != nil { err = errors.New("no proposals exist yet and proposalID has not been set") w.Write([]byte(err.Error())) + return } + var maxProposalID int64 cdc.MustUnmarshalBinary(res, &maxProposalID) @@ -460,20 +494,20 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { for proposalID := int64(0); proposalID < maxProposalID; proposalID++ { if voterAddr != nil { - res, err = ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) if err != nil || len(res) == 0 { continue } } if depositerAddr != nil { - res, err = ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) + res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) if err != nil || len(res) == 0 { continue } } - res, err = ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) if err != nil || len(res) == 0 { continue } @@ -494,8 +528,10 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) + return } + w.Write(output) } } diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index 341f0b05775e..58d96b591faa 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -7,6 +7,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" + "github.com/pkg/errors" ) @@ -67,23 +69,24 @@ func writeErr(w *http.ResponseWriter, status int, msg string) { (*w).Write([]byte(err.Error())) } -// TODO: Build this function out into a more generic base-request (probably should live in client/lcd) -func signAndBuild(w http.ResponseWriter, ctx context.CoreContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) { - ctx = ctx.WithAccountNumber(baseReq.AccountNumber) - ctx = ctx.WithSequence(baseReq.Sequence) - ctx = ctx.WithChainID(baseReq.ChainID) - - // add gas to context - ctx = ctx.WithGas(baseReq.Gas) +// TODO: Build this function out into a more generic base-request +// (probably should live in client/lcd). +func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) { + txCtx := authctx.TxContext{ + Codec: cdc, + AccountNumber: baseReq.AccountNumber, + Sequence: baseReq.Sequence, + ChainID: baseReq.ChainID, + Gas: baseReq.Gas, + } - txBytes, err := ctx.SignAndBuild(baseReq.Name, baseReq.Password, []sdk.Msg{msg}, cdc) + txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg}) if err != nil { writeErr(&w, http.StatusUnauthorized, err.Error()) return } - // send - res, err := ctx.BroadcastTx(txBytes) + res, err := cliCtx.BroadcastTx(txBytes) if err != nil { writeErr(&w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 909272808003..9dd241aabda4 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -124,6 +124,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) + } func TestTickPassedVotingPeriod(t *testing.T) { @@ -166,6 +167,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.False(t, depositsIterator.Valid()) depositsIterator.Close() require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus()) + require.True(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult())) } func TestSlashing(t *testing.T) { @@ -204,6 +206,8 @@ func TestSlashing(t *testing.T) { EndBlocker(ctx, keeper) + require.False(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult())) + endTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx) val0End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(endTotalPower) val1End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(endTotalPower) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index e232094114c5..78b39ff1c70f 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewDecWithPrec(5, 1), - Veto: sdk.NewDecWithPrec(333, 3), // 33.3% - GovernancePenalty: sdk.NewDecWithPrec(1, 2), // 1% + Threshold: sdk.NewRat(1, 2), + Veto: sdk.NewRat(1, 3), + GovernancePenalty: sdk.NewRat(1, 100), }, } } diff --git a/x/gov/handler.go b/x/gov/handler.go index 747671cbac6c..a9fdfcb3cd57 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -111,9 +111,6 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { resTags.AppendTag(tags.ProposalID, proposalIDBytes) } - var passes bool - var nonVotingVals []sdk.AccAddress - // Check if earliest Active Proposal ended voting period yet for shouldPopActiveProposalQueue(ctx, keeper) { activeProposal := keeper.ActiveProposalQueuePop(ctx) @@ -124,7 +121,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { continue } - passes, nonVotingVals = tally(ctx, keeper, activeProposal) + passes, tallyResults, nonVotingVals := tally(ctx, keeper, activeProposal) proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID()) var action []byte if passes { @@ -136,6 +133,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { activeProposal.SetStatus(StatusRejected) action = tags.ActionProposalRejected } + activeProposal.SetTallyResult(tallyResults) keeper.SetProposal(ctx, activeProposal) for _, valAddr := range nonVotingVals { diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 4f49cac582c6..0034e3d713c1 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -71,6 +71,7 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description Description: description, ProposalType: proposalType, Status: StatusDepositPeriod, + TallyResult: EmptyTallyResult(), TotalDeposit: sdk.Coins{}, SubmitBlock: ctx.BlockHeight(), VotingStartBlock: -1, // TODO: Make Time diff --git a/x/gov/procedures.go b/x/gov/procedures.go index f74091c74fda..f46c2149fa6b 100644 --- a/x/gov/procedures.go +++ b/x/gov/procedures.go @@ -12,9 +12,9 @@ type DepositProcedure struct { // Procedure around Tallying votes in governance type TallyingProcedure struct { - Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 - Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 - GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote + Threshold sdk.Rat `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 + Veto sdk.Rat `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 + GovernancePenalty sdk.Rat `json:"governance_penalty"` // Penalty if validator does not vote } // Procedure around Voting in governance diff --git a/x/gov/proposals.go b/x/gov/proposals.go index 4a07342cb49a..0a7f5de70dac 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -27,6 +27,9 @@ type Proposal interface { GetStatus() ProposalStatus SetStatus(ProposalStatus) + GetTallyResult() TallyResult + SetTallyResult(TallyResult) + GetSubmitBlock() int64 SetSubmitBlock(int64) @@ -39,17 +42,18 @@ type Proposal interface { // checks if two proposals are equal func ProposalEqual(proposalA Proposal, proposalB Proposal) bool { - if proposalA.GetProposalID() != proposalB.GetProposalID() || - proposalA.GetTitle() != proposalB.GetTitle() || - proposalA.GetDescription() != proposalB.GetDescription() || - proposalA.GetProposalType() != proposalB.GetProposalType() || - proposalA.GetStatus() != proposalB.GetStatus() || - proposalA.GetSubmitBlock() != proposalB.GetSubmitBlock() || - !(proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit())) || - proposalA.GetVotingStartBlock() != proposalB.GetVotingStartBlock() { - return false + if proposalA.GetProposalID() == proposalB.GetProposalID() && + proposalA.GetTitle() == proposalB.GetTitle() && + proposalA.GetDescription() == proposalB.GetDescription() && + proposalA.GetProposalType() == proposalB.GetProposalType() && + proposalA.GetStatus() == proposalB.GetStatus() && + proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) && + proposalA.GetSubmitBlock() == proposalB.GetSubmitBlock() && + proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) && + proposalA.GetVotingStartBlock() == proposalB.GetVotingStartBlock() { + return true } - return true + return false } //----------------------------------------------------------- @@ -60,7 +64,8 @@ type TextProposal struct { Description string `json:"description"` // Description of the proposal ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} - Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} + Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} + TallyResult TallyResult `json:"tally_result"` // Result of Tallys SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit @@ -82,6 +87,8 @@ func (tp TextProposal) GetProposalType() ProposalKind { return tp.P func (tp *TextProposal) SetProposalType(proposalType ProposalKind) { tp.ProposalType = proposalType } func (tp TextProposal) GetStatus() ProposalStatus { return tp.Status } func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status } +func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult } +func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult } func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock } func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock } func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit } @@ -167,11 +174,11 @@ func (pt *ProposalKind) UnmarshalJSON(data []byte) error { // Turns VoteOption byte to String func (pt ProposalKind) String() string { switch pt { - case 0x01: + case ProposalTypeText: return "Text" - case 0x02: + case ProposalTypeParameterChange: return "ParameterChange" - case 0x03: + case ProposalTypeSoftwareUpgrade: return "SoftwareUpgrade" default: return "" @@ -286,3 +293,33 @@ func (status ProposalStatus) Format(s fmt.State, verb rune) { s.Write([]byte(fmt.Sprintf("%v", byte(status)))) } } + +//----------------------------------------------------------- +// Tally Results +type TallyResult struct { + Yes sdk.Rat `json:"yes"` + Abstain sdk.Rat `json:"abstain"` + No sdk.Rat `json:"no"` + NoWithVeto sdk.Rat `json:"no_with_veto"` +} + +// checks if two proposals are equal +func EmptyTallyResult() TallyResult { + return TallyResult{ + Yes: sdk.ZeroRat(), + Abstain: sdk.ZeroRat(), + No: sdk.ZeroRat(), + NoWithVeto: sdk.ZeroRat(), + } +} + +// checks if two proposals are equal +func (resultA TallyResult) Equals(resultB TallyResult) bool { + if resultA.Yes.Equal(resultB.Yes) && + resultA.Abstain.Equal(resultB.Abstain) && + resultA.No.Equal(resultB.No) && + resultA.NoWithVeto.Equal(resultB.NoWithVeto) { + return true + } + return false +} diff --git a/x/gov/tally.go b/x/gov/tally.go index 35c9f1514779..f8a341e1ed9d 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -7,20 +7,20 @@ import ( // validatorGovInfo used for tallying type validatorGovInfo struct { Address sdk.AccAddress // sdk.AccAddress of the validator owner - Power sdk.Dec // Power of a Validator - DelegatorShares sdk.Dec // Total outstanding delegator shares - Minus sdk.Dec // Minus of validator, used to compute validator's voting power + Power sdk.Rat // Power of a Validator + DelegatorShares sdk.Rat // Total outstanding delegator shares + Minus sdk.Rat // Minus of validator, used to compute validator's voting power Vote VoteOption // Vote of the validator } -func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonVoting []sdk.AccAddress) { - results := make(map[VoteOption]sdk.Dec) - results[OptionYes] = sdk.ZeroDec() - results[OptionAbstain] = sdk.ZeroDec() - results[OptionNo] = sdk.ZeroDec() - results[OptionNoWithVeto] = sdk.ZeroDec() +func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.AccAddress) { + results := make(map[VoteOption]sdk.Rat) + results[OptionYes] = sdk.ZeroRat() + results[OptionAbstain] = sdk.ZeroRat() + results[OptionNo] = sdk.ZeroRat() + results[OptionNoWithVeto] = sdk.ZeroRat() - totalVotingPower := sdk.ZeroDec() + totalVotingPower := sdk.ZeroRat() currValidators := make(map[string]validatorGovInfo) keeper.vs.IterateValidatorsBonded(ctx, func(index int64, validator sdk.Validator) (stop bool) { @@ -28,7 +28,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV Address: validator.GetOwner(), Power: validator.GetPower(), DelegatorShares: validator.GetDelegatorShares(), - Minus: sdk.ZeroDec(), + Minus: sdk.ZeroRat(), Vote: OptionEmpty, } return false @@ -83,18 +83,25 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV tallyingProcedure := keeper.GetTallyingProcedure(ctx) + tallyResults = TallyResult{ + Yes: results[OptionYes], + Abstain: results[OptionAbstain], + No: results[OptionNo], + NoWithVeto: results[OptionNoWithVeto], + } + // If no one votes, proposal fails - if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroDec()) { - return false, nonVoting + if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroRat()) { + return false, tallyResults, nonVoting } // If more than 1/3 of voters veto, proposal fails if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyingProcedure.Veto) { - return false, nonVoting + return false, tallyResults, nonVoting } // If more than 1/2 of non-abstaining voters vote Yes, proposal passes if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyingProcedure.Threshold) { - return true, nonVoting + return true, tallyResults, nonVoting } // If more than 1/2 of non-abstaining voters vote No, proposal fails - return false, nonVoting + return false, tallyResults, nonVoting } diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index ab6d6f00ca54..730885266f84 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -40,9 +40,10 @@ func TestTallyNoOneVotes(t *testing.T) { proposal.SetStatus(StatusVotingPeriod) keeper.SetProposal(ctx, proposal) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.True(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidatorsAllYes(t *testing.T) { @@ -63,9 +64,10 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.True(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidators51No(t *testing.T) { @@ -86,7 +88,7 @@ func TestTallyOnlyValidators51No(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, _, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) } @@ -111,9 +113,10 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.True(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidatorsVetoed(t *testing.T) { @@ -136,9 +139,10 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNoWithVeto) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { @@ -161,9 +165,10 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.True(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { @@ -186,9 +191,10 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyOnlyValidatorsNonVoter(t *testing.T) { @@ -209,11 +215,12 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) require.Nil(t, err) - passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) require.Equal(t, 1, len(nonVoting)) require.Equal(t, addrs[0], nonVoting[0]) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyDelgatorOverride(t *testing.T) { @@ -241,9 +248,10 @@ func TestTallyDelgatorOverride(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyDelgatorInherit(t *testing.T) { @@ -269,10 +277,11 @@ func TestTallyDelgatorInherit(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) require.Nil(t, err) - passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.True(t, passes) require.Equal(t, 0, len(nonVoting)) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyDelgatorMultipleOverride(t *testing.T) { @@ -302,9 +311,10 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyDelgatorMultipleInherit(t *testing.T) { @@ -338,9 +348,10 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.False(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } func TestTallyRevokedValidator(t *testing.T) { @@ -371,7 +382,8 @@ func TestTallyRevokedValidator(t *testing.T) { err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) require.Nil(t, err) - passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) + passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) require.True(t, passes) + require.False(t, tallyResults.Equals(EmptyTallyResult())) } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 5e7977b50c34..df66fa40c493 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -64,7 +64,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) validators, err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index f5505d9a47d9..f44c736d891c 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -2,18 +2,19 @@ package cli import ( "encoding/hex" - - "github.com/spf13/cobra" - "github.com/spf13/viper" + "os" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" - + "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" - authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/ibc" + + "github.com/spf13/cobra" + "github.com/spf13/viper" ) const ( @@ -22,37 +23,35 @@ const ( flagChain = "chain" ) -// IBC transfer command +// IBCTransferCmd implements the IBC transfer command. func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "transfer", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - // get the from address - from, err := ctx.GetFromAddress() + from, err := cliCtx.GetFromAddress() if err != nil { return err } - // build the message msg, err := buildMsg(from) if err != nil { return err } - // get password - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().String(flagTo, "", "Address to send coins") cmd.Flags().String(flagAmount, "", "Amount of coins to send") cmd.Flags().String(flagChain, "", "Destination chain to send coins") + return cmd } diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 58d8f272b179..92b03a66fcbb 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -4,17 +4,19 @@ import ( "os" "time" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/ibc" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/tendermint/tendermint/libs/log" ) // flags @@ -36,7 +38,7 @@ type relayCommander struct { logger log.Logger } -// IBC relay command +// IBCRelayCmd implements the IBC relay command. func IBCRelayCmd(cdc *wire.Codec) *cobra.Command { cmdr := relayCommander{ cdc: cdc, @@ -77,10 +79,12 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { fromChainNode := viper.GetString(FlagFromChainNode) toChainID := viper.GetString(FlagToChainID) toChainNode := viper.GetString(FlagToChainNode) - address, err := context.NewCoreContextFromViper().GetFromAddress() + + address, err := context.NewCLIContext().GetFromAddress() if err != nil { panic(err) } + c.address = address c.loop(fromChainID, fromChainNode, toChainID, toChainNode) @@ -88,12 +92,10 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { // This is nolinted as someone is in the process of refactoring this to remove the goto // nolint: gocyclo -func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, - toChainNode string) { +func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) { + cliCtx := context.NewCLIContext() - ctx := context.NewCoreContextFromViper() - // get password - passphrase, err := ctx.GetPassphraseFromStdin(ctx.FromAddressName) + passphrase, err := keys.ReadPassphraseFromStdin(cliCtx.FromAddressName) if err != nil { panic(err) } @@ -122,12 +124,14 @@ OUTER: c.logger.Error("error querying outgoing packet list length", "err", err) continue OUTER //TODO replace with continue (I think it should just to the correct place where OUTER is now) } + var egressLength int64 if egressLengthbz == nil { egressLength = 0 } else if err = c.cdc.UnmarshalBinary(egressLengthbz, &egressLength); err != nil { panic(err) } + if egressLength > processed { c.logger.Info("Detected IBC packet", "number", egressLength-1) } @@ -142,7 +146,9 @@ OUTER: } err = c.broadcastTx(seq, toChainNode, c.refine(egressbz, i, passphrase)) + seq++ + if err != nil { c.logger.Error("error broadcasting ingress packet", "err", err) continue OUTER // TODO replace to break, will break first loop then send back to the beginning (aka OUTER) @@ -154,11 +160,11 @@ OUTER: } func query(node string, key []byte, storeName string) (res []byte, err error) { - return context.NewCoreContextFromViper().WithNodeURI(node).QueryStore(key, storeName) + return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName) } func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error { - _, err := context.NewCoreContextFromViper().WithNodeURI(node).WithSequence(seq + 1).BroadcastTx(tx) + _, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx) return err } @@ -167,6 +173,7 @@ func (c relayCommander) getSequence(node string) int64 { if err != nil { panic(err) } + if nil != res { account, err := c.decoder(res) if err != nil { @@ -191,10 +198,13 @@ func (c relayCommander) refine(bz []byte, sequence int64, passphrase string) []b Sequence: sequence, } - ctx := context.NewCoreContextFromViper().WithSequence(sequence) - res, err := ctx.SignAndBuild(ctx.FromAddressName, passphrase, []sdk.Msg{msg}, c.cdc) + txCtx := authctx.NewTxContextFromCLI().WithSequence(sequence).WithCodec(c.cdc) + cliCtx := context.NewCLIContext() + + res, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, []sdk.Msg{msg}) if err != nil { panic(err) } + return res } diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index bee9f955f45f..4470f556e087 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -4,18 +4,19 @@ import ( "io/ioutil" "net/http" - "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/ibc" + + "github.com/gorilla/mux" ) // RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, ctx)).Methods("POST") +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST") } type transferBody struct { @@ -31,9 +32,8 @@ type transferBody struct { // TransferRequestHandler - http request handler to transfer coins to a address // on a different chain via IBC -func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // collect data vars := mux.Vars(r) destChainID := vars["destchain"] bech32addr := vars["address"] @@ -52,6 +52,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core w.Write([]byte(err.Error())) return } + err = cdc.UnmarshalJSON(body, &m) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -70,21 +71,22 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core packet := ibc.NewIBCPacket(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount, m.SrcChainID, destChainID) msg := ibc.IBCTransferMsg{packet} - // add gas to context - ctx = ctx.WithGas(m.Gas) + txCtx := authctx.TxContext{ + Codec: cdc, + ChainID: m.SrcChainID, + AccountNumber: m.AccountNumber, + Sequence: m.Sequence, + Gas: m.Gas, + } - // sign - ctx = ctx.WithAccountNumber(m.AccountNumber) - ctx = ctx.WithSequence(m.Sequence) - txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc) + txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(err.Error())) return } - // send - res, err := ctx.BroadcastTx(txBytes) + res, err := cliCtx.BroadcastTx(txBytes) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/x/params/keeper.go b/x/params/keeper.go index 30bdcaa39c0d..8817b7c6c8de 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -183,8 +183,8 @@ func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) { return } -// GetDec is helper function for rat params -func (k Getter) GetDec(ctx sdk.Context, key string) (res sdk.Dec, err error) { +// GetRat is helper function for rat params +func (k Getter) GetRat(ctx sdk.Context, key string) (res sdk.Rat, err error) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) err = k.k.cdc.UnmarshalBinary(bz, &res) @@ -301,8 +301,8 @@ func (k Getter) GetUintWithDefault(ctx sdk.Context, key string, def sdk.Uint) (r return } -// GetDecWithDefault is helper function for sdk.Dec params with default value -func (k Getter) GetDecWithDefault(ctx sdk.Context, key string, def sdk.Dec) (res sdk.Dec) { +// GetRatWithDefault is helper function for sdk.Rat params with default value +func (k Getter) GetRatWithDefault(ctx sdk.Context, key string, def sdk.Rat) (res sdk.Rat) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) if bz == nil { @@ -397,8 +397,8 @@ func (k Setter) SetUint(ctx sdk.Context, key string, param sdk.Uint) { } } -// SetDec is helper function for rat params -func (k Setter) SetDec(ctx sdk.Context, key string, param sdk.Dec) { +// SetRat is helper function for rat params +func (k Setter) SetRat(ctx sdk.Context, key string, param sdk.Rat) { if err := k.k.set(ctx, key, param); err != nil { panic(err) } diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 22348f8a44a0..4bb5744ea458 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -94,7 +94,7 @@ func TestGetter(t *testing.T) { {"uint64", uint64(1)}, {"int", sdk.NewInt(1)}, {"uint", sdk.NewUint(1)}, - {"rat", sdk.NewDecWithPrec(1, 1)}, + {"rat", sdk.NewRat(1)}, } assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDecWithPrec(1, 1)) }) + assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewRat(1)) }) var res interface{} var err error @@ -262,19 +262,19 @@ func TestGetter(t *testing.T) { res = g.GetUintWithDefault(ctx, "invalid", def9) assert.Equal(t, def9, res) - // Dec - def10 := sdk.NewDec(0) - res, err = g.GetDec(ctx, kvs[10].key) + // Rat + def10 := sdk.NewRat(0) + res, err = g.GetRat(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) - _, err = g.GetDec(ctx, "invalid") + _, err = g.GetRat(ctx, "invalid") assert.NotNil(t, err) - res = g.GetDecWithDefault(ctx, kvs[10].key, def10) + res = g.GetRatWithDefault(ctx, kvs[10].key, def10) assert.Equal(t, kvs[10].param, res) - res = g.GetDecWithDefault(ctx, "invalid", def10) + res = g.GetRatWithDefault(ctx, "invalid", def10) assert.Equal(t, def10, res) } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 1e6a4e89d4b4..523a2e220941 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -58,7 +58,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -109,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 0360eb315a90..0901eef97085 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -13,24 +13,26 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing" ) -// get the command to query signing info +// GetCmdQuerySigningInfo implements the command to query signing info. func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "signing-info [validator-pubkey]", Short: "Query a validator's signing information", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - pk, err := sdk.GetValPubKeyBech32(args[0]) if err != nil { return err } + key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address())) - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } + signingInfo := new(slashing.ValidatorSigningInfo) cdc.MustUnmarshalBinary(res, signingInfo) diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index ab8911c119ba..5085f5aacce8 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -1,38 +1,42 @@ package cli import ( - "github.com/spf13/cobra" + "os" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/slashing" + + "github.com/spf13/cobra" ) -// create unrevoke command +// GetCmdUnrevoke implements the create unrevoke validator command. func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unrevoke", Args: cobra.ExactArgs(0), Short: "unrevoke validator previously revoked for downtime", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := ctx.GetFromAddress() + validatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } msg := slashing.NewMsgUnrevoke(validatorAddr) - // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } + return cmd } diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 535a642d4285..5509ed1a8d4e 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -4,26 +4,23 @@ import ( "fmt" "net/http" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/gorilla/mux" ) -func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) { r.HandleFunc( "/slashing/signing_info/{validator}", - signingInfoHandlerFn(ctx, "slashing", cdc), + signingInfoHandlerFn(cliCtx, "slashing", cdc), ).Methods("GET") } // http request handler to query signing info -func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { +func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - - // read parameters vars := mux.Vars(r) pk, err := sdk.GetValPubKeyBech32(vars["validator"]) @@ -34,7 +31,8 @@ func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.C } key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address())) - res, err := ctx.QueryStore(key, storeName) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query signing info. Error: %s", err.Error()))) @@ -42,6 +40,7 @@ func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.C } var signingInfo slashing.ValidatorSigningInfo + err = cdc.UnmarshalBinary(res, &signingInfo) if err != nil { w.WriteHeader(http.StatusInternalServerError) diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go index 156d400334c7..7c2fdf905207 100644 --- a/x/slashing/client/rest/rest.go +++ b/x/slashing/client/rest/rest.go @@ -1,15 +1,15 @@ package rest import ( - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/wire" + + "github.com/gorilla/mux" ) // RegisterRoutes registers staking-related REST handlers to a router -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - registerQueryRoutes(ctx, r, cdc) - registerTxRoutes(ctx, r, cdc, kb) +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + registerQueryRoutes(cliCtx, r, cdc) + registerTxRoutes(cliCtx, r, cdc, kb) } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index f358075447c4..2ecec51ea851 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -7,19 +7,20 @@ import ( "io/ioutil" "net/http" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/slashing" + + "github.com/gorilla/mux" ) -func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { r.HandleFunc( "/slashing/unrevoke", - unrevokeRequestHandlerFn(cdc, kb, ctx), + unrevokeRequestHandlerFn(cdc, kb, cliCtx), ).Methods("POST") } @@ -34,7 +35,7 @@ type UnrevokeBody struct { ValidatorAddr string `json:"validator_addr"` } -func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var m UnrevokeBody body, err := ioutil.ReadAll(r.Body) @@ -70,21 +71,24 @@ func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core return } - ctx = ctx.WithGas(m.Gas) - ctx = ctx.WithChainID(m.ChainID) - ctx = ctx.WithAccountNumber(m.AccountNumber) - ctx = ctx.WithSequence(m.Sequence) + txCtx := authctx.TxContext{ + Codec: cdc, + ChainID: m.ChainID, + AccountNumber: m.AccountNumber, + Sequence: m.Sequence, + Gas: m.Gas, + } msg := slashing.NewMsgUnrevoke(validatorAddr) - txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc) + txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(err.Error())) return } - res, err := ctx.BroadcastTx(txBytes) + res, err := cliCtx.BroadcastTx(txBytes) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go new file mode 100644 index 000000000000..6e2809bfcbcb --- /dev/null +++ b/x/slashing/genesis.go @@ -0,0 +1,14 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake/types" +) + +// InitGenesis initializes the keeper's address to pubkey map. +func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { + for _, validator := range data.Validators { + keeper.addPubkey(ctx, validator.GetPubKey()) + } + return +} diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 19a48b448edf..0cb64ab40904 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -39,7 +39,7 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { } // Cannot be unrevoked until out of jail - if ctx.BlockHeader().Time < info.JailedUntil { + if ctx.BlockHeader().Time.Before(info.JailedUntil) { return ErrValidatorJailed(k.codespace).Result() } diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 41cb5d19968c..89c1e11a604b 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // assert non-revoked validator can't be unrevoked got = slh(ctx, NewMsgUnrevoke(addr)) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index cd4e69be1c2d..2f163e57a9f1 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -2,10 +2,14 @@ package slashing import ( "fmt" + "time" + + tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/params" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" ) @@ -15,7 +19,6 @@ type Keeper struct { cdc *wire.Codec validatorSet sdk.ValidatorSet params params.Getter - // codespace codespace sdk.CodespaceType } @@ -33,10 +36,10 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, params pa } // handle a validator signing two blocks at the same height -func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, timestamp int64, power int64) { +func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, timestamp time.Time, power int64) { logger := ctx.Logger().With("module", "x/slashing") time := ctx.BlockHeader().Time - age := time - timestamp + age := time.Sub(timestamp) address := sdk.ValAddress(pubkey.Address()) // Double sign too old @@ -60,23 +63,26 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti if !found { panic(fmt.Sprintf("Expected signing info for validator %s but not found", address)) } - signInfo.JailedUntil = time + k.DoubleSignUnbondDuration(ctx) + signInfo.JailedUntil = time.Add(k.DoubleSignUnbondDuration(ctx)) k.setValidatorSigningInfo(ctx, address, signInfo) } // handle a validator signature, must be called once per validator per block // nolint gocyclo -func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, power int64, signed bool) { +func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) { logger := ctx.Logger().With("module", "x/slashing") height := ctx.BlockHeight() - address := sdk.ValAddress(pubkey.Address()) - + address := sdk.ValAddress(addr) + pubkey, err := k.getPubkey(ctx, addr) + if err != nil { + panic(fmt.Sprintf("Validator address %v not found", addr)) + } // Local index, so counts blocks validator *should* have signed // Will use the 0-value default signing info if not present, except for start height signInfo, found := k.getValidatorSigningInfo(ctx, address) if !found { // If this validator has never been seen before, construct a new SigningInfo with the correct start height - signInfo = NewValidatorSigningInfo(height, 0, 0, 0) + signInfo = NewValidatorSigningInfo(height, 0, time.Unix(0, 0), 0) } index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx) signInfo.IndexOffset++ @@ -98,7 +104,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } if !signed { - logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx))) + logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", addr, height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx))) } minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx) if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) { @@ -109,7 +115,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx))) k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx)) k.validatorSet.Revoke(ctx, pubkey) - signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx) + signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeUnbondDuration(ctx)) } else { // Validator was (a) not found or (b) already revoked, don't slash logger.Info(fmt.Sprintf("Validator %s would have been slashed for downtime, but was either not found in store or already revoked", @@ -120,3 +126,46 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, // Set the updated signing info k.setValidatorSigningInfo(ctx, address, signInfo) } + +// AddValidators adds the validators to the keepers validator addr to pubkey mapping. +func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.Validator) { + for i := 0; i < len(vals); i++ { + val := vals[i] + pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey) + if err != nil { + panic(err) + } + k.addPubkey(ctx, pubkey) + } +} + +// TODO: Make a method to remove the pubkey from the map when a validator is unbonded. +func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) { + addr := pubkey.Address() + k.setAddrPubkeyRelation(ctx, addr, pubkey) +} + +func (k Keeper) getPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKey, error) { + store := ctx.KVStore(k.storeKey) + var pubkey crypto.PubKey + err := k.cdc.UnmarshalBinary(store.Get(getAddrPubkeyRelationKey(address)), &pubkey) + if err != nil { + return nil, fmt.Errorf("address %v not found", address) + } + return pubkey, nil +} + +func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey crypto.PubKey) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(pubkey) + store.Set(getAddrPubkeyRelationKey(addr), bz) +} + +func (k Keeper) deleteAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address) { + store := ctx.KVStore(k.storeKey) + store.Delete(getAddrPubkeyRelationKey(addr)) +} + +func getAddrPubkeyRelationKey(address []byte) []byte { + return append([]byte{0x03}, address...) +} diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 74b33f7c2f8d..d3d6b06ed690 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -2,13 +2,12 @@ package slashing import ( "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) // Have to change these parameters for tests @@ -29,27 +28,28 @@ func TestHandleDoubleSign(t *testing.T) { addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info - keeper.handleValidatorSignature(ctx, val, amtInt, true) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) // double sign less than max age - keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) + keeper.handleDoubleSign(ctx, val, 0, time.Unix(0, 0), amtInt) // should be revoked require.True(t, sk.Validator(ctx, addr).GetRevoked()) // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) - ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) + require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))}) // double sign past max age - keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + keeper.handleDoubleSign(ctx, val, 0, time.Unix(0, 0), amtInt) + require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, @@ -64,21 +64,24 @@ func TestHandleAbsentValidator(t *testing.T) { slh := NewHandler(keeper) got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, int64(0), info.IndexOffset) require.Equal(t, int64(0), info.SignedBlocksCounter) - require.Equal(t, int64(0), info.JailedUntil) + // default time.Time value + var blankTime time.Time + require.Equal(t, blankTime, info.JailedUntil) height := int64(0) // 1000 first blocks OK for ; height < keeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, true) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) } info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) @@ -88,7 +91,7 @@ func TestHandleAbsentValidator(t *testing.T) { // 500 blocks missed for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) @@ -103,7 +106,7 @@ func TestHandleAbsentValidator(t *testing.T) { // 501st block missed ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -118,7 +121,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.False(t, got.IsOK()) // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(abci.Header{Time: keeper.DowntimeUnbondDuration(ctx) + 1}) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))}) got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) @@ -128,7 +131,8 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should have been slashed pool = sk.GetPool(ctx) - require.Equal(t, int64(amtInt-1), pool.BondedTokens.RoundInt64()) + slashAmt := sdk.NewRat(amtInt).Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() + require.Equal(t, int64(amtInt)-slashAmt, pool.BondedTokens.RoundInt64()) // validator start height should have been changed info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) @@ -139,7 +143,7 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should not be immediately revoked again height++ ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) @@ -147,14 +151,14 @@ func TestHandleAbsentValidator(t *testing.T) { nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1 for ; height < nextHeight; height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } // validator should be revoked again after 500 unsigned blocks nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 for ; height <= nextHeight; height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) @@ -170,24 +174,25 @@ func TestHandleNewValidator(t *testing.T) { sh := stake.NewHandler(sk) got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt))) require.True(t, got.IsOK()) - stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) // Now a validator, for two blocks - keeper.handleValidatorSignature(ctx, val, 100, true) + keeper.handleValidatorSignature(ctx, val.Address(), 100, true) ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) - keeper.handleValidatorSignature(ctx, val, 100, false) + keeper.handleValidatorSignature(ctx, val.Address(), 100, false) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight) require.Equal(t, int64(2), info.IndexOffset) require.Equal(t, int64(1), info.SignedBlocksCounter) - require.Equal(t, int64(0), info.JailedUntil) + require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) // validator should be bonded still, should not have been revoked or slashed validator, _ := sk.GetValidatorByPubKey(ctx, val) @@ -207,19 +212,20 @@ func TestHandleAlreadyRevoked(t *testing.T) { sh := stake.NewHandler(sk) got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) // 1000 first blocks OK height := int64(0) for ; height < keeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, true) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) } // 501 blocks missed for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx))+1; height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } // validator should have been revoked and slashed @@ -231,7 +237,7 @@ func TestHandleAlreadyRevoked(t *testing.T) { // another block missed ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, amtInt, false) + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) // validator should not have been slashed twice validator, _ = sk.GetValidatorByPubKey(ctx, val) diff --git a/x/slashing/params.go b/x/slashing/params.go index 3480de28fd76..9d1bc39609db 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -1,6 +1,8 @@ package slashing import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -17,8 +19,8 @@ const ( // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 -func (k Keeper) MaxEvidenceAge(ctx sdk.Context) int64 { - return k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge) +func (k Keeper) MaxEvidenceAge(ctx sdk.Context) time.Duration { + return time.Duration(k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)) * time.Second } // SignedBlocksWindow - sliding window for downtime slashing @@ -28,29 +30,29 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { // Downtime slashing thershold - default 50% func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { - minSignedPerWindow := k.params.GetDecWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) + minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) signedBlocksWindow := k.SignedBlocksWindow(ctx) - return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() + return sdk.NewRat(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() } // Double-sign unbond duration -func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) int64 { - return k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration) +func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) time.Duration { + return time.Duration(k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)) * time.Second } // Downtime unbond duration -func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) int64 { - return k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration) +func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration { + return time.Duration(k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)) * time.Second } // SlashFractionDoubleSign - currently default 5% -func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec { - return k.params.GetDecWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) +func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Rat { + return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) } // SlashFractionDowntime - currently default 1% -func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec { - return k.params.GetDecWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) +func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Rat { + return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) } // declared as var because of keeper_test.go @@ -70,9 +72,9 @@ var ( // TODO Temporarily set to 10 minutes for testnets defaultDowntimeUnbondDuration int64 = 60 * 10 - defaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1) // 0.5 + defaultMinSignedPerWindow = sdk.NewRat(1, 2) - defaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20)) + defaultSlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) - defaultSlashFractionDowntime = sdk.NewDec(1).Quo(sdk.NewDec(100)) + defaultSlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) ) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 3118793aac14..a21917e796ca 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -3,6 +3,7 @@ package slashing import ( "encoding/binary" "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -48,7 +49,7 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddr } // Construct a new `ValidatorSigningInfo` struct -func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil int64, signedBlocksCounter int64) ValidatorSigningInfo { +func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil time.Time, signedBlocksCounter int64) ValidatorSigningInfo { return ValidatorSigningInfo{ StartHeight: startHeight, IndexOffset: indexOffset, @@ -59,15 +60,15 @@ func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil i // Signing info for a validator type ValidatorSigningInfo struct { - StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked - IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array - JailedUntil int64 `json:"jailed_until"` // timestamp validator cannot be unrevoked until - SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time) + StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked + IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array + JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unrevoked until + SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time) } // Return human readable signing info func (i ValidatorSigningInfo) HumanReadableString() string { - return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %d, signed blocks counter: %d", + return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, signed blocks counter: %d", i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter) } diff --git a/x/slashing/signing_info_test.go b/x/slashing/signing_info_test.go index b2da974e79a0..f92c43581b5a 100644 --- a/x/slashing/signing_info_test.go +++ b/x/slashing/signing_info_test.go @@ -2,6 +2,7 @@ package slashing import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -15,7 +16,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { newInfo := ValidatorSigningInfo{ StartHeight: int64(4), IndexOffset: int64(3), - JailedUntil: int64(2), + JailedUntil: time.Unix(2, 0), SignedBlocksCounter: int64(10), } keeper.setValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]), newInfo) @@ -23,7 +24,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { require.True(t, found) require.Equal(t, info.StartHeight, int64(4)) require.Equal(t, info.IndexOffset, int64(3)) - require.Equal(t, info.JailedUntil, int64(2)) + require.Equal(t, info.JailedUntil, time.Unix(2, 0).UTC()) require.Equal(t, info.SignedBlocksCounter, int64(10)) } diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 089bdca3c878..7b3ab04362c5 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -69,8 +69,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - ic := initCoins.MulRaw(int64(len(addrs))) - genesis.Pool.LooseTokens = sdk.NewDec(ic.Int64()) + genesis.Pool.LooseTokens = sdk.NewRat(initCoins.MulRaw(int64(len(addrs))).Int64()) _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index da157ca7a564..7478b511cf87 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -20,13 +20,9 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags // Iterate over all the validators which *should* have signed this block // Store whether or not they have actually signed it and slash/unbond any // which have missed too many blocks in a row (downtime slashing) - for _, signingValidator := range req.Validators { + for _, signingValidator := range req.LastCommitInfo.GetValidators() { present := signingValidator.SignedLastBlock - pubkey, err := tmtypes.PB2TM.PubKey(signingValidator.Validator.PubKey) - if err != nil { - panic(err) - } - sk.handleValidatorSignature(ctx, pubkey, signingValidator.Validator.Power, present) + sk.handleValidatorSignature(ctx, signingValidator.Validator.Address, signingValidator.Validator.Power, present) } // Iterate through any newly discovered evidence of infraction diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 9540745bb9ce..8e0d66ed63f8 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -2,11 +2,11 @@ package slashing import ( "testing" + "time" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" @@ -19,21 +19,24 @@ func TestBeginBlocker(t *testing.T) { // bond the validator got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt)) require.True(t, got.IsOK()) - stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) val := abci.Validator{ - PubKey: tmtypes.TM2PB.PubKey(pk), - Power: amt.Int64(), + Address: pk.Address(), + Power: amt.Int64(), } // mark the validator as having signed req := abci.RequestBeginBlock{ - Validators: []abci.SigningValidator{{ - Validator: val, - SignedLastBlock: true, - }}, + LastCommitInfo: abci.LastCommitInfo{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: true, + }}, + }, } BeginBlocker(ctx, req, keeper) @@ -41,7 +44,7 @@ func TestBeginBlocker(t *testing.T) { require.True(t, found) require.Equal(t, ctx.BlockHeight(), info.StartHeight) require.Equal(t, int64(1), info.IndexOffset) - require.Equal(t, int64(0), info.JailedUntil) + require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) require.Equal(t, int64(1), info.SignedBlocksCounter) height := int64(0) @@ -50,10 +53,12 @@ func TestBeginBlocker(t *testing.T) { for ; height < keeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ - Validators: []abci.SigningValidator{{ - Validator: val, - SignedLastBlock: true, - }}, + LastCommitInfo: abci.LastCommitInfo{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: true, + }}, + }, } BeginBlocker(ctx, req, keeper) } @@ -62,10 +67,12 @@ func TestBeginBlocker(t *testing.T) { for ; height < ((keeper.SignedBlocksWindow(ctx) * 2) - keeper.MinSignedPerWindow(ctx) + 1); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ - Validators: []abci.SigningValidator{{ - Validator: val, - SignedLastBlock: false, - }}, + LastCommitInfo: abci.LastCommitInfo{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: false, + }}, + }, } BeginBlocker(ctx, req, keeper) } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 9847ed2904b6..4e1b2c2acdea 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -90,14 +90,14 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, func checkDelegation( t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, - validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Dec, + validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Rat, ) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { require.True(t, found) - require.True(sdk.DecEq(t, expShares, delegation.Shares)) + require.True(sdk.RatEq(t, expShares, delegation.Shares)) return } @@ -138,7 +138,7 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) // addr1 create validator on behalf of addr2 createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) @@ -150,10 +150,10 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) // edit the validator description = NewDescription("bar_moniker", "", "", "") @@ -169,14 +169,14 @@ func TestStakeMsgs(t *testing.T) { mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore - checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Dec{}) + checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{}) // balance should be the same because bonding not yet complete mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index c2d85d4b1a94..5ac303f9fe51 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -14,26 +14,28 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake/types" ) -// get the command to query a validator +// GetCmdQueryValidator implements the validator query command. func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "validator [owner-addr]", Short: "Query a validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } + key := stake.GetValidatorKey(addr) - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } else if len(res) == 0 { return fmt.Errorf("No validator found with address %s", args[0]) } + validator := types.MustUnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { @@ -50,9 +52,11 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(string(output)) } - // TODO output with proofs / machine parseable etc. + + // TODO: output with proofs / machine parseable etc. return nil }, } @@ -60,16 +64,16 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { return cmd } -// get the command to query a validator +// GetCmdQueryValidators implements the query all validators command. func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "validators", Short: "Query for all validators", RunE: func(cmd *cobra.Command, args []string) error { - key := stake.ValidatorsKey - ctx := context.NewCoreContextFromViper() - resKVs, err := ctx.QuerySubspace(cdc, key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + resKVs, err := cliCtx.QuerySubspace(key, storeName) if err != nil { return err } @@ -89,6 +93,7 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(resp) } case "json": @@ -96,24 +101,25 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(string(output)) return nil } - return nil - // TODO output with proofs / machine parseable etc. + // TODO: output with proofs / machine parseable etc. + return nil }, } + return cmd } -// get the command to query a single delegation +// GetCmdQueryDelegation the query delegation command. func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "delegation", Short: "Query a delegation based on address and validator address", RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -125,8 +131,9 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } key := stake.GetDelegationKey(delAddr, valAddr) - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } @@ -140,39 +147,45 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(resp) case "json": output, err := wire.MarshalJSONIndent(cdc, delegation) if err != nil { return err } + fmt.Println(string(output)) return nil } + return nil }, } cmd.Flags().AddFlagSet(fsValidator) cmd.Flags().AddFlagSet(fsDelegator) + return cmd } -// get the command to query all the delegations made from one delegator +// GetCmdQueryDelegations implements the command to query all the delegations +// made from one delegator. func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "delegations [delegator-addr]", Short: "Query all delegations made from one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } + key := stake.GetDelegationsKey(delegatorAddr) - ctx := context.NewCoreContextFromViper() - resKVs, err := ctx.QuerySubspace(cdc, key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + resKVs, err := cliCtx.QuerySubspace(key, storeName) if err != nil { return err } @@ -188,22 +201,24 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(string(output)) - return nil - // TODO output with proofs / machine parseable etc. + // TODO: output with proofs / machine parseable etc. + return nil }, } + return cmd } -// get the command to query a single unbonding-delegation record +// GetCmdQueryUnbondingDelegation implements the command to query a single +// unbonding-delegation record. func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbonding-delegation", Short: "Query an unbonding-delegation record based on delegator and validator address", RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -215,8 +230,9 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } key := stake.GetUBDKey(delAddr, valAddr) - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } @@ -230,39 +246,45 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co if err != nil { return err } + fmt.Println(resp) case "json": output, err := wire.MarshalJSONIndent(cdc, ubd) if err != nil { return err } + fmt.Println(string(output)) return nil } + return nil }, } cmd.Flags().AddFlagSet(fsValidator) cmd.Flags().AddFlagSet(fsDelegator) + return cmd } -// get the command to query all the unbonding-delegation records for a delegator +// GetCmdQueryUnbondingDelegations implements the command to query all the +// unbonding-delegation records for a delegator. func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbonding-delegations [delegator-addr]", Short: "Query all unbonding-delegations records for one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } + key := stake.GetUBDsKey(delegatorAddr) - ctx := context.NewCoreContextFromViper() - resKVs, err := ctx.QuerySubspace(cdc, key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + resKVs, err := cliCtx.QuerySubspace(key, storeName) if err != nil { return err } @@ -278,38 +300,43 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C if err != nil { return err } + fmt.Println(string(output)) - return nil - // TODO output with proofs / machine parseable etc. + // TODO: output with proofs / machine parseable etc. + return nil }, } + return cmd } -// get the command to query a single unbonding-delegation record +// GetCmdQueryRedelegation implements the command to query a single +// unbonding-delegation record. func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbonding-delegation", Short: "Query an unbonding-delegation record based on delegator and validator address", RunE: func(cmd *cobra.Command, args []string) error { - valSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } + valDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err } + delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) if err != nil { return err } key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr) - ctx := context.NewCoreContextFromViper() - res, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } @@ -323,39 +350,45 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(resp) case "json": output, err := wire.MarshalJSONIndent(cdc, red) if err != nil { return err } + fmt.Println(string(output)) return nil } + return nil }, } cmd.Flags().AddFlagSet(fsRedelegation) cmd.Flags().AddFlagSet(fsDelegator) + return cmd } -// get the command to query all the unbonding-delegation records for a delegator +// GetCmdQueryRedelegations implements the command to query all the +// unbonding-delegation records for a delegator. func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbonding-delegations [delegator-addr]", Short: "Query all unbonding-delegations records for one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } + key := stake.GetREDsKey(delegatorAddr) - ctx := context.NewCoreContextFromViper() - resKVs, err := ctx.QuerySubspace(cdc, key, storeName) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + resKVs, err := cliCtx.QuerySubspace(key, storeName) if err != nil { return err } @@ -371,11 +404,13 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command if err != nil { return err } + fmt.Println(string(output)) - return nil - // TODO output with proofs / machine parseable etc. + // TODO: output with proofs / machine parseable etc. + return nil }, } + return cmd } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 12786706c271..4c86777f343d 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -2,27 +2,34 @@ package cli import ( "fmt" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" + "os" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake/types" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) -// create create validator command +// GetCmdCreateValidator implements the create validator command handler. func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator", Short: "create new validator initialized with a self-delegation to it", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) amounstStr := viper.GetString(FlagAmount) if amounstStr == "" { @@ -32,7 +39,8 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { if err != nil { return err } - validatorAddr, err := ctx.GetFromAddress() + + validatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } @@ -41,13 +49,16 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { if len(pkStr) == 0 { return fmt.Errorf("must use --pubkey flag") } + pk, err := sdk.GetValPubKeyBech32(pkStr) if err != nil { return err } + if viper.GetString(FlagMoniker) == "" { return fmt.Errorf("please enter a moniker for the validator using --moniker") } + description := stake.Description{ Moniker: viper.GetString(FlagMoniker), Identity: viper.GetString(FlagIdentity), @@ -61,17 +72,14 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { if err != nil { return err } + msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description) } else { msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) } // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } @@ -79,21 +87,27 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { cmd.Flags().AddFlagSet(fsAmount) cmd.Flags().AddFlagSet(fsDescriptionCreate) cmd.Flags().AddFlagSet(fsDelegator) + return cmd } -// create edit validator command +// GetCmdEditValidator implements the create edit validator command. func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "edit-validator", Short: "edit and existing validator account", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := ctx.GetFromAddress() + validatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + description := stake.Description{ Moniker: viper.GetString(FlagMoniker), Identity: viper.GetString(FlagIdentity), @@ -103,36 +117,37 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgEditValidator(validatorAddr, description) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().AddFlagSet(fsDescriptionEdit) + return cmd } -// delegate command +// GetCmdDelegate implements the delegate command. func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "delegate", Short: "delegate liquid tokens to an validator", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) amount, err := sdk.ParseCoin(viper.GetString(FlagAmount)) if err != nil { return err } - delegatorAddr, err := ctx.GetFromAddress() + delegatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -141,51 +156,55 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgDelegate(delegatorAddr, validatorAddr, amount) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().AddFlagSet(fsAmount) cmd.Flags().AddFlagSet(fsValidator) + return cmd } -// create edit validator command +// GetCmdRedelegate implements the redelegate validator command. func GetCmdRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "redelegate", Short: "redelegate illiquid tokens from one validator to another", } + cmd.AddCommand( client.PostCommands( GetCmdBeginRedelegate(storeName, cdc), GetCmdCompleteRedelegate(cdc), )...) + return cmd } -// redelegate command +// GetCmdBeginRedelegate the begin redelegation command. func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "begin", Short: "begin redelegation", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) var err error - delegatorAddr, err := ctx.GetFromAddress() + delegatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } + validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err @@ -194,8 +213,10 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // get the shares amount sharesAmountStr := viper.GetString(FlagSharesAmount) sharesPercentStr := viper.GetString(FlagSharesPercent) - sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr, - delegatorAddr, validatorSrcAddr) + sharesAmount, err := getShares( + storeName, cdc, sharesAmountStr, sharesPercentStr, + delegatorAddr, validatorSrcAddr, + ) if err != nil { return err } @@ -203,77 +224,85 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr, sharesAmount) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().AddFlagSet(fsShares) cmd.Flags().AddFlagSet(fsRedelegation) + return cmd } // nolint: gocyclo // TODO: Make this pass gocyclo linting -func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercentStr string, - delegatorAddr, validatorAddr sdk.AccAddress) (sharesAmount sdk.Dec, err error) { - +func getShares( + storeName string, cdc *wire.Codec, sharesAmountStr, + sharesPercentStr string, delegatorAddr, validatorAddr sdk.AccAddress, +) (sharesAmount sdk.Rat, err error) { switch { case sharesAmountStr != "" && sharesPercentStr != "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr) + sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesAmount.GT(sdk.ZeroDec()) { + if !sharesAmount.GT(sdk.ZeroRat()) { return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)") } case sharesPercentStr != "": - var sharesPercent sdk.Dec - sharesPercent, err = sdk.NewDecFromStr(sharesPercentStr) + var sharesPercent sdk.Rat + sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesPercent.GT(sdk.ZeroDec()) || !sharesPercent.LTE(sdk.OneDec()) { + if !sharesPercent.GT(sdk.ZeroRat()) || !sharesPercent.LTE(sdk.OneRat()) { return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)") } // make a query to get the existing delegation shares key := stake.GetDelegationKey(delegatorAddr, validatorAddr) - ctx := context.NewCoreContextFromViper() - resQuery, err := ctx.QueryStore(key, storeName) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + resQuery, err := cliCtx.QueryStore(key, storeName) if err != nil { return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err) } + delegation := types.MustUnmarshalDelegation(cdc, key, resQuery) sharesAmount = sharesPercent.Mul(delegation.Shares) } + return } -// redelegate command +// GetCmdCompleteRedelegate implements the complete redelegation command. func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "complete", Short: "complete redelegation", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := ctx.GetFromAddress() + delegatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } + validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err @@ -282,44 +311,48 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } + cmd.Flags().AddFlagSet(fsRedelegation) + return cmd } -// create edit validator command +// GetCmdUnbond implements the unbond validator command. func GetCmdUnbond(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbond", Short: "begin or complete unbonding shares from a validator", } + cmd.AddCommand( client.PostCommands( GetCmdBeginUnbonding(storeName, cdc), GetCmdCompleteUnbonding(cdc), )...) + return cmd } -// create edit validator command +// GetCmdBeginUnbonding implements the begin unbonding validator command. func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "begin", Short: "begin unbonding", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := ctx.GetFromAddress() + delegatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -328,8 +361,10 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { // get the shares amount sharesAmountStr := viper.GetString(FlagSharesAmount) sharesPercentStr := viper.GetString(FlagSharesPercent) - sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr, - delegatorAddr, validatorAddr) + sharesAmount, err := getShares( + storeName, cdc, sharesAmountStr, sharesPercentStr, + delegatorAddr, validatorAddr, + ) if err != nil { return err } @@ -337,32 +372,33 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sharesAmount) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().AddFlagSet(fsShares) cmd.Flags().AddFlagSet(fsValidator) + return cmd } -// create edit validator command +// GetCmdCompleteUnbonding implements the complete unbonding validator command. func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "complete", Short: "complete unbonding", RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := ctx.GetFromAddress() + delegatorAddr, err := cliCtx.GetFromAddress() if err != nil { return err } + validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -371,14 +407,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - - return nil + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, } + cmd.Flags().AddFlagSet(fsValidator) + return cmd } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 9a4c3755ddcc..ac660f98f66b 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -3,50 +3,87 @@ package rest import ( "fmt" "net/http" - - "github.com/gorilla/mux" + "strings" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/tags" "github.com/cosmos/cosmos-sdk/x/stake/types" + + "github.com/gorilla/mux" ) const storeName = "stake" -func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) { + + // GET /stake/delegators/{delegatorAddr} // Get all delegations (delegation, undelegation and redelegation) from a delegator + r.HandleFunc( + "/stake/delegators/{delegatorAddr}", + delegatorHandlerFn(cliCtx, cdc), + ).Methods("GET") + // GET /stake/delegators/{delegatorAddr}/txs?type= // Get all staking txs (i.e msgs) from a delegator r.HandleFunc( - "/stake/{delegator}/delegation/{validator}", - delegationHandlerFn(ctx, cdc), + "/stake/delegators/{delegatorAddr}/txs", + delegatorTxsHandlerFn(cliCtx, cdc), ).Methods("GET") + // GET /stake/delegators/{delegatorAddr}/delegations/{validatorAddr} // Query a delegation between a delegator and a validator r.HandleFunc( - "/stake/{delegator}/ubd/{validator}", - ubdHandlerFn(ctx, cdc), + "/stake/delegators/{delegatorAddr}/delegations/{validatorAddr}", + delegationHandlerFn(cliCtx, cdc), ).Methods("GET") + // GET /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr} // Query all unbonding_delegations between a delegator and a validator r.HandleFunc( - "/stake/{delegator}/red/{validator_src}/{validator_dst}", - redHandlerFn(ctx, cdc), + "/stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}", + unbondingDelegationsHandlerFn(cliCtx, cdc), ).Methods("GET") + // GET /stake/validators/ r.HandleFunc( "/stake/validators", - validatorsHandlerFn(ctx, cdc), + validatorsHandlerFn(cliCtx, cdc), + ).Methods("GET") + + // GET /stake/validators/{addr} + r.HandleFunc( + "/stake/validators/{addr}", + validatorHandlerFn(cliCtx, cdc), ).Methods("GET") } -// http request handler to query a delegation -func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { +// already resolve the rational shares to not handle this in the client + +// defines a delegation without type Rat for shares +type DelegationWithoutRat struct { + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` + ValidatorAddr sdk.AccAddress `json:"validator_addr"` + Shares string `json:"shares"` + Height int64 `json:"height"` +} + +// aggregation of all delegations, unbondings and redelegations +type DelegationSummary struct { + Delegations []DelegationWithoutRat `json:"delegations"` + UnbondingDelegations []stake.UnbondingDelegation `json:"unbonding_delegations"` + Redelegations []stake.Redelegation `json:"redelegations"` +} + +// HTTP request handler to query a delegator delegations +func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + var validatorAddr sdk.AccAddress + var delegationSummary = DelegationSummary{} + // read parameters vars := mux.Vars(r) - bech32delegator := vars["delegator"] - bech32validator := vars["validator"] + bech32delegator := vars["delegatorAddr"] delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { @@ -55,54 +92,147 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - validatorAddr, err := sdk.AccAddressFromBech32(bech32validator) + // Get all validators using key + validators, statusCode, errMsg, err := getBech32Validators(storeName, cliCtx, cdc) if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) return } - key := stake.GetDelegationKey(delegatorAddr, validatorAddr) + for _, validator := range validators { + validatorAddr = validator.Owner - res, err := ctx.QueryStore(key, storeName) + // Delegations + delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + if err != nil { + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) + return + } + if statusCode != http.StatusNoContent { + delegationSummary.Delegations = append(delegationSummary.Delegations, delegations) + } + + // Undelegations + unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + if err != nil { + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) + return + } + if statusCode != http.StatusNoContent { + delegationSummary.UnbondingDelegations = append(delegationSummary.UnbondingDelegations, unbondingDelegation) + } + + // Redelegations + // only querying redelegations to a validator as this should give us already all relegations + // if we also would put in redelegations from, we would have every redelegation double + redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + if err != nil { + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) + return + } + if statusCode != http.StatusNoContent { + delegationSummary.Redelegations = append(delegationSummary.Redelegations, redelegations) + } + } + + output, err := cdc.MarshalJSON(delegationSummary) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query delegation. Error: %s", err.Error()))) + w.Write([]byte(err.Error())) return } - // the query will return empty if there is no data for this record - if len(res) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } + w.Write(output) + } +} - delegation, err := types.UnmarshalDelegation(cdc, key, res) +// nolint gocyclo +// HTTP request handler to query all staking txs (msgs) from a delegator +func delegatorTxsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var output []byte + var typesQuerySlice []string + vars := mux.Vars(r) + delegatorAddr := vars["delegatorAddr"] + + _, err := sdk.AccAddressFromBech32(delegatorAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - output, err := cdc.MarshalJSON(delegation) + node, err := cliCtx.GetNode() if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + w.Write([]byte(fmt.Sprintf("Couldn't get current Node information. Error: %s", err.Error()))) + return + } + + // Get values from query + + typesQuery := r.URL.Query().Get("type") + trimmedQuery := strings.TrimSpace(typesQuery) + if len(trimmedQuery) != 0 { + typesQuerySlice = strings.Split(trimmedQuery, " ") + } + + noQuery := len(typesQuerySlice) == 0 + isBondTx := contains(typesQuerySlice, "bond") + isUnbondTx := contains(typesQuerySlice, "unbond") + isRedTx := contains(typesQuerySlice, "redelegate") + var txs = []tx.Info{} + var actions []string + + switch { + case isBondTx: + actions = append(actions, string(tags.ActionDelegate)) + case isUnbondTx: + actions = append(actions, string(tags.ActionBeginUnbonding)) + actions = append(actions, string(tags.ActionCompleteUnbonding)) + case isRedTx: + actions = append(actions, string(tags.ActionBeginRedelegation)) + actions = append(actions, string(tags.ActionCompleteRedelegation)) + case noQuery: + actions = append(actions, string(tags.ActionDelegate)) + actions = append(actions, string(tags.ActionBeginUnbonding)) + actions = append(actions, string(tags.ActionCompleteUnbonding)) + actions = append(actions, string(tags.ActionBeginRedelegation)) + actions = append(actions, string(tags.ActionCompleteRedelegation)) + default: + w.WriteHeader(http.StatusNoContent) return } + for _, action := range actions { + foundTxs, errQuery := queryTxs(node, cdc, action, delegatorAddr) + if errQuery != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("error querying transactions. Error: %s", errQuery.Error()))) + } + txs = append(txs, foundTxs...) + } + + output, err = cdc.MarshalJSON(txs) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } w.Write(output) } } -// http request handler to query an unbonding-delegation -func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { +// HTTP request handler to query an unbonding-delegation +func unbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - - // read parameters vars := mux.Vars(r) - bech32delegator := vars["delegator"] - bech32validator := vars["validator"] + bech32delegator := vars["delegatorAddr"] + bech32validator := vars["validatorAddr"] delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { @@ -117,10 +247,11 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { w.Write([]byte(err.Error())) return } + validatorAddrAcc := sdk.AccAddress(validatorAddr) - key := stake.GetUBDKey(delegatorAddr, validatorAddr) + key := stake.GetUBDKey(delegatorAddr, validatorAddrAcc) - res, err := ctx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(key, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) @@ -136,14 +267,17 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { ubd, err := types.UnmarshalUBD(cdc, key, res) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("couldn't unmarshall unbonding-delegation. Error: %s", err.Error()))) return } - output, err := cdc.MarshalJSON(ubd) + // unbondings will be a list in the future but is not yet, but we want to keep the API consistent + ubdArray := []stake.UnbondingDelegation{ubd} + + output, err := cdc.MarshalJSON(ubdArray) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + w.Write([]byte(fmt.Sprintf("couldn't marshall unbonding-delegation. Error: %s", err.Error()))) return } @@ -151,15 +285,13 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { } } -// http request handler to query an redelegation -func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { +// HTTP request handler to query a bonded validator +func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // read parameters vars := mux.Vars(r) - bech32delegator := vars["delegator"] - bech32validatorSrc := vars["validator_src"] - bech32validatorDst := vars["validator_dst"] + bech32delegator := vars["delegatorAddr"] + bech32validator := vars["validatorAddr"] delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { @@ -168,58 +300,159 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - validatorSrcAddr, err := sdk.AccAddressFromBech32(bech32validatorSrc) + validatorAddr, err := sdk.AccAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } + validatorAddrAcc := sdk.AccAddress(validatorAddr) + + key := stake.GetDelegationKey(delegatorAddr, validatorAddrAcc) - validatorDstAddr, err := sdk.AccAddressFromBech32(bech32validatorDst) + res, err := cliCtx.QueryStore(key, storeName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query delegation. Error: %s", err.Error()))) + return + } + + // the query will return empty if there is no data for this record + if len(res) == 0 { + w.WriteHeader(http.StatusNoContent) + return + } + + delegation, err := types.UnmarshalDelegation(cdc, key, res) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr) + outputDelegation := DelegationWithoutRat{ + DelegatorAddr: delegation.DelegatorAddr, + ValidatorAddr: delegation.ValidatorAddr, + Height: delegation.Height, + Shares: delegation.Shares.FloatString(), + } - res, err := ctx.QueryStore(key, storeName) + output, err := cdc.MarshalJSON(outputDelegation) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query redelegation. Error: %s", err.Error()))) + w.Write([]byte(err.Error())) return } - // the query will return empty if there is no data for this record - if len(res) == 0 { + w.Write(output) + } +} + +// HTTP request handler to query all delegator bonded validators +func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var validatorAccAddr sdk.AccAddress + var bondedValidators []types.BechValidator + + // read parameters + vars := mux.Vars(r) + bech32delegator := vars["delegatorAddr"] + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + // Get all validators using key + kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error()))) + return + } else if len(kvs) == 0 { + // the query will return empty if there are no validators w.WriteHeader(http.StatusNoContent) return } - red, err := types.UnmarshalRED(cdc, key, res) + validators, err := getValidators(kvs, cdc) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) return } - output, err := cdc.MarshalJSON(red) + for _, validator := range validators { + // get all transactions from the delegator to val and append + validatorAccAddr = validator.Owner + + validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr) + if errRes != nil { + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, errRes.Error()))) + return + } else if statusCode == http.StatusNoContent { + continue + } + + bondedValidators = append(bondedValidators, validator) + } + output, err := cdc.MarshalJSON(bondedValidators) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } + w.Write(output) + } +} +// HTTP request handler to get information from a currently bonded validator +func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // read parameters + var output []byte + vars := mux.Vars(r) + bech32delegator := vars["delegatorAddr"] + bech32validator := vars["validatorAddr"] + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + validatorAccAddr, err := sdk.AccAddressFromBech32(bech32validator) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + return + } + + // Check if there if the delegator is bonded or redelegated to the validator + + validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr) + if err != nil { + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) + return + } else if statusCode == http.StatusNoContent { + w.WriteHeader(statusCode) + return + } + output, err = cdc.MarshalJSON(validator) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } w.Write(output) } } // TODO bech32 // http request handler to query list of validators -func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { +func validatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - kvs, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName) + kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error()))) @@ -232,25 +465,11 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - // parse out the validators - validators := make([]types.BechValidator, len(kvs)) - for i, kv := range kvs { - - addr := kv.Key[1:] - validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) - return - } - - bech32Validator, err := validator.Bech32Validator() - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - } - validators[i] = bech32Validator + validators, err := getValidators(kvs, cdc) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + return } output, err := cdc.MarshalJSON(validators) @@ -263,3 +482,47 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF w.Write(output) } } + +// HTTP request handler to query the validator information from a given validator address +func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var output []byte + // read parameters + vars := mux.Vars(r) + bech32validatorAddr := vars["addr"] + valAddress, err := sdk.AccAddressFromBech32(bech32validatorAddr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + return + } + + kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + return + } + + validator, err := getValidator(valAddress, kvs, cdc) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query validator. Error: %s", err.Error()))) + return + } + + output, err = cdc.MarshalJSON(validator) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + return + } + + if output == nil { + w.WriteHeader(http.StatusNoContent) + return + } + w.Write(output) + } +} diff --git a/x/stake/client/rest/rest.go b/x/stake/client/rest/rest.go index 3528d45e4c09..7c2fdf905207 100644 --- a/x/stake/client/rest/rest.go +++ b/x/stake/client/rest/rest.go @@ -1,15 +1,15 @@ package rest import ( - "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/wire" + + "github.com/gorilla/mux" ) // RegisterRoutes registers staking-related REST handlers to a router -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - registerQueryRoutes(ctx, r, cdc) - registerTxRoutes(ctx, r, cdc, kb) +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + registerQueryRoutes(cliCtx, r, cdc) + registerTxRoutes(cliCtx, r, cdc, kb) } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index c1c30e0c0a97..fbefc7f21987 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -6,20 +6,23 @@ import ( "io/ioutil" "net/http" - "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/gorilla/mux" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + authcliCtx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" + + "github.com/gorilla/mux" + + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) -func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { +func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { r.HandleFunc( - "/stake/delegations", - editDelegationsRequestHandlerFn(cdc, kb, ctx), + "/stake/delegators/{delegatorAddr}/delegations", + delegationsRequestHandlerFn(cdc, kb, cliCtx), ).Methods("POST") } @@ -49,7 +52,7 @@ type msgCompleteUnbondingInput struct { ValidatorAddr string `json:"validator_addr"` // in bech32 } -// request body for edit delegations +// the request body for edit delegations type EditDelegationsBody struct { LocalAccountName string `json:"name"` Password string `json:"password"` @@ -66,15 +69,18 @@ type EditDelegationsBody struct { // nolint: gocyclo // TODO: Split this up into several smaller functions, and remove the above nolint -func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +// TODO: use sdk.ValAddress instead of sdk.AccAddress for validators in messages +func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var m EditDelegationsBody + body, err := ioutil.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } + err = cdc.UnmarshalJSON(body, &m) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -104,22 +110,26 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } + validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } + messages[i] = stake.MsgDelegate{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, Delegation: msg.Delegation, } + i++ } @@ -130,11 +140,13 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } + validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -147,18 +159,21 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewDecFromStr(msg.SharesAmount) + + shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) return } + messages[i] = stake.MsgBeginRedelegate{ DelegatorAddr: delegatorAddr, ValidatorSrcAddr: validatorSrcAddr, ValidatorDstAddr: validatorDstAddr, SharesAmount: shares, } + i++ } @@ -169,6 +184,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } + validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -181,16 +197,19 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } + messages[i] = stake.MsgCompleteRedelegate{ DelegatorAddr: delegatorAddr, ValidatorSrcAddr: validatorSrcAddr, ValidatorDstAddr: validatorDstAddr, } + i++ } @@ -201,28 +220,33 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } + validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewDecFromStr(msg.SharesAmount) + + shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) return } + messages[i] = stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, SharesAmount: shares, } + i++ } @@ -233,36 +257,44 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } + validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } + messages[i] = stake.MsgCompleteUnbonding{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, } + i++ } - // add gas to context - ctx = ctx.WithGas(m.Gas) + txCtx := authcliCtx.TxContext{ + Codec: cdc, + ChainID: m.ChainID, + Gas: m.Gas, + } // sign messages signedTxs := make([][]byte, len(messages[:])) for i, msg := range messages { // increment sequence for each message - ctx = ctx.WithAccountNumber(m.AccountNumber) - ctx = ctx.WithSequence(m.Sequence) + txCtx = txCtx.WithAccountNumber(m.AccountNumber) + txCtx = txCtx.WithSequence(m.Sequence) + m.Sequence++ - txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc) + txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(err.Error())) @@ -277,12 +309,13 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte // should we have a sdk.MultiMsg type to make sending atomic? results := make([]*ctypes.ResultBroadcastTxCommit, len(signedTxs[:])) for i, txBytes := range signedTxs { - res, err := ctx.BroadcastTx(txBytes) + res, err := cliCtx.BroadcastTx(txBytes) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } + results[i] = res } diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go new file mode 100644 index 000000000000..86e714662861 --- /dev/null +++ b/x/stake/client/rest/utils.go @@ -0,0 +1,228 @@ +package rest + +import ( + "bytes" + "fmt" + "net/http" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/tags" + "github.com/cosmos/cosmos-sdk/x/stake/types" + "github.com/pkg/errors" + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +// contains checks if the a given query contains one of the tx types +func contains(stringSlice []string, txType string) bool { + for _, word := range stringSlice { + if word == txType { + return true + } + } + return false +} + +func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAccAddr sdk.AccAddress) ( + validator types.BechValidator, httpStatusCode int, errMsg string, err error) { + + // check if the delegator is bonded or redelegated to the validator + keyDel := stake.GetDelegationKey(delegatorAddr, validatorAccAddr) + + res, err := cliCtx.QueryStore(keyDel, storeName) + if err != nil { + return types.BechValidator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err + } + + if len(res) == 0 { + return types.BechValidator{}, http.StatusNoContent, "", nil + } + + kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) + if err != nil { + return types.BechValidator{}, http.StatusInternalServerError, "Error: ", err + } + if len(kvs) == 0 { + // the query will return empty if there are no delegations + return types.BechValidator{}, http.StatusNoContent, "", nil + } + + validator, errVal := getValidatorFromAccAdrr(validatorAccAddr, kvs, cdc) + if errVal != nil { + return types.BechValidator{}, http.StatusInternalServerError, "Couldn't get info from validator. Error: ", errVal + } + return validator, http.StatusOK, "", nil +} + +func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( + outputDelegation DelegationWithoutRat, httpStatusCode int, errMsg string, err error) { + delegationKey := stake.GetDelegationKey(delegatorAddr, validatorAddr) + marshalledDelegation, err := cliCtx.QueryStore(delegationKey, storeName) + if err != nil { + return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err + } + + // the query will return empty if there is no data for this record + if len(marshalledDelegation) == 0 { + return DelegationWithoutRat{}, http.StatusNoContent, "", nil + } + + delegation, err := types.UnmarshalDelegation(cdc, delegationKey, marshalledDelegation) + if err != nil { + return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't unmarshall delegation. Error: ", err + } + + outputDelegation = DelegationWithoutRat{ + DelegatorAddr: delegation.DelegatorAddr, + ValidatorAddr: delegation.ValidatorAddr, + Height: delegation.Height, + Shares: delegation.Shares.FloatString(), + } + + return outputDelegation, http.StatusOK, "", nil +} + +func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( + unbonds types.UnbondingDelegation, httpStatusCode int, errMsg string, err error) { + undelegationKey := stake.GetUBDKey(delegatorAddr, validatorAddr) + marshalledUnbondingDelegation, err := cliCtx.QueryStore(undelegationKey, storeName) + if err != nil { + return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't query unbonding-delegation. Error: ", err + } + + // the query will return empty if there is no data for this record + if len(marshalledUnbondingDelegation) == 0 { + return types.UnbondingDelegation{}, http.StatusNoContent, "", nil + } + + unbondingDelegation, err := types.UnmarshalUBD(cdc, undelegationKey, marshalledUnbondingDelegation) + if err != nil { + return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't unmarshall unbonding-delegation. Error: ", err + } + return unbondingDelegation, http.StatusOK, "", nil +} + +func getDelegatorRedelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( + regelegations types.Redelegation, httpStatusCode int, errMsg string, err error) { + + keyRedelegateTo := stake.GetREDsByDelToValDstIndexKey(delegatorAddr, validatorAddr) + marshalledRedelegations, err := cliCtx.QueryStore(keyRedelegateTo, storeName) + if err != nil { + return types.Redelegation{}, http.StatusInternalServerError, "couldn't query redelegation. Error: ", err + } + + if len(marshalledRedelegations) == 0 { + return types.Redelegation{}, http.StatusNoContent, "", nil + } + + redelegations, err := types.UnmarshalRED(cdc, keyRedelegateTo, marshalledRedelegations) + if err != nil { + return types.Redelegation{}, http.StatusInternalServerError, "couldn't unmarshall redelegations. Error: ", err + } + + return redelegations, http.StatusOK, "", nil +} + +// queries staking txs +func queryTxs(node rpcclient.Client, cdc *wire.Codec, tag string, delegatorAddr string) ([]tx.Info, error) { + page := 0 + perPage := 100 + prove := false + query := fmt.Sprintf("%s='%s' AND %s='%s'", tags.Action, tag, tags.Delegator, delegatorAddr) + res, err := node.TxSearch(query, prove, page, perPage) + if err != nil { + return nil, err + } + + return tx.FormatTxResults(cdc, res.Txs) +} + +// gets all validators +func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechValidator, error) { + validators := make([]types.BechValidator, len(validatorKVs)) + for i, kv := range validatorKVs { + + addr := kv.Key[1:] + validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) + if err != nil { + return nil, err + } + + bech32Validator, err := validator.Bech32Validator() + if err != nil { + return nil, err + } + validators[i] = bech32Validator + } + return validators, nil +} + +// gets a validator given a ValAddress +func getValidator(address sdk.AccAddress, validatorKVs []sdk.KVPair, cdc *wire.Codec) (stake.BechValidator, error) { + // parse out the validators + for _, kv := range validatorKVs { + addr := kv.Key[1:] + validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) + if err != nil { + return stake.BechValidator{}, err + } + + ownerAddress := validator.PubKey.Address() + if bytes.Equal(ownerAddress.Bytes(), address.Bytes()) { + bech32Validator, err := validator.Bech32Validator() + if err != nil { + return stake.BechValidator{}, err + } + + return bech32Validator, nil + } + } + return stake.BechValidator{}, errors.Errorf("Couldn't find validator") +} + +// gets a validator given an AccAddress +func getValidatorFromAccAdrr(address sdk.AccAddress, validatorKVs []sdk.KVPair, cdc *wire.Codec) (stake.BechValidator, error) { + // parse out the validators + for _, kv := range validatorKVs { + addr := kv.Key[1:] + validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) + if err != nil { + return stake.BechValidator{}, err + } + + ownerAddress := validator.PubKey.Address() + if bytes.Equal(ownerAddress.Bytes(), address.Bytes()) { + bech32Validator, err := validator.Bech32Validator() + if err != nil { + return stake.BechValidator{}, err + } + + return bech32Validator, nil + } + } + return stake.BechValidator{}, errors.Errorf("Couldn't find validator") +} + +// gets all Bech32 validators from a key +func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *wire.Codec) ( + validators []types.BechValidator, httpStatusCode int, errMsg string, err error) { + // Get all validators using key + kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) + if err != nil { + return nil, http.StatusInternalServerError, "couldn't query validators. Error: ", err + } + + // the query will return empty if there are no validators + if len(kvs) == 0 { + return nil, http.StatusNoContent, "", nil + } + + validators, err = getValidators(kvs, cdc) + if err != nil { + return nil, http.StatusInternalServerError, "Error: ", err + } + return validators, http.StatusOK, "", nil +} diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 9cdbe19826bc..2febd2c6a636 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -17,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(2) + pool.BondedTokens = sdk.NewRat(2) params := keeper.GetParams(ctx) var delegations []Delegation @@ -32,11 +32,11 @@ func TestInitGenesis(t *testing.T) { // initialize the validators validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.OneDec() - validators[0].DelegatorShares = sdk.OneDec() + validators[0].Tokens = sdk.OneRat() + validators[0].DelegatorShares = sdk.OneRat() validators[1].Status = sdk.Bonded - validators[1].Tokens = sdk.OneDec() - validators[1].DelegatorShares = sdk.OneDec() + validators[1].Tokens = sdk.OneRat() + validators[1].DelegatorShares = sdk.OneRat() genesisState = types.NewGenesisState(pool, params, validators, delegations) vals, err := InitGenesis(ctx, keeper, genesisState) @@ -69,7 +69,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewDec(int64(200 + (size - 100))) + pool.BondedTokens = sdk.NewRat(int64(200 + (size - 100))) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -80,11 +80,11 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators[i].Status = sdk.Bonded if i < 100 { - validators[i].Tokens = sdk.NewDec(2) - validators[i].DelegatorShares = sdk.NewDec(2) + validators[i].Tokens = sdk.NewRat(2) + validators[i].DelegatorShares = sdk.NewRat(2) } else { - validators[i].Tokens = sdk.OneDec() - validators[i].DelegatorShares = sdk.OneDec() + validators[i].Tokens = sdk.OneRat() + validators[i].DelegatorShares = sdk.OneRat() } } diff --git a/x/stake/handler.go b/x/stake/handler.go index 9a8cee446bc6..8f7475de9b79 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -1,6 +1,8 @@ package stake import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/keeper" "github.com/cosmos/cosmos-sdk/x/stake/tags" @@ -38,7 +40,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid // Process provision inflation blockTime := ctx.BlockHeader().Time - if blockTime-pool.InflationLastTime >= 3600 { + if blockTime.Sub(pool.InflationLastTime) >= time.Hour { params := k.GetParams(ctx) pool.InflationLastTime = blockTime pool = pool.ProcessProvisions(params) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index cebe28885887..edad64f4477a 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -2,6 +2,7 @@ package stake import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -80,7 +81,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDecWithPrec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewRat(1, 2)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -109,7 +110,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(1000000)) msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -137,8 +138,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewDec(10), validator.BondedTokens()) - assert.Equal(t, sdk.NewDec(10), validator.DelegatorShares) + assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) + assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) // two validators can't have the same owner address @@ -161,8 +162,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -181,8 +182,8 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Owner) assert.Equal(t, pk, validator.PubKey) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator @@ -220,7 +221,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v", exRate) + require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64()) // just send the same msgbond multiple times @@ -239,7 +240,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.True(t, found) exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v, i = %v", exRate, i) + require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v, i = %v", exRate, i) expBond := int64(i+1) * bondAmount expDelegatorShares := int64(i+2) * bondAmount // (1 self delegation) @@ -294,7 +295,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here - unbondShares := sdk.NewDec(10) + unbondShares := sdk.NewRat(10) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) numUnbonds := 5 @@ -338,7 +339,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } for _, c := range errorCases { - unbondShares := sdk.NewDec(int64(c)) + unbondShares := sdk.NewRat(int64(c)) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "expected unbond msg to fail") @@ -347,14 +348,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have - unbondShares = sdk.NewDec(leftBonded + 1) + unbondShares = sdk.NewRat(leftBonded + 1) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have - unbondShares = sdk.NewDec(leftBonded) + unbondShares = sdk.NewRat(leftBonded) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), @@ -390,7 +391,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewRat(10)) // remove delegation msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -435,7 +436,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -466,7 +467,7 @@ func TestRevokeValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -482,7 +483,7 @@ func TestRevokeValidator(t *testing.T) { require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds - msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -500,7 +501,7 @@ func TestUnbondingPeriod(t *testing.T) { // set the unbonding time params := keeper.GetParams(ctx) - params.UnbondingTime = 7 + params.UnbondingTime = 7 * time.Second keeper.SetParams(ctx, params) // create the validator @@ -509,26 +510,26 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") // cannot complete unbonding at same time msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) - require.True(t, !got.IsOK(), "expected no error") + require.True(t, !got.IsOK(), "expected an error") // cannot complete unbonding at time 6 seconds later origHeader := ctx.BlockHeader() headerTime6 := origHeader - headerTime6.Time += 6 + headerTime6.Time = headerTime6.Time.Add(time.Second * 6) ctx = ctx.WithBlockHeader(headerTime6) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) - require.True(t, !got.IsOK(), "expected no error") + require.True(t, !got.IsOK(), "expected an error") // can complete unbonding at time 7 seconds later headerTime7 := origHeader - headerTime7.Time += 7 + headerTime7.Time = headerTime7.Time.Add(time.Second * 7) ctx = ctx.WithBlockHeader(headerTime7) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") @@ -541,7 +542,7 @@ func TestRedelegationPeriod(t *testing.T) { // set the unbonding time params := keeper.GetParams(ctx) - params.UnbondingTime = 7 + params.UnbondingTime = 7 * time.Second keeper.SetParams(ctx, params) // create the validators @@ -564,7 +565,7 @@ func TestRedelegationPeriod(t *testing.T) { bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) @@ -580,14 +581,14 @@ func TestRedelegationPeriod(t *testing.T) { // cannot complete redelegation at time 6 seconds later origHeader := ctx.BlockHeader() headerTime6 := origHeader - headerTime6.Time += 6 + headerTime6.Time = headerTime6.Time.Add(time.Second * 6) ctx = ctx.WithBlockHeader(headerTime6) got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error") // can complete redelegation at time 7 seconds later headerTime7 := origHeader - headerTime7.Time += 7 + headerTime7.Time = headerTime7.Time.Add(time.Second * 7) ctx = ctx.WithBlockHeader(headerTime7) got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper) require.True(t, got.IsOK(), "expected no error") @@ -616,12 +617,12 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) + msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewRat(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) @@ -662,7 +663,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -784,7 +785,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -797,7 +798,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) + msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewRat(50)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -831,22 +832,22 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx = ctx.WithBlockHeight(1) // begin unbonding 4 stake - msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4)) + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewRat(4)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // begin redelegate 6 stake - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6)) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewRat(6)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(6), delegation.Shares) + require.Equal(t, sdk.NewRat(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDecWithPrec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewRat(1, 2)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -861,16 +862,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3), delegation.Shares) + require.Equal(t, sdk.NewRat(3), delegation.Shares) // validator power should have been reduced by half validator, found := keeper.GetValidator(ctx, valA) require.True(t, found) - require.Equal(t, sdk.NewDec(5), validator.GetPower()) + require.Equal(t, sdk.NewRat(5), validator.GetPower()) // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDecWithPrec(5, 1)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewRat(1, 2)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) @@ -885,7 +886,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewDec(3), delegation.Shares) + require.Equal(t, sdk.NewRat(3), delegation.Shares) // validator power should have been reduced to zero // ergo validator should have been removed from the store diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 892ef81a31fb..484e85ad5c42 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -218,7 +218,7 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { // Perform a delegation, set/update everything necessary within the store. func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt sdk.Coin, - validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { + validator types.Validator, subtractAccount bool) (newShares sdk.Rat, err sdk.Error) { // Get or create the delegator delegation delegation, found := k.GetDelegation(ctx, delegatorAddr, validator.Owner) @@ -226,7 +226,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt delegation = types.Delegation{ DelegatorAddr: delegatorAddr, ValidatorAddr: validator.Owner, - Shares: sdk.ZeroDec(), + Shares: sdk.ZeroRat(), } } @@ -254,7 +254,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt // unbond the the delegation return func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, - shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { + shares sdk.Rat) (amount sdk.Rat, err sdk.Error) { // check if delegation has any shares in it unbond delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -312,7 +312,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr //______________________________________________________________________________________________________ // complete unbonding an unbonding record -func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { +func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 _, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) @@ -327,7 +327,7 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk // create the unbonding delegation params := k.GetParams(ctx) - minTime := ctx.BlockHeader().Time + params.UnbondingTime + minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime) balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} ubd := types.UnbondingDelegation{ @@ -351,7 +351,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr // ensure that enough time has passed ctxTime := ctx.BlockHeader().Time - if ubd.MinTime > ctxTime { + if ubd.MinTime.After(ctxTime) { return types.ErrNotMature(k.Codespace(), "unbonding", "unit-time", ubd.MinTime, ctxTime) } @@ -365,7 +365,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr // complete unbonding an unbonding record func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delegatorAddr, validatorSrcAddr) { @@ -389,7 +389,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd } // create the unbonding delegation - minTime := ctx.BlockHeader().Time + params.UnbondingTime + minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime) red := types.Redelegation{ DelegatorAddr: delegatorAddr, @@ -415,7 +415,7 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delegatorAddr, validatorSr // ensure that enough time has passed ctxTime := ctx.BlockHeader().Time - if red.MinTime > ctxTime { + if red.MinTime.After(ctxTime) { return types.ErrNotMature(k.Codespace(), "redelegation", "unit-time", red.MinTime, ctxTime) } diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 79d50ac18fcc..5d512f0cf5ba 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -2,6 +2,7 @@ package keeper import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" @@ -31,7 +32,7 @@ func TestDelegation(t *testing.T) { bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], - Shares: sdk.NewDec(9), + Shares: sdk.NewRat(9), } // check the empty keeper first @@ -45,18 +46,18 @@ func TestDelegation(t *testing.T) { require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewDec(99) + bond1to1.Shares = sdk.NewRat(99) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9), 0} - bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9), 1} - bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9), 2} - bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9), 3} - bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9), 4} + bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} + bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewRat(9), 1} + bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewRat(9), 2} + bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewRat(9), 3} + bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewRat(9), 4} keeper.SetDelegation(ctx, bond1to2) keeper.SetDelegation(ctx, bond1to3) keeper.SetDelegation(ctx, bond2to1) @@ -115,7 +116,7 @@ func TestUnbondingDelegation(t *testing.T) { DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], CreationHeight: 0, - MinTime: 0, + MinTime: time.Unix(0, 0), Balance: sdk.NewInt64Coin("steak", 5), } @@ -141,7 +142,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewRat(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -162,8 +163,8 @@ func TestUnbondDelegation(t *testing.T) { keeper.SetDelegation(ctx, delegation) var err error - var amount sdk.Dec - amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) + var amount sdk.Rat + amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewRat(6)) require.NoError(t, err) require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation @@ -188,9 +189,9 @@ func TestGetRedelegationsFromValidator(t *testing.T) { ValidatorSrcAddr: addrVals[0], ValidatorDstAddr: addrVals[1], CreationHeight: 0, - MinTime: 0, - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), + MinTime: time.Unix(0, 0), + SharesSrc: sdk.NewRat(5), + SharesDst: sdk.NewRat(5), } // set and retrieve a record @@ -218,9 +219,9 @@ func TestRedelegation(t *testing.T) { ValidatorSrcAddr: addrVals[0], ValidatorDstAddr: addrVals[1], CreationHeight: 0, - MinTime: 0, - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), + MinTime: time.Unix(0, 0), + SharesSrc: sdk.NewRat(5), + SharesDst: sdk.NewRat(5), } // test shouldn't have and redelegations @@ -241,8 +242,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewDec(21) - rd.SharesDst = sdk.NewDec(21) + rd.SharesSrc = sdk.NewRat(21) + rd.SharesDst = sdk.NewRat(21) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 9307ddddf252..3f763ea25efa 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = sdk.NewDec(777) + expPool.BondedTokens = sdk.NewRat(777) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index e373ede18a45..502ec2654419 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -34,19 +34,19 @@ var ( const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch -// get the key for the validator with address. +// gets the key for the validator with address // VALUE: stake/types.Validator func GetValidatorKey(ownerAddr sdk.AccAddress) []byte { return append(ValidatorsKey, ownerAddr.Bytes()...) } -// get the key for the validator with pubkey. +// gets the key for the validator with pubkey // VALUE: validator owner address ([]byte) func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) } -// get the key for the current validator group +// gets the key for the current validator group // VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey) func GetValidatorsBondedIndexKey(ownerAddr sdk.AccAddress) []byte { return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) @@ -57,8 +57,9 @@ func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { return IndexKey[1:] // remove prefix bytes } -// get the validator by power index. power index is the key used in the power-store, -// and represents the relative power ranking of the validator. +// get the validator by power index. +// Power index is the key used in the power-store, and represents the relative +// power ranking of the validator. // VALUE: validator owner address ([]byte) func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { // NOTE the address doesn't need to be stored because counter bytes must always be different @@ -93,29 +94,29 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { counterBytes...) } -// get the key for the accumulated update validators. +// get the key for the accumulated update validators // VALUE: abci.Validator // note records using these keys should never persist between blocks func GetTendermintUpdatesKey(ownerAddr sdk.AccAddress) []byte { return append(TendermintUpdatesKey, ownerAddr.Bytes()...) } -//________________________________________________________________________________ +//______________________________________________________________________________ -// get the key for delegator bond with validator. +// gets the key for delegator bond with validator // VALUE: stake/types.Delegation func GetDelegationKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...) } -// get the prefix for a delegator for all validators +// gets the prefix for a delegator for all validators func GetDelegationsKey(delegatorAddr sdk.AccAddress) []byte { return append(DelegationKey, delegatorAddr.Bytes()...) } -//________________________________________________________________________________ +//______________________________________________________________________________ -// get the key for an unbonding delegation by delegator and validator addr. +// gets the key for an unbonding delegation by delegator and validator addr // VALUE: stake/types.UnbondingDelegation func GetUBDKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { return append( @@ -123,13 +124,13 @@ func GetUBDKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { validatorAddr.Bytes()...) } -// get the index-key for an unbonding delegation, stored by validator-index +// gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...) } -// rearrange the ValIndexKey to get the UBDKey +// rearranges the ValIndexKey to get the UBDKey func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes if len(addrs) != 2*sdk.AddrLen { @@ -142,19 +143,19 @@ func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { //______________ -// get the prefix for all unbonding delegations from a delegator +// gets the prefix for all unbonding delegations from a delegator func GetUBDsKey(delegatorAddr sdk.AccAddress) []byte { return append(UnbondingDelegationKey, delegatorAddr.Bytes()...) } -// get the prefix keyspace for the indexes of unbonding delegations for a validator +// gets the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(validatorAddr sdk.AccAddress) []byte { return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...) } //________________________________________________________________________________ -// get the key for a redelegation +// gets the key for a redelegation // VALUE: stake/types.RedelegationKey func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { return append(append( @@ -163,7 +164,7 @@ func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) validatorDstAddr.Bytes()...) } -// get the index-key for a redelegation, stored by source-validator-index +// gets the index-key for a redelegation, stored by source-validator-index // VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { return append(append( @@ -172,7 +173,7 @@ func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sd validatorDstAddr.Bytes()...) } -// get the index-key for a redelegation, stored by destination-validator-index +// gets the index-key for a redelegation, stored by destination-validator-index // VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { return append(append( @@ -181,7 +182,7 @@ func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sd validatorSrcAddr.Bytes()...) } -// rearrange the ValSrcIndexKey to get the REDKey +// rearranges the ValSrcIndexKey to get the REDKey func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes if len(addrs) != 3*sdk.AddrLen { @@ -194,7 +195,7 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { return GetREDKey(delAddr, valSrcAddr, valDstAddr) } -// rearrange the ValDstIndexKey to get the REDKey +// rearranges the ValDstIndexKey to get the REDKey func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes if len(addrs) != 3*sdk.AddrLen { @@ -208,22 +209,22 @@ func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { //______________ -// get the prefix keyspace for redelegations from a delegator +// gets the prefix keyspace for redelegations from a delegator func GetREDsKey(delegatorAddr sdk.AccAddress) []byte { return append(RedelegationKey, delegatorAddr.Bytes()...) } -// get the prefix keyspace for all redelegations redelegating away from a source validator +// gets the prefix keyspace for all redelegations redelegating away from a source validator func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.AccAddress) []byte { return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...) } -// get the prefix keyspace for all redelegations redelegating towards a destination validator +// gets the prefix keyspace for all redelegations redelegating towards a destination validator func GetREDsToValDstIndexKey(validatorDstAddr sdk.AccAddress) []byte { return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...) } -// get the prefix keyspace for all redelegations redelegating towards a destination validator +// gets the prefix keyspace for all redelegations redelegating towards a destination validator // from a particular delegator func GetREDsByDelToValDstIndexKey(delegatorAddr, validatorDstAddr sdk.AccAddress) []byte { return append( diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index aeec44fae959..9c331147447e 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -69,7 +69,7 @@ func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Val } // total power from the bond -func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec { +func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { pool := k.GetPool(ctx) return pool.BondedTokens } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 856c43531fc8..a741b5a85766 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -20,15 +20,15 @@ import ( // CONTRACT: // Infraction committed at the current height or at a past height, // not at a height in the future -func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) { +func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Rat) { logger := ctx.Logger().With("module", "x/stake") - if slashFactor.LT(sdk.ZeroDec()) { + if slashFactor.LT(sdk.ZeroRat()) { panic(fmt.Errorf("attempted to slash with a negative slashFactor: %v", slashFactor)) } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewDec(power).Mul(slashFactor) + slashAmount := sdk.NewRat(power).Mul(slashFactor) // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -89,7 +89,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Cannot decrease balance below zero - tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens) + tokensToBurn := sdk.MinRat(remainingSlashAmount, validator.Tokens) // Get the current pool pool := k.GetPool(ctx) @@ -150,23 +150,23 @@ func (k Keeper) setRevoked(ctx sdk.Context, pubkey crypto.PubKey, revoked bool) // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, - infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { + infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { now := ctx.BlockHeader().Time // If unbonding started before this height, stake didn't contribute to infraction if unbondingDelegation.CreationHeight < infractionHeight { - return sdk.ZeroDec() + return sdk.ZeroRat() } - if unbondingDelegation.MinTime < now { + if unbondingDelegation.MinTime.Before(now) { // Unbonding delegation no longer eligible for slashing, skip it // TODO Settle and delete it automatically? - return sdk.ZeroDec() + return sdk.ZeroRat() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount).Mul(slashFactor) + slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -194,23 +194,23 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, - infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { + infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { now := ctx.BlockHeader().Time // If redelegation started before this height, stake didn't contribute to infraction if redelegation.CreationHeight < infractionHeight { - return sdk.ZeroDec() + return sdk.ZeroRat() } - if redelegation.MinTime < now { + if redelegation.MinTime.Before(now) { // Redelegation no longer eligible for slashing, skip it // TODO Delete it automatically? - return sdk.ZeroDec() + return sdk.ZeroRat() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount).Mul(slashFactor) + slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 05b98a05f5cb..878c44d1eb80 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -2,6 +2,7 @@ package keeper import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -18,7 +19,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewDec(amt * int64(numVals)) + pool.LooseTokens = sdk.NewRat(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { @@ -62,7 +63,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -70,7 +71,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { ValidatorAddr: addrVals[0], CreationHeight: 0, // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: 0, + MinTime: time.Unix(0, 0), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), Balance: sdk.NewInt64Coin(params.BondDenom, 10), } @@ -81,14 +82,14 @@ func TestSlashUnbondingDelegation(t *testing.T) { require.Equal(t, int64(0), slashAmount.RoundInt64()) // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) require.Equal(t, int64(0), slashAmount.RoundInt64()) // test valid slash, before expiration timestamp and to which stake contributed oldPool := keeper.GetPool(ctx) - ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)}) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetUnbondingDelegation(ctx, ubd) slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) require.Equal(t, int64(5), slashAmount.RoundInt64()) @@ -105,7 +106,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) // set a redelegation rd := types.Redelegation{ @@ -114,9 +115,9 @@ func TestSlashRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, // expiration timestamp (beyond which the redelegation shouldn't be slashed) - MinTime: 0, - SharesSrc: sdk.NewDec(10), - SharesDst: sdk.NewDec(10), + MinTime: time.Unix(0, 0), + SharesSrc: sdk.NewRat(10), + SharesDst: sdk.NewRat(10), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), Balance: sdk.NewInt64Coin(params.BondDenom, 10), } @@ -126,7 +127,7 @@ func TestSlashRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(10), + Shares: sdk.NewRat(10), } keeper.SetDelegation(ctx, del) @@ -137,7 +138,7 @@ func TestSlashRedelegation(t *testing.T) { require.Equal(t, int64(0), slashAmount.RoundInt64()) // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) keeper.SetRedelegation(ctx, rd) validator, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) @@ -146,7 +147,7 @@ func TestSlashRedelegation(t *testing.T) { // test valid slash, before expiration timestamp and to which stake contributed oldPool := keeper.GetPool(ctx) - ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)}) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) keeper.SetRedelegation(ctx, rd) validator, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) @@ -171,7 +172,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -179,7 +180,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -192,16 +193,16 @@ func TestSlashAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // power decreased - require.Equal(t, sdk.NewDec(5), validator.GetPower()) + require.Equal(t, sdk.NewRat(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewDec(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -209,7 +210,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { ValidatorAddr: addrVals[0], CreationHeight: 11, // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: 0, + MinTime: time.Unix(0, 0), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4), Balance: sdk.NewInt64Coin(params.BondDenom, 4), } @@ -238,7 +239,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(7), validator.GetPower()) + require.Equal(t, sdk.NewRat(7), validator.GetPower()) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -255,7 +256,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(4), validator.GetPower()) + require.Equal(t, sdk.NewRat(4), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -275,7 +276,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewDec(1), validator.GetPower()) + require.Equal(t, sdk.NewRat(1), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -302,7 +303,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) // set a redelegation rd := types.Redelegation{ @@ -310,9 +311,9 @@ func TestSlashWithRedelegation(t *testing.T) { ValidatorSrcAddr: addrVals[0], ValidatorDstAddr: addrVals[1], CreationHeight: 11, - MinTime: 0, - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), + MinTime: time.Unix(0, 0), + SharesSrc: sdk.NewRat(6), + SharesDst: sdk.NewRat(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -322,13 +323,13 @@ func TestSlashWithRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6), + Shares: sdk.NewRat(6), } keeper.SetDelegation(ctx, del) // update bonded tokens pool := keeper.GetPool(ctx) - pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewRat(6)) keeper.SetPool(ctx, pool) // slash validator @@ -354,13 +355,13 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewDec(8), validator.GetPower()) + require.Equal(t, sdk.NewRat(8), validator.GetPower()) // slash the validator again ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) }) + require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -375,13 +376,13 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 4 - require.Equal(t, sdk.NewDec(4), validator.GetPower()) + require.Equal(t, sdk.NewRat(4), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -403,7 +404,7 @@ func TestSlashWithRedelegation(t *testing.T) { // validator no longer in the store _, found = keeper.GetValidatorByPubKey(ctx, pk) require.False(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -423,7 +424,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) + fraction := sdk.NewRat(1, 2) // set a redelegation rdA := types.Redelegation{ @@ -432,9 +433,9 @@ func TestSlashBoth(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 11, // expiration timestamp (beyond which the redelegation shouldn't be slashed) - MinTime: 0, - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), + MinTime: time.Unix(0, 0), + SharesSrc: sdk.NewRat(6), + SharesDst: sdk.NewRat(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -444,7 +445,7 @@ func TestSlashBoth(t *testing.T) { delA := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewDec(6), + Shares: sdk.NewRat(6), } keeper.SetDelegation(ctx, delA) @@ -454,7 +455,7 @@ func TestSlashBoth(t *testing.T) { ValidatorAddr: addrVals[0], CreationHeight: 11, // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: 0, + MinTime: time.Unix(0, 0), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4), Balance: sdk.NewInt64Coin(params.BondDenom, 4), } @@ -482,5 +483,5 @@ func TestSlashBoth(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, sdk.NewDec(10), validator.GetPower()) + require.Equal(t, sdk.NewRat(10), validator.GetPower()) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 0470c28988a4..010963034982 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -77,10 +77,10 @@ func MakeTestCodec() *wire.Codec { // default params without inflation func ParamsNoInflation() types.Params { return types.Params{ - InflationRateChange: sdk.ZeroDec(), - InflationMax: sdk.ZeroDec(), - InflationMin: sdk.ZeroDec(), - GoalBonded: sdk.NewDecWithPrec(67, 2), + InflationRateChange: sdk.ZeroRat(), + InflationMax: sdk.ZeroRat(), + InflationMin: sdk.ZeroRat(), + GoalBonded: sdk.NewRat(67, 100), MaxValidators: 100, BondDenom: "steak", } @@ -119,7 +119,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(initCoins)) keeper.SetPool(ctx, pool) } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 8f9399b2af78..eaaf3df9ef10 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -134,6 +134,8 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat } // get the group of bonded validators sorted by power-rank +// +// TODO: Rename to GetBondedValidatorsByPower or GetValidatorsByPower(ctx, status) func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators @@ -191,13 +193,13 @@ func (k Keeper) ClearTendermintUpdates(ctx sdk.Context) { //___________________________________________________________________________ -// Perfom all the necessary steps for when a validator changes its power. This +// Perform all the necessary steps for when a validator changes its power. This // function updates all validator stores as well as tendermint update store. // It may kick out validators if a new validator is entering the bonded validator // group. // // nolint: gocyclo -// TODO: Remove above nolint, function needs to be simplified +// TODO: Remove above nolint, function needs to be simplified! func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) @@ -210,19 +212,29 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type cliffPower := k.GetCliffValidatorPower(ctx) switch { - // if already bonded and power increasing only need to update tendermint + // if the validator is already bonded and the power is increasing, we need + // perform the following: + // a) update Tendermint + // b) check if the cliff validator needs to be updated case powerIncreasing && !validator.Revoked && (oldFound && oldValidator.Status == sdk.Bonded): bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(validator.Owner), bz) + if cliffPower != nil { + cliffAddr := sdk.AccAddress(k.GetCliffValidator(ctx)) + if bytes.Equal(cliffAddr, validator.Owner) { + k.updateCliffValidator(ctx, validator) + } + } + // if is a new validator and the new power is less than the cliff validator case cliffPower != nil && !oldFound && bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower // skip to completion - // if was unbonded and the new power is less than the cliff validator + // if was unbonded and the new power is less than the cliff validator case cliffPower != nil && (oldFound && oldValidator.Status == sdk.Unbonded) && bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower @@ -232,11 +244,10 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type // a) not-bonded and now has power-rank greater than cliff validator // b) bonded and now has decreased in power default: - // update the validator set for this validator - // if updated, the validator has changed bonding status updatedVal, updated := k.UpdateBondedValidators(ctx, validator) - if updated { // updates to validator occurred to be updated + if updated { + // the validator has changed bonding status validator = updatedVal break } @@ -246,13 +257,69 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(validator.Owner), bz) } - } k.SetValidator(ctx, validator) return validator } +// updateCliffValidator determines if the current cliff validator needs to be +// updated or swapped. If the provided affected validator is the current cliff +// validator before it's power was increased, either the cliff power key will +// be updated or if it's power is greater than the next bonded validator by +// power, it'll be swapped. +func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validator) { + var newCliffVal types.Validator + + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + cliffAddr := sdk.AccAddress(k.GetCliffValidator(ctx)) + + oldCliffVal, found := k.GetValidator(ctx, cliffAddr) + if !found { + panic(fmt.Sprintf("cliff validator record not found for address: %v\n", cliffAddr)) + } + + // NOTE: We get the power via affectedVal since the store (by power key) + // has yet to be updated. + affectedValPower := affectedVal.GetPower() + + // Create a validator iterator ranging from smallest to largest by power + // starting the current cliff validator's power. + start := GetValidatorsByPowerIndexKey(oldCliffVal, pool) + end := sdk.PrefixEndBytes(ValidatorsByPowerIndexKey) + iterator := store.Iterator(start, end) + + if iterator.Valid() { + ownerAddr := iterator.Value() + currVal, found := k.GetValidator(ctx, ownerAddr) + if !found { + panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr)) + } + + if currVal.Status != sdk.Bonded || currVal.Revoked { + panic(fmt.Sprintf("unexpected revoked or unbonded validator for address: %s\n", ownerAddr)) + } + + newCliffVal = currVal + iterator.Close() + } else { + panic("failed to create valid validator power iterator") + } + + if bytes.Equal(affectedVal.Owner, newCliffVal.Owner) { + // The affected validator remains the cliff validator, however, since + // the store does not contain the new power, set the new cliff + // validator to the affected validator. + bz := GetValidatorsByPowerIndexKey(affectedVal, pool) + store.Set(ValidatorPowerCliffKey, bz) + } else if affectedValPower.GT(newCliffVal.GetPower()) { + // The affected validator no longer remains the cliff validator as it's + // power is greater than the new current cliff validator. + k.setCliffValidator(ctx, newCliffVal, pool) + } +} + func (k Keeper) updateForRevoking(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator { if newValidator.Revoked && oldFound && oldValidator.Status == sdk.Bonded { newValidator = k.unbondValidator(ctx, newValidator) @@ -317,8 +384,9 @@ func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidato // // nolint: gocyclo // TODO: Remove the above golint -func (k Keeper) UpdateBondedValidators(ctx sdk.Context, - affectedValidator types.Validator) (updatedVal types.Validator, updated bool) { +func (k Keeper) UpdateBondedValidators( + ctx sdk.Context, affectedValidator types.Validator) ( + updatedVal types.Validator, updated bool) { store := ctx.KVStore(k.storeKey) @@ -328,7 +396,8 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, var validator, validatorToBond types.Validator newValidatorBonded := false - iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest + // create a validator iterator ranging from largest to smallest by power + iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) for { if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) { break @@ -354,6 +423,7 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, validatorToBond = validator newValidatorBonded = true } + bondedValidatorsCount++ // sanity check @@ -363,6 +433,7 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, iterator.Next() } + iterator.Close() // clear or set the cliff validator @@ -372,17 +443,17 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, k.clearCliffValidator(ctx) } - // swap the cliff validator for a new validator if the affected validator was bonded + // swap the cliff validator for a new validator if the affected validator + // was bonded if newValidatorBonded { - // unbond the cliff validator if oldCliffValidatorAddr != nil { cliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr) if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", oldCliffValidatorAddr)) } - k.unbondValidator(ctx, cliffVal) + k.unbondValidator(ctx, cliffVal) } // bond the new validator @@ -391,6 +462,7 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context, return validator, true } } + return types.Validator{}, false } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 7d5fec95ad5c..b9e61a1014b2 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,8 +20,8 @@ func TestSetValidator(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -28,8 +29,8 @@ func TestSetValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -55,8 +56,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewDec(10000) - pool.BondedTokens = sdk.NewDec(1234) + pool.LooseTokens = sdk.NewRat(10000) + pool.BondedTokens = sdk.NewRat(1234) keeper.SetPool(ctx, pool) // add a validator @@ -75,7 +76,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares - validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) + validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out @@ -88,6 +89,62 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) } +func TestCliffValidatorChange(t *testing.T) { + numVals := 10 + maxVals := 5 + + // create context, keeper, and pool for tests + ctx, _, keeper := CreateTestInput(t, false, 0) + pool := keeper.GetPool(ctx) + + // create keeper parameters + params := keeper.GetParams(ctx) + params.MaxValidators = uint16(maxVals) + keeper.SetParams(ctx, params) + + // create a random pool + pool.LooseTokens = sdk.NewRat(10000) + pool.BondedTokens = sdk.NewRat(1234) + keeper.SetPool(ctx, pool) + + validators := make([]types.Validator, numVals) + for i := 0; i < len(validators); i++ { + moniker := fmt.Sprintf("val#%d", int64(i)) + val := types.NewValidator(Addrs[i], PKs[i], types.Description{Moniker: moniker}) + val.BondHeight = int64(i) + val.BondIntraTxCounter = int16(i) + val, pool, _ = val.AddTokensFromDel(pool, int64((i+1)*10)) + + keeper.SetPool(ctx, pool) + val = keeper.UpdateValidator(ctx, val) + validators[i] = val + } + + // add a large amount of tokens to current cliff validator + currCliffVal := validators[numVals-maxVals] + currCliffVal, pool, _ = currCliffVal.AddTokensFromDel(pool, 200) + keeper.SetPool(ctx, pool) + currCliffVal = keeper.UpdateValidator(ctx, currCliffVal) + + // assert new cliff validator to be set to the second lowest bonded validator by power + newCliffVal := validators[numVals-maxVals+1] + require.Equal(t, newCliffVal.Owner, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + + // assert cliff validator power should have been updated + cliffPower := keeper.GetCliffValidatorPower(ctx) + require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) + + // add small amount of tokens to new current cliff validator + newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, 1) + keeper.SetPool(ctx, pool) + newCliffVal = keeper.UpdateValidator(ctx, newCliffVal) + + // assert cliff validator has not change but increased in power + cliffPower = keeper.GetCliffValidatorPower(ctx) + require.Equal(t, newCliffVal.Owner, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) +} + func TestSlashToZeroPowerRemoved(t *testing.T) { // initialize setup ctx, _, keeper := CreateTestInput(t, false, 100) @@ -104,7 +161,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% - keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneDec()) + keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneRat()) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) @@ -121,13 +178,13 @@ func TestValidatorBasics(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) validators[i].Status = sdk.Unbonded - validators[i].Tokens = sdk.ZeroDec() + validators[i].Tokens = sdk.ZeroRat() validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) } - assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(8), validators[1].Tokens)) - assert.True(sdk.DecEq(t, sdk.NewDec(7), validators[2].Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(8), validators[1].Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(7), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -136,7 +193,7 @@ func TestValidatorBasics(t *testing.T) { assert.Zero(t, len(resVals)) pool = keeper.GetPool(ctx) - assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) + assert.True(sdk.RatEq(t, sdk.ZeroRat(), pool.BondedTokens)) // set and retrieve a record validators[0] = keeper.UpdateValidator(ctx, validators[0]) @@ -148,15 +205,15 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].BondedTokens())) + assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].BondedTokens())) pool = keeper.GetPool(ctx) - assert.True(sdk.DecEq(t, pool.BondedTokens, validators[0].BondedTokens())) + assert.True(sdk.RatEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(10) - validators[0].DelegatorShares = sdk.NewDec(10) + validators[0].Tokens = sdk.NewRat(10) + validators[0].DelegatorShares = sdk.NewRat(10) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -199,19 +256,19 @@ func GetValidatorSortingUnmixed(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewDec(amt) - validators[i].DelegatorShares = sdk.NewDec(amt) + validators[i].Tokens = sdk.NewRat(amt) + validators[i].DelegatorShares = sdk.NewRat(amt) keeper.UpdateValidator(ctx, validators[i]) } // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDecWithPrec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -219,14 +276,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewDec(500) + validators[3].Tokens = sdk.NewRat(500) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewDec(300) + validators[3].Tokens = sdk.NewRat(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -234,7 +291,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewDec(200) + validators[3].Tokens = sdk.NewRat(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -253,8 +310,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewDec(300) - validators[4].Tokens = sdk.NewDec(300) + validators[3].Tokens = sdk.NewRat(300) + validators[4].Tokens = sdk.NewRat(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -281,20 +338,20 @@ func GetValidatorSortingMixed(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewDec(amt, 0) + validators[i].DelegatorShares = sdk.NewRat(amt) } validators[0].Status = sdk.Bonded validators[1].Status = sdk.Bonded validators[2].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(amts[0]) - validators[1].Tokens = sdk.NewDec(amts[1]) - validators[2].Tokens = sdk.NewDec(amts[2]) + validators[0].Tokens = sdk.NewRat(amts[0]) + validators[1].Tokens = sdk.NewRat(amts[1]) + validators[2].Tokens = sdk.NewRat(amts[2]) validators[3].Status = sdk.Bonded validators[4].Status = sdk.Bonded - validators[3].Tokens = sdk.NewDec(amts[3]) - validators[4].Tokens = sdk.NewDec(amts[4]) + validators[3].Tokens = sdk.NewRat(amts[3]) + validators[4].Tokens = sdk.NewRat(amts[4]) for i := range amts { keeper.UpdateValidator(ctx, validators[i]) @@ -318,11 +375,11 @@ func GetValidatorSortingMixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDecWithPrec(1, 1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -387,7 +444,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewRat(201)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -599,7 +656,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewDec(600) + validators[0].Tokens = sdk.NewRat(600) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -737,21 +794,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power - require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64()) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} pool := keeper.GetPool(ctx) - validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) - validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) // power has changed - require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 654d5560b0ac..e4869693cfa0 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -31,7 +31,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim pool := k.GetPool(ctx) loose := sdk.ZeroInt() - bonded := sdk.ZeroDec() + bonded := sdk.ZeroRat() am.IterateAccounts(ctx, func(acc auth.Account) bool { loose = loose.Add(acc.GetCoins().AmountOf("steak")) return false @@ -67,7 +67,7 @@ func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { return func(t *testing.T, app *baseapp.BaseApp, log string) { ctx := app.NewContext(false, abci.Header{}) k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { - require.True(t, validator.GetPower().GT(sdk.ZeroDec()), "validator with non-positive power stored") + require.True(t, validator.GetPower().GT(sdk.ZeroRat()), "validator with non-positive power stored") return false }) } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index f402d765fc0e..e4077a7497ce 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -132,7 +132,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewDecFromInt(amount), + SharesAmount: sdk.NewRatFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -191,7 +191,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation DelegatorAddr: delegatorAddress, ValidatorSrcAddr: sourceValidatorAddress, ValidatorDstAddr: destValidatorAddress, - SharesAmount: sdk.NewDecFromInt(amount), + SharesAmount: sdk.NewRatFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64())) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(loose.Int64(), 1)) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index f09cd8f4c098..77fd327a5e4d 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -15,12 +16,12 @@ import ( type Delegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - Shares sdk.Dec `json:"shares"` + Shares sdk.Rat `json:"shares"` Height int64 `json:"height"` // Last height bond updated } type delegationValue struct { - Shares sdk.Dec + Shares sdk.Rat Height int64 } @@ -80,7 +81,7 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr } func (d Delegation) GetValidator() sdk.AccAddress { return d.ValidatorAddr } -func (d Delegation) GetBondShares() sdk.Dec { return d.Shares } +func (d Delegation) GetBondShares() sdk.Rat { return d.Shares } // HumanReadableString returns a human readable string representation of a // Delegation. An error is returned if the Delegation's delegator or validator @@ -100,14 +101,14 @@ type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator ValidatorAddr sdk.AccAddress `json:"validator_addr"` // validator unbonding from owner addr CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime int64 `json:"min_time"` // unix time for unbonding completion + MinTime time.Time `json:"min_time"` // unix time for unbonding completion InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion } type ubdValue struct { CreationHeight int64 - MinTime int64 + MinTime time.Time InitialBalance sdk.Coin Balance sdk.Coin } @@ -186,20 +187,20 @@ type Redelegation struct { ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` // validator redelegation destination owner addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime int64 `json:"min_time"` // unix time for redelegation completion + MinTime time.Time `json:"min_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating + SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } type redValue struct { CreationHeight int64 - MinTime int64 + MinTime time.Time InitialBalance sdk.Coin Balance sdk.Coin - SharesSrc sdk.Dec - SharesDst sdk.Dec + SharesSrc sdk.Rat + SharesDst sdk.Rat } // return the redelegation without fields contained within the key for the store diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index db4dd77233b1..69823db14521 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -2,6 +2,7 @@ package types import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -11,19 +12,19 @@ func TestDelegationEqual(t *testing.T) { d1 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewRat(100), } d2 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewRat(100), } ok := d1.Equal(d2) require.True(t, ok) d2.ValidatorAddr = addr3 - d2.Shares = sdk.NewDec(200) + d2.Shares = sdk.NewRat(200) ok = d1.Equal(d2) require.False(t, ok) @@ -33,7 +34,7 @@ func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewDec(100), + Shares: sdk.NewRat(100), } // NOTE: Being that the validator's keypair is random, we cannot test the @@ -57,7 +58,7 @@ func TestUnbondingDelegationEqual(t *testing.T) { require.True(t, ok) ud2.ValidatorAddr = addr3 - ud2.MinTime = 20 * 20 * 2 + ud2.MinTime = time.Unix(20*20*2, 0) ok = ud1.Equal(ud2) require.False(t, ok) @@ -91,9 +92,9 @@ func TestRedelegationEqual(t *testing.T) { ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewDec(10) - r2.SharesSrc = sdk.NewDec(20) - r2.MinTime = 20 * 20 * 2 + r2.SharesDst = sdk.NewRat(10) + r2.SharesSrc = sdk.NewRat(20) + r2.MinTime = time.Unix(20*20*2, 0) ok = r1.Equal(r2) require.False(t, ok) @@ -104,8 +105,8 @@ func TestRedelegationHumanReadableString(t *testing.T) { DelegatorAddr: addr1, ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, - SharesDst: sdk.NewDec(10), - SharesSrc: sdk.NewDec(20), + SharesDst: sdk.NewRat(10), + SharesSrc: sdk.NewRat(20), } // NOTE: Being that the validator's keypair is random, we cannot test the diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index b34aeeefb1e9..b3e279c8eea0 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -3,6 +3,7 @@ package types import ( "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -99,11 +100,18 @@ func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") } +func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidDelegation, + fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", + maximumBondingRationalDenominator.String()), + ) +} + func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } -func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error { +func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error { msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", operation, descriptor, got, min) return sdk.NewError(codespace, CodeUnauthorized, msg) diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index fd181af3c927..0114b1e05729 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -23,30 +23,30 @@ func TestGetInflation(t *testing.T) { tests := []struct { name string setBondedTokens, setLooseTokens, - setInflation, expectedChange sdk.Dec + setInflation, expectedChange sdk.Rat }{ // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)}, + {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), - sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, + {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), + sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDecWithPrec(10, 2), - sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, + {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), + sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()}, - {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)}, + {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, + {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()}, - {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)}, + {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, + {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000)}, // perfect balance shouldn't change inflation - {"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()}, + {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -67,80 +67,77 @@ func TestProcessProvisions(t *testing.T) { var ( initialTotalTokens int64 = 550000000 - cumulativeExpProvs = sdk.ZeroDec() + cumulativeExpProvs = sdk.ZeroRat() ) - pool.LooseTokens = sdk.NewDec(initialTotalTokens) + pool.LooseTokens = sdk.NewRat(initialTotalTokens) // process the provisions for a year for hr := 0; hr < 100; hr++ { - var expProvisions sdk.Dec + var expProvisions sdk.Rat _, expProvisions, pool = updateProvisions(t, pool, params, hr) cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) } //get the pool and do the final value checks from checkFinalPoolValues - checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) } //_________________________________________________________________________________________ ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions -func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Dec) { +func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) - require.True(sdk.DecEq(t, calculatedTotalTokens, pool.TokenSupply())) + require.True(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) } // Processes provisions are added to the pool correctly every hour // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Dec, sdk.Dec, Pool) { +func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Rat, sdk.Rat, Pool) { expInflation := pool.NextInflation(params) - expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrDec) + expProvisions := expInflation.Mul(pool.TokenSupply().Round(precision)).Quo(hrsPerYrRat) startTotalSupply := pool.TokenSupply() pool = pool.ProcessProvisions(params) //check provisions were added to pool - require.True(sdk.DecEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) + require.True(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) return expInflation, expProvisions, pool } // Checks that The inflation will correctly increase or decrease after an update to the pool // nolint: gocyclo -func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Dec, msg string) { +func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { inflationChange := updatedInflation.Sub(previousInflation) switch { //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.LT(sdk.NewDecWithPrec(20, 2)): - require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) + case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.Equal(sdk.NewDecWithPrec(20, 2)): - if previousInflation.Equal(sdk.NewDecWithPrec(20, 2)) { + case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): + if previousInflation.Equal(sdk.NewRat(20, 100)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) } else { - require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) } //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && - updatedInflation.LT(sdk.NewDecWithPrec(20, 2)) && updatedInflation.GT(sdk.NewDecWithPrec(7, 2)): - require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) + case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && - updatedInflation.Equal(sdk.NewDecWithPrec(7, 2)): - - if previousInflation.Equal(sdk.NewDecWithPrec(7, 2)) { + case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): + if previousInflation.Equal(sdk.NewRat(7, 100)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) } else { - require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) } } } diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 282000294bce..27edad5dd28b 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -1,6 +1,7 @@ package types import ( + "math" "reflect" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,11 +11,18 @@ import ( // name to idetify transaction types const MsgType = "stake" +// Maximum amount of decimal points in the decimal representation of rationals +// used in MsgBeginUnbonding / MsgBeginRedelegate +const MaxBondDenominatorPrecision = 8 + // Verify interface at compile time var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{} var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{} var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{} +// Initialize Int for the denominator +var maximumBondingRationalDenominator = sdk.NewInt(int64(math.Pow10(MaxBondDenominatorPrecision))) + //______________________________________________________________________ // MsgCreateValidator - struct for unbonding transactions @@ -203,11 +211,11 @@ type MsgBeginRedelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` - SharesAmount sdk.Dec `json:"shares_amount"` + SharesAmount sdk.Rat `json:"shares_amount"` } func NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginRedelegate { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginRedelegate { return MsgBeginRedelegate{ DelegatorAddr: delegatorAddr, @@ -253,9 +261,12 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.ValidatorDstAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroDec()) { + if msg.SharesAmount.LTE(sdk.ZeroRat()) { return ErrBadSharesAmount(DefaultCodespace) } + if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { + return ErrBadSharesPrecision(DefaultCodespace) + } return nil } @@ -311,10 +322,10 @@ func (msg MsgCompleteRedelegate) ValidateBasic() sdk.Error { type MsgBeginUnbonding struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - SharesAmount sdk.Dec `json:"shares_amount"` + SharesAmount sdk.Rat `json:"shares_amount"` } -func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginUnbonding { +func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginUnbonding { return MsgBeginUnbonding{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, @@ -351,9 +362,12 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroDec()) { + if msg.SharesAmount.LTE(sdk.ZeroRat()) { return ErrBadSharesAmount(DefaultCodespace) } + if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { + return ErrBadSharesPrecision(DefaultCodespace) + } return nil } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 2be34fb20754..82f92d9f360f 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -143,15 +143,15 @@ func TestMsgBeginRedelegate(t *testing.T) { delegatorAddr sdk.AccAddress validatorSrcAddr sdk.AccAddress validatorDstAddr sdk.AccAddress - sharesAmount sdk.Dec + sharesAmount sdk.Rat expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewDecWithPrec(1, 1), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewDecWithPrec(-1, 1), false}, - {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDecWithPrec(1, 1), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, + {"regular", addr1, addr2, addr3, sdk.NewRat(1, 10), true}, + {"negative decimal", addr1, addr2, addr3, sdk.NewRat(-1, 10), false}, + {"zero amount", addr1, addr2, addr3, sdk.ZeroRat(), false}, + {"empty delegator", emptyAddr, addr1, addr3, sdk.NewRat(1, 10), false}, + {"empty source validator", addr1, emptyAddr, addr3, sdk.NewRat(1, 10), false}, + {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewRat(1, 10), false}, } for _, tc := range tests { @@ -195,14 +195,14 @@ func TestMsgBeginUnbonding(t *testing.T) { name string delegatorAddr sdk.AccAddress validatorAddr sdk.AccAddress - sharesAmount sdk.Dec + sharesAmount sdk.Rat expectPass bool }{ - {"regular", addr1, addr2, sdk.NewDecWithPrec(1, 1), true}, - {"negative decimal", addr1, addr2, sdk.NewDecWithPrec(-1, 1), false}, - {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewDecWithPrec(1, 1), false}, - {"empty validator", addr1, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, + {"regular", addr1, addr2, sdk.NewRat(1, 10), true}, + {"negative decimal", addr1, addr2, sdk.NewRat(-1, 10), false}, + {"zero amount", addr1, addr2, sdk.ZeroRat(), false}, + {"empty delegator", emptyAddr, addr1, sdk.NewRat(1, 10), false}, + {"empty validator", addr1, emptyAddr, sdk.NewRat(1, 10), false}, } for _, tc := range tests { diff --git a/x/stake/types/params.go b/x/stake/types/params.go index c2e28bbddfc1..0ae1ade090a1 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -2,22 +2,23 @@ package types import ( "bytes" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // defaultUnbondingTime reflects three weeks in seconds as the default // unbonding time. -const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 +const defaultUnbondingTime time.Duration = 60 * 60 * 24 * 3 * time.Second // Params defines the high level settings for staking type Params struct { - InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate - InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate - InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate - GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms + InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate + InflationMax sdk.Rat `json:"inflation_max"` // maximum inflation rate + InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate + GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms - UnbondingTime int64 `json:"unbonding_time"` + UnbondingTime time.Duration `json:"unbonding_time"` MaxValidators uint16 `json:"max_validators"` // maximum number of validators BondDenom string `json:"bond_denom"` // bondable coin denomination @@ -33,10 +34,10 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationRateChange: sdk.NewDecWithPrec(13, 2), - InflationMax: sdk.NewDecWithPrec(20, 2), - InflationMin: sdk.NewDecWithPrec(7, 2), - GoalBonded: sdk.NewDecWithPrec(67, 2), + InflationRateChange: sdk.NewRat(13, 100), + InflationMax: sdk.NewRat(20, 100), + InflationMin: sdk.NewRat(7, 100), + GoalBonded: sdk.NewRat(67, 100), UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 04325a4fbf52..5aab4294b36c 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -3,21 +3,22 @@ package types import ( "bytes" "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator - BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens - InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time - Inflation sdk.Dec `json:"inflation"` // current annual inflation rate + LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens + InflationLastTime time.Time `json:"inflation_last_time"` // block which the last inflation was processed + Inflation sdk.Rat `json:"inflation"` // current annual inflation rate DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily) // Fee Related - PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations + PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations } // nolint @@ -30,48 +31,48 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - LooseTokens: sdk.ZeroDec(), - BondedTokens: sdk.ZeroDec(), - InflationLastTime: 0, - Inflation: sdk.NewDecWithPrec(7, 2), + LooseTokens: sdk.ZeroRat(), + BondedTokens: sdk.ZeroRat(), + InflationLastTime: time.Unix(0, 0), + Inflation: sdk.NewRat(7, 100), DateLastCommissionReset: 0, - PrevBondedShares: sdk.ZeroDec(), + PrevBondedShares: sdk.ZeroRat(), } } //____________________________________________________________________ // Sum total of all staking tokens in the pool -func (p Pool) TokenSupply() sdk.Dec { +func (p Pool) TokenSupply() sdk.Rat { return p.LooseTokens.Add(p.BondedTokens) } //____________________________________________________________________ // get the bond ratio of the global state -func (p Pool) BondedRatio() sdk.Dec { +func (p Pool) BondedRatio() sdk.Rat { supply := p.TokenSupply() - if supply.GT(sdk.ZeroDec()) { + if supply.GT(sdk.ZeroRat()) { return p.BondedTokens.Quo(supply) } - return sdk.ZeroDec() + return sdk.ZeroRat() } //_______________________________________________________________________ -func (p Pool) looseTokensToBonded(bondedTokens sdk.Dec) Pool { +func (p Pool) looseTokensToBonded(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) p.LooseTokens = p.LooseTokens.Sub(bondedTokens) - if p.LooseTokens.LT(sdk.ZeroDec()) { + if p.LooseTokens.LT(sdk.ZeroRat()) { panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) } return p } -func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool { +func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) p.LooseTokens = p.LooseTokens.Add(bondedTokens) - if p.BondedTokens.LT(sdk.ZeroDec()) { + if p.BondedTokens.LT(sdk.ZeroRat()) { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } return p @@ -81,14 +82,14 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool { // Inflation const precision = 10000 // increased to this precision for accuracy -var hrsPerYrDec = sdk.NewDec(8766) // as defined by a julian year of 365.25 days +var hrsPerYrRat = sdk.NewRat(8766) // as defined by a julian year of 365.25 days // process provisions for an hour period func (p Pool) ProcessProvisions(params Params) Pool { p.Inflation = p.NextInflation(params) provisions := p.Inflation. - Mul(p.TokenSupply()). - Quo(hrsPerYrDec) + Mul(p.TokenSupply().Round(precision)). + Quo(hrsPerYrRat) // TODO add to the fees provisions p.LooseTokens = p.LooseTokens.Add(provisions) @@ -96,7 +97,7 @@ func (p Pool) ProcessProvisions(params Params) Pool { } // get the next inflation rate for the hour -func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { +func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { // The target annual inflation rate is recalculated for each previsions cycle. The // inflation is also subject to a rate change (positive or negative) depending on @@ -105,11 +106,11 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { // 7% and 20%. // (1 - bondedRatio/GoalBonded) * InflationRateChange - inflationRateChangePerYear := sdk.OneDec(). - Sub(p.BondedRatio(). + inflationRateChangePerYear := sdk.OneRat(). + Sub(p.BondedRatio().Round(precision). Quo(params.GoalBonded)). Mul(params.InflationRateChange) - inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrDec) + inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrRat) // increase the new annual inflation for this next cycle inflation = p.Inflation.Add(inflationRateChange) @@ -120,5 +121,5 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { inflation = params.InflationMin } - return inflation + return inflation.Round(precision) } diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 4541edd3d9c7..43a2eac065a4 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -11,28 +11,28 @@ func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() require.True(t, p1.Equal(p2)) - p2.BondedTokens = sdk.NewDec(3) + p2.BondedTokens = sdk.NewRat(3) require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) - pool.BondedTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewRat(10) + pool.BondedTokens = sdk.NewRat(10) - pool = pool.looseTokensToBonded(sdk.NewDec(10)) + pool = pool.looseTokensToBonded(sdk.NewRat(10)) - require.True(sdk.DecEq(t, sdk.NewDec(20), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(0), pool.LooseTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(20), pool.BondedTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10) - pool.BondedTokens = sdk.NewDec(10) + pool.LooseTokens = sdk.NewRat(10) + pool.BondedTokens = sdk.NewRat(10) - pool = pool.bondedTokensToLoose(sdk.NewDec(5)) + pool = pool.bondedTokensToLoose(sdk.NewRat(5)) - require.True(sdk.DecEq(t, sdk.NewDec(5), pool.BondedTokens)) - require.True(sdk.DecEq(t, sdk.NewDec(15), pool.LooseTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(5), pool.BondedTokens)) + require.True(sdk.RatEq(t, sdk.NewRat(15), pool.LooseTokens)) } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c9626b5ec5ca..837b8f8e8a02 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -26,21 +26,21 @@ type Validator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Dec `json:"prev_bonded_tokens"` // Previous bonded tokens held + LastBondedTokens sdk.Rat `json:"prev_bonded_tokens"` // Previous bonded tokens held } // NewValidator - initialize a new validator @@ -50,17 +50,17 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri PubKey: pubKey, Revoked: false, Status: sdk.Unbonded, - Tokens: sdk.ZeroDec(), - DelegatorShares: sdk.ZeroDec(), + Tokens: sdk.ZeroRat(), + DelegatorShares: sdk.ZeroRat(), Description: description, BondHeight: int64(0), BondIntraTxCounter: int16(0), ProposerRewardPool: sdk.Coins{}, - Commission: sdk.ZeroDec(), - CommissionMax: sdk.ZeroDec(), - CommissionChangeRate: sdk.ZeroDec(), - CommissionChangeToday: sdk.ZeroDec(), - LastBondedTokens: sdk.ZeroDec(), + Commission: sdk.ZeroRat(), + CommissionMax: sdk.ZeroRat(), + CommissionChangeRate: sdk.ZeroRat(), + CommissionChangeToday: sdk.ZeroRat(), + LastBondedTokens: sdk.ZeroRat(), } } @@ -69,17 +69,17 @@ type validatorValue struct { PubKey crypto.PubKey Revoked bool Status sdk.BondStatus - Tokens sdk.Dec - DelegatorShares sdk.Dec + Tokens sdk.Rat + DelegatorShares sdk.Rat Description Description BondHeight int64 BondIntraTxCounter int16 ProposerRewardPool sdk.Coins - Commission sdk.Dec - CommissionMax sdk.Dec - CommissionChangeRate sdk.Dec - CommissionChangeToday sdk.Dec - LastBondedTokens sdk.Dec + Commission sdk.Rat + CommissionMax sdk.Rat + CommissionChangeRate sdk.Rat + CommissionChangeToday sdk.Rat + LastBondedTokens sdk.Rat } // return the redelegation without fields contained within the key for the store @@ -159,8 +159,8 @@ func (v Validator) HumanReadableString() (string, error) { resp += fmt.Sprintf("Validator: %s\n", bechVal) resp += fmt.Sprintf("Revoked: %v\n", v.Revoked) resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) - resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.String()) - resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String()) + resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.FloatString()) + resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.FloatString()) resp += fmt.Sprintf("Description: %s\n", v.Description) resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) resp += fmt.Sprintf("Proposer Reward Pool: %s\n", v.ProposerRewardPool.String()) @@ -182,21 +182,21 @@ type BechValidator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Dec `json:"prev_bonded_shares"` // last bonded token amount + LastBondedTokens sdk.Rat `json:"prev_bonded_shares"` // last bonded token amount } // get the bech validator from the the regular validator @@ -364,7 +364,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, } // removes tokens from a validator -func (v Validator) RemoveTokens(pool Pool, tokens sdk.Dec) (Validator, Pool) { +func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { if v.Status == sdk.Bonded { pool = pool.bondedTokensToLoose(tokens) } @@ -376,25 +376,25 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Dec) (Validator, Pool) { //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Dec) { +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { // bondedShare/delegatedShare exRate := v.DelegatorShareExRate() - amountDec := sdk.NewDec(amount) + amountRat := sdk.NewRat(amount) if v.Status == sdk.Bonded { - pool = pool.looseTokensToBonded(amountDec) + pool = pool.looseTokensToBonded(amountRat) } - v.Tokens = v.Tokens.Add(amountDec) - issuedShares := amountDec.Quo(exRate) + v.Tokens = v.Tokens.Add(amountRat) + issuedShares := amountRat.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedShares } // RemoveDelShares removes delegator shares from a validator. -func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Pool, sdk.Dec) { +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { issuedTokens := v.DelegatorShareExRate().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) @@ -408,19 +408,19 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Poo // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. // UNITS: tokens/delegator-shares -func (v Validator) DelegatorShareExRate() sdk.Dec { +func (v Validator) DelegatorShareExRate() sdk.Rat { if v.DelegatorShares.IsZero() { - return sdk.OneDec() + return sdk.OneRat() } return v.Tokens.Quo(v.DelegatorShares) } // Get the bonded tokens which the validator holds -func (v Validator) BondedTokens() sdk.Dec { +func (v Validator) BondedTokens() sdk.Rat { if v.Status == sdk.Bonded { return v.Tokens } - return sdk.ZeroDec() + return sdk.ZeroRat() } //______________________________________________________________________ @@ -434,7 +434,7 @@ func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOwner() sdk.AccAddress { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } -func (v Validator) GetTokens() sdk.Dec { return v.Tokens } -func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } +func (v Validator) GetPower() sdk.Rat { return v.BondedTokens() } +func (v Validator) GetTokens() sdk.Rat { return v.Tokens } +func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index e92e02b96ede..f0dff4732c4d 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -3,6 +3,7 @@ package types import ( "fmt" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" @@ -74,19 +75,19 @@ func TestRemoveTokens(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100), - DelegatorShares: sdk.NewDec(100), + Tokens: sdk.NewRat(100), + DelegatorShares: sdk.NewRat(100), } pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewRat(10) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) // remove tokens and test check everything - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) + validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) @@ -97,7 +98,7 @@ func TestRemoveTokens(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) + validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) @@ -105,43 +106,43 @@ func TestRemoveTokens(t *testing.T) { func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewRat(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) + assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewRat(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewRat(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -150,16 +151,16 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewDec(100), - DelegatorShares: sdk.NewDec(100), + Tokens: sdk.NewRat(100), + DelegatorShares: sdk.NewRat(100), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewDec(10, 0) + poolA.LooseTokens = sdk.NewRat(10) poolA.BondedTokens = valA.BondedTokens() - require.Equal(t, valA.DelegatorShareExRate(), sdk.OneDec()) + require.Equal(t, valA.DelegatorShareExRate(), sdk.OneRat()) // Remove delegator shares - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10, 0)) + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) assert.Equal(t, int64(10), coinsB.RoundInt64()) assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) @@ -167,13 +168,13 @@ func TestRemoveDelShares(t *testing.T) { assert.Equal(t, int64(20), poolB.LooseTokens.RoundInt64()) // conservation of tokens - require.True(sdk.DecEq(t, + require.True(sdk.RatEq(t, poolB.LooseTokens.Add(poolB.BondedTokens), poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests - poolTokens := sdk.NewDec(5102, 0) - delShares := sdk.NewDec(115, 0) + poolTokens := sdk.NewRat(5102) + delShares := sdk.NewRat(115) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -182,27 +183,22 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - BondedTokens: sdk.NewDec(248305, 0), - LooseTokens: sdk.NewDec(232147, 0), - InflationLastTime: 0, - Inflation: sdk.NewDec(7, 2), + BondedTokens: sdk.NewRat(248305), + LooseTokens: sdk.NewRat(232147), + InflationLastTime: time.Unix(0, 0), + Inflation: sdk.NewRat(7, 100), } - shares := sdk.NewDec(29, 0) + shares := sdk.NewRat(29) _, newPool, tokens := validator.RemoveDelShares(pool, shares) - - exp, err := sdk.NewDecFromStr("1286.5913043477") - require.NoError(t, err) - - require.True(sdk.DecEq(t, exp, tokens)) - - require.True(sdk.DecEq(t, + require.True(sdk.RatEq(t, sdk.NewRat(147958, 115), tokens)) + require.True(sdk.RatEq(t, newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) } func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(100) + pool.LooseTokens = sdk.NewRat(100) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) @@ -225,8 +221,8 @@ func TestUpdateStatus(t *testing.T) { } func TestPossibleOverflow(t *testing.T) { - poolTokens := sdk.NewDec(2159, 0) - delShares := sdk.NewDec(391432570689183511, 0).Quo(sdk.NewDec(40113011844664, 0)) + poolTokens := sdk.NewRat(2159) + delShares := sdk.NewRat(391432570689183511).Quo(sdk.NewRat(40113011844664)) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -235,17 +231,17 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewDec(100), + LooseTokens: sdk.NewRat(100), BondedTokens: poolTokens, - InflationLastTime: 0, - Inflation: sdk.NewDec(7, 2), + InflationLastTime: time.Unix(0, 0), + Inflation: sdk.NewRat(7, 100), } tokens := int64(71) msg := fmt.Sprintf("validator %#v", validator) newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroDec()), + require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative DelegatorShareExRate(): %v", msg, newValidator.DelegatorShareExRate()) } From 18b48261846b3521ffed26f0edc9f7125bda69de Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 14:50:37 -0400 Subject: [PATCH 43/50] ... --- client/lcd/test_helpers.go | 2 +- docs/spec/inflation/state.md | 2 +- x/distribution/keeper.go | 4 +- x/distribution/keeper_test.go | 8 +-- x/distribution/movement.go | 14 ++--- x/distribution/types.go | 22 +++---- x/gov/genesis.go | 6 +- x/gov/procedures.go | 6 +- x/gov/proposals.go | 16 ++--- x/gov/tally.go | 22 +++---- x/gov/test_common.go | 2 +- x/params/keeper.go | 12 ++-- x/params/keeper_test.go | 6 +- x/slashing/app_test.go | 4 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper_test.go | 12 ++-- x/slashing/params.go | 12 ++-- x/slashing/test_common.go | 2 +- x/slashing/tick_test.go | 2 +- x/stake/app_test.go | 18 +++--- x/stake/client/cli/tx.go | 12 ++-- x/stake/client/rest/tx.go | 4 +- x/stake/genesis_test.go | 20 +++--- x/stake/handler_test.go | 66 ++++++++++---------- x/stake/keeper/delegation.go | 10 +-- x/stake/keeper/delegation_test.go | 32 +++++----- x/stake/keeper/keeper_test.go | 2 +- x/stake/keeper/sdk_types.go | 2 +- x/stake/keeper/slash.go | 22 +++---- x/stake/keeper/slash_test.go | 58 ++++++++--------- x/stake/keeper/test_common.go | 10 +-- x/stake/keeper/validator_test.go | 100 +++++++++++++++--------------- x/stake/simulation/invariants.go | 4 +- x/stake/simulation/msgs.go | 6 +- x/stake/types/delegation.go | 23 ++++--- x/stake/types/delegation_test.go | 21 +++---- x/stake/types/errors.go | 10 +-- x/stake/types/inflation_test.go | 65 ++++++++++--------- x/stake/types/msg.go | 26 ++------ x/stake/types/msg_test.go | 26 ++++---- x/stake/types/params.go | 21 +++---- x/stake/types/pool.go | 53 ++++++++-------- x/stake/types/pool_test.go | 22 +++---- x/stake/types/validator.go | 88 +++++++++++++------------- x/stake/types/validator_test.go | 84 +++++++++++++------------ 45 files changed, 471 insertions(+), 490 deletions(-) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index ee46b267dd08..818eae1e86f6 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -173,7 +173,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewRat(100)) + genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) } appState, err := wire.MarshalJSONIndent(cdc, genesisState) diff --git a/docs/spec/inflation/state.md b/docs/spec/inflation/state.md index dea10c046265..c16286804a65 100644 --- a/docs/spec/inflation/state.md +++ b/docs/spec/inflation/state.md @@ -7,7 +7,7 @@ The current annual inflation rate. ```golang -type Inflation sdk.Rat +type Inflation sdk.Dec ``` ### InflationLastTime diff --git a/x/distribution/keeper.go b/x/distribution/keeper.go index 1450717193bb..aba07eaca1c1 100644 --- a/x/distribution/keeper.go +++ b/x/distribution/keeper.go @@ -23,13 +23,13 @@ package stake ////_________________________________________________________________________ //// cummulative power of the non-absent prevotes -//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat { +//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Dec { //store := ctx.KVStore(k.storeKey) //// get absent prevote indexes //absents := ctx.AbsentValidators() -//TotalPower := sdk.ZeroRat() +//TotalPower := sdk.ZeroDec() //i := int32(0) //iterator := store.SubspaceIterator(ValidatorsBondedKey) //for ; iterator.Valid(); iterator.Next() { diff --git a/x/distribution/keeper_test.go b/x/distribution/keeper_test.go index 0d732f8a1917..8902680604e7 100644 --- a/x/distribution/keeper_test.go +++ b/x/distribution/keeper_test.go @@ -8,8 +8,8 @@ package stake //var candidatesIn [5]Candidate //for i, amt := range amts { //candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) -//candidatesIn[i].BondedShares = sdk.NewRat(amt) -//candidatesIn[i].DelegatorShares = sdk.NewRat(amt) +//candidatesIn[i].BondedShares = sdk.NewDec(amt) +//candidatesIn[i].DelegatorShares = sdk.NewDec(amt) //keeper.setCandidate(ctx, candidatesIn[i]) //} @@ -18,7 +18,7 @@ package stake //require.Equal(t, 5, len(gotValidators)) //totPow := keeper.GetTotalPrecommitVotingPower(ctx) -//exp := sdk.NewRat(11111) +//exp := sdk.NewDec(11111) //require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address @@ -26,6 +26,6 @@ package stake //totPow = keeper.GetTotalPrecommitVotingPower(ctx) //// XXX verify that this order should infact exclude these two records -//exp = sdk.NewRat(11100) +//exp = sdk.NewDec(11100) //require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //} diff --git a/x/distribution/movement.go b/x/distribution/movement.go index 03c4de72cb05..399a25a68133 100644 --- a/x/distribution/movement.go +++ b/x/distribution/movement.go @@ -17,7 +17,7 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //// calculate the proposer reward //precommitPower := k.GetTotalPrecommitVotingPower(ctx) -//toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) +//toProposer := coinsMulRat(collectedFees, (sdk.NewDec(1, 100).Add(sdk.NewDec(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) //candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) //toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee) @@ -34,10 +34,10 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //k.setPool(ctx, pool) //} -//func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins { +//func coinsMulRat(coins sdk.Coins, rat sdk.Dec) sdk.Coins { //var res sdk.Coins //for _, coin := range coins { -//coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate() +//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount)).Evaluate() //coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} //res = res.Plus(coinMul) //} @@ -49,14 +49,14 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} //// calculate adjustment changes for a candidate at a height //func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { -//heightRat := sdk.NewRat(height) -//lastHeightRat := sdk.NewRat(height - 1) +//heightRat := sdk.NewDec(height) +//lastHeightRat := sdk.NewDec(height - 1) //candidateFeeCount := candidate.BondedShares.Mul(heightRat) //poolFeeCount := pool.BondedShares.Mul(heightRat) //for i, denom := range denoms { -//poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom)) -//poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom)) +//poolFeeSumReceived := sdk.NewDec(pool.FeeSumReceived.AmountOf(denom)) +//poolFeeRecent := sdk.NewDec(pool.FeeRecent.AmountOf(denom)) //// calculate simple and projected pools //simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) //calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent) diff --git a/x/distribution/types.go b/x/distribution/types.go index f9d4f905f6bc..2234104717c0 100644 --- a/x/distribution/types.go +++ b/x/distribution/types.go @@ -23,8 +23,8 @@ package stake //// fee information for a validator //type Validator struct { -//Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +//Adjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // total shares of a global hold pools //} ////_________________________________________________________________________ @@ -32,7 +32,7 @@ package stake //// Params defines the high level settings for staking //type Params struct { //FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms -//ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool +//ReservePoolFee sdk.Dec `json:"reserve_pool_fee"` // percent of fees which go to reserve pool //} //func (p Params) equal(p2 Params) bool { @@ -43,7 +43,7 @@ package stake //func defaultParams() Params { //return Params{ //FeeDenoms: []string{"steak"}, -//ReservePoolFee: sdk.NewRat(5, 100), +//ReservePoolFee: sdk.NewDec(5, 100), //} //} @@ -55,8 +55,8 @@ package stake //FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed //FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` //FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected -//FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares +//FeeAdjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // XXX last recorded bonded shares //} //func (p Pool) equal(p2 Pool) bool { @@ -64,7 +64,7 @@ package stake //p.FeePool.IsEqual(p2.FeePool) && //p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && //p.FeeRecent.IsEqual(p2.FeeRecent) && -//sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) && +//sdk.DecsEqual(p.FeeAdjustments, p2.FeeAdjustments) && //p.PrevBondedShares.Equal(p2.PrevBondedShares) //} @@ -75,8 +75,8 @@ package stake //FeePool: sdk.Coins(nil), //FeeSumReceived: sdk.Coins(nil), //FeeRecent: sdk.Coins(nil), -//FeeAdjustments: []sdk.Rat{sdk.ZeroRat()}, -//PrevBondedShares: sdk.ZeroRat(), +//FeeAdjustments: []sdk.Dec{sdk.ZeroDec()}, +//PrevBondedShares: sdk.ZeroDec(), //} //} @@ -85,8 +85,8 @@ package stake //// Used in calculation of fee shares, added to a queue for each block where a power change occures //type PowerChange struct { //Height int64 `json:"height"` // block height at change -//Power sdk.Rat `json:"power"` // total power at change -//PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1 +//Power sdk.Dec `json:"power"` // total power at change +//PrevPower sdk.Dec `json:"prev_power"` // total power at previous height-1 //FeesIn sdk.Coins `json:"fees_in"` // fees in at block height //PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height //} diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 78b39ff1c70f..42d0e0d6cc68 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewRat(1, 2), - Veto: sdk.NewRat(1, 3), - GovernancePenalty: sdk.NewRat(1, 100), + Threshold: sdk.NewDec(1, 2), + Veto: sdk.NewDec(1, 3), + GovernancePenalty: sdk.NewDec(1, 100), }, } } diff --git a/x/gov/procedures.go b/x/gov/procedures.go index f46c2149fa6b..f74091c74fda 100644 --- a/x/gov/procedures.go +++ b/x/gov/procedures.go @@ -12,9 +12,9 @@ type DepositProcedure struct { // Procedure around Tallying votes in governance type TallyingProcedure struct { - Threshold sdk.Rat `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 - Veto sdk.Rat `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 - GovernancePenalty sdk.Rat `json:"governance_penalty"` // Penalty if validator does not vote + Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 + Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 + GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote } // Procedure around Voting in governance diff --git a/x/gov/proposals.go b/x/gov/proposals.go index 0a7f5de70dac..f05dabd08d06 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -297,19 +297,19 @@ func (status ProposalStatus) Format(s fmt.State, verb rune) { //----------------------------------------------------------- // Tally Results type TallyResult struct { - Yes sdk.Rat `json:"yes"` - Abstain sdk.Rat `json:"abstain"` - No sdk.Rat `json:"no"` - NoWithVeto sdk.Rat `json:"no_with_veto"` + Yes sdk.Dec `json:"yes"` + Abstain sdk.Dec `json:"abstain"` + No sdk.Dec `json:"no"` + NoWithVeto sdk.Dec `json:"no_with_veto"` } // checks if two proposals are equal func EmptyTallyResult() TallyResult { return TallyResult{ - Yes: sdk.ZeroRat(), - Abstain: sdk.ZeroRat(), - No: sdk.ZeroRat(), - NoWithVeto: sdk.ZeroRat(), + Yes: sdk.ZeroDec(), + Abstain: sdk.ZeroDec(), + No: sdk.ZeroDec(), + NoWithVeto: sdk.ZeroDec(), } } diff --git a/x/gov/tally.go b/x/gov/tally.go index f8a341e1ed9d..fc5b4317b26a 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -7,20 +7,20 @@ import ( // validatorGovInfo used for tallying type validatorGovInfo struct { Address sdk.AccAddress // sdk.AccAddress of the validator owner - Power sdk.Rat // Power of a Validator - DelegatorShares sdk.Rat // Total outstanding delegator shares - Minus sdk.Rat // Minus of validator, used to compute validator's voting power + Power sdk.Dec // Power of a Validator + DelegatorShares sdk.Dec // Total outstanding delegator shares + Minus sdk.Dec // Minus of validator, used to compute validator's voting power Vote VoteOption // Vote of the validator } func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.AccAddress) { - results := make(map[VoteOption]sdk.Rat) - results[OptionYes] = sdk.ZeroRat() - results[OptionAbstain] = sdk.ZeroRat() - results[OptionNo] = sdk.ZeroRat() - results[OptionNoWithVeto] = sdk.ZeroRat() + results := make(map[VoteOption]sdk.Dec) + results[OptionYes] = sdk.ZeroDec() + results[OptionAbstain] = sdk.ZeroDec() + results[OptionNo] = sdk.ZeroDec() + results[OptionNoWithVeto] = sdk.ZeroDec() - totalVotingPower := sdk.ZeroRat() + totalVotingPower := sdk.ZeroDec() currValidators := make(map[string]validatorGovInfo) keeper.vs.IterateValidatorsBonded(ctx, func(index int64, validator sdk.Validator) (stop bool) { @@ -28,7 +28,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall Address: validator.GetOwner(), Power: validator.GetPower(), DelegatorShares: validator.GetDelegatorShares(), - Minus: sdk.ZeroRat(), + Minus: sdk.ZeroDec(), Vote: OptionEmpty, } return false @@ -91,7 +91,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall } // If no one votes, proposal fails - if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroRat()) { + if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroDec()) { return false, tallyResults, nonVoting } // If more than 1/3 of voters veto, proposal fails diff --git a/x/gov/test_common.go b/x/gov/test_common.go index df66fa40c493..5e7977b50c34 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -64,7 +64,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { diff --git a/x/params/keeper.go b/x/params/keeper.go index 8817b7c6c8de..69bcc05ea8aa 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -183,8 +183,8 @@ func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) { return } -// GetRat is helper function for rat params -func (k Getter) GetRat(ctx sdk.Context, key string) (res sdk.Rat, err error) { +// GetDec is helper function for decimal params +func (k Getter) GetDec(ctx sdk.Context, key string) (res sdk.Dec, err error) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) err = k.k.cdc.UnmarshalBinary(bz, &res) @@ -301,8 +301,8 @@ func (k Getter) GetUintWithDefault(ctx sdk.Context, key string, def sdk.Uint) (r return } -// GetRatWithDefault is helper function for sdk.Rat params with default value -func (k Getter) GetRatWithDefault(ctx sdk.Context, key string, def sdk.Rat) (res sdk.Rat) { +// GetDecWithDefault is helper function for sdk.Dec params with default value +func (k Getter) GetDecWithDefault(ctx sdk.Context, key string, def sdk.Dec) (res sdk.Dec) { store := ctx.KVStore(k.k.key) bz := store.Get([]byte(key)) if bz == nil { @@ -397,8 +397,8 @@ func (k Setter) SetUint(ctx sdk.Context, key string, param sdk.Uint) { } } -// SetRat is helper function for rat params -func (k Setter) SetRat(ctx sdk.Context, key string, param sdk.Rat) { +// SetDec is helper function for decimal params +func (k Setter) SetDec(ctx sdk.Context, key string, param sdk.Dec) { if err := k.k.set(ctx, key, param); err != nil { panic(err) } diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 4bb5744ea458..0afa898b3f13 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -94,7 +94,7 @@ func TestGetter(t *testing.T) { {"uint64", uint64(1)}, {"int", sdk.NewInt(1)}, {"uint", sdk.NewUint(1)}, - {"rat", sdk.NewRat(1)}, + {"rat", sdk.NewDec(1)}, } assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewRat(1)) }) + assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewDec(1)) }) var res interface{} var err error @@ -263,7 +263,7 @@ func TestGetter(t *testing.T) { assert.Equal(t, def9, res) // Rat - def10 := sdk.NewRat(0) + def10 := sdk.NewDec(0) res, err = g.GetRat(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 523a2e220941..1e6a4e89d4b4 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -58,7 +58,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) @@ -109,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { validator := checkValidator(t, mapp, stakeKeeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} // no signing info yet diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 89c1e11a604b..41cb5d19968c 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // assert non-revoked validator can't be unrevoked got = slh(ctx, NewMsgUnrevoke(addr)) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index d3d6b06ed690..68de7a43c5e0 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -31,7 +31,7 @@ func TestHandleDoubleSign(t *testing.T) { validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) @@ -44,12 +44,12 @@ func TestHandleDoubleSign(t *testing.T) { // unrevoke to measure power sk.Unrevoke(ctx, val) // power should be reduced - require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, time.Unix(0, 0), amtInt) - require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) } // Test a validator through uptime, downtime, revocation, @@ -67,7 +67,7 @@ func TestHandleAbsentValidator(t *testing.T) { validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -131,7 +131,7 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should have been slashed pool = sk.GetPool(ctx) - slashAmt := sdk.NewRat(amtInt).Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() + slashAmt := sdk.NewDec(amtInt).Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64() require.Equal(t, int64(amtInt)-slashAmt, pool.BondedTokens.RoundInt64()) // validator start height should have been changed @@ -177,7 +177,7 @@ func TestHandleNewValidator(t *testing.T) { validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) diff --git a/x/slashing/params.go b/x/slashing/params.go index 9d1bc39609db..6608518ae421 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -32,7 +32,7 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) signedBlocksWindow := k.SignedBlocksWindow(ctx) - return sdk.NewRat(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() + return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() } // Double-sign unbond duration @@ -46,12 +46,12 @@ func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration { } // SlashFractionDoubleSign - currently default 5% -func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Rat { +func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec { return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) } // SlashFractionDowntime - currently default 1% -func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Rat { +func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec { return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) } @@ -72,9 +72,9 @@ var ( // TODO Temporarily set to 10 minutes for testnets defaultDowntimeUnbondDuration int64 = 60 * 10 - defaultMinSignedPerWindow = sdk.NewRat(1, 2) + defaultMinSignedPerWindow = sdk.NewDec(1, 2) - defaultSlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) + defaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20)) - defaultSlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) + defaultSlashFractionDowntime = sdk.NewDec(1).Quo(sdk.NewDec(100)) ) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 7b3ab04362c5..50c501d7e3bd 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -69,7 +69,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - genesis.Pool.LooseTokens = sdk.NewRat(initCoins.MulRaw(int64(len(addrs))).Int64()) + genesis.Pool.LooseTokens = sdk.NewDec(initCoins.MulRaw(int64(len(addrs))).Int64()) _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 8e0d66ed63f8..b230f9c94004 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -22,7 +22,7 @@ func TestBeginBlocker(t *testing.T) { validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) val := abci.Validator{ Address: pk.Address(), diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 4e1b2c2acdea..9847ed2904b6 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -63,7 +63,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := DefaultGenesisState() - stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) + stakeGenesis.Pool.LooseTokens = sdk.NewDec(100000) validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { @@ -90,14 +90,14 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, func checkDelegation( t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, - validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Rat, + validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Dec, ) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { require.True(t, found) - require.True(sdk.RatEq(t, expShares, delegation.Shares)) + require.True(sdk.DecEq(t, expShares, delegation.Shares)) return } @@ -138,7 +138,7 @@ func TestStakeMsgs(t *testing.T) { validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) // addr1 create validator on behalf of addr2 createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) @@ -150,10 +150,10 @@ func TestStakeMsgs(t *testing.T) { validator = checkValidator(t, mApp, keeper, addr2, true) require.Equal(t, addr2, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status) - require.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) // edit the validator description = NewDescription("bar_moniker", "", "", "") @@ -169,14 +169,14 @@ func TestStakeMsgs(t *testing.T) { mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10)) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore - checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{}) + checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Dec{}) // balance should be the same because bonding not yet complete mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 4c86777f343d..77f0520f333f 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -239,27 +239,27 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { func getShares( storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercentStr string, delegatorAddr, validatorAddr sdk.AccAddress, -) (sharesAmount sdk.Rat, err error) { +) (sharesAmount sdk.Dec, err error) { switch { case sharesAmountStr != "" && sharesPercentStr != "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) + sharesAmount, err = sdk.NewDecFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesAmount.GT(sdk.ZeroRat()) { + if !sharesAmount.GT(sdk.ZeroDec()) { return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)") } case sharesPercentStr != "": - var sharesPercent sdk.Rat - sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) + var sharesPercent sdk.Dec + sharesPercent, err = sdk.NewDecFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } - if !sharesPercent.GT(sdk.ZeroRat()) || !sharesPercent.LTE(sdk.OneRat()) { + if !sharesPercent.GT(sdk.ZeroDec()) || !sharesPercent.LTE(sdk.OneDec()) { return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)") } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index fbefc7f21987..917794065471 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -160,7 +160,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) @@ -234,7 +234,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 2febd2c6a636..9cdbe19826bc 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -17,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewRat(2) + pool.BondedTokens = sdk.NewDec(2) params := keeper.GetParams(ctx) var delegations []Delegation @@ -32,11 +32,11 @@ func TestInitGenesis(t *testing.T) { // initialize the validators validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.OneRat() - validators[0].DelegatorShares = sdk.OneRat() + validators[0].Tokens = sdk.OneDec() + validators[0].DelegatorShares = sdk.OneDec() validators[1].Status = sdk.Bonded - validators[1].Tokens = sdk.OneRat() - validators[1].DelegatorShares = sdk.OneRat() + validators[1].Tokens = sdk.OneDec() + validators[1].DelegatorShares = sdk.OneDec() genesisState = types.NewGenesisState(pool, params, validators, delegations) vals, err := InitGenesis(ctx, keeper, genesisState) @@ -69,7 +69,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) - pool.BondedTokens = sdk.NewRat(int64(200 + (size - 100))) + pool.BondedTokens = sdk.NewDec(int64(200 + (size - 100))) params := keeper.GetParams(ctx) delegations := []Delegation{} @@ -80,11 +80,11 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators[i].Status = sdk.Bonded if i < 100 { - validators[i].Tokens = sdk.NewRat(2) - validators[i].DelegatorShares = sdk.NewRat(2) + validators[i].Tokens = sdk.NewDec(2) + validators[i].DelegatorShares = sdk.NewDec(2) } else { - validators[i].Tokens = sdk.OneRat() - validators[i].DelegatorShares = sdk.OneRat() + validators[i].Tokens = sdk.OneDec() + validators[i].DelegatorShares = sdk.OneDec() } } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index edad64f4477a..735fe7701459 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -81,7 +81,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(1, 2)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -110,7 +110,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(1000000)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -138,8 +138,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.Owner) assert.Equal(t, pk1, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.BondedTokens()) - assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) + assert.Equal(t, sdk.NewDec(10), validator.BondedTokens()) + assert.Equal(t, sdk.NewDec(10), validator.DelegatorShares) assert.Equal(t, Description{}, validator.Description) // two validators can't have the same owner address @@ -162,8 +162,8 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr2, validator.Owner) assert.Equal(t, pk2, validator.PubKey) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) } @@ -182,8 +182,8 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, validatorAddr, validator.Owner) assert.Equal(t, pk, validator.PubKey) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) assert.Equal(t, Description{}, validator.Description) // one validator cannot be created twice even from different delegator @@ -221,7 +221,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) + require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v", exRate) require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64()) // just send the same msgbond multiple times @@ -240,7 +240,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.True(t, found) exRate := validator.DelegatorShareExRate() - require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v, i = %v", exRate, i) + require.True(t, exRate.Equal(sdk.OneDec()), "expected exRate 1 got %v, i = %v", exRate, i) expBond := int64(i+1) * bondAmount expDelegatorShares := int64(i+2) * bondAmount // (1 self delegation) @@ -295,7 +295,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { // just send the same msgUnbond multiple times // TODO use decimals here - unbondShares := sdk.NewRat(10) + unbondShares := sdk.NewDec(10) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) numUnbonds := 5 @@ -339,7 +339,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } for _, c := range errorCases { - unbondShares := sdk.NewRat(int64(c)) + unbondShares := sdk.NewDec(int64(c)) msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "expected unbond msg to fail") @@ -348,14 +348,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have - unbondShares = sdk.NewRat(leftBonded + 1) + unbondShares = sdk.NewDec(leftBonded + 1) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have - unbondShares = sdk.NewRat(leftBonded) + unbondShares = sdk.NewDec(leftBonded) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), @@ -391,7 +391,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { for i, validatorAddr := range validatorAddrs { _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewRat(10)) // remove delegation + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -436,7 +436,7 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { - msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) @@ -467,7 +467,7 @@ func TestRevokeValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -483,7 +483,7 @@ func TestRevokeValidator(t *testing.T) { require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds - msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper) require.True(t, got.IsOK(), "expected no error") @@ -510,7 +510,7 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") @@ -565,7 +565,7 @@ func TestRedelegationPeriod(t *testing.T) { bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) @@ -617,12 +617,12 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewRat(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewRat(10)) + msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) @@ -663,7 +663,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -785,7 +785,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewRat(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -798,7 +798,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewRat(50)) + msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -832,22 +832,22 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx = ctx.WithBlockHeight(1) // begin unbonding 4 stake - msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewRat(4)) + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewDec(4)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // begin redelegate 6 stake - msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewRat(6)) + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewDec(6)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(6), delegation.Shares) + require.Equal(t, sdk.NewDec(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(1, 2)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -862,16 +862,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced by half validator, found := keeper.GetValidator(ctx, valA) require.True(t, found) - require.Equal(t, sdk.NewRat(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(1, 2)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) @@ -886,7 +886,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) require.True(t, found) - require.Equal(t, sdk.NewRat(3), delegation.Shares) + require.Equal(t, sdk.NewDec(3), delegation.Shares) // validator power should have been reduced to zero // ergo validator should have been removed from the store diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 484e85ad5c42..4b4d267aa20c 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -218,7 +218,7 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { // Perform a delegation, set/update everything necessary within the store. func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt sdk.Coin, - validator types.Validator, subtractAccount bool) (newShares sdk.Rat, err sdk.Error) { + validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { // Get or create the delegator delegation delegation, found := k.GetDelegation(ctx, delegatorAddr, validator.Owner) @@ -226,7 +226,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt delegation = types.Delegation{ DelegatorAddr: delegatorAddr, ValidatorAddr: validator.Owner, - Shares: sdk.ZeroRat(), + Shares: sdk.ZeroDec(), } } @@ -254,7 +254,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt // unbond the the delegation return func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, - shares sdk.Rat) (amount sdk.Rat, err sdk.Error) { + shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { // check if delegation has any shares in it unbond delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -312,7 +312,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr //______________________________________________________________________________________________________ // complete unbonding an unbonding record -func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { +func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 _, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) @@ -365,7 +365,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr // complete unbonding an unbonding record func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) sdk.Error { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delegatorAddr, validatorSrcAddr) { diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 5d512f0cf5ba..4333a749426f 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -32,7 +32,7 @@ func TestDelegation(t *testing.T) { bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], - Shares: sdk.NewRat(9), + Shares: sdk.NewDec(9), } // check the empty keeper first @@ -46,18 +46,18 @@ func TestDelegation(t *testing.T) { require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve - bond1to1.Shares = sdk.NewRat(99) + bond1to1.Shares = sdk.NewDec(99) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) require.True(t, bond1to1.Equal(resBond)) // add some more records - bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} - bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewRat(9), 1} - bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewRat(9), 2} - bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewRat(9), 3} - bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewRat(9), 4} + bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewDec(9), 0} + bond1to3 := types.Delegation{addrDels[0], addrVals[2], sdk.NewDec(9), 1} + bond2to1 := types.Delegation{addrDels[1], addrVals[0], sdk.NewDec(9), 2} + bond2to2 := types.Delegation{addrDels[1], addrVals[1], sdk.NewDec(9), 3} + bond2to3 := types.Delegation{addrDels[1], addrVals[2], sdk.NewDec(9), 4} keeper.SetDelegation(ctx, bond1to2) keeper.SetDelegation(ctx, bond1to3) keeper.SetDelegation(ctx, bond2to1) @@ -142,7 +142,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -163,8 +163,8 @@ func TestUnbondDelegation(t *testing.T) { keeper.SetDelegation(ctx, delegation) var err error - var amount sdk.Rat - amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewRat(6)) + var amount sdk.Dec + amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) require.NoError(t, err) require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation @@ -190,8 +190,8 @@ func TestGetRedelegationsFromValidator(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewRat(5), - SharesDst: sdk.NewRat(5), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // set and retrieve a record @@ -220,8 +220,8 @@ func TestRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 0, MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewRat(5), - SharesDst: sdk.NewRat(5), + SharesSrc: sdk.NewDec(5), + SharesDst: sdk.NewDec(5), } // test shouldn't have and redelegations @@ -242,8 +242,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewRat(21) - rd.SharesDst = sdk.NewRat(21) + rd.SharesSrc = sdk.NewDec(21) + rd.SharesDst = sdk.NewDec(21) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 3f763ea25efa..9307ddddf252 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -33,7 +33,7 @@ func TestPool(t *testing.T) { require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve - expPool.BondedTokens = sdk.NewRat(777) + expPool.BondedTokens = sdk.NewDec(777) keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) require.True(t, expPool.Equal(resPool)) diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 9c331147447e..aeec44fae959 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -69,7 +69,7 @@ func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Val } // total power from the bond -func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { +func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec { pool := k.GetPool(ctx) return pool.BondedTokens } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index a741b5a85766..a5757d5cd8fd 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -20,15 +20,15 @@ import ( // CONTRACT: // Infraction committed at the current height or at a past height, // not at a height in the future -func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Rat) { +func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) { logger := ctx.Logger().With("module", "x/stake") - if slashFactor.LT(sdk.ZeroRat()) { + if slashFactor.LT(sdk.ZeroDec()) { panic(fmt.Errorf("attempted to slash with a negative slashFactor: %v", slashFactor)) } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewRat(power).Mul(slashFactor) + slashAmount := sdk.NewDec(power).Mul(slashFactor) // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -150,23 +150,23 @@ func (k Keeper) setRevoked(ctx sdk.Context, pubkey crypto.PubKey, revoked bool) // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, - infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { now := ctx.BlockHeader().Time // If unbonding started before this height, stake didn't contribute to infraction if unbondingDelegation.CreationHeight < infractionHeight { - return sdk.ZeroRat() + return sdk.ZeroDec() } if unbondingDelegation.MinTime.Before(now) { // Unbonding delegation no longer eligible for slashing, skip it // TODO Settle and delete it automatically? - return sdk.ZeroRat() + return sdk.ZeroDec() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -194,23 +194,23 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, - infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Rat) { + infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) { now := ctx.BlockHeader().Time // If redelegation started before this height, stake didn't contribute to infraction if redelegation.CreationHeight < infractionHeight { - return sdk.ZeroRat() + return sdk.ZeroDec() } if redelegation.MinTime.Before(now) { // Redelegation no longer eligible for slashing, skip it // TODO Delete it automatically? - return sdk.ZeroRat() + return sdk.ZeroDec() } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 878c44d1eb80..3aea1083a83e 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -19,7 +19,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewRat(amt * int64(numVals)) + pool.LooseTokens = sdk.NewDec(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { @@ -63,7 +63,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -106,7 +106,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rd := types.Redelegation{ @@ -116,8 +116,8 @@ func TestSlashRedelegation(t *testing.T) { CreationHeight: 0, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewRat(10), - SharesDst: sdk.NewRat(10), + SharesSrc: sdk.NewDec(10), + SharesDst: sdk.NewDec(10), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), Balance: sdk.NewInt64Coin(params.BondDenom, 10), } @@ -127,7 +127,7 @@ func TestSlashRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(10), + Shares: sdk.NewDec(10), } keeper.SetDelegation(ctx, del) @@ -172,7 +172,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -180,7 +180,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -193,16 +193,16 @@ func TestSlashAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // power decreased - require.Equal(t, sdk.NewRat(5), validator.GetPower()) + require.Equal(t, sdk.NewDec(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + require.Equal(t, sdk.NewDec(5).RoundInt64(), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -239,7 +239,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewRat(7), validator.GetPower()) + require.Equal(t, sdk.NewDec(7), validator.GetPower()) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -256,7 +256,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewRat(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -276,7 +276,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 3 again - require.Equal(t, sdk.NewRat(1), validator.GetPower()) + require.Equal(t, sdk.NewDec(1), validator.GetPower()) // slash validator again // all originally bonded stake has been slashed, so this will have no effect @@ -303,7 +303,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rd := types.Redelegation{ @@ -312,8 +312,8 @@ func TestSlashWithRedelegation(t *testing.T) { ValidatorDstAddr: addrVals[1], CreationHeight: 11, MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewRat(6), - SharesDst: sdk.NewRat(6), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -323,13 +323,13 @@ func TestSlashWithRedelegation(t *testing.T) { del := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(6), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, del) // update bonded tokens pool := keeper.GetPool(ctx) - pool.BondedTokens = pool.BondedTokens.Add(sdk.NewRat(6)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(6)) keeper.SetPool(ctx, pool) // slash validator @@ -355,13 +355,13 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, sdk.NewRat(8), validator.GetPower()) + require.Equal(t, sdk.NewDec(8), validator.GetPower()) // slash the validator again ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) }) + require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -376,13 +376,13 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) // power decreased by 4 - require.Equal(t, sdk.NewRat(4), validator.GetPower()) + require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) validator, found = keeper.GetValidatorByPubKey(ctx, pk) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -404,7 +404,7 @@ func TestSlashWithRedelegation(t *testing.T) { // validator no longer in the store _, found = keeper.GetValidatorByPubKey(ctx, pk) require.False(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -424,7 +424,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewRat(1, 2) + fraction := sdk.NewDec(1, 2) // set a redelegation rdA := types.Redelegation{ @@ -434,8 +434,8 @@ func TestSlashBoth(t *testing.T) { CreationHeight: 11, // expiration timestamp (beyond which the redelegation shouldn't be slashed) MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewRat(6), - SharesDst: sdk.NewRat(6), + SharesSrc: sdk.NewDec(6), + SharesDst: sdk.NewDec(6), InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), Balance: sdk.NewInt64Coin(params.BondDenom, 6), } @@ -445,7 +445,7 @@ func TestSlashBoth(t *testing.T) { delA := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[1], - Shares: sdk.NewRat(6), + Shares: sdk.NewDec(6), } keeper.SetDelegation(ctx, delA) @@ -483,5 +483,5 @@ func TestSlashBoth(t *testing.T) { validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, sdk.NewRat(10), validator.GetPower()) + require.Equal(t, sdk.NewDec(10), validator.GetPower()) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 010963034982..86dacccdb885 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -77,10 +77,10 @@ func MakeTestCodec() *wire.Codec { // default params without inflation func ParamsNoInflation() types.Params { return types.Params{ - InflationRateChange: sdk.ZeroRat(), - InflationMax: sdk.ZeroRat(), - InflationMin: sdk.ZeroRat(), - GoalBonded: sdk.NewRat(67, 100), + InflationRateChange: sdk.ZeroDec(), + InflationMax: sdk.ZeroDec(), + InflationMin: sdk.ZeroDec(), + GoalBonded: sdk.NewDec(67, 100), MaxValidators: 100, BondDenom: "steak", } @@ -119,7 +119,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(initCoins)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins)) keeper.SetPool(ctx, pool) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index b9e61a1014b2..7b15a9c7f100 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -20,8 +20,8 @@ func TestSetValidator(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) @@ -29,8 +29,8 @@ func TestSetValidator(t *testing.T) { validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.DelegatorShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) @@ -56,8 +56,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewRat(10000) - pool.BondedTokens = sdk.NewRat(1234) + pool.LooseTokens = sdk.NewDec(10000) + pool.BondedTokens = sdk.NewDec(1234) keeper.SetPool(ctx, pool) // add a validator @@ -76,7 +76,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares - validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2))) + validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out @@ -103,8 +103,8 @@ func TestCliffValidatorChange(t *testing.T) { keeper.SetParams(ctx, params) // create a random pool - pool.LooseTokens = sdk.NewRat(10000) - pool.BondedTokens = sdk.NewRat(1234) + pool.LooseTokens = sdk.NewDec(10000) + pool.BondedTokens = sdk.NewDec(1234) keeper.SetPool(ctx, pool) validators := make([]types.Validator, numVals) @@ -161,7 +161,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% - keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneRat()) + keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneDec()) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) @@ -178,13 +178,13 @@ func TestValidatorBasics(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{}) validators[i].Status = sdk.Unbonded - validators[i].Tokens = sdk.ZeroRat() + validators[i].Tokens = sdk.ZeroDec() validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) } - assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(8), validators[1].Tokens)) - assert.True(sdk.RatEq(t, sdk.NewRat(7), validators[2].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(8), validators[1].Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(7), validators[2].Tokens)) // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) @@ -193,7 +193,7 @@ func TestValidatorBasics(t *testing.T) { assert.Zero(t, len(resVals)) pool = keeper.GetPool(ctx) - assert.True(sdk.RatEq(t, sdk.ZeroRat(), pool.BondedTokens)) + assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) // set and retrieve a record validators[0] = keeper.UpdateValidator(ctx, validators[0]) @@ -205,15 +205,15 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, sdk.Bonded, validators[0].Status) - assert.True(sdk.RatEq(t, sdk.NewRat(9), validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(9), validators[0].BondedTokens())) pool = keeper.GetPool(ctx) - assert.True(sdk.RatEq(t, pool.BondedTokens, validators[0].BondedTokens())) + assert.True(sdk.DecEq(t, pool.BondedTokens, validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(10) - validators[0].DelegatorShares = sdk.NewRat(10) + validators[0].Tokens = sdk.NewDec(10) + validators[0].DelegatorShares = sdk.NewDec(10) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -256,19 +256,19 @@ func GetValidatorSortingUnmixed(t *testing.T) { for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) validators[i].Status = sdk.Bonded - validators[i].Tokens = sdk.NewRat(amt) - validators[i].DelegatorShares = sdk.NewRat(amt) + validators[i].Tokens = sdk.NewDec(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) keeper.UpdateValidator(ctx, validators[i]) } // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -276,14 +276,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].Owner, resValidators[4].Owner, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewRat(500) + validators[3].Tokens = sdk.NewDec(500) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewRat(300) + validators[3].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -291,7 +291,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewRat(200) + validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -310,8 +310,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewRat(300) - validators[4].Tokens = sdk.NewRat(300) + validators[3].Tokens = sdk.NewDec(300) + validators[4].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -338,20 +338,20 @@ func GetValidatorSortingMixed(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) - validators[i].DelegatorShares = sdk.NewRat(amt) + validators[i].DelegatorShares = sdk.NewDec(amt) } validators[0].Status = sdk.Bonded validators[1].Status = sdk.Bonded validators[2].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(amts[0]) - validators[1].Tokens = sdk.NewRat(amts[1]) - validators[2].Tokens = sdk.NewRat(amts[2]) + validators[0].Tokens = sdk.NewDec(amts[0]) + validators[1].Tokens = sdk.NewDec(amts[1]) + validators[2].Tokens = sdk.NewDec(amts[2]) validators[3].Status = sdk.Bonded validators[4].Status = sdk.Bonded - validators[3].Tokens = sdk.NewRat(amts[3]) - validators[4].Tokens = sdk.NewRat(amts[4]) + validators[3].Tokens = sdk.NewDec(amts[3]) + validators[4].Tokens = sdk.NewDec(amts[4]) for i := range amts { keeper.UpdateValidator(ctx, validators[i]) @@ -375,11 +375,11 @@ func GetValidatorSortingMixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewRat(400), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(200), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(100), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(1), resValidators[3].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewRat(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(100), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(1), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewDec(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].Owner, resValidators[0].Owner, "%v", resValidators) assert.Equal(t, validators[4].Owner, resValidators[1].Owner, "%v", resValidators) assert.Equal(t, validators[1].Owner, resValidators[2].Owner, "%v", resValidators) @@ -444,7 +444,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewRat(201)) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) resValidators = keeper.GetValidatorsByPower(ctx) @@ -656,7 +656,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.NewRat(600) + validators[0].Tokens = sdk.NewDec(600) validators[0] = keeper.UpdateValidator(ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -794,21 +794,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power - require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[1].GetPower().RoundInt64()) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} pool := keeper.GetPool(ctx) - validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20)) - validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30)) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) // power has changed - require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64()) - require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change updates := keeper.GetTendermintUpdates(ctx) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index e4869693cfa0..654d5560b0ac 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -31,7 +31,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim pool := k.GetPool(ctx) loose := sdk.ZeroInt() - bonded := sdk.ZeroRat() + bonded := sdk.ZeroDec() am.IterateAccounts(ctx, func(acc auth.Account) bool { loose = loose.Add(acc.GetCoins().AmountOf("steak")) return false @@ -67,7 +67,7 @@ func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { return func(t *testing.T, app *baseapp.BaseApp, log string) { ctx := app.NewContext(false, abci.Header{}) k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { - require.True(t, validator.GetPower().GT(sdk.ZeroRat()), "validator with non-positive power stored") + require.True(t, validator.GetPower().GT(sdk.ZeroDec()), "validator with non-positive power stored") return false }) } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index e4077a7497ce..0b4b3b47d5e1 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -132,7 +132,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewRatFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -191,7 +191,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation DelegatorAddr: delegatorAddress, ValidatorSrcAddr: sourceValidatorAddress, ValidatorDstAddr: destValidatorAddress, - SharesAmount: sdk.NewRatFromInt(amount), + SharesAmount: sdk.NewDecFromInt(amount), } require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewRat(loose.Int64(), 1)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 1)) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 77fd327a5e4d..f09cd8f4c098 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "fmt" - "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -16,12 +15,12 @@ import ( type Delegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - Shares sdk.Rat `json:"shares"` + Shares sdk.Dec `json:"shares"` Height int64 `json:"height"` // Last height bond updated } type delegationValue struct { - Shares sdk.Rat + Shares sdk.Dec Height int64 } @@ -81,7 +80,7 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr } func (d Delegation) GetValidator() sdk.AccAddress { return d.ValidatorAddr } -func (d Delegation) GetBondShares() sdk.Rat { return d.Shares } +func (d Delegation) GetBondShares() sdk.Dec { return d.Shares } // HumanReadableString returns a human readable string representation of a // Delegation. An error is returned if the Delegation's delegator or validator @@ -101,14 +100,14 @@ type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator ValidatorAddr sdk.AccAddress `json:"validator_addr"` // validator unbonding from owner addr CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime time.Time `json:"min_time"` // unix time for unbonding completion + MinTime int64 `json:"min_time"` // unix time for unbonding completion InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion } type ubdValue struct { CreationHeight int64 - MinTime time.Time + MinTime int64 InitialBalance sdk.Coin Balance sdk.Coin } @@ -187,20 +186,20 @@ type Redelegation struct { ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` // validator redelegation destination owner addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime time.Time `json:"min_time"` // unix time for redelegation completion + MinTime int64 `json:"min_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating + SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } type redValue struct { CreationHeight int64 - MinTime time.Time + MinTime int64 InitialBalance sdk.Coin Balance sdk.Coin - SharesSrc sdk.Rat - SharesDst sdk.Rat + SharesSrc sdk.Dec + SharesDst sdk.Dec } // return the redelegation without fields contained within the key for the store diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index 69823db14521..db4dd77233b1 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -2,7 +2,6 @@ package types import ( "testing" - "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -12,19 +11,19 @@ func TestDelegationEqual(t *testing.T) { d1 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } d2 := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } ok := d1.Equal(d2) require.True(t, ok) d2.ValidatorAddr = addr3 - d2.Shares = sdk.NewRat(200) + d2.Shares = sdk.NewDec(200) ok = d1.Equal(d2) require.False(t, ok) @@ -34,7 +33,7 @@ func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ DelegatorAddr: addr1, ValidatorAddr: addr2, - Shares: sdk.NewRat(100), + Shares: sdk.NewDec(100), } // NOTE: Being that the validator's keypair is random, we cannot test the @@ -58,7 +57,7 @@ func TestUnbondingDelegationEqual(t *testing.T) { require.True(t, ok) ud2.ValidatorAddr = addr3 - ud2.MinTime = time.Unix(20*20*2, 0) + ud2.MinTime = 20 * 20 * 2 ok = ud1.Equal(ud2) require.False(t, ok) @@ -92,9 +91,9 @@ func TestRedelegationEqual(t *testing.T) { ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewRat(10) - r2.SharesSrc = sdk.NewRat(20) - r2.MinTime = time.Unix(20*20*2, 0) + r2.SharesDst = sdk.NewDec(10) + r2.SharesSrc = sdk.NewDec(20) + r2.MinTime = 20 * 20 * 2 ok = r1.Equal(r2) require.False(t, ok) @@ -105,8 +104,8 @@ func TestRedelegationHumanReadableString(t *testing.T) { DelegatorAddr: addr1, ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, - SharesDst: sdk.NewRat(10), - SharesSrc: sdk.NewRat(20), + SharesDst: sdk.NewDec(10), + SharesSrc: sdk.NewDec(20), } // NOTE: Being that the validator's keypair is random, we cannot test the diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index b3e279c8eea0..b34aeeefb1e9 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -3,7 +3,6 @@ package types import ( "fmt" - "time" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -100,18 +99,11 @@ func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") } -func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", - maximumBondingRationalDenominator.String()), - ) -} - func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } -func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error { +func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error { msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", operation, descriptor, got, min) return sdk.NewError(codespace, CodeUnauthorized, msg) diff --git a/x/stake/types/inflation_test.go b/x/stake/types/inflation_test.go index 0114b1e05729..fd181af3c927 100644 --- a/x/stake/types/inflation_test.go +++ b/x/stake/types/inflation_test.go @@ -23,30 +23,30 @@ func TestGetInflation(t *testing.T) { tests := []struct { name string setBondedTokens, setLooseTokens, - setInflation, expectedChange sdk.Rat + setInflation, expectedChange sdk.Dec }{ // with 0% bonded atom supply the inflation should increase by InflationRateChange - {"test 1", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), params.InflationRateChange.Quo(hrsPerYrRat).Round(precision)}, + {"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)}, // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) - {"test 2", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), - sdk.OneRat().Sub(sdk.OneRat().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + {"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), + sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // 50% bonded, starting at 10% inflation and being increased - {"test 3", sdk.OneRat(), sdk.OneRat(), sdk.NewRat(10, 100), - sdk.OneRat().Sub(sdk.NewRat(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrRat).Round(precision)}, + {"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDecWithPrec(10, 2), + sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)}, // test 7% minimum stop (testing with 100% bonded) - {"test 4", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(7, 100), sdk.ZeroRat()}, - {"test 5", sdk.OneRat(), sdk.ZeroRat(), sdk.NewRat(70001, 1000000), sdk.NewRat(-1, 1000000)}, + {"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()}, + {"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)}, // test 20% maximum stop (testing with 0% bonded) - {"test 6", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(20, 100), sdk.ZeroRat()}, - {"test 7", sdk.ZeroRat(), sdk.ZeroRat(), sdk.NewRat(199999, 1000000), sdk.NewRat(1, 1000000)}, + {"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()}, + {"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)}, // perfect balance shouldn't change inflation - {"test 8", sdk.NewRat(67), sdk.NewRat(33), sdk.NewRat(15, 100), sdk.ZeroRat()}, + {"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()}, } for _, tc := range tests { pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens @@ -67,77 +67,80 @@ func TestProcessProvisions(t *testing.T) { var ( initialTotalTokens int64 = 550000000 - cumulativeExpProvs = sdk.ZeroRat() + cumulativeExpProvs = sdk.ZeroDec() ) - pool.LooseTokens = sdk.NewRat(initialTotalTokens) + pool.LooseTokens = sdk.NewDec(initialTotalTokens) // process the provisions for a year for hr := 0; hr < 100; hr++ { - var expProvisions sdk.Rat + var expProvisions sdk.Dec _, expProvisions, pool = updateProvisions(t, pool, params, hr) cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions) } //get the pool and do the final value checks from checkFinalPoolValues - checkFinalPoolValues(t, pool, sdk.NewRat(initialTotalTokens), cumulativeExpProvs) + checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs) } //_________________________________________________________________________________________ ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions -func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Rat) { +func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Dec) { calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs) - require.True(sdk.RatEq(t, calculatedTotalTokens, pool.TokenSupply())) + require.True(sdk.DecEq(t, calculatedTotalTokens, pool.TokenSupply())) } // Processes provisions are added to the pool correctly every hour // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Rat, sdk.Rat, Pool) { +func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Dec, sdk.Dec, Pool) { expInflation := pool.NextInflation(params) - expProvisions := expInflation.Mul(pool.TokenSupply().Round(precision)).Quo(hrsPerYrRat) + expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrDec) startTotalSupply := pool.TokenSupply() pool = pool.ProcessProvisions(params) //check provisions were added to pool - require.True(sdk.RatEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) + require.True(sdk.DecEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply())) return expInflation, expProvisions, pool } // Checks that The inflation will correctly increase or decrease after an update to the pool // nolint: gocyclo -func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { +func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Dec, msg string) { inflationChange := updatedInflation.Sub(previousInflation) switch { //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.LT(sdk.NewDecWithPrec(20, 2)): + require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio - case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): - if previousInflation.Equal(sdk.NewRat(20, 100)) { + case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.Equal(sdk.NewDecWithPrec(20, 2)): + if previousInflation.Equal(sdk.NewDecWithPrec(20, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) } else { - require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg) } //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && + updatedInflation.LT(sdk.NewDecWithPrec(20, 2)) && updatedInflation.GT(sdk.NewDecWithPrec(7, 2)): + require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. - case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): - if previousInflation.Equal(sdk.NewRat(7, 100)) { + case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) && + updatedInflation.Equal(sdk.NewDecWithPrec(7, 2)): + + if previousInflation.Equal(sdk.NewDecWithPrec(7, 2)) { require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) } else { - require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg) } } } diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 27edad5dd28b..282000294bce 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -1,7 +1,6 @@ package types import ( - "math" "reflect" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,18 +10,11 @@ import ( // name to idetify transaction types const MsgType = "stake" -// Maximum amount of decimal points in the decimal representation of rationals -// used in MsgBeginUnbonding / MsgBeginRedelegate -const MaxBondDenominatorPrecision = 8 - // Verify interface at compile time var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{} var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{} var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{} -// Initialize Int for the denominator -var maximumBondingRationalDenominator = sdk.NewInt(int64(math.Pow10(MaxBondDenominatorPrecision))) - //______________________________________________________________________ // MsgCreateValidator - struct for unbonding transactions @@ -211,11 +203,11 @@ type MsgBeginRedelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` - SharesAmount sdk.Rat `json:"shares_amount"` + SharesAmount sdk.Dec `json:"shares_amount"` } func NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginRedelegate { + validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginRedelegate { return MsgBeginRedelegate{ DelegatorAddr: delegatorAddr, @@ -261,12 +253,9 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.ValidatorDstAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroRat()) { + if msg.SharesAmount.LTE(sdk.ZeroDec()) { return ErrBadSharesAmount(DefaultCodespace) } - if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { - return ErrBadSharesPrecision(DefaultCodespace) - } return nil } @@ -322,10 +311,10 @@ func (msg MsgCompleteRedelegate) ValidateBasic() sdk.Error { type MsgBeginUnbonding struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - SharesAmount sdk.Rat `json:"shares_amount"` + SharesAmount sdk.Dec `json:"shares_amount"` } -func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Rat) MsgBeginUnbonding { +func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginUnbonding { return MsgBeginUnbonding{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, @@ -362,12 +351,9 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if msg.SharesAmount.LTE(sdk.ZeroRat()) { + if msg.SharesAmount.LTE(sdk.ZeroDec()) { return ErrBadSharesAmount(DefaultCodespace) } - if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { - return ErrBadSharesPrecision(DefaultCodespace) - } return nil } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 82f92d9f360f..2be34fb20754 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -143,15 +143,15 @@ func TestMsgBeginRedelegate(t *testing.T) { delegatorAddr sdk.AccAddress validatorSrcAddr sdk.AccAddress validatorDstAddr sdk.AccAddress - sharesAmount sdk.Rat + sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewRat(1, 10), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewRat(-1, 10), false}, - {"zero amount", addr1, addr2, addr3, sdk.ZeroRat(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewRat(1, 10), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewRat(1, 10), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewRat(1, 10), false}, + {"regular", addr1, addr2, addr3, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", addr1, addr2, addr3, sdk.NewDecWithPrec(-1, 1), false}, + {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, + {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { @@ -195,14 +195,14 @@ func TestMsgBeginUnbonding(t *testing.T) { name string delegatorAddr sdk.AccAddress validatorAddr sdk.AccAddress - sharesAmount sdk.Rat + sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, sdk.NewRat(1, 10), true}, - {"negative decimal", addr1, addr2, sdk.NewRat(-1, 10), false}, - {"zero amount", addr1, addr2, sdk.ZeroRat(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewRat(1, 10), false}, - {"empty validator", addr1, emptyAddr, sdk.NewRat(1, 10), false}, + {"regular", addr1, addr2, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", addr1, addr2, sdk.NewDecWithPrec(-1, 1), false}, + {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, + {"empty delegator", emptyAddr, addr1, sdk.NewDecWithPrec(1, 1), false}, + {"empty validator", addr1, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 0ae1ade090a1..c2e28bbddfc1 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -2,23 +2,22 @@ package types import ( "bytes" - "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // defaultUnbondingTime reflects three weeks in seconds as the default // unbonding time. -const defaultUnbondingTime time.Duration = 60 * 60 * 24 * 3 * time.Second +const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 // Params defines the high level settings for staking type Params struct { - InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate - InflationMax sdk.Rat `json:"inflation_max"` // maximum inflation rate - InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate - GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms + InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate + InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate + InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate + GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms - UnbondingTime time.Duration `json:"unbonding_time"` + UnbondingTime int64 `json:"unbonding_time"` MaxValidators uint16 `json:"max_validators"` // maximum number of validators BondDenom string `json:"bond_denom"` // bondable coin denomination @@ -34,10 +33,10 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - InflationRateChange: sdk.NewRat(13, 100), - InflationMax: sdk.NewRat(20, 100), - InflationMin: sdk.NewRat(7, 100), - GoalBonded: sdk.NewRat(67, 100), + InflationRateChange: sdk.NewDecWithPrec(13, 2), + InflationMax: sdk.NewDecWithPrec(20, 2), + InflationMin: sdk.NewDecWithPrec(7, 2), + GoalBonded: sdk.NewDecWithPrec(67, 2), UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 5aab4294b36c..04325a4fbf52 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -3,22 +3,21 @@ package types import ( "bytes" "fmt" - "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator - BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens - InflationLastTime time.Time `json:"inflation_last_time"` // block which the last inflation was processed - Inflation sdk.Rat `json:"inflation"` // current annual inflation rate + LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens + InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time + Inflation sdk.Dec `json:"inflation"` // current annual inflation rate DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily) // Fee Related - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations + PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations } // nolint @@ -31,48 +30,48 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - LooseTokens: sdk.ZeroRat(), - BondedTokens: sdk.ZeroRat(), - InflationLastTime: time.Unix(0, 0), - Inflation: sdk.NewRat(7, 100), + LooseTokens: sdk.ZeroDec(), + BondedTokens: sdk.ZeroDec(), + InflationLastTime: 0, + Inflation: sdk.NewDecWithPrec(7, 2), DateLastCommissionReset: 0, - PrevBondedShares: sdk.ZeroRat(), + PrevBondedShares: sdk.ZeroDec(), } } //____________________________________________________________________ // Sum total of all staking tokens in the pool -func (p Pool) TokenSupply() sdk.Rat { +func (p Pool) TokenSupply() sdk.Dec { return p.LooseTokens.Add(p.BondedTokens) } //____________________________________________________________________ // get the bond ratio of the global state -func (p Pool) BondedRatio() sdk.Rat { +func (p Pool) BondedRatio() sdk.Dec { supply := p.TokenSupply() - if supply.GT(sdk.ZeroRat()) { + if supply.GT(sdk.ZeroDec()) { return p.BondedTokens.Quo(supply) } - return sdk.ZeroRat() + return sdk.ZeroDec() } //_______________________________________________________________________ -func (p Pool) looseTokensToBonded(bondedTokens sdk.Rat) Pool { +func (p Pool) looseTokensToBonded(bondedTokens sdk.Dec) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) p.LooseTokens = p.LooseTokens.Sub(bondedTokens) - if p.LooseTokens.LT(sdk.ZeroRat()) { + if p.LooseTokens.LT(sdk.ZeroDec()) { panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) } return p } -func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { +func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) p.LooseTokens = p.LooseTokens.Add(bondedTokens) - if p.BondedTokens.LT(sdk.ZeroRat()) { + if p.BondedTokens.LT(sdk.ZeroDec()) { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } return p @@ -82,14 +81,14 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Rat) Pool { // Inflation const precision = 10000 // increased to this precision for accuracy -var hrsPerYrRat = sdk.NewRat(8766) // as defined by a julian year of 365.25 days +var hrsPerYrDec = sdk.NewDec(8766) // as defined by a julian year of 365.25 days // process provisions for an hour period func (p Pool) ProcessProvisions(params Params) Pool { p.Inflation = p.NextInflation(params) provisions := p.Inflation. - Mul(p.TokenSupply().Round(precision)). - Quo(hrsPerYrRat) + Mul(p.TokenSupply()). + Quo(hrsPerYrDec) // TODO add to the fees provisions p.LooseTokens = p.LooseTokens.Add(provisions) @@ -97,7 +96,7 @@ func (p Pool) ProcessProvisions(params Params) Pool { } // get the next inflation rate for the hour -func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { +func (p Pool) NextInflation(params Params) (inflation sdk.Dec) { // The target annual inflation rate is recalculated for each previsions cycle. The // inflation is also subject to a rate change (positive or negative) depending on @@ -106,11 +105,11 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { // 7% and 20%. // (1 - bondedRatio/GoalBonded) * InflationRateChange - inflationRateChangePerYear := sdk.OneRat(). - Sub(p.BondedRatio().Round(precision). + inflationRateChangePerYear := sdk.OneDec(). + Sub(p.BondedRatio(). Quo(params.GoalBonded)). Mul(params.InflationRateChange) - inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrRat) + inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrDec) // increase the new annual inflation for this next cycle inflation = p.Inflation.Add(inflationRateChange) @@ -121,5 +120,5 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Rat) { inflation = params.InflationMin } - return inflation.Round(precision) + return inflation } diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 43a2eac065a4..4541edd3d9c7 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -11,28 +11,28 @@ func TestPoolEqual(t *testing.T) { p1 := InitialPool() p2 := InitialPool() require.True(t, p1.Equal(p2)) - p2.BondedTokens = sdk.NewRat(3) + p2.BondedTokens = sdk.NewDec(3) require.False(t, p1.Equal(p2)) } func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) - pool.BondedTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.looseTokensToBonded(sdk.NewRat(10)) + pool = pool.looseTokensToBonded(sdk.NewDec(10)) - require.True(sdk.RatEq(t, sdk.NewRat(20), pool.BondedTokens)) - require.True(sdk.RatEq(t, sdk.NewRat(0), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(20), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(0), pool.LooseTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) - pool.BondedTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10) + pool.BondedTokens = sdk.NewDec(10) - pool = pool.bondedTokensToLoose(sdk.NewRat(5)) + pool = pool.bondedTokensToLoose(sdk.NewDec(5)) - require.True(sdk.RatEq(t, sdk.NewRat(5), pool.BondedTokens)) - require.True(sdk.RatEq(t, sdk.NewRat(15), pool.LooseTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(5), pool.BondedTokens)) + require.True(sdk.DecEq(t, sdk.NewDec(15), pool.LooseTokens)) } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 837b8f8e8a02..c9626b5ec5ca 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -26,21 +26,21 @@ type Validator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Rat `json:"prev_bonded_tokens"` // Previous bonded tokens held + LastBondedTokens sdk.Dec `json:"prev_bonded_tokens"` // Previous bonded tokens held } // NewValidator - initialize a new validator @@ -50,17 +50,17 @@ func NewValidator(owner sdk.AccAddress, pubKey crypto.PubKey, description Descri PubKey: pubKey, Revoked: false, Status: sdk.Unbonded, - Tokens: sdk.ZeroRat(), - DelegatorShares: sdk.ZeroRat(), + Tokens: sdk.ZeroDec(), + DelegatorShares: sdk.ZeroDec(), Description: description, BondHeight: int64(0), BondIntraTxCounter: int16(0), ProposerRewardPool: sdk.Coins{}, - Commission: sdk.ZeroRat(), - CommissionMax: sdk.ZeroRat(), - CommissionChangeRate: sdk.ZeroRat(), - CommissionChangeToday: sdk.ZeroRat(), - LastBondedTokens: sdk.ZeroRat(), + Commission: sdk.ZeroDec(), + CommissionMax: sdk.ZeroDec(), + CommissionChangeRate: sdk.ZeroDec(), + CommissionChangeToday: sdk.ZeroDec(), + LastBondedTokens: sdk.ZeroDec(), } } @@ -69,17 +69,17 @@ type validatorValue struct { PubKey crypto.PubKey Revoked bool Status sdk.BondStatus - Tokens sdk.Rat - DelegatorShares sdk.Rat + Tokens sdk.Dec + DelegatorShares sdk.Dec Description Description BondHeight int64 BondIntraTxCounter int16 ProposerRewardPool sdk.Coins - Commission sdk.Rat - CommissionMax sdk.Rat - CommissionChangeRate sdk.Rat - CommissionChangeToday sdk.Rat - LastBondedTokens sdk.Rat + Commission sdk.Dec + CommissionMax sdk.Dec + CommissionChangeRate sdk.Dec + CommissionChangeToday sdk.Dec + LastBondedTokens sdk.Dec } // return the redelegation without fields contained within the key for the store @@ -159,8 +159,8 @@ func (v Validator) HumanReadableString() (string, error) { resp += fmt.Sprintf("Validator: %s\n", bechVal) resp += fmt.Sprintf("Revoked: %v\n", v.Revoked) resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) - resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.FloatString()) - resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.FloatString()) + resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.String()) + resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String()) resp += fmt.Sprintf("Description: %s\n", v.Description) resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) resp += fmt.Sprintf("Proposer Reward Pool: %s\n", v.ProposerRewardPool.String()) @@ -182,21 +182,21 @@ type BechValidator struct { Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) - Tokens sdk.Rat `json:"tokens"` // delegated tokens (incl. self-delegation) - DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators + Tokens sdk.Dec `json:"tokens"` // delegated tokens (incl. self-delegation) + DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators Description Description `json:"description"` // description terms for the validator BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer - Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators - CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge - CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission - CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) // fee related - LastBondedTokens sdk.Rat `json:"prev_bonded_shares"` // last bonded token amount + LastBondedTokens sdk.Dec `json:"prev_bonded_shares"` // last bonded token amount } // get the bech validator from the the regular validator @@ -364,7 +364,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, } // removes tokens from a validator -func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { +func (v Validator) RemoveTokens(pool Pool, tokens sdk.Dec) (Validator, Pool) { if v.Status == sdk.Bonded { pool = pool.bondedTokensToLoose(tokens) } @@ -376,25 +376,25 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Rat) (Validator, Pool) { //_________________________________________________________________________________________________________ // AddTokensFromDel adds tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Dec) { // bondedShare/delegatedShare exRate := v.DelegatorShareExRate() - amountRat := sdk.NewRat(amount) + amountDec := sdk.NewDec(amount) if v.Status == sdk.Bonded { - pool = pool.looseTokensToBonded(amountRat) + pool = pool.looseTokensToBonded(amountDec) } - v.Tokens = v.Tokens.Add(amountRat) - issuedShares := amountRat.Quo(exRate) + v.Tokens = v.Tokens.Add(amountDec) + issuedShares := amountDec.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedShares) return v, pool, issuedShares } // RemoveDelShares removes delegator shares from a validator. -func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, sdk.Rat) { +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Pool, sdk.Dec) { issuedTokens := v.DelegatorShareExRate().Mul(delShares) v.Tokens = v.Tokens.Sub(issuedTokens) v.DelegatorShares = v.DelegatorShares.Sub(delShares) @@ -408,19 +408,19 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Poo // DelegatorShareExRate gets the exchange rate of tokens over delegator shares. // UNITS: tokens/delegator-shares -func (v Validator) DelegatorShareExRate() sdk.Rat { +func (v Validator) DelegatorShareExRate() sdk.Dec { if v.DelegatorShares.IsZero() { - return sdk.OneRat() + return sdk.OneDec() } return v.Tokens.Quo(v.DelegatorShares) } // Get the bonded tokens which the validator holds -func (v Validator) BondedTokens() sdk.Rat { +func (v Validator) BondedTokens() sdk.Dec { if v.Status == sdk.Bonded { return v.Tokens } - return sdk.ZeroRat() + return sdk.ZeroDec() } //______________________________________________________________________ @@ -434,7 +434,7 @@ func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOwner() sdk.AccAddress { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Rat { return v.BondedTokens() } -func (v Validator) GetTokens() sdk.Rat { return v.Tokens } -func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares } +func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } +func (v Validator) GetTokens() sdk.Dec { return v.Tokens } +func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index f0dff4732c4d..e92e02b96ede 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -3,7 +3,6 @@ package types import ( "fmt" "testing" - "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" @@ -75,19 +74,19 @@ func TestRemoveTokens(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewRat(100), - DelegatorShares: sdk.NewRat(100), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10, 0) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) // remove tokens and test check everything - validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) @@ -98,7 +97,7 @@ func TestRemoveTokens(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) - validator, pool = validator.RemoveTokens(pool, sdk.NewRat(10)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) @@ -106,43 +105,43 @@ func TestRemoveTokens(t *testing.T) { func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(10) + pool.LooseTokens = sdk.NewDec(10, 0) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, sdk.OneRat(), validator.DelegatorShareExRate()) + require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.RatEq(t, sdk.NewRat(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -151,16 +150,16 @@ func TestRemoveDelShares(t *testing.T) { Owner: addr1, PubKey: pk1, Status: sdk.Bonded, - Tokens: sdk.NewRat(100), - DelegatorShares: sdk.NewRat(100), + Tokens: sdk.NewDec(100), + DelegatorShares: sdk.NewDec(100), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewRat(10) + poolA.LooseTokens = sdk.NewDec(10, 0) poolA.BondedTokens = valA.BondedTokens() - require.Equal(t, valA.DelegatorShareExRate(), sdk.OneRat()) + require.Equal(t, valA.DelegatorShareExRate(), sdk.OneDec()) // Remove delegator shares - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10, 0)) assert.Equal(t, int64(10), coinsB.RoundInt64()) assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) @@ -168,13 +167,13 @@ func TestRemoveDelShares(t *testing.T) { assert.Equal(t, int64(20), poolB.LooseTokens.RoundInt64()) // conservation of tokens - require.True(sdk.RatEq(t, + require.True(sdk.DecEq(t, poolB.LooseTokens.Add(poolB.BondedTokens), poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests - poolTokens := sdk.NewRat(5102) - delShares := sdk.NewRat(115) + poolTokens := sdk.NewDec(5102, 0) + delShares := sdk.NewDec(115, 0) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -183,22 +182,27 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - BondedTokens: sdk.NewRat(248305), - LooseTokens: sdk.NewRat(232147), - InflationLastTime: time.Unix(0, 0), - Inflation: sdk.NewRat(7, 100), + BondedTokens: sdk.NewDec(248305, 0), + LooseTokens: sdk.NewDec(232147, 0), + InflationLastTime: 0, + Inflation: sdk.NewDec(7, 2), } - shares := sdk.NewRat(29) + shares := sdk.NewDec(29, 0) _, newPool, tokens := validator.RemoveDelShares(pool, shares) - require.True(sdk.RatEq(t, sdk.NewRat(147958, 115), tokens)) - require.True(sdk.RatEq(t, + + exp, err := sdk.NewDecFromStr("1286.5913043477") + require.NoError(t, err) + + require.True(sdk.DecEq(t, exp, tokens)) + + require.True(sdk.DecEq(t, newPool.LooseTokens.Add(newPool.BondedTokens), pool.LooseTokens.Add(pool.BondedTokens))) } func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewRat(100) + pool.LooseTokens = sdk.NewDec(100) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, 100) @@ -221,8 +225,8 @@ func TestUpdateStatus(t *testing.T) { } func TestPossibleOverflow(t *testing.T) { - poolTokens := sdk.NewRat(2159) - delShares := sdk.NewRat(391432570689183511).Quo(sdk.NewRat(40113011844664)) + poolTokens := sdk.NewDec(2159, 0) + delShares := sdk.NewDec(391432570689183511, 0).Quo(sdk.NewDec(40113011844664, 0)) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -231,17 +235,17 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewRat(100), + LooseTokens: sdk.NewDec(100), BondedTokens: poolTokens, - InflationLastTime: time.Unix(0, 0), - Inflation: sdk.NewRat(7, 100), + InflationLastTime: 0, + Inflation: sdk.NewDec(7, 2), } tokens := int64(71) msg := fmt.Sprintf("validator %#v", validator) newValidator, _, _ := validator.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroRat()), + require.False(t, newValidator.DelegatorShareExRate().LT(sdk.ZeroDec()), "Applying operation \"%s\" resulted in negative DelegatorShareExRate(): %v", msg, newValidator.DelegatorShareExRate()) } From b77fc5134924ac43f2a7af9d6fa69c02b054fd67 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 16:17:27 -0400 Subject: [PATCH 44/50] compiling --- x/gov/genesis.go | 6 +++--- x/slashing/params.go | 8 ++++---- x/stake/client/cli/tx.go | 4 ++-- x/stake/client/rest/query.go | 2 +- x/stake/client/rest/tx.go | 5 ++--- x/stake/client/rest/utils.go | 2 +- x/stake/keeper/slash.go | 6 +++--- x/stake/keeper/test_common.go | 2 +- x/stake/types/delegation.go | 9 +++++---- x/stake/types/errors.go | 3 ++- x/stake/types/params.go | 5 +++-- x/stake/types/pool.go | 11 ++++++----- 12 files changed, 33 insertions(+), 30 deletions(-) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 42d0e0d6cc68..15f952c000aa 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -33,9 +33,9 @@ func DefaultGenesisState() GenesisState { VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ - Threshold: sdk.NewDec(1, 2), - Veto: sdk.NewDec(1, 3), - GovernancePenalty: sdk.NewDec(1, 100), + Threshold: sdk.NewDecWithPrec(5, 1), + Veto: sdk.NewDecWithPrec(334, 3), + GovernancePenalty: sdk.NewDecWithPrec(1, 2), }, } } diff --git a/x/slashing/params.go b/x/slashing/params.go index 6608518ae421..a25d121c94c4 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -30,7 +30,7 @@ func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { // Downtime slashing thershold - default 50% func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { - minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) + minSignedPerWindow := k.params.GetDecWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) signedBlocksWindow := k.SignedBlocksWindow(ctx) return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() } @@ -47,12 +47,12 @@ func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration { // SlashFractionDoubleSign - currently default 5% func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec { - return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) + return k.params.GetDecWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) } // SlashFractionDowntime - currently default 1% func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec { - return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) + return k.params.GetDecWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) } // declared as var because of keeper_test.go @@ -72,7 +72,7 @@ var ( // TODO Temporarily set to 10 minutes for testnets defaultDowntimeUnbondDuration int64 = 60 * 10 - defaultMinSignedPerWindow = sdk.NewDec(1, 2) + defaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1) defaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20)) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 77f0520f333f..bf2df4913515 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -246,7 +246,7 @@ func getShares( case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewDecFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) + sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr) if err != nil { return sharesAmount, err } @@ -255,7 +255,7 @@ func getShares( } case sharesPercentStr != "": var sharesPercent sdk.Dec - sharesPercent, err = sdk.NewDecFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) + sharesPercent, err = sdk.NewDecFromStr(sharesPercentStr) if err != nil { return sharesAmount, err } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index ac660f98f66b..e30d19e45025 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -334,7 +334,7 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handle DelegatorAddr: delegation.DelegatorAddr, ValidatorAddr: delegation.ValidatorAddr, Height: delegation.Height, - Shares: delegation.Shares.FloatString(), + Shares: delegation.Shares.String(), } output, err := cdc.MarshalJSON(outputDelegation) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 917794065471..d8b9b6011366 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/wire" authcliCtx "github.com/cosmos/cosmos-sdk/x/auth/client/context" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/gorilla/mux" @@ -160,7 +159,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex return } - shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) @@ -234,7 +233,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex return } - shares, err := sdk.NewDecFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) + shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index 86e714662861..b7da69c7d4c9 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -79,7 +79,7 @@ func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegat DelegatorAddr: delegation.DelegatorAddr, ValidatorAddr: delegation.ValidatorAddr, Height: delegation.Height, - Shares: delegation.Shares.FloatString(), + Shares: delegation.Shares.String(), } return outputDelegation, http.StatusOK, "", nil diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index a5757d5cd8fd..c1fabe44112c 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -89,7 +89,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Cannot decrease balance below zero - tokensToBurn := sdk.MinRat(remainingSlashAmount, validator.Tokens) + tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens) // Get the current pool pool := k.GetPool(ctx) @@ -166,7 +166,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount).Mul(slashFactor) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -210,7 +210,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor) + slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount).Mul(slashFactor) // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 86dacccdb885..0470c28988a4 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -80,7 +80,7 @@ func ParamsNoInflation() types.Params { InflationRateChange: sdk.ZeroDec(), InflationMax: sdk.ZeroDec(), InflationMin: sdk.ZeroDec(), - GoalBonded: sdk.NewDec(67, 100), + GoalBonded: sdk.NewDecWithPrec(67, 2), MaxValidators: 100, BondDenom: "steak", } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index f09cd8f4c098..78111c03076f 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -100,14 +101,14 @@ type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator ValidatorAddr sdk.AccAddress `json:"validator_addr"` // validator unbonding from owner addr CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime int64 `json:"min_time"` // unix time for unbonding completion + MinTime time.Time `json:"min_time"` // unix time for unbonding completion InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion } type ubdValue struct { CreationHeight int64 - MinTime int64 + MinTime time.Time InitialBalance sdk.Coin Balance sdk.Coin } @@ -186,7 +187,7 @@ type Redelegation struct { ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` // validator redelegation destination owner addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime int64 `json:"min_time"` // unix time for redelegation completion + MinTime time.Time `json:"min_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started Balance sdk.Coin `json:"balance"` // current balance SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating @@ -195,7 +196,7 @@ type Redelegation struct { type redValue struct { CreationHeight int64 - MinTime int64 + MinTime time.Time InitialBalance sdk.Coin Balance sdk.Coin SharesSrc sdk.Dec diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index b34aeeefb1e9..1595a70d9102 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -3,6 +3,7 @@ package types import ( "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -103,7 +104,7 @@ func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } -func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error { +func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error { msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", operation, descriptor, got, min) return sdk.NewError(codespace, CodeUnauthorized, msg) diff --git a/x/stake/types/params.go b/x/stake/types/params.go index c2e28bbddfc1..f297f3105963 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -2,13 +2,14 @@ package types import ( "bytes" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // defaultUnbondingTime reflects three weeks in seconds as the default // unbonding time. -const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 +const defaultUnbondingTime time.Duration = 60 * 60 * 24 * 3 * time.Second // Params defines the high level settings for staking type Params struct { @@ -17,7 +18,7 @@ type Params struct { InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms - UnbondingTime int64 `json:"unbonding_time"` + UnbondingTime time.Duration `json:"unbonding_time"` MaxValidators uint16 `json:"max_validators"` // maximum number of validators BondDenom string `json:"bond_denom"` // bondable coin denomination diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index 04325a4fbf52..d59c1ed251ad 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -3,16 +3,17 @@ package types import ( "bytes" "fmt" + "time" sdk "github.com/cosmos/cosmos-sdk/types" ) // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator - BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens - InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time - Inflation sdk.Dec `json:"inflation"` // current annual inflation rate + LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens + InflationLastTime time.Time `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time + Inflation sdk.Dec `json:"inflation"` // current annual inflation rate DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily) @@ -32,7 +33,7 @@ func InitialPool() Pool { return Pool{ LooseTokens: sdk.ZeroDec(), BondedTokens: sdk.ZeroDec(), - InflationLastTime: 0, + InflationLastTime: time.Unix(0, 0), Inflation: sdk.NewDecWithPrec(7, 2), DateLastCommissionReset: 0, PrevBondedShares: sdk.ZeroDec(), From 24ce274c7a8d960a42441a03ab2471bc54a9dfe6 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 16:56:45 -0400 Subject: [PATCH 45/50] tests pass --- x/params/keeper_test.go | 10 +++---- x/stake/handler_test.go | 6 ++-- x/stake/keeper/slash_test.go | 14 ++++----- x/stake/simulation/msgs.go | 2 +- x/stake/types/delegation_test.go | 5 ++-- x/stake/types/validator_test.go | 51 ++++++++++++++++---------------- 6 files changed, 45 insertions(+), 43 deletions(-) diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 0afa898b3f13..626d68c7d68b 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -107,7 +107,7 @@ func TestGetter(t *testing.T) { assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) - assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewDec(1)) }) + assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1)) }) var res interface{} var err error @@ -264,17 +264,17 @@ func TestGetter(t *testing.T) { // Rat def10 := sdk.NewDec(0) - res, err = g.GetRat(ctx, kvs[10].key) + res, err = g.GetDec(ctx, kvs[10].key) assert.Nil(t, err) assert.Equal(t, kvs[10].param, res) - _, err = g.GetRat(ctx, "invalid") + _, err = g.GetDec(ctx, "invalid") assert.NotNil(t, err) - res = g.GetRatWithDefault(ctx, kvs[10].key, def10) + res = g.GetDecWithDefault(ctx, kvs[10].key, def10) assert.Equal(t, kvs[10].param, res) - res = g.GetRatWithDefault(ctx, "invalid", def10) + res = g.GetDecWithDefault(ctx, "invalid", def10) assert.Equal(t, def10, res) } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 735fe7701459..a06be0f8869c 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -81,7 +81,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDecWithPrec(5, 1)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -847,7 +847,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.Equal(t, sdk.NewDec(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -871,7 +871,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDec(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 3aea1083a83e..444858f290f5 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -63,7 +63,7 @@ func TestRevocation(t *testing.T) { // tests slashUnbondingDelegation func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -106,7 +106,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -172,7 +172,7 @@ func TestSlashRedelegation(t *testing.T) { func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) } @@ -180,7 +180,7 @@ func TestSlashAtFutureHeight(t *testing.T) { func TestSlashAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) oldPool := keeper.GetPool(ctx) validator, found := keeper.GetValidatorByPubKey(ctx, pk) @@ -202,7 +202,7 @@ func TestSlashAtCurrentHeight(t *testing.T) { func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) // set an unbonding delegation ubd := types.UnbondingDelegation{ @@ -303,7 +303,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) pk := PKs[0] - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rd := types.Redelegation{ @@ -424,7 +424,7 @@ func TestSlashWithRedelegation(t *testing.T) { // tests Slash at a previous height with both an unbonding delegation and a redelegation func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - fraction := sdk.NewDec(1, 2) + fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation rdA := types.Redelegation{ diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 0b4b3b47d5e1..f402d765fc0e 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -247,7 +247,7 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { return false }) pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64(), 1)) + pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(loose.Int64())) k.SetPool(ctx, pool) } } diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index db4dd77233b1..5624b71015e6 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -2,6 +2,7 @@ package types import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -57,8 +58,8 @@ func TestUnbondingDelegationEqual(t *testing.T) { require.True(t, ok) ud2.ValidatorAddr = addr3 - ud2.MinTime = 20 * 20 * 2 + ud2.MinTime = time.Unix(20*20*2, 0) ok = ud1.Equal(ud2) require.False(t, ok) } @@ -93,7 +94,7 @@ func TestRedelegationEqual(t *testing.T) { r2.SharesDst = sdk.NewDec(10) r2.SharesSrc = sdk.NewDec(20) - r2.MinTime = 20 * 20 * 2 + r2.MinTime = time.Unix(20*20*2, 0) ok = r1.Equal(r2) require.False(t, ok) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index e92e02b96ede..3981f5754d64 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -3,6 +3,7 @@ package types import ( "fmt" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" @@ -79,14 +80,14 @@ func TestRemoveTokens(t *testing.T) { } pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) // remove tokens and test check everything - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) require.Equal(t, int64(90), validator.Tokens.RoundInt64()) require.Equal(t, int64(90), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(20), pool.LooseTokens.RoundInt64()) @@ -97,7 +98,7 @@ func TestRemoveTokens(t *testing.T) { require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) - validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10, 0)) + validator, pool = validator.RemoveTokens(pool, sdk.NewDec(10)) require.Equal(t, int64(80), validator.Tokens.RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens.RoundInt64()) require.Equal(t, int64(110), pool.LooseTokens.RoundInt64()) @@ -105,43 +106,43 @@ func TestRemoveTokens(t *testing.T) { func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.BondedTokens())) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) } func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) assert.Equal(t, sdk.Unbonding, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) } func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewDec(10, 0) + pool.LooseTokens = sdk.NewDec(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, 10) require.Equal(t, sdk.OneDec(), validator.DelegatorShareExRate()) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), delShares)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), delShares)) assert.Equal(t, sdk.Unbonded, validator.Status) - assert.True(sdk.DecEq(t, sdk.NewDec(10, 0), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) } // TODO refactor to make simpler like the AddToken tests above @@ -154,12 +155,12 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: sdk.NewDec(100), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewDec(10, 0) + poolA.LooseTokens = sdk.NewDec(10) poolA.BondedTokens = valA.BondedTokens() require.Equal(t, valA.DelegatorShareExRate(), sdk.OneDec()) // Remove delegator shares - valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10, 0)) + valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewDec(10)) assert.Equal(t, int64(10), coinsB.RoundInt64()) assert.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) assert.Equal(t, int64(90), valB.BondedTokens().RoundInt64()) @@ -172,8 +173,8 @@ func TestRemoveDelShares(t *testing.T) { poolA.LooseTokens.Add(poolA.BondedTokens))) // specific case from random tests - poolTokens := sdk.NewDec(5102, 0) - delShares := sdk.NewDec(115, 0) + poolTokens := sdk.NewDec(5102) + delShares := sdk.NewDec(115) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -182,12 +183,12 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - BondedTokens: sdk.NewDec(248305, 0), - LooseTokens: sdk.NewDec(232147, 0), - InflationLastTime: 0, - Inflation: sdk.NewDec(7, 2), + BondedTokens: sdk.NewDec(248305), + LooseTokens: sdk.NewDec(232147), + InflationLastTime: time.Unix(0, 0), + Inflation: sdk.NewDecWithPrec(7, 2), } - shares := sdk.NewDec(29, 0) + shares := sdk.NewDec(29) _, newPool, tokens := validator.RemoveDelShares(pool, shares) exp, err := sdk.NewDecFromStr("1286.5913043477") @@ -225,8 +226,8 @@ func TestUpdateStatus(t *testing.T) { } func TestPossibleOverflow(t *testing.T) { - poolTokens := sdk.NewDec(2159, 0) - delShares := sdk.NewDec(391432570689183511, 0).Quo(sdk.NewDec(40113011844664, 0)) + poolTokens := sdk.NewDec(2159) + delShares := sdk.NewDec(391432570689183511).Quo(sdk.NewDec(40113011844664)) validator := Validator{ Owner: addr1, PubKey: pk1, @@ -237,8 +238,8 @@ func TestPossibleOverflow(t *testing.T) { pool := Pool{ LooseTokens: sdk.NewDec(100), BondedTokens: poolTokens, - InflationLastTime: 0, - Inflation: sdk.NewDec(7, 2), + InflationLastTime: time.Unix(0, 0), + Inflation: sdk.NewDecWithPrec(7, 2), } tokens := int64(71) msg := fmt.Sprintf("validator %#v", validator) From b600f714e29c401db594f7af241fc1006f91ce4f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Aug 2018 17:41:44 -0400 Subject: [PATCH 46/50] cli fix --- cmd/gaia/cli_test/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index dd8b244dfc66..e2e4f2aa1422 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -132,7 +132,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) require.Equal(t, validator.Owner, barAddr) - require.True(sdk.DecEq(t, sdk.NewDec(2, 0), validator.Tokens)) + require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens)) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) From d81775b52c2a899f916ef1eb929716f8bde57beb Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Aug 2018 15:18:59 -0400 Subject: [PATCH 47/50] anton, cwgoes, val comments --- types/decimal.go | 95 +++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index a6a7362488ee..c7ae18f9f0c5 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -29,6 +29,7 @@ var ( fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) precisionMultipliers []*big.Int zeroInt = big.NewInt(0) + oneInt = big.NewInt(1) tenInt = big.NewInt(10) ) @@ -118,8 +119,10 @@ func NewDecFromIntWithPrec(i Int, prec int64) Dec { // 345 // -456789 // -// NOTE an error will return if more decimal places -// are provided in the string than the constant Precision +// NOTE - An error will return if more decimal places +// are provided in the string than the constant Precision. +// +// CONTRACT - This function does not mutate the input str. func NewDecFromStr(str string) (d Dec, err Error) { if len(str) == 0 { return d, ErrUnknownRequest("decimal string is empty") @@ -127,7 +130,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { // first extract any negative symbol neg := false - if string(str[0]) == "-" { + if str[0] == '-' { neg = true str = str[1:] } @@ -150,7 +153,8 @@ func NewDecFromStr(str string) (d Dec, err Error) { } if lenDecs > Precision { - return d, ErrUnknownRequest("too much Precision in decimal") + return d, ErrUnknownRequest( + fmt.Sprintf("too much precision, maximum %v, len decimal %v", Precision, lenDecs)) } // add some extra zero's to correct to the Precision factor @@ -160,7 +164,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { combined, ok := new(big.Int).SetString(combinedStr, 10) if !ok { - return d, ErrUnknownRequest("bad string to integer conversion") + return d, ErrUnknownRequest(fmt.Sprintf("bad string to integer conversion, combinedStr: %v", combinedStr)) } if neg { combined = new(big.Int).Neg(combined) @@ -201,7 +205,7 @@ func (d Dec) Sub(d2 Dec) Dec { // multiplication func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) - chopped := ChopPrecisionAndRound(mul) + chopped := chopPrecisionAndRound(mul) if chopped.BitLen() > 255+DecimalPrecisionBytes { panic("Int overflow") @@ -217,7 +221,11 @@ func (d Dec) Quo(d2 Dec) Dec { mul.Mul(mul, precisionReuse) quo := new(big.Int).Quo(mul, d2.Int) - chopped := ChopPrecisionAndRound(quo) + chopped := chopPrecisionAndRound(quo) + + if chopped.BitLen() > 255+DecimalPrecisionBytes { + panic("Int overflow") + } return Dec{chopped} } @@ -241,7 +249,7 @@ func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { // TODO panic if negative or if totalDigits < len(initStr)??? // evaluate as an integer and return left padded string func (d Dec) ToLeftPadded(totalDigits int8) string { - chopped := ChopPrecisionAndRound(d.Int) + chopped := chopPrecisionAndRound(d.Int) intStr := chopped.String() fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` return fmt.Sprintf(fcode, intStr) @@ -259,16 +267,19 @@ func (d Dec) ToLeftPadded(totalDigits int8) string { // nolint - go-cyclo // Remove a Precision amount of rightmost digits and perform bankers rounding // on the remainder (gaussian rounding) on the digits which have been removed. -func ChopPrecisionAndRound(d *big.Int) (chopped *big.Int) { +// +// TODO We should make this function mutate the input. The functions here +// don't need to allocate different memory for chopped after computing the +// result +func chopPrecisionAndRound(d *big.Int) *big.Int { // remove the negative and add it back when returning if d.Sign() == -1 { // make d positive, compute chopped value, and then un-mutate d d = d.Neg(d) - chopped = ChopPrecisionAndRound(d) + d = chopPrecisionAndRound(d) d = d.Neg(d) - chopped.Neg(chopped) - return chopped + return d } // get the trucated quotient and remainder @@ -279,39 +290,27 @@ func ChopPrecisionAndRound(d *big.Int) (chopped *big.Int) { return quo } - //lenWhole := len(d.String()) - //if quo.Sign() == 0 { // only the decimal places (ex. 0.1234) - //lenWhole++ - //} - //lenQuo := len(quo.String()) - //lenRem := len(rem.String()) - //leadingZeros := lenWhole - (lenQuo + lenRem) // leading zeros removed from the remainder - - //zerosToAdd := int64(lenRem - 1 + leadingZeros) - //multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(zerosToAdd), nil) - //fiveLine := new(big.Int).Mul(big.NewInt(5), multiplier) - switch rem.Cmp(fivePrecision) { case -1: - chopped = quo - return + d = quo + return d case 1: - chopped = quo.Add(quo, big.NewInt(1)) - return + d = quo.Add(quo, oneInt) + return d default: // bankers rounding must take place // always round to an even number if quo.Bit(0) == 0 { - chopped = quo - return + d = quo + return d } - chopped = quo.Add(quo, big.NewInt(1)) - return + d = quo.Add(quo, oneInt) + return d } } // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - chopped := ChopPrecisionAndRound(d.Int) + chopped := chopPrecisionAndRound(d.Int) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -320,15 +319,35 @@ func (d Dec) RoundInt64() int64 { // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return NewIntFromBigInt(ChopPrecisionAndRound(d.Int)) + return NewIntFromBigInt(chopPrecisionAndRound(d.Int)) } //___________________________________________________________________________________ +// reuse nil values +var ( + nilAmino string + nilJSON []byte +) + +func init() { + empty := new(big.Int) + bz, err := empty.MarshalText() + if err != nil { + panic("bad nil amino init") + } + nilAmino = string(bz) + + nilJSON, err = json.Marshal(string(bz)) + if err != nil { + panic("bad nil json init") + } +} + // wraps d.MarshalText() func (d Dec) MarshalAmino() (string, error) { if d.Int == nil { - d.Int = new(big.Int) + return nilAmino, nil } bz, err := d.Int.MarshalText() return string(bz), err @@ -348,14 +367,14 @@ func (d *Dec) UnmarshalAmino(text string) (err error) { // MarshalJSON defines custom encoding scheme func (d Dec) MarshalJSON() ([]byte, error) { if d.Int == nil { - d.Int = new(big.Int) + return nilJSON, nil } - text, err := d.Int.MarshalText() + bz, err := d.Int.MarshalText() if err != nil { return nil, err } - return json.Marshal(string(text)) + return json.Marshal(string(bz)) } // UnmarshalJSON defines custom decoding scheme From af48ed27a2c2c424b5f37b6af079ef0862c80f3f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Aug 2018 19:01:47 -0400 Subject: [PATCH 48/50] val and jae comments --- types/decimal.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index c7ae18f9f0c5..df2ac92c6d38 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -21,7 +21,7 @@ const ( // bytes required to represent the above precision // ceil(log2(9999999999)) - DecimalPrecisionBytes = 34 + DecimalPrecisionBits = 34 ) var ( @@ -59,7 +59,7 @@ func calcPrecisionMultiplier(prec int64) *big.Int { return multiplier } -// get the precision multiplier. Do not mutate result. +// get the precision multiplier, do not mutate result func precisionMultiplier(prec int64) *big.Int { if prec > Precision { panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) @@ -176,9 +176,9 @@ func NewDecFromStr(str string) (d Dec, err Error) { //nolint func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } -func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 1 } // greater than +func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == -1 } // less than +func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) < 0 } // less than func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // reverse the decimal sign @@ -186,7 +186,7 @@ func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // rever func (d Dec) Add(d2 Dec) Dec { res := new(big.Int).Add(d.Int, d2.Int) - if res.BitLen() > 255+DecimalPrecisionBytes { + if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") } return Dec{res} @@ -196,7 +196,7 @@ func (d Dec) Add(d2 Dec) Dec { func (d Dec) Sub(d2 Dec) Dec { res := new(big.Int).Sub(d.Int, d2.Int) - if res.BitLen() > 255+DecimalPrecisionBytes { + if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") } return Dec{res} @@ -207,7 +207,7 @@ func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.Int, d2.Int) chopped := chopPrecisionAndRound(mul) - if chopped.BitLen() > 255+DecimalPrecisionBytes { + if chopped.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") } return Dec{chopped} @@ -223,7 +223,7 @@ func (d Dec) Quo(d2 Dec) Dec { quo := new(big.Int).Quo(mul, d2.Int) chopped := chopPrecisionAndRound(quo) - if chopped.BitLen() > 255+DecimalPrecisionBytes { + if chopped.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") } return Dec{chopped} @@ -283,7 +283,7 @@ func chopPrecisionAndRound(d *big.Int) *big.Int { } // get the trucated quotient and remainder - quo, rem := big.NewInt(0), big.NewInt(0) + quo, rem := d, big.NewInt(0) quo, rem = quo.QuoRem(d, precisionReuse, rem) if rem.Sign() == 0 { // remainder is zero @@ -292,19 +292,16 @@ func chopPrecisionAndRound(d *big.Int) *big.Int { switch rem.Cmp(fivePrecision) { case -1: - d = quo - return d + return quo case 1: - d = quo.Add(quo, oneInt) - return d + return quo.Add(quo, oneInt) default: // bankers rounding must take place // always round to an even number if quo.Bit(0) == 0 { d = quo return d } - d = quo.Add(quo, oneInt) - return d + return quo.Add(quo, oneInt) } } From db72022172c1afcbacc766f5f4c6deaeefb0ee3a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Aug 2018 19:08:44 -0400 Subject: [PATCH 49/50] type --- types/decimal.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index df2ac92c6d38..8400b694acfe 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -298,8 +298,7 @@ func chopPrecisionAndRound(d *big.Int) *big.Int { default: // bankers rounding must take place // always round to an even number if quo.Bit(0) == 0 { - d = quo - return d + return quo } return quo.Add(quo, oneInt) } From fa57c3835489107614001e8285d282fda983fdd1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Aug 2018 19:14:15 -0400 Subject: [PATCH 50/50] undo reuse quo --- types/decimal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/decimal.go b/types/decimal.go index 8400b694acfe..cd5c048e3485 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -283,7 +283,7 @@ func chopPrecisionAndRound(d *big.Int) *big.Int { } // get the trucated quotient and remainder - quo, rem := d, big.NewInt(0) + quo, rem := big.NewInt(0), big.NewInt(0) quo, rem = quo.QuoRem(d, precisionReuse, rem) if rem.Sign() == 0 { // remainder is zero