Merge pull request #1819: rational -> decimal

* changelog

* ...

* decimal func working

* decimal complete, untested

* fixing tests

* decimal compile errors resolved

* test compile errors

* precision multiplier test

* 1% laptop battery

* fixed TestNewDecFromStr

* equalities working

* fix bankers round chop

* ...

* working, some decimal issues resolved

* fix rounding error

* rounding works

* decimal works

* ...

* deleted rational

* rational conversion working

* revert changelog

* code compiles (not tests)

* went through all NewDec, made sure they were converted from NewRat properly

* test debugging

* all testing bugs besides the json marshalling fixed

* json unmarshal

* lint

* document update

* fix lcd test

* cli test fix

* mostly undo Dece -> Rate

* val comments

* 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)

* Cache another precisionInt() call.

* Improve banker rounding efficiency

* remove defer, make negation in-place.

* chris val comments

* bez comments

* Aditya comments

* ...

* val comments

* rebasing start

* ...

* compiling

* tests pass

* cli fix

* anton, cwgoes, val comments

* val and jae comments

* type

* undo reuse quo
This commit is contained in:
Rigel 2018-08-14 20:15:02 -04:00 committed by GitHub
parent 0adbd60dfa
commit d9dc061b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1254 additions and 1213 deletions

View File

@ -34,6 +34,7 @@ BREAKING CHANGES
* `gaiacli gov vote --voter`
* [x/gov] Added tags sub-package, changed tags to use dash-case
* [x/gov] Governance parameters are now stored in globalparams store
* [core] \#1807 Switch from use of rational to decimal
* [lcd] \#1866 Updated lcd /slashing/signing_info endpoint to take cosmosvalpub instead of cosmosvaladdr
* [types] sdk.NewCoin now takes sdk.Int, sdk.NewInt64Coin takes int64
* [cli] #1551: Officially removed `--name` from CLI commands

View File

@ -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)

View File

@ -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.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 {
@ -193,10 +193,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)

View File

@ -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,

View File

@ -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)
@ -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) {

View File

@ -25,9 +25,9 @@ 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
GovernancePenalty sdk.Rat // Penalty if validator does not vote
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
}
```
@ -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

View File

@ -7,7 +7,7 @@
The current annual inflation rate.
```golang
type Inflation sdk.Rat
type Inflation sdk.Dec
```
### InflationLastTime

View File

@ -16,4 +16,3 @@ EndBlock() ValidatorSetChanges
ClearTendermintUpdates()
return vsc
```

View File

@ -13,7 +13,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)
}
@ -28,10 +28,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
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
MaxValidators uint16 // maximum number of validators
BondDenom string // bondable coin denomination
@ -74,9 +74,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
@ -88,10 +88,10 @@ type Validator struct {
}
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)
Rate sdk.Dec // the commission rate of fees charged to any delegators
Max sdk.Dec // maximum commission rate which this validator can ever charge
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
}
@ -117,7 +117,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
}
```
@ -178,8 +178,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
}
```

View File

@ -18,7 +18,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 decimal type specified by the SDK.
### TxCreateValidator
@ -34,9 +34,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
}
@ -65,7 +65,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
}
@ -199,7 +199,7 @@ type TxRedelegate struct {
DelegatorAddr Address
ValidatorFrom Validator
ValidatorTo Validator
Shares sdk.Rat
Shares sdk.Dec
CompletedTime int64
}

View File

@ -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")
}

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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.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.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})

418
types/decimal.go Normal file
View File

