github.com/516108736/tendermint@v0.36.0/types/light.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	tmproto "github.com/tendermint/tendermint/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() (*tmproto.LightBlock, error) {
    67  	if lb == nil {
    68  		return nil, nil
    69  	}
    70  
    71  	lbp := new(tmproto.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 *tmproto.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  // ValidateBasic does basic consistency checks and makes sure the header
   124  // and commit are consistent.
   125  //
   126  // NOTE: This does not actually check the cryptographic signatures.  Make sure
   127  // to use a Verifier to validate the signatures actually provide a
   128  // significantly strong proof for this header's validity.
   129  func (sh SignedHeader) ValidateBasic(chainID string) error {
   130  	if sh.Header == nil {
   131  		return errors.New("missing header")
   132  	}
   133  	if sh.Commit == nil {
   134  		return errors.New("missing commit")
   135  	}
   136  
   137  	if err := sh.Header.ValidateBasic(); err != nil {
   138  		return fmt.Errorf("invalid header: %w", err)
   139  	}
   140  	if err := sh.Commit.ValidateBasic(); err != nil {
   141  		return fmt.Errorf("invalid commit: %w", err)
   142  	}
   143  
   144  	if sh.ChainID != chainID {
   145  		return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
   146  	}
   147  
   148  	// Make sure the header is consistent with the commit.
   149  	if sh.Commit.Height != sh.Height {
   150  		return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
   151  	}
   152  	if hhash, chash := sh.Hash(), sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {
   153  		return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash)
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  // String returns a string representation of SignedHeader.
   160  func (sh SignedHeader) String() string {
   161  	return sh.StringIndented("")
   162  }
   163  
   164  // StringIndented returns an indented string representation of SignedHeader.
   165  //
   166  // Header
   167  // Commit
   168  func (sh SignedHeader) StringIndented(indent string) string {
   169  	return fmt.Sprintf(`SignedHeader{
   170  %s  %v
   171  %s  %v
   172  %s}`,
   173  		indent, sh.Header.StringIndented(indent+"  "),
   174  		indent, sh.Commit.StringIndented(indent+"  "),
   175  		indent)
   176  }
   177  
   178  // ToProto converts SignedHeader to protobuf
   179  func (sh *SignedHeader) ToProto() *tmproto.SignedHeader {
   180  	if sh == nil {
   181  		return nil
   182  	}
   183  
   184  	psh := new(tmproto.SignedHeader)
   185  	if sh.Header != nil {
   186  		psh.Header = sh.Header.ToProto()
   187  	}
   188  	if sh.Commit != nil {
   189  		psh.Commit = sh.Commit.ToProto()
   190  	}
   191  
   192  	return psh
   193  }
   194  
   195  // FromProto sets a protobuf SignedHeader to the given pointer.
   196  // It returns an error if the header or the commit is invalid.
   197  func SignedHeaderFromProto(shp *tmproto.SignedHeader) (*SignedHeader, error) {
   198  	if shp == nil {
   199  		return nil, errors.New("nil SignedHeader")
   200  	}
   201  
   202  	sh := new(SignedHeader)
   203  
   204  	if shp.Header != nil {
   205  		h, err := HeaderFromProto(shp.Header)
   206  		if err != nil {
   207  			return nil, err
   208  		}
   209  		sh.Header = &h
   210  	}
   211  
   212  	if shp.Commit != nil {
   213  		c, err := CommitFromProto(shp.Commit)
   214  		if err != nil {
   215  			return nil, err
   216  		}
   217  		sh.Commit = c
   218  	}
   219  
   220  	return sh, nil
   221  }