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
+2 -2
View File
@@ -253,8 +253,8 @@ func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 {
// of evidence.
//
// XXX: Panics on negative result.
func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 {
_, maxEvidenceBytes := MaxEvidencePerBlock(maxBytes)
func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int, maxNumEvidence uint32) int64 {
maxEvidenceBytes := int64(maxNumEvidence) * MaxEvidenceBytes
maxDataBytes := maxBytes -
MaxAminoOverheadForBlock -
MaxHeaderBytes -
+13 -11
View File
@@ -399,28 +399,30 @@ func TestBlockMaxDataBytes(t *testing.T) {
func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
testCases := []struct {
maxBytes int64
valsCount int
panics bool
result int64
maxBytes int64
maxEvidence uint32
valsCount int
panics bool
result int64
}{
0: {-10, 1, true, 0},
1: {10, 1, true, 0},
2: {961, 1, true, 0},
3: {962, 1, false, 0},
4: {963, 1, false, 1},
0: {-10, 0, 1, true, 0},
1: {10, 0, 1, true, 0},
2: {865, 0, 1, true, 0},
3: {866, 0, 1, false, 0},
4: {1310, 1, 1, false, 0},
5: {1311, 1, 1, false, 1},
}
for i, tc := range testCases {
tc := tc
if tc.panics {
assert.Panics(t, func() {
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount)
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount, tc.maxEvidence)
}, "#%v", i)
} else {
assert.Equal(t,
tc.result,
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount),
MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount, tc.maxEvidence),
"#%v", i)
}
}
+3 -18
View File
@@ -48,12 +48,12 @@ func (err *ErrEvidenceInvalid) Error() string {
// ErrEvidenceOverflow is for when there is too much evidence in a block.
type ErrEvidenceOverflow struct {
MaxNum int64
GotNum int64
MaxNum int
GotNum int
}
// NewErrEvidenceOverflow returns a new ErrEvidenceOverflow where got > max.
func NewErrEvidenceOverflow(max, got int64) *ErrEvidenceOverflow {
func NewErrEvidenceOverflow(max, got int) *ErrEvidenceOverflow {
return &ErrEvidenceOverflow{max, got}
}
@@ -97,21 +97,6 @@ func RegisterMockEvidences(cdc *amino.Codec) {
cdc.RegisterConcrete(MockRandomEvidence{}, "tendermint/MockRandomEvidence", nil)
}
const (
MaxEvidenceBytesDenominator = 10
)
// MaxEvidencePerBlock returns the maximum number of evidences
// allowed in the block and their maximum total size (limitted to 1/10th
// of the maximum block size).
// TODO: change to a constant, or to a fraction of the validator set size.
// See https://github.com/tendermint/tendermint/issues/2590
func MaxEvidencePerBlock(blockMaxBytes int64) (int64, int64) {
maxBytes := blockMaxBytes / MaxEvidenceBytesDenominator
maxNum := maxBytes / MaxEvidenceBytes
return maxNum, maxBytes
}
//-------------------------------------------
// DuplicateVoteEvidence contains evidence a validator signed two conflicting
+21
View File
@@ -19,6 +19,9 @@ 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
)
// ConsensusParams contains consensus critical parameters that determine the
@@ -67,6 +70,12 @@ 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 `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 `json:"max_num"`
}
// ValidatorParams restrict the public key types validators can use.
@@ -98,6 +107,7 @@ func DefaultEvidenceParams() EvidenceParams {
return EvidenceParams{
MaxAgeNumBlocks: 100000, // 27.8 hrs at 1block/s
MaxAgeDuration: 48 * time.Hour,
MaxNum: 50,
}
}
@@ -148,6 +158,16 @@ func (params *ConsensusParams) Validate() error {
params.Evidence.MaxAgeDuration)
}
if params.Evidence.MaxNum > MaxEvidencePerBlock {
return errors.Errorf("evidenceParams.MaxNumEvidence is greater than upper bound, %d > %d",
params.Evidence.MaxNum, MaxEvidencePerBlock)
}
if int64(params.Evidence.MaxNum)*MaxEvidenceBytes > params.Block.MaxBytes {
return errors.Errorf("total possible evidence size is bigger than block.MaxBytes, %d > %d",
int64(params.Evidence.MaxNum)*MaxEvidenceBytes, params.Block.MaxBytes)
}
if len(params.Validator.PubKeyTypes) == 0 {
return errors.New("len(Validator.PubKeyTypes) must be greater than 0")
}
@@ -204,6 +224,7 @@ func (params ConsensusParams) Update(params2 *abci.ConsensusParams) ConsensusPar
if params2.Evidence != nil {
res.Evidence.MaxAgeNumBlocks = params2.Evidence.MaxAgeNumBlocks
res.Evidence.MaxAgeDuration = params2.Evidence.MaxAgeDuration
res.Evidence.MaxNum = params2.Evidence.MaxNumEvidence
}
if params2.Validator != nil {
// Copy params2.Validator.PubkeyTypes, and set result's value to the copy.
+30 -25
View File
@@ -22,22 +22,24 @@ func TestConsensusParamsValidation(t *testing.T) {
valid bool
}{
// test block params
0: {makeParams(1, 0, 10, 1, valEd25519), true},
1: {makeParams(0, 0, 10, 1, valEd25519), false},
2: {makeParams(47*1024*1024, 0, 10, 1, valEd25519), true},
3: {makeParams(10, 0, 10, 1, valEd25519), true},
4: {makeParams(100*1024*1024, 0, 10, 1, valEd25519), true},
5: {makeParams(101*1024*1024, 0, 10, 1, valEd25519), false},
6: {makeParams(1024*1024*1024, 0, 10, 1, valEd25519), false},
7: {makeParams(1024*1024*1024, 0, 10, -1, valEd25519), false},
8: {makeParams(1, 0, -10, 1, valEd25519), false},
0: {makeParams(1, 0, 10, 1, 0, valEd25519), true},
1: {makeParams(0, 0, 10, 1, 0, valEd25519), false},
2: {makeParams(47*1024*1024, 0, 10, 1, 0, valEd25519), true},
3: {makeParams(10, 0, 10, 1, 0, valEd25519), true},
4: {makeParams(100*1024*1024, 0, 10, 1, 0, valEd25519), true},
5: {makeParams(101*1024*1024, 0, 10, 1, 0, valEd25519), false},
6: {makeParams(1024*1024*1024, 0, 10, 1, 0, valEd25519), false},
7: {makeParams(1024*1024*1024, 0, 10, -1, 0, valEd25519), false},
8: {makeParams(1, 0, -10, 1, 0, valEd25519), false},
// test evidence params
9: {makeParams(1, 0, 10, 0, valEd25519), false},
10: {makeParams(1, 0, 10, -1, valEd25519), false},
9: {makeParams(1, 0, 10, 0, 0, valEd25519), false},
10: {makeParams(1, 0, 10, 1, 1, valEd25519), false},
11: {makeParams(1000, 0, 10, 1, 1, valEd25519), true},
12: {makeParams(1, 0, 10, -1, 0, valEd25519), false},
// test no pubkey type provided
11: {makeParams(1, 0, 10, 1, []string{}), false},
13: {makeParams(1, 0, 10, 1, 0, []string{}), false},
// test invalid pubkey type provided
12: {makeParams(1, 0, 10, 1, []string{"potatoes make good pubkeys"}), false},
14: {makeParams(1, 0, 10, 1, 0, []string{"potatoes make good pubkeys"}), false},
}
for i, tc := range testCases {
if tc.valid {
@@ -52,6 +54,7 @@ func makeParams(
blockBytes, blockGas int64,
blockTimeIotaMs int64,
evidenceAge int64,
maxEvidence uint32,
pubkeyTypes []string,
) ConsensusParams {
return ConsensusParams{
@@ -63,6 +66,7 @@ func makeParams(
Evidence: EvidenceParams{
MaxAgeNumBlocks: evidenceAge,
MaxAgeDuration: time.Duration(evidenceAge),
MaxNum: maxEvidence,
},
Validator: ValidatorParams{
PubKeyTypes: pubkeyTypes,
@@ -72,14 +76,14 @@ func makeParams(
func TestConsensusParamsHash(t *testing.T) {
params := []ConsensusParams{
makeParams(4, 2, 10, 3, valEd25519),
makeParams(1, 4, 10, 3, valEd25519),
makeParams(1, 2, 10, 4, valEd25519),
makeParams(2, 5, 10, 7, valEd25519),
makeParams(1, 7, 10, 6, valEd25519),
makeParams(9, 5, 10, 4, valEd25519),
makeParams(7, 8, 10, 9, valEd25519),
makeParams(4, 6, 10, 5, valEd25519),
makeParams(4, 2, 10, 3, 1, valEd25519),
makeParams(1, 4, 10, 3, 1, valEd25519),
makeParams(1, 2, 10, 4, 1, valEd25519),
makeParams(2, 5, 10, 7, 1, valEd25519),
makeParams(1, 7, 10, 6, 1, valEd25519),
makeParams(9, 5, 10, 4, 1, valEd25519),
makeParams(7, 8, 10, 9, 1, valEd25519),
makeParams(4, 6, 10, 5, 1, valEd25519),
}
hashes := make([][]byte, len(params))
@@ -105,13 +109,13 @@ func TestConsensusParamsUpdate(t *testing.T) {
}{
// empty updates
{
makeParams(1, 2, 10, 3, valEd25519),
makeParams(1, 2, 10, 3, 0, valEd25519),
&abci.ConsensusParams{},
makeParams(1, 2, 10, 3, valEd25519),
makeParams(1, 2, 10, 3, 0, valEd25519),
},
// fine updates
{
makeParams(1, 2, 10, 3, valEd25519),
makeParams(1, 2, 10, 3, 0, valEd25519),
&abci.ConsensusParams{
Block: &abci.BlockParams{
MaxBytes: 100,
@@ -120,12 +124,13 @@ func TestConsensusParamsUpdate(t *testing.T) {
Evidence: &abci.EvidenceParams{
MaxAgeNumBlocks: 300,
MaxAgeDuration: time.Duration(300),
MaxNumEvidence: 50,
},
Validator: &abci.ValidatorParams{
PubKeyTypes: valSecp256k1,
},
},
makeParams(100, 200, 10, 300, valSecp256k1),
makeParams(100, 200, 10, 300, 50, valSecp256k1),
},
}
for _, tc := range testCases {
+1
View File
@@ -139,6 +139,7 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams {
Evidence: &abci.EvidenceParams{
MaxAgeNumBlocks: params.Evidence.MaxAgeNumBlocks,
MaxAgeDuration: params.Evidence.MaxAgeDuration,
MaxNumEvidence: params.Evidence.MaxNum,
},
Validator: &abci.ValidatorParams{
PubKeyTypes: params.Validator.PubKeyTypes,