@ -0,0 +1,418 @@
package types
import (
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"testing"
)
// NOTE: never use new(Dec) or else we will panic unmarshalling into the
// nil embedded big.Int
type Dec struct {
*big.Int `json:"int"`
}
// number of decimal places
const (
Precision = 10
// bytes required to represent the above precision
// ceil(log2(9999999999))
DecimalPrecisionBits = 34
)
var (
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil)
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))
precisionMultipliers []*big.Int
zeroInt = big.NewInt(0)
oneInt = big.NewInt(1)
tenInt = big.NewInt(10)
)
// 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 new(big.Int).Set(precisionReuse)
}
// nolint - common values
func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} }
func OneDec() Dec { return Dec{precisionInt()} }
// calculate the precision multiplier
func calcPrecisionMultiplier(prec int64) *big.Int {
if prec > 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)
return multiplier
}
// 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))
}
return precisionMultipliers[prec]
}
//______________________________________________________________________________________________
// 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 NewDecWithPrec(i, prec int64) Dec {
return Dec{
new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)),
}
}
// create a new Dec from big integer assuming whole numbers
// CONTRACT: prec <= Precision
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)),
}
}
// create a new Dec from big integer assuming whole numbers
// CONTRACT: prec <= Precision
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)),
}
}
// 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.
//
// 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")
}
// first extract any negative symbol
neg := false
if str[0] == '-' {
neg = true
str = str[1:]
}
if len(str) == 0 {
return d, 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 d, ErrUnknownRequest("bad decimal length")
}
combinedStr = combinedStr + strs[1]
} else if len(strs) > 2 {
return d, ErrUnknownRequest("too many periods to be a decimal string")
}
if lenDecs > Precision {
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
zerosToAdd := Precision - lenDecs
zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "")
combinedStr = combinedStr + zeros
combined, ok := new(big.Int).SetString(combinedStr, 10)
if !ok {
return d, ErrUnknownRequest(fmt.Sprintf("bad string to integer conversion, combinedStr: %v", combinedStr))
}
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 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 }
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) < 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
// addition
func (d Dec) Add(d2 Dec) Dec {
res := new(big.Int).Add(d.Int, d2.Int)
if res.BitLen() > 255+DecimalPrecisionBits {
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+DecimalPrecisionBits {
panic("Int overflow")
}
return Dec{res}
}
// multiplication
func (d Dec) Mul(d2 Dec) Dec {
mul := new(big.Int).Mul(d.Int, d2.Int)
chopped := chopPrecisionAndRound(mul)
if chopped.BitLen() > 255+DecimalPrecisionBits {
panic("Int overflow")
}
return Dec{chopped}
}
// quotient
func (d Dec) Quo(d2 Dec) Dec {
// multiply precision twice
mul := new(big.Int).Mul(d.Int, precisionReuse)
mul.Mul(mul, precisionReuse)
quo := new(big.Int).Quo(mul, d2.Int)
chopped := chopPrecisionAndRound(quo)
if chopped.BitLen() > 255+DecimalPrecisionBits {
panic("Int overflow")
}
return Dec{chopped}
}
func (d Dec) String() string {
str := d.ToLeftPaddedWithDecimals(Precision)
placement := len(str) - Precision
if placement < 0 {
panic("too few decimal digits")
}
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) 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 {
chopped := chopPrecisionAndRound(d.Int)
intStr := chopped.String()
fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s`
return fmt.Sprintf(fcode, intStr)
}
// ____
// __| |__ "chop 'em
// ` \ round!"
// ___|| ~ _ -bankers
// | | __
// | | | __|__|__
// |_____: / | $$$ |
// |________|
// 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.
//
// 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)
d = chopPrecisionAndRound(d)
d = d.Neg(d)
return d
}
// get the trucated quotient and remainder
quo, rem := big.NewInt(0), big.NewInt(0)
quo, rem = quo.QuoRem(d, precisionReuse, rem)
if rem.Sign() == 0 { // remainder is zero
return quo
}
switch rem.Cmp(fivePrecision) {
case -1:
return quo
case 1:
return quo.Add(quo, oneInt)
default: // bankers rounding must take place
// always round to an even number
if quo.Bit(0) == 0 {
return quo
}
return quo.Add(quo, oneInt)
}
}
// RoundInt64 rounds the decimal using bankers rounding
func (d Dec) RoundInt64() int64 {
chopped := chopPrecisionAndRound(d.Int)
if !chopped.IsInt64() {
panic("Int64() out of bound")
}
return chopped.Int64()
}
// RoundInt round the decimal using bankers rounding
func (d Dec) RoundInt() 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 {
return nilAmino, nil
}
bz, err := d.Int.MarshalText()
return string(bz), err
}
// requires a valid JSON string - strings quotes and calls UnmarshalText
func (d *Dec) UnmarshalAmino(text string) (err error) {
tempInt := new(big.Int)
err = tempInt.UnmarshalText([]byte(text))
if err != nil {
return err
}
d.Int = tempInt
return nil
}
// MarshalJSON defines custom encoding scheme
func (d Dec) MarshalJSON() ([]byte, error) {
if d.Int == nil {
return nilJSON, nil
}
bz, err := d.Int.MarshalText()
if err != nil {
return nil, err
}
return json.Marshal(string(bz))
}
// 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
// test if two decimal arrays are equal
func DecsEqual(d1s, d2s []Dec) bool {
if len(d1s) != len(d2s) {
return false
}
for i, d1 := range d1s {
if !d1.Equal(d2s[i]) {
return false
}
}
return true
}
// minimum decimal between two
func MinDec(d1, d2 Dec) Dec {
if d1.LT(d2) {
return d1
}
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
}

