mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-06 13:26:23 +00:00
proto: add more to/from (#4956)
## Description adding in some more to/from methods/functions Closes: #XXX
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmmerkle "github.com/tendermint/tendermint/proto/crypto/merkle"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,8 +24,8 @@ const (
|
||||
// everything. This also affects the generalized proof system as
|
||||
// well.
|
||||
type SimpleProof struct {
|
||||
Total int `json:"total"` // Total number of items.
|
||||
Index int `json:"index"` // Index of item to prove.
|
||||
Total int64 `json:"total"` // Total number of items.
|
||||
Index int64 `json:"index"` // Index of item to prove.
|
||||
LeafHash []byte `json:"leaf_hash"` // Hash of item value.
|
||||
Aunts [][]byte `json:"aunts"` // Hashes from leaf's sibling to a root's child.
|
||||
}
|
||||
@@ -37,8 +38,8 @@ func SimpleProofsFromByteSlices(items [][]byte) (rootHash []byte, proofs []*Simp
|
||||
proofs = make([]*SimpleProof, len(items))
|
||||
for i, trail := range trails {
|
||||
proofs[i] = &SimpleProof{
|
||||
Total: len(items),
|
||||
Index: i,
|
||||
Total: int64(len(items)),
|
||||
Index: int64(i),
|
||||
LeafHash: trail.Hash,
|
||||
Aunts: trail.FlattenAunts(),
|
||||
}
|
||||
@@ -115,10 +116,38 @@ func (sp *SimpleProof) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sp *SimpleProof) ToProto() *tmmerkle.SimpleProof {
|
||||
if sp == nil {
|
||||
return nil
|
||||
}
|
||||
pb := new(tmmerkle.SimpleProof)
|
||||
|
||||
pb.Total = sp.Total
|
||||
pb.Index = sp.Index
|
||||
pb.LeafHash = sp.LeafHash
|
||||
pb.Aunts = sp.Aunts
|
||||
|
||||
return pb
|
||||
}
|
||||
|
||||
func SimpleProofFromProto(pb *tmmerkle.SimpleProof) (*SimpleProof, error) {
|
||||
if pb == nil {
|
||||
return nil, errors.New("nil proof")
|
||||
}
|
||||
sp := new(SimpleProof)
|
||||
|
||||
sp.Total = pb.Total
|
||||
sp.Index = pb.Index
|
||||
sp.LeafHash = pb.LeafHash
|
||||
sp.Aunts = pb.Aunts
|
||||
|
||||
return sp, sp.ValidateBasic()
|
||||
}
|
||||
|
||||
// Use the leafHash and innerHashes to get the root merkle hash.
|
||||
// If the length of the innerHashes slice isn't exactly correct, the result is nil.
|
||||
// Recursive impl.
|
||||
func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][]byte) []byte {
|
||||
func computeHashFromAunts(index, total int64, leafHash []byte, innerHashes [][]byte) []byte {
|
||||
if index >= total || index < 0 || total <= 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -192,7 +221,7 @@ func trailsFromByteSlices(items [][]byte) (trails []*SimpleProofNode, root *Simp
|
||||
trail := &SimpleProofNode{leafHash(items[0]), nil, nil, nil}
|
||||
return []*SimpleProofNode{trail}, trail
|
||||
default:
|
||||
k := getSplitPoint(len(items))
|
||||
k := getSplitPoint(int64(len(items)))
|
||||
lefts, leftRoot := trailsFromByteSlices(items[:k])
|
||||
rights, rightRoot := trailsFromByteSlices(items[k:])
|
||||
rootHash := innerHash(leftRoot.Hash, rightRoot.Hash)
|
||||
|
||||
@@ -13,7 +13,7 @@ func SimpleHashFromByteSlices(items [][]byte) []byte {
|
||||
case 1:
|
||||
return leafHash(items[0])
|
||||
default:
|
||||
k := getSplitPoint(len(items))
|
||||
k := getSplitPoint(int64(len(items)))
|
||||
left := SimpleHashFromByteSlices(items[:k])
|
||||
right := SimpleHashFromByteSlices(items[k:])
|
||||
return innerHash(left, right)
|
||||
@@ -92,13 +92,13 @@ func SimpleHashFromByteSlicesIterative(input [][]byte) []byte {
|
||||
}
|
||||
|
||||
// getSplitPoint returns the largest power of 2 less than length
|
||||
func getSplitPoint(length int) int {
|
||||
func getSplitPoint(length int64) int64 {
|
||||
if length < 1 {
|
||||
panic("Trying to split a tree with size < 1")
|
||||
}
|
||||
uLength := uint(length)
|
||||
bitlen := bits.Len(uLength)
|
||||
k := 1 << uint(bitlen-1)
|
||||
k := int64(1 << uint(bitlen-1))
|
||||
if k == length {
|
||||
k >>= 1
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ func TestSimpleProof(t *testing.T) {
|
||||
proof := proofs[i]
|
||||
|
||||
// Check total/index
|
||||
require.Equal(t, proof.Index, i, "Unmatched indicies: %d vs %d", proof.Index, i)
|
||||
require.EqualValues(t, proof.Index, i, "Unmatched indicies: %d vs %d", proof.Index, i)
|
||||
|
||||
require.Equal(t, proof.Total, total, "Unmatched totals: %d vs %d", proof.Total, total)
|
||||
require.EqualValues(t, proof.Total, total, "Unmatched totals: %d vs %d", proof.Total, total)
|
||||
|
||||
// Verify success
|
||||
err := proof.Verify(rootHash, item)
|
||||
@@ -108,7 +108,7 @@ func BenchmarkSimpleHashAlternatives(b *testing.B) {
|
||||
|
||||
func Test_getSplitPoint(t *testing.T) {
|
||||
tests := []struct {
|
||||
length int
|
||||
length int64
|
||||
want int
|
||||
}{
|
||||
{1, 0},
|
||||
@@ -125,6 +125,6 @@ func Test_getSplitPoint(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := getSplitPoint(tt.length)
|
||||
require.Equal(t, tt.want, got, "getSplitPoint(%d) = %v, want %v", tt.length, got, tt.want)
|
||||
require.EqualValues(t, tt.want, got, "getSplitPoint(%d) = %v, want %v", tt.length, got, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
139
types/block.go
139
types/block.go
@@ -202,6 +202,58 @@ func (b *Block) StringShort() string {
|
||||
return fmt.Sprintf("Block#%v", b.Hash())
|
||||
}
|
||||
|
||||
// ToProto converts Block to protobuf
|
||||
func (b *Block) ToProto() (*tmproto.Block, error) {
|
||||
if b == nil {
|
||||
return nil, errors.New("nil Block")
|
||||
}
|
||||
|
||||
pb := new(tmproto.Block)
|
||||
|
||||
pb.Header = *b.Header.ToProto()
|
||||
pb.LastCommit = b.LastCommit.ToProto()
|
||||
pb.Data = b.Data.ToProto()
|
||||
|
||||
protoEvidence, err := b.Evidence.ToProto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pb.Evidence = *protoEvidence
|
||||
|
||||
return pb, nil
|
||||
}
|
||||
|
||||
// FromProto sets a protobuf Block to the given pointer.
|
||||
// It returns an error if the block is invalid.
|
||||
func BlockFromProto(bp *tmproto.Block) (*Block, error) {
|
||||
if bp == nil {
|
||||
return nil, errors.New("nil block")
|
||||
}
|
||||
|
||||
b := new(Block)
|
||||
h, err := HeaderFromProto(&bp.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Header = h
|
||||
data, err := DataFromProto(&bp.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Data = data
|
||||
b.Evidence.FromProto(&bp.Evidence)
|
||||
|
||||
if bp.LastCommit != nil {
|
||||
lc, err := CommitFromProto(bp.LastCommit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.LastCommit = lc
|
||||
}
|
||||
|
||||
return b, b.ValidateBasic()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// These methods are for Protobuf Compatibility
|
||||
|
||||
@@ -1050,6 +1102,48 @@ func (data *Data) StringIndented(indent string) string {
|
||||
indent, data.hash)
|
||||
}
|
||||
|
||||
// ToProto converts Data to protobuf
|
||||
func (data *Data) ToProto() tmproto.Data {
|
||||
tp := new(tmproto.Data)
|
||||
|
||||
if len(data.Txs) > 0 {
|
||||
txBzs := make([][]byte, len(data.Txs))
|
||||
for i := range data.Txs {
|
||||
txBzs[i] = data.Txs[i]
|
||||
}
|
||||
tp.Txs = txBzs
|
||||
}
|
||||
|
||||
if data.hash != nil {
|
||||
tp.Hash = data.hash
|
||||
}
|
||||
|
||||
return *tp
|
||||
}
|
||||
|
||||
// DataFromProto takes a protobud representation of Data &
|
||||
// returns the native type.
|
||||
func DataFromProto(dp *tmproto.Data) (Data, error) {
|
||||
if dp == nil {
|
||||
return Data{}, errors.New("nil data")
|
||||
}
|
||||
data := new(Data)
|
||||
|
||||
if len(dp.Txs) > 0 {
|
||||
txBzs := make(Txs, len(dp.Txs))
|
||||
for i := range dp.Txs {
|
||||
txBzs[i] = Tx(dp.Txs[i])
|
||||
}
|
||||
data.Txs = txBzs
|
||||
} else {
|
||||
data.Txs = Txs{}
|
||||
}
|
||||
|
||||
data.hash = dp.Hash
|
||||
|
||||
return *data, nil
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// EvidenceData contains any evidence of malicious wrong-doing by validators
|
||||
@@ -1088,6 +1182,51 @@ func (data *EvidenceData) StringIndented(indent string) string {
|
||||
indent, data.hash)
|
||||
}
|
||||
|
||||
// ToProto converts EvidenceData to protobuf
|
||||
func (data *EvidenceData) ToProto() (*tmproto.EvidenceData, error) {
|
||||
if data == nil {
|
||||
return nil, errors.New("nil evidence data")
|
||||
}
|
||||
|
||||
evi := new(tmproto.EvidenceData)
|
||||
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
|
||||
|
||||
if data.hash != nil {
|
||||
evi.Hash = data.hash
|
||||
}
|
||||
|
||||
return evi, nil
|
||||
}
|
||||
|
||||
// FromProto sets a protobuf EvidenceData to the given pointer.
|
||||
func (data *EvidenceData) FromProto(eviData *tmproto.EvidenceData) 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.hash = eviData.GetHash()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// BlockID
|
||||
|
||||
@@ -2,7 +2,10 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
)
|
||||
|
||||
// BlockMeta contains meta information.
|
||||
@@ -23,6 +26,45 @@ func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
||||
}
|
||||
}
|
||||
|
||||
func (bm *BlockMeta) ToProto() *tmproto.BlockMeta {
|
||||
if bm == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pb := &tmproto.BlockMeta{
|
||||
BlockID: bm.BlockID.ToProto(),
|
||||
BlockSize: int64(bm.BlockSize),
|
||||
Header: *bm.Header.ToProto(),
|
||||
NumTxs: int64(bm.NumTxs),
|
||||
}
|
||||
return pb
|
||||
}
|
||||
|
||||
func BlockMetaFromProto(pb *tmproto.BlockMeta) (*BlockMeta, error) {
|
||||
if pb == nil {
|
||||
return nil, errors.New("blockmeta is empty")
|
||||
}
|
||||
|
||||
bm := new(BlockMeta)
|
||||
|
||||
bi, err := BlockIDFromProto(&pb.BlockID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h, err := HeaderFromProto(&pb.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bm.BlockID = *bi
|
||||
bm.BlockSize = int(pb.BlockSize)
|
||||
bm.Header = h
|
||||
bm.NumTxs = int(pb.NumTxs)
|
||||
|
||||
return bm, bm.ValidateBasic()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// These methods are for Protobuf Compatibility
|
||||
|
||||
|
||||
@@ -630,6 +630,75 @@ func makeRandHeader() Header {
|
||||
return h
|
||||
}
|
||||
|
||||
func TestBlockProtoBuf(t *testing.T) {
|
||||
h := tmrand.Int63()
|
||||
c1 := randCommit(time.Now())
|
||||
b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, &Commit{Signatures: []CommitSig{}}, []Evidence{})
|
||||
b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize)
|
||||
b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{})
|
||||
b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize)
|
||||
evi := NewMockEvidence(b2.Height, time.Now(), tmrand.Bytes(32))
|
||||
b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}}
|
||||
b2.EvidenceHash = b2.Evidence.Hash()
|
||||
b3 := MakeBlock(h, []Tx{}, c1, []Evidence{})
|
||||
b3.ProposerAddress = tmrand.Bytes(crypto.AddressSize)
|
||||
testCases := []struct {
|
||||
msg string
|
||||
b1 *Block
|
||||
expPass bool
|
||||
expPass2 bool
|
||||
}{
|
||||
{"nil block", nil, false, false},
|
||||
{"b1", b1, true, true},
|
||||
{"b2", b2, true, true},
|
||||
{"b3", b3, true, true},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
pb, err := tc.b1.ToProto()
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.msg)
|
||||
} else {
|
||||
require.Error(t, err, tc.msg)
|
||||
}
|
||||
block, err := BlockFromProto(pb)
|
||||
if tc.expPass2 {
|
||||
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.LastCommit, *block.LastCommit, tc.msg)
|
||||
} else {
|
||||
require.Error(t, err, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataProtoBuf(t *testing.T) {
|
||||
data := &Data{Txs: Txs{Tx([]byte{1}), Tx([]byte{2}), Tx([]byte{3})}}
|
||||
_ = data.Hash()
|
||||
data2 := &Data{Txs: Txs{}}
|
||||
_ = data2.Hash()
|
||||
|
||||
testCases := []struct {
|
||||
msg string
|
||||
data1 *Data
|
||||
expPass bool
|
||||
}{
|
||||
{"success", data, true},
|
||||
{"success data2", data2, true},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
protoData := tc.data1.ToProto()
|
||||
d, err := DataFromProto(&protoData)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.msg)
|
||||
require.EqualValues(t, tc.data1, &d, tc.msg)
|
||||
} else {
|
||||
require.Error(t, err, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderProto(t *testing.T) {
|
||||
h1 := makeRandHeader()
|
||||
tc := []struct {
|
||||
@@ -710,6 +779,45 @@ func TestSignedHeaderProtoBuf(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvidenceDataProtoBuf(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")))
|
||||
const chainID = "mychain"
|
||||
v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, time.Now())
|
||||
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()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestCommitProtoBuf(t *testing.T) {
|
||||
commit := randCommit(time.Now())
|
||||
|
||||
|
||||
@@ -51,6 +51,37 @@ func (part *Part) StringIndented(indent string) string {
|
||||
indent)
|
||||
}
|
||||
|
||||
func (part *Part) ToProto() (*tmproto.Part, error) {
|
||||
if part == nil {
|
||||
return nil, errors.New("nil part")
|
||||
}
|
||||
pb := new(tmproto.Part)
|
||||
proof := part.Proof.ToProto()
|
||||
|
||||
pb.Index = part.Index
|
||||
pb.Bytes = part.Bytes
|
||||
pb.Proof = *proof
|
||||
|
||||
return pb, nil
|
||||
}
|
||||
|
||||
func PartFromProto(pb *tmproto.Part) (*Part, error) {
|
||||
if pb == nil {
|
||||
return nil, errors.New("nil part")
|
||||
}
|
||||
|
||||
part := new(Part)
|
||||
proof, err := merkle.SimpleProofFromProto(&pb.Proof)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part.Index = pb.Index
|
||||
part.Bytes = pb.Bytes
|
||||
part.Proof = *proof
|
||||
|
||||
return part, part.ValidateBasic()
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type PartSetHeader struct {
|
||||
|
||||
@@ -157,3 +157,35 @@ func TestParSetHeaderProtoBuf(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPartProtoBuf(t *testing.T) {
|
||||
|
||||
proof := merkle.SimpleProof{
|
||||
Total: 1,
|
||||
Index: 1,
|
||||
LeafHash: tmrand.Bytes(32),
|
||||
}
|
||||
testCases := []struct {
|
||||
msg string
|
||||
ps1 *Part
|
||||
expPass bool
|
||||
}{
|
||||
{"failure empty", &Part{}, false},
|
||||
{"failure nil", nil, false},
|
||||
{"success",
|
||||
&Part{Index: 1, Bytes: tmrand.Bytes(32), Proof: proof}, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
proto, err := tc.ps1.ToProto()
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.msg)
|
||||
}
|
||||
|
||||
p, err := PartFromProto(proto)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.ps1, p, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ func TestValidTxProof(t *testing.T) {
|
||||
for i := range txs {
|
||||
tx := []byte(txs[i])
|
||||
proof := txs.Proof(i)
|
||||
assert.Equal(t, i, proof.Proof.Index, "%d: %d", h, i)
|
||||
assert.Equal(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
|
||||
assert.EqualValues(t, i, proof.Proof.Index, "%d: %d", h, i)
|
||||
assert.EqualValues(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
|
||||
assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
|
||||
assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i)
|
||||
assert.EqualValues(t, txs[i].Hash(), proof.Leaf(), "%d: %d", h, i)
|
||||
|
||||
Reference in New Issue
Block a user