From e11c52e873b1025d95b9e99c78275f65a4fa8dc7 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 26 Sep 2018 03:13:40 -0700 Subject: [PATCH] Merge PR #2408: decimal: Add a method to multiply a decimal by an Int This is for usage within the slash function, to minimize operations required to slash each unbonded and redelegating account. --- PENDING.md | 3 ++- types/decimal.go | 10 ++++++++++ types/decimal_test.go | 17 +++++++++++++++++ x/stake/keeper/slash.go | 4 ++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/PENDING.md b/PENDING.md index c432ec3e0..aa328d969 100644 --- a/PENDING.md +++ b/PENDING.md @@ -44,7 +44,8 @@ BREAKING CHANGES * [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal * [types] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator interface's GetOwner() renamed to GetOperator() * [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period - * [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable. + * [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable. + * [types] \#2407 MulInt method added to big decimal in order to improve efficiency of slashing * [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153) * [simulation] Remove log and testing.TB from Operation and Invariants, in favor of using errors \#2282 * [simulation] Remove usage of keys and addrs in the types, in favor of simulation.Account \#2384 diff --git a/types/decimal.go b/types/decimal.go index 13a494ba0..13a8a26c1 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -215,6 +215,16 @@ func (d Dec) Mul(d2 Dec) Dec { return Dec{chopped} } +// multiplication +func (d Dec) MulInt(i Int) Dec { + mul := new(big.Int).Mul(d.Int, i.i) + + if mul.BitLen() > 255+DecimalPrecisionBits { + panic("Int overflow") + } + return Dec{mul} +} + // quotient func (d Dec) Quo(d2 Dec) Dec { diff --git a/types/decimal_test.go b/types/decimal_test.go index 161215467..a6ec0740e 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -325,3 +325,20 @@ func TestStringOverflow(t *testing.T) { dec3.String(), ) } + +func TestDecMulInt(t *testing.T) { + tests := []struct { + sdkDec Dec + sdkInt Int + want Dec + }{ + {NewDec(10), NewInt(2), NewDec(20)}, + {NewDec(1000000), NewInt(100), NewDec(100000000)}, + {NewDecWithPrec(1, 1), NewInt(10), NewDec(1)}, + {NewDecWithPrec(1, 5), NewInt(20), NewDecWithPrec(2, 4)}, + } + for i, tc := range tests { + got := tc.sdkDec.MulInt(tc.sdkInt) + require.Equal(t, tc.want, got, "Incorrect result on test case %d", i) + } +} diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 486dc3286..7bfe4eb25 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -172,7 +172,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).Mul(slashFactor) + slashAmount = slashFactor.MulInt(unbondingDelegation.InitialBalance.Amount) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -218,7 +218,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).Mul(slashFactor) + slashAmount = slashFactor.MulInt(redelegation.InitialBalance.Amount) // Don't slash more tokens than held // Possible since the redelegation may already