301
types/decimal_test.go Normal file
View File

@ -0,0 +1,301 @@
package types
import (
"math/big"
"testing"
wire "github.com/cosmos/cosmos-sdk/wire"
"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)
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)
tests := []struct {
decimalStr string
expErr bool
exp Dec
}{
{"", true, Dec{}},
{"0.-75", true, Dec{}},
{"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, NewDecFromBigIntWithPrec(largeBigInt, 4)},
{"314460551102969314427823434337.1835",
false, NewDecFromBigIntWithPrec(largeBigInt, 4)},
{".", true, Dec{}},
{".0", true, NewDec(0)},
{"1.", true, NewDec(1)},
{"foobar", true, Dec{}},
{"0.foobar", true, Dec{}},
{"0.foobar.", true, Dec{}},
}
for tcIndex, tc := range tests {
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, res %v, exp %v, tc %v", res, tc.exp, tcIndex)
}
// negative tc
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)
exp := tc.exp.Mul(NewDec(-1))
require.True(t, res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex)
}
}
}
func TestEqualities(t *testing.T) {
tests := []struct {
d1, d2 Dec
gt, lt, eq bool
}{
{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 {
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 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 TestArithmetic(t *testing.T) {
tests := []struct {
d1, d2 Dec
expMul, expDiv, expAdd, expSub 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), 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 {
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 TestBankerRoundChop(t *testing.T) {
tests := []struct {
d1 Dec
exp int64
}{
{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 {
resNeg := tc.d1.Neg().RoundInt64()
require.Equal(t, -1*tc.exp, resNeg, "negative tc %d", tcIndex)
resPos := tc.d1.RoundInt64()
require.Equal(t, tc.exp, resPos, "positive tc %d", tcIndex)
}
}
func TestToLeftPadded(t *testing.T) {
tests := []struct {
dec Dec
digits int8
exp string
}{
{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)
require.Equal(t, tc.exp, res, "incorrect left padding, tc %d", tcIndex)
}
}
var cdc = wire.NewCodec()
func TestZeroDeserializationJSON(t *testing.T) {
d := Dec{new(big.Int)}
err := cdc.UnmarshalJSON([]byte(`"0"`), &d)
require.Nil(t, err)
err = cdc.UnmarshalJSON([]byte(`"{}"`), &d)
require.NotNil(t, err)
}
func TestSerializationText(t *testing.T) {
d := mustNewDecFromStr(t, "0.333")
bz, err := d.MarshalText()
require.NoError(t, err)
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) {
d := mustNewDecFromStr(t, "0.333")
bz, err := cdc.MarshalJSON(d)
require.NoError(t, err)
d2 := Dec{new(big.Int)}
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 := mustNewDecFromStr(t, "0.333")
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 testDEmbedStruct struct {
Field1 string `json:"f1"`
Field2 int `json:"f2"`
Field3 Dec `json:"f3"`
}
// TODO make work for UnmarshalJSON
func TestEmbeddedStructSerializationGoWire(t *testing.T) {
obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)}
bz, err := cdc.MarshalBinary(obj)
require.Nil(t, err)
var obj2 testDEmbedStruct
err = cdc.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 TestStringOverflow(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(),
)
}

View File

@ -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
}

View File

@ -1,402 +0,0 @@
package types
import (
"math/big"
"math/rand"
"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(),
)
}
// Tests below uses randomness
// Since we are using *big.Rat as underlying value
// and (U/)Int is immutable value(see TestImmutability(U/)Int)
// it is safe to use randomness in the tests
func TestArithRat(t *testing.T) {
for i := 0; i < 20; i++ {
n1 := NewInt(int64(rand.Int31()))
d1 := NewInt(int64(rand.Int31()))
rat1 := NewRatFromInt(n1, d1)
n2 := NewInt(int64(rand.Int31()))
d2 := NewInt(int64(rand.Int31()))
rat2 := NewRatFromInt(n2, d2)
n1d2 := n1.Mul(d2)
n2d1 := n2.Mul(d1)
cases := []struct {
nres Int
dres Int
rres Rat
}{
{n1d2.Add(n2d1), d1.Mul(d2), rat1.Add(rat2)},
{n1d2.Sub(n2d1), d1.Mul(d2), rat1.Sub(rat2)},
{n1.Mul(n2), d1.Mul(d2), rat1.Mul(rat2)},
{n1d2, n2d1, rat1.Quo(rat2)},
}
for _, tc := range cases {
require.Equal(t, NewRatFromInt(tc.nres, tc.dres), tc.rres)
}
}
}
func TestCompRat(t *testing.T) {
for i := 0; i < 20; i++ {
n1 := NewInt(int64(rand.Int31()))
d1 := NewInt(int64(rand.Int31()))
rat1 := NewRatFromInt(n1, d1)
n2 := NewInt(int64(rand.Int31()))
d2 := NewInt(int64(rand.Int31()))
rat2 := NewRatFromInt(n2, d2)
n1d2 := n1.Mul(d2)
n2d1 := n2.Mul(d1)
cases := []struct {
ires bool
rres bool
}{
{n1d2.Equal(n2d1), rat1.Equal(rat2)},
{n1d2.GT(n2d1), rat1.GT(rat2)},
{n1d2.LT(n2d1), rat1.LT(rat2)},
{n1d2.GT(n2d1) || n1d2.Equal(n2d1), rat1.GTE(rat2)},
{n1d2.LT(n2d1) || n1d2.Equal(n2d1), rat1.LTE(rat2)},
}
for _, tc := range cases {
require.Equal(t, tc.ires, tc.rres)
}
}
}
func TestImmutabilityRat(t *testing.T) {
for i := 0; i < 20; i++ {
n := int64(rand.Int31())
r := NewRat(n)
z := ZeroRat()
o := OneRat()
r.Add(z)
r.Sub(z)
r.Mul(o)
r.Quo(o)
require.Equal(t, n, r.RoundInt64())
require.True(t, NewRat(n).Equal(r))
}
}

View File

@ -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

View File

@ -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() {

View File

@ -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)
//}

View File

@ -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)

View File

@ -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
//}

View File

@ -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.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
},
}
}

View File

@ -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

View File

@ -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(),
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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)
}

