evidence: cap evidence to an absolute number (#4780)

The number of evidence that can be committed in a single block is capped by a new evidence parameter called MaxNum
This commit is contained in:
Callum Waters
2020-05-11 15:28:08 +02:00
committed by GitHub
parent fed2502618
commit a620e5fd96
25 changed files with 130 additions and 99 deletions

View File

@@ -98,9 +98,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
maxBytes := state.ConsensusParams.Block.MaxBytes
maxGas := state.ConsensusParams.Block.MaxGas
// Fetch a limited amount of valid evidence
maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBytes)
evidence := blockExec.evpool.PendingEvidence(maxNumEvidence)
evidence := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxNum)
// Fetch a limited amount of valid txs
maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))

View File

@@ -57,11 +57,11 @@ func (_m *EvidencePool) IsPending(_a0 types.Evidence) bool {
}
// PendingEvidence provides a mock function with given fields: _a0
func (_m *EvidencePool) PendingEvidence(_a0 int64) []types.Evidence {
func (_m *EvidencePool) PendingEvidence(_a0 uint32) []types.Evidence {
ret := _m.Called(_a0)
var r0 []types.Evidence
if rf, ok := ret.Get(0).(func(int64) []types.Evidence); ok {
if rf, ok := ret.Get(0).(func(uint32) []types.Evidence); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {

View File

@@ -40,17 +40,18 @@ type BlockStore interface {
// EvidencePool defines the EvidencePool interface used by the ConsensusState.
// Get/Set/Commit
type EvidencePool interface {
PendingEvidence(int64) []types.Evidence
PendingEvidence(uint32) []types.Evidence
AddEvidence(types.Evidence) error
Update(*types.Block, State)
IsCommitted(types.Evidence) bool
IsPending(types.Evidence) bool
}
// MockEvidencePool is an empty implementation of EvidencePool, useful for testing.
type MockEvidencePool struct{}
func (me MockEvidencePool) PendingEvidence(int64) []types.Evidence { return nil }
func (me MockEvidencePool) AddEvidence(types.Evidence) error { return nil }
func (me MockEvidencePool) Update(*types.Block, State) {}
func (me MockEvidencePool) IsCommitted(types.Evidence) bool { return false }
func (me MockEvidencePool) IsPending(types.Evidence) bool { return false }
func (me MockEvidencePool) PendingEvidence(uint32) []types.Evidence { return nil }
func (me MockEvidencePool) AddEvidence(types.Evidence) error { return nil }
func (me MockEvidencePool) Update(*types.Block, State) {}
func (me MockEvidencePool) IsCommitted(types.Evidence) bool { return false }
func (me MockEvidencePool) IsPending(types.Evidence) bool { return false }

View File

@@ -11,6 +11,7 @@ func TxPreCheck(state State) mempl.PreCheckFunc {
maxDataBytes := types.MaxDataBytesUnknownEvidence(
state.ConsensusParams.Block.MaxBytes,
state.Validators.Size(),
state.ConsensusParams.Evidence.MaxNum,
)
return mempl.PreCheckAminoMaxBytes(maxDataBytes)
}

View File

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

View File

@@ -120,11 +120,10 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
}
// Limit the amount of evidence
maxNumEvidence, _ := types.MaxEvidencePerBlock(state.ConsensusParams.Block.MaxBytes)
numEvidence := int64(len(block.Evidence.Evidence))
if numEvidence > maxNumEvidence {
return types.NewErrEvidenceOverflow(maxNumEvidence, numEvidence)
numEvidence := len(block.Evidence.Evidence)
// MaxNumEvidence is capped at uint16, so conversion is always safe.
if maxEvidence := int(state.ConsensusParams.Evidence.MaxNum); numEvidence > maxEvidence {
return types.NewErrEvidenceOverflow(maxEvidence, numEvidence)
}
// Validate all evidence.

View File

@@ -216,16 +216,15 @@ func TestValidateBlockEvidence(t *testing.T) {
for height := int64(1); height < validationTestsStopHeight; height++ {
proposerAddr := state.Validators.GetProposer().Address
goodEvidence := types.NewMockEvidence(height, time.Now(), proposerAddr)
maxNumEvidence := state.ConsensusParams.Evidence.MaxNum
if height > 1 {
/*
A block with too much evidence fails
*/
maxBlockSize := state.ConsensusParams.Block.MaxBytes
maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBlockSize)
require.True(t, maxNumEvidence > 2)
evidence := make([]types.Evidence, 0)
// one more than the maximum allowed evidence
for i := int64(0); i <= maxNumEvidence; i++ {
for i := uint32(0); i <= maxNumEvidence; i++ {
evidence = append(evidence, goodEvidence)
}
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr)
@@ -237,12 +236,10 @@ func TestValidateBlockEvidence(t *testing.T) {
/*
A good block with several pieces of good evidence passes
*/
maxBlockSize := state.ConsensusParams.Block.MaxBytes
maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBlockSize)
require.True(t, maxNumEvidence > 2)
evidence := make([]types.Evidence, 0)
// precisely the amount of allowed evidence
for i := int64(0); i < maxNumEvidence; i++ {
for i := uint32(0); i < maxNumEvidence; i++ {
evidence = append(evidence, goodEvidence)
}