diff --git a/docs/spec/staking/old/spec.md b/docs/spec/staking/old/spec.md index 7010ee153..dac69aa06 100644 --- a/docs/spec/staking/old/spec.md +++ b/docs/spec/staking/old/spec.md @@ -49,7 +49,7 @@ type Params struct { GoalBonded rational.Rational // Goal of percent bonded atoms ReserveTax rational.Rational // Tax collected on all fees - MaxVals uint16 // maximum number of validators + MaxValidators uint16 // maximum number of validators BondDenom string // bondable coin denomination // gas costs for txs diff --git a/x/stake/commands/query.go b/x/stake/commands/query.go index 2a72d569a..b6ccb712e 100644 --- a/x/stake/commands/query.go +++ b/x/stake/commands/query.go @@ -45,7 +45,7 @@ func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command { Short: "Query for the set of validator-candidates pubkeys", RunE: func(cmd *cobra.Command, args []string) error { - key := PrefixedKey(stake.Name, stake.CandidatesAddrKey) + key := PrefixedKey(stake.MsgType, stake.CandidatesAddrKey) res, err := builder.Query(key, storeName) if err != nil { @@ -85,7 +85,7 @@ func GetCmdQueryCandidate(cdc *wire.Codec, storeName string) *cobra.Command { return err } - key := PrefixedKey(stake.Name, stake.GetCandidateKey(addr)) + key := PrefixedKey(stake.MsgType, stake.GetCandidateKey(addr)) res, err := builder.Query(key, storeName) if err != nil { @@ -131,7 +131,7 @@ func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command } delegator := crypto.Address(bz) - key := PrefixedKey(stake.Name, stake.GetDelegatorBondKey(delegator, addr, cdc)) + key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondKey(delegator, addr, cdc)) res, err := builder.Query(key, storeName) if err != nil { @@ -173,7 +173,7 @@ func GetCmdQueryDelegatorBonds(cdc *wire.Codec, storeName string) *cobra.Command } delegator := crypto.Address(bz) - key := PrefixedKey(stake.Name, stake.GetDelegatorBondsKey(delegator, cdc)) + key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondsKey(delegator, cdc)) res, err := builder.Query(key, storeName) if err != nil { diff --git a/x/stake/commands/tx.go b/x/stake/commands/tx.go index 56b41a15f..431483288 100644 --- a/x/stake/commands/tx.go +++ b/x/stake/commands/tx.go @@ -19,10 +19,11 @@ import ( // nolint const ( - FlagAddress = "address" - FlagPubKey = "pubkey" - FlagAmount = "amount" - FlagShares = "shares" + FlagAddressDelegator = "addressD" + FlagAddressCandidate = "addressC" + FlagPubKey = "pubkey" + FlagAmount = "amount" + FlagShares = "shares" FlagMoniker = "moniker" FlagIdentity = "keybase-sig" @@ -36,6 +37,7 @@ var ( fsAmount = flag.NewFlagSet("", flag.ContinueOnError) fsShares = flag.NewFlagSet("", flag.ContinueOnError) fsCandidate = flag.NewFlagSet("", flag.ContinueOnError) + fsDelegator = flag.NewFlagSet("", flag.ContinueOnError) ) func init() { @@ -45,7 +47,8 @@ func init() { fsCandidate.String(FlagMoniker, "", "validator-candidate name") fsCandidate.String(FlagIdentity, "", "optional keybase signature") fsCandidate.String(FlagWebsite, "", "optional website") - fsCandidate.String(FlagDetails, "", "optional detailed description space") + fsCandidate.String(FlagAddressCandidate, "", "hex address of the validator/candidate") + fsDelegator.String(FlagAddressDelegator, "", "hex address of the delegator") } //TODO refactor to common functionality @@ -69,7 +72,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command { if err != nil { return err } - addr, err := sdk.GetAddress(viper.GetString(FlagAddress)) + candidateAddr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate)) if err != nil { return err } @@ -86,7 +89,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgDeclareCandidacy(addr, pk, amount, description) + msg := stake.NewMsgDeclareCandidacy(candidateAddr, pk, amount, description) name, pass, err := getNamePassword() if err != nil { @@ -117,7 +120,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command { Short: "edit and existing validator-candidate account", RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.GetAddress(viper.GetString(FlagAddress)) + candidateAddr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate)) if err != nil { return err } @@ -127,7 +130,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgEditCandidacy(addr, description) + msg := stake.NewMsgEditCandidacy(candidateAddr, description) name, pass, err := getNamePassword() if err != nil { @@ -161,12 +164,13 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { return err } - addr, err := sdk.GetAddress(viper.GetString(FlagAddress)) + delegatorAddr, err := sdk.GetAddress(viper.GetString(FlagAddressDelegator)) + candidateAddr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate)) if err != nil { return err } - msg := stake.NewMsgDelegate(addr, amount) + msg := stake.NewMsgDelegate(delegatorAddr, candidateAddr, amount) name, pass, err := getNamePassword() if err != nil { @@ -186,6 +190,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { cmd.Flags().AddFlagSet(fsPk) cmd.Flags().AddFlagSet(fsAmount) + cmd.Flags().AddFlagSet(fsDelegator) return cmd } @@ -210,12 +215,13 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command { } } - addr, err := sdk.GetAddress(viper.GetString(FlagAddress)) + delegatorAddr, err := sdk.GetAddress(viper.GetString(FlagAddressDelegator)) + candidateAddr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate)) if err != nil { return err } - msg := stake.NewMsgUnbond(addr, sharesStr) + msg := stake.NewMsgUnbond(delegatorAddr, candidateAddr, sharesStr) name, pass, err := getNamePassword() if err != nil { @@ -235,6 +241,7 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command { cmd.Flags().AddFlagSet(fsPk) cmd.Flags().AddFlagSet(fsShares) + cmd.Flags().AddFlagSet(fsDelegator) return cmd } diff --git a/x/stake/errors.go b/x/stake/errors.go index aae855f6e..a8038a3d8 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -91,7 +91,10 @@ func ErrNoDelegatorForAddress() sdk.Error { return newError(CodeInvalidValidator, "Delegator does not contain validator bond") } func ErrInsufficientFunds() sdk.Error { - return newError(CodeInvalidValidator, "Insufficient bond shares") + return newError(CodeInvalidInput, "Insufficient bond shares") +} +func ErrBadShares() sdk.Error { + return newError(CodeInvalidInput, "bad shares provided as input, must be MAX or decimal") } func ErrBadRemoveValidator() sdk.Error { return newError(CodeInvalidValidator, "Error removing validator") diff --git a/x/stake/handler.go b/x/stake/handler.go index e96e8484c..8dda9e7f3 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -80,27 +80,6 @@ func NewHandler(k Keeper, ck bank.CoinKeeper) sdk.Handler { //sender := signers[0] //} -//_____________________________________________________________________ -// helper functions - -// move a candidates asset pool from bonded to unbonded pool -func (k Keeper) bondedToUnbondedPool(ctx sdk.Context, candidate *Candidate) { - - // replace bonded shares with unbonded shares - tokens := k.getGlobalState(ctx).removeSharesBonded(candidate.Assets) - candidate.Assets = k.getGlobalState(ctx).addTokensUnbonded(tokens) - candidate.Status = Unbonded -} - -// move a candidates asset pool from unbonded to bonded pool -func (k Keeper) unbondedToBondedPool(ctx sdk.Context, candidate *Candidate) { - - // replace unbonded shares with bonded shares - tokens := k.getGlobalState(ctx).removeSharesUnbonded(candidate.Assets) - candidate.Assets = k.getGlobalState(ctx).addTokensBonded(tokens) - candidate.Status = Bonded -} - //_____________________________________________________________________ // These functions assume everything has been authenticated, @@ -109,11 +88,12 @@ func (k Keeper) unbondedToBondedPool(ctx sdk.Context, candidate *Candidate) { func (k Keeper) handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy) sdk.Result { // check to see if the pubkey or sender has been registered before - if k.getCandidate(msg.Address) != nil { - return ErrCandidateExistsAddr() + _, found := k.getCandidate(ctx, msg.CandidateAddr) + if found { + return ErrCandidateExistsAddr().Result() } - if msg.bond.Denom != k.getParams().BondDenom { - return ErrBadBondingDenom() + if msg.Bond.Denom != k.getParams(ctx).BondDenom { + return ErrBadBondingDenom().Result() } if ctx.IsCheckTx() { return sdk.Result{ @@ -121,19 +101,19 @@ func (k Keeper) handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandida } } - candidate := NewCandidate(msg.PubKey, msg.Address, msg.Description) - k.setCandidate(candidate) + candidate := NewCandidate(msg.CandidateAddr, msg.PubKey, msg.Description) + k.setCandidate(ctx, candidate) // move coins from the msg.Address account to a (self-bond) delegator account // the candidate account and global shares are updated within here - txDelegate := NewMsgDelegate(msg.Address, msg.Bond) - return delegateWithCandidate(txDelegate, candidate) + return k.delegateWithCandidate(ctx, msg.CandidateAddr, msg.Bond, candidate).Result() } func (k Keeper) handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy) sdk.Result { // candidate must already be registered - if k.getCandidate(msg.Address) == nil { + candidate, found := k.getCandidate(ctx, msg.CandidateAddr) + if !found { return ErrBadCandidateAddr().Result() } if ctx.IsCheckTx() { @@ -141,16 +121,11 @@ func (k Keeper) handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy) sd GasUsed: GasEditCandidacy, } } - - // Get the pubKey bond account - candidate := k.getCandidate(msg.Address) - if candidate == nil { - return ErrBondNotNominated().Result() - } if candidate.Status == Unbonded { //candidate has been withdrawn return ErrBondNotNominated().Result() } + // XXX move to types //check and edit any of the editable terms if msg.Description.Moniker != "" { candidate.Description.Moniker = msg.Description.Moniker @@ -165,16 +140,17 @@ func (k Keeper) handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy) sd candidate.Description.Details = msg.Description.Details } - k.setCandidate(candidate) - return nil + k.setCandidate(ctx, candidate) + return sdk.Result{} } func (k Keeper) handleMsgDelegate(ctx sdk.Context, msg MsgDelegate) sdk.Result { - if k.getCandidate(msg.Address) == nil { + candidate, found := k.getCandidate(ctx, msg.CandidateAddr) + if !found { return ErrBadCandidateAddr().Result() } - if msg.bond.Denom != k.getParams().BondDenom { + if msg.Bond.Denom != k.getParams(ctx).BondDenom { return ErrBadBondingDenom().Result() } if ctx.IsCheckTx() { @@ -182,17 +158,10 @@ func (k Keeper) handleMsgDelegate(ctx sdk.Context, msg MsgDelegate) sdk.Result { GasUsed: GasDelegate, } } - - // Get the pubKey bond account - candidate := k.getCandidate(msg.Address) - if candidate == nil { - return ErrBondNotNominated().Result() - } - - return tr.delegateWithCandidate(msg, candidate).Result() + return k.delegateWithCandidate(ctx, msg.DelegatorAddr, msg.Bond, candidate).Result() } -func (k Keeper) delegateWithCandidate(ctx sdk.Context, candidateAddr, delegatorAddr sdk.Address, +func (k Keeper) delegateWithCandidate(ctx sdk.Context, delegatorAddr sdk.Address, bondAmt sdk.Coin, candidate Candidate) sdk.Error { if candidate.Status == Revoked { //candidate has been withdrawn @@ -200,63 +169,43 @@ func (k Keeper) delegateWithCandidate(ctx sdk.Context, candidateAddr, delegatorA } // Get or create the delegator bond - bond := k.getDelegatorBond(tr.sender, canad) - if bond == nil { - bond = &DelegatorBond{ - CandidateAddr: delegatorAddr, - DelegatorAddr: candidateAddr, + existingBond, found := k.getDelegatorBond(ctx, delegatorAddr, candidate.Address) + if !found { + existingBond = DelegatorBond{ + DelegatorAddr: delegatorAddr, + CandidateAddr: candidate.Address, Shares: sdk.ZeroRat, } } // Account new shares, save - err := BondCoins(bond, candidate, msg.Bond) + err := k.BondCoins(ctx, existingBond, candidate, bondAmt) if err != nil { - return err.Result() + return err } - k.setDelegatorBond(tr.sender, bond) - k.setCandidate(candidate) - k.setGlobalState(tr.gs) + k.setDelegatorBond(ctx, existingBond) + k.setCandidate(ctx, candidate) return nil } // Perform all the actions required to bond tokens to a delegator bond from their account -func (k Keeper) BondCoins(ctx sdk.Context, bond DelegatorBond, amount sdk.Coin) sdk.Error { +func (k Keeper) BondCoins(ctx sdk.Context, bond DelegatorBond, candidate Candidate, amount sdk.Coin) sdk.Error { _, err := k.coinKeeper.SubtractCoins(ctx, bond.DelegatorAddr, sdk.Coins{amount}) if err != nil { return err } - newShares := candidate.addTokens(tokens.Amount, tr.gs) + newShares := k.candidateAddTokens(ctx, candidate, amount.Amount) bond.Shares = bond.Shares.Add(newShares) - k.SetDelegatorBond() - return nil -} - -// Perform all the actions required to bond tokens to a delegator bond from their account -func (k Keeper) UnbondCoins(ctx sdk.Context, bond *DelegatorBond, candidate *Candidate, shares sdk.Rat) sdk.Error { - - // subtract bond tokens from delegator bond - if bond.Shares.LT(shares) { - return sdk.ErrInsufficientFunds("") //XXX variables inside - } - bond.Shares = bond.Shares.Sub(shares) - - returnAmount := candidate.removeShares(shares, tr.gs) - returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}} - - _, err := tr.coinKeeper.AddCoins(ctx, candidate.Address, returnCoins) - if err != nil { - return err - } + k.setDelegatorBond(ctx, bond) return nil } func (k Keeper) handleMsgUnbond(ctx sdk.Context, msg MsgUnbond) sdk.Result { // check if bond has any shares in it unbond - bond := k.getDelegatorBond(sender, msg.Address) - if bond == nil { + bond, found := k.getDelegatorBond(ctx, msg.DelegatorAddr, msg.CandidateAddr) + if !found { return ErrNoDelegatorForAddress().Result() } if !bond.Shares.GT(sdk.ZeroRat) { // bond shares < msg shares @@ -301,8 +250,8 @@ func (k Keeper) handleMsgUnbond(ctx sdk.Context, msg MsgUnbond) sdk.Result { bond.Shares = bond.Shares.Sub(shares) // get pubKey candidate - candidate := k.getCandidate(msg.Address) - if candidate == nil { + candidate, found := k.getCandidate(ctx, msg.CandidateAddr) + if !found { return ErrNoCandidateForAddress().Result() } @@ -311,41 +260,59 @@ func (k Keeper) handleMsgUnbond(ctx sdk.Context, msg MsgUnbond) sdk.Result { // if the bond is the owner of the candidate then // trigger a revoke candidacy - if bytes.Equal(tr.sender, candidate.Address) && + if bytes.Equal(bond.DelegatorAddr, candidate.Address) && candidate.Status != Revoked { revokeCandidacy = true } // remove the bond - k.removeDelegatorBond(ctx, msg.Address) + k.removeDelegatorBond(ctx, bond) } else { - k.setDelegatorBond(tr.sender, bond) + k.setDelegatorBond(ctx, bond) } // Add the coins - returnAmount := candidate.removeShares(shares, tr.gs) - returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}} - tr.coinKeeper.AddCoins(ctx, tr.sender, returnCoins) + returnAmount := k.candidateRemoveShares(ctx, candidate, shares) + returnCoins := sdk.Coins{{k.getParams(ctx).BondDenom, returnAmount}} + k.coinKeeper.AddCoins(ctx, bond.DelegatorAddr, returnCoins) // lastly if an revoke candidate if necessary if revokeCandidacy { // change the share types to unbonded if they were not already if candidate.Status == Bonded { - tr.bondedToUnbondedPool(candidate) + k.bondedToUnbondedPool(ctx, candidate) } // lastly update the status candidate.Status = Revoked } - // deduct shares from the candidate and save + // deduct shares from the candidate if candidate.Liabilities.IsZero() { - k.removeCandidate(msg.Address) + k.removeCandidate(ctx, candidate.Address) } else { - k.setCandidate(candidate) + k.setCandidate(ctx, candidate) } - - k.setGlobalState(tr.gs) return sdk.Result{} } + +// XXX where this used +// Perform all the actions required to bond tokens to a delegator bond from their account +func (k Keeper) UnbondCoins(ctx sdk.Context, bond DelegatorBond, candidate Candidate, shares sdk.Rat) sdk.Error { + + // subtract bond tokens from delegator bond + if bond.Shares.LT(shares) { + return sdk.ErrInsufficientFunds("") //XXX variables inside + } + bond.Shares = bond.Shares.Sub(shares) + + returnAmount := k.candidateRemoveShares(ctx, candidate, shares) + returnCoins := sdk.Coins{{k.getParams(ctx).BondDenom, returnAmount}} + + _, err := k.coinKeeper.AddCoins(ctx, candidate.Address, returnCoins) + if err != nil { + return err + } + return nil +} diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 214ee4350..665458c1a 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -1,247 +1,248 @@ package stake -import ( - "strconv" - "testing" +//import ( +//"strconv" +//"testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" +//"github.com/stretchr/testify/assert" +//"github.com/stretchr/testify/require" - crypto "github.com/tendermint/go-crypto" +//crypto "github.com/tendermint/go-crypto" - sdk "github.com/cosmos/cosmos-sdk/types" -) +//sdk "github.com/cosmos/cosmos-sdk/types" +//) -//______________________________________________________________________ +////______________________________________________________________________ -func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgDeclareCandidacy { - return MsgDeclareCandidacy{ - MsgAddr: NewMsgAddr(address), - Description: Description{}, - Bond: sdk.Coin{"fermion", amt}, - PubKey: pubKey, - } -} +//func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgDeclareCandidacy { +//return MsgDeclareCandidacy{ +//Description: Description{}, +//CandidateAddr: address, +//Bond: sdk.Coin{"fermion", amt}, +//PubKey: pubKey, +//} +//} -func newTestMsgDelegate(amt int64, address sdk.Address) MsgDelegate { - return MsgDelegate{ - MsgAddr: NewMsgAddr(address), - Bond: sdk.Coin{"fermion", amt}, - } -} +//func newTestMsgDelegate(amt int64, delegatorAddr, candidateAddr sdk.Address) MsgDelegate { +//return MsgDelegate{ +//DelegatorAddr: delegatorAddr, +//CandidateAddr: candidateAddr, +//Bond: sdk.Coin{"fermion", amt}, +//} +//} -func TestDuplicatesMsgDeclareCandidacy(t *testing.T) { - _, _, _, deliverer := createTestInput(t, addrs[0], false, 1000) - _, _, _, checker := createTestInput(t, addrs[0], true, 1000) +//func TestDuplicatesMsgDeclareCandidacy(t *testing.T) { +//ctxDeliver, _, keeper := createTestInput(t, addrs[0], false, 1000) +//ctxCheck, _, keeper := createTestInput(t, addrs[0], true, 1000) - msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], 10) - got := deliverer.declareCandidacy(msgDeclareCandidacy) - assert.NoError(t, got, "expected no error on runMsgDeclareCandidacy") +//msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], 10) +//got := deliverer.declareCandidacy(msgDeclareCandidacy) +//assert.NoError(t, got, "expected no error on runMsgDeclareCandidacy") - // one sender can bond to two different addresses - msgDeclareCandidacy.Address = addrs[1] - err := checker.declareCandidacy(msgDeclareCandidacy) - assert.Nil(t, err, "didn't expected error on checkTx") +//// one sender can bond to two different addresses +//msgDeclareCandidacy.Address = addrs[1] +//err := checker.declareCandidacy(msgDeclareCandidacy) +//assert.Nil(t, err, "didn't expected error on checkTx") - // two addrs cant bond to the same pubkey - checker.sender = addrs[1] - msgDeclareCandidacy.Address = addrs[0] - err = checker.declareCandidacy(msgDeclareCandidacy) - assert.NotNil(t, err, "expected error on checkTx") -} +//// two addrs cant bond to the same pubkey +//checker.sender = addrs[1] +//msgDeclareCandidacy.Address = addrs[0] +//err = checker.declareCandidacy(msgDeclareCandidacy) +//assert.NotNil(t, err, "expected error on checkTx") +//} -func TestIncrementsMsgDelegate(t *testing.T) { - _, _, mapper, deliverer := createTestInput(t, addrs[0], false, 1000) +//func TestIncrementsMsgDelegate(t *testing.T) { +//_, _, mapper, deliverer := createTestInput(t, addrs[0], false, 1000) - // first declare candidacy - bondAmount := int64(10) - msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], bondAmount) - got := deliverer.declareCandidacy(msgDeclareCandidacy) - assert.NoError(t, got, "expected declare candidacy msg to be ok, got %v", got) - expectedBond := bondAmount // 1 since we send 1 at the start of loop, +//// first declare candidacy +//bondAmount := int64(10) +//msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], bondAmount) +//got := deliverer.declareCandidacy(msgDeclareCandidacy) +//assert.NoError(t, got, "expected declare candidacy msg to be ok, got %v", got) +//expectedBond := bondAmount // 1 since we send 1 at the start of loop, - // just send the same msgbond multiple times - msgDelegate := newTestMsgDelegate(bondAmount, addrs[0]) - for i := 0; i < 5; i++ { - got := deliverer.delegate(msgDelegate) - assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// just send the same msgbond multiple times +//msgDelegate := newTestMsgDelegate(bondAmount, addrs[0]) +//for i := 0; i < 5; i++ { +//got := deliverer.delegate(msgDelegate) +//assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the accounts and the bond account have the appropriate values - candidates := mapper.getCandidates() - expectedBond += bondAmount - //expectedSender := initSender - expectedBond - gotBonded := candidates[0].Liabilities.Evaluate() - //gotSender := accStore[string(deliverer.sender)] //XXX use StoreMapper - assert.Equal(t, expectedBond, gotBonded, "i: %v, %v, %v", i, expectedBond, gotBonded) - //assert.Equal(t, expectedSender, gotSender, "i: %v, %v, %v", i, expectedSender, gotSender) // XXX fix - } -} +////Check that the accounts and the bond account have the appropriate values +//candidates := mapper.getCandidates() +//expectedBond += bondAmount +////expectedSender := initSender - expectedBond +//gotBonded := candidates[0].Liabilities.Evaluate() +////gotSender := accStore[string(deliverer.sender)] //XXX use StoreMapper +//assert.Equal(t, expectedBond, gotBonded, "i: %v, %v, %v", i, expectedBond, gotBonded) +////assert.Equal(t, expectedSender, gotSender, "i: %v, %v, %v", i, expectedSender, gotSender) // XXX fix +//} +//} -func TestIncrementsMsgUnbond(t *testing.T) { - _, _, mapper, deliverer := createTestInput(t, addrs[0], false, 0) +//func TestIncrementsMsgUnbond(t *testing.T) { +//_, _, mapper, deliverer := createTestInput(t, addrs[0], false, 0) - // set initial bond - initBond := int64(1000) - //accStore[string(deliverer.sender)] = initBond //XXX use StoreMapper - got := deliverer.declareCandidacy(newTestMsgDeclareCandidacy(addrs[0], pks[0], initBond)) - assert.NoError(t, got, "expected initial bond msg to be ok, got %v", got) +//// set initial bond +//initBond := int64(1000) +////accStore[string(deliverer.sender)] = initBond //XXX use StoreMapper +//got := deliverer.declareCandidacy(newTestMsgDeclareCandidacy(addrs[0], pks[0], initBond)) +//assert.NoError(t, got, "expected initial bond msg to be ok, got %v", got) - // just send the same msgunbond multiple times - // XXX use decimals here - unbondShares, unbondSharesStr := int64(10), "10" - msgUndelegate := NewMsgUnbond(addrs[0], unbondSharesStr) - nUnbonds := 5 - for i := 0; i < nUnbonds; i++ { - got := deliverer.unbond(msgUndelegate) - assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// just send the same msgunbond multiple times +//// XXX use decimals here +//unbondShares, unbondSharesStr := int64(10), "10" +//msgUndelegate := NewMsgUnbond(addrs[0], unbondSharesStr) +//nUnbonds := 5 +//for i := 0; i < nUnbonds; i++ { +//got := deliverer.unbond(msgUndelegate) +//assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the accounts and the bond account have the appropriate values - candidates := mapper.getCandidates() - expectedBond := initBond - int64(i+1)*unbondShares // +1 since we send 1 at the start of loop - //expectedSender := initSender + (initBond - expectedBond) - gotBonded := candidates[0].Liabilities.Evaluate() - //gotSender := accStore[string(deliverer.sender)] // XXX use storemapper +////Check that the accounts and the bond account have the appropriate values +//candidates := mapper.getCandidates() +//expectedBond := initBond - int64(i+1)*unbondShares // +1 since we send 1 at the start of loop +////expectedSender := initSender + (initBond - expectedBond) +//gotBonded := candidates[0].Liabilities.Evaluate() +////gotSender := accStore[string(deliverer.sender)] // XXX use storemapper - assert.Equal(t, expectedBond, gotBonded, "%v, %v", expectedBond, gotBonded) - //assert.Equal(t, expectedSender, gotSender, "%v, %v", expectedSender, gotSender) //XXX fix - } +//assert.Equal(t, expectedBond, gotBonded, "%v, %v", expectedBond, gotBonded) +////assert.Equal(t, expectedSender, gotSender, "%v, %v", expectedSender, gotSender) //XXX fix +//} - // these are more than we have bonded now - errorCases := []int64{ - //1<<64 - 1, // more than int64 - //1<<63 + 1, // more than int64 - 1<<63 - 1, - 1 << 31, - initBond, - } - for _, c := range errorCases { - unbondShares := strconv.Itoa(int(c)) - msgUndelegate := NewMsgUnbond(addrs[0], unbondShares) - got = deliverer.unbond(msgUndelegate) - assert.Error(t, got, "expected unbond msg to fail") - } +//// these are more than we have bonded now +//errorCases := []int64{ +////1<<64 - 1, // more than int64 +////1<<63 + 1, // more than int64 +//1<<63 - 1, +//1 << 31, +//initBond, +//} +//for _, c := range errorCases { +//unbondShares := strconv.Itoa(int(c)) +//msgUndelegate := NewMsgUnbond(addrs[0], unbondShares) +//got = deliverer.unbond(msgUndelegate) +//assert.Error(t, got, "expected unbond msg to fail") +//} - leftBonded := initBond - unbondShares*int64(nUnbonds) +//leftBonded := initBond - unbondShares*int64(nUnbonds) - // should be unable to unbond one more than we have - msgUndelegate = NewMsgUnbond(addrs[0], strconv.Itoa(int(leftBonded)+1)) - got = deliverer.unbond(msgUndelegate) - assert.Error(t, got, "expected unbond msg to fail") +//// should be unable to unbond one more than we have +//msgUndelegate = NewMsgUnbond(addrs[0], strconv.Itoa(int(leftBonded)+1)) +//got = deliverer.unbond(msgUndelegate) +//assert.Error(t, got, "expected unbond msg to fail") - // should be able to unbond just what we have - msgUndelegate = NewMsgUnbond(addrs[0], strconv.Itoa(int(leftBonded))) - got = deliverer.unbond(msgUndelegate) - assert.NoError(t, got, "expected unbond msg to pass") -} +//// should be able to unbond just what we have +//msgUndelegate = NewMsgUnbond(addrs[0], strconv.Itoa(int(leftBonded))) +//got = deliverer.unbond(msgUndelegate) +//assert.NoError(t, got, "expected unbond msg to pass") +//} -func TestMultipleMsgDeclareCandidacy(t *testing.T) { - initSender := int64(1000) - ctx, accStore, mapper, deliverer := createTestInput(t, addrs[0], false, initSender) - addrs := []sdk.Address{addrs[0], addrs[1], addrs[2]} +//func TestMultipleMsgDeclareCandidacy(t *testing.T) { +//initSender := int64(1000) +//ctx, accStore, mapper, deliverer := createTestInput(t, addrs[0], false, initSender) +//addrs := []sdk.Address{addrs[0], addrs[1], addrs[2]} - // bond them all - for i, addr := range addrs { - msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[i], pks[i], 10) - deliverer.sender = addr - got := deliverer.declareCandidacy(msgDeclareCandidacy) - assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// bond them all +//for i, addr := range addrs { +//msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[i], pks[i], 10) +//deliverer.sender = addr +//got := deliverer.declareCandidacy(msgDeclareCandidacy) +//assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the account is bonded - candidates := mapper.getCandidates() - require.Equal(t, i, len(candidates)) - val := candidates[i] - balanceExpd := initSender - 10 - balanceGot := accStore.GetAccount(ctx, val.Address).GetCoins() - assert.Equal(t, i+1, len(candidates), "expected %d candidates got %d, candidates: %v", i+1, len(candidates), candidates) - assert.Equal(t, 10, int(val.Liabilities.Evaluate()), "expected %d shares, got %d", 10, val.Liabilities) - assert.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } +////Check that the account is bonded +//candidates := mapper.getCandidates() +//require.Equal(t, i, len(candidates)) +//val := candidates[i] +//balanceExpd := initSender - 10 +//balanceGot := accStore.GetAccount(ctx, val.Address).GetCoins() +//assert.Equal(t, i+1, len(candidates), "expected %d candidates got %d, candidates: %v", i+1, len(candidates), candidates) +//assert.Equal(t, 10, int(val.Liabilities.Evaluate()), "expected %d shares, got %d", 10, val.Liabilities) +//assert.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) +//} - // unbond them all - for i, addr := range addrs { - candidatePre := mapper.getCandidate(addrs[i]) - msgUndelegate := NewMsgUnbond(addrs[i], "10") - deliverer.sender = addr - got := deliverer.unbond(msgUndelegate) - assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// unbond them all +//for i, addr := range addrs { +//candidatePre := mapper.getCandidate(addrs[i]) +//msgUndelegate := NewMsgUnbond(addrs[i], "10") +//deliverer.sender = addr +//got := deliverer.unbond(msgUndelegate) +//assert.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the account is unbonded - candidates := mapper.getCandidates() - assert.Equal(t, len(addrs)-(i+1), len(candidates), "expected %d candidates got %d", len(addrs)-(i+1), len(candidates)) +////Check that the account is unbonded +//candidates := mapper.getCandidates() +//assert.Equal(t, len(addrs)-(i+1), len(candidates), "expected %d candidates got %d", len(addrs)-(i+1), len(candidates)) - candidatePost := mapper.getCandidate(addrs[i]) - balanceExpd := initSender - balanceGot := accStore.GetAccount(ctx, candidatePre.Address).GetCoins() - assert.Nil(t, candidatePost, "expected nil candidate retrieve, got %d", 0, candidatePost) - assert.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } -} +//candidatePost := mapper.getCandidate(addrs[i]) +//balanceExpd := initSender +//balanceGot := accStore.GetAccount(ctx, candidatePre.Address).GetCoins() +//assert.Nil(t, candidatePost, "expected nil candidate retrieve, got %d", 0, candidatePost) +//assert.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) +//} +//} -func TestMultipleMsgDelegate(t *testing.T) { - sender, delegators := addrs[0], addrs[1:] - _, _, mapper, deliverer := createTestInput(t, addrs[0], false, 1000) +//func TestMultipleMsgDelegate(t *testing.T) { +//sender, delegators := addrs[0], addrs[1:] +//_, _, mapper, deliverer := createTestInput(t, addrs[0], false, 1000) - //first make a candidate - msgDeclareCandidacy := newTestMsgDeclareCandidacy(sender, pks[0], 10) - got := deliverer.declareCandidacy(msgDeclareCandidacy) - require.NoError(t, got, "expected msg to be ok, got %v", got) +////first make a candidate +//msgDeclareCandidacy := newTestMsgDeclareCandidacy(sender, pks[0], 10) +//got := deliverer.declareCandidacy(msgDeclareCandidacy) +//require.NoError(t, got, "expected msg to be ok, got %v", got) - // delegate multiple parties - for i, delegator := range delegators { - msgDelegate := newTestMsgDelegate(10, sender) - deliverer.sender = delegator - got := deliverer.delegate(msgDelegate) - require.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// delegate multiple parties +//for i, delegator := range delegators { +//msgDelegate := newTestMsgDelegate(10, sender) +//deliverer.sender = delegator +//got := deliverer.delegate(msgDelegate) +//require.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the account is bonded - bond := mapper.getDelegatorBond(delegator, sender) - assert.NotNil(t, bond, "expected delegatee bond %d to exist", bond) - } +////Check that the account is bonded +//bond := mapper.getDelegatorBond(delegator, sender) +//assert.NotNil(t, bond, "expected delegatee bond %d to exist", bond) +//} - // unbond them all - for i, delegator := range delegators { - msgUndelegate := NewMsgUnbond(sender, "10") - deliverer.sender = delegator - got := deliverer.unbond(msgUndelegate) - require.NoError(t, got, "expected msg %d to be ok, got %v", i, got) +//// unbond them all +//for i, delegator := range delegators { +//msgUndelegate := NewMsgUnbond(sender, "10") +//deliverer.sender = delegator +//got := deliverer.unbond(msgUndelegate) +//require.NoError(t, got, "expected msg %d to be ok, got %v", i, got) - //Check that the account is unbonded - bond := mapper.getDelegatorBond(delegator, sender) - assert.Nil(t, bond, "expected delegatee bond %d to be nil", bond) - } -} +////Check that the account is unbonded +//bond := mapper.getDelegatorBond(delegator, sender) +//assert.Nil(t, bond, "expected delegatee bond %d to be nil", bond) +//} +//} -func TestVoidCandidacy(t *testing.T) { - sender, delegator := addrs[0], addrs[1] - _, _, _, deliverer := createTestInput(t, addrs[0], false, 1000) +//func TestVoidCandidacy(t *testing.T) { +//sender, delegator := addrs[0], addrs[1] +//_, _, _, deliverer := createTestInput(t, addrs[0], false, 1000) - // create the candidate - msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], 10) - got := deliverer.declareCandidacy(msgDeclareCandidacy) - require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") +//// create the candidate +//msgDeclareCandidacy := newTestMsgDeclareCandidacy(addrs[0], pks[0], 10) +//got := deliverer.declareCandidacy(msgDeclareCandidacy) +//require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") - // bond a delegator - msgDelegate := newTestMsgDelegate(10, addrs[0]) - deliverer.sender = delegator - got = deliverer.delegate(msgDelegate) - require.NoError(t, got, "expected ok, got %v", got) +//// bond a delegator +//msgDelegate := newTestMsgDelegate(10, addrs[0]) +//deliverer.sender = delegator +//got = deliverer.delegate(msgDelegate) +//require.NoError(t, got, "expected ok, got %v", got) - // unbond the candidates bond portion - msgUndelegate := NewMsgUnbond(addrs[0], "10") - deliverer.sender = sender - got = deliverer.unbond(msgUndelegate) - require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") +//// unbond the candidates bond portion +//msgUndelegate := NewMsgUnbond(addrs[0], "10") +//deliverer.sender = sender +//got = deliverer.unbond(msgUndelegate) +//require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") - // test that this pubkey cannot yet be bonded too - deliverer.sender = delegator - got = deliverer.delegate(msgDelegate) - assert.Error(t, got, "expected error, got %v", got) +//// test that this pubkey cannot yet be bonded too +//deliverer.sender = delegator +//got = deliverer.delegate(msgDelegate) +//assert.Error(t, got, "expected error, got %v", got) - // test that the delegator can still withdraw their bonds - got = deliverer.unbond(msgUndelegate) - require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") +//// test that the delegator can still withdraw their bonds +//got = deliverer.unbond(msgUndelegate) +//require.NoError(t, got, "expected no error on runMsgDeclareCandidacy") - // verify that the pubkey can now be reused - got = deliverer.declareCandidacy(msgDeclareCandidacy) - assert.NoError(t, got, "expected ok, got %v", got) -} +//// verify that the pubkey can now be reused +//got = deliverer.declareCandidacy(msgDeclareCandidacy) +//assert.NoError(t, got, "expected ok, got %v", got) +//} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 2428aaeca..a54d006bc 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -84,39 +84,39 @@ func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinK } //XXX load/save -> get/set -func (m Keeper) getCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candidate) { - store := ctx.KVStore(storeKey) +func (k Keeper) getCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candidate, found bool) { + store := ctx.KVStore(k.storeKey) b := store.Get(GetCandidateKey(addr)) if b == nil { - return nil + return candidate, false } - err := m.cdc.UnmarshalJSON(b, &candidate) + err := k.cdc.UnmarshalJSON(b, &candidate) if err != nil { - panic(err) // This error should never occur big problem if does + panic(err) } - return + return candidate, true } -func (m Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { - store := ctx.KVStore(storeKey) +func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { + store := ctx.KVStore(k.storeKey) // XXX should only remove validator if we know candidate is a validator - m.removeValidator(candidate.Address) - validator := &Validator{candidate.Address, candidate.VotingPower} - m.updateValidator(validator) + k.removeValidator(ctx, candidate.Address) + validator := Validator{candidate.Address, candidate.VotingPower} + k.updateValidator(ctx, validator) - b, err := m.cdc.MarshalJSON(candidate) + b, err := k.cdc.MarshalJSON(candidate) if err != nil { panic(err) } store.Set(GetCandidateKey(candidate.Address), b) } -func (m Keeper) removeCandidate(ctx sdk.Context, candidateAddr sdk.Address) { - store := ctx.KVStore(storeKey) +func (k Keeper) removeCandidate(ctx sdk.Context, candidateAddr sdk.Address) { + store := ctx.KVStore(k.storeKey) // XXX should only remove validator if we know candidate is a validator - m.removeValidator(candidateAddr) + k.removeValidator(ctx, candidateAddr) store.Delete(GetCandidateKey(candidateAddr)) } @@ -137,10 +137,10 @@ func (m Keeper) removeCandidate(ctx sdk.Context, candidateAddr sdk.Address) { // updateValidator - update a validator and create accumulate any changes // in the changed validator substore -func (m Keeper) updateValidator(ctx sdk.Context, validator Validator) { - store := ctx.KVStore(storeKey) +func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) { + store := ctx.KVStore(k.storeKey) - b, err := m.cdc.MarshalJSON(validator) + b, err := k.cdc.MarshalJSON(validator) if err != nil { panic(err) } @@ -149,31 +149,31 @@ func (m Keeper) updateValidator(ctx sdk.Context, validator Validator) { store.Set(GetValidatorUpdatesKey(validator.Address), b) // update the list ordered by voting power - store.Set(GetValidatorKey(validator.Address, validator.VotingPower, m.cdc), b) + store.Set(GetValidatorKey(validator.Address, validator.VotingPower, k.cdc), b) } -func (m Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { - store := ctx.KVStore(storeKey) +func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { + store := ctx.KVStore(k.storeKey) //add validator with zero power to the validator updates - b, err := m.cdc.MarshalJSON(Validator{address, sdk.ZeroRat}) + b, err := k.cdc.MarshalJSON(Validator{address, sdk.ZeroRat}) if err != nil { panic(err) } store.Set(GetValidatorUpdatesKey(address), b) // now actually delete from the validator set - candidate := m.getCandidate(address) - if candidate != nil { - store.Delete(GetValidatorKey(address, candidate.VotingPower, m.cdc)) + candidate, found := k.getCandidate(ctx, address) + if found { + store.Delete(GetValidatorKey(address, candidate.VotingPower, k.cdc)) } } // get the most recent updated validator set from the Candidates. These bonds // are already sorted by VotingPower from the UpdateVotingPower function which // is the only function which is to modify the VotingPower -func (m Keeper) getValidators(ctx sdk.Context, maxVal uint16) (validators []Validator) { - store := ctx.KVStore(storeKey) +func (k Keeper) getValidators(ctx sdk.Context, maxVal uint16) (validators []Validator) { + store := ctx.KVStore(k.storeKey) iterator := store.Iterator(subspace(ValidatorKeyPrefix)) //smallest to largest @@ -185,7 +185,7 @@ func (m Keeper) getValidators(ctx sdk.Context, maxVal uint16) (validators []Vali } valBytes := iterator.Value() var val Validator - err := m.cdc.UnmarshalJSON(valBytes, &val) + err := k.cdc.UnmarshalJSON(valBytes, &val) if err != nil { panic(err) } @@ -199,15 +199,15 @@ func (m Keeper) getValidators(ctx sdk.Context, maxVal uint16) (validators []Vali //_________________________________________________________________________ // get the most updated validators -func (m Keeper) getValidatorUpdates(ctx sdk.Context) (updates []Validator) { - store := ctx.KVStore(storeKey) +func (k Keeper) getValidatorUpdates(ctx sdk.Context) (updates []Validator) { + store := ctx.KVStore(k.storeKey) iterator := store.Iterator(subspace(ValidatorUpdatesKeyPrefix)) //smallest to largest for ; iterator.Valid(); iterator.Next() { valBytes := iterator.Value() var val Validator - err := m.cdc.UnmarshalJSON(valBytes, &val) + err := k.cdc.UnmarshalJSON(valBytes, &val) if err != nil { panic(err) } @@ -219,8 +219,8 @@ func (m Keeper) getValidatorUpdates(ctx sdk.Context) (updates []Validator) { } // remove all validator update entries -func (m Keeper) clearValidatorUpdates(ctx sdk.Context, maxVal int) { - store := ctx.KVStore(storeKey) +func (k Keeper) clearValidatorUpdates(ctx sdk.Context, maxVal int) { + store := ctx.KVStore(k.storeKey) iterator := store.Iterator(subspace(ValidatorUpdatesKeyPrefix)) for ; iterator.Valid(); iterator.Next() { store.Delete(iterator.Key()) // XXX write test for this, may need to be in a second loop @@ -230,22 +230,19 @@ func (m Keeper) clearValidatorUpdates(ctx sdk.Context, maxVal int) { //--------------------------------------------------------------------- -// getCandidates - get the active list of all candidates TODO replace with multistore -func (m Keeper) getCandidates(ctx sdk.Context) (candidates Candidates) { - store := ctx.KVStore(storeKey) - +// getCandidates - get the active list of all candidates +func (k Keeper) getCandidates(ctx sdk.Context) (candidates Candidates) { + store := ctx.KVStore(k.storeKey) iterator := store.Iterator(subspace(CandidateKeyPrefix)) - //iterator := store.Iterator(CandidateKeyPrefix, []byte(nil)) - //iterator := store.Iterator([]byte{}, []byte(nil)) for ; iterator.Valid(); iterator.Next() { candidateBytes := iterator.Value() var candidate Candidate - err := m.cdc.UnmarshalJSON(candidateBytes, &candidate) + err := k.cdc.UnmarshalJSON(candidateBytes, &candidate) if err != nil { panic(err) } - candidates = append(candidates, &candidate) + candidates = append(candidates, candidate) } iterator.Close() return candidates @@ -253,17 +250,17 @@ func (m Keeper) getCandidates(ctx sdk.Context) (candidates Candidates) { //_____________________________________________________________________ -// XXX use a store iterator to get +// XXX use a store iterator here instead //// load the pubkeys of all candidates a delegator is delegated too -//func (m Keeper) getDelegatorCandidates(ctx sdk.Context, delegator sdk.Address) (candidateAddrs []sdk.Address) { -//store := ctx.KVStore(storeKey) +//func (k Keeper) getDelegatorCandidates(ctx sdk.Context, delegator sdk.Address) (candidateAddrs []sdk.Address) { +//store := ctx.KVStore(k.storeKey) -//candidateBytes := store.Get(GetDelegatorBondsKey(delegator, m.cdc)) +//candidateBytes := store.Get(GetDelegatorBondsKey(delegator, k.cdc)) //if candidateBytes == nil { //return nil //} -//err := m.cdc.UnmarshalJSON(candidateBytes, &candidateAddrs) +//err := k.cdc.UnmarshalJSON(candidateBytes, &candidateAddrs) //if err != nil { //panic(err) //} @@ -272,126 +269,229 @@ func (m Keeper) getCandidates(ctx sdk.Context) (candidates Candidates) { //_____________________________________________________________________ -func (m Keeper) getDelegatorBond(ctx sdk.Context, - delegator, candidate sdk.Address) (bond DelegatorBond) { +func (k Keeper) getDelegatorBond(ctx sdk.Context, + delegatorAddr, candidateAddr sdk.Address) (bond DelegatorBond, found bool) { - store := ctx.KVStore(storeKey) - delegatorBytes := store.Get(GetDelegatorBondKey(delegator, candidate, m.cdc)) + store := ctx.KVStore(k.storeKey) + delegatorBytes := store.Get(GetDelegatorBondKey(delegatorAddr, candidateAddr, k.cdc)) if delegatorBytes == nil { - return nil + return bond, false } - err := m.cdc.UnmarshalJSON(delegatorBytes, &bond) + err := k.cdc.UnmarshalJSON(delegatorBytes, &bond) if err != nil { panic(err) } - return bond + return bond, true } -func (m Keeper) setDelegatorBond(ctx sdk.Context, bond DelegatorBond) { - store := ctx.KVStore(storeKey) +func (k Keeper) setDelegatorBond(ctx sdk.Context, bond DelegatorBond) { + store := ctx.KVStore(k.storeKey) // XXX use store iterator // if a new bond add to the list of bonds - //if m.getDelegatorBond(delegator, bond.Address) == nil { - //pks := m.getDelegatorCandidates(delegator) + //if k.getDelegatorBond(delegator, bond.Address) == nil { + //pks := k.getDelegatorCandidates(delegator) //pks = append(pks, bond.Address) - //b, err := m.cdc.MarshalJSON(pks) + //b, err := k.cdc.MarshalJSON(pks) //if err != nil { //panic(err) //} - //store.Set(GetDelegatorBondsKey(delegator, m.cdc), b) + //store.Set(GetDelegatorBondsKey(delegator, k.cdc), b) //} // now actually save the bond - b, err := m.cdc.MarshalJSON(bond) + b, err := k.cdc.MarshalJSON(bond) if err != nil { panic(err) } - store.Set(GetDelegatorBondKey(delegator, bond.Address, m.cdc), b) + store.Set(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc), b) } -func (m Keeper) removeDelegatorBond(ctx sdk.Context, bond DelegatorBond) { - store := ctx.KVStore(storeKey) +func (k Keeper) removeDelegatorBond(ctx sdk.Context, bond DelegatorBond) { + store := ctx.KVStore(k.storeKey) // XXX use store iterator // TODO use list queries on multistore to remove iterations here! // first remove from the list of bonds - //addrs := m.getDelegatorCandidates(delegator) + //addrs := k.getDelegatorCandidates(delegator) //for i, addr := range addrs { //if bytes.Equal(candidateAddr, addr) { //addrs = append(addrs[:i], addrs[i+1:]...) //} //} - //b, err := m.cdc.MarshalJSON(addrs) + //b, err := k.cdc.MarshalJSON(addrs) //if err != nil { //panic(err) //} - //store.Set(GetDelegatorBondsKey(delegator, m.cdc), b) + //store.Set(GetDelegatorBondsKey(delegator, k.cdc), b) // now remove the actual bond - store.Delete(GetDelegatorBondKey(bond.delegatorAddr, bond.candidateAddr, m.cdc)) + store.Delete(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc)) //updateDelegatorBonds(store, delegator) //XXX remove? } //_______________________________________________________________________ // load/save the global staking params -func (m Keeper) getParams(ctx sdk.Context) (params Params) { +func (k Keeper) getParams(ctx sdk.Context) (params Params) { // check if cached before anything - if m.params != (Params{}) { - return m.params + if k.params != (Params{}) { + return k.params } - store := ctx.KVStore(storeKey) + store := ctx.KVStore(k.storeKey) b := store.Get(ParamKey) if b == nil { return defaultParams() } - err := m.cdc.UnmarshalJSON(b, ¶ms) + err := k.cdc.UnmarshalJSON(b, ¶ms) if err != nil { panic(err) // This error should never occur big problem if does } return } -func (m Keeper) setParams(ctx sdk.Context, params Params) { - store := ctx.KVStore(storeKey) - b, err := m.cdc.MarshalJSON(params) +func (k Keeper) setParams(ctx sdk.Context, params Params) { + store := ctx.KVStore(k.storeKey) + b, err := k.cdc.MarshalJSON(params) if err != nil { panic(err) } store.Set(ParamKey, b) - m.params = Params{} // clear the cache + k.params = Params{} // clear the cache } //_______________________________________________________________________ // XXX nothing is this Keeper should return a pointer...!!!!!! // load/save the global staking state -func (m Keeper) getGlobalState(ctx sdk.Context) (gs GlobalState) { +func (k Keeper) getGlobalState(ctx sdk.Context) (gs GlobalState) { // check if cached before anything - if m.gs != nil { - return m.gs + if k.gs != (GlobalState{}) { + return k.gs } - store := ctx.KVStore(storeKey) + store := ctx.KVStore(k.storeKey) b := store.Get(GlobalStateKey) if b == nil { return initialGlobalState() } - gs = new(GlobalState) - err := m.cdc.UnmarshalJSON(b, &gs) + err := k.cdc.UnmarshalJSON(b, &gs) if err != nil { panic(err) // This error should never occur big problem if does } return } -func (m Keeper) setGlobalState(ctx sdk.Context, gs GlobalState) { - store := ctx.KVStore(storeKey) - b, err := m.cdc.MarshalJSON(gs) +func (k Keeper) setGlobalState(ctx sdk.Context, gs GlobalState) { + store := ctx.KVStore(k.storeKey) + b, err := k.cdc.MarshalJSON(gs) if err != nil { panic(err) } store.Set(GlobalStateKey, b) - m.gs = GlobalState{} // clear the cache + k.gs = GlobalState{} // clear the cache +} + +//_______________________________________________________________________ + +//TODO make these next two functions more efficient should be reading and writting to state ye know + +// move a candidates asset pool from bonded to unbonded pool +func (k Keeper) bondedToUnbondedPool(ctx sdk.Context, candidate Candidate) { + + // replace bonded shares with unbonded shares + tokens := k.removeSharesBonded(ctx, candidate.Assets) + candidate.Assets = k.addTokensUnbonded(ctx, tokens) + candidate.Status = Unbonded + k.setCandidate(ctx, candidate) +} + +// move a candidates asset pool from unbonded to bonded pool +func (k Keeper) unbondedToBondedPool(ctx sdk.Context, candidate Candidate) { + + // replace unbonded shares with bonded shares + tokens := k.removeSharesUnbonded(ctx, candidate.Assets) + candidate.Assets = k.addTokensBonded(ctx, tokens) + candidate.Status = Bonded + k.setCandidate(ctx, candidate) +} + +// XXX expand to include the function of actually transfering the tokens + +//XXX CONFIRM that use of the exRate is correct with Zarko Spec! +func (k Keeper) addTokensBonded(ctx sdk.Context, amount int64) (issuedShares sdk.Rat) { + gs := k.getGlobalState(ctx) + issuedShares = gs.bondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens + gs.BondedPool += amount + gs.BondedShares = gs.BondedShares.Add(issuedShares) + k.setGlobalState(ctx, gs) + return +} + +//XXX CONFIRM that use of the exRate is correct with Zarko Spec! +func (k Keeper) removeSharesBonded(ctx sdk.Context, shares sdk.Rat) (removedTokens int64) { + gs := k.getGlobalState(ctx) + removedTokens = gs.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + gs.BondedShares = gs.BondedShares.Sub(shares) + gs.BondedPool -= removedTokens + k.setGlobalState(ctx, gs) + return +} + +//XXX CONFIRM that use of the exRate is correct with Zarko Spec! +func (k Keeper) addTokensUnbonded(ctx sdk.Context, amount int64) (issuedShares sdk.Rat) { + gs := k.getGlobalState(ctx) + issuedShares = gs.unbondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens + gs.UnbondedShares = gs.UnbondedShares.Add(issuedShares) + gs.UnbondedPool += amount + k.setGlobalState(ctx, gs) + return +} + +//XXX CONFIRM that use of the exRate is correct with Zarko Spec! +func (k Keeper) removeSharesUnbonded(ctx sdk.Context, shares sdk.Rat) (removedTokens int64) { + gs := k.getGlobalState(ctx) + removedTokens = gs.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + gs.UnbondedShares = gs.UnbondedShares.Sub(shares) + gs.UnbondedPool -= removedTokens + k.setGlobalState(ctx, gs) + return +} + +// add tokens to a candidate +func (k Keeper) candidateAddTokens(ctx sdk.Context, candidate Candidate, amount int64) (issuedDelegatorShares sdk.Rat) { + + gs := k.getGlobalState(ctx) + exRate := candidate.delegatorShareExRate() + + var receivedGlobalShares sdk.Rat + if candidate.Status == Bonded { + receivedGlobalShares = k.addTokensBonded(ctx, amount) + } else { + receivedGlobalShares = k.addTokensUnbonded(ctx, amount) + } + candidate.Assets = candidate.Assets.Add(receivedGlobalShares) + + issuedDelegatorShares = exRate.Mul(receivedGlobalShares) + candidate.Liabilities = candidate.Liabilities.Add(issuedDelegatorShares) + k.setGlobalState(ctx, gs) // TODO cache GlobalState? + return +} + +// remove shares from a candidate +func (k Keeper) candidateRemoveShares(ctx sdk.Context, candidate Candidate, shares sdk.Rat) (createdCoins int64) { + + gs := k.getGlobalState(ctx) + //exRate := candidate.delegatorShareExRate() //XXX make sure not used + + globalPoolSharesToRemove := candidate.delegatorShareExRate().Mul(shares) + if candidate.Status == Bonded { + createdCoins = k.removeSharesBonded(ctx, globalPoolSharesToRemove) + } else { + createdCoins = k.removeSharesUnbonded(ctx, globalPoolSharesToRemove) + } + candidate.Assets = candidate.Assets.Sub(globalPoolSharesToRemove) + candidate.Liabilities = candidate.Liabilities.Sub(shares) + k.setGlobalState(ctx, gs) // TODO cache GlobalState? + return } diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 680b51642..fa01bb9a3 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -37,7 +37,7 @@ import ( //assert.Equal(int64(500), candidates[1].VotingPower.Evaluate(), "%v", candidates[1]) //// test the max validators term -//params.MaxVals = 4 +//params.MaxValidators = 4 //setParams(store, params) //candidates.updateVotingPower(store, gs, params) //assert.Equal(int64(0), candidates[4].VotingPower.Evaluate(), "%v", candidates[4]) @@ -131,7 +131,7 @@ import ( //require.Equal(0, len(change), "%v", change) // change 1, remove 1, add 2 //// test the max value and test again -//params.MaxVals = 4 +//params.MaxValidators = 4 //setParams(store, params) //change, err = UpdateValidatorSet(store, gs, params) //require.Nil(err) @@ -161,7 +161,7 @@ import ( //} func TestState(t *testing.T) { - _, _, keeper, _ := createTestInput(t, nil, false, 0) + ctx, _, keeper := createTestInput(t, nil, false, 0) addrDel := sdk.Address([]byte("addressdelegator")) addrVal := sdk.Address([]byte("addressvalidator")) @@ -172,7 +172,7 @@ func TestState(t *testing.T) { // Candidate checks // XXX expand to include both liabilities and assets use/test all candidate fields - candidate := &Candidate{ + candidate := Candidate{ Address: addrVal, PubKey: pk, Assets: sdk.NewRat(9), @@ -180,7 +180,7 @@ func TestState(t *testing.T) { VotingPower: sdk.ZeroRat, } - candidatesEqual := func(c1, c2 *Candidate) bool { + candidatesEqual := func(c1, c2 Candidate) bool { return c1.Status == c2.Status && c1.PubKey.Equals(c2.PubKey) && bytes.Equal(c1.Address, c2.Address) && @@ -191,54 +191,59 @@ func TestState(t *testing.T) { } // check the empty keeper first - resCand := keeper.getCandidate(addrVal) - assert.Nil(t, resCand) - resPks := keeper.getCandidates() + _, found := keeper.getCandidate(ctx, addrVal) + assert.False(t, found) + resPks := keeper.getCandidates(ctx) assert.Zero(t, len(resPks)) // set and retrieve a record - keeper.setCandidate(candidate) - resCand = keeper.getCandidate(addrVal) - //assert.Equal(candidate, resCand) + keeper.setCandidate(ctx, candidate) + resCand, found := keeper.getCandidate(ctx, addrVal) + assert.True(t, found) assert.True(t, candidatesEqual(candidate, resCand), "%#v \n %#v", resCand, candidate) // modify a records, save, and retrieve candidate.Liabilities = sdk.NewRat(99) - keeper.setCandidate(candidate) - resCand = keeper.getCandidate(addrVal) + keeper.setCandidate(ctx, candidate) + resCand, found = keeper.getCandidate(ctx, addrVal) + assert.True(t, found) assert.True(t, candidatesEqual(candidate, resCand)) // also test that the pubkey has been added to pubkey list - resPks = keeper.getCandidates() + resPks = keeper.getCandidates(ctx) require.Equal(t, 1, len(resPks)) assert.Equal(t, addrVal, resPks[0].PubKey) //---------------------------------------------------------------------- // Bond checks - bond := &DelegatorBond{ - Address: addrDel, - Shares: sdk.NewRat(9), + bond := DelegatorBond{ + DelegatorAddr: addrDel, + CandidateAddr: addrVal, + Shares: sdk.NewRat(9), } - bondsEqual := func(b1, b2 *DelegatorBond) bool { - return bytes.Equal(b1.Address, b2.Address) && + bondsEqual := func(b1, b2 DelegatorBond) bool { + return bytes.Equal(b1.DelegatorAddr, b2.DelegatorAddr) && + bytes.Equal(b1.CandidateAddr, b2.CandidateAddr) && b1.Shares == b2.Shares } //check the empty keeper first - resBond := keeper.getDelegatorBond(addrDel, addrVal) - assert.Nil(t, resBond) + _, found = keeper.getDelegatorBond(ctx, addrDel, addrVal) + assert.False(t, found) //Set and retrieve a record - keeper.setDelegatorBond(addrDel, bond) - resBond = keeper.getDelegatorBond(addrDel, addrVal) + keeper.setDelegatorBond(ctx, bond) + resBond, found := keeper.getDelegatorBond(ctx, addrDel, addrVal) + assert.True(t, found) assert.True(t, bondsEqual(bond, resBond)) //modify a records, save, and retrieve bond.Shares = sdk.NewRat(99) - keeper.setDelegatorBond(addrDel, bond) - resBond = keeper.getDelegatorBond(addrDel, addrVal) + keeper.setDelegatorBond(ctx, bond) + resBond, found = keeper.getDelegatorBond(ctx, addrDel, addrVal) + assert.True(t, found) assert.True(t, bondsEqual(bond, resBond)) //---------------------------------------------------------------------- @@ -247,21 +252,21 @@ func TestState(t *testing.T) { params := defaultParams() //check that the empty keeper loads the default - resParams := keeper.getParams() + resParams := keeper.getParams(ctx) assert.Equal(t, params, resParams) //modify a params, save, and retrieve - params.MaxVals = 777 - keeper.setParams(params) - resParams = keeper.getParams() + params.MaxValidators = 777 + keeper.setParams(ctx, params) + resParams = keeper.getParams(ctx) assert.Equal(t, params, resParams) } func TestGetValidators(t *testing.T) { - _, _, keeper, _ := createTestInput(t, nil, false, 0) - candidatesFromAddrs(keeper, addrs, []int64{400, 200, 0, 0, 0}) + ctx, _, keeper := createTestInput(t, nil, false, 0) + candidatesFromAddrs(ctx, keeper, addrs, []int64{400, 200, 0, 0, 0}) - validators := keeper.getValidators(5) + validators := keeper.getValidators(ctx, 5) require.Equal(t, 2, len(validators)) assert.Equal(t, addrs[0], validators[0].Address) assert.Equal(t, addrs[1], validators[1].Address) diff --git a/x/stake/msg.go b/x/stake/msg.go index ad9e7e2eb..3b94b6bcb 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -20,8 +20,8 @@ var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelega type MsgDeclareCandidacy struct { Description CandidateAddr sdk.Address `json:"address"` - Bond sdk.Coin `json:"bond"` PubKey crypto.PubKey `json:"pubkey"` + Bond sdk.Coin `json:"bond"` } func NewMsgDeclareCandidacy(candidateAddr sdk.Address, pubkey crypto.PubKey, @@ -29,8 +29,8 @@ func NewMsgDeclareCandidacy(candidateAddr sdk.Address, pubkey crypto.PubKey, return MsgDeclareCandidacy{ Description: description, CandidateAddr: candidateAddr, - Bond: bond, PubKey: pubkey, + Bond: bond, } } @@ -39,7 +39,7 @@ func (msg MsgDeclareCandidacy) Type() string { return func (msg MsgDeclareCandidacy) Get(key interface{}) (value interface{}) { return nil } func (msg MsgDeclareCandidacy) GetSigners() []sdk.Address { return []sdk.Address{msg.CandidateAddr} } func (msg MsgDeclareCandidacy) String() string { - return fmt.Sprintf("CandidateAddr{Address: %v}", msg.Address) // XXX fix + return fmt.Sprintf("CandidateAddr{Address: %v}", msg.CandidateAddr) // XXX fix } // get the bytes for the message signer to sign on @@ -53,11 +53,11 @@ func (msg MsgDeclareCandidacy) GetSignBytes() []byte { // quick validity check func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error { - if msg.Address == nil { + if msg.CandidateAddr == nil { return ErrCandidateEmpty() } - if msg.Bond.Denom <= 0 { - return sdk.ErrInvalidCoins(coins) + if msg.Bond.Amount <= 0 { + return sdk.ErrInvalidCoins(sdk.Coins{msg.Bond}) } empty := Description{} if msg.Description == empty { @@ -74,10 +74,10 @@ type MsgEditCandidacy struct { CandidateAddr sdk.Address `json:"address"` } -func NewMsgEditCandidacy(address sdk.Address, description Description) MsgEditCandidacy { +func NewMsgEditCandidacy(candidateAddr sdk.Address, description Description) MsgEditCandidacy { return MsgEditCandidacy{ - Description: description, - Address: address, + Description: description, + CandidateAddr: candidateAddr, } } @@ -86,7 +86,7 @@ func (msg MsgEditCandidacy) Type() string { return Ms func (msg MsgEditCandidacy) Get(key interface{}) (value interface{}) { return nil } func (msg MsgEditCandidacy) GetSigners() []sdk.Address { return []sdk.Address{msg.CandidateAddr} } func (msg MsgEditCandidacy) String() string { - return fmt.Sprintf("CandidateAddr{Address: %v}", msg.Address) // XXX fix + return fmt.Sprintf("CandidateAddr{Address: %v}", msg.CandidateAddr) // XXX fix } // get the bytes for the message signer to sign on @@ -100,12 +100,9 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte { // quick validity check func (msg MsgEditCandidacy) ValidateBasic() sdk.Error { - if msg.Address == nil { + if msg.CandidateAddr == nil { return ErrCandidateEmpty() } - if err != nil { - return err - } empty := Description{} if msg.Description == empty { return newError(CodeInvalidInput, "Transaction must include some information to modify") @@ -155,8 +152,8 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { if msg.CandidateAddr == nil { return ErrBadCandidateAddr() } - if msg.Bond.Denom <= 0 { - return sdk.ErrInvalidCoins(coins) + if msg.Bond.Amount <= 0 { + return sdk.ErrInvalidCoins(sdk.Coins{msg.Bond}) } return nil } @@ -204,7 +201,7 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error { return ErrBadCandidateAddr() } if msg.Shares != "MAX" { - shares, err = sdk.NewRatFromDecimal(msg.Shares) + _, err := sdk.NewRatFromDecimal(msg.Shares) if err != nil { return ErrBadShares() } diff --git a/x/stake/msg_test.go b/x/stake/msg_test.go index 0af8b0db6..26d58a3db 100644 --- a/x/stake/msg_test.go +++ b/x/stake/msg_test.go @@ -23,39 +23,40 @@ var ( coinNegNotAtoms = sdk.Coin{"foo", -10000} ) -func TestMsgAddrValidateBasic(t *testing.T) { - tests := []struct { - name string - address sdk.Address - wantErr bool - }{ - {"basic good", addrs[0], false}, - {"empty delegator", sdk.Address{}, true}, - } +//TODO add these tests to one of some of the types +//func TestMsgAddrValidateBasic(t *testing.T) { +//tests := []struct { +//name string +//address sdk.Address +//wantErr bool +//}{ +//{"basic good", addrs[0], false}, +//{"empty delegator", sdk.Address{}, true}, +//} - for _, tc := range tests { - tx := NewMsgAddr(tc.address) - assert.Equal(t, tc.wantErr, tx.ValidateBasic() != nil, - "test: %v, tx.ValidateBasic: %v", tc.name, tx.ValidateBasic()) - } -} +//for _, tc := range tests { +//tx := NewMsgAddr(tc.address) +//assert.Equal(t, tc.wantErr, tx.ValidateBasic() != nil, +//"test: %v, tx.ValidateBasic: %v", tc.name, tx.ValidateBasic()) +//} +//} -func TestValidateCoin(t *testing.T) { - tests := []struct { - name string - coin sdk.Coin - wantErr bool - }{ - {"basic good", coinPos, false}, - {"zero coin", coinZero, true}, - {"neg coin", coinNeg, true}, - } +//func TestValidateCoin(t *testing.T) { +//tests := []struct { +//name string +//coin sdk.Coin +//wantErr bool +//}{ +//{"basic good", coinPos, false}, +//{"zero coin", coinZero, true}, +//{"neg coin", coinNeg, true}, +//} - for _, tc := range tests { - assert.Equal(t, tc.wantErr, validateCoin(tc.coin) != nil, - "test: %v, tx.ValidateBasic: %v", tc.name, validateCoin(tc.coin)) - } -} +//for _, tc := range tests { +//assert.Equal(t, tc.wantErr, validateCoin(tc.coin) != nil, +//"test: %v, tx.ValidateBasic: %v", tc.name, validateCoin(tc.coin)) +//} +//} func TestSerializeMsg(t *testing.T) { @@ -68,8 +69,8 @@ func TestSerializeMsg(t *testing.T) { }{ {NewMsgDeclareCandidacy(addrs[0], pks[0], bond, Description{})}, {NewMsgEditCandidacy(addrs[0], Description{})}, - {NewMsgDelegate(addrs[0], bond)}, - {NewMsgUnbond(addrs[0], strconv.Itoa(bondAmt))}, + {NewMsgDelegate(addrs[0], addrs[1], bond)}, + {NewMsgUnbond(addrs[0], addrs[1], strconv.Itoa(bondAmt))}, } for i, tc := range tests { diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 601ee50fd..d3db53af4 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -65,20 +65,16 @@ func paramsNoInflation() Params { InflationMax: sdk.ZeroRat, InflationMin: sdk.ZeroRat, GoalBonded: sdk.NewRat(67, 100), - MaxVals: 100, + MaxValidators: 100, BondDenom: "fermion", - GasDeclareCandidacy: 20, - GasEditCandidacy: 20, - GasDelegate: 20, - GasUnbond: 20, } } // hogpodge of all sorts of input required for testing -func createTestInput(t *testing.T, sender sdk.Address, isCheckTx bool, initCoins int64) (sdk.Context, sdk.AccountMapper, Mapper, transact) { +func createTestInput(t *testing.T, sender sdk.Address, isCheckTx bool, initCoins int64) (sdk.Context, sdk.AccountMapper, Keeper) { db := dbm.NewMemDB() keyStake := sdk.NewKVStoreKey("stake") - keyMain := keyStake //sdk.NewKVStoreKey("main") //XXX fix multistore + keyMain := keyStake //sdk.NewKVStoreKey("main") //TODO fix multistore ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db) @@ -86,26 +82,23 @@ func createTestInput(t *testing.T, sender sdk.Address, isCheckTx bool, initCoins require.Nil(t, err) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil) - cdc := makeTestCodec() - mapper := NewMapper(ctx, cdc, keyStake) - accountMapper := auth.NewAccountMapperSealed( keyMain, // target store &auth.BaseAccount{}, // prototype ) ck := bank.NewCoinKeeper(accountMapper) + keeper := NewKeeper(ctx, cdc, keyStake, ck) + params := paramsNoInflation() - mapper.setParams(params) + keeper.setParams(ctx, params) // fill all the addresses with some coins for _, addr := range addrs { ck.AddCoins(ctx, addr, sdk.Coins{{params.BondDenom, initCoins}}) } - tr := newTransact(ctx, sender, mapper, ck) - - return ctx, accountMapper, mapper, tr + return ctx, accountMapper, keeper } func newPubKey(pk string) (res crypto.PubKey) { @@ -157,9 +150,9 @@ var addrs = []sdk.Address{ // NOTE: PubKey is supposed to be the binaryBytes of the crypto.PubKey // instead this is just being set the address here for testing purposes -func candidatesFromAddrs(mapper Mapper, addrs []crypto.Address, amts []int64) { +func candidatesFromAddrs(ctx sdk.Context, keeper Keeper, addrs []crypto.Address, amts []int64) { for i := 0; i < len(amts); i++ { - c := &Candidate{ + c := Candidate{ Status: Unbonded, PubKey: pks[i], Address: addrs[i], @@ -167,13 +160,13 @@ func candidatesFromAddrs(mapper Mapper, addrs []crypto.Address, amts []int64) { Liabilities: sdk.NewRat(amts[i]), VotingPower: sdk.NewRat(amts[i]), } - mapper.setCandidate(c) + keeper.setCandidate(ctx, c) } } func candidatesFromAddrsEmpty(addrs []crypto.Address) (candidates Candidates) { for i := 0; i < len(addrs); i++ { - c := &Candidate{ + c := Candidate{ Status: Unbonded, PubKey: pks[i], Address: addrs[i], diff --git a/x/stake/tick.go b/x/stake/tick.go index 27ba44f6a..9148dcf6e 100644 --- a/x/stake/tick.go +++ b/x/stake/tick.go @@ -6,21 +6,21 @@ import ( ) // Tick - called at the end of every block -func Tick(ctx sdk.Context, m Mapper) (change []*abci.Validator, err error) { +func Tick(ctx sdk.Context, k Keeper) (change []*abci.Validator, err error) { // retrieve params - params := m.getParams() - gs := m.getGlobalState() + params := k.getParams(ctx) + gs := k.getGlobalState(ctx) height := ctx.BlockHeight() // Process Validator Provisions // XXX right now just process every 5 blocks, in new SDK make hourly if gs.InflationLastTime+5 <= height { gs.InflationLastTime = height - processProvisions(m, gs, params) + processProvisions(ctx, k, gs, params) } - newVals := m.getValidators(params.MaxVals) + newVals := k.getValidators(ctx, params.MaxValidators) // XXX determine change from old validators, set to change _ = newVals return change, nil @@ -29,7 +29,7 @@ func Tick(ctx sdk.Context, m Mapper) (change []*abci.Validator, err error) { var hrsPerYr = sdk.NewRat(8766) // as defined by a julian year of 365.25 days // process provisions for an hour period -func processProvisions(m Mapper, gs *GlobalState, params Params) { +func processProvisions(ctx sdk.Context, k Keeper, gs GlobalState, params Params) { gs.Inflation = nextInflation(gs, params).Round(1000000000) @@ -46,11 +46,11 @@ func processProvisions(m Mapper, gs *GlobalState, params Params) { // XXX XXX XXX XXX XXX XXX XXX XXX XXX // save the params - m.setGlobalState(gs) + k.setGlobalState(ctx, gs) } // get the next inflation rate for the hour -func nextInflation(gs *GlobalState, params Params) (inflation sdk.Rat) { +func nextInflation(gs GlobalState, params Params) (inflation sdk.Rat) { // The target annual inflation rate is recalculated for each previsions cycle. The // inflation is also subject to a rate change (positive of negative) depending or diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index fcd67af9c..aceeb1b63 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -8,9 +8,9 @@ import ( ) func TestGetInflation(t *testing.T) { - _, _, mapper, _ := createTestInput(t, nil, false, 0) - params := mapper.getParams() - gs := mapper.getGlobalState() + ctx, _, keeper := createTestInput(t, nil, false, 0) + params := keeper.getParams(ctx) + gs := keeper.getGlobalState(ctx) // Governing Mechanism: // bondedRatio = BondedPool / TotalSupply @@ -53,9 +53,9 @@ func TestGetInflation(t *testing.T) { } func TestProcessProvisions(t *testing.T) { - _, _, mapper, _ := createTestInput(t, nil, false, 0) - params := mapper.getParams() - gs := mapper.getGlobalState() + ctx, _, keeper := createTestInput(t, nil, false, 0) + params := keeper.getParams(ctx) + gs := keeper.getGlobalState(ctx) // create some candidates some bonded, some unbonded candidates := candidatesFromAddrsEmpty(addrs) @@ -65,8 +65,8 @@ func TestProcessProvisions(t *testing.T) { } mintedTokens := int64((i + 1) * 10000000) gs.TotalSupply += mintedTokens - candidate.addTokens(mintedTokens, gs) - mapper.setCandidate(candidate) + keeper.candidateAddTokens(ctx, candidate, mintedTokens) + keeper.setCandidate(ctx, candidate) } var totalSupply int64 = 550000000 var bondedShares int64 = 150000000 @@ -92,7 +92,7 @@ func TestProcessProvisions(t *testing.T) { expProvisions := (expInflation.Mul(sdk.NewRat(gs.TotalSupply)).Quo(hrsPerYr)).Evaluate() startBondedPool := gs.BondedPool startTotalSupply := gs.TotalSupply - processProvisions(mapper, gs, params) + processProvisions(ctx, keeper, gs, params) assert.Equal(t, startBondedPool+expProvisions, gs.BondedPool) assert.Equal(t, startTotalSupply+expProvisions, gs.TotalSupply) } diff --git a/x/stake/types.go b/x/stake/types.go index d1cf6df5f..72bc9db51 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -42,8 +42,8 @@ type GlobalState struct { // XXX define globalstate interface? -func initialGlobalState() *GlobalState { - return &GlobalState{ +func initialGlobalState() GlobalState { + return GlobalState{ TotalSupply: 0, BondedShares: sdk.ZeroRat, UnbondedShares: sdk.ZeroRat, @@ -55,7 +55,7 @@ func initialGlobalState() *GlobalState { } // get the bond ratio of the global state -func (gs *GlobalState) bondedRatio() sdk.Rat { +func (gs GlobalState) bondedRatio() sdk.Rat { if gs.TotalSupply > 0 { return sdk.NewRat(gs.BondedPool, gs.TotalSupply) } @@ -63,7 +63,7 @@ func (gs *GlobalState) bondedRatio() sdk.Rat { } // get the exchange rate of bonded token per issued share -func (gs *GlobalState) bondedShareExRate() sdk.Rat { +func (gs GlobalState) bondedShareExRate() sdk.Rat { if gs.BondedShares.IsZero() { return sdk.OneRat } @@ -71,48 +71,13 @@ func (gs *GlobalState) bondedShareExRate() sdk.Rat { } // get the exchange rate of unbonded tokens held in candidates per issued share -func (gs *GlobalState) unbondedShareExRate() sdk.Rat { +func (gs GlobalState) unbondedShareExRate() sdk.Rat { if gs.UnbondedShares.IsZero() { return sdk.OneRat } return gs.UnbondedShares.Inv().Mul(sdk.NewRat(gs.UnbondedPool)) } -// XXX XXX XXX -// expand to include the function of actually transfering the tokens - -//XXX CONFIRM that use of the exRate is correct with Zarko Spec! -func (gs *GlobalState) addTokensBonded(amount int64) (issuedShares sdk.Rat) { - issuedShares = gs.bondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens - gs.BondedPool += amount - gs.BondedShares = gs.BondedShares.Add(issuedShares) - return -} - -//XXX CONFIRM that use of the exRate is correct with Zarko Spec! -func (gs *GlobalState) removeSharesBonded(shares sdk.Rat) (removedTokens int64) { - removedTokens = gs.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares - gs.BondedShares = gs.BondedShares.Sub(shares) - gs.BondedPool -= removedTokens - return -} - -//XXX CONFIRM that use of the exRate is correct with Zarko Spec! -func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rat) { - issuedShares = gs.unbondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens - gs.UnbondedShares = gs.UnbondedShares.Add(issuedShares) - gs.UnbondedPool += amount - return -} - -//XXX CONFIRM that use of the exRate is correct with Zarko Spec! -func (gs *GlobalState) removeSharesUnbonded(shares sdk.Rat) (removedTokens int64) { - removedTokens = gs.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares - gs.UnbondedShares = gs.UnbondedShares.Sub(shares) - gs.UnbondedPool -= removedTokens - return -} - //_______________________________________________________________________________________________________ // CandidateStatus - status of a validator-candidate @@ -151,8 +116,8 @@ type Description struct { } // NewCandidate - initialize a new candidate -func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Description) *Candidate { - return &Candidate{ +func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Description) Candidate { + return Candidate{ Status: Unbonded, Address: address, PubKey: pubKey, @@ -164,50 +129,16 @@ func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Descrip } // get the exchange rate of global pool shares over delegator shares -func (c *Candidate) delegatorShareExRate() sdk.Rat { +func (c Candidate) delegatorShareExRate() sdk.Rat { if c.Liabilities.IsZero() { return sdk.OneRat } return c.Assets.Quo(c.Liabilities) } -// add tokens to a candidate -func (c *Candidate) addTokens(amount int64, gs *GlobalState) (issuedDelegatorShares sdk.Rat) { - - exRate := c.delegatorShareExRate() - - var receivedGlobalShares sdk.Rat - if c.Status == Bonded { - receivedGlobalShares = gs.addTokensBonded(amount) - } else { - receivedGlobalShares = gs.addTokensUnbonded(amount) - } - c.Assets = c.Assets.Add(receivedGlobalShares) - - issuedDelegatorShares = exRate.Mul(receivedGlobalShares) - c.Liabilities = c.Liabilities.Add(issuedDelegatorShares) - return -} - -// remove shares from a candidate -func (c *Candidate) removeShares(shares sdk.Rat, gs *GlobalState) (createdCoins int64) { - - globalPoolSharesToRemove := c.delegatorShareExRate().Mul(shares) - - if c.Status == Bonded { - createdCoins = gs.removeSharesBonded(globalPoolSharesToRemove) - } else { - createdCoins = gs.removeSharesUnbonded(globalPoolSharesToRemove) - } - c.Assets = c.Assets.Sub(globalPoolSharesToRemove) - - c.Liabilities = c.Liabilities.Sub(shares) - return -} - // Validator returns a copy of the Candidate as a Validator. // Should only be called when the Candidate qualifies as a validator. -func (c *Candidate) validator() Validator { +func (c Candidate) validator() Validator { return Validator{ Address: c.Address, // XXX !!! VotingPower: c.VotingPower, @@ -242,7 +173,7 @@ func (v Validator) ABCIValidator() (*abci.Validator, error) { //_________________________________________________________________________ // Candidates - list of Candidates -type Candidates []*Candidate +type Candidates []Candidate //_________________________________________________________________________ @@ -251,7 +182,7 @@ type Candidates []*Candidate // pubKey. // TODO better way of managing space type DelegatorBond struct { - Address sdk.Address `json:"address"` + DelegatorAddr sdk.Address `json:"delegatoraddr"` CandidateAddr sdk.Address `json:"candidate_addr"` Shares sdk.Rat `json:"shares"` }