types: remove nested evidence field from block (#7765)

* types: replaced EvidenceData in block structure with EvidenceList

* types: introduced toProto, fromProto functions to EvidenceList

* updated Changelog

* Removed comments from tests
This commit is contained in:
Jasmina Malicevic
2022-02-07 13:57:52 +01:00
committed by GitHub
parent a9fa2ac5f9
commit cd875c8a2c
13 changed files with 130 additions and 153 deletions

View File

@@ -44,7 +44,7 @@ type Block struct {
Header `json:"header"`
Data `json:"data"`
Evidence EvidenceData `json:"evidence"`
Evidence EvidenceList `json:"evidence"`
LastCommit *Commit `json:"last_commit"`
}
@@ -80,8 +80,8 @@ func (b *Block) ValidateBasic() error {
return fmt.Errorf("wrong Header.DataHash. Expected %X, got %X", w, g)
}
// NOTE: b.Evidence.Evidence may be nil, but we're just looping.
for i, ev := range b.Evidence.Evidence {
// NOTE: b.Evidence may be nil, but we're just looping.
for i, ev := range b.Evidence {
if err := ev.ValidateBasic(); err != nil {
return fmt.Errorf("invalid evidence (#%d): %v", i, err)
}
@@ -316,7 +316,7 @@ func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence)
Data: Data{
Txs: txs,
},
Evidence: EvidenceData{Evidence: evidence},
Evidence: evidence,
LastCommit: lastCommit,
}
block.fillHeader()
@@ -1083,97 +1083,6 @@ func DataFromProto(dp *tmproto.Data) (Data, error) {
return *data, nil
}
//-----------------------------------------------------------------------------
// EvidenceData contains any evidence of malicious wrong-doing by validators
type EvidenceData struct {
Evidence EvidenceList `json:"evidence"`
// Volatile. Used as cache
hash tmbytes.HexBytes
byteSize int64
}
// Hash returns the hash of the data.
func (data *EvidenceData) Hash() tmbytes.HexBytes {
if data.hash == nil {
data.hash = data.Evidence.Hash()
}
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 {
pb, err := data.ToProto()
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 {
return "nil-Evidence"
}
evStrings := make([]string, tmmath.MinInt(len(data.Evidence), 21))
for i, ev := range data.Evidence {
if i == 20 {
evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence))
break
}
evStrings[i] = fmt.Sprintf("Evidence:%v", ev)
}
return fmt.Sprintf(`EvidenceData{
%s %v
%s}#%v`,
indent, strings.Join(evStrings, "\n"+indent+" "),
indent, data.hash)
}
// ToProto converts EvidenceData to protobuf
func (data *EvidenceData) ToProto() (*tmproto.EvidenceList, error) {
if data == nil {
return nil, errors.New("nil evidence data")
}
evi := new(tmproto.EvidenceList)
eviBzs := make([]tmproto.Evidence, len(data.Evidence))
for i := range data.Evidence {
protoEvi, err := EvidenceToProto(data.Evidence[i])
if err != nil {
return nil, err
}
eviBzs[i] = *protoEvi
}
evi.Evidence = eviBzs
return evi, nil
}
// FromProto sets a protobuf EvidenceData to the given pointer.
func (data *EvidenceData) FromProto(eviData *tmproto.EvidenceList) error {
if eviData == nil {
return errors.New("nil evidenceData")
}
eviBzs := make(EvidenceList, len(eviData.Evidence))
for i := range eviData.Evidence {
evi, err := EvidenceFromProto(&eviData.Evidence[i])
if err != nil {
return err
}
eviBzs[i] = evi
}
data.Evidence = eviBzs
data.byteSize = int64(eviData.Size())
return nil
}
//--------------------------------------------------------------------------------
// BlockID

View File