View File

@ -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
@ -263,18 +263,18 @@ func TestGetter(t *testing.T) {
assert.Equal(t, def9, res)
// Rat
def10 := sdk.NewRat(0)
res, err = g.GetRat(ctx, kvs[10].key)
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)
}

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -30,9 +30,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).Mul(minSignedPerWindow).RoundInt64()
}
// Double-sign unbond duration
@ -46,13 +46,13 @@ func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration {
}
// 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
@ -72,9 +72,9 @@ var (
// TODO Temporarily set to 10 minutes for testnets
defaultDowntimeUnbondDuration int64 = 60 * 10
defaultMinSignedPerWindow = sdk.NewRat(1, 2)
defaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1)
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))
)

View File

@ -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)

View File

@ -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(),

View File

@ -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)})

View File

@ -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.NewDecFromStr(sharesAmountStr)
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.NewDecFromStr(sharesPercentStr)
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)")
}

View File

@ -347,7 +347,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)

View File

@ -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.NewRatFromDecimal(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.NewRatFromDecimal(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())))

View File

@ -76,7 +76,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

View File

@ -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()
}
}

View File

@ -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.NewDecWithPrec(5, 1))
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.NewDecWithPrec(5, 1))
// 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.NewDecWithPrec(5, 1))
// 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

