Browse Source

evidence: use bytes instead of quantity to limit size (#5449)(#5476)

rc5/v0.34.0
Callum Waters 4 years ago
committed by GitHub
parent
commit
7d5d417dc9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 227 additions and 274 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +1
    -1
      config/toml.go
  3. +3
    -3
      consensus/reactor_test.go
  4. +1
    -1
      evidence/doc.go
  5. +0
    -52
      evidence/mocks/state_store.go
  6. +26
    -22
      evidence/pool.go
  7. +27
    -14
      evidence/pool_test.go
  8. +6
    -3
      evidence/reactor_test.go
  9. +3
    -3
      evidence/verify_test.go
  10. +5
    -3
      node/node_test.go
  11. +49
    -51
      proto/tendermint/types/params.pb.go
  12. +4
    -5
      proto/tendermint/types/params.proto
  13. +2
    -2
      state/execution.go
  14. +10
    -3
      state/mocks/evidence_pool.go
  15. +4
    -2
      state/services.go
  16. +1
    -2
      state/tx_filter.go
  17. +3
    -3
      state/tx_filter_test.go
  18. +2
    -2
      state/validation.go
  19. +18
    -13
      state/validation_test.go
  20. +23
    -11
      types/block.go
  21. +18
    -19
      types/block_test.go
  22. +5
    -10
      types/evidence.go
  23. +0
    -31
      types/evidence_test.go
  24. +10
    -13
      types/params.go
  25. +4
    -4
      types/params_test.go
  26. +1
    -1
      types/part_set.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -15,6 +15,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- P2P Protocol
- Go API
- [evidence] [\#5499](https://github.com/tendermint/tendermint/pull/5449) `MaxNum` evidence consensus parameter has been changed to `MaxBytes` (@cmwaters)
- Blockchain Protocol


+ 1
- 1
config/toml.go View File

@ -515,7 +515,7 @@ var testGenesisFmt = `{
"evidence": {
"max_age_num_blocks": "100000",
"max_age_duration": "172800000000000",
"max_num": 50
"max_bytes": "1048576"
},
"validator": {
"pub_key_types": [


+ 3
- 3
consensus/reactor_test.go View File

@ -167,11 +167,11 @@ func TestReactorWithEvidence(t *testing.T) {
// mock the evidence pool
// everyone includes evidence of another double signing
vIdx := (i + 1) % nValidators
ev := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID())
evpool := &statemocks.EvidencePool{}
evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
evpool.On("PendingEvidence", mock.AnythingOfType("uint32")).Return([]types.Evidence{
types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID()),
})
evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return([]types.Evidence{
ev}, int64(len(ev.Bytes())))
evpool.On("Update", mock.AnythingOfType("state.State")).Return()
evpool.On("ABCIEvidence", mock.AnythingOfType("int64"), mock.AnythingOfType("[]types.Evidence")).Return(
[]abci.Evidence{})


+ 1
- 1
evidence/doc.go View File

@ -32,7 +32,7 @@ All evidence is proto encoded to disk.
Proposing
When a new block is being proposed (in state/execution.go#CreateProposalBlock),
`PendingEvidence(maxNum)` is called to send up to the maxNum number of uncommitted evidence, from the evidence store,
`PendingEvidence(maxBytes)` is called to send up to the maxBytes of uncommitted evidence, from the evidence store,
prioritized in order of age. All evidence is checked for expiration.
When a node receives evidence in a block it will use the evidence module as a cache first to see if it has


+ 0
- 52
evidence/mocks/state_store.go View File

@ -1,52 +0,0 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
state "github.com/tendermint/tendermint/state"
types "github.com/tendermint/tendermint/types"
)
// StateStore is an autogenerated mock type for the StateStore type
type StateStore struct {
mock.Mock
}
// LoadState provides a mock function with given fields:
func (_m *StateStore) LoadState() state.State {
ret := _m.Called()
var r0 state.State
if rf, ok := ret.Get(0).(func() state.State); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(state.State)
}
return r0
}
// LoadValidators provides a mock function with given fields: height
func (_m *StateStore) LoadValidators(height int64) (*types.ValidatorSet, error) {
ret := _m.Called(height)
var r0 *types.ValidatorSet
if rf, ok := ret.Get(0).(func(int64) *types.ValidatorSet); ok {
r0 = rf(height)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.ValidatorSet)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(int64) error); ok {
r1 = rf(height)
} else {
r1 = ret.Error(1)
}
return r0, r1
}

+ 26
- 22
evidence/pool.go View File

@ -64,19 +64,16 @@ func NewPool(evidenceDB dbm.DB, stateDB sm.Store, blockStore BlockStore) (*Pool,
logger: log.NewNopLogger(),
evidenceStore: evidenceDB,
evidenceList: clist.New(),
evidenceSize: 0,
pruningHeight: state.LastBlockHeight,
pruningTime: state.LastBlockTime,
}
// if pending evidence already in db, in event of prior failure, then check for expiration,
// update the size and load it back to the evidenceList
pool.removeExpiredPendingEvidence()
evList, err := pool.listEvidence(baseKeyPending, -1)
pool.pruningHeight, pool.pruningTime = pool.removeExpiredPendingEvidence()
evList, _, err := pool.listEvidence(baseKeyPending, -1)
if err != nil {
return nil, err
}
atomic.AddUint32(&pool.evidenceSize, uint32(len(evList)))
atomic.StoreUint32(&pool.evidenceSize, uint32(len(evList)))
for _, ev := range evList {
pool.evidenceList.PushBack(ev)
}
@ -85,12 +82,15 @@ func NewPool(evidenceDB dbm.DB, stateDB sm.Store, blockStore BlockStore) (*Pool,
}
// PendingEvidence is used primarily as part of block proposal and returns up to maxNum of uncommitted evidence.
func (evpool *Pool) PendingEvidence(maxNum uint32) []types.Evidence {
evidence, err := evpool.listEvidence(baseKeyPending, int64(maxNum))
func (evpool *Pool) PendingEvidence(maxBytes int64) ([]types.Evidence, int64) {
if atomic.LoadUint32(&evpool.evidenceSize) == 0 {
return []types.Evidence{}, 0
}
evidence, size, err := evpool.listEvidence(baseKeyPending, maxBytes)
if err != nil {
evpool.logger.Error("Unable to retrieve pending evidence", "err", err)
}
return evidence
return evidence, size
}
// Update pulls the latest state to be used for expiration and evidence params and then prunes all expired evidence
@ -330,6 +330,7 @@ type info struct {
Time time.Time
Validators []*types.Validator
TotalVotingPower int64
ByteSize int64
}
// ToProto encodes into protobuf
@ -381,6 +382,7 @@ func infoFromProto(proto *evproto.Info) (info, error) {
Time: proto.Time,
Validators: vals,
TotalVotingPower: proto.TotalVotingPower,
ByteSize: int64(proto.Evidence.Size()),
}, nil
}
@ -489,31 +491,32 @@ func (evpool *Pool) removePendingEvidence(evidence types.Evidence) {
}
}
// listEvidence lists up to maxNum pieces of evidence for the given prefix key.
// If maxNum is -1, there's no cap on the size of returned evidence.
func (evpool *Pool) listEvidence(prefixKey byte, maxNum int64) ([]types.Evidence, error) {
var count int64
// listEvidence retrieves lists evidence from oldest to newest within maxBytes.
// If maxBytes is -1, there's no cap on the size of returned evidence.
func (evpool *Pool) listEvidence(prefixKey byte, maxBytes int64) ([]types.Evidence, int64, error) {
var totalSize int64
var evidence []types.Evidence
iter, err := dbm.IteratePrefix(evpool.evidenceStore, []byte{prefixKey})
if err != nil {
return nil, fmt.Errorf("database error: %v", err)
return nil, totalSize, fmt.Errorf("database error: %v", err)
}
defer iter.Close()
for ; iter.Valid(); iter.Next() {
if count == maxNum {
return evidence, nil
}
count++
evInfo, err := bytesToInfo(iter.Value())
if err != nil {
return nil, err
return nil, totalSize, err
}
totalSize += evInfo.ByteSize
if maxBytes != -1 && totalSize > maxBytes {
return evidence, totalSize - evInfo.ByteSize, nil
}
evidence = append(evidence, evInfo.Evidence)
}
return evidence, nil
return evidence, totalSize, nil
}
func (evpool *Pool) removeExpiredPendingEvidence() (int64, time.Time) {
@ -534,7 +537,8 @@ func (evpool *Pool) removeExpiredPendingEvidence() (int64, time.Time) {
if len(blockEvidenceMap) != 0 {
evpool.removeEvidenceFromList(blockEvidenceMap)
}
// return the time with which this evidence will have expired so we know when to prune next
// return the height and time with which this evidence will have expired so we know when to prune next
return evInfo.Evidence.Height() + evpool.State().ConsensusParams.Evidence.MaxAgeNumBlocks + 1,
evInfo.Time.Add(evpool.State().ConsensusParams.Evidence.MaxAgeDuration).Add(time.Second)
}


+ 27
- 14
evidence/pool_test.go View File

@ -32,7 +32,10 @@ func TestMain(m *testing.M) {
const evidenceChainID = "test_chain"
var defaultEvidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
var (
defaultEvidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
defaultEvidenceMaxBytes int64 = 1000
)
func TestEvidencePoolBasic(t *testing.T) {
var (
@ -52,10 +55,12 @@ func TestEvidencePoolBasic(t *testing.T) {
pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
require.NoError(t, err)
pool.SetLogger(log.TestingLogger())
// evidence not seen yet:
evs := pool.PendingEvidence(10)
evs, size := pool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Equal(t, 0, len(evs))
assert.Zero(t, size)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime, privVals[0], evidenceChainID)
@ -78,12 +83,14 @@ func TestEvidencePoolBasic(t *testing.T) {
next := pool.EvidenceFront()
assert.Equal(t, ev, next.Value.(types.Evidence))
evs = pool.PendingEvidence(10)
evs, size = pool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Equal(t, 1, len(evs))
assert.Equal(t, int64(357), size) // check that the size of the single evidence in bytes is correct
// shouldn't be able to add evidence twice
assert.Error(t, pool.AddEvidence(ev))
assert.Equal(t, 1, len(pool.PendingEvidence(10)))
evs, _ = pool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Equal(t, 1, len(evs))
}
@ -183,12 +190,15 @@ func TestEvidencePoolUpdate(t *testing.T) {
},
}
assert.Equal(t, expectedByzVals, byzVals)
assert.Equal(t, 1, len(pool.PendingEvidence(10)))
evList, _ := pool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Equal(t, 1, len(evList))
pool.Update(state)
// a) Update marks evidence as committed so pending evidence should be empty
assert.Empty(t, pool.PendingEvidence(10))
evList, evSize := pool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Empty(t, evList)
assert.Zero(t, evSize)
// b) If we try to check this evidence again it should fail because it has already been committed
err = pool.CheckEvidence(types.EvidenceList{ev})
@ -293,7 +303,6 @@ func TestCheckEvidenceWithLightClientAttack(t *testing.T) {
func TestRecoverPendingEvidence(t *testing.T) {
height := int64(10)
expiredEvidenceTime := time.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC)
val := types.NewMockPV()
valAddress := val.PrivKey.PubKey().Address()
evidenceDB := dbm.NewMemDB()
@ -301,21 +310,24 @@ func TestRecoverPendingEvidence(t *testing.T) {
state, err := stateStore.Load()
require.NoError(t, err)
blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress)
// create previous pool and populate it
pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
require.NoError(t, err)
pool.SetLogger(log.TestingLogger())
goodEvidence := types.NewMockDuplicateVoteEvidenceWithValidator(height,
defaultEvidenceTime, val, evidenceChainID)
expiredEvidence := types.NewMockDuplicateVoteEvidenceWithValidator(int64(1),
expiredEvidenceTime, val, evidenceChainID)
defaultEvidenceTime, val, evidenceChainID)
err = pool.AddEvidence(goodEvidence)
require.NoError(t, err)
err = pool.AddEvidence(expiredEvidence)
require.NoError(t, err)
// now recover from the previous pool at a different time
newStateStore := &smmocks.Store{}
newStateStore.On("Load").Return(sm.State{
LastBlockTime: defaultEvidenceTime.Add(49 * time.Hour),
LastBlockHeight: height + 12,
LastBlockTime: defaultEvidenceTime.Add(25 * time.Minute),
LastBlockHeight: height + 15,
ConsensusParams: tmproto.ConsensusParams{
Block: tmproto.BlockParams{
MaxBytes: 22020096,
@ -323,14 +335,15 @@ func TestRecoverPendingEvidence(t *testing.T) {
},
Evidence: tmproto.EvidenceParams{
MaxAgeNumBlocks: 20,
MaxAgeDuration: 1 * time.Hour,
MaxNum: 50,
MaxAgeDuration: 20 * time.Minute,
MaxBytes: 1000,
},
},
}, nil)
newPool, err := evidence.NewPool(evidenceDB, newStateStore, blockStore)
assert.NoError(t, err)
assert.Equal(t, 1, len(newPool.PendingEvidence(10)))
evList, _ := newPool.PendingEvidence(defaultEvidenceMaxBytes)
assert.Equal(t, 1, len(evList))
next := newPool.EvidenceFront()
assert.Equal(t, goodEvidence, next.Value.(types.Evidence))
@ -356,7 +369,7 @@ func initializeStateFromValidatorSet(valSet *types.ValidatorSet, height int64) s
Evidence: tmproto.EvidenceParams{
MaxAgeNumBlocks: 20,
MaxAgeDuration: 20 * time.Minute,
MaxNum: 50,
MaxBytes: 1000,
},
},
}


+ 6
- 3
evidence/reactor_test.go View File

@ -106,14 +106,17 @@ func _waitForEvidence(
pools []*evidence.Pool,
) {
evpool := pools[poolIdx]
for len(evpool.PendingEvidence(uint32(len(evs)))) != len(evs) {
var evList []types.Evidence
currentPoolSize := 0
for currentPoolSize != len(evs) {
evList, _ = evpool.PendingEvidence(int64(len(evs) * 500)) // each evidence should not be more than 500 bytes
currentPoolSize = len(evList)
time.Sleep(time.Millisecond * 100)
}
reapedEv := evpool.PendingEvidence(uint32(len(evs)))
// put the reaped evidence in a map so we can quickly check we got everything
evMap := make(map[string]types.Evidence)
for _, e := range reapedEv {
for _, e := range evList {
evMap[string(e.Hash())] = e
}
for i, expectedEv := range evs {


+ 3
- 3
evidence/verify_test.go View File

@ -102,7 +102,7 @@ func TestVerifyLightClientAttack_Lunatic(t *testing.T) {
err = pool.CheckEvidence(evList)
assert.NoError(t, err)
pendingEvs := pool.PendingEvidence(2)
pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
assert.Equal(t, 1, len(pendingEvs))
pubKey, err := newPrivVal.GetPubKey()
@ -206,7 +206,7 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) {
err = pool.CheckEvidence(evList)
assert.NoError(t, err)
pendingEvs := pool.PendingEvidence(2)
pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
assert.Equal(t, 1, len(pendingEvs))
pubKey, err := conflictingPrivVals[0].GetPubKey()
@ -303,7 +303,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) {
err = pool.CheckEvidence(evList)
assert.NoError(t, err)
pendingEvs := pool.PendingEvidence(2)
pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
assert.Equal(t, 1, len(pendingEvs))
pubKey, err := conflictingPrivVals[0].GetPubKey()


+ 5
- 3
node/node_test.go View File

@ -234,9 +234,9 @@ func TestCreateProposalBlock(t *testing.T) {
state, stateDB, privVals := state(1, height)
stateStore := sm.NewStore(stateDB)
maxBytes := 16384
maxEvidence := 10
maxEvidenceBytes := int64(maxBytes / 2)
state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
state.ConsensusParams.Evidence.MaxNum = uint32(maxEvidence)
state.ConsensusParams.Evidence.MaxBytes = maxEvidenceBytes
proposerAddr, _ := state.Validators.GetByIndex(0)
// Make Mempool
@ -260,8 +260,10 @@ func TestCreateProposalBlock(t *testing.T) {
// fill the evidence pool with more evidence
// than can fit in a block
for i := 0; i <= maxEvidence; i++ {
var currentBytes int64 = 0
for currentBytes <= maxEvidenceBytes {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
currentBytes += int64(len(ev.Bytes()))
err := evidencePool.AddEvidenceFromConsensus(ev, time.Now(), state.Validators)
require.NoError(t, err)
}


+ 49
- 51
proto/tendermint/types/params.pb.go View File

@ -179,11 +179,10 @@ type EvidenceParams struct {
// mechanism for handling [Nothing-At-Stake
// attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed).
MaxAgeDuration time.Duration `protobuf:"bytes,2,opt,name=max_age_duration,json=maxAgeDuration,proto3,stdduration" json:"max_age_duration"`
// This sets the maximum number of evidence that can be committed in a single block.
// and should fall comfortably under the max block bytes when we consider the size of
// each evidence (See MaxEvidenceBytes). The maximum number is MaxEvidencePerBlock.
// Default is 50
MaxNum uint32 `protobuf:"varint,3,opt,name=max_num,json=maxNum,proto3" json:"max_num,omitempty"`
// This sets the maximum size of total evidence in bytes that can be committed in a single block.
// and should fall comfortably under the max block bytes.
// Default is 1048576 or 1MB
MaxBytes int64 `protobuf:"varint,3,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"`
}
func (m *EvidenceParams) Reset() { *m = EvidenceParams{} }
@ -233,9 +232,9 @@ func (m *EvidenceParams) GetMaxAgeDuration() time.Duration {
return 0
}
func (m *EvidenceParams) GetMaxNum() uint32 {
func (m *EvidenceParams) GetMaxBytes() int64 {
if m != nil {
return m.MaxNum
return m.MaxBytes
}
return 0
}
@ -398,42 +397,41 @@ func init() {
func init() { proto.RegisterFile("tendermint/types/params.proto", fileDescriptor_e12598271a686f57) }
var fileDescriptor_e12598271a686f57 = []byte{
// 545 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0x4f, 0x6f, 0xd3, 0x30,
0x1c, 0xad, 0xd7, 0xb2, 0xb5, 0xbf, 0xae, 0xeb, 0x64, 0x21, 0x51, 0x86, 0x96, 0x94, 0x1c, 0xd0,
0x24, 0xa4, 0x44, 0x82, 0x03, 0x62, 0x97, 0x89, 0xc0, 0x34, 0x10, 0xea, 0x84, 0x22, 0xe0, 0xb0,
0x4b, 0xe4, 0xb4, 0x26, 0x8b, 0x56, 0xc7, 0x51, 0x6c, 0x57, 0xed, 0xb7, 0xe0, 0xb8, 0xe3, 0x2e,
0x48, 0x7c, 0x04, 0x3e, 0xc2, 0x8e, 0x3b, 0x72, 0x02, 0xd4, 0x5e, 0xf8, 0x18, 0x28, 0x4e, 0x4d,
0xff, 0x6c, 0xb7, 0xe4, 0xf7, 0x7b, 0xef, 0xd9, 0xef, 0x3d, 0x19, 0xf6, 0x25, 0x4d, 0x07, 0x34,
0x67, 0x49, 0x2a, 0x3d, 0x39, 0xc9, 0xa8, 0xf0, 0x32, 0x92, 0x13, 0x26, 0xdc, 0x2c, 0xe7, 0x92,
0xe3, 0xdd, 0xc5, 0xda, 0xd5, 0xeb, 0xbd, 0xfb, 0x31, 0x8f, 0xb9, 0x5e, 0x7a, 0xc5, 0x57, 0x89,
0xdb, 0xb3, 0x62, 0xce, 0xe3, 0x21, 0xf5, 0xf4, 0x5f, 0xa4, 0xbe, 0x78, 0x03, 0x95, 0x13, 0x99,
0xf0, 0xb4, 0xdc, 0x3b, 0x97, 0x1b, 0xd0, 0x7e, 0xcd, 0x53, 0x41, 0x53, 0xa1, 0xc4, 0x07, 0x7d,
0x02, 0x7e, 0x09, 0xf7, 0xa2, 0x21, 0xef, 0x5f, 0x74, 0x50, 0x17, 0x1d, 0x34, 0x9f, 0xed, 0xbb,
0xeb, 0x67, 0xb9, 0x7e, 0xb1, 0x2e, 0xd1, 0x7e, 0xed, 0xfa, 0x97, 0x5d, 0x09, 0x4a, 0x06, 0xf6,
0xa1, 0x4e, 0x47, 0xc9, 0x80, 0xa6, 0x7d, 0xda, 0xd9, 0xd0, 0xec, 0xee, 0x6d, 0xf6, 0xf1, 0x1c,
0xb1, 0x22, 0xf0, 0x9f, 0x87, 0x8f, 0xa1, 0x31, 0x22, 0xc3, 0x64, 0x40, 0x24, 0xcf, 0x3b, 0x55,
0x2d, 0xf2, 0xf8, 0xb6, 0xc8, 0x67, 0x03, 0x59, 0x51, 0x59, 0x30, 0xf1, 0x11, 0x6c, 0x8d, 0x68,
0x2e, 0x12, 0x9e, 0x76, 0x6a, 0x5a, 0xc4, 0xbe, 0x43, 0xa4, 0x04, 0xac, 0x48, 0x18, 0x96, 0x43,
0xa1, 0xb9, 0xe4, 0x13, 0x3f, 0x82, 0x06, 0x23, 0xe3, 0x30, 0x9a, 0x48, 0x2a, 0x74, 0x32, 0xd5,
0xa0, 0xce, 0xc8, 0xd8, 0x2f, 0xfe, 0xf1, 0x03, 0xd8, 0x2a, 0x96, 0x31, 0x11, 0xda, 0x76, 0x35,
0xd8, 0x64, 0x64, 0x7c, 0x42, 0x04, 0xee, 0xc2, 0xb6, 0x4c, 0x18, 0x0d, 0x13, 0x2e, 0x49, 0xc8,
0x84, 0xf6, 0x53, 0x0d, 0xa0, 0x98, 0xbd, 0xe3, 0x92, 0xf4, 0x84, 0xf3, 0x0d, 0xc1, 0xce, 0x6a,
0x22, 0xf8, 0x29, 0xe0, 0x42, 0x8d, 0xc4, 0x34, 0x4c, 0x15, 0x0b, 0x75, 0xb4, 0xe6, 0xcc, 0x36,
0x23, 0xe3, 0x57, 0x31, 0x3d, 0x55, 0x4c, 0x5f, 0x4e, 0xe0, 0x1e, 0xec, 0x1a, 0xb0, 0xe9, 0x76,
0x1e, 0xfd, 0x43, 0xb7, 0x2c, 0xdf, 0x35, 0xe5, 0xbb, 0x6f, 0xe6, 0x00, 0xbf, 0x5e, 0x58, 0xbd,
0xfc, 0x6d, 0xa3, 0x60, 0xa7, 0xd4, 0x33, 0x1b, 0xe3, 0x24, 0x55, 0x4c, 0xdf, 0xb5, 0xa5, 0x9d,
0x9c, 0x2a, 0xe6, 0x1c, 0x41, 0x7b, 0x2d, 0x73, 0xec, 0x40, 0x2b, 0x53, 0x51, 0x78, 0x41, 0x27,
0xa1, 0xce, 0xb3, 0x83, 0xba, 0xd5, 0x83, 0x46, 0xd0, 0xcc, 0x54, 0xf4, 0x9e, 0x4e, 0x3e, 0x16,
0xa3, 0xc3, 0xfa, 0x8f, 0x2b, 0x1b, 0xfd, 0xbd, 0xb2, 0x91, 0x73, 0x08, 0xad, 0x95, 0xbc, 0xb1,
0x0d, 0x4d, 0x92, 0x65, 0xa1, 0x69, 0xa9, 0xf0, 0x57, 0x0b, 0x80, 0x64, 0xd9, 0x1c, 0xb6, 0xc4,
0x3d, 0x83, 0xed, 0xb7, 0x44, 0x9c, 0xd3, 0xc1, 0x9c, 0xfa, 0x04, 0xda, 0x3a, 0x95, 0x70, 0xbd,
0x92, 0x96, 0x1e, 0xf7, 0x4c, 0x2f, 0x0e, 0xb4, 0x16, 0xb8, 0x45, 0x3b, 0x4d, 0x83, 0x3a, 0x21,
0xc2, 0xff, 0xf4, 0x7d, 0x6a, 0xa1, 0xeb, 0xa9, 0x85, 0x6e, 0xa6, 0x16, 0xfa, 0x33, 0xb5, 0xd0,
0xd7, 0x99, 0x55, 0xb9, 0x99, 0x59, 0x95, 0x9f, 0x33, 0xab, 0x72, 0xf6, 0x22, 0x4e, 0xe4, 0xb9,
0x8a, 0xdc, 0x3e, 0x67, 0xde, 0xf2, 0x93, 0x5c, 0x7c, 0x96, 0x6f, 0x6e, 0xfd, 0xb9, 0x46, 0x9b,
0x7a, 0xfe, 0xfc, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x53, 0x0a, 0x6c, 0x0d, 0xc9, 0x03, 0x00,
0x00,
// 537 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0x31, 0x6f, 0xd3, 0x40,
0x18, 0xcd, 0xd5, 0xa5, 0x4d, 0xbe, 0x34, 0x4d, 0x75, 0x42, 0x22, 0x14, 0xd5, 0x0e, 0x1e, 0x50,
0x25, 0x24, 0x5b, 0x82, 0x01, 0xd1, 0xa5, 0xc2, 0x50, 0x15, 0x84, 0x82, 0x90, 0x05, 0x0c, 0x5d,
0xac, 0x73, 0x72, 0xb8, 0x56, 0x73, 0x3e, 0xcb, 0x77, 0x8e, 0x92, 0x7f, 0xc1, 0xd8, 0xb1, 0x23,
0xfc, 0x03, 0x7e, 0x42, 0xc7, 0x8e, 0x4c, 0x80, 0x92, 0x85, 0x9f, 0x81, 0x7c, 0xce, 0xe1, 0x38,
0x65, 0xf3, 0x7d, 0xdf, 0x7b, 0xef, 0xfc, 0xde, 0xd3, 0xc1, 0x81, 0xa4, 0xc9, 0x88, 0x66, 0x2c,
0x4e, 0xa4, 0x2b, 0x67, 0x29, 0x15, 0x6e, 0x4a, 0x32, 0xc2, 0x84, 0x93, 0x66, 0x5c, 0x72, 0xbc,
0x57, 0xad, 0x1d, 0xb5, 0xde, 0xbf, 0x1b, 0xf1, 0x88, 0xab, 0xa5, 0x5b, 0x7c, 0x95, 0xb8, 0x7d,
0x33, 0xe2, 0x3c, 0x1a, 0x53, 0x57, 0x9d, 0xc2, 0xfc, 0xb3, 0x3b, 0xca, 0x33, 0x22, 0x63, 0x9e,
0x94, 0x7b, 0xfb, 0x72, 0x03, 0xba, 0x2f, 0x79, 0x22, 0x68, 0x22, 0x72, 0xf1, 0x5e, 0xdd, 0x80,
0x9f, 0xc3, 0x9d, 0x70, 0xcc, 0x87, 0x17, 0x3d, 0xd4, 0x47, 0x87, 0xed, 0x27, 0x07, 0xce, 0xfa,
0x5d, 0x8e, 0x57, 0xac, 0x4b, 0xb4, 0xb7, 0x79, 0xfd, 0xd3, 0x6a, 0xf8, 0x25, 0x03, 0x7b, 0xd0,
0xa4, 0x93, 0x78, 0x44, 0x93, 0x21, 0xed, 0x6d, 0x28, 0x76, 0xff, 0x36, 0xfb, 0x64, 0x89, 0xa8,
0x09, 0xfc, 0xe3, 0xe1, 0x13, 0x68, 0x4d, 0xc8, 0x38, 0x1e, 0x11, 0xc9, 0xb3, 0x9e, 0xa1, 0x44,
0x1e, 0xde, 0x16, 0xf9, 0xa4, 0x21, 0x35, 0x95, 0x8a, 0x89, 0x8f, 0x61, 0x7b, 0x42, 0x33, 0x11,
0xf3, 0xa4, 0xb7, 0xa9, 0x44, 0xac, 0xff, 0x88, 0x94, 0x80, 0x9a, 0x84, 0x66, 0xd9, 0x14, 0xda,
0x2b, 0x3e, 0xf1, 0x03, 0x68, 0x31, 0x32, 0x0d, 0xc2, 0x99, 0xa4, 0x42, 0x25, 0x63, 0xf8, 0x4d,
0x46, 0xa6, 0x5e, 0x71, 0xc6, 0xf7, 0x60, 0xbb, 0x58, 0x46, 0x44, 0x28, 0xdb, 0x86, 0xbf, 0xc5,
0xc8, 0xf4, 0x94, 0x08, 0xdc, 0x87, 0x1d, 0x19, 0x33, 0x1a, 0xc4, 0x5c, 0x92, 0x80, 0x09, 0xe5,
0xc7, 0xf0, 0xa1, 0x98, 0xbd, 0xe1, 0x92, 0x0c, 0x84, 0xfd, 0x0d, 0xc1, 0x6e, 0x3d, 0x11, 0xfc,
0x18, 0x70, 0xa1, 0x46, 0x22, 0x1a, 0x24, 0x39, 0x0b, 0x54, 0xb4, 0xfa, 0xce, 0x2e, 0x23, 0xd3,
0x17, 0x11, 0x7d, 0x97, 0x33, 0xf5, 0x73, 0x02, 0x0f, 0x60, 0x4f, 0x83, 0x75, 0xb7, 0xcb, 0xe8,
0xef, 0x3b, 0x65, 0xf9, 0x8e, 0x2e, 0xdf, 0x79, 0xb5, 0x04, 0x78, 0xcd, 0xc2, 0xea, 0xe5, 0x2f,
0x0b, 0xf9, 0xbb, 0xa5, 0x9e, 0xde, 0xd4, 0x6d, 0x1a, 0x75, 0x9b, 0xf6, 0x31, 0x74, 0xd7, 0x72,
0xc7, 0x36, 0x74, 0xd2, 0x3c, 0x0c, 0x2e, 0xe8, 0x2c, 0x50, 0x99, 0xf6, 0x50, 0xdf, 0x38, 0x6c,
0xf9, 0xed, 0x34, 0x0f, 0xdf, 0xd2, 0xd9, 0x87, 0x62, 0x74, 0xd4, 0xfc, 0x7e, 0x65, 0xa1, 0x3f,
0x57, 0x16, 0xb2, 0x8f, 0xa0, 0x53, 0xcb, 0x1c, 0x5b, 0xd0, 0x26, 0x69, 0x1a, 0xe8, 0xa6, 0x0a,
0x8f, 0x9b, 0x3e, 0x90, 0x34, 0x5d, 0xc2, 0x56, 0xb8, 0x67, 0xb0, 0xf3, 0x9a, 0x88, 0x73, 0x3a,
0x5a, 0x52, 0x1f, 0x41, 0x57, 0x25, 0x13, 0xac, 0xd7, 0xd2, 0x51, 0xe3, 0x81, 0xee, 0xc6, 0x86,
0x4e, 0x85, 0xab, 0x1a, 0x6a, 0x6b, 0xd4, 0x29, 0x11, 0xde, 0xc7, 0xaf, 0x73, 0x13, 0x5d, 0xcf,
0x4d, 0x74, 0x33, 0x37, 0xd1, 0xef, 0xb9, 0x89, 0xbe, 0x2c, 0xcc, 0xc6, 0xcd, 0xc2, 0x6c, 0xfc,
0x58, 0x98, 0x8d, 0xb3, 0x67, 0x51, 0x2c, 0xcf, 0xf3, 0xd0, 0x19, 0x72, 0xe6, 0xae, 0x3e, 0xcb,
0xea, 0xb3, 0x7c, 0x77, 0xeb, 0x4f, 0x36, 0xdc, 0x52, 0xf3, 0xa7, 0x7f, 0x03, 0x00, 0x00, 0xff,
0xff, 0xfe, 0xe0, 0x3d, 0x9c, 0xcd, 0x03, 0x00, 0x00,
}
func (this *ConsensusParams) Equal(that interface{}) bool {
@ -524,7 +522,7 @@ func (this *EvidenceParams) Equal(that interface{}) bool {
if this.MaxAgeDuration != that1.MaxAgeDuration {
return false
}
if this.MaxNum != that1.MaxNum {
if this.MaxBytes != that1.MaxBytes {
return false
}
return true
@ -730,8 +728,8 @@ func (m *EvidenceParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.MaxNum != 0 {
i = encodeVarintParams(dAtA, i, uint64(m.MaxNum))
if m.MaxBytes != 0 {
i = encodeVarintParams(dAtA, i, uint64(m.MaxBytes))
i--
dAtA[i] = 0x18
}
@ -993,8 +991,8 @@ func (m *EvidenceParams) Size() (n int) {
}
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxAgeDuration)
n += 1 + l + sovParams(uint64(l))
if m.MaxNum != 0 {
n += 1 + sovParams(uint64(m.MaxNum))
if m.MaxBytes != 0 {
n += 1 + sovParams(uint64(m.MaxBytes))
}
return n
}
@ -1425,9 +1423,9 @@ func (m *EvidenceParams) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MaxNum", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field MaxBytes", wireType)
}
m.MaxNum = 0
m.MaxBytes = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowParams
@ -1437,7 +1435,7 @@ func (m *EvidenceParams) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.MaxNum |= uint32(b&0x7F) << shift
m.MaxBytes |= int64(b&0x7F) << shift
if b < 0x80 {
break
}


+ 4
- 5
proto/tendermint/types/params.proto View File

@ -48,11 +48,10 @@ message EvidenceParams {
google.protobuf.Duration max_age_duration = 2
[(gogoproto.nullable) = false, (gogoproto.stdduration) = true];
// This sets the maximum number of evidence that can be committed in a single block.
// and should fall comfortably under the max block bytes when we consider the size of
// each evidence (See MaxEvidenceBytes). The maximum number is MaxEvidencePerBlock.
// Default is 50
uint32 max_num = 3;
// This sets the maximum size of total evidence in bytes that can be committed in a single block.
// and should fall comfortably under the max block bytes.
// Default is 1048576 or 1MB
int64 max_bytes = 3;
}
// ValidatorParams restrict the public key types validators can use.


+ 2
- 2
state/execution.go View File

@ -100,10 +100,10 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
maxBytes := state.ConsensusParams.Block.MaxBytes
maxGas := state.ConsensusParams.Block.MaxGas
evidence := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxNum)
evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
// Fetch a limited amount of valid txs
maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))
maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size())
txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
return state.MakeBlock(height, txs, commit, evidence, proposerAddr)


+ 10
- 3
state/mocks/evidence_pool.go View File

@ -61,11 +61,11 @@ func (_m *EvidencePool) CheckEvidence(_a0 types.EvidenceList) error {
}
// PendingEvidence provides a mock function with given fields: _a0
func (_m *EvidencePool) PendingEvidence(_a0 uint32) []types.Evidence {
func (_m *EvidencePool) PendingEvidence(_a0 int64) ([]types.Evidence, int64) {
ret := _m.Called(_a0)
var r0 []types.Evidence
if rf, ok := ret.Get(0).(func(uint32) []types.Evidence); ok {
if rf, ok := ret.Get(0).(func(int64) []types.Evidence); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
@ -73,7 +73,14 @@ func (_m *EvidencePool) PendingEvidence(_a0 uint32) []types.Evidence {
}
}
return r0
var r1 int64
if rf, ok := ret.Get(1).(func(int64) int64); ok {
r1 = rf(_a0)
} else {
r1 = ret.Get(1).(int64)
}
return r0, r1
}
// Update provides a mock function with given fields: _a0


+ 4
- 2
state/services.go View File

@ -43,7 +43,7 @@ type BlockStore interface {
// EvidencePool defines the EvidencePool interface used by State.
type EvidencePool interface {
PendingEvidence(uint32) []types.Evidence
PendingEvidence(maxBytes int64) (ev []types.Evidence, size int64)
AddEvidence(types.Evidence) error
Update(State)
CheckEvidence(types.EvidenceList) error
@ -54,7 +54,9 @@ type EvidencePool interface {
// to the consensus evidence pool interface
type EmptyEvidencePool struct{}
func (EmptyEvidencePool) PendingEvidence(uint32) []types.Evidence { return nil }
func (EmptyEvidencePool) PendingEvidence(maxBytes int64) (ev []types.Evidence, size int64) {
return nil, 0
}
func (EmptyEvidencePool) AddEvidence(types.Evidence) error { return nil }
func (EmptyEvidencePool) Update(State) {}
func (EmptyEvidencePool) CheckEvidence(evList types.EvidenceList) error { return nil }


+ 1
- 2
state/tx_filter.go View File

@ -8,10 +8,9 @@ import (
// TxPreCheck returns a function to filter transactions before processing.
// The function limits the size of a transaction to the block's maximum data size.
func TxPreCheck(state State) mempl.PreCheckFunc {
maxDataBytes := types.MaxDataBytesUnknownEvidence(
maxDataBytes := types.MaxDataBytesNoEvidence(
state.ConsensusParams.Block.MaxBytes,
state.Validators.Size(),
state.ConsensusParams.Evidence.MaxNum,
)
return mempl.PreCheckMaxBytes(maxDataBytes)
}


+ 3
- 3
state/tx_filter_test.go View File

@ -17,7 +17,7 @@ import (
func TestTxFilter(t *testing.T) {
genDoc := randomGenesisDoc()
genDoc.ConsensusParams.Block.MaxBytes = 3000
genDoc.ConsensusParams.Evidence.MaxNum = 1
genDoc.ConsensusParams.Evidence.MaxBytes = 1500
// Max size of Txs is much smaller than size of block,
// since we need to account for commits and evidence.
@ -25,8 +25,8 @@ func TestTxFilter(t *testing.T) {
tx types.Tx
isErr bool
}{
{types.Tx(tmrand.Bytes(1680)), false},
{types.Tx(tmrand.Bytes(1853)), true},
{types.Tx(tmrand.Bytes(2154)), false},
{types.Tx(tmrand.Bytes(2155)), true},
{types.Tx(tmrand.Bytes(3000)), true},
}


+ 2
- 2
state/validation.go View File

@ -142,8 +142,8 @@ func validateBlock(evidencePool EvidencePool, state State, block *types.Block) e
block.Height, state.InitialHeight)
}
// Check evidence doesn't exceed the limit. MaxNumEvidence is capped at uint16, so conversion is always safe.
if max, got := int(state.ConsensusParams.Evidence.MaxNum), len(block.Evidence.Evidence); got > max {
// Check evidence doesn't exceed the limit amount of bytes.
if max, got := state.ConsensusParams.Evidence.MaxBytes, block.Evidence.ByteSize(); got > max {
return types.NewErrEvidenceOverflow(max, got)
}


+ 18
- 13
state/validation_test.go View File

@ -222,7 +222,7 @@ func TestValidateBlockEvidence(t *testing.T) {
evpool.On("ABCIEvidence", mock.AnythingOfType("int64"), mock.AnythingOfType("[]types.Evidence")).Return(
[]abci.Evidence{})
state.ConsensusParams.Evidence.MaxNum = 3
state.ConsensusParams.Evidence.MaxBytes = 1000
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
@ -234,17 +234,19 @@ func TestValidateBlockEvidence(t *testing.T) {
for height := int64(1); height < validationTestsStopHeight; height++ {
proposerAddr := state.Validators.GetProposer().Address
maxNumEvidence := state.ConsensusParams.Evidence.MaxNum
maxBytesEvidence := state.ConsensusParams.Evidence.MaxBytes
if height > 1 {
/*
A block with too much evidence fails
*/
require.True(t, maxNumEvidence > 2)
evidence := make([]types.Evidence, 0)
// one more than the maximum allowed evidence
for i := uint32(0); i <= maxNumEvidence; i++ {
evidence = append(evidence, types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(),
privVals[proposerAddr.String()], chainID))
var currentBytes int64 = 0
// more bytes than the maximum allowed for evidence
for currentBytes <= maxBytesEvidence {
newEv := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(),
privVals[proposerAddr.String()], chainID)
evidence = append(evidence, newEv)
currentBytes += int64(len(newEv.Bytes()))
}
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr)
err := blockExec.ValidateBlock(state, block)
@ -257,14 +259,17 @@ func TestValidateBlockEvidence(t *testing.T) {
/*
A good block with several pieces of good evidence passes
*/
require.True(t, maxNumEvidence > 2)
evidence := make([]types.Evidence, 0)
var currentBytes int64 = 0
// precisely the amount of allowed evidence
for i := int32(0); uint32(i) < maxNumEvidence; i++ {
// make different evidence for each validator
_, val := state.Validators.GetByIndex(i)
evidence = append(evidence, types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime,
privVals[val.Address.String()], chainID))
for {
newEv := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime,
privVals[proposerAddr.String()], chainID)
currentBytes += int64(len(newEv.Bytes()))
if currentBytes >= maxBytesEvidence {
break
}
evidence = append(evidence, newEv)
}
var err error


+ 23
- 11
types/block.go View File

@ -273,12 +273,12 @@ func BlockFromProto(bp *tmproto.Block) (*Block, error) {
// MaxDataBytes returns the maximum size of block's data.
//
// XXX: Panics on negative result.
func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 {
func MaxDataBytes(maxBytes, evidenceBytes int64, valsCount int) int64 {
maxDataBytes := maxBytes -
MaxOverheadForBlock -
MaxHeaderBytes -
int64(valsCount)*MaxVoteBytes -
int64(evidenceCount)*MaxEvidenceBytes
evidenceBytes
if maxDataBytes < 0 {
panic(fmt.Sprintf(
@ -292,18 +292,16 @@ func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 {
}
// MaxDataBytesUnknownEvidence returns the maximum size of block's data when
// MaxDataBytesNoEvidence returns the maximum size of block's data when
// evidence count is unknown. MaxEvidencePerBlock will be used for the size
// of evidence.
//
// XXX: Panics on negative result.
func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int, maxNumEvidence uint32) int64 {
maxEvidenceBytes := int64(maxNumEvidence) * MaxEvidenceBytes
func MaxDataBytesNoEvidence(maxBytes int64, valsCount int) int64 {
maxDataBytes := maxBytes -
MaxOverheadForBlock -
MaxHeaderBytes -
int64(valsCount)*MaxVoteBytes -
maxEvidenceBytes
int64(valsCount)*MaxVoteBytes
if maxDataBytes < 0 {
panic(fmt.Sprintf(
@ -1073,8 +1071,9 @@ func DataFromProto(dp *tmproto.Data) (Data, error) {
type EvidenceData struct {
Evidence EvidenceList `json:"evidence"`
// Volatile
hash tmbytes.HexBytes
// Volatile. Used as cache
hash tmbytes.HexBytes
byteSize int64
}
// Hash returns the hash of the data.
@ -1085,6 +1084,20 @@ func (data *EvidenceData) Hash() tmbytes.HexBytes {
return data.hash
}
// ByteSize returns the total byte size of all the evidence
func (data *EvidenceData) ByteSize() int64 {
if data.byteSize == 0 && len(data.Evidence) != 0 {
for _, ev := range data.Evidence {
pb, err := EvidenceToProto(ev)
if err != nil {
panic(err)
}
data.byteSize += int64(pb.Size())
}
}
return data.byteSize
}
// StringIndented returns a string representation of the evidence.
func (data *EvidenceData) StringIndented(indent string) string {
if data == nil {
@ -1142,11 +1155,10 @@ func (data *EvidenceData) FromProto(eviData *tmproto.EvidenceData) error {
return err
}
eviBzs[i] = evi
data.byteSize += int64(eviData.Evidence[i].Size())
}
data.Evidence = eviBzs
data.hash = eviData.GetHash()
return nil
}


+ 18
- 19
types/block_test.go View File

@ -401,7 +401,7 @@ func TestBlockMaxDataBytes(t *testing.T) {
testCases := []struct {
maxBytes int64
valsCount int
evidenceCount int
evidenceBytes int64
panics bool
result int64
}{
@ -416,43 +416,41 @@ func TestBlockMaxDataBytes(t *testing.T) {
tc := tc
if tc.panics {
assert.Panics(t, func() {
MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount)
MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount)
}, "#%v", i)
} else {
assert.Equal(t,
tc.result,
MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount),
MaxDataBytes(tc.maxBytes, tc.evidenceBytes, tc.valsCount),
"#%v", i)
}
}
}
func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
func TestBlockMaxDataBytesNoEvidence(t *testing.T) {
testCases := []struct {
maxBytes int64
maxEvidence uint32
valsCount int
panics bool
result int64
maxBytes int64
valsCount int
panics bool
result int64
}{
0: {-10, 0, 1, true, 0},
1: {10, 0, 1, true, 0},
2: {845, 0, 1, true, 0},
3: {846, 0, 1, false, 0},
4: {1290, 1, 1, false, 0},
5: {1291, 1, 1, false, 1},
0: {-10, 1, true, 0},
1: {10, 1, true, 0},
2: {845, 1, true, 0},
3: {846, 1, false, 0},
4: {847, 1, false, 1},
}
for i, tc := range testCases {
tc := tc
if tc.panics {
assert.Panics(t, func() {
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount, tc.maxEvidence)
MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount)
}, "#%v", i)
} else {
assert.Equal(t,
tc.result,
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount, tc.maxEvidence),
MaxDataBytesNoEvidence(tc.maxBytes, tc.valsCount),
"#%v", i)
}
}
@ -620,7 +618,7 @@ func TestBlockProtoBuf(t *testing.T) {
require.NoError(t, err, tc.msg)
require.EqualValues(t, tc.b1.Header, block.Header, tc.msg)
require.EqualValues(t, tc.b1.Data, block.Data, tc.msg)
require.EqualValues(t, tc.b1.Evidence, block.Evidence, tc.msg)
require.EqualValues(t, tc.b1.Evidence.Evidence, block.Evidence.Evidence, tc.msg)
require.EqualValues(t, *tc.b1.LastCommit, *block.LastCommit, tc.msg)
} else {
require.Error(t, err, tc.msg)
@ -653,6 +651,7 @@ func TestDataProtoBuf(t *testing.T) {
}
}
// TestEvidenceDataProtoBuf ensures parity in converting to and from proto.
func TestEvidenceDataProtoBuf(t *testing.T) {
val := NewMockPV()
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
@ -662,7 +661,7 @@ func TestEvidenceDataProtoBuf(t *testing.T) {
v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, time.Now())
ev := NewDuplicateVoteEvidence(v2, v)
data := &EvidenceData{Evidence: EvidenceList{ev}}
_ = data.Hash()
_ = data.ByteSize()
testCases := []struct {
msg string
data1 *EvidenceData


+ 5
- 10
types/evidence.go View File

@ -25,11 +25,6 @@ type Evidence interface {
String() string // string format of the evidence
}
const (
// MaxEvidenceBytes is a maximum size of any evidence (including amino overhead).
MaxEvidenceBytes int64 = 444
)
//--------------------------------------------------------------------------------------
// DuplicateVoteEvidence contains evidence a validator signed two conflicting
@ -365,20 +360,20 @@ func (err *ErrInvalidEvidence) Error() string {
return fmt.Sprintf("Invalid evidence: %v. Evidence: %v", err.Reason, err.Evidence)
}
// ErrEvidenceOverflow is for when there is too much evidence in a block.
// ErrEvidenceOverflow is for when there the amount of evidence exceeds the max bytes.
type ErrEvidenceOverflow struct {
MaxNum int
GotNum int
Max int64
Got int64
}
// NewErrEvidenceOverflow returns a new ErrEvidenceOverflow where got > max.
func NewErrEvidenceOverflow(max, got int) *ErrEvidenceOverflow {
func NewErrEvidenceOverflow(max, got int64) *ErrEvidenceOverflow {
return &ErrEvidenceOverflow{max, got}
}
// Error returns a string representation of the error.
func (err *ErrEvidenceOverflow) Error() string {
return fmt.Sprintf("Too much evidence: Max %d, got %d", err.MaxNum, err.GotNum)
return fmt.Sprintf("Too much evidence: Max %d, got %d", err.Max, err.Got)
}
//-------------------------------------------- MOCKING --------------------------------------


+ 0
- 31
types/evidence_test.go View File

@ -27,37 +27,6 @@ func TestEvidenceList(t *testing.T) {
assert.False(t, evl.Has(&DuplicateVoteEvidence{}))
}
func TestMaxEvidenceBytes(t *testing.T) {
val := NewMockPV()
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
maxTime := time.Date(9999, 0, 0, 0, 0, 0, 0, time.UTC)
const chainID = "mychain"
ev := &DuplicateVoteEvidence{
VoteA: makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, math.MaxInt64, blockID, maxTime),
VoteB: makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, math.MaxInt64, blockID2, maxTime),
}
//TODO: Add other types of evidence to test and set MaxEvidenceBytes accordingly
testCases := []struct {
testName string
evidence Evidence
}{
{"DuplicateVote", ev},
}
for _, tt := range testCases {
pb, err := EvidenceToProto(tt.evidence)
require.NoError(t, err, tt.testName)
bz, err := pb.Marshal()
require.NoError(t, err, tt.testName)
assert.LessOrEqual(t, int64(len(bz)), MaxEvidenceBytes, tt.testName)
}
}
func randomDuplicateVoteEvidence(t *testing.T) *DuplicateVoteEvidence {
val := NewMockPV()
blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))


+ 10
- 13
types/params.go View File

@ -19,9 +19,6 @@ const (
// MaxBlockPartsCount is the maximum number of block parts.
MaxBlockPartsCount = (MaxBlockSizeBytes / BlockPartSizeBytes) + 1
// Restrict the upper bound of the amount of evidence (uses uint16 for safe conversion)
MaxEvidencePerBlock = 65535
)
// DefaultConsensusParams returns a default ConsensusParams.
@ -48,7 +45,7 @@ func DefaultEvidenceParams() tmproto.EvidenceParams {
return tmproto.EvidenceParams{
MaxAgeNumBlocks: 100000, // 27.8 hrs at 1block/s
MaxAgeDuration: 48 * time.Hour,
MaxNum: 50,
MaxBytes: 1048576, // 1MB
}
}
@ -98,23 +95,23 @@ func ValidateConsensusParams(params tmproto.ConsensusParams) error {
}
if params.Evidence.MaxAgeNumBlocks <= 0 {
return fmt.Errorf("evidenceParams.MaxAgeNumBlocks must be greater than 0. Got %d",
return fmt.Errorf("evidence.MaxAgeNumBlocks must be greater than 0. Got %d",
params.Evidence.MaxAgeNumBlocks)
}
if params.Evidence.MaxAgeDuration <= 0 {
return fmt.Errorf("evidenceParams.MaxAgeDuration must be grater than 0 if provided, Got %v",
return fmt.Errorf("evidence.MaxAgeDuration must be grater than 0 if provided, Got %v",
params.Evidence.MaxAgeDuration)
}
if params.Evidence.MaxNum > MaxEvidencePerBlock {
return fmt.Errorf("evidenceParams.MaxNumEvidence is greater than upper bound, %d > %d",
params.Evidence.MaxNum, MaxEvidencePerBlock)
if params.Evidence.MaxBytes > params.Block.MaxBytes {
return fmt.Errorf("evidence.MaxBytesEvidence is greater than upper bound, %d > %d",
params.Evidence.MaxBytes, params.Block.MaxBytes)
}
if int64(params.Evidence.MaxNum)*MaxEvidenceBytes > params.Block.MaxBytes {
return fmt.Errorf("total possible evidence size is bigger than block.MaxBytes, %d > %d",
int64(params.Evidence.MaxNum)*MaxEvidenceBytes, params.Block.MaxBytes)
if params.Evidence.MaxBytes < 0 {
return fmt.Errorf("evidence.MaxBytes must be non negative. Got: %d",
params.Evidence.MaxBytes)
}
if len(params.Validator.PubKeyTypes) == 0 {
@ -174,7 +171,7 @@ func UpdateConsensusParams(params tmproto.ConsensusParams, params2 *abci.Consens
if params2.Evidence != nil {
res.Evidence.MaxAgeNumBlocks = params2.Evidence.MaxAgeNumBlocks
res.Evidence.MaxAgeDuration = params2.Evidence.MaxAgeDuration
res.Evidence.MaxNum = params2.Evidence.MaxNum
res.Evidence.MaxBytes = params2.Evidence.MaxBytes
}
if params2.Validator != nil {
// Copy params2.Validator.PubkeyTypes, and set result's value to the copy.


+ 4
- 4
types/params_test.go View File

@ -33,7 +33,7 @@ func TestConsensusParamsValidation(t *testing.T) {
8: {makeParams(1, 0, -10, 2, 0, valEd25519), false},
// test evidence params
9: {makeParams(1, 0, 10, 0, 0, valEd25519), false},
10: {makeParams(1, 0, 10, 2, 1, valEd25519), false},
10: {makeParams(1, 0, 10, 2, 2, valEd25519), false},
11: {makeParams(1000, 0, 10, 2, 1, valEd25519), true},
12: {makeParams(1, 0, 10, -1, 0, valEd25519), false},
// test no pubkey type provided
@ -54,7 +54,7 @@ func makeParams(
blockBytes, blockGas int64,
blockTimeIotaMs int64,
evidenceAge int64,
maxEvidence uint32,
maxEvidenceBytes int64,
pubkeyTypes []string,
) tmproto.ConsensusParams {
return tmproto.ConsensusParams{
@ -66,7 +66,7 @@ func makeParams(
Evidence: tmproto.EvidenceParams{
MaxAgeNumBlocks: evidenceAge,
MaxAgeDuration: time.Duration(evidenceAge),
MaxNum: maxEvidence,
MaxBytes: maxEvidenceBytes,
},
Validator: tmproto.ValidatorParams{
PubKeyTypes: pubkeyTypes,
@ -124,7 +124,7 @@ func TestConsensusParamsUpdate(t *testing.T) {
Evidence: &tmproto.EvidenceParams{
MaxAgeNumBlocks: 300,
MaxAgeDuration: time.Duration(300),
MaxNum: 50,
MaxBytes: 50,
},
Validator: &tmproto.ValidatorParams{
PubKeyTypes: valEd25519,


+ 1
- 1
types/part_set.go View File

@ -121,7 +121,7 @@ func (psh PartSetHeader) ValidateBasic() error {
return nil
}
// ToProto converts BloPartSetHeaderckID to protobuf
// ToProto converts PartSetHeader to protobuf
func (psh *PartSetHeader) ToProto() tmproto.PartSetHeader {
if psh == nil {
return tmproto.PartSetHeader{}


Loading…
Cancel
Save