Upgrade to tm version 23.0. (#1927)
* Start upgrade. Currently go test ./... hangs. * (squash this) Fix staking tests * wip * note what changes need to be made to make this work on tm v0.23.0 * Fix addr -> pubkey map * cleanup code * Fix slashing test failures except for begin blocker * fix all slashing tests * fix lcd tests * Address PR comments * add link to changelog. * (wip) start making addrToPubkey map persisted. Since amino can't handle maps, we have to change from what this commit is doing. * Use the correct method of storing a map * (squash this) address PR comments * Did you run 'make'? * remove gaiadebug binary
This commit is contained in:
parent
691048c88a
commit
b2a4aecc44
18
Gopkg.lock
generated
18
Gopkg.lock
generated
@ -423,7 +423,7 @@
|
||||
version = "v0.9.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:eb0f8bee357e6c28c9ad5fa074545b5085d0dcf580ba0e7024ab8c3285a5c815"
|
||||
digest = "1:26146cdb2811ce481e72138439b9b1aa17a64d54364f96bb92f97a9ef8ba4f01"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
@ -486,8 +486,8 @@
|
||||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "d542d2c3945116697f60451e6a407082c41c3cc9"
|
||||
version = "v0.22.8"
|
||||
revision = "013b9cef642f875634c614019ab13b17570778ad"
|
||||
version = "v0.23.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5bd938386bd1f61a581bf8cd6ff2b7b2f79c542929176db4ceb44965440dae07"
|
||||
@ -498,11 +498,14 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:65a21a9e051d54eb6a3f70c659a765f706a998d9287c302269f4ed8054b2a852"
|
||||
digest = "1:7a71fffde456d746c52f9cd09c50b034533a3180fb1f6320abb149f2ccc579e5"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"blowfish",
|
||||
"chacha20poly1305",
|
||||
"curve25519",
|
||||
"hkdf",
|
||||
"internal/chacha20",
|
||||
"internal/subtle",
|
||||
"nacl/box",
|
||||
"nacl/secretbox",
|
||||
@ -534,9 +537,12 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4d7a8265af700258feaff86722049eb5b787240d66dfaf45ff4962f09de6e0be"
|
||||
digest = "1:4d64ef38a30b73db6e8e7a2824b7fd356d921e0ee3fdd3248658996821d3b47d"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
packages = [
|
||||
"cpu",
|
||||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "acbc56fc7007d2a01796d5bde54f39e3b3e95945"
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "=v0.22.8"
|
||||
version = "=v0.23.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/bartekn/go-bip39"
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
## v0.24.0 PENDING
|
||||
^--- PENDING wasn't purged on sdk v0.23.0 release.
|
||||
|
||||
BREAKING CHANGES
|
||||
* Update to tendermint v0.23.0. This involves removing crypto.Pubkey,
|
||||
maintaining a validator address to pubkey map, and using time.Time instead of int64 for time. [SDK PR](https://github.com/cosmos/cosmos-sdk/pull/1927)
|
||||
|
||||
## PENDING
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
@ -387,7 +387,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
||||
}
|
||||
|
||||
// set the signed validators for addition to context in deliverTx
|
||||
app.signedValidators = req.Validators
|
||||
// TODO: communicate this result to the address to pubkey map in slashing
|
||||
app.signedValidators = req.LastCommitInfo.GetValidators()
|
||||
return
|
||||
}
|
||||
|
||||
@ -412,11 +413,7 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
|
||||
Log: result.Log,
|
||||
GasWanted: result.GasWanted,
|
||||
GasUsed: result.GasUsed,
|
||||
Fee: cmn.KI64Pair{
|
||||
[]byte(result.FeeDenom),
|
||||
result.FeeAmount,
|
||||
},
|
||||
Tags: result.Tags,
|
||||
Tags: result.Tags,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
@ -564,7 +565,7 @@ func TestUnrevoke(t *testing.T) {
|
||||
signingInfo := getSigningInfo(t, port, pkString)
|
||||
tests.WaitForHeight(4, port)
|
||||
require.Equal(t, true, signingInfo.IndexOffset > 0)
|
||||
require.Equal(t, int64(0), signingInfo.JailedUntil)
|
||||
require.Equal(t, time.Unix(0, 0).UTC(), signingInfo.JailedUntil)
|
||||
require.Equal(t, true, signingInfo.SignedBlocksCounter > 0)
|
||||
}
|
||||
|
||||
|
||||
@ -223,7 +223,7 @@ func startTM(
|
||||
proxy.NewLocalClientCreator(app),
|
||||
genDocProvider,
|
||||
dbProvider,
|
||||
nm.DefaultMetricsProvider,
|
||||
nm.DefaultMetricsProvider(tmcfg.Instrumentation),
|
||||
logger.With("module", "node"),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@ -44,5 +44,5 @@ func SignTxRequstHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(sig.Bytes())
|
||||
w.Write(sig)
|
||||
}
|
||||
|
||||
@ -148,7 +148,8 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab
|
||||
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||
|
||||
// Add these new validators to the addr -> pubkey map.
|
||||
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
Tags: tags,
|
||||
@ -181,6 +182,9 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
// load the address to pubkey map
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)
|
||||
|
||||
gov.InitGenesis(ctx, app.govKeeper, gov.DefaultGenesisState())
|
||||
|
||||
return abci.ResponseInitChain{
|
||||
|
||||
Binary file not shown.
@ -15,12 +15,14 @@ type byter interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
func checkAminoBinary(t *testing.T, src byter, dst interface{}, size int) {
|
||||
func checkAminoBinary(t *testing.T, src, dst interface{}, size int) {
|
||||
// Marshal to binary bytes.
|
||||
bz, err := cdc.MarshalBinaryBare(src)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
// Make sure this is compatible with current (Bytes()) encoding.
|
||||
require.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch")
|
||||
if byterSrc, ok := src.(byter); ok {
|
||||
// Make sure this is compatible with current (Bytes()) encoding.
|
||||
require.Equal(t, byterSrc.Bytes(), bz, "Amino binary vs Bytes() mismatch")
|
||||
}
|
||||
// Make sure we have the expected length.
|
||||
if size != -1 {
|
||||
require.Equal(t, size, len(bz), "Amino binary size mismatch")
|
||||
@ -55,8 +57,6 @@ func ExamplePrintRegisteredTypes() {
|
||||
//| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | |
|
||||
//| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | |
|
||||
//| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | |
|
||||
//| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | |
|
||||
//| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable | |
|
||||
}
|
||||
|
||||
func TestKeyEncodings(t *testing.T) {
|
||||
@ -86,13 +86,11 @@ func TestKeyEncodings(t *testing.T) {
|
||||
require.EqualValues(t, tc.privKey, priv3)
|
||||
|
||||
// Check (de/en)codings of Signatures.
|
||||
var sig1, sig2, sig3 tcrypto.Signature
|
||||
var sig1, sig2 []byte
|
||||
sig1, err := tc.privKey.Sign([]byte("something"))
|
||||
require.NoError(t, err)
|
||||
checkAminoBinary(t, sig1, &sig2, -1) // Signature size changes for Secp anyways.
|
||||
require.EqualValues(t, sig1, sig2)
|
||||
checkAminoJSON(t, sig1, &sig3, false) // TODO also check Prefix bytes.
|
||||
require.EqualValues(t, sig1, sig3)
|
||||
|
||||
// Check (de/en)codings of PubKeys.
|
||||
pubKey := tc.privKey.PubKey()
|
||||
@ -107,7 +105,7 @@ func TestKeyEncodings(t *testing.T) {
|
||||
func TestNilEncodings(t *testing.T) {
|
||||
|
||||
// Check nil Signature.
|
||||
var a, b tcrypto.Signature
|
||||
var a, b []byte
|
||||
checkAminoJSON(t, &a, &b, true)
|
||||
require.EqualValues(t, a, b)
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ func (kb dbKeybase) Get(name string) (Info, error) {
|
||||
|
||||
// Sign signs the msg with the named key.
|
||||
// It returns an error if the key doesn't exist or the decryption fails.
|
||||
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tmcrypto.Signature, pub tmcrypto.PubKey, err error) {
|
||||
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@ -146,7 +146,7 @@ func TestSignVerify(t *testing.T) {
|
||||
cases := []struct {
|
||||
key crypto.PubKey
|
||||
data []byte
|
||||
sig crypto.Signature
|
||||
sig []byte
|
||||
valid bool
|
||||
}{
|
||||
// proper matches
|
||||
|
||||
@ -16,7 +16,7 @@ type Keybase interface {
|
||||
Delete(name, passphrase string) error
|
||||
|
||||
// Sign some bytes, looking up the private key to use
|
||||
Sign(name, passphrase string, msg []byte) (crypto.Signature, crypto.PubKey, error)
|
||||
Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)
|
||||
|
||||
// CreateMnemonic creates a new mnemonic, and derives a hierarchical deterministic
|
||||
// key from that.
|
||||
|
||||
@ -114,7 +114,7 @@ func (pkl PrivKeyLedgerSecp256k1) Equals(other tmcrypto.PrivKey) bool {
|
||||
// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, returning
|
||||
// an error, so this should only trigger if the private key is held in memory
|
||||
// for a while before use.
|
||||
func (pkl PrivKeyLedgerSecp256k1) Sign(msg []byte) (tmcrypto.Signature, error) {
|
||||
func (pkl PrivKeyLedgerSecp256k1) Sign(msg []byte) ([]byte, error) {
|
||||
sig, err := pkl.signLedgerSecp256k1(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -135,13 +135,8 @@ func (pkl PrivKeyLedgerSecp256k1) getPubKey() (key tmcrypto.PubKey, err error) {
|
||||
return key, err
|
||||
}
|
||||
|
||||
func (pkl PrivKeyLedgerSecp256k1) signLedgerSecp256k1(msg []byte) (tmcrypto.Signature, error) {
|
||||
sigBytes, err := pkl.ledger.SignSECP256K1(pkl.Path, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tmsecp256k1.SignatureSecp256k1FromBytes(sigBytes), nil
|
||||
func (pkl PrivKeyLedgerSecp256k1) signLedgerSecp256k1(msg []byte) ([]byte, error) {
|
||||
return pkl.ledger.SignSECP256K1(pkl.Path, msg)
|
||||
}
|
||||
|
||||
func (pkl PrivKeyLedgerSecp256k1) pubkeyLedgerSecp256k1() (pub tmcrypto.PubKey, err error) {
|
||||
|
||||
@ -150,7 +150,7 @@ func NewCodec() *wire.Codec {
|
||||
```
|
||||
|
||||
Note: We also register the types in the `tendermint/tendermint/crypto` module so that `crypto.PubKey`
|
||||
and `crypto.Signature` are encoded/decoded correctly.
|
||||
is encoded/decoded correctly.
|
||||
|
||||
Amino supports encoding and decoding in both a binary and JSON format.
|
||||
See the [codec API docs](https://godoc.org/github.com/tendermint/go-amino#Codec) for more details.
|
||||
@ -166,7 +166,7 @@ type app2Tx struct {
|
||||
sdk.Msg
|
||||
|
||||
PubKey crypto.PubKey
|
||||
Signature crypto.Signature
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// This tx only has one Msg.
|
||||
|
||||
@ -160,7 +160,7 @@ The standard form for signatures is `StdSignature`:
|
||||
// the first transaction made by the account.
|
||||
type StdSignature struct {
|
||||
crypto.PubKey `json:"pub_key"` // optional
|
||||
crypto.Signature `json:"signature"`
|
||||
[]byte `json:"signature"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ type app2Tx struct {
|
||||
sdk.Msg
|
||||
|
||||
PubKey crypto.PubKey
|
||||
Signature crypto.Signature
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// This tx only has one Msg.
|
||||
@ -191,7 +191,7 @@ func (tx app2Tx) GetMsgs() []sdk.Msg {
|
||||
return []sdk.Msg{tx.Msg}
|
||||
}
|
||||
|
||||
func (tx app2Tx) GetSignature() crypto.Signature {
|
||||
func (tx app2Tx) GetSignature() []byte {
|
||||
return tx.Signature
|
||||
}
|
||||
|
||||
|
||||
@ -279,7 +279,7 @@ type TxInput struct {
|
||||
Address []byte `json:"address"` // Hash of the PubKey
|
||||
Coins Coins `json:"coins"` //
|
||||
Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput
|
||||
Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
|
||||
Signature []byte `json:"signature"` // Depends on the PubKey type and the whole Tx
|
||||
PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@ -101,7 +101,7 @@ func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
||||
proxy.NewLocalClientCreator(app),
|
||||
node.DefaultGenesisDocProviderFunc(cfg),
|
||||
node.DefaultDBProvider,
|
||||
node.DefaultMetricsProvider,
|
||||
node.DefaultMetricsProvider(cfg.Instrumentation),
|
||||
ctx.Logger.With("module", "node"),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@ -158,10 +158,10 @@ func (msg StdSignMsg) Bytes() []byte {
|
||||
|
||||
// Standard Signature
|
||||
type StdSignature struct {
|
||||
crypto.PubKey `json:"pub_key"` // optional
|
||||
crypto.Signature `json:"signature"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
crypto.PubKey `json:"pub_key"` // optional
|
||||
Signature []byte `json:"signature"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
}
|
||||
|
||||
// logic for standard transaction decoding
|
||||
|
||||
14
x/slashing/genesis.go
Normal file
14
x/slashing/genesis.go
Normal file
@ -0,0 +1,14 @@
|
||||
package slashing
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// InitGenesis initializes the keeper's address to pubkey map.
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
|
||||
for _, validator := range data.Validators {
|
||||
keeper.addPubkey(ctx, validator.GetPubKey())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -39,7 +39,7 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result {
|
||||
}
|
||||
|
||||
// Cannot be unrevoked until out of jail
|
||||
if ctx.BlockHeader().Time < info.JailedUntil {
|
||||
if ctx.BlockHeader().Time.Before(info.JailedUntil) {
|
||||
return ErrValidatorJailed(k.codespace).Result()
|
||||
}
|
||||
|
||||
|
||||
@ -2,10 +2,14 @@ package slashing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
@ -15,7 +19,6 @@ type Keeper struct {
|
||||
cdc *wire.Codec
|
||||
validatorSet sdk.ValidatorSet
|
||||
params params.Getter
|
||||
|
||||
// codespace
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
@ -33,10 +36,10 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, params pa
|
||||
}
|
||||
|
||||
// handle a validator signing two blocks at the same height
|
||||
func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, timestamp int64, power int64) {
|
||||
func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, timestamp time.Time, power int64) {
|
||||
logger := ctx.Logger().With("module", "x/slashing")
|
||||
time := ctx.BlockHeader().Time
|
||||
age := time - timestamp
|
||||
age := time.Sub(timestamp)
|
||||
address := sdk.ValAddress(pubkey.Address())
|
||||
|
||||
// Double sign too old
|
||||
@ -60,23 +63,26 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti
|
||||
if !found {
|
||||
panic(fmt.Sprintf("Expected signing info for validator %s but not found", address))
|
||||
}
|
||||
signInfo.JailedUntil = time + k.DoubleSignUnbondDuration(ctx)
|
||||
signInfo.JailedUntil = time.Add(k.DoubleSignUnbondDuration(ctx))
|
||||
k.setValidatorSigningInfo(ctx, address, signInfo)
|
||||
}
|
||||
|
||||
// handle a validator signature, must be called once per validator per block
|
||||
// nolint gocyclo
|
||||
func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, power int64, signed bool) {
|
||||
func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) {
|
||||
logger := ctx.Logger().With("module", "x/slashing")
|
||||
height := ctx.BlockHeight()
|
||||
address := sdk.ValAddress(pubkey.Address())
|
||||
|
||||
address := sdk.ValAddress(addr)
|
||||
pubkey, err := k.getPubkey(ctx, addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Validator address %v not found", addr))
|
||||
}
|
||||
// Local index, so counts blocks validator *should* have signed
|
||||
// Will use the 0-value default signing info if not present, except for start height
|
||||
signInfo, found := k.getValidatorSigningInfo(ctx, address)
|
||||
if !found {
|
||||
// If this validator has never been seen before, construct a new SigningInfo with the correct start height
|
||||
signInfo = NewValidatorSigningInfo(height, 0, 0, 0)
|
||||
signInfo = NewValidatorSigningInfo(height, 0, time.Unix(0, 0), 0)
|
||||
}
|
||||
index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx)
|
||||
signInfo.IndexOffset++
|
||||
@ -98,7 +104,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
|
||||
}
|
||||
|
||||
if !signed {
|
||||
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", addr, height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
}
|
||||
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
|
||||
if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) {
|
||||
@ -109,7 +115,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
|
||||
pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx)))
|
||||
k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx))
|
||||
k.validatorSet.Revoke(ctx, pubkey)
|
||||
signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx)
|
||||
signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeUnbondDuration(ctx))
|
||||
} else {
|
||||
// Validator was (a) not found or (b) already revoked, don't slash
|
||||
logger.Info(fmt.Sprintf("Validator %s would have been slashed for downtime, but was either not found in store or already revoked",
|
||||
@ -120,3 +126,46 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
|
||||
// Set the updated signing info
|
||||
k.setValidatorSigningInfo(ctx, address, signInfo)
|
||||
}
|
||||
|
||||
// AddValidators adds the validators to the keepers validator addr to pubkey mapping.
|
||||
func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.Validator) {
|
||||
for i := 0; i < len(vals); i++ {
|
||||
val := vals[i]
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
k.addPubkey(ctx, pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make a method to remove the pubkey from the map when a validator is unbonded.
|
||||
func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
addr := pubkey.Address()
|
||||
k.setAddrPubkeyRelation(ctx, addr, pubkey)
|
||||
}
|
||||
|
||||
func (k Keeper) getPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKey, error) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
var pubkey crypto.PubKey
|
||||
err := k.cdc.UnmarshalBinary(store.Get(getAddrPubkeyRelationKey(address)), &pubkey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("address %v not found", address)
|
||||
}
|
||||
return pubkey, nil
|
||||
}
|
||||
|
||||
func (k Keeper) setAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address, pubkey crypto.PubKey) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinary(pubkey)
|
||||
store.Set(getAddrPubkeyRelationKey(addr), bz)
|
||||
}
|
||||
|
||||
func (k Keeper) deleteAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(getAddrPubkeyRelationKey(addr))
|
||||
}
|
||||
|
||||
func getAddrPubkeyRelationKey(address []byte) []byte {
|
||||
return append([]byte{0x03}, address...)
|
||||
}
|
||||
|
||||
@ -2,13 +2,12 @@ package slashing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// Have to change these parameters for tests
|
||||
@ -29,15 +28,16 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||
|
||||
// handle a signature to set signing info
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, true)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
|
||||
|
||||
// double sign less than max age
|
||||
keeper.handleDoubleSign(ctx, val, 0, 0, amtInt)
|
||||
keeper.handleDoubleSign(ctx, val, 0, time.Unix(0, 0), amtInt)
|
||||
|
||||
// should be revoked
|
||||
require.True(t, sk.Validator(ctx, addr).GetRevoked())
|
||||
@ -45,10 +45,10 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||
sk.Unrevoke(ctx, val)
|
||||
// power should be reduced
|
||||
require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))})
|
||||
|
||||
// double sign past max age
|
||||
keeper.handleDoubleSign(ctx, val, 0, 0, amtInt)
|
||||
keeper.handleDoubleSign(ctx, val, 0, time.Unix(0, 0), amtInt)
|
||||
require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
|
||||
}
|
||||
|
||||
@ -64,7 +64,8 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
slh := NewHandler(keeper)
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
|
||||
@ -72,13 +73,15 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
require.Equal(t, int64(0), info.StartHeight)
|
||||
require.Equal(t, int64(0), info.IndexOffset)
|
||||
require.Equal(t, int64(0), info.SignedBlocksCounter)
|
||||
require.Equal(t, int64(0), info.JailedUntil)
|
||||
// default time.Time value
|
||||
var blankTime time.Time
|
||||
require.Equal(t, blankTime, info.JailedUntil)
|
||||
height := int64(0)
|
||||
|
||||
// 1000 first blocks OK
|
||||
for ; height < keeper.SignedBlocksWindow(ctx); height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, true)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
|
||||
}
|
||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
|
||||
require.True(t, found)
|
||||
@ -88,7 +91,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
// 500 blocks missed
|
||||
for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
|
||||
require.True(t, found)
|
||||
@ -103,7 +106,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
|
||||
// 501st block missed
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(0), info.StartHeight)
|
||||
@ -118,7 +121,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
require.False(t, got.IsOK())
|
||||
|
||||
// unrevocation should succeed after jail expiration
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: keeper.DowntimeUnbondDuration(ctx) + 1})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))})
|
||||
got = slh(ctx, NewMsgUnrevoke(addr))
|
||||
require.True(t, got.IsOK())
|
||||
|
||||
@ -140,7 +143,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
// validator should not be immediately revoked again
|
||||
height++
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
|
||||
@ -148,14 +151,14 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1
|
||||
for ; height < nextHeight; height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
|
||||
// validator should be revoked again after 500 unsigned blocks
|
||||
nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1
|
||||
for ; height <= nextHeight; height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||
@ -171,7 +174,8 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
sh := stake.NewHandler(sk)
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
|
||||
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
|
||||
|
||||
@ -179,16 +183,16 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1)
|
||||
|
||||
// Now a validator, for two blocks
|
||||
keeper.handleValidatorSignature(ctx, val, 100, true)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), 100, true)
|
||||
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2)
|
||||
keeper.handleValidatorSignature(ctx, val, 100, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), 100, false)
|
||||
|
||||
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight)
|
||||
require.Equal(t, int64(2), info.IndexOffset)
|
||||
require.Equal(t, int64(1), info.SignedBlocksCounter)
|
||||
require.Equal(t, int64(0), info.JailedUntil)
|
||||
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
||||
|
||||
// validator should be bonded still, should not have been revoked or slashed
|
||||
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||
@ -208,19 +212,20 @@ func TestHandleAlreadyRevoked(t *testing.T) {
|
||||
sh := stake.NewHandler(sk)
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
||||
// 1000 first blocks OK
|
||||
height := int64(0)
|
||||
for ; height < keeper.SignedBlocksWindow(ctx); height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, true)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
|
||||
}
|
||||
|
||||
// 501 blocks missed
|
||||
for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx))+1; height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
|
||||
// validator should have been revoked and slashed
|
||||
@ -232,7 +237,7 @@ func TestHandleAlreadyRevoked(t *testing.T) {
|
||||
|
||||
// another block missed
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val, amtInt, false)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
|
||||
// validator should not have been slashed twice
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package slashing
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -17,8 +19,8 @@ const (
|
||||
|
||||
// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks)
|
||||
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
|
||||
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) int64 {
|
||||
return k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)
|
||||
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) time.Duration {
|
||||
return time.Duration(k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)) * time.Second
|
||||
}
|
||||
|
||||
// SignedBlocksWindow - sliding window for downtime slashing
|
||||
@ -34,13 +36,13 @@ func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 {
|
||||
}
|
||||
|
||||
// Double-sign unbond duration
|
||||
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) int64 {
|
||||
return k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)
|
||||
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) time.Duration {
|
||||
return time.Duration(k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)) * time.Second
|
||||
}
|
||||
|
||||
// Downtime unbond duration
|
||||
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) int64 {
|
||||
return k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)
|
||||
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration {
|
||||
return time.Duration(k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)) * time.Second
|
||||
}
|
||||
|
||||
// SlashFractionDoubleSign - currently default 5%
|
||||
|
||||
@ -3,6 +3,7 @@ package slashing
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
@ -48,7 +49,7 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddr
|
||||
}
|
||||
|
||||
// Construct a new `ValidatorSigningInfo` struct
|
||||
func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil int64, signedBlocksCounter int64) ValidatorSigningInfo {
|
||||
func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil time.Time, signedBlocksCounter int64) ValidatorSigningInfo {
|
||||
return ValidatorSigningInfo{
|
||||
StartHeight: startHeight,
|
||||
IndexOffset: indexOffset,
|
||||
@ -59,15 +60,15 @@ func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil i
|
||||
|
||||
// Signing info for a validator
|
||||
type ValidatorSigningInfo struct {
|
||||
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked
|
||||
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
|
||||
JailedUntil int64 `json:"jailed_until"` // timestamp validator cannot be unrevoked until
|
||||
SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time)
|
||||
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked
|
||||
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
|
||||
JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unrevoked until
|
||||
SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time)
|
||||
}
|
||||
|
||||
// Return human readable signing info
|
||||
func (i ValidatorSigningInfo) HumanReadableString() string {
|
||||
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %d, signed blocks counter: %d",
|
||||
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, signed blocks counter: %d",
|
||||
i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter)
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package slashing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -15,7 +16,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
|
||||
newInfo := ValidatorSigningInfo{
|
||||
StartHeight: int64(4),
|
||||
IndexOffset: int64(3),
|
||||
JailedUntil: int64(2),
|
||||
JailedUntil: time.Unix(2, 0),
|
||||
SignedBlocksCounter: int64(10),
|
||||
}
|
||||
keeper.setValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]), newInfo)
|
||||
@ -23,7 +24,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
|
||||
require.True(t, found)
|
||||
require.Equal(t, info.StartHeight, int64(4))
|
||||
require.Equal(t, info.IndexOffset, int64(3))
|
||||
require.Equal(t, info.JailedUntil, int64(2))
|
||||
require.Equal(t, info.JailedUntil, time.Unix(2, 0).UTC())
|
||||
require.Equal(t, info.SignedBlocksCounter, int64(10))
|
||||
}
|
||||
|
||||
|
||||
@ -20,13 +20,9 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags
|
||||
// Iterate over all the validators which *should* have signed this block
|
||||
// Store whether or not they have actually signed it and slash/unbond any
|
||||
// which have missed too many blocks in a row (downtime slashing)
|
||||
for _, signingValidator := range req.Validators {
|
||||
for _, signingValidator := range req.LastCommitInfo.GetValidators() {
|
||||
present := signingValidator.SignedLastBlock
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(signingValidator.Validator.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sk.handleValidatorSignature(ctx, pubkey, signingValidator.Validator.Power, present)
|
||||
sk.handleValidatorSignature(ctx, signingValidator.Validator.Address, signingValidator.Validator.Power, present)
|
||||
}
|
||||
|
||||
// Iterate through any newly discovered evidence of infraction
|
||||
|
||||
@ -2,11 +2,11 @@ package slashing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
@ -19,21 +19,24 @@ func TestBeginBlocker(t *testing.T) {
|
||||
// bond the validator
|
||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt))
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||
|
||||
val := abci.Validator{
|
||||
PubKey: tmtypes.TM2PB.PubKey(pk),
|
||||
Power: amt.Int64(),
|
||||
Address: pk.Address(),
|
||||
Power: amt.Int64(),
|
||||
}
|
||||
|
||||
// mark the validator as having signed
|
||||
req := abci.RequestBeginBlock{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: true,
|
||||
}},
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: true,
|
||||
}},
|
||||
},
|
||||
}
|
||||
BeginBlocker(ctx, req, keeper)
|
||||
|
||||
@ -41,7 +44,7 @@ func TestBeginBlocker(t *testing.T) {
|
||||
require.True(t, found)
|
||||
require.Equal(t, ctx.BlockHeight(), info.StartHeight)
|
||||
require.Equal(t, int64(1), info.IndexOffset)
|
||||
require.Equal(t, int64(0), info.JailedUntil)
|
||||
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
||||
require.Equal(t, int64(1), info.SignedBlocksCounter)
|
||||
|
||||
height := int64(0)
|
||||
@ -50,10 +53,12 @@ func TestBeginBlocker(t *testing.T) {
|
||||
for ; height < keeper.SignedBlocksWindow(ctx); height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
req = abci.RequestBeginBlock{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: true,
|
||||
}},
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: true,
|
||||
}},
|
||||
},
|
||||
}
|
||||
BeginBlocker(ctx, req, keeper)
|
||||
}
|
||||
@ -62,10 +67,12 @@ func TestBeginBlocker(t *testing.T) {
|
||||
for ; height < ((keeper.SignedBlocksWindow(ctx) * 2) - keeper.MinSignedPerWindow(ctx) + 1); height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
req = abci.RequestBeginBlock{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: false,
|
||||
}},
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Validators: []abci.SigningValidator{{
|
||||
Validator: val,
|
||||
SignedLastBlock: false,
|
||||
}},
|
||||
},
|
||||
}
|
||||
BeginBlocker(ctx, req, keeper)
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package stake
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/tags"
|
||||
@ -38,7 +40,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid
|
||||
|
||||
// Process provision inflation
|
||||
blockTime := ctx.BlockHeader().Time
|
||||
if blockTime-pool.InflationLastTime >= 3600 {
|
||||
if blockTime.Sub(pool.InflationLastTime) >= time.Hour {
|
||||
params := k.GetParams(ctx)
|
||||
pool.InflationLastTime = blockTime
|
||||
pool = pool.ProcessProvisions(params)
|
||||
|
||||
@ -2,6 +2,7 @@ package stake
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -500,7 +501,7 @@ func TestUnbondingPeriod(t *testing.T) {
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 7
|
||||
params.UnbondingTime = 7 * time.Second
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validator
|
||||
@ -516,19 +517,19 @@ func TestUnbondingPeriod(t *testing.T) {
|
||||
// cannot complete unbonding at same time
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, !got.IsOK(), "expected no error")
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
|
||||
// cannot complete unbonding at time 6 seconds later
|
||||
origHeader := ctx.BlockHeader()
|
||||
headerTime6 := origHeader
|
||||
headerTime6.Time += 6
|
||||
headerTime6.Time = headerTime6.Time.Add(time.Second * 6)
|
||||
ctx = ctx.WithBlockHeader(headerTime6)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, !got.IsOK(), "expected no error")
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
|
||||
// can complete unbonding at time 7 seconds later
|
||||
headerTime7 := origHeader
|
||||
headerTime7.Time += 7
|
||||
headerTime7.Time = headerTime7.Time.Add(time.Second * 7)
|
||||
ctx = ctx.WithBlockHeader(headerTime7)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
@ -541,7 +542,7 @@ func TestRedelegationPeriod(t *testing.T) {
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 7
|
||||
params.UnbondingTime = 7 * time.Second
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validators
|
||||
@ -580,14 +581,14 @@ func TestRedelegationPeriod(t *testing.T) {
|
||||
// cannot complete redelegation at time 6 seconds later
|
||||
origHeader := ctx.BlockHeader()
|
||||
headerTime6 := origHeader
|
||||
headerTime6.Time += 6
|
||||
headerTime6.Time = headerTime6.Time.Add(time.Second * 6)
|
||||
ctx = ctx.WithBlockHeader(headerTime6)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
|
||||
// can complete redelegation at time 7 seconds later
|
||||
headerTime7 := origHeader
|
||||
headerTime7.Time += 7
|
||||
headerTime7.Time = headerTime7.Time.Add(time.Second * 7)
|
||||
ctx = ctx.WithBlockHeader(headerTime7)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
@ -327,7 +327,7 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk
|
||||
|
||||
// create the unbonding delegation
|
||||
params := k.GetParams(ctx)
|
||||
minTime := ctx.BlockHeader().Time + params.UnbondingTime
|
||||
minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()}
|
||||
|
||||
ubd := types.UnbondingDelegation{
|
||||
@ -351,7 +351,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr
|
||||
|
||||
// ensure that enough time has passed
|
||||
ctxTime := ctx.BlockHeader().Time
|
||||
if ubd.MinTime > ctxTime {
|
||||
if ubd.MinTime.After(ctxTime) {
|
||||
return types.ErrNotMature(k.Codespace(), "unbonding", "unit-time", ubd.MinTime, ctxTime)
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd
|
||||
}
|
||||
|
||||
// create the unbonding delegation
|
||||
minTime := ctx.BlockHeader().Time + params.UnbondingTime
|
||||
minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
|
||||
red := types.Redelegation{
|
||||
DelegatorAddr: delegatorAddr,
|
||||
@ -415,7 +415,7 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delegatorAddr, validatorSr
|
||||
|
||||
// ensure that enough time has passed
|
||||
ctxTime := ctx.BlockHeader().Time
|
||||
if red.MinTime > ctxTime {
|
||||
if red.MinTime.After(ctxTime) {
|
||||
return types.ErrNotMature(k.Codespace(), "redelegation", "unit-time", red.MinTime, ctxTime)
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
@ -115,7 +116,7 @@ func TestUnbondingDelegation(t *testing.T) {
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
CreationHeight: 0,
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
Balance: sdk.NewInt64Coin("steak", 5),
|
||||
}
|
||||
|
||||
@ -188,7 +189,7 @@ func TestGetRedelegationsFromValidator(t *testing.T) {
|
||||
ValidatorSrcAddr: addrVals[0],
|
||||
ValidatorDstAddr: addrVals[1],
|
||||
CreationHeight: 0,
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
SharesSrc: sdk.NewRat(5),
|
||||
SharesDst: sdk.NewRat(5),
|
||||
}
|
||||
@ -218,7 +219,7 @@ func TestRedelegation(t *testing.T) {
|
||||
ValidatorSrcAddr: addrVals[0],
|
||||
ValidatorDstAddr: addrVals[1],
|
||||
CreationHeight: 0,
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
SharesSrc: sdk.NewRat(5),
|
||||
SharesDst: sdk.NewRat(5),
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
|
||||
return sdk.ZeroRat()
|
||||
}
|
||||
|
||||
if unbondingDelegation.MinTime < now {
|
||||
if unbondingDelegation.MinTime.Before(now) {
|
||||
// Unbonding delegation no longer eligible for slashing, skip it
|
||||
// TODO Settle and delete it automatically?
|
||||
return sdk.ZeroRat()
|
||||
@ -203,7 +203,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re
|
||||
return sdk.ZeroRat()
|
||||
}
|
||||
|
||||
if redelegation.MinTime < now {
|
||||
if redelegation.MinTime.Before(now) {
|
||||
// Redelegation no longer eligible for slashing, skip it
|
||||
// TODO Delete it automatically?
|
||||
return sdk.ZeroRat()
|
||||
|
||||
@ -2,6 +2,7 @@ package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -70,7 +71,7 @@ func TestSlashUnbondingDelegation(t *testing.T) {
|
||||
ValidatorAddr: addrVals[0],
|
||||
CreationHeight: 0,
|
||||
// expiration timestamp (beyond which the unbonding delegation shouldn't be slashed)
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10),
|
||||
Balance: sdk.NewInt64Coin(params.BondDenom, 10),
|
||||
}
|
||||
@ -81,14 +82,14 @@ func TestSlashUnbondingDelegation(t *testing.T) {
|
||||
require.Equal(t, int64(0), slashAmount.RoundInt64())
|
||||
|
||||
// after the expiration time, no longer eligible for slashing
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)})
|
||||
keeper.SetUnbondingDelegation(ctx, ubd)
|
||||
slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction)
|
||||
require.Equal(t, int64(0), slashAmount.RoundInt64())
|
||||
|
||||
// test valid slash, before expiration timestamp and to which stake contributed
|
||||
oldPool := keeper.GetPool(ctx)
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)})
|
||||
keeper.SetUnbondingDelegation(ctx, ubd)
|
||||
slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction)
|
||||
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
||||
@ -114,7 +115,7 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
ValidatorDstAddr: addrVals[1],
|
||||
CreationHeight: 0,
|
||||
// expiration timestamp (beyond which the redelegation shouldn't be slashed)
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
SharesSrc: sdk.NewRat(10),
|
||||
SharesDst: sdk.NewRat(10),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10),
|
||||
@ -137,7 +138,7 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
require.Equal(t, int64(0), slashAmount.RoundInt64())
|
||||
|
||||
// after the expiration time, no longer eligible for slashing
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)})
|
||||
keeper.SetRedelegation(ctx, rd)
|
||||
validator, found = keeper.GetValidator(ctx, addrVals[1])
|
||||
require.True(t, found)
|
||||
@ -146,7 +147,7 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
|
||||
// test valid slash, before expiration timestamp and to which stake contributed
|
||||
oldPool := keeper.GetPool(ctx)
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)})
|
||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)})
|
||||
keeper.SetRedelegation(ctx, rd)
|
||||
validator, found = keeper.GetValidator(ctx, addrVals[1])
|
||||
require.True(t, found)
|
||||
@ -209,7 +210,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
|
||||
ValidatorAddr: addrVals[0],
|
||||
CreationHeight: 11,
|
||||
// expiration timestamp (beyond which the unbonding delegation shouldn't be slashed)
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4),
|
||||
Balance: sdk.NewInt64Coin(params.BondDenom, 4),
|
||||
}
|
||||
@ -310,7 +311,7 @@ func TestSlashWithRedelegation(t *testing.T) {
|
||||
ValidatorSrcAddr: addrVals[0],
|
||||
ValidatorDstAddr: addrVals[1],
|
||||
CreationHeight: 11,
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
SharesSrc: sdk.NewRat(6),
|
||||
SharesDst: sdk.NewRat(6),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6),
|
||||
@ -432,7 +433,7 @@ func TestSlashBoth(t *testing.T) {
|
||||
ValidatorDstAddr: addrVals[1],
|
||||
CreationHeight: 11,
|
||||
// expiration timestamp (beyond which the redelegation shouldn't be slashed)
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
SharesSrc: sdk.NewRat(6),
|
||||
SharesDst: sdk.NewRat(6),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6),
|
||||
@ -454,7 +455,7 @@ func TestSlashBoth(t *testing.T) {
|
||||
ValidatorAddr: addrVals[0],
|
||||
CreationHeight: 11,
|
||||
// expiration timestamp (beyond which the unbonding delegation shouldn't be slashed)
|
||||
MinTime: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4),
|
||||
Balance: sdk.NewInt64Coin(params.BondDenom, 4),
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
@ -100,14 +101,14 @@ type UnbondingDelegation struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator
|
||||
ValidatorAddr sdk.AccAddress `json:"validator_addr"` // validator unbonding from owner addr
|
||||
CreationHeight int64 `json:"creation_height"` // height which the unbonding took place
|
||||
MinTime int64 `json:"min_time"` // unix time for unbonding completion
|
||||
MinTime time.Time `json:"min_time"` // unix time for unbonding completion
|
||||
InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion
|
||||
Balance sdk.Coin `json:"balance"` // atoms to receive at completion
|
||||
}
|
||||
|
||||
type ubdValue struct {
|
||||
CreationHeight int64
|
||||
MinTime int64
|
||||
MinTime time.Time
|
||||
InitialBalance sdk.Coin
|
||||
Balance sdk.Coin
|
||||
}
|
||||
@ -186,7 +187,7 @@ type Redelegation struct {
|
||||
ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` // validator redelegation source owner addr
|
||||
ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` // validator redelegation destination owner addr
|
||||
CreationHeight int64 `json:"creation_height"` // height which the redelegation took place
|
||||
MinTime int64 `json:"min_time"` // unix time for redelegation completion
|
||||
MinTime time.Time `json:"min_time"` // unix time for redelegation completion
|
||||
InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started
|
||||
Balance sdk.Coin `json:"balance"` // current balance
|
||||
SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating
|
||||
@ -195,7 +196,7 @@ type Redelegation struct {
|
||||
|
||||
type redValue struct {
|
||||
CreationHeight int64
|
||||
MinTime int64
|
||||
MinTime time.Time
|
||||
InitialBalance sdk.Coin
|
||||
Balance sdk.Coin
|
||||
SharesSrc sdk.Rat
|
||||
|
||||
@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -57,7 +58,7 @@ func TestUnbondingDelegationEqual(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
ud2.ValidatorAddr = addr3
|
||||
ud2.MinTime = 20 * 20 * 2
|
||||
ud2.MinTime = time.Unix(20*20*2, 0)
|
||||
|
||||
ok = ud1.Equal(ud2)
|
||||
require.False(t, ok)
|
||||
@ -93,7 +94,7 @@ func TestRedelegationEqual(t *testing.T) {
|
||||
|
||||
r2.SharesDst = sdk.NewRat(10)
|
||||
r2.SharesSrc = sdk.NewRat(20)
|
||||
r2.MinTime = 20 * 20 * 2
|
||||
r2.MinTime = time.Unix(20*20*2, 0)
|
||||
|
||||
ok = r1.Equal(r2)
|
||||
require.False(t, ok)
|
||||
|
||||
@ -3,6 +3,7 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
@ -110,7 +111,7 @@ func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1")
|
||||
}
|
||||
|
||||
func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error {
|
||||
func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error {
|
||||
msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v",
|
||||
operation, descriptor, got, min)
|
||||
return sdk.NewError(codespace, CodeUnauthorized, msg)
|
||||
|
||||
@ -2,13 +2,14 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// defaultUnbondingTime reflects three weeks in seconds as the default
|
||||
// unbonding time.
|
||||
const defaultUnbondingTime int64 = 60 * 60 * 24 * 3
|
||||
const defaultUnbondingTime time.Duration = 60 * 60 * 24 * 3 * time.Second
|
||||
|
||||
// Params defines the high level settings for staking
|
||||
type Params struct {
|
||||
@ -17,7 +18,7 @@ type Params struct {
|
||||
InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate
|
||||
GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms
|
||||
|
||||
UnbondingTime int64 `json:"unbonding_time"`
|
||||
UnbondingTime time.Duration `json:"unbonding_time"`
|
||||
|
||||
MaxValidators uint16 `json:"max_validators"` // maximum number of validators
|
||||
BondDenom string `json:"bond_denom"` // bondable coin denomination
|
||||
|
||||
@ -3,16 +3,17 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Pool - dynamic parameters of the current state
|
||||
type Pool struct {
|
||||
LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator
|
||||
BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens
|
||||
InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time
|
||||
Inflation sdk.Rat `json:"inflation"` // current annual inflation rate
|
||||
LooseTokens sdk.Rat `json:"loose_tokens"` // tokens which are not bonded in a validator
|
||||
BondedTokens sdk.Rat `json:"bonded_tokens"` // reserve of bonded tokens
|
||||
InflationLastTime time.Time `json:"inflation_last_time"` // block which the last inflation was processed
|
||||
Inflation sdk.Rat `json:"inflation"` // current annual inflation rate
|
||||
|
||||
DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily)
|
||||
|
||||
@ -32,7 +33,7 @@ func InitialPool() Pool {
|
||||
return Pool{
|
||||
LooseTokens: sdk.ZeroRat(),
|
||||
BondedTokens: sdk.ZeroRat(),
|
||||
InflationLastTime: 0,
|
||||
InflationLastTime: time.Unix(0, 0),
|
||||
Inflation: sdk.NewRat(7, 100),
|
||||
DateLastCommissionReset: 0,
|
||||
PrevBondedShares: sdk.ZeroRat(),
|
||||
|
||||
@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -184,7 +185,7 @@ func TestRemoveDelShares(t *testing.T) {
|
||||
pool := Pool{
|
||||
BondedTokens: sdk.NewRat(248305),
|
||||
LooseTokens: sdk.NewRat(232147),
|
||||
InflationLastTime: 0,
|
||||
InflationLastTime: time.Unix(0, 0),
|
||||
Inflation: sdk.NewRat(7, 100),
|
||||
}
|
||||
shares := sdk.NewRat(29)
|
||||
@ -232,7 +233,7 @@ func TestPossibleOverflow(t *testing.T) {
|
||||
pool := Pool{
|
||||
LooseTokens: sdk.NewRat(100),
|
||||
BondedTokens: poolTokens,
|
||||
InflationLastTime: 0,
|
||||
InflationLastTime: time.Unix(0, 0),
|
||||
Inflation: sdk.NewRat(7, 100),
|
||||
}
|
||||
tokens := int64(71)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user