View File

@ -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) {

View File

@ -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])

View File

@ -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))

View File

@ -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
}

View File

@ -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
@ -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.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).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).Mul(slashFactor)
// Don't slash more tokens than held
// Possible since the redelegation may already

View File

@ -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.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.NewRat(1, 2)
fraction := sdk.NewDecWithPrec(5, 1)
// 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.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.NewRat(1, 2)
fraction := sdk.NewDecWithPrec(5, 1)
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.NewDecWithPrec(5, 1)
// 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.NewDecWithPrec(5, 1)
// 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.NewDecWithPrec(5, 1)
// 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())
}

View File

@ -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.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.NewRat(initCoins))
pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins))
keeper.SetPool(ctx, pool)
}

View File

@ -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)

View File

@ -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
})
}

View File

@ -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()))
k.SetPool(ctx, pool)
}
}

View File

@ -16,12 +16,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 +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.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
@ -190,8 +190,8 @@ type Redelegation struct {
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.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 {
@ -199,8 +199,8 @@ type redValue struct {
MinTime time.Time
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

View File

@ -12,19 +12,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 +34,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,8 +58,8 @@ func TestUnbondingDelegationEqual(t *testing.T) {
require.True(t, ok)
ud2.ValidatorAddr = addr3
ud2.MinTime = time.Unix(20*20*2, 0)
ud2.MinTime = time.Unix(20*20*2, 0)
ok = ud1.Equal(ud2)
require.False(t, ok)
}
@ -92,8 +92,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 = time.Unix(20*20*2, 0)
ok = r1.Equal(r2)
@ -105,8 +105,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

View File

@ -100,13 +100,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")
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -13,10 +13,10 @@ const defaultUnbondingTime time.Duration = 60 * 60 * 24 * 3 * time.Second
// 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"`
@ -34,10 +34,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",

View File

@ -10,15 +10,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
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 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)
// 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 +31,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: time.Unix(0, 0),
Inflation: sdk.NewRat(7, 100),
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 +82,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 +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.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 +106,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 +121,5 @@ func (p Pool) NextInflation(params Params) (inflation sdk.Rat) {
inflation = params.InflationMin
}
return inflation.Round(precision)
return inflation
}

View File

@ -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))
}

View File

@ -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 }

View File

@ -75,19 +75,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())
@ -98,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.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())
@ -106,43 +106,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.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), 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.DelegatorShareExRate())
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.DelegatorShareExRate())
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
@ -151,16 +151,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.DelegatorShareExRate(), 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())
@ -168,13 +168,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,
@ -183,22 +183,27 @@ 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: time.Unix(0, 0),
Inflation: sdk.NewRat(7, 100),
Inflation: sdk.NewDecWithPrec(7, 2),
}
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,
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 +226,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,
@ -231,17 +236,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),
Inflation: sdk.NewDecWithPrec(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())
}