mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
commit
4253e67c07
1
.gitignore
vendored
1
.gitignore
vendored
@ -35,6 +35,7 @@ shunit2
|
|||||||
addrbook.json
|
addrbook.json
|
||||||
|
|
||||||
*/vendor
|
*/vendor
|
||||||
|
.vendor-new/
|
||||||
*/.glide
|
*/.glide
|
||||||
.terraform
|
.terraform
|
||||||
terraform.tfstate
|
terraform.tfstate
|
||||||
|
32
CHANGELOG.md
32
CHANGELOG.md
@ -1,5 +1,28 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.31.5
|
||||||
|
|
||||||
|
*April 16th, 2019*
|
||||||
|
|
||||||
|
This release fixes a regression from v0.31.4 where, in existing chains that
|
||||||
|
were upgraded, `/validators` could return an empty validator set. This is true
|
||||||
|
for almost all heights, given the validator set remains the same.
|
||||||
|
|
||||||
|
Special thanks to external contributors on this release:
|
||||||
|
@brapse, @guagualvcha, @dongsam, @phucc
|
||||||
|
|
||||||
|
### IMPROVEMENTS:
|
||||||
|
|
||||||
|
- [libs/common] `CMap`: slight optimization in `Keys()` and `Values()` (@phucc)
|
||||||
|
- [gitignore] gitignore: add .vendor-new (@dongsam)
|
||||||
|
|
||||||
|
### BUG FIXES:
|
||||||
|
|
||||||
|
- [state] [\#3537](https://github.com/tendermint/tendermint/pull/3537#issuecomment-482711833)
|
||||||
|
`LoadValidators`: do not return an empty validator set
|
||||||
|
- [blockchain] [\#3457](https://github.com/tendermint/tendermint/issues/3457)
|
||||||
|
Fix "peer did not send us anything" in `fast_sync` mode when under high pressure
|
||||||
|
|
||||||
## v0.31.4
|
## v0.31.4
|
||||||
|
|
||||||
*April 12th, 2019*
|
*April 12th, 2019*
|
||||||
@ -9,13 +32,14 @@ the address book. This swallowed the peer's self-reported port which is importan
|
|||||||
It brings back `NetAddress()` to `NodeInfo` and uses it instead of `SocketAddr` for adding peers.
|
It brings back `NetAddress()` to `NodeInfo` and uses it instead of `SocketAddr` for adding peers.
|
||||||
Additionally, it improves response time on the `/validators` or `/status` RPC endpoints.
|
Additionally, it improves response time on the `/validators` or `/status` RPC endpoints.
|
||||||
As a side-effect it makes these RPC endpoint more difficult to DoS and fixes a performance degradation in `ExecCommitBlock`.
|
As a side-effect it makes these RPC endpoint more difficult to DoS and fixes a performance degradation in `ExecCommitBlock`.
|
||||||
Also, it contains an [ADR](https://github.com/tendermint/tendermint/pull/3539) that proposes decoupling the
|
Also, it contains an [ADR](https://github.com/tendermint/tendermint/pull/3539) that proposes decoupling the
|
||||||
responsibility for peer behaviour from the `p2p.Switch` (by @brapse).
|
responsibility for peer behaviour from the `p2p.Switch` (by @brapse).
|
||||||
|
|
||||||
Special thanks to external contributors on this release:
|
Special thanks to external contributors on this release:
|
||||||
@brapse, @guagualvcha, @mydring
|
@brapse, @guagualvcha, @mydring
|
||||||
|
|
||||||
### IMPROVEMENTS:
|
### IMPROVEMENTS:
|
||||||
|
|
||||||
- [p2p] [\#3463](https://github.com/tendermint/tendermint/pull/3463) Do not log "Can't add peer's address to addrbook" error for a private peer
|
- [p2p] [\#3463](https://github.com/tendermint/tendermint/pull/3463) Do not log "Can't add peer's address to addrbook" error for a private peer
|
||||||
- [p2p] [\#3547](https://github.com/tendermint/tendermint/pull/3547) Fix a couple of annoying typos (@mdyring)
|
- [p2p] [\#3547](https://github.com/tendermint/tendermint/pull/3547) Fix a couple of annoying typos (@mdyring)
|
||||||
|
|
||||||
@ -43,8 +67,8 @@ panic if the lookup failed.
|
|||||||
|
|
||||||
### BREAKING CHANGES:
|
### BREAKING CHANGES:
|
||||||
* Go API
|
* Go API
|
||||||
- [crypto/secp256k1] [\#3439](https://github.com/tendermint/tendermint/issues/3439)
|
- [crypto/secp256k1] [\#3439](https://github.com/tendermint/tendermint/issues/3439)
|
||||||
The `secp256k1.GenPrivKeySecp256k1` function has changed to guarantee that it returns a valid key, which means it
|
The `secp256k1.GenPrivKeySecp256k1` function has changed to guarantee that it returns a valid key, which means it
|
||||||
will return a different private key than in previous versions for the same secret.
|
will return a different private key than in previous versions for the same secret.
|
||||||
|
|
||||||
### BUG FIXES:
|
### BUG FIXES:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
## v0.31.5
|
## v0.31.6
|
||||||
|
|
||||||
**
|
**
|
||||||
|
|
||||||
|
@ -228,32 +228,40 @@ func (bcR *BlockchainReactor) poolRoutine() {
|
|||||||
|
|
||||||
didProcessCh := make(chan struct{}, 1)
|
didProcessCh := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-bcR.Quit():
|
||||||
|
return
|
||||||
|
case <-bcR.pool.Quit():
|
||||||
|
return
|
||||||
|
case request := <-bcR.requestsCh:
|
||||||
|
peer := bcR.Switch.Peers().Get(request.PeerID)
|
||||||
|
if peer == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockRequestMessage{request.Height})
|
||||||
|
queued := peer.TrySend(BlockchainChannel, msgBytes)
|
||||||
|
if !queued {
|
||||||
|
bcR.Logger.Debug("Send queue is full, drop block request", "peer", peer.ID(), "height", request.Height)
|
||||||
|
}
|
||||||
|
case err := <-bcR.errorsCh:
|
||||||
|
peer := bcR.Switch.Peers().Get(err.peerID)
|
||||||
|
if peer != nil {
|
||||||
|
bcR.Switch.StopPeerForError(peer, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-statusUpdateTicker.C:
|
||||||
|
// ask for status updates
|
||||||
|
go bcR.BroadcastStatusRequest() // nolint: errcheck
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
FOR_LOOP:
|
FOR_LOOP:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case request := <-bcR.requestsCh:
|
|
||||||
peer := bcR.Switch.Peers().Get(request.PeerID)
|
|
||||||
if peer == nil {
|
|
||||||
continue FOR_LOOP // Peer has since been disconnected.
|
|
||||||
}
|
|
||||||
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockRequestMessage{request.Height})
|
|
||||||
queued := peer.TrySend(BlockchainChannel, msgBytes)
|
|
||||||
if !queued {
|
|
||||||
// We couldn't make the request, send-queue full.
|
|
||||||
// The pool handles timeouts, just let it go.
|
|
||||||
continue FOR_LOOP
|
|
||||||
}
|
|
||||||
|
|
||||||
case err := <-bcR.errorsCh:
|
|
||||||
peer := bcR.Switch.Peers().Get(err.peerID)
|
|
||||||
if peer != nil {
|
|
||||||
bcR.Switch.StopPeerForError(peer, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case <-statusUpdateTicker.C:
|
|
||||||
// ask for status updates
|
|
||||||
go bcR.BroadcastStatusRequest() // nolint: errcheck
|
|
||||||
|
|
||||||
case <-switchToConsensusTicker.C:
|
case <-switchToConsensusTicker.C:
|
||||||
height, numPending, lenRequesters := bcR.pool.GetStatus()
|
height, numPending, lenRequesters := bcR.pool.GetStatus()
|
||||||
outbound, inbound, _ := bcR.Switch.NumPeers()
|
outbound, inbound, _ := bcR.Switch.NumPeers()
|
||||||
@ -262,7 +270,6 @@ FOR_LOOP:
|
|||||||
if bcR.pool.IsCaughtUp() {
|
if bcR.pool.IsCaughtUp() {
|
||||||
bcR.Logger.Info("Time to switch to consensus reactor!", "height", height)
|
bcR.Logger.Info("Time to switch to consensus reactor!", "height", height)
|
||||||
bcR.pool.Stop()
|
bcR.pool.Stop()
|
||||||
|
|
||||||
conR, ok := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
|
conR, ok := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
|
||||||
if ok {
|
if ok {
|
||||||
conR.SwitchToConsensus(state, blocksSynced)
|
conR.SwitchToConsensus(state, blocksSynced)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
# ADR 037: Peer Behaviour Interface
|
# ADR 039: Peer Behaviour Interface
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
* 07-03-2019: Initial draft
|
* 07-03-2019: Initial draft
|
||||||
|
* 14-03-2019: Updates from feedback
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
@ -19,36 +20,46 @@ and ties up the reactors in a larger dependency graph when testing.
|
|||||||
|
|
||||||
Introduce a `PeerBehaviour` interface and concrete implementations which
|
Introduce a `PeerBehaviour` interface and concrete implementations which
|
||||||
provide methods for reactors to signal peer behaviour without direct
|
provide methods for reactors to signal peer behaviour without direct
|
||||||
coupling `p2p.Switch`. Introduce a ErrPeer to provide
|
coupling `p2p.Switch`. Introduce a ErrorBehaviourPeer to provide
|
||||||
concrete reasons for stopping peers.
|
concrete reasons for stopping peers. Introduce GoodBehaviourPeer to provide
|
||||||
|
concrete ways in which a peer contributes.
|
||||||
|
|
||||||
### Implementation Changes
|
### Implementation Changes
|
||||||
|
|
||||||
PeerBehaviour then becomes an interface for signaling peer errors as well
|
PeerBehaviour then becomes an interface for signaling peer errors as well
|
||||||
as for marking peers as `good`.
|
as for marking peers as `good`.
|
||||||
|
|
||||||
XXX: It might be better to pass p2p.ID instead of the whole peer but as
|
|
||||||
a first draft maintain the underlying implementation as much as
|
|
||||||
possible.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type PeerBehaviour interface {
|
type PeerBehaviour interface {
|
||||||
Errored(peer Peer, reason ErrPeer)
|
Behaved(peer Peer, reason GoodBehaviourPeer)
|
||||||
MarkPeerAsGood(peer Peer)
|
Errored(peer Peer, reason ErrorBehaviourPeer)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Instead of signaling peers to stop with arbitrary reasons:
|
Instead of signaling peers to stop with arbitrary reasons:
|
||||||
`reason interface{}`
|
`reason interface{}`
|
||||||
|
|
||||||
We introduce a concrete error type ErrPeer:
|
We introduce a concrete error type ErrorBehaviourPeer:
|
||||||
```go
|
```go
|
||||||
type ErrPeer int
|
type ErrorBehaviourPeer int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ErrPeerUnknown = iota
|
ErrorBehaviourUnknown = iota
|
||||||
ErrPeerBadMessage
|
ErrorBehaviourBadMessage
|
||||||
ErrPeerMessageOutofOrder
|
ErrorBehaviourMessageOutofOrder
|
||||||
|
...
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
To provide additional information on the ways a peer contributed, we introduce
|
||||||
|
the GoodBehaviourPeer type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type GoodBehaviourPeer int
|
||||||
|
|
||||||
|
const (
|
||||||
|
GoodBehaviourVote = iota
|
||||||
|
GoodBehaviourBlockPart
|
||||||
...
|
...
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@ -60,11 +71,11 @@ type SwitchedPeerBehaviour struct {
|
|||||||
sw *Switch
|
sw *Switch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spb *SwitchedPeerBehaviour) Errored(peer Peer, reason ErrPeer) {
|
func (spb *SwitchedPeerBehaviour) Errored(peer Peer, reason ErrorBehaviourPeer) {
|
||||||
spb.sw.StopPeerForError(peer, reason)
|
spb.sw.StopPeerForError(peer, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spb *SwitchedPeerBehaviour) MarkPeerAsGood(peer Peer) {
|
func (spb *SwitchedPeerBehaviour) Behaved(peer Peer, reason GoodBehaviourPeer) {
|
||||||
spb.sw.MarkPeerAsGood(peer)
|
spb.sw.MarkPeerAsGood(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,51 +86,54 @@ func NewSwitchedPeerBehaviour(sw *Switch) *SwitchedPeerBehaviour {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Reactors, which are often difficult to unit test[<sup>2</sup>](#references). could use an implementation which exposes the signals produced by the reactor in
|
Reactors, which are often difficult to unit test[<sup>2</sup>](#references) could use an implementation which exposes the signals produced by the reactor in
|
||||||
manufactured scenarios:
|
manufactured scenarios:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type PeerErrors map[Peer][]ErrPeer
|
type ErrorBehaviours map[Peer][]ErrorBehaviourPeer
|
||||||
type GoodPeers map[Peer]bool
|
type GoodBehaviours map[Peer][]GoodBehaviourPeer
|
||||||
|
|
||||||
type StorePeerBehaviour struct {
|
type StorePeerBehaviour struct {
|
||||||
pe PeerErrors
|
eb ErrorBehaviours
|
||||||
gp GoodPeers
|
gb GoodBehaviours
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorePeerBehaviour() *StorePeerBehaviour{
|
func NewStorePeerBehaviour() *StorePeerBehaviour{
|
||||||
return &StorePeerBehaviour{
|
return &StorePeerBehaviour{
|
||||||
pe: make(PeerErrors),
|
eb: make(ErrorBehaviours),
|
||||||
gp: GoodPeers{},
|
gb: make(GoodBehaviours),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spb StorePeerBehaviour) Errored(peer Peer, reason ErrPeer) {
|
func (spb StorePeerBehaviour) Errored(peer Peer, reason ErrorBehaviourPeer) {
|
||||||
if _, ok := spb.pe[peer]; !ok {
|
if _, ok := spb.eb[peer]; !ok {
|
||||||
spb.pe[peer] = []ErrPeer{reason}
|
spb.eb[peer] = []ErrorBehaviours{reason}
|
||||||
} else {
|
} else {
|
||||||
spb.pe[peer] = append(spb.pe[peer], reason)
|
spb.eb[peer] = append(spb.eb[peer], reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mpb *StorePeerBehaviour) GetPeerErrors() PeerErrors {
|
func (mpb *StorePeerBehaviour) GetErrored() ErrorBehaviours {
|
||||||
return mpb.pe
|
return mpb.eb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spb *StorePeerBehaviour) MarkPeerAsGood(peer Peer) {
|
|
||||||
if _, ok := spb.gp[peer]; !ok {
|
func (spb StorePeerBehaviour) Behaved(peer Peer, reason GoodBehaviourPeer) {
|
||||||
spb.gp[peer] = true
|
if _, ok := spb.gb[peer]; !ok {
|
||||||
|
spb.gb[peer] = []GoodBehaviourPeer{reason}
|
||||||
|
} else {
|
||||||
|
spb.gb[peer] = append(spb.gb[peer], reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spb *StorePeerBehaviour) GetGoodPeers() GoodPeers {
|
func (spb *StorePeerBehaviour) GetBehaved() GoodBehaviours {
|
||||||
return spb.gp
|
return spb.gb
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Proposed
|
Accepted
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
@ -56,7 +56,7 @@ func (cm *CMap) Clear() {
|
|||||||
func (cm *CMap) Keys() []string {
|
func (cm *CMap) Keys() []string {
|
||||||
cm.l.Lock()
|
cm.l.Lock()
|
||||||
|
|
||||||
keys := []string{}
|
keys := make([]string, 0, len(cm.m))
|
||||||
for k := range cm.m {
|
for k := range cm.m {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ func (cm *CMap) Keys() []string {
|
|||||||
|
|
||||||
func (cm *CMap) Values() []interface{} {
|
func (cm *CMap) Values() []interface{} {
|
||||||
cm.l.Lock()
|
cm.l.Lock()
|
||||||
items := []interface{}{}
|
items := make([]interface{}, 0, len(cm.m))
|
||||||
for _, v := range cm.m {
|
for _, v := range cm.m {
|
||||||
items = append(items, v)
|
items = append(items, v)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
// make govet noshadow happy...
|
// make govet noshadow happy...
|
||||||
|
|
||||||
asrt "github.com/stretchr/testify/assert"
|
asrt "github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import "sync"
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type atomicSetDeleter interface {
|
type atomicSetDeleter interface {
|
||||||
Mutex() *sync.Mutex
|
Mutex() *sync.Mutex
|
||||||
|
@ -193,7 +193,7 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
|
|||||||
if valInfo.ValidatorSet == nil {
|
if valInfo.ValidatorSet == nil {
|
||||||
lastStoredHeight := lastStoredHeightFor(height, valInfo.LastHeightChanged)
|
lastStoredHeight := lastStoredHeightFor(height, valInfo.LastHeightChanged)
|
||||||
valInfo2 := loadValidatorsInfo(db, lastStoredHeight)
|
valInfo2 := loadValidatorsInfo(db, lastStoredHeight)
|
||||||
if valInfo2 == nil {
|
if valInfo2 == nil || valInfo2.ValidatorSet == nil {
|
||||||
// TODO (melekes): remove the below if condition in the 0.33 major
|
// TODO (melekes): remove the below if condition in the 0.33 major
|
||||||
// release and just panic. Old chains might panic otherwise if they
|
// release and just panic. Old chains might panic otherwise if they
|
||||||
// haven't saved validators at intermediate (%valSetCheckpointInterval)
|
// haven't saved validators at intermediate (%valSetCheckpointInterval)
|
||||||
@ -201,7 +201,7 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
|
|||||||
// https://github.com/tendermint/tendermint/issues/3543
|
// https://github.com/tendermint/tendermint/issues/3543
|
||||||
valInfo2 = loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
valInfo2 = loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
||||||
lastStoredHeight = valInfo.LastHeightChanged
|
lastStoredHeight = valInfo.LastHeightChanged
|
||||||
if valInfo2 == nil {
|
if valInfo2 == nil || valInfo2.ValidatorSet == nil {
|
||||||
panic(
|
panic(
|
||||||
fmt.Sprintf("Couldn't find validators at height %d (height %d was originally requested)",
|
fmt.Sprintf("Couldn't find validators at height %d (height %d was originally requested)",
|
||||||
lastStoredHeight,
|
lastStoredHeight,
|
||||||
|
@ -6,34 +6,50 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSaveValidatorsInfo(t *testing.T) {
|
func TestStoreLoadValidators(t *testing.T) {
|
||||||
// test we persist validators every valSetCheckpointInterval blocks
|
|
||||||
stateDB := dbm.NewMemDB()
|
stateDB := dbm.NewMemDB()
|
||||||
val, _ := types.RandValidator(true, 10)
|
val, _ := types.RandValidator(true, 10)
|
||||||
vals := types.NewValidatorSet([]*types.Validator{val})
|
vals := types.NewValidatorSet([]*types.Validator{val})
|
||||||
|
|
||||||
// TODO(melekes): remove in 0.33 release
|
// 1) LoadValidators loads validators using a height where they were last changed
|
||||||
// https://github.com/tendermint/tendermint/issues/3543
|
|
||||||
saveValidatorsInfo(stateDB, 1, 1, vals)
|
saveValidatorsInfo(stateDB, 1, 1, vals)
|
||||||
saveValidatorsInfo(stateDB, 2, 1, vals)
|
saveValidatorsInfo(stateDB, 2, 1, vals)
|
||||||
|
loadedVals, err := LoadValidators(stateDB, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotZero(t, loadedVals.Size())
|
||||||
|
|
||||||
|
// 2) LoadValidators loads validators using a checkpoint height
|
||||||
|
|
||||||
|
// TODO(melekes): REMOVE in 0.33 release
|
||||||
|
// https://github.com/tendermint/tendermint/issues/3543
|
||||||
|
// for releases prior to v0.31.4, it uses last height changed
|
||||||
|
valInfo := &ValidatorsInfo{
|
||||||
|
LastHeightChanged: valSetCheckpointInterval,
|
||||||
|
}
|
||||||
|
stateDB.Set(calcValidatorsKey(valSetCheckpointInterval), valInfo.Bytes())
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
_, err := LoadValidators(stateDB, 2)
|
saveValidatorsInfo(stateDB, valSetCheckpointInterval+1, 1, vals)
|
||||||
|
loadedVals, err := LoadValidators(stateDB, valSetCheckpointInterval+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if loadedVals.Size() == 0 {
|
||||||
|
t.Fatal("Expected validators to be non-empty")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//ENDREMOVE
|
// ENDREMOVE
|
||||||
|
|
||||||
saveValidatorsInfo(stateDB, valSetCheckpointInterval, 1, vals)
|
saveValidatorsInfo(stateDB, valSetCheckpointInterval, 1, vals)
|
||||||
|
|
||||||
loadedVals, err := LoadValidators(stateDB, valSetCheckpointInterval)
|
loadedVals, err = LoadValidators(stateDB, valSetCheckpointInterval)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotZero(t, loadedVals.Size())
|
assert.NotZero(t, loadedVals.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const (
|
|||||||
// Must be a string because scripts like dist.sh read this file.
|
// Must be a string because scripts like dist.sh read this file.
|
||||||
// XXX: Don't change the name of this variable or you will break
|
// XXX: Don't change the name of this variable or you will break
|
||||||
// automation :)
|
// automation :)
|
||||||
TMCoreSemVer = "0.31.4"
|
TMCoreSemVer = "0.31.5"
|
||||||
|
|
||||||
// ABCISemVer is the semantic version of the ABCI library
|
// ABCISemVer is the semantic version of the ABCI library
|
||||||
ABCISemVer = "0.16.0"
|
ABCISemVer = "0.16.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user