github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/types/block.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/gogo/protobuf/proto"
    11  	gogotypes "github.com/gogo/protobuf/types"
    12  
    13  	"github.com/badrootd/celestia-core/crypto"
    14  	"github.com/badrootd/celestia-core/crypto/merkle"
    15  	"github.com/badrootd/celestia-core/crypto/tmhash"
    16  	"github.com/badrootd/celestia-core/libs/bits"
    17  	cmtbytes "github.com/badrootd/celestia-core/libs/bytes"
    18  	cmtmath "github.com/badrootd/celestia-core/libs/math"
    19  	cmtsync "github.com/badrootd/celestia-core/libs/sync"
    20  	cmtproto "github.com/badrootd/celestia-core/proto/tendermint/types"
    21  	cmtversion "github.com/badrootd/celestia-core/proto/tendermint/version"
    22  	"github.com/badrootd/celestia-core/version"
    23  )
    24  
    25  const (
    26  	// MaxHeaderBytes is a maximum header size.
    27  	// NOTE: Because app hash can be of arbitrary size, the header is therefore not
    28  	// capped in size and thus this number should be seen as a soft max
    29  	MaxHeaderBytes int64 = 626
    30  
    31  	// MaxOverheadForBlock - maximum overhead to encode a block (up to
    32  	// MaxBlockSizeBytes in size) not including it's parts except Data.
    33  	// This means it also excludes the overhead for individual transactions.
    34  	//
    35  	// Uvarint length of MaxBlockSizeBytes: 4 bytes
    36  	// 2 fields (2 embedded):               2 bytes
    37  	// Uvarint length of Data.Txs:          4 bytes
    38  	// Data.Txs field:                      1 byte
    39  	MaxOverheadForBlock int64 = 11
    40  )
    41  
    42  // Block defines the atomic unit of a CometBFT blockchain.
    43  type Block struct {
    44  	mtx cmtsync.Mutex
    45  
    46  	Header     `json:"header"`
    47  	Data       `json:"data"`
    48  	Evidence   EvidenceData `json:"evidence"`
    49  	LastCommit *Commit      `json:"last_commit"`
    50  }
    51  
    52  // ValidateBasic performs basic validation that doesn't involve state data. It
    53  // checks the internal consistency of the block. Further validation is done
    54  // using state#ValidateBlock. celestia-app's ProcessProposal checks that the
    55  // block's DataHash matches the hash of the data availability header.
    56  func (b *Block) ValidateBasic() error {
    57  	if b == nil {
    58  		return errors.New("nil block")
    59  	}
    60  
    61  	b.mtx.Lock()
    62  	defer b.mtx.Unlock()
    63  
    64  	if err := b.Header.ValidateBasic(); err != nil {
    65  		return fmt.Errorf("invalid header: %w", err)
    66  	}
    67  
    68  	// Validate the last commit and its hash.
    69  	if b.LastCommit == nil {
    70  		return errors.New("nil LastCommit")
    71  	}
    72  	if err := b.LastCommit.ValidateBasic(); err != nil {
    73  		return fmt.Errorf("wrong LastCommit: %v", err)
    74  	}
    75  
    76  	if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) {
    77  		return fmt.Errorf("wrong Header.LastCommitHash. Expected %v, got %v",
    78  			b.LastCommit.Hash(),
    79  			b.LastCommitHash,
    80  		)
    81  	}
    82  
    83  	// NOTE: b.Evidence.Evidence may be nil, but we're just looping.
    84  	for i, ev := range b.Evidence.Evidence {
    85  		if err := ev.ValidateBasic(); err != nil {
    86  			return fmt.Errorf("invalid evidence (#%d): %v", i, err)
    87  		}
    88  	}
    89  
    90  	if !bytes.Equal(b.EvidenceHash, b.Evidence.Hash()) {
    91  		return fmt.Errorf("wrong Header.EvidenceHash. Expected %v, got %v",
    92  			b.EvidenceHash,
    93  			b.Evidence.Hash(),
    94  		)
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  // fillHeader fills in any remaining header fields that are a function of the
   101  // block data NOTE: we expect celestia-app to populate the block DataHash but we
   102  // populate it here (in celestia-core) to not break existing tests in this repo.
   103  func (b *Block) fillHeader() {
   104  	if b.LastCommitHash == nil {
   105  		b.LastCommitHash = b.LastCommit.Hash()
   106  	}
   107  	if b.DataHash == nil {
   108  		b.DataHash = b.Data.Hash()
   109  	}
   110  	if b.EvidenceHash == nil {
   111  		b.EvidenceHash = b.Evidence.Hash()
   112  	}
   113  }
   114  
   115  // Hash computes and returns the block hash.
   116  // If the block is incomplete, block hash is nil for safety.
   117  func (b *Block) Hash() cmtbytes.HexBytes {
   118  	if b == nil {
   119  		return nil
   120  	}
   121  	b.mtx.Lock()
   122  	defer b.mtx.Unlock()
   123  
   124  	if b.LastCommit == nil {
   125  		return nil
   126  	}
   127  	b.fillHeader()
   128  	return b.Header.Hash()
   129  }
   130  
   131  // MakePartSet returns a PartSet containing parts of a serialized block.
   132  // This is the form in which the block is gossipped to peers.
   133  // CONTRACT: partSize is greater than zero.
   134  func (b *Block) MakePartSet(partSize uint32) *PartSet {
   135  	if b == nil {
   136  		return nil
   137  	}
   138  	b.mtx.Lock()
   139  	defer b.mtx.Unlock()
   140  
   141  	pbb, err := b.ToProto()
   142  	if err != nil {
   143  		panic(err)
   144  	}
   145  	bz, err := proto.Marshal(pbb)
   146  	if err != nil {
   147  		panic(err)
   148  	}
   149  	return NewPartSetFromData(bz, partSize)
   150  }
   151  
   152  // HashesTo is a convenience function that checks if a block hashes to the given argument.
   153  // Returns false if the block is nil or the hash is empty.
   154  func (b *Block) HashesTo(hash []byte) bool {
   155  	if len(hash) == 0 {
   156  		return false
   157  	}
   158  	if b == nil {
   159  		return false
   160  	}
   161  	return bytes.Equal(b.Hash(), hash)
   162  }
   163  
   164  // Size returns size of the block in bytes.
   165  func (b *Block) Size() int {
   166  	pbb, err := b.ToProto()
   167  	if err != nil {
   168  		return 0
   169  	}
   170  
   171  	return pbb.Size()
   172  }
   173  
   174  // String returns a string representation of the block
   175  //
   176  // See StringIndented.
   177  func (b *Block) String() string {
   178  	return b.StringIndented("")
   179  }
   180  
   181  // StringIndented returns an indented String.
   182  //
   183  // Header
   184  // Data
   185  // Evidence
   186  // LastCommit
   187  // Hash
   188  func (b *Block) StringIndented(indent string) string {
   189  	if b == nil {
   190  		return "nil-Block"
   191  	}
   192  	return fmt.Sprintf(`Block{
   193  %s  %v
   194  %s  %v
   195  %s  %v
   196  %s  %v
   197  %s}#%v`,
   198  		indent, b.Header.StringIndented(indent+"  "),
   199  		indent, b.Data.StringIndented(indent+"  "),
   200  		indent, b.Evidence.StringIndented(indent+"  "),
   201  		indent, b.LastCommit.StringIndented(indent+"  "),
   202  		indent, b.Hash())
   203  }
   204  
   205  // StringShort returns a shortened string representation of the block.
   206  func (b *Block) StringShort() string {
   207  	if b == nil {
   208  		return "nil-Block"
   209  	}
   210  	return fmt.Sprintf("Block#%X", b.Hash())
   211  }
   212  
   213  // ToProto converts Block to protobuf
   214  func (b *Block) ToProto() (*cmtproto.Block, error) {
   215  	if b == nil {
   216  		return nil, errors.New("nil Block")
   217  	}
   218  
   219  	pb := new(cmtproto.Block)
   220  
   221  	pb.Header = *b.Header.ToProto()
   222  	pb.LastCommit = b.LastCommit.ToProto()
   223  	pb.Data = b.Data.ToProto()
   224  
   225  	protoEvidence, err := b.Evidence.ToProto()
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	pb.Evidence = *protoEvidence
   230  
   231  	return pb, nil
   232  }
   233  
   234  // FromProto sets a protobuf Block to the given pointer.
   235  // It returns an error if the block is invalid.
   236  func BlockFromProto(bp *cmtproto.Block) (*Block, error) {
   237  	if bp == nil {
   238  		return nil, errors.New("nil block")
   239  	}
   240  
   241  	b := new(Block)
   242  	h, err := HeaderFromProto(&bp.Header)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	b.Header = h
   247  	data, err := DataFromProto(&bp.Data)
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  	b.Data = data
   252  	if err := b.Evidence.FromProto(&bp.Evidence); err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	if bp.LastCommit != nil {
   257  		lc, err := CommitFromProto(bp.LastCommit)
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  		b.LastCommit = lc
   262  	}
   263  
   264  	return b, b.ValidateBasic()
   265  }
   266  
   267  //-----------------------------------------------------------------------------
   268  
   269  // MaxDataBytes returns the maximum size of block's data.
   270  //
   271  // XXX: Panics on negative result.
   272  func MaxDataBytes(maxBytes, evidenceBytes int64, valsCount int) int64 {
   273  	maxDataBytes := maxBytes -
   274  		MaxOverheadForBlock -
   275  		MaxHeaderBytes -
   276  		MaxCommitBytes(valsCount) -
   277  		evidenceBytes
   278  
   279  	if maxDataBytes < 0 {
   280  		panic(fmt.Sprintf(
   281  			"Negative MaxDataBytes. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d",
   282  			maxBytes,
   283  			-(maxDataBytes - maxBytes),
   284  		))
   285  	}
   286  
   287  	return maxDataBytes
   288  }
   289  
   290  // MaxDataBytesNoEvidence returns the maximum size of block's data when
   291  // evidence count is unknown. MaxEvidencePerBlock will be used for the size
   292  // of evidence.
   293  //
   294  // XXX: Panics on negative result.
   295  func MaxDataBytesNoEvidence(maxBytes int64, valsCount int) int64 {
   296  	maxDataBytes := maxBytes -
   297  		MaxOverheadForBlock -
   298  		MaxHeaderBytes -
   299  		MaxCommitBytes(valsCount)
   300  
   301  	if maxDataBytes < 0 {
   302  		panic(fmt.Sprintf(
   303  			"Negative MaxDataBytesUnknownEvidence. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d",
   304  			maxBytes,
   305  			-(maxDataBytes - maxBytes),
   306  		))
   307  	}
   308  
   309  	return maxDataBytes
   310  }
   311  
   312  // MakeBlock returns a new block with an empty header, except what can be
   313  // computed from itself.
   314  // It populates the same set of fields validated by ValidateBasic.
   315  func MakeBlock(
   316  	height int64,
   317  	txs Txs,
   318  	lastCommit *Commit,
   319  	evidence []Evidence) *Block {
   320  	block := &Block{
   321  		Header: Header{
   322  			Version: cmtversion.Consensus{Block: version.BlockProtocol, App: 0},
   323  			Height:  height,
   324  		},
   325  		Data:       Data{Txs: txs},
   326  		Evidence:   EvidenceData{Evidence: evidence},
   327  		LastCommit: lastCommit,
   328  	}
   329  	block.fillHeader()
   330  	return block
   331  }
   332  
   333  //-----------------------------------------------------------------------------
   334  
   335  // Header defines the structure of a CometBFT block header.
   336  // NOTE: changes to the Header should be duplicated in:
   337  // - header.Hash()
   338  // - abci.Header
   339  // - https://github.com/cometbft/cometbft/blob/v0.34.x/spec/blockchain/blockchain.md
   340  type Header struct {
   341  	// basic block info
   342  	Version cmtversion.Consensus `json:"version"`
   343  	ChainID string               `json:"chain_id"`
   344  	Height  int64                `json:"height"`
   345  	Time    time.Time            `json:"time"`
   346  
   347  	// prev block info
   348  	LastBlockID BlockID `json:"last_block_id"`
   349  
   350  	// hashes of block data
   351  	LastCommitHash cmtbytes.HexBytes `json:"last_commit_hash"` // commit from validators from the last block
   352  	DataHash       cmtbytes.HexBytes `json:"data_hash"`        // transactions
   353  
   354  	// hashes from the app output from the prev block
   355  	ValidatorsHash     cmtbytes.HexBytes `json:"validators_hash"`      // validators for the current block
   356  	NextValidatorsHash cmtbytes.HexBytes `json:"next_validators_hash"` // validators for the next block
   357  	ConsensusHash      cmtbytes.HexBytes `json:"consensus_hash"`       // consensus params for current block
   358  	AppHash            cmtbytes.HexBytes `json:"app_hash"`             // state after txs from the previous block
   359  	// root hash of all results from the txs from the previous block
   360  	// see `deterministicResponseDeliverTx` to understand which parts of a tx is hashed into here
   361  	LastResultsHash cmtbytes.HexBytes `json:"last_results_hash"`
   362  
   363  	// consensus info
   364  	EvidenceHash    cmtbytes.HexBytes `json:"evidence_hash"`    // evidence included in the block
   365  	ProposerAddress Address           `json:"proposer_address"` // original proposer of the block
   366  }
   367  
   368  // Populate the Header with state-derived data.
   369  // Call this after MakeBlock to complete the Header.
   370  func (h *Header) Populate(
   371  	version cmtversion.Consensus, chainID string,
   372  	timestamp time.Time, lastBlockID BlockID,
   373  	valHash, nextValHash []byte,
   374  	consensusHash, appHash, lastResultsHash []byte,
   375  	proposerAddress Address,
   376  ) {
   377  	h.Version = version
   378  	h.ChainID = chainID
   379  	h.Time = timestamp
   380  	h.LastBlockID = lastBlockID
   381  	h.ValidatorsHash = valHash
   382  	h.NextValidatorsHash = nextValHash
   383  	h.ConsensusHash = consensusHash
   384  	h.AppHash = appHash
   385  	h.LastResultsHash = lastResultsHash
   386  	h.ProposerAddress = proposerAddress
   387  }
   388  
   389  // ValidateBasic performs stateless validation on a Header returning an error
   390  // if any validation fails.
   391  //
   392  // NOTE: Timestamp validation is subtle and handled elsewhere.
   393  func (h Header) ValidateBasic() error {
   394  	if h.Version.Block != version.BlockProtocol {
   395  		return fmt.Errorf("block protocol is incorrect: got: %d, want: %d ", h.Version.Block, version.BlockProtocol)
   396  	}
   397  	if len(h.ChainID) > MaxChainIDLen {
   398  		return fmt.Errorf("chainID is too long; got: %d, max: %d", len(h.ChainID), MaxChainIDLen)
   399  	}
   400  
   401  	if h.Height < 0 {
   402  		return errors.New("negative Height")
   403  	} else if h.Height == 0 {
   404  		return errors.New("zero Height")
   405  	}
   406  
   407  	if err := h.LastBlockID.ValidateBasic(); err != nil {
   408  		return fmt.Errorf("wrong LastBlockID: %w", err)
   409  	}
   410  
   411  	if err := ValidateHash(h.LastCommitHash); err != nil {
   412  		return fmt.Errorf("wrong LastCommitHash: %v", err)
   413  	}
   414  
   415  	if err := ValidateHash(h.DataHash); err != nil {
   416  		return fmt.Errorf("wrong DataHash: %v", err)
   417  	}
   418  
   419  	if err := ValidateHash(h.EvidenceHash); err != nil {
   420  		return fmt.Errorf("wrong EvidenceHash: %v", err)
   421  	}
   422  
   423  	if len(h.ProposerAddress) != crypto.AddressSize {
   424  		return fmt.Errorf(
   425  			"invalid ProposerAddress length; got: %d, expected: %d",
   426  			len(h.ProposerAddress), crypto.AddressSize,
   427  		)
   428  	}
   429  
   430  	// Basic validation of hashes related to application data.
   431  	// Will validate fully against state in state#ValidateBlock.
   432  	if err := ValidateHash(h.ValidatorsHash); err != nil {
   433  		return fmt.Errorf("wrong ValidatorsHash: %v", err)
   434  	}
   435  	if err := ValidateHash(h.NextValidatorsHash); err != nil {
   436  		return fmt.Errorf("wrong NextValidatorsHash: %v", err)
   437  	}
   438  	if err := ValidateHash(h.ConsensusHash); err != nil {
   439  		return fmt.Errorf("wrong ConsensusHash: %v", err)
   440  	}
   441  	// NOTE: AppHash is arbitrary length
   442  	if err := ValidateHash(h.LastResultsHash); err != nil {
   443  		return fmt.Errorf("wrong LastResultsHash: %v", err)
   444  	}
   445  
   446  	return nil
   447  }
   448  
   449  // Hash returns the hash of the header.
   450  // It computes a Merkle tree from the header fields
   451  // ordered as they appear in the Header.
   452  // Returns nil if ValidatorHash is missing,
   453  // since a Header is not valid unless there is
   454  // a ValidatorsHash (corresponding to the validator set).
   455  func (h *Header) Hash() cmtbytes.HexBytes {
   456  	if h == nil || len(h.ValidatorsHash) == 0 {
   457  		return nil
   458  	}
   459  	hbz, err := h.Version.Marshal()
   460  	if err != nil {
   461  		return nil
   462  	}
   463  
   464  	pbt, err := gogotypes.StdTimeMarshal(h.Time)
   465  	if err != nil {
   466  		return nil
   467  	}
   468  
   469  	pbbi := h.LastBlockID.ToProto()
   470  	bzbi, err := pbbi.Marshal()
   471  	if err != nil {
   472  		return nil
   473  	}
   474  	return merkle.HashFromByteSlices([][]byte{
   475  		hbz,
   476  		cdcEncode(h.ChainID),
   477  		cdcEncode(h.Height),
   478  		pbt,
   479  		bzbi,
   480  		cdcEncode(h.LastCommitHash),
   481  		cdcEncode(h.DataHash),
   482  		cdcEncode(h.ValidatorsHash),
   483  		cdcEncode(h.NextValidatorsHash),
   484  		cdcEncode(h.ConsensusHash),
   485  		cdcEncode(h.AppHash),
   486  		cdcEncode(h.LastResultsHash),
   487  		cdcEncode(h.EvidenceHash),
   488  		cdcEncode(h.ProposerAddress),
   489  	})
   490  }
   491  
   492  // StringIndented returns an indented string representation of the header.
   493  func (h *Header) StringIndented(indent string) string {
   494  	if h == nil {
   495  		return "nil-Header"
   496  	}
   497  	return fmt.Sprintf(`Header{
   498  %s  Version:        %v
   499  %s  ChainID:        %v
   500  %s  Height:         %v
   501  %s  Time:           %v
   502  %s  LastBlockID:    %v
   503  %s  LastCommit:     %v
   504  %s  Data:           %v
   505  %s  Validators:     %v
   506  %s  NextValidators: %v
   507  %s  App:            %v
   508  %s  Consensus:      %v
   509  %s  Results:        %v
   510  %s  Evidence:       %v
   511  %s  Proposer:       %v
   512  %s}#%v`,
   513  		indent, h.Version,
   514  		indent, h.ChainID,
   515  		indent, h.Height,
   516  		indent, h.Time,
   517  		indent, h.LastBlockID,
   518  		indent, h.LastCommitHash,
   519  		indent, h.DataHash,
   520  		indent, h.ValidatorsHash,
   521  		indent, h.NextValidatorsHash,
   522  		indent, h.AppHash,
   523  		indent, h.ConsensusHash,
   524  		indent, h.LastResultsHash,
   525  		indent, h.EvidenceHash,
   526  		indent, h.ProposerAddress,
   527  		indent, h.Hash())
   528  }
   529  
   530  // ToProto converts Header to protobuf
   531  func (h *Header) ToProto() *cmtproto.Header {
   532  	if h == nil {
   533  		return nil
   534  	}
   535  
   536  	return &cmtproto.Header{
   537  		Version:            h.Version,
   538  		ChainID:            h.ChainID,
   539  		Height:             h.Height,
   540  		Time:               h.Time,
   541  		LastBlockId:        h.LastBlockID.ToProto(),
   542  		ValidatorsHash:     h.ValidatorsHash,
   543  		NextValidatorsHash: h.NextValidatorsHash,
   544  		ConsensusHash:      h.ConsensusHash,
   545  		AppHash:            h.AppHash,
   546  		DataHash:           h.DataHash,
   547  		EvidenceHash:       h.EvidenceHash,
   548  		LastResultsHash:    h.LastResultsHash,
   549  		LastCommitHash:     h.LastCommitHash,
   550  		ProposerAddress:    h.ProposerAddress,
   551  	}
   552  }
   553  
   554  // FromProto sets a protobuf Header to the given pointer.
   555  // It returns an error if the header is invalid.
   556  func HeaderFromProto(ph *cmtproto.Header) (Header, error) {
   557  	if ph == nil {
   558  		return Header{}, errors.New("nil Header")
   559  	}
   560  
   561  	h := new(Header)
   562  
   563  	bi, err := BlockIDFromProto(&ph.LastBlockId)
   564  	if err != nil {
   565  		return Header{}, err
   566  	}
   567  
   568  	h.Version = ph.Version
   569  	h.ChainID = ph.ChainID
   570  	h.Height = ph.Height
   571  	h.Time = ph.Time
   572  	h.Height = ph.Height
   573  	h.LastBlockID = *bi
   574  	h.ValidatorsHash = ph.ValidatorsHash
   575  	h.NextValidatorsHash = ph.NextValidatorsHash
   576  	h.ConsensusHash = ph.ConsensusHash
   577  	h.AppHash = ph.AppHash
   578  	h.DataHash = ph.DataHash
   579  	h.EvidenceHash = ph.EvidenceHash
   580  	h.LastResultsHash = ph.LastResultsHash
   581  	h.LastCommitHash = ph.LastCommitHash
   582  	h.ProposerAddress = ph.ProposerAddress
   583  
   584  	return *h, h.ValidateBasic()
   585  }
   586  
   587  //-------------------------------------
   588  
   589  // BlockIDFlag indicates which BlockID the signature is for.
   590  type BlockIDFlag byte
   591  
   592  const (
   593  	// BlockIDFlagAbsent - no vote was received from a validator.
   594  	BlockIDFlagAbsent BlockIDFlag = iota + 1
   595  	// BlockIDFlagCommit - voted for the Commit.BlockID.
   596  	BlockIDFlagCommit
   597  	// BlockIDFlagNil - voted for nil.
   598  	BlockIDFlagNil
   599  )
   600  
   601  const (
   602  	// Max size of commit without any commitSigs -> 82 for BlockID, 8 for Height, 4 for Round.
   603  	MaxCommitOverheadBytes int64 = 94
   604  	// Commit sig size is made up of 64 bytes for the signature, 20 bytes for the address,
   605  	// 1 byte for the flag and 14 bytes for the timestamp
   606  	MaxCommitSigBytes int64 = 109
   607  )
   608  
   609  // CommitSig is a part of the Vote included in a Commit.
   610  type CommitSig struct {
   611  	BlockIDFlag      BlockIDFlag `json:"block_id_flag"`
   612  	ValidatorAddress Address     `json:"validator_address"`
   613  	Timestamp        time.Time   `json:"timestamp"`
   614  	Signature        []byte      `json:"signature"`
   615  }
   616  
   617  // NewCommitSigForBlock returns new CommitSig with BlockIDFlagCommit.
   618  func NewCommitSigForBlock(signature []byte, valAddr Address, ts time.Time) CommitSig {
   619  	return CommitSig{
   620  		BlockIDFlag:      BlockIDFlagCommit,
   621  		ValidatorAddress: valAddr,
   622  		Timestamp:        ts,
   623  		Signature:        signature,
   624  	}
   625  }
   626  
   627  func MaxCommitBytes(valCount int) int64 {
   628  	// From the repeated commit sig field
   629  	var protoEncodingOverhead int64 = 2
   630  	return MaxCommitOverheadBytes + ((MaxCommitSigBytes + protoEncodingOverhead) * int64(valCount))
   631  }
   632  
   633  // NewCommitSigAbsent returns new CommitSig with BlockIDFlagAbsent. Other
   634  // fields are all empty.
   635  func NewCommitSigAbsent() CommitSig {
   636  	return CommitSig{
   637  		BlockIDFlag: BlockIDFlagAbsent,
   638  	}
   639  }
   640  
   641  // ForBlock returns true if CommitSig is for the block.
   642  func (cs CommitSig) ForBlock() bool {
   643  	return cs.BlockIDFlag == BlockIDFlagCommit
   644  }
   645  
   646  // Absent returns true if CommitSig is absent.
   647  func (cs CommitSig) Absent() bool {
   648  	return cs.BlockIDFlag == BlockIDFlagAbsent
   649  }
   650  
   651  // CommitSig returns a string representation of CommitSig.
   652  //
   653  // 1. first 6 bytes of signature
   654  // 2. first 6 bytes of validator address
   655  // 3. block ID flag
   656  // 4. timestamp
   657  func (cs CommitSig) String() string {
   658  	return fmt.Sprintf("CommitSig{%X by %X on %v @ %s}",
   659  		cmtbytes.Fingerprint(cs.Signature),
   660  		cmtbytes.Fingerprint(cs.ValidatorAddress),
   661  		cs.BlockIDFlag,
   662  		CanonicalTime(cs.Timestamp))
   663  }
   664  
   665  // BlockID returns the Commit's BlockID if CommitSig indicates signing,
   666  // otherwise - empty BlockID.
   667  func (cs CommitSig) BlockID(commitBlockID BlockID) BlockID {
   668  	var blockID BlockID
   669  	switch cs.BlockIDFlag {
   670  	case BlockIDFlagAbsent:
   671  		blockID = BlockID{}
   672  	case BlockIDFlagCommit:
   673  		blockID = commitBlockID
   674  	case BlockIDFlagNil:
   675  		blockID = BlockID{}
   676  	default:
   677  		panic(fmt.Sprintf("Unknown BlockIDFlag: %v", cs.BlockIDFlag))
   678  	}
   679  	return blockID
   680  }
   681  
   682  // ValidateBasic performs basic validation.
   683  func (cs CommitSig) ValidateBasic() error {
   684  	switch cs.BlockIDFlag {
   685  	case BlockIDFlagAbsent:
   686  	case BlockIDFlagCommit:
   687  	case BlockIDFlagNil:
   688  	default:
   689  		return fmt.Errorf("unknown BlockIDFlag: %v", cs.BlockIDFlag)
   690  	}
   691  
   692  	switch cs.BlockIDFlag {
   693  	case BlockIDFlagAbsent:
   694  		if len(cs.ValidatorAddress) != 0 {
   695  			return errors.New("validator address is present")
   696  		}
   697  		if !cs.Timestamp.IsZero() {
   698  			return errors.New("time is present")
   699  		}
   700  		if len(cs.Signature) != 0 {
   701  			return errors.New("signature is present")
   702  		}
   703  	default:
   704  		if len(cs.ValidatorAddress) != crypto.AddressSize {
   705  			return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes",
   706  				crypto.AddressSize,
   707  				len(cs.ValidatorAddress),
   708  			)
   709  		}
   710  		// NOTE: Timestamp validation is subtle and handled elsewhere.
   711  		if len(cs.Signature) == 0 {
   712  			return errors.New("signature is missing")
   713  		}
   714  		if len(cs.Signature) > MaxSignatureSize {
   715  			return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
   716  		}
   717  	}
   718  
   719  	return nil
   720  }
   721  
   722  // ToProto converts CommitSig to protobuf
   723  func (cs *CommitSig) ToProto() *cmtproto.CommitSig {
   724  	if cs == nil {
   725  		return nil
   726  	}
   727  
   728  	return &cmtproto.CommitSig{
   729  		BlockIdFlag:      cmtproto.BlockIDFlag(cs.BlockIDFlag),
   730  		ValidatorAddress: cs.ValidatorAddress,
   731  		Timestamp:        cs.Timestamp,
   732  		Signature:        cs.Signature,
   733  	}
   734  }
   735  
   736  // FromProto sets a protobuf CommitSig to the given pointer.
   737  // It returns an error if the CommitSig is invalid.
   738  func (cs *CommitSig) FromProto(csp cmtproto.CommitSig) error {
   739  
   740  	cs.BlockIDFlag = BlockIDFlag(csp.BlockIdFlag)
   741  	cs.ValidatorAddress = csp.ValidatorAddress
   742  	cs.Timestamp = csp.Timestamp
   743  	cs.Signature = csp.Signature
   744  
   745  	return cs.ValidateBasic()
   746  }
   747  
   748  //-------------------------------------
   749  
   750  // Commit contains the evidence that a block was committed by a set of validators.
   751  // NOTE: Commit is empty for height 1, but never nil.
   752  type Commit struct {
   753  	// NOTE: The signatures are in order of address to preserve the bonded
   754  	// ValidatorSet order.
   755  	// Any peer with a block can gossip signatures by index with a peer without
   756  	// recalculating the active ValidatorSet.
   757  	Height     int64       `json:"height"`
   758  	Round      int32       `json:"round"`
   759  	BlockID    BlockID     `json:"block_id"`
   760  	Signatures []CommitSig `json:"signatures"`
   761  
   762  	// Memoized in first call to corresponding method.
   763  	// NOTE: can't memoize in constructor because constructor isn't used for
   764  	// unmarshaling.
   765  	hash     cmtbytes.HexBytes
   766  	bitArray *bits.BitArray
   767  }
   768  
   769  // NewCommit returns a new Commit.
   770  func NewCommit(height int64, round int32, blockID BlockID, commitSigs []CommitSig) *Commit {
   771  	return &Commit{
   772  		Height:     height,
   773  		Round:      round,
   774  		BlockID:    blockID,
   775  		Signatures: commitSigs,
   776  	}
   777  }
   778  
   779  // CommitToVoteSet constructs a VoteSet from the Commit and validator set.
   780  // Panics if signatures from the commit can't be added to the voteset.
   781  // Inverse of VoteSet.MakeCommit().
   782  func CommitToVoteSet(chainID string, commit *Commit, vals *ValidatorSet) *VoteSet {
   783  	voteSet := NewVoteSet(chainID, commit.Height, commit.Round, cmtproto.PrecommitType, vals)
   784  	for idx, commitSig := range commit.Signatures {
   785  		if commitSig.Absent() {
   786  			continue // OK, some precommits can be missing.
   787  		}
   788  		added, err := voteSet.AddVote(commit.GetVote(int32(idx)))
   789  		if !added || err != nil {
   790  			panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))
   791  		}
   792  	}
   793  	return voteSet
   794  }
   795  
   796  // GetVote converts the CommitSig for the given valIdx to a Vote.
   797  // Returns nil if the precommit at valIdx is nil.
   798  // Panics if valIdx >= commit.Size().
   799  func (commit *Commit) GetVote(valIdx int32) *Vote {
   800  	commitSig := commit.Signatures[valIdx]
   801  	return &Vote{
   802  		Type:             cmtproto.PrecommitType,
   803  		Height:           commit.Height,
   804  		Round:            commit.Round,
   805  		BlockID:          commitSig.BlockID(commit.BlockID),
   806  		Timestamp:        commitSig.Timestamp,
   807  		ValidatorAddress: commitSig.ValidatorAddress,
   808  		ValidatorIndex:   valIdx,
   809  		Signature:        commitSig.Signature,
   810  	}
   811  }
   812  
   813  // VoteSignBytes returns the bytes of the Vote corresponding to valIdx for
   814  // signing.
   815  //
   816  // The only unique part is the Timestamp - all other fields signed over are
   817  // otherwise the same for all validators.
   818  //
   819  // Panics if valIdx >= commit.Size().
   820  //
   821  // See VoteSignBytes
   822  func (commit *Commit) VoteSignBytes(chainID string, valIdx int32) []byte {
   823  	v := commit.GetVote(valIdx).ToProto()
   824  	return VoteSignBytes(chainID, v)
   825  }
   826  
   827  // Type returns the vote type of the commit, which is always VoteTypePrecommit
   828  // Implements VoteSetReader.
   829  func (commit *Commit) Type() byte {
   830  	return byte(cmtproto.PrecommitType)
   831  }
   832  
   833  // GetHeight returns height of the commit.
   834  // Implements VoteSetReader.
   835  func (commit *Commit) GetHeight() int64 {
   836  	return commit.Height
   837  }
   838  
   839  // GetRound returns height of the commit.
   840  // Implements VoteSetReader.
   841  func (commit *Commit) GetRound() int32 {
   842  	return commit.Round
   843  }
   844  
   845  // Size returns the number of signatures in the commit.
   846  // Implements VoteSetReader.
   847  func (commit *Commit) Size() int {
   848  	if commit == nil {
   849  		return 0
   850  	}
   851  	return len(commit.Signatures)
   852  }
   853  
   854  // BitArray returns a BitArray of which validators voted for BlockID or nil in this commit.
   855  // Implements VoteSetReader.
   856  func (commit *Commit) BitArray() *bits.BitArray {
   857  	if commit.bitArray == nil {
   858  		commit.bitArray = bits.NewBitArray(len(commit.Signatures))
   859  		for i, commitSig := range commit.Signatures {
   860  			// TODO: need to check the BlockID otherwise we could be counting conflicts,
   861  			// not just the one with +2/3 !
   862  			commit.bitArray.SetIndex(i, !commitSig.Absent())
   863  		}
   864  	}
   865  	return commit.bitArray
   866  }
   867  
   868  // GetByIndex returns the vote corresponding to a given validator index.
   869  // Panics if `index >= commit.Size()`.
   870  // Implements VoteSetReader.
   871  func (commit *Commit) GetByIndex(valIdx int32) *Vote {
   872  	return commit.GetVote(valIdx)
   873  }
   874  
   875  // IsCommit returns true if there is at least one signature.
   876  // Implements VoteSetReader.
   877  func (commit *Commit) IsCommit() bool {
   878  	return len(commit.Signatures) != 0
   879  }
   880  
   881  // ValidateBasic performs basic validation that doesn't involve state data.
   882  // Does not actually check the cryptographic signatures.
   883  func (commit *Commit) ValidateBasic() error {
   884  	if commit == nil {
   885  		return errors.New("nil commit")
   886  	}
   887  
   888  	if commit.Height < 0 {
   889  		return errors.New("negative Height")
   890  	}
   891  	if commit.Round < 0 {
   892  		return errors.New("negative Round")
   893  	}
   894  
   895  	if commit.Height >= 1 {
   896  		if commit.BlockID.IsZero() {
   897  			return errors.New("commit cannot be for nil block")
   898  		}
   899  
   900  		if len(commit.Signatures) == 0 {
   901  			return errors.New("no signatures in commit")
   902  		}
   903  		for i, commitSig := range commit.Signatures {
   904  			if err := commitSig.ValidateBasic(); err != nil {
   905  				return fmt.Errorf("wrong CommitSig #%d: %v", i, err)
   906  			}
   907  		}
   908  	}
   909  	return nil
   910  }
   911  
   912  // Hash returns the hash of the commit
   913  func (commit *Commit) Hash() cmtbytes.HexBytes {
   914  	if commit == nil {
   915  		return nil
   916  	}
   917  	if commit.hash == nil {
   918  		bs := make([][]byte, len(commit.Signatures))
   919  		for i, commitSig := range commit.Signatures {
   920  			pbcs := commitSig.ToProto()
   921  			bz, err := pbcs.Marshal()
   922  			if err != nil {
   923  				panic(err)
   924  			}
   925  
   926  			bs[i] = bz
   927  		}
   928  		commit.hash = merkle.HashFromByteSlices(bs)
   929  	}
   930  	return commit.hash
   931  }
   932  
   933  // StringIndented returns a string representation of the commit.
   934  func (commit *Commit) StringIndented(indent string) string {
   935  	if commit == nil {
   936  		return "nil-Commit"
   937  	}
   938  	commitSigStrings := make([]string, len(commit.Signatures))
   939  	for i, commitSig := range commit.Signatures {
   940  		commitSigStrings[i] = commitSig.String()
   941  	}
   942  	return fmt.Sprintf(`Commit{
   943  %s  Height:     %d
   944  %s  Round:      %d
   945  %s  BlockID:    %v
   946  %s  Signatures:
   947  %s    %v
   948  %s}#%v`,
   949  		indent, commit.Height,
   950  		indent, commit.Round,
   951  		indent, commit.BlockID,
   952  		indent,
   953  		indent, strings.Join(commitSigStrings, "\n"+indent+"    "),
   954  		indent, commit.hash)
   955  }
   956  
   957  // ToProto converts Commit to protobuf
   958  func (commit *Commit) ToProto() *cmtproto.Commit {
   959  	if commit == nil {
   960  		return nil
   961  	}
   962  
   963  	c := new(cmtproto.Commit)
   964  	sigs := make([]cmtproto.CommitSig, len(commit.Signatures))
   965  	for i := range commit.Signatures {
   966  		sigs[i] = *commit.Signatures[i].ToProto()
   967  	}
   968  	c.Signatures = sigs
   969  
   970  	c.Height = commit.Height
   971  	c.Round = commit.Round
   972  	c.BlockID = commit.BlockID.ToProto()
   973  
   974  	return c
   975  }
   976  
   977  // FromProto sets a protobuf Commit to the given pointer.
   978  // It returns an error if the commit is invalid.
   979  func CommitFromProto(cp *cmtproto.Commit) (*Commit, error) {
   980  	if cp == nil {
   981  		return nil, errors.New("nil Commit")
   982  	}
   983  
   984  	var (
   985  		commit = new(Commit)
   986  	)
   987  
   988  	bi, err := BlockIDFromProto(&cp.BlockID)
   989  	if err != nil {
   990  		return nil, err
   991  	}
   992  
   993  	sigs := make([]CommitSig, len(cp.Signatures))
   994  	for i := range cp.Signatures {
   995  		if err := sigs[i].FromProto(cp.Signatures[i]); err != nil {
   996  			return nil, err
   997  		}
   998  	}
   999  	commit.Signatures = sigs
  1000  
  1001  	commit.Height = cp.Height
  1002  	commit.Round = cp.Round
  1003  	commit.BlockID = *bi
  1004  
  1005  	return commit, commit.ValidateBasic()
  1006  }
  1007  
  1008  //-----------------------------------------------------------------------------
  1009  
  1010  // Data contains all the available Data of the block.
  1011  // Data with reserved namespaces (Txs, IntermediateStateRoots, Evidence) and
  1012  // Celestia application specific Blobs.
  1013  type Data struct {
  1014  	// Txs that will be applied by state @ block.Height+1.
  1015  	// NOTE: not all txs here are valid.  We're just agreeing on the order first.
  1016  	// This means that block.AppHash does not include these txs.
  1017  	Txs Txs `json:"txs"`
  1018  
  1019  	// SquareSize is the size of the square after splitting all the block data
  1020  	// into shares. The erasure data is discarded after generation, and keeping this
  1021  	// value avoids unnecessarily regenerating all of the shares when returning
  1022  	// proofs that some element was included in the block
  1023  	SquareSize uint64 `json:"square_size"`
  1024  
  1025  	// Volatile
  1026  	hash cmtbytes.HexBytes
  1027  }
  1028  
  1029  // Hash returns the hash of the data
  1030  func (data *Data) Hash() cmtbytes.HexBytes {
  1031  	if data == nil {
  1032  		return (Txs{}).Hash()
  1033  	}
  1034  	if data.hash == nil {
  1035  		data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs
  1036  	}
  1037  
  1038  	// this is the expected behavior where `data.hash` was set by celestia-app
  1039  	// in PrepareProposal
  1040  	return data.hash
  1041  }
  1042  
  1043  type Blob struct {
  1044  	// NamespaceVersion is the version of the namespace. Used in conjunction
  1045  	// with NamespaceID to determine the namespace of this blob.
  1046  	NamespaceVersion uint8
  1047  
  1048  	// NamespaceID defines the namespace ID of this blob. Used in conjunction
  1049  	// with NamespaceVersion to determine the namespace of this blob.
  1050  	NamespaceID []byte
  1051  
  1052  	// Data is the actual data of the blob.
  1053  	// (e.g. a block of a virtual sidechain).
  1054  	Data []byte
  1055  
  1056  	// ShareVersion is the version of the share format that this blob should use
  1057  	// when encoded into shares.
  1058  	ShareVersion uint8
  1059  }
  1060  
  1061  // Namespace returns the namespace of this blob encoded as a byte slice.
  1062  func (b Blob) Namespace() []byte {
  1063  	return append([]byte{b.NamespaceVersion}, b.NamespaceID...)
  1064  }
  1065  
  1066  // StringIndented returns an indented string representation of the transactions.
  1067  func (data *Data) StringIndented(indent string) string {
  1068  	if data == nil {
  1069  		return "nil-Data"
  1070  	}
  1071  	txStrings := make([]string, cmtmath.MinInt(len(data.Txs), 21))
  1072  	for i, tx := range data.Txs {
  1073  		if i == 20 {
  1074  			txStrings[i] = fmt.Sprintf("... (%v total)", len(data.Txs))
  1075  			break
  1076  		}
  1077  		txStrings[i] = fmt.Sprintf("%X (%d bytes)", tx.Hash(), len(tx))
  1078  	}
  1079  	return fmt.Sprintf(`Data{
  1080  %s  %v
  1081  }`,
  1082  		indent, strings.Join(txStrings, "\n"+indent+"  "))
  1083  }
  1084  
  1085  // ToProto converts Data to protobuf
  1086  func (data *Data) ToProto() cmtproto.Data {
  1087  	tp := new(cmtproto.Data)
  1088  
  1089  	if len(data.Txs) > 0 {
  1090  		txBzs := make([][]byte, len(data.Txs))
  1091  		for i := range data.Txs {
  1092  			txBzs[i] = data.Txs[i]
  1093  		}
  1094  		tp.Txs = txBzs
  1095  	}
  1096  
  1097  	tp.Hash = data.hash
  1098  
  1099  	return *tp
  1100  }
  1101  
  1102  // DataFromProto takes a protobuf representation of Data &
  1103  // returns the native type.
  1104  func DataFromProto(dp *cmtproto.Data) (Data, error) {
  1105  	if dp == nil {
  1106  		return Data{}, errors.New("nil data")
  1107  	}
  1108  	data := new(Data)
  1109  
  1110  	if len(dp.Txs) > 0 {
  1111  		txBzs := make(Txs, len(dp.Txs))
  1112  		for i := range dp.Txs {
  1113  			txBzs[i] = Tx(dp.Txs[i])
  1114  		}
  1115  		data.Txs = txBzs
  1116  	} else {
  1117  		data.Txs = Txs{}
  1118  	}
  1119  
  1120  	data.hash = dp.Hash
  1121  
  1122  	return *data, nil
  1123  }
  1124  
  1125  //-----------------------------------------------------------------------------
  1126  
  1127  // EvidenceData contains any evidence of malicious wrong-doing by validators
  1128  type EvidenceData struct {
  1129  	Evidence EvidenceList `json:"evidence"`
  1130  
  1131  	// Volatile. Used as cache
  1132  	hash     cmtbytes.HexBytes
  1133  	byteSize int64
  1134  }
  1135  
  1136  // Hash returns the hash of the data.
  1137  func (data *EvidenceData) Hash() cmtbytes.HexBytes {
  1138  	if data.hash == nil {
  1139  		data.hash = data.Evidence.Hash()
  1140  	}
  1141  	return data.hash
  1142  }
  1143  
  1144  // ByteSize returns the total byte size of all the evidence
  1145  func (data *EvidenceData) ByteSize() int64 {
  1146  	if data.byteSize == 0 && len(data.Evidence) != 0 {
  1147  		pb, err := data.ToProto()
  1148  		if err != nil {
  1149  			panic(err)
  1150  		}
  1151  		data.byteSize = int64(pb.Size())
  1152  	}
  1153  	return data.byteSize
  1154  }
  1155  
  1156  // StringIndented returns a string representation of the evidence.
  1157  func (data *EvidenceData) StringIndented(indent string) string {
  1158  	if data == nil {
  1159  		return "nil-Evidence"
  1160  	}
  1161  	evStrings := make([]string, cmtmath.MinInt(len(data.Evidence), 21))
  1162  	for i, ev := range data.Evidence {
  1163  		if i == 20 {
  1164  			evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence))
  1165  			break
  1166  		}
  1167  		evStrings[i] = fmt.Sprintf("Evidence:%v", ev)
  1168  	}
  1169  	return fmt.Sprintf(`EvidenceData{
  1170  %s  %v
  1171  %s}#%v`,
  1172  		indent, strings.Join(evStrings, "\n"+indent+"  "),
  1173  		indent, data.hash)
  1174  }
  1175  
  1176  // ToProto converts EvidenceData to protobuf
  1177  func (data *EvidenceData) ToProto() (*cmtproto.EvidenceList, error) {
  1178  	if data == nil {
  1179  		return nil, errors.New("nil evidence data")
  1180  	}
  1181  
  1182  	evi := new(cmtproto.EvidenceList)
  1183  	eviBzs := make([]cmtproto.Evidence, len(data.Evidence))
  1184  	for i := range data.Evidence {
  1185  		protoEvi, err := EvidenceToProto(data.Evidence[i])
  1186  		if err != nil {
  1187  			return nil, err
  1188  		}
  1189  		eviBzs[i] = *protoEvi
  1190  	}
  1191  	evi.Evidence = eviBzs
  1192  
  1193  	return evi, nil
  1194  }
  1195  
  1196  // FromProto sets a protobuf EvidenceData to the given pointer.
  1197  func (data *EvidenceData) FromProto(eviData *cmtproto.EvidenceList) error {
  1198  	if eviData == nil {
  1199  		return errors.New("nil evidenceData")
  1200  	}
  1201  
  1202  	eviBzs := make(EvidenceList, len(eviData.Evidence))
  1203  	for i := range eviData.Evidence {
  1204  		evi, err := EvidenceFromProto(&eviData.Evidence[i])
  1205  		if err != nil {
  1206  			return err
  1207  		}
  1208  		eviBzs[i] = evi
  1209  	}
  1210  	data.Evidence = eviBzs
  1211  	data.byteSize = int64(eviData.Size())
  1212  
  1213  	return nil
  1214  }
  1215  
  1216  //--------------------------------------------------------------------------------
  1217  
  1218  // BlockID
  1219  type BlockID struct {
  1220  	Hash          cmtbytes.HexBytes `json:"hash"`
  1221  	PartSetHeader PartSetHeader     `json:"parts"`
  1222  }
  1223  
  1224  // Equals returns true if the BlockID matches the given BlockID
  1225  func (blockID BlockID) Equals(other BlockID) bool {
  1226  	return bytes.Equal(blockID.Hash, other.Hash) &&
  1227  		blockID.PartSetHeader.Equals(other.PartSetHeader)
  1228  }
  1229  
  1230  // Key returns a machine-readable string representation of the BlockID
  1231  func (blockID BlockID) Key() string {
  1232  	pbph := blockID.PartSetHeader.ToProto()
  1233  	bz, err := pbph.Marshal()
  1234  	if err != nil {
  1235  		panic(err)
  1236  	}
  1237  
  1238  	return fmt.Sprint(string(blockID.Hash), string(bz))
  1239  }
  1240  
  1241  // ValidateBasic performs basic validation.
  1242  func (blockID BlockID) ValidateBasic() error {
  1243  	// Hash can be empty in case of POLBlockID in Proposal.
  1244  	if err := ValidateHash(blockID.Hash); err != nil {
  1245  		return fmt.Errorf("wrong Hash")
  1246  	}
  1247  	if err := blockID.PartSetHeader.ValidateBasic(); err != nil {
  1248  		return fmt.Errorf("wrong PartSetHeader: %v", err)
  1249  	}
  1250  	return nil
  1251  }
  1252  
  1253  // IsZero returns true if this is the BlockID of a nil block.
  1254  func (blockID BlockID) IsZero() bool {
  1255  	return len(blockID.Hash) == 0 &&
  1256  		blockID.PartSetHeader.IsZero()
  1257  }
  1258  
  1259  // IsComplete returns true if this is a valid BlockID of a non-nil block.
  1260  func (blockID BlockID) IsComplete() bool {
  1261  	return len(blockID.Hash) == tmhash.Size &&
  1262  		blockID.PartSetHeader.Total > 0 &&
  1263  		len(blockID.PartSetHeader.Hash) == tmhash.Size
  1264  }
  1265  
  1266  // String returns a human readable string representation of the BlockID.
  1267  //
  1268  // 1. hash
  1269  // 2. part set header
  1270  //
  1271  // See PartSetHeader#String
  1272  func (blockID BlockID) String() string {
  1273  	return fmt.Sprintf(`%v:%v`, blockID.Hash, blockID.PartSetHeader)
  1274  }
  1275  
  1276  // ToProto converts BlockID to protobuf
  1277  func (blockID *BlockID) ToProto() cmtproto.BlockID {
  1278  	if blockID == nil {
  1279  		return cmtproto.BlockID{}
  1280  	}
  1281  
  1282  	return cmtproto.BlockID{
  1283  		Hash:          blockID.Hash,
  1284  		PartSetHeader: blockID.PartSetHeader.ToProto(),
  1285  	}
  1286  }
  1287  
  1288  // FromProto sets a protobuf BlockID to the given pointer.
  1289  // It returns an error if the block id is invalid.
  1290  func BlockIDFromProto(bID *cmtproto.BlockID) (*BlockID, error) {
  1291  	if bID == nil {
  1292  		return nil, errors.New("nil BlockID")
  1293  	}
  1294  
  1295  	blockID := new(BlockID)
  1296  	ph, err := PartSetHeaderFromProto(&bID.PartSetHeader)
  1297  	if err != nil {
  1298  		return nil, err
  1299  	}
  1300  
  1301  	blockID.PartSetHeader = *ph
  1302  	blockID.Hash = bID.Hash
  1303  
  1304  	return blockID, blockID.ValidateBasic()
  1305  }