@@ -52,7 +52,7 @@ func TestBlockAddEvidence(t *testing.T) {
block := MakeBlock(h, txs, commit, evList)
require.NotNil(t, block)
require.Equal(t, 1, len(block.Evidence.Evidence))
require.Equal(t, 1, len(block.Evidence))
require.NotNil(t, block.EvidenceHash)
}
@@ -109,7 +109,7 @@ func TestBlockValidateBasic(t *testing.T) {
}, true},
{"Invalid Evidence", func(blk *Block) {
emptyEv := &DuplicateVoteEvidence{}
blk.Evidence = EvidenceData{Evidence: []Evidence{emptyEv}}
blk.Evidence = []Evidence{emptyEv}
}, true},
}
for i, tc := range testCases {
@@ -700,7 +700,7 @@ func TestBlockProtoBuf(t *testing.T) {
evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
evi, err := NewMockDuplicateVoteEvidence(ctx, h, evidenceTime, "block-test-chain")
require.NoError(t, err)
b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}}
b2.Evidence = EvidenceList{evi}
b2.EvidenceHash = b2.Evidence.Hash()
b3 := MakeBlock(h, []Tx{}, c1, []Evidence{})
@@ -729,7 +729,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.Evidence, block.Evidence.Evidence, tc.msg)
require.EqualValues(t, tc.b1.Evidence, block.Evidence, tc.msg)
require.EqualValues(t, *tc.b1.LastCommit, *block.LastCommit, tc.msg)
} else {
require.Error(t, err, tc.msg)
@@ -760,46 +760,6 @@ func TestDataProtoBuf(t *testing.T) {
}
}
// TestEvidenceDataProtoBuf ensures parity in converting to and from proto.
func TestEvidenceDataProtoBuf(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const chainID = "mychain"
ev, err := NewMockDuplicateVoteEvidence(ctx, math.MaxInt64, time.Now(), chainID)
require.NoError(t, err)
data := &EvidenceData{Evidence: EvidenceList{ev}}
_ = data.ByteSize()
testCases := []struct {
msg string
data1 *EvidenceData
expPass1 bool
expPass2 bool
}{
{"success", data, true, true},
{"empty evidenceData", &EvidenceData{Evidence: EvidenceList{}}, true, true},
{"fail nil Data", nil, false, false},
}
for _, tc := range testCases {
protoData, err := tc.data1.ToProto()
if tc.expPass1 {
require.NoError(t, err, tc.msg)
} else {
require.Error(t, err, tc.msg)
}
eviD := new(EvidenceData)
err = eviD.FromProto(protoData)
if tc.expPass2 {
require.NoError(t, err, tc.msg)
require.Equal(t, tc.data1, eviD, tc.msg)
} else {
require.Error(t, err, tc.msg)
}
}
}
// exposed for testing
func MakeRandHeader() Header {
chainID := "test"

View File

@@ -15,6 +15,7 @@ import (
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/jsontypes"
tmmath "github.com/tendermint/tendermint/libs/math"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
@@ -554,6 +555,73 @@ func LightClientAttackEvidenceFromProto(lpb *tmproto.LightClientAttackEvidence)
// EvidenceList is a list of Evidence. Evidences is not a word.
type EvidenceList []Evidence
// StringIndented returns a string representation of the evidence.
func (evl EvidenceList) StringIndented(indent string) string {
if evl == nil {
return "nil-Evidence"
}
evStrings := make([]string, tmmath.MinInt(len(evl), 21))
for i, ev := range evl {
if i == 20 {
evStrings[i] = fmt.Sprintf("... (%v total)", len(evl))
break
}
evStrings[i] = fmt.Sprintf("Evidence:%v", ev)
}
return fmt.Sprintf(`EvidenceList{
%s %v
%s}#%v`,
indent, strings.Join(evStrings, "\n"+indent+" "),
indent, evl.Hash())
}
// ByteSize returns the total byte size of all the evidence
func (evl EvidenceList) ByteSize() int64 {
if len(evl) != 0 {
pb, err := evl.ToProto()
if err != nil {
panic(err)
}
return int64(pb.Size())
}
return 0
}
// FromProto sets a protobuf EvidenceList to the given pointer.
func (evl *EvidenceList) FromProto(eviList *tmproto.EvidenceList) error {
if eviList == nil {
return errors.New("nil evidence list")
}
eviBzs := make(EvidenceList, len(eviList.Evidence))
for i := range eviList.Evidence {
evi, err := EvidenceFromProto(&eviList.Evidence[i])
if err != nil {
return err
}
eviBzs[i] = evi
}
*evl = eviBzs
return nil
}
// ToProto converts EvidenceList to protobuf
func (evl *EvidenceList) ToProto() (*tmproto.EvidenceList, error) {
if evl == nil {
return nil, errors.New("nil evidence list")
}
eviBzs := make([]tmproto.Evidence, len(*evl))
for i, v := range *evl {
protoEvi, err := EvidenceToProto(v)
if err != nil {
return nil, err
}
eviBzs[i] = *protoEvi
}
return &tmproto.EvidenceList{Evidence: eviBzs}, nil
}
func (evl EvidenceList) MarshalJSON() ([]byte, error) {
lst := make([]json.RawMessage, len(evl))
for i, ev := range evl {

View File

@@ -33,6 +33,44 @@ func TestEvidenceList(t *testing.T) {
assert.False(t, evl.Has(&DuplicateVoteEvidence{}))
}
// TestEvidenceListProtoBuf to ensure parity in protobuf output and input
func TestEvidenceListProtoBuf(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const chainID = "mychain"
ev, err := NewMockDuplicateVoteEvidence(ctx, math.MaxInt64, time.Now(), chainID)
require.NoError(t, err)
data := EvidenceList{ev}
testCases := []struct {
msg string
data1 *EvidenceList
expPass1 bool
expPass2 bool
}{
{"success", &data, true, true},
{"empty evidenceData", &EvidenceList{}, true, true},
{"fail nil Data", nil, false, false},
}
for _, tc := range testCases {
protoData, err := tc.data1.ToProto()
if tc.expPass1 {
require.NoError(t, err, tc.msg)
} else {
require.Error(t, err, tc.msg)
}
eviD := new(EvidenceList)
err = eviD.FromProto(protoData)
if tc.expPass2 {
require.NoError(t, err, tc.msg)
require.Equal(t, tc.data1, eviD, tc.msg)
} else {
require.Error(t, err, tc.msg)
}
}
}
func randomDuplicateVoteEvidence(ctx context.Context, t *testing.T) *DuplicateVoteEvidence {
t.Helper()
val := NewMockPV()