mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-30 03:31:56 +00:00
Compare commits
9 Commits
v0.29.1
...
2565-max-a
Author | SHA1 | Date | |
---|---|---|---|
|
a2e7494b4b | ||
|
56f943e890 | ||
|
e9f30e1f22 | ||
|
7482113547 | ||
|
42b84972f5 | ||
|
5481c6b150 | ||
|
f7e0cd1360 | ||
|
166dc01ab5 | ||
|
7e7e4c74ca |
@@ -12,10 +12,17 @@ BREAKING CHANGES:
|
|||||||
* [rpc] \#2298 `/abci_query` takes `prove` argument instead of `trusted` and switches the default
|
* [rpc] \#2298 `/abci_query` takes `prove` argument instead of `trusted` and switches the default
|
||||||
behaviour to `prove=false`
|
behaviour to `prove=false`
|
||||||
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
||||||
|
* [genesis] \#2565 `consensus_params.evidence_params.max_age` is now `time.Duration` (nanosecond count)
|
||||||
|
```json
|
||||||
|
"evidence_params": {
|
||||||
|
"max_age": "48h0m0s"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* Apps
|
* Apps
|
||||||
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
|
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
|
||||||
arbitrary bytes
|
arbitrary bytes
|
||||||
|
* [abci] \#2565 InitChain `ConsensusParams.EvidenceParams.MaxAge` is now `google.protobuf.Duration` (see https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/duration)
|
||||||
|
|
||||||
* Go API
|
* Go API
|
||||||
* [node] Remove node.RunForever
|
* [node] Remove node.RunForever
|
||||||
|
1
Gopkg.lock
generated
1
Gopkg.lock
generated
@@ -517,6 +517,7 @@
|
|||||||
"github.com/gogo/protobuf/proto",
|
"github.com/gogo/protobuf/proto",
|
||||||
"github.com/gogo/protobuf/types",
|
"github.com/gogo/protobuf/types",
|
||||||
"github.com/golang/protobuf/proto",
|
"github.com/golang/protobuf/proto",
|
||||||
|
"github.com/golang/protobuf/ptypes/duration",
|
||||||
"github.com/golang/protobuf/ptypes/timestamp",
|
"github.com/golang/protobuf/ptypes/timestamp",
|
||||||
"github.com/gorilla/websocket",
|
"github.com/gorilla/websocket",
|
||||||
"github.com/jmhodges/levigo",
|
"github.com/jmhodges/levigo",
|
||||||
|
2
Makefile
2
Makefile
@@ -44,7 +44,7 @@ protoc_all: protoc_libs protoc_merkle protoc_abci protoc_grpc
|
|||||||
## See https://stackoverflow.com/a/25518702
|
## See https://stackoverflow.com/a/25518702
|
||||||
## Note the $< here is substituted for the %.proto
|
## Note the $< here is substituted for the %.proto
|
||||||
## Note the $@ here is substituted for the %.pb.go
|
## Note the $@ here is substituted for the %.pb.go
|
||||||
protoc $(INCLUDE) $< --gogo_out=Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,plugins=grpc:.
|
protoc $(INCLUDE) $< --gogo_out=Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration,plugins=grpc:.
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
### Build ABCI
|
### Build ABCI
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ package types;
|
|||||||
// https://github.com/gogo/protobuf/blob/master/extensions.md
|
// https://github.com/gogo/protobuf/blob/master/extensions.md
|
||||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
import "github.com/tendermint/tendermint/libs/common/types.proto";
|
import "github.com/tendermint/tendermint/libs/common/types.proto";
|
||||||
import "github.com/tendermint/tendermint/crypto/merkle/merkle.proto";
|
import "github.com/tendermint/tendermint/crypto/merkle/merkle.proto";
|
||||||
|
|
||||||
@@ -217,8 +218,8 @@ message BlockSize {
|
|||||||
|
|
||||||
// EvidenceParams contains limits on the evidence.
|
// EvidenceParams contains limits on the evidence.
|
||||||
message EvidenceParams {
|
message EvidenceParams {
|
||||||
// Note: must be greater than 0
|
// Note: must be greater than 0 if provided
|
||||||
int64 max_age = 1;
|
google.protobuf.Duration max_age = 1 [(gogoproto.nullable)=false, (gogoproto.stdduration)=true];
|
||||||
}
|
}
|
||||||
|
|
||||||
message LastCommitInfo {
|
message LastCommitInfo {
|
||||||
|
@@ -13,6 +13,7 @@ import golang_proto "github.com/golang/protobuf/proto"
|
|||||||
import fmt "fmt"
|
import fmt "fmt"
|
||||||
import math "math"
|
import math "math"
|
||||||
import _ "github.com/gogo/protobuf/gogoproto"
|
import _ "github.com/gogo/protobuf/gogoproto"
|
||||||
|
import _ "github.com/golang/protobuf/ptypes/duration"
|
||||||
import _ "github.com/golang/protobuf/ptypes/timestamp"
|
import _ "github.com/golang/protobuf/ptypes/timestamp"
|
||||||
import _ "github.com/tendermint/tendermint/crypto/merkle"
|
import _ "github.com/tendermint/tendermint/crypto/merkle"
|
||||||
import _ "github.com/tendermint/tendermint/libs/common"
|
import _ "github.com/tendermint/tendermint/libs/common"
|
||||||
|
@@ -8,8 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/tendermint/go-amino"
|
amino "github.com/tendermint/go-amino"
|
||||||
|
|
||||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
tmevents "github.com/tendermint/tendermint/libs/events"
|
tmevents "github.com/tendermint/tendermint/libs/events"
|
||||||
@@ -948,8 +947,8 @@ func (ps *PeerState) ToJSON() ([]byte, error) {
|
|||||||
return cdc.MarshalJSON(ps)
|
return cdc.MarshalJSON(ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeight returns an atomic snapshot of the PeerRoundState's height
|
// GetHeight returns an atomic snapshot of the PeerRoundState's height used by
|
||||||
// used by the mempool to ensure peers are caught up before broadcasting new txs
|
// the mempool to ensure peers are caught up before broadcasting new txs.
|
||||||
func (ps *PeerState) GetHeight() int64 {
|
func (ps *PeerState) GetHeight() int64 {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
@@ -443,11 +443,10 @@ Commit are included in the header of the next block.
|
|||||||
### EvidenceParams
|
### EvidenceParams
|
||||||
|
|
||||||
- **Fields**:
|
- **Fields**:
|
||||||
- `MaxAge (int64)`: Max age of evidence, in blocks. Evidence older than this
|
- `MaxAge (google.protobuf.Duration)`: Max age of evidence. Evidence older
|
||||||
is considered stale and ignored.
|
than this is considered stale and ignored.
|
||||||
- This should correspond with an app's "unbonding period" or other
|
- This should correspond with an app's "unbonding period" or other
|
||||||
similar mechanism for handling Nothing-At-Stake attacks.
|
similar mechanism for handling Nothing-At-Stake attacks.
|
||||||
- NOTE: this should change to time (instead of blocks)!
|
|
||||||
|
|
||||||
### Proof
|
### Proof
|
||||||
|
|
||||||
|
@@ -101,7 +101,7 @@ type BlockGossip struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EvidenceParams struct {
|
type EvidenceParams struct {
|
||||||
MaxAge int64
|
MaxAge time.Duration
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -129,5 +129,5 @@ size of each part is `ConsensusParams.BlockGossip.BlockPartSizeBytes`.
|
|||||||
For evidence in a block to be valid, it must satisfy:
|
For evidence in a block to be valid, it must satisfy:
|
||||||
|
|
||||||
```
|
```
|
||||||
block.Header.Height - evidence.Height < ConsensusParams.EvidenceParams.MaxAge
|
block.Header.Time - evidence.Time < ConsensusParams.EvidenceParams.MaxAge
|
||||||
```
|
```
|
||||||
|
@@ -3,6 +3,7 @@ package evidence
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
clist "github.com/tendermint/tendermint/libs/clist"
|
clist "github.com/tendermint/tendermint/libs/clist"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
@@ -84,7 +85,7 @@ func (evpool *EvidencePool) Update(block *types.Block, state sm.State) {
|
|||||||
evpool.mtx.Unlock()
|
evpool.mtx.Unlock()
|
||||||
|
|
||||||
// remove evidence from pending and mark committed
|
// remove evidence from pending and mark committed
|
||||||
evpool.MarkEvidenceAsCommitted(block.Height, block.Evidence.Evidence)
|
evpool.MarkEvidenceAsCommitted(block.Evidence.Evidence, block.Time)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEvidence checks the evidence is valid and adds it to the pool.
|
// AddEvidence checks the evidence is valid and adds it to the pool.
|
||||||
@@ -117,8 +118,9 @@ func (evpool *EvidencePool) AddEvidence(evidence types.Evidence) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkEvidenceAsCommitted marks all the evidence as committed and removes it from the queue.
|
// MarkEvidenceAsCommitted marks all the evidence as committed and removes it
|
||||||
func (evpool *EvidencePool) MarkEvidenceAsCommitted(height int64, evidence []types.Evidence) {
|
// from the queue.
|
||||||
|
func (evpool *EvidencePool) MarkEvidenceAsCommitted(evidence []types.Evidence, lastBlockTime time.Time) {
|
||||||
// make a map of committed evidence to remove from the clist
|
// make a map of committed evidence to remove from the clist
|
||||||
blockEvidenceMap := make(map[string]struct{})
|
blockEvidenceMap := make(map[string]struct{})
|
||||||
for _, ev := range evidence {
|
for _, ev := range evidence {
|
||||||
@@ -127,20 +129,22 @@ func (evpool *EvidencePool) MarkEvidenceAsCommitted(height int64, evidence []typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove committed evidence from the clist
|
// remove committed evidence from the clist
|
||||||
maxAge := evpool.State().ConsensusParams.EvidenceParams.MaxAge
|
maxAge := evpool.State().ConsensusParams.EvidenceParams.MaxAge.Duration
|
||||||
evpool.removeEvidence(height, maxAge, blockEvidenceMap)
|
evpool.removeEvidence(blockEvidenceMap, lastBlockTime, maxAge)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (evpool *EvidencePool) removeEvidence(height, maxAge int64, blockEvidenceMap map[string]struct{}) {
|
func (evpool *EvidencePool) removeEvidence(
|
||||||
|
blockEvidenceMap map[string]struct{},
|
||||||
|
lastBlockTime time.Time,
|
||||||
|
maxAge time.Duration,
|
||||||
|
) {
|
||||||
for e := evpool.evidenceList.Front(); e != nil; e = e.Next() {
|
for e := evpool.evidenceList.Front(); e != nil; e = e.Next() {
|
||||||
ev := e.Value.(types.Evidence)
|
ev := e.Value.(types.Evidence)
|
||||||
|
evAge := lastBlockTime.Sub(ev.Time())
|
||||||
|
|
||||||
// Remove the evidence if it's already in a block
|
// Remove the evidence if it's already in a block
|
||||||
// or if it's now too old.
|
// or if it's now too old.
|
||||||
if _, ok := blockEvidenceMap[evMapKey(ev)]; ok ||
|
if _, ok := blockEvidenceMap[evMapKey(ev)]; ok || evAge > maxAge {
|
||||||
ev.Height() < height-maxAge {
|
|
||||||
|
|
||||||
// remove from clist
|
// remove from clist
|
||||||
evpool.evidenceList.Remove(e)
|
evpool.evidenceList.Remove(e)
|
||||||
e.DetachPrev()
|
e.DetachPrev()
|
||||||
|
@@ -39,7 +39,7 @@ func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
|
|||||||
LastHeightValidatorsChanged: 1,
|
LastHeightValidatorsChanged: 1,
|
||||||
ConsensusParams: types.ConsensusParams{
|
ConsensusParams: types.ConsensusParams{
|
||||||
EvidenceParams: types.EvidenceParams{
|
EvidenceParams: types.EvidenceParams{
|
||||||
MaxAge: 1000000,
|
MaxAge: tmtime.DurationPretty{1000000},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -91,7 +91,7 @@ func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEventSwitch implements events.Eventable.
|
// SetEventBus implements events.Eventable.
|
||||||
func (evR *EvidenceReactor) SetEventBus(b *types.EventBus) {
|
func (evR *EvidenceReactor) SetEventBus(b *types.EventBus) {
|
||||||
evR.eventBus = b
|
evR.eventBus = b
|
||||||
}
|
}
|
||||||
@@ -153,28 +153,17 @@ func (evR *EvidenceReactor) broadcastEvidenceRoutine(peer p2p.Peer) {
|
|||||||
// Returns the message to send the peer, or nil if the evidence is invalid for the peer.
|
// Returns the message to send the peer, or nil if the evidence is invalid for the peer.
|
||||||
// If message is nil, return true if we should sleep and try again.
|
// If message is nil, return true if we should sleep and try again.
|
||||||
func (evR EvidenceReactor) checkSendEvidenceMessage(peer p2p.Peer, ev types.Evidence) (msg EvidenceMessage, retry bool) {
|
func (evR EvidenceReactor) checkSendEvidenceMessage(peer p2p.Peer, ev types.Evidence) (msg EvidenceMessage, retry bool) {
|
||||||
|
|
||||||
// make sure the peer is up to date
|
|
||||||
evHeight := ev.Height()
|
|
||||||
peerState, ok := peer.Get(types.PeerStateKey).(PeerState)
|
peerState, ok := peer.Get(types.PeerStateKey).(PeerState)
|
||||||
if !ok {
|
if !ok {
|
||||||
evR.Logger.Info("Found peer without PeerState", "peer", peer)
|
evR.Logger.Info("Found peer without PeerState", "peer", peer)
|
||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We only send evidence to peers where
|
// NOTE: We only send evidence to peers where evidenceHeight < peerHeight
|
||||||
// peerHeight - maxAge < evidenceHeight < peerHeight
|
|
||||||
maxAge := evR.evpool.State().ConsensusParams.EvidenceParams.MaxAge
|
|
||||||
peerHeight := peerState.GetHeight()
|
peerHeight := peerState.GetHeight()
|
||||||
if peerHeight < evHeight {
|
if peerHeight < ev.Height() {
|
||||||
// peer is behind. sleep while he catches up
|
// peer is behind. sleep while he catches up
|
||||||
return nil, true
|
return nil, true
|
||||||
} else if peerHeight > evHeight+maxAge {
|
|
||||||
// evidence is too old, skip
|
|
||||||
// NOTE: if evidence is too old for an honest peer,
|
|
||||||
// then we're behind and either it already got committed or it never will!
|
|
||||||
evR.Logger.Info("Not sending peer old evidence", "peerHeight", peerHeight, "evHeight", evHeight, "maxAge", maxAge, "peer", peer)
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send evidence
|
// send evidence
|
||||||
|
@@ -132,7 +132,7 @@ func TestReactorBroadcastEvidence(t *testing.T) {
|
|||||||
// set the peer height on each reactor
|
// set the peer height on each reactor
|
||||||
for _, r := range reactors {
|
for _, r := range reactors {
|
||||||
for _, peer := range r.Switch.Peers().List() {
|
for _, peer := range r.Switch.Peers().List() {
|
||||||
ps := peerState{height}
|
ps := testPeerState{height}
|
||||||
peer.Set(types.PeerStateKey, ps)
|
peer.Set(types.PeerStateKey, ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,11 +143,13 @@ func TestReactorBroadcastEvidence(t *testing.T) {
|
|||||||
waitForEvidence(t, evList, reactors)
|
waitForEvidence(t, evList, reactors)
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerState struct {
|
type testPeerState struct {
|
||||||
height int64
|
height int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps peerState) GetHeight() int64 {
|
var _ PeerState = (*testPeerState)(nil)
|
||||||
|
|
||||||
|
func (ps testPeerState) GetHeight() int64 {
|
||||||
return ps.height
|
return ps.height
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ func TestReactorSelectiveBroadcast(t *testing.T) {
|
|||||||
// make reactors from statedb
|
// make reactors from statedb
|
||||||
reactors := makeAndConnectEvidenceReactors(config, []dbm.DB{stateDB1, stateDB2})
|
reactors := makeAndConnectEvidenceReactors(config, []dbm.DB{stateDB1, stateDB2})
|
||||||
peer := reactors[0].Switch.Peers().List()[0]
|
peer := reactors[0].Switch.Peers().List()[0]
|
||||||
ps := peerState{height2}
|
ps := testPeerState{height2}
|
||||||
peer.Set(types.PeerStateKey, ps)
|
peer.Set(types.PeerStateKey, ps)
|
||||||
|
|
||||||
// send a bunch of valid evidence to the first reactor's evpool
|
// send a bunch of valid evidence to the first reactor's evpool
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
@@ -386,14 +388,14 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeParams(blockBytes, blockGas, evidenceAge int64) types.ConsensusParams {
|
func makeParams(blockBytes, blockGas int64, evidenceAge time.Duration) types.ConsensusParams {
|
||||||
return types.ConsensusParams{
|
return types.ConsensusParams{
|
||||||
BlockSize: types.BlockSize{
|
BlockSize: types.BlockSize{
|
||||||
MaxBytes: blockBytes,
|
MaxBytes: blockBytes,
|
||||||
MaxGas: blockGas,
|
MaxGas: blockGas,
|
||||||
},
|
},
|
||||||
EvidenceParams: types.EvidenceParams{
|
EvidenceParams: types.EvidenceParams{
|
||||||
MaxAge: evidenceAge,
|
MaxAge: tmtime.DurationPretty{evidenceAge},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,7 +405,7 @@ func pk() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyUpdates(t *testing.T) {
|
func TestApplyUpdates(t *testing.T) {
|
||||||
initParams := makeParams(1, 2, 3)
|
initParams := makeParams(1, 2, 3*time.Second)
|
||||||
|
|
||||||
cases := [...]struct {
|
cases := [...]struct {
|
||||||
init types.ConsensusParams
|
init types.ConsensusParams
|
||||||
@@ -419,14 +421,14 @@ func TestApplyUpdates(t *testing.T) {
|
|||||||
MaxGas: 55,
|
MaxGas: 55,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
makeParams(44, 55, 3)},
|
makeParams(44, 55, 3*time.Second)},
|
||||||
3: {initParams,
|
3: {initParams,
|
||||||
abci.ConsensusParams{
|
abci.ConsensusParams{
|
||||||
EvidenceParams: &abci.EvidenceParams{
|
EvidenceParams: &abci.EvidenceParams{
|
||||||
MaxAge: 66,
|
MaxAge: 66 * time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
makeParams(1, 2, 66)},
|
makeParams(1, 2, 66*time.Second)},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
@@ -168,13 +168,11 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
// - it is internally consistent
|
// - it is internally consistent
|
||||||
// - it was properly signed by the alleged equivocator
|
// - it was properly signed by the alleged equivocator
|
||||||
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error {
|
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error {
|
||||||
height := state.LastBlockHeight
|
evidenceAge := state.LastBlockTime.Sub(evidence.Time())
|
||||||
|
maxAge := state.ConsensusParams.EvidenceParams.MaxAge.Duration
|
||||||
evidenceAge := height - evidence.Height()
|
|
||||||
maxAge := state.ConsensusParams.EvidenceParams.MaxAge
|
|
||||||
if evidenceAge > maxAge {
|
if evidenceAge > maxAge {
|
||||||
return fmt.Errorf("Evidence from height %d is too old. Min height is %d",
|
return fmt.Errorf("Evidence from %v is too old. Expecting evidence no older than %v",
|
||||||
evidence.Height(), height-maxAge)
|
evidence.Time(), state.LastBlockTime.Add(-maxAge))
|
||||||
}
|
}
|
||||||
|
|
||||||
valset, err := LoadValidators(stateDB, evidence.Height())
|
valset, err := LoadValidators(stateDB, evidence.Height())
|
||||||
|
@@ -3,8 +3,10 @@ package types
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
amino "github.com/tendermint/go-amino"
|
amino "github.com/tendermint/go-amino"
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ func (err *ErrEvidenceOverflow) Error() string {
|
|||||||
// Evidence represents any provable malicious activity by a validator
|
// Evidence represents any provable malicious activity by a validator
|
||||||
type Evidence interface {
|
type Evidence interface {
|
||||||
Height() int64 // height of the equivocation
|
Height() int64 // height of the equivocation
|
||||||
|
Time() time.Time // when the evidence was created
|
||||||
Address() []byte // address of the equivocating validator
|
Address() []byte // address of the equivocating validator
|
||||||
Bytes() []byte // bytes which compromise the evidence
|
Bytes() []byte // bytes which compromise the evidence
|
||||||
Hash() []byte // hash of the evidence
|
Hash() []byte // hash of the evidence
|
||||||
@@ -102,6 +105,11 @@ func (dve *DuplicateVoteEvidence) Height() int64 {
|
|||||||
return dve.VoteA.Height
|
return dve.VoteA.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time returns the time when the evidence was created.
|
||||||
|
func (dve *DuplicateVoteEvidence) Time() time.Time {
|
||||||
|
return dve.VoteA.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
// Address returns the address of the validator.
|
// Address returns the address of the validator.
|
||||||
func (dve *DuplicateVoteEvidence) Address() []byte {
|
func (dve *DuplicateVoteEvidence) Address() []byte {
|
||||||
return dve.PubKey.Address()
|
return dve.PubKey.Address()
|
||||||
@@ -188,6 +196,7 @@ func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
||||||
|
func (e MockGoodEvidence) Time() time.Time { return tmtime.Now() }
|
||||||
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
||||||
func (e MockGoodEvidence) Hash() []byte {
|
func (e MockGoodEvidence) Hash() []byte {
|
||||||
return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_))
|
return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_))
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,7 +32,7 @@ type BlockSize struct {
|
|||||||
|
|
||||||
// EvidenceParams determine how we handle evidence of malfeasance
|
// EvidenceParams determine how we handle evidence of malfeasance
|
||||||
type EvidenceParams struct {
|
type EvidenceParams struct {
|
||||||
MaxAge int64 `json:"max_age"` // only accept new evidence more recent than this
|
MaxAge tmtime.DurationPretty `json:"max_age"` // only accept new evidence more recent than this
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConsensusParams returns a default ConsensusParams.
|
// DefaultConsensusParams returns a default ConsensusParams.
|
||||||
@@ -51,7 +54,7 @@ func DefaultBlockSize() BlockSize {
|
|||||||
// DefaultEvidenceParams Params returns a default EvidenceParams.
|
// DefaultEvidenceParams Params returns a default EvidenceParams.
|
||||||
func DefaultEvidenceParams() EvidenceParams {
|
func DefaultEvidenceParams() EvidenceParams {
|
||||||
return EvidenceParams{
|
return EvidenceParams{
|
||||||
MaxAge: 100000, // 27.8 hrs at 1block/s
|
MaxAge: tmtime.DurationPretty{48 * time.Hour},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +75,9 @@ func (params *ConsensusParams) Validate() error {
|
|||||||
params.BlockSize.MaxGas)
|
params.BlockSize.MaxGas)
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.EvidenceParams.MaxAge <= 0 {
|
if params.EvidenceParams.MaxAge.Duration <= 0 {
|
||||||
return cmn.NewError("EvidenceParams.MaxAge must be greater than 0. Got %d",
|
return cmn.NewError("EvidenceParams.MaxAge must be greater than 0. Got %d",
|
||||||
params.EvidenceParams.MaxAge)
|
params.EvidenceParams.MaxAge.Duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -109,7 +112,7 @@ func (params ConsensusParams) Update(params2 *abci.ConsensusParams) ConsensusPar
|
|||||||
res.BlockSize.MaxGas = params2.BlockSize.MaxGas
|
res.BlockSize.MaxGas = params2.BlockSize.MaxGas
|
||||||
}
|
}
|
||||||
if params2.EvidenceParams != nil {
|
if params2.EvidenceParams != nil {
|
||||||
res.EvidenceParams.MaxAge = params2.EvidenceParams.MaxAge
|
res.EvidenceParams.MaxAge = tmtime.DurationPretty{params2.EvidenceParams.MaxAge}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConsensusParamsValidation(t *testing.T) {
|
func TestConsensusParamsValidation(t *testing.T) {
|
||||||
@@ -15,17 +17,17 @@ func TestConsensusParamsValidation(t *testing.T) {
|
|||||||
valid bool
|
valid bool
|
||||||
}{
|
}{
|
||||||
// test block size
|
// test block size
|
||||||
0: {makeParams(1, 0, 1), true},
|
0: {makeParams(1, 0, 10*time.Second), true},
|
||||||
1: {makeParams(0, 0, 1), false},
|
1: {makeParams(0, 0, 10*time.Second), false},
|
||||||
2: {makeParams(47*1024*1024, 0, 1), true},
|
2: {makeParams(47*1024*1024, 0, 10*time.Second), true},
|
||||||
3: {makeParams(10, 0, 1), true},
|
3: {makeParams(10, 0, 10*time.Second), true},
|
||||||
4: {makeParams(100*1024*1024, 0, 1), true},
|
4: {makeParams(100*1024*1024, 0, 10*time.Second), true},
|
||||||
5: {makeParams(101*1024*1024, 0, 1), false},
|
5: {makeParams(101*1024*1024, 0, 10*time.Second), false},
|
||||||
6: {makeParams(1024*1024*1024, 0, 1), false},
|
6: {makeParams(1024*1024*1024, 0, 10*time.Second), false},
|
||||||
7: {makeParams(1024*1024*1024, 0, -1), false},
|
7: {makeParams(1024*1024*1024, 0, -10*time.Second), false},
|
||||||
// test evidence age
|
// test evidence age
|
||||||
8: {makeParams(1, 0, 0), false},
|
8: {makeParams(1, 0, 0), false},
|
||||||
9: {makeParams(1, 0, -1), false},
|
9: {makeParams(1, 0, -1*time.Millisecond), false},
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
if tc.valid {
|
if tc.valid {
|
||||||
@@ -36,28 +38,23 @@ func TestConsensusParamsValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeParams(blockBytes, blockGas, evidenceAge int64) ConsensusParams {
|
func makeParams(blockBytes, blockGas int64, evidenceAge time.Duration) ConsensusParams {
|
||||||
return ConsensusParams{
|
return ConsensusParams{
|
||||||
BlockSize: BlockSize{
|
BlockSize: BlockSize{
|
||||||
MaxBytes: blockBytes,
|
MaxBytes: blockBytes,
|
||||||
MaxGas: blockGas,
|
MaxGas: blockGas,
|
||||||
},
|
},
|
||||||
EvidenceParams: EvidenceParams{
|
EvidenceParams: EvidenceParams{
|
||||||
MaxAge: evidenceAge,
|
MaxAge: tmtime.DurationPretty{evidenceAge},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConsensusParamsHash(t *testing.T) {
|
func TestConsensusParamsHash(t *testing.T) {
|
||||||
params := []ConsensusParams{
|
params := []ConsensusParams{
|
||||||
makeParams(4, 2, 3),
|
makeParams(4, 2, 3*time.Second),
|
||||||
makeParams(1, 4, 3),
|
makeParams(1, 4, 3*time.Second),
|
||||||
makeParams(1, 2, 4),
|
makeParams(1, 2, 4*time.Second),
|
||||||
makeParams(2, 5, 7),
|
|
||||||
makeParams(1, 7, 6),
|
|
||||||
makeParams(9, 5, 4),
|
|
||||||
makeParams(7, 8, 9),
|
|
||||||
makeParams(4, 6, 5),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hashes := make([][]byte, len(params))
|
hashes := make([][]byte, len(params))
|
||||||
@@ -83,23 +80,23 @@ func TestConsensusParamsUpdate(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
// empty updates
|
// empty updates
|
||||||
{
|
{
|
||||||
makeParams(1, 2, 3),
|
makeParams(1, 2, 3*time.Second),
|
||||||
&abci.ConsensusParams{},
|
&abci.ConsensusParams{},
|
||||||
makeParams(1, 2, 3),
|
makeParams(1, 2, 3*time.Second),
|
||||||
},
|
},
|
||||||
// fine updates
|
// fine updates
|
||||||
{
|
{
|
||||||
makeParams(1, 2, 3),
|
makeParams(1, 2, 3*time.Second),
|
||||||
&abci.ConsensusParams{
|
&abci.ConsensusParams{
|
||||||
BlockSize: &abci.BlockSize{
|
BlockSize: &abci.BlockSize{
|
||||||
MaxBytes: 100,
|
MaxBytes: 100,
|
||||||
MaxGas: 200,
|
MaxGas: 200,
|
||||||
},
|
},
|
||||||
EvidenceParams: &abci.EvidenceParams{
|
EvidenceParams: &abci.EvidenceParams{
|
||||||
MaxAge: 300,
|
MaxAge: 300 * time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
makeParams(100, 200, 300),
|
makeParams(100, 200, 300*time.Second),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
@@ -119,7 +120,7 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams {
|
|||||||
MaxGas: params.BlockSize.MaxGas,
|
MaxGas: params.BlockSize.MaxGas,
|
||||||
},
|
},
|
||||||
EvidenceParams: &abci.EvidenceParams{
|
EvidenceParams: &abci.EvidenceParams{
|
||||||
MaxAge: params.EvidenceParams.MaxAge,
|
MaxAge: params.EvidenceParams.MaxAge.Duration,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,13 +210,18 @@ func (pb2tm) ValidatorUpdates(vals []abci.ValidatorUpdate) ([]*Validator, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pb2tm) ConsensusParams(csp *abci.ConsensusParams) ConsensusParams {
|
func (pb2tm) ConsensusParams(csp *abci.ConsensusParams) ConsensusParams {
|
||||||
return ConsensusParams{
|
params := ConsensusParams{}
|
||||||
BlockSize: BlockSize{
|
|
||||||
|
// we must defensively consider any structs may be nil
|
||||||
|
if csp.BlockSize != nil {
|
||||||
|
params.BlockSize = BlockSize{
|
||||||
MaxBytes: csp.BlockSize.MaxBytes,
|
MaxBytes: csp.BlockSize.MaxBytes,
|
||||||
MaxGas: csp.BlockSize.MaxGas,
|
MaxGas: csp.BlockSize.MaxGas,
|
||||||
},
|
}
|
||||||
EvidenceParams: EvidenceParams{
|
|
||||||
MaxAge: csp.EvidenceParams.MaxAge,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
if csp.EvidenceParams != nil {
|
||||||
|
params.EvidenceParams.MaxAge = tmtime.DurationPretty{csp.EvidenceParams.MaxAge}
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
}
|
}
|
||||||
|
@@ -68,7 +68,7 @@ func TestABCIValidators(t *testing.T) {
|
|||||||
|
|
||||||
func TestABCIConsensusParams(t *testing.T) {
|
func TestABCIConsensusParams(t *testing.T) {
|
||||||
cp := DefaultConsensusParams()
|
cp := DefaultConsensusParams()
|
||||||
cp.EvidenceParams.MaxAge = 0 // TODO add this to ABCI
|
cp.EvidenceParams.MaxAge.Duration = 0 // TODO add this to ABCI
|
||||||
abciCP := TM2PB.ConsensusParams(cp)
|
abciCP := TM2PB.ConsensusParams(cp)
|
||||||
cp2 := PB2TM.ConsensusParams(abciCP)
|
cp2 := PB2TM.ConsensusParams(abciCP)
|
||||||
|
|
||||||
|
41
types/time/duration.go
Normal file
41
types/time/duration.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DurationPretty is a wrapper around time.Duration implementing custom
|
||||||
|
// marshaller/unmarshaller which make it pretty (e.g. "10s", not
|
||||||
|
// "10000000000").
|
||||||
|
type DurationPretty struct {
|
||||||
|
time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaller.
|
||||||
|
func (d DurationPretty) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller.
|
||||||
|
func (d *DurationPretty) UnmarshalJSON(b []byte) error {
|
||||||
|
var v interface{}
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch value := v.(type) {
|
||||||
|
case float64:
|
||||||
|
d.Duration = time.Duration(value)
|
||||||
|
return nil
|
||||||
|
case string:
|
||||||
|
var err error
|
||||||
|
d.Duration, err = time.ParseDuration(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("invalid duration")
|
||||||
|
}
|
||||||
|
}
|
31
types/time/duration_test.go
Normal file
31
types/time/duration_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDurationPretty(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
jsonBytes []byte
|
||||||
|
expErr bool
|
||||||
|
expValue time.Duration
|
||||||
|
}{
|
||||||
|
{[]byte(`"10s"`), false, 10 * time.Second},
|
||||||
|
{[]byte(`"48h0m0s"`), false, 48 * time.Hour},
|
||||||
|
{[]byte(`"10kkk"`), true, 0},
|
||||||
|
{[]byte(`"kkk"`), true, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
var d DurationPretty
|
||||||
|
if tc.expErr {
|
||||||
|
assert.Error(t, d.UnmarshalJSON(tc.jsonBytes), "#%d", i)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, d.UnmarshalJSON(tc.jsonBytes), "#%d", i)
|
||||||
|
assert.Equal(t, tc.expValue, d.Duration, "#%d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user