303 lines
11 KiB
Go
303 lines
11 KiB
Go
package stake
|
|
|
|
import (
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
crypto "github.com/tendermint/go-crypto"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
coin "github.com/cosmos/cosmos-sdk/x/bank" // XXX fix
|
|
)
|
|
|
|
//______________________________________________________________________
|
|
|
|
func initAccounts(n int, amount int64) ([]sdk.Address, map[string]int64) {
|
|
accStore := map[string]int64{}
|
|
senders := newActors(n)
|
|
for _, sender := range senders {
|
|
accStore[string(sender.Address)] = amount
|
|
}
|
|
return senders, accStore
|
|
}
|
|
|
|
func newTestMsgDeclareCandidacy(amt int64, pubKey crypto.PubKey, address sdk.Address) MsgDeclareCandidacy {
|
|
return MsgDeclareCandidacy{
|
|
MsgAddr: NewMsgAddr(address),
|
|
PubKey: pubKey,
|
|
Bond: coin.Coin{"fermion", amt},
|
|
Description{},
|
|
}
|
|
}
|
|
|
|
func newTestMsgDelegate(amt int64, address sdk.Address) MsgDelegate {
|
|
return MsgDelegate{
|
|
MsgAddr: NewMsgAddr(address),
|
|
Bond: coin.Coin{"fermion", amt},
|
|
}
|
|
}
|
|
|
|
func newMsgUnbond(shares string, pubKey crypto.PubKey) MsgUnbond {
|
|
return MsgUnbond{
|
|
PubKey: pubKey,
|
|
Shares: shares,
|
|
}
|
|
}
|
|
|
|
func paramsNoInflation() Params {
|
|
return Params{
|
|
InflationRateChange: sdk.Zero,
|
|
InflationMax: sdk.Zero,
|
|
InflationMin: sdk.Zero,
|
|
GoalBonded: sdk.New(67, 100),
|
|
MaxVals: 100,
|
|
BondDenom: "fermion",
|
|
GasDeclareCandidacy: 20,
|
|
GasEditCandidacy: 20,
|
|
GasDelegate: 20,
|
|
GasUnbond: 20,
|
|
}
|
|
}
|
|
|
|
func newTestTransact(t, sender sdk.Address, isCheckTx bool) transact {
|
|
store, mapper, coinKeeper := createTestInput(t, isCheckTx)
|
|
params := paramsNoInflation()
|
|
mapper.saveParams(params)
|
|
newTransact(ctx, sender, mapper, coinKeeper)
|
|
}
|
|
|
|
func TestDuplicatesMsgDeclareCandidacy(t *testing.T) {
|
|
senders, accStore := initAccounts(2, 1000) // for accounts
|
|
|
|
deliverer := newDeliver(t, senders[0], accStore)
|
|
checker := check{
|
|
store: deliverer.store,
|
|
sender: senders[0],
|
|
}
|
|
|
|
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
|
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
|
assert.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
|
|
|
// one sender can bond to two different pubKeys
|
|
txDeclareCandidacy.PubKey = pks[1]
|
|
err := checker.declareCandidacy(txDeclareCandidacy)
|
|
assert.Nil(t, err, "didn't expected error on checkTx")
|
|
|
|
// two senders cant bond to the same pubkey
|
|
checker.sender = senders[1]
|
|
txDeclareCandidacy.PubKey = pks[0]
|
|
err = checker.declareCandidacy(txDeclareCandidacy)
|
|
assert.NotNil(t, err, "expected error on checkTx")
|
|
}
|
|
|
|
func TestIncrementsMsgDelegate(t *testing.T) {
|
|
initSender := int64(1000)
|
|
senders, accStore := initAccounts(1, initSender) // for accounts
|
|
deliverer := newDeliver(t, senders[0], accStore)
|
|
|
|
// first declare candidacy
|
|
bondAmount := int64(10)
|
|
txDeclareCandidacy := newTestMsgDeclareCandidacy(bondAmount, pks[0])
|
|
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
|
assert.NoError(t, got, "expected declare candidacy tx to be ok, got %v", got)
|
|
expectedBond := bondAmount // 1 since we send 1 at the start of loop,
|
|
|
|
// just send the same txbond multiple times
|
|
holder := deliverer.params.HoldUnbonded // XXX this should be HoldBonded, new SDK updates
|
|
txDelegate := newTestMsgDelegate(bondAmount, pks[0])
|
|
for i := 0; i < 5; i++ {
|
|
got := deliverer.delegate(txDelegate)
|
|
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the accounts and the bond account have the appropriate values
|
|
candidates := loadCandidates(deliverer.store)
|
|
expectedBond += bondAmount
|
|
expectedSender := initSender - expectedBond
|
|
gotBonded := candidates[0].Liabilities.Evaluate()
|
|
gotHolder := accStore[string(holder.Address)]
|
|
gotSender := accStore[string(deliverer.sender.Address)]
|
|
assert.Equal(t, expectedBond, gotBonded, "i: %v, %v, %v", i, expectedBond, gotBonded)
|
|
assert.Equal(t, expectedBond, gotHolder, "i: %v, %v, %v", i, expectedBond, gotHolder)
|
|
assert.Equal(t, expectedSender, gotSender, "i: %v, %v, %v", i, expectedSender, gotSender)
|
|
}
|
|
}
|
|
|
|
func TestIncrementsMsgUnbond(t *testing.T) {
|
|
initSender := int64(0)
|
|
senders, accStore := initAccounts(1, initSender) // for accounts
|
|
deliverer := newDeliver(t, senders[0], accStore)
|
|
|
|
// set initial bond
|
|
initBond := int64(1000)
|
|
accStore[string(deliverer.sender.Address)] = initBond
|
|
got := deliverer.declareCandidacy(newTestMsgDeclareCandidacy(initBond, pks[0]))
|
|
assert.NoError(t, got, "expected initial bond tx to be ok, got %v", got)
|
|
|
|
// just send the same txunbond multiple times
|
|
holder := deliverer.params.HoldUnbonded // XXX new SDK, this should be HoldBonded
|
|
|
|
// XXX use decimals here
|
|
unbondShares, unbondSharesStr := int64(10), "10"
|
|
txUndelegate := newMsgUnbond(unbondSharesStr, pks[0])
|
|
nUnbonds := 5
|
|
for i := 0; i < nUnbonds; i++ {
|
|
got := deliverer.unbond(txUndelegate)
|
|
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the accounts and the bond account have the appropriate values
|
|
candidates := loadCandidates(deliverer.store)
|
|
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()
|
|
gotHolder := accStore[string(holder.Address)]
|
|
gotSender := accStore[string(deliverer.sender.Address)]
|
|
|
|
assert.Equal(t, expectedBond, gotBonded, "%v, %v", expectedBond, gotBonded)
|
|
assert.Equal(t, expectedBond, gotHolder, "%v, %v", expectedBond, gotHolder)
|
|
assert.Equal(t, expectedSender, gotSender, "%v, %v", expectedSender, gotSender)
|
|
}
|
|
|
|
// 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))
|
|
txUndelegate := newMsgUnbond(unbondShares, pks[0])
|
|
got = deliverer.unbond(txUndelegate)
|
|
assert.Error(t, got, "expected unbond tx to fail")
|
|
}
|
|
|
|
leftBonded := initBond - unbondShares*int64(nUnbonds)
|
|
|
|
// should be unable to unbond one more than we have
|
|
txUndelegate = newMsgUnbond(strconv.Itoa(int(leftBonded)+1), pks[0])
|
|
got = deliverer.unbond(txUndelegate)
|
|
assert.Error(t, got, "expected unbond tx to fail")
|
|
|
|
// should be able to unbond just what we have
|
|
txUndelegate = newMsgUnbond(strconv.Itoa(int(leftBonded)), pks[0])
|
|
got = deliverer.unbond(txUndelegate)
|
|
assert.NoError(t, got, "expected unbond tx to pass")
|
|
}
|
|
|
|
func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
|
initSender := int64(1000)
|
|
senders, accStore := initAccounts(3, initSender)
|
|
pubKeys := []crypto.PubKey{pks[0], pks[1], pks[2]}
|
|
deliverer := newDeliver(t, senders[0], accStore)
|
|
|
|
// bond them all
|
|
for i, sender := range senders {
|
|
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pubKeys[i])
|
|
deliverer.sender = sender
|
|
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
|
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the account is bonded
|
|
candidates := loadCandidates(deliverer.store)
|
|
val := candidates[i]
|
|
balanceGot, balanceExpd := accStore[string(val.Owner.Address)], initSender-10
|
|
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, sender := range senders {
|
|
candidatePre := loadCandidate(deliverer.store, pubKeys[i])
|
|
txUndelegate := newMsgUnbond("10", pubKeys[i])
|
|
deliverer.sender = sender
|
|
got := deliverer.unbond(txUndelegate)
|
|
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the account is unbonded
|
|
candidates := loadCandidates(deliverer.store)
|
|
assert.Equal(t, len(senders)-(i+1), len(candidates), "expected %d candidates got %d", len(senders)-(i+1), len(candidates))
|
|
|
|
candidatePost := loadCandidate(deliverer.store, pubKeys[i])
|
|
balanceGot, balanceExpd := accStore[string(candidatePre.Owner.Address)], initSender
|
|
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) {
|
|
accounts, accStore := initAccounts(3, 1000)
|
|
sender, delegators := accounts[0], accounts[1:]
|
|
deliverer := newDeliver(t, sender, accStore)
|
|
|
|
//first make a candidate
|
|
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
|
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
|
require.NoError(t, got, "expected tx to be ok, got %v", got)
|
|
|
|
// delegate multiple parties
|
|
for i, delegator := range delegators {
|
|
txDelegate := newTestMsgDelegate(10, pks[0])
|
|
deliverer.sender = delegator
|
|
got := deliverer.delegate(txDelegate)
|
|
require.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the account is bonded
|
|
bond := loadDelegatorBond(deliverer.store, delegator, pks[0])
|
|
assert.NotNil(t, bond, "expected delegatee bond %d to exist", bond)
|
|
}
|
|
|
|
// unbond them all
|
|
for i, delegator := range delegators {
|
|
txUndelegate := newMsgUnbond("10", pks[0])
|
|
deliverer.sender = delegator
|
|
got := deliverer.unbond(txUndelegate)
|
|
require.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
|
|
|
//Check that the account is unbonded
|
|
bond := loadDelegatorBond(deliverer.store, delegator, pks[0])
|
|
assert.Nil(t, bond, "expected delegatee bond %d to be nil", bond)
|
|
}
|
|
}
|
|
|
|
func TestVoidCandidacy(t *testing.T) {
|
|
accounts, accStore := initAccounts(2, 1000) // for accounts
|
|
sender, delegator := accounts[0], accounts[1]
|
|
deliverer := newDeliver(t, sender, accStore)
|
|
|
|
// create the candidate
|
|
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
|
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
|
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
|
|
|
// bond a delegator
|
|
txDelegate := newTestMsgDelegate(10, pks[0])
|
|
deliverer.sender = delegator
|
|
got = deliverer.delegate(txDelegate)
|
|
require.NoError(t, got, "expected ok, got %v", got)
|
|
|
|
// unbond the candidates bond portion
|
|
txUndelegate := newMsgUnbond("10", pks[0])
|
|
deliverer.sender = sender
|
|
got = deliverer.unbond(txUndelegate)
|
|
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
|
|
|
// test that this pubkey cannot yet be bonded too
|
|
deliverer.sender = delegator
|
|
got = deliverer.delegate(txDelegate)
|
|
assert.Error(t, got, "expected error, got %v", got)
|
|
|
|
// test that the delegator can still withdraw their bonds
|
|
got = deliverer.unbond(txUndelegate)
|
|
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
|
|
|
// verify that the pubkey can now be reused
|
|
got = deliverer.declareCandidacy(txDeclareCandidacy)
|
|
assert.NoError(t, got, "expected ok, got %v", got)
|
|
}
|