github.com/aakash4dev/cometbft@v0.38.2/types/light.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	cmtproto "github.com/aakash4dev/cometbft/proto/tendermint/types"
     9  )
    10  
    11  // LightBlock is a SignedHeader and a ValidatorSet.
    12  // It is the basis of the light client
    13  type LightBlock struct {
    14  	*SignedHeader `json:"signed_header"`
    15  	ValidatorSet  *ValidatorSet `json:"validator_set"`
    16  }
    17  
    18  // ValidateBasic checks that the data is correct and consistent
    19  //
    20  // This does no verification of the signatures
    21  func (lb LightBlock) ValidateBasic(chainID string) error {
    22  	if lb.SignedHeader == nil {
    23  		return errors.New("missing signed header")
    24  	}
    25  	if lb.ValidatorSet == nil {
    26  		return errors.New("missing validator set")
    27  	}
    28  
    29  	if err := lb.SignedHeader.ValidateBasic(chainID); err != nil {
    30  		return fmt.Errorf("invalid signed header: %w", err)
    31  	}
    32  	if err := lb.ValidatorSet.ValidateBasic(); err != nil {
    33  		return fmt.Errorf("invalid validator set: %w", err)
    34  	}
    35  
    36  	// make sure the validator set is consistent with the header
    37  	if valSetHash := lb.ValidatorSet.Hash(); !bytes.Equal(lb.SignedHeader.ValidatorsHash, valSetHash) {
    38  		return fmt.Errorf("expected validator hash of header to match validator set hash (%X != %X)",
    39  			lb.SignedHeader.ValidatorsHash, valSetHash,
    40  		)
    41  	}
    42  
    43  	return nil
    44  }
    45  
    46  // String returns a string representation of the LightBlock
    47  func (lb LightBlock) String() string {
    48  	return lb.StringIndented("")
    49  }
    50  
    51  // StringIndented returns an indented string representation of the LightBlock
    52  //
    53  // SignedHeader
    54  // ValidatorSet
    55  func (lb LightBlock) StringIndented(indent string) string {
    56  	return fmt.Sprintf(`LightBlock{
    57  %s  %v
    58  %s  %v
    59  %s}`,
    60  		indent, lb.SignedHeader.StringIndented(indent+"  "),
    61  		indent, lb.ValidatorSet.StringIndented(indent+"  "),
    62  		indent)
    63  }
    64  
    65  // ToProto converts the LightBlock to protobuf
    66  func (lb *LightBlock) ToProto() (*cmtproto.LightBlock, error) {
    67  	if lb == nil {
    68  		return nil, nil
    69  	}
    70  
    71  	lbp := new(cmtproto.LightBlock)
    72  	var err error
    73  	if lb.SignedHeader != nil {
    74  		lbp.SignedHeader = lb.SignedHeader.ToProto()
    75  	}
    76  	if lb.ValidatorSet != nil {
    77  		lbp.ValidatorSet, err = lb.ValidatorSet.ToProto()
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  	}
    82  
    83  	return lbp, nil
    84  }
    85  
    86  // LightBlockFromProto converts from protobuf back into the Lightblock.
    87  // An error is returned if either the validator set or signed header are invalid
    88  func LightBlockFromProto(pb *cmtproto.LightBlock) (*LightBlock, error) {
    89  	if pb == nil {
    90  		return nil, errors.New("nil light block")
    91  	}
    92  
    93  	lb := new(LightBlock)
    94  
    95  	if pb.SignedHeader != nil {
    96  		sh, err := SignedHeaderFromProto(pb.SignedHeader)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		lb.SignedHeader = sh
   101  	}
   102  
   103  	if pb.ValidatorSet != nil {
   104  		vals, err := ValidatorSetFromProto(pb.ValidatorSet)
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		lb.ValidatorSet = vals
   109  	}
   110  
   111  	return lb, nil
   112  }
   113  
   114  //-----------------------------------------------------------------------------
   115  
   116  // SignedHeader is a header along with the commits that prove it.
   117  type SignedHeader struct {
   118  	*Header `json:"header"`
   119  
   120  	Commit *Commit `json:"commit"`
   121  }
   122  
   123  // IsEmpty returns true if both the header and commit are nil.
   124  func (sh SignedHeader) IsEmpty() bool {
   125  	return sh.Header == nil && sh.Commit == nil
   126  }
   127  
   128  // ValidateBasic does basic consistency checks and makes sure the header
   129  // and commit are consistent.
   130  //
   131  // NOTE: This does not actually check the cryptographic signatures.  Make sure
   132  // to use a Verifier to validate the signatures actually provide a
   133  // significantly strong proof for this header's validity.
   134  func (sh SignedHeader) ValidateBasic(chainID string) error {
   135  	if sh.Header == nil {
   136  		return errors.New("missing header")
   137  	}
   138  	if sh.Commit == nil {
   139  		return errors.New("missing commit")
   140  	}
   141  
   142  	if err := sh.Header.ValidateBasic(); err != nil {
   143  		return fmt.Errorf("invalid header: %w", err)
   144  	}
   145  	if err := sh.Commit.ValidateBasic(); err != nil {
   146  		return fmt.Errorf("invalid commit: %w", err)
   147  	}
   148  
   149  	if sh.ChainID != chainID {
   150  		return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
   151  	}
   152  
   153  	// Make sure the header is consistent with the commit.
   154  	if sh.Commit.Height != sh.Height {
   155  		return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
   156  	}
   157  	if hhash, chash := sh.Header.Hash(), sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {
   158  		return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash)
   159  	}
   160  
   161  	return nil
   162  }
   163  
   164  // String returns a string representation of SignedHeader.
   165  func (sh SignedHeader) String() string {
   166  	return sh.StringIndented("")
   167  }
   168  
   169  // StringIndented returns an indented string representation of SignedHeader.
   170  //
   171  // Header
   172  // Commit
   173  func (sh SignedHeader) StringIndented(indent string) string {
   174  	return fmt.Sprintf(`SignedHeader{
   175  %s  %v
   176  %s  %v
   177  %s}`,
   178  		indent, sh.Header.StringIndented(indent+"  "),
   179  		indent, sh.Commit.StringIndented(indent+"  "),
   180  		indent)
   181  }
   182  
   183  // ToProto converts SignedHeader to protobuf
   184  func (sh *SignedHeader) ToProto() *cmtproto.SignedHeader {
   185  	if sh == nil {
   186  		return nil
   187  	}
   188  
   189  	psh := new(cmtproto.SignedHeader)
   190  	if sh.Header != nil {
   191  		psh.Header = sh.Header.ToProto()
   192  	}
   193  	if sh.Commit != nil {
   194  		psh.Commit = sh.Commit.ToProto()
   195  	}
   196  
   197  	return psh
   198  }
   199  
   200  // FromProto sets a protobuf SignedHeader to the given pointer.
   201  // It returns an error if the header or the commit is invalid.
   202  func SignedHeaderFromProto(shp *cmtproto.SignedHeader) (*SignedHeader, error) {
   203  	if shp == nil {
   204  		return nil, errors.New("nil SignedHeader")
   205  	}
   206  
   207  	sh := new(SignedHeader)
   208  
   209  	if shp.Header != nil {
   210  		h, err := HeaderFromProto(shp.Header)
   211  		if err != nil {
   212  			return nil, err
   213  		}
   214  		sh.Header = &h
   215  	}
   216  
   217  	if shp.Commit != nil {
   218  		c, err := CommitFromProto(shp.Commit)
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  		sh.Commit = c
   223  	}
   224  
   225  	return sh, nil
   226  }