Merge PR #3099: F1 fee distribution
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Coins which can have additional decimal points
|
||||
type DecCoin struct {
|
||||
Denom string `json:"denom"`
|
||||
Amount Dec `json:"amount"`
|
||||
}
|
||||
|
||||
func NewDecCoin(denom string, amount int64) DecCoin {
|
||||
return DecCoin{
|
||||
Denom: denom,
|
||||
Amount: NewDec(amount),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDecCoinFromDec(denom string, amount Dec) DecCoin {
|
||||
return DecCoin{
|
||||
Denom: denom,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDecCoinFromCoin(coin Coin) DecCoin {
|
||||
return DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: NewDecFromInt(coin.Amount),
|
||||
}
|
||||
}
|
||||
|
||||
// Adds amounts of two coins with same denom
|
||||
func (coin DecCoin) Plus(coinB DecCoin) DecCoin {
|
||||
if coin.Denom != coinB.Denom {
|
||||
panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
|
||||
}
|
||||
return DecCoin{coin.Denom, coin.Amount.Add(coinB.Amount)}
|
||||
}
|
||||
|
||||
// Subtracts amounts of two coins with same denom
|
||||
func (coin DecCoin) Minus(coinB DecCoin) DecCoin {
|
||||
if coin.Denom != coinB.Denom {
|
||||
panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
|
||||
}
|
||||
return DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
|
||||
}
|
||||
|
||||
// return the decimal coins with trunctated decimals, and return the change
|
||||
func (coin DecCoin) TruncateDecimal() (Coin, DecCoin) {
|
||||
truncated := coin.Amount.TruncateInt()
|
||||
change := coin.Amount.Sub(NewDecFromInt(truncated))
|
||||
return NewCoin(coin.Denom, truncated), DecCoin{coin.Denom, change}
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
func NewDecCoins(coins Coins) DecCoins {
|
||||
dcs := make(DecCoins, len(coins))
|
||||
for i, coin := range coins {
|
||||
dcs[i] = NewDecCoinFromCoin(coin)
|
||||
}
|
||||
return dcs
|
||||
}
|
||||
|
||||
// return the coins with trunctated decimals, and return the change
|
||||
func (coins DecCoins) TruncateDecimal() (Coins, DecCoins) {
|
||||
changeSum := DecCoins{}
|
||||
out := make(Coins, len(coins))
|
||||
for i, coin := range coins {
|
||||
truncated, change := coin.TruncateDecimal()
|
||||
out[i] = truncated
|
||||
changeSum = changeSum.Plus(DecCoins{change})
|
||||
}
|
||||
return out, changeSum
|
||||
}
|
||||
|
||||
// Plus combines two sets of coins
|
||||
// CONTRACT: Plus will never return Coins where one Coin has a 0 amount.
|
||||
func (coins DecCoins) Plus(coinsB DecCoins) DecCoins {
|
||||
sum := ([]DecCoin)(nil)
|
||||
indexA, indexB := 0, 0
|
||||
lenA, lenB := len(coins), len(coinsB)
|
||||
for {
|
||||
if indexA == lenA {
|
||||
if indexB == lenB {
|
||||
return sum
|
||||
}
|
||||
return append(sum, coinsB[indexB:]...)
|
||||
} else if indexB == lenB {
|
||||
return append(sum, coins[indexA:]...)
|
||||
}
|
||||
coinA, coinB := coins[indexA], coinsB[indexB]
|
||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
||||
case -1:
|
||||
sum = append(sum, coinA)
|
||||
indexA++
|
||||
case 0:
|
||||
if coinA.Amount.Add(coinB.Amount).IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
sum = append(sum, coinA.Plus(coinB))
|
||||
}
|
||||
indexA++
|
||||
indexB++
|
||||
case 1:
|
||||
sum = append(sum, coinB)
|
||||
indexB++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative returns a set of coins with all amount negative
|
||||
func (coins DecCoins) Negative() DecCoins {
|
||||
res := make([]DecCoin, 0, len(coins))
|
||||
for _, coin := range coins {
|
||||
res = append(res, DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Neg(),
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Minus subtracts a set of coins from another (adds the inverse)
|
||||
func (coins DecCoins) Minus(coinsB DecCoins) DecCoins {
|
||||
return coins.Plus(coinsB.Negative())
|
||||
}
|
||||
|
||||
// multiply all the coins by a decimal
|
||||
func (coins DecCoins) MulDec(d Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
product := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Mul(d),
|
||||
}
|
||||
res[i] = product
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// divide all the coins by a decimal
|
||||
func (coins DecCoins) QuoDec(d Dec) DecCoins {
|
||||
res := make([]DecCoin, len(coins))
|
||||
for i, coin := range coins {
|
||||
quotient := DecCoin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount.Quo(d),
|
||||
}
|
||||
res[i] = quotient
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// returns the amount of a denom from deccoins
|
||||
func (coins DecCoins) AmountOf(denom string) Dec {
|
||||
switch len(coins) {
|
||||
case 0:
|
||||
return ZeroDec()
|
||||
case 1:
|
||||
coin := coins[0]
|
||||
if coin.Denom == denom {
|
||||
return coin.Amount
|
||||
}
|
||||
return ZeroDec()
|
||||
default:
|
||||
midIdx := len(coins) / 2 // binary search
|
||||
coin := coins[midIdx]
|
||||
if denom < coin.Denom {
|
||||
return coins[:midIdx].AmountOf(denom)
|
||||
} else if denom == coin.Denom {
|
||||
return coin.Amount
|
||||
} else {
|
||||
return coins[midIdx+1:].AmountOf(denom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// has a negative DecCoin amount
|
||||
func (coins DecCoins) HasNegative() bool {
|
||||
for _, coin := range coins {
|
||||
if coin.Amount.IsNegative() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// return whether all coins are zero
|
||||
func (coins DecCoins) IsZero() bool {
|
||||
for _, coin := range coins {
|
||||
if !coin.Amount.IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPlusDecCoin(t *testing.T) {
|
||||
decCoinA1 := DecCoin{"A", NewDecWithPrec(11, 1)}
|
||||
decCoinA2 := DecCoin{"A", NewDecWithPrec(22, 1)}
|
||||
decCoinB1 := DecCoin{"B", NewDecWithPrec(11, 1)}
|
||||
|
||||
// regular add
|
||||
res := decCoinA1.Plus(decCoinA1)
|
||||
require.Equal(t, decCoinA2, res, "sum of coins is incorrect")
|
||||
|
||||
// bad denom add
|
||||
assert.Panics(t, func() {
|
||||
decCoinA1.Plus(decCoinB1)
|
||||
}, "expected panic on sum of different denoms")
|
||||
|
||||
}
|
||||
|
||||
func TestPlusDecCoins(t *testing.T) {
|
||||
one := NewDec(1)
|
||||
zero := NewDec(0)
|
||||
negone := NewDec(-1)
|
||||
two := NewDec(2)
|
||||
|
||||
cases := []struct {
|
||||
inputOne DecCoins
|
||||
inputTwo DecCoins
|
||||
expected DecCoins
|
||||
}{
|
||||
{DecCoins{{"A", one}, {"B", one}}, DecCoins{{"A", one}, {"B", one}}, DecCoins{{"A", two}, {"B", two}}},
|
||||
{DecCoins{{"A", zero}, {"B", one}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"B", one}}},
|
||||
{DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins(nil)},
|
||||
{DecCoins{{"A", one}, {"B", zero}}, DecCoins{{"A", negone}, {"B", zero}}, DecCoins(nil)},
|
||||
{DecCoins{{"A", negone}, {"B", zero}}, DecCoins{{"A", zero}, {"B", zero}}, DecCoins{{"A", negone}}},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
res := tc.inputOne.Plus(tc.inputTwo)
|
||||
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -45,8 +45,9 @@ type Validator interface {
|
||||
GetPower() Int // validation power
|
||||
GetTokens() Int // validation tokens
|
||||
GetCommission() Dec // validator commission rate
|
||||
GetDelegatorShares() Dec // Total out standing delegator shares
|
||||
GetDelegatorShares() Dec // total outstanding delegator shares
|
||||
GetBondHeight() int64 // height in which the validator became active
|
||||
GetDelegatorShareExRate() Dec // tokens per delegator share exchange rate
|
||||
}
|
||||
|
||||
// validator which fulfills abci validator interface for use in Tendermint
|
||||
@@ -126,4 +127,6 @@ type StakingHooks interface {
|
||||
BeforeDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is created
|
||||
BeforeDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation's shares are modified
|
||||
BeforeDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is removed
|
||||
AfterDelegationModified(ctx Context, delAddr AccAddress, valAddr ValAddress)
|
||||
BeforeValidatorSlashed(ctx Context, valAddr ValAddress, fraction Dec)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user