github.com/celestiaorg/celestia-node@v0.15.0-beta.1/header/serde.go (about) 1 package header 2 3 import ( 4 pb "github.com/libp2p/go-libp2p-pubsub/pb" 5 core "github.com/tendermint/tendermint/types" 6 "golang.org/x/crypto/blake2b" 7 8 "github.com/celestiaorg/celestia-app/pkg/da" 9 10 header_pb "github.com/celestiaorg/celestia-node/header/pb" 11 ) 12 13 // MarshalExtendedHeader serializes given ExtendedHeader to bytes using protobuf. 14 // Paired with UnmarshalExtendedHeader. 15 func MarshalExtendedHeader(in *ExtendedHeader) (_ []byte, err error) { 16 out := &header_pb.ExtendedHeader{ 17 Header: in.RawHeader.ToProto(), 18 Commit: in.Commit.ToProto(), 19 } 20 21 out.ValidatorSet, err = in.ValidatorSet.ToProto() 22 if err != nil { 23 return nil, err 24 } 25 26 out.Dah, err = in.DAH.ToProto() 27 if err != nil { 28 return nil, err 29 } 30 31 return out.Marshal() 32 } 33 34 // UnmarshalExtendedHeader deserializes given data into a new ExtendedHeader using protobuf. 35 // Paired with MarshalExtendedHeader. 36 func UnmarshalExtendedHeader(data []byte) (*ExtendedHeader, error) { 37 in := &header_pb.ExtendedHeader{} 38 err := in.Unmarshal(data) 39 if err != nil { 40 return nil, err 41 } 42 43 out := &ExtendedHeader{} 44 out.RawHeader, err = core.HeaderFromProto(in.Header) 45 if err != nil { 46 return nil, err 47 } 48 49 out.Commit, err = core.CommitFromProto(in.Commit) 50 if err != nil { 51 return nil, err 52 } 53 54 out.ValidatorSet, err = core.ValidatorSetFromProto(in.ValidatorSet) 55 if err != nil { 56 return nil, err 57 } 58 59 out.DAH, err = da.DataAvailabilityHeaderFromProto(in.Dah) 60 if err != nil { 61 return nil, err 62 } 63 64 return out, nil 65 } 66 67 func ExtendedHeaderToProto(eh *ExtendedHeader) (*header_pb.ExtendedHeader, error) { 68 pb := &header_pb.ExtendedHeader{ 69 Header: eh.RawHeader.ToProto(), 70 Commit: eh.Commit.ToProto(), 71 } 72 valSet, err := eh.ValidatorSet.ToProto() 73 if err != nil { 74 return nil, err 75 } 76 pb.ValidatorSet = valSet 77 dah, err := eh.DAH.ToProto() 78 if err != nil { 79 return nil, err 80 } 81 pb.Dah = dah 82 return pb, nil 83 } 84 85 func ProtoToExtendedHeader(pb *header_pb.ExtendedHeader) (*ExtendedHeader, error) { 86 bin, err := pb.Marshal() 87 if err != nil { 88 return nil, err 89 } 90 header := new(ExtendedHeader) 91 err = header.UnmarshalBinary(bin) 92 if err != nil { 93 return nil, err 94 } 95 return header, nil 96 } 97 98 // msgID computes an id for a pubsub message 99 // TODO(@Wondertan): This cause additional allocations per each recvd message in the topic 100 // 101 // Find a way to avoid those. 102 func MsgID(pmsg *pb.Message) string { 103 mID := func(data []byte) string { 104 hash := blake2b.Sum256(data) 105 return string(hash[:]) 106 } 107 108 h, _ := UnmarshalExtendedHeader(pmsg.Data) 109 if h == nil || h.RawHeader.ValidateBasic() != nil { 110 // There is nothing we can do about the error, and it will be anyway caught during validation. 111 // We also *have* to return some ID for the msg, so give the hash of even faulty msg 112 return mID(pmsg.Data) 113 } 114 115 // IMPORTANT NOTE: 116 // Due to the nature of the Tendermint consensus, validators don't necessarily collect commit 117 // signatures from the entire validator set, but only the minimum required amount of them (>2/3 of 118 // voting power). In addition, signatures are collected asynchronously. Therefore, each validator 119 // may have a different set of signatures that pass the minimum required voting power threshold, 120 // causing nondeterminism in the header message gossiped over the network. Subsequently, this 121 // causes message duplicates as each Bridge Node, connected to a personal validator, sends the 122 // validator's own view of commits of effectively the same header. 123 // 124 // To solve the nondeterminism problem above, we don't compute msg id on message body and take 125 // the actual header hash as an id. 126 return h.Commit.BlockID.String() 127 }