From 3b5e57be08cbc77dc13ec3ff2c6b76afd7779a58 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 10 Oct 2018 17:43:47 -0400 Subject: [PATCH] ctx with proposer, working through allocation test --- types/context.go | 6 +++ x/distribution/abci_app.go | 6 +-- x/distribution/keeper/allocation.go | 9 +++- x/distribution/keeper/allocation_test.go | 49 ++++++++++++++++++- x/distribution/keeper/delegation_test.go | 17 +++++-- x/distribution/keeper/keeper.go | 32 +++++++++--- x/distribution/keeper/key.go | 10 +++- x/distribution/keeper/test_common.go | 62 ++++++++++++++++++------ 8 files changed, 157 insertions(+), 34 deletions(-) diff --git a/types/context.go b/types/context.go index cb5958c5c9..e038337f41 100644 --- a/types/context.go +++ b/types/context.go @@ -188,6 +188,12 @@ func (c Context) WithBlockTime(newTime time.Time) Context { return c.WithBlockHeader(newHeader) } +func (c Context) WithProposer(addr ConsAddress) Context { + newHeader := c.BlockHeader() + newHeader.ProposerAddress = addr.Bytes() + return c.WithBlockHeader(newHeader) +} + func (c Context) WithBlockHeight(height int64) Context { return c.withValue(contextKeyBlockHeight, height) } diff --git a/x/distribution/abci_app.go b/x/distribution/abci_app.go index 9cced9ab83..0b634be874 100644 --- a/x/distribution/abci_app.go +++ b/x/distribution/abci_app.go @@ -1,8 +1,6 @@ package distribution import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,8 +10,10 @@ import ( // set the proposer for determining distribution during endblock func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) { consAddr := sdk.ConsAddress(req.Header.ProposerAddress) - fmt.Printf("debug consAddr: %v\n", consAddr) k.SetProposerConsAddr(ctx, consAddr) + + // XXX TODO actually calculate this + k.SetSumPrecommitPower(ctx, sdk.NewDec(1)) } // allocate fees diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 3c4bd3971b..1acd3e7304 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -11,6 +11,12 @@ import ( func (k Keeper) AllocateFees(ctx sdk.Context) { ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("allocation height: %v", ctx.BlockHeight())) + // if there is no power in the system nothing should be allocated + bondedTokens := k.stakeKeeper.TotalPower(ctx) + if bondedTokens.IsZero() { + return + } + // get the proposer of this block proposerConsAddr := k.GetProposerConsAddr(ctx) proposerValidator := k.stakeKeeper.ValidatorByConsAddr(ctx, proposerConsAddr) @@ -22,8 +28,7 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { feesCollectedDec := types.NewDecCoins(feesCollected) // allocated rewards to proposer - bondedTokens := k.stakeKeeper.TotalPower(ctx) - sumPowerPrecommitValidators := sdk.NewDec(1) // XXX TODO actually calculate this + sumPowerPrecommitValidators := k.GetSumPrecommitPower(ctx) proposerMultiplier := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul( sumPowerPrecommitValidators).Quo(bondedTokens)) proposerReward := feesCollectedDec.MulDec(proposerMultiplier) diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 77daa1cf69..7e4f8a32fa 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -1,7 +1,52 @@ package keeper -import "testing" +import ( + "testing" -func TestAllocateFees(t *testing.T) { + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) +func TestAllocateFeesBasic(t *testing.T) { + + // no community tax on inputs + ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec()) + stakeHandler := stake.NewHandler(sk) + denom := sk.GetParams(ctx).BondDenom + + //first make a validator + msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, 10) + got := stakeHandler(ctx, msgCreateValidator) + require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) + + // verify everything has been set in staking correctly + validator, found := sk.GetValidator(ctx, valOpAddr1) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) + assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) + bondedTokens := sk.TotalPower(ctx) + assert.True(sdk.DecEq(t, sdk.NewDec(10), bondedTokens)) + + // initial fee pool should be empty + feePool := keeper.GetFeePool(ctx) + require.Nil(t, feePool.Pool) + + // allocate 10 denom of fees + feeInputs := sdk.NewInt(100) + fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) + require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) + ctx = ctx.WithProposer(valConsAddr1) + keeper.SetProposerConsAddr(ctx, valConsAddr1) + keeper.SetSumPrecommitPower(ctx, sdk.NewDec(10)) + keeper.AllocateFees(ctx) + + // verify that these fees have been received by the feePool + feePool = keeper.GetFeePool(ctx) + expRes := sdk.NewDecFromInt(feeInputs).Mul(sdk.NewDecWithPrec(95, 2)) // 5% goes to proposer + require.Equal(t, 1, len(feePool.Pool)) + require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount)) } diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 98749c2b80..8ff99e4110 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -3,29 +3,38 @@ package keeper import ( "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/stretchr/testify/require" ) func TestWithdrawDelegationReward(t *testing.T) { - ctx, accMapper, keeper, sk := CreateTestInput(t, false, 100) + ctx, accMapper, keeper, sk, fck := CreateTestInputDefault(t, false, 100) stakeHandler := stake.NewHandler(sk) denom := sk.GetParams(ctx).BondDenom //first make a validator - msgCreateValidator := stake.NewTestMsgCreateValidator(valAddr1, valPk1, 10) + msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, 10) got := stakeHandler(ctx, msgCreateValidator) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) // delegate - msgDelegate := stake.NewTestMsgDelegate(delAddr1, valAddr1, 10) + msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10) got = stakeHandler(ctx, msgDelegate) require.True(t, got.IsOK()) amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - keeper.WithdrawDelegationReward(ctx, delAddr1, valAddr1) + feeInputs := sdk.NewInt(20) + fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) + require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) + + keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) + + amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + require.Equal(t, int64(100), amt.Int64()) } func TestWithdrawDelegationRewardsAll(t *testing.T) { diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 22932065bb..9c3949b8b9 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -7,11 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/params" ) -// nolint -const ( - ParamStoreKeyCommunityTax = "distr/community-tax" -) - // keeper of the stake store type Keeper struct { storeKey sdk.StoreKey @@ -70,7 +65,7 @@ func (k Keeper) GetProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsAddress) b := tstore.Get(ProposerKey) if b == nil { - panic("Stored fee pool should not have been nil") + panic("Proposer cons address was likely not set in begin block") } k.cdc.MustUnmarshalBinary(b, &consAddr) @@ -86,7 +81,30 @@ func (k Keeper) SetProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { //______________________________________________________________________ -// Returns the current Deposit Procedure from the global param store +// set the proposer public key for this block +func (k Keeper) GetSumPrecommitPower(ctx sdk.Context) (sumPrecommitPower sdk.Dec) { + tstore := ctx.KVStore(k.storeTKey) + + b := tstore.Get(ProposerKey) + if b == nil { + panic("Proposer cons address was likely not set in begin block") + } + + k.cdc.MustUnmarshalBinary(b, &sumPrecommitPower) + return +} + +// get the proposer public key for this block +func (k Keeper) SetSumPrecommitPower(ctx sdk.Context, sumPrecommitPower sdk.Dec) { + tstore := ctx.KVStore(k.storeTKey) + b := k.cdc.MustMarshalBinary(sumPrecommitPower) + tstore.Set(ProposerKey, b) +} + +//______________________________________________________________________ +// PARAM STORE + +// Returns the current CommunityTax rate from the global param store // nolint: errcheck func (k Keeper) GetCommunityTax(ctx sdk.Context) sdk.Dec { var communityTax sdk.Dec diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index f4e18cf63b..bd24bff031 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -8,11 +8,17 @@ import ( var ( FeePoolKey = []byte{0x00} // key for global distribution state ValidatorDistInfoKey = []byte{0x01} // prefix for each key to a validator distribution - DelegationDistInfoKey = []byte{0x02} // prefix for each key to a delegation distribution + DelegationDistInfoKey = []byte{0x02} // prefix for each key to a delegation distribution DelegatorWithdrawInfoKey = []byte{0x03} // prefix for each key to a delegator withdraw info // transient - ProposerKey = []byte{0x00} // key for storing the proposer operator address + ProposerKey = []byte{0x00} // key for storing the proposer operator address + SumPrecommitPowerKey = []byte{0x01} // key for storing the power of the precommit validators +) + +// nolint +const ( + ParamStoreKeyCommunityTax = "distr/community-tax" ) // gets the key for the validator distribution info from address diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 95921068be..1a64811056 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -30,15 +30,22 @@ var ( delAddr2 = sdk.AccAddress(delPk2.Address()) delAddr3 = sdk.AccAddress(delPk3.Address()) - valPk1 = ed25519.GenPrivKey().PubKey() - valPk2 = ed25519.GenPrivKey().PubKey() - valPk3 = ed25519.GenPrivKey().PubKey() - valAddr1 = sdk.ValAddress(valPk1.Address()) - valAddr2 = sdk.ValAddress(valPk2.Address()) - valAddr3 = sdk.ValAddress(valPk3.Address()) - valAccAddr1 = sdk.AccAddress(valPk1.Address()) // generate acc addresses for these validator keys too - valAccAddr2 = sdk.AccAddress(valPk2.Address()) - valAccAddr3 = sdk.AccAddress(valPk3.Address()) + valOpPk1 = ed25519.GenPrivKey().PubKey() + valOpPk2 = ed25519.GenPrivKey().PubKey() + valOpPk3 = ed25519.GenPrivKey().PubKey() + valOpAddr1 = sdk.ValAddress(valOpPk1.Address()) + valOpAddr2 = sdk.ValAddress(valOpPk2.Address()) + valOpAddr3 = sdk.ValAddress(valOpPk3.Address()) + valAccAddr1 = sdk.AccAddress(valOpPk1.Address()) // generate acc addresses for these validator keys too + valAccAddr2 = sdk.AccAddress(valOpPk2.Address()) + valAccAddr3 = sdk.AccAddress(valOpPk3.Address()) + + valConsPk1 = ed25519.GenPrivKey().PubKey() + valConsPk2 = ed25519.GenPrivKey().PubKey() + valConsPk3 = ed25519.GenPrivKey().PubKey() + valConsAddr1 = sdk.ConsAddress(valConsPk1.Address()) + valConsAddr2 = sdk.ConsAddress(valConsPk2.Address()) + valConsAddr3 = sdk.ConsAddress(valConsPk3.Address()) addrs = []sdk.AccAddress{ delAddr1, delAddr2, delAddr3, @@ -63,9 +70,18 @@ func MakeTestCodec() *codec.Codec { return cdc } +// test input with default values +func CreateTestInputDefault(t *testing.T, isCheckTx bool, initCoins int64) ( + sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { + + communityTax := sdk.NewDecWithPrec(2, 2) + return CreateTestInputAdvanced(t, isCheckTx, initCoins, communityTax) +} + // hogpodge of all sorts of input required for testing -func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) ( - sdk.Context, auth.AccountMapper, Keeper, stake.Keeper) { +func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64, + communityTax sdk.Dec) ( + sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { keyDistr := sdk.NewKVStoreKey("distr") tkeyDistr := sdk.NewTransientStoreKey("transient_distr") @@ -109,7 +125,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) ( sk.SetPool(ctx, pool) } - fck := auth.NewFeeCollectionKeeper(cdc, keyFeeCollection) + fck := DummyFeeCollectionKeeper{} pk := params.NewKeeper(cdc, keyParams) keeper := NewKeeper(cdc, keyDistr, tkeyDistr, pk.Setter(), ck, sk, fck, types.DefaultCodespace) @@ -118,7 +134,25 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) ( // set genesis items required for distribution keeper.SetFeePool(ctx, types.InitialFeePool()) - keeper.SetCommunityTax(ctx, sdk.NewDecWithPrec(2, 2)) + keeper.SetCommunityTax(ctx, communityTax) - return ctx, accountMapper, keeper, sk + return ctx, accountMapper, keeper, sk, fck +} + +//__________________________________________________________________________________ +// fee collection keeper used only for testing +type DummyFeeCollectionKeeper struct{} + +var heldFees sdk.Coins +var _ types.FeeCollectionKeeper = DummyFeeCollectionKeeper{} + +// nolint +func (fck DummyFeeCollectionKeeper) GetCollectedFees(_ sdk.Context) sdk.Coins { + return heldFees +} +func (fck DummyFeeCollectionKeeper) SetCollectedFees(in sdk.Coins) { + heldFees = in +} +func (fck DummyFeeCollectionKeeper) ClearCollectedFees(_ sdk.Context) { + heldFees = sdk.Coins{} }