2018-01-20 20:08:00 -08:00
|
|
|
package baseapp
|
2017-12-20 17:34:51 -08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
abci "github.com/tendermint/abci/types"
|
|
|
|
"github.com/tendermint/go-crypto"
|
|
|
|
cmn "github.com/tendermint/tmlibs/common"
|
2017-12-26 17:04:48 -08:00
|
|
|
dbm "github.com/tendermint/tmlibs/db"
|
2018-01-15 17:38:56 -08:00
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2017-12-20 17:34:51 -08:00
|
|
|
)
|
|
|
|
|
2018-01-06 12:53:31 -08:00
|
|
|
// A mock transaction to update a validator's voting power.
|
2018-01-26 04:19:33 -08:00
|
|
|
type testUpdatePowerTx struct {
|
2018-01-06 12:53:31 -08:00
|
|
|
Addr []byte
|
|
|
|
NewPower int64
|
|
|
|
}
|
2017-12-20 17:34:51 -08:00
|
|
|
|
2018-01-26 06:22:56 -08:00
|
|
|
const msgType = "testUpdatePowerTx"
|
2018-01-15 17:38:56 -08:00
|
|
|
|
2018-01-26 06:22:56 -08:00
|
|
|
func (tx testUpdatePowerTx) Type() string { return msgType }
|
2018-01-26 04:19:33 -08:00
|
|
|
func (tx testUpdatePowerTx) Get(key interface{}) (value interface{}) { return nil }
|
2018-01-26 06:22:56 -08:00
|
|
|
func (tx testUpdatePowerTx) GetMsg() sdk.Msg { return tx }
|
2018-01-26 04:19:33 -08:00
|
|
|
func (tx testUpdatePowerTx) GetSignBytes() []byte { return nil }
|
|
|
|
func (tx testUpdatePowerTx) ValidateBasic() sdk.Error { return nil }
|
|
|
|
func (tx testUpdatePowerTx) GetSigners() []crypto.Address { return nil }
|
|
|
|
func (tx testUpdatePowerTx) GetFeePayer() crypto.Address { return nil }
|
|
|
|
func (tx testUpdatePowerTx) GetSignatures() []sdk.StdSignature { return nil }
|
2018-01-06 12:53:31 -08:00
|
|
|
|
|
|
|
func TestBasic(t *testing.T) {
|
2017-12-20 17:34:51 -08:00
|
|
|
|
|
|
|
// Create app.
|
2018-01-22 05:44:24 -08:00
|
|
|
app := NewBaseApp(t.Name())
|
2018-01-26 04:19:33 -08:00
|
|
|
storeKeys := createMounts(app.cms)
|
|
|
|
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
|
|
|
|
var ttx testUpdatePowerTx
|
2018-01-06 12:53:31 -08:00
|
|
|
fromJSON(txBytes, &ttx)
|
|
|
|
return ttx, nil
|
|
|
|
})
|
2018-01-15 17:38:56 -08:00
|
|
|
|
|
|
|
app.SetDefaultAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
2018-01-26 06:22:56 -08:00
|
|
|
app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
2018-01-06 12:53:31 -08:00
|
|
|
// TODO
|
2018-01-15 17:38:56 -08:00
|
|
|
return sdk.Result{}
|
2017-12-20 17:34:51 -08:00
|
|
|
})
|
|
|
|
|
|
|
|
// Load latest state, which should be empty.
|
2018-01-15 17:38:56 -08:00
|
|
|
err := app.LoadLatestVersion(storeKeys["main"])
|
2017-12-20 17:34:51 -08:00
|
|
|
assert.Nil(t, err)
|
2017-12-26 17:04:48 -08:00
|
|
|
assert.Equal(t, app.LastBlockHeight(), int64(0))
|
2017-12-20 17:34:51 -08:00
|
|
|
|
|
|
|
// Create the validators
|
|
|
|
var numVals = 3
|
2017-12-26 17:04:48 -08:00
|
|
|
var valSet = make([]abci.Validator, numVals)
|
2017-12-20 17:34:51 -08:00
|
|
|
for i := 0; i < numVals; i++ {
|
|
|
|
valSet[i] = makeVal(secret(i))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the chain
|
|
|
|
app.InitChain(abci.RequestInitChain{
|
2017-12-26 17:04:48 -08:00
|
|
|
Validators: valSet,
|
2017-12-20 17:34:51 -08:00
|
|
|
})
|
|
|
|
|
|
|
|
// Simulate the start of a block.
|
|
|
|
app.BeginBlock(abci.RequestBeginBlock{})
|
|
|
|
|
|
|
|
// Add 1 to each validator's voting power.
|
|
|
|
for i, val := range valSet {
|
2018-01-26 04:19:33 -08:00
|
|
|
tx := testUpdatePowerTx{
|
2017-12-20 17:34:51 -08:00
|
|
|
Addr: makePubKey(secret(i)).Address(),
|
|
|
|
NewPower: val.Power + 1,
|
|
|
|
}
|
|
|
|
txBytes := toJSON(tx)
|
|
|
|
res := app.DeliverTx(txBytes)
|
2018-01-26 05:11:01 -08:00
|
|
|
assert.True(t, res.IsOK(), "%#v\nABCI log: %s", res, res.Log)
|
2017-12-20 17:34:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Simulate the end of a block.
|
|
|
|
// Get the summary of validator updates.
|
2017-12-26 17:04:48 -08:00
|
|
|
res := app.EndBlock(abci.RequestEndBlock{})
|
2017-12-20 17:34:51 -08:00
|
|
|
valUpdates := res.ValidatorUpdates
|
|
|
|
|
|
|
|
// Assert that validator updates are correct.
|
|
|
|
for _, val := range valSet {
|
2017-12-26 17:04:48 -08:00
|
|
|
// Sanity
|
|
|
|
assert.NotEqual(t, len(val.PubKey), 0)
|
2017-12-20 17:34:51 -08:00
|
|
|
|
|
|
|
// Find matching update and splice it out.
|
|
|
|
for j := 0; j < len(valUpdates); {
|
2017-12-26 17:04:48 -08:00
|
|
|
valUpdate := valUpdates[j]
|
2017-12-20 17:34:51 -08:00
|
|
|
|
|
|
|
// Matched.
|
|
|
|
if bytes.Equal(valUpdate.PubKey, val.PubKey) {
|
2017-12-26 17:04:48 -08:00
|
|
|
assert.Equal(t, valUpdate.Power, val.Power+1)
|
2017-12-20 17:34:51 -08:00
|
|
|
if j < len(valUpdates)-1 {
|
|
|
|
// Splice it out.
|
|
|
|
valUpdates = append(valUpdates[:j], valUpdates[j+1:]...)
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not matched.
|
|
|
|
j += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected")
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
func randPower() int64 {
|
|
|
|
return cmn.RandInt64()
|
|
|
|
}
|
|
|
|
|
2017-12-26 17:04:48 -08:00
|
|
|
func makeVal(secret string) abci.Validator {
|
|
|
|
return abci.Validator{
|
|
|
|
PubKey: makePubKey(secret).Bytes(),
|
2017-12-20 17:34:51 -08:00
|
|
|
Power: randPower(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makePubKey(secret string) crypto.PubKey {
|
|
|
|
return makePrivKey(secret).PubKey()
|
|
|
|
}
|
|
|
|
|
|
|
|
func makePrivKey(secret string) crypto.PrivKey {
|
2017-12-26 17:04:48 -08:00
|
|
|
privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret))
|
2018-01-15 17:38:56 -08:00
|
|
|
return privKey
|
2017-12-20 17:34:51 -08:00
|
|
|
}
|
|
|
|
|
2017-12-26 17:04:48 -08:00
|
|
|
func secret(index int) string {
|
|
|
|
return fmt.Sprintf("secret%d", index)
|
2017-12-20 17:34:51 -08:00
|
|
|
}
|
|
|
|
|
2017-12-26 17:04:48 -08:00
|
|
|
func copyVal(val abci.Validator) abci.Validator {
|
|
|
|
// val2 := *val
|
|
|
|
// return &val2
|
|
|
|
return val
|
2017-12-20 17:34:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func toJSON(o interface{}) []byte {
|
2017-12-26 17:04:48 -08:00
|
|
|
bz, err := json.Marshal(o)
|
2017-12-20 17:34:51 -08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2017-12-26 17:04:48 -08:00
|
|
|
// fmt.Println(">> toJSON:", string(bz))
|
|
|
|
return bz
|
2017-12-20 17:34:51 -08:00
|
|
|
}
|
|
|
|
|
2017-12-26 17:04:48 -08:00
|
|
|
func fromJSON(bz []byte, ptr interface{}) {
|
|
|
|
// fmt.Println(">> fromJSON:", string(bz))
|
|
|
|
err := json.Unmarshal(bz, ptr)
|
2017-12-20 17:34:51 -08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2017-12-26 17:04:48 -08:00
|
|
|
|
2018-01-22 05:44:24 -08:00
|
|
|
// Mounts stores to CommitMultiStore and returns a map of keys.
|
|
|
|
func createMounts(ms sdk.CommitMultiStore) map[string]sdk.StoreKey {
|
2017-12-26 17:04:48 -08:00
|
|
|
dbMain := dbm.NewMemDB()
|
|
|
|
dbXtra := dbm.NewMemDB()
|
2018-01-15 17:38:56 -08:00
|
|
|
keyMain := sdk.NewKVStoreKey("main")
|
|
|
|
keyXtra := sdk.NewKVStoreKey("xtra")
|
2018-01-22 05:44:24 -08:00
|
|
|
ms.MountStoreWithDB(keyMain, sdk.StoreTypeIAVL, dbMain)
|
|
|
|
ms.MountStoreWithDB(keyXtra, sdk.StoreTypeIAVL, dbXtra)
|
|
|
|
return map[string]sdk.StoreKey{
|
2018-01-15 17:38:56 -08:00
|
|
|
"main": keyMain,
|
|
|
|
"xtra": keyXtra,
|
|
|
|
}
|
2017-12-26 17:04:48 -08:00
|
|
|
}
|