github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/header.go (about)

     1  package flow
     2  
     3  import (
     4  	"encoding/json"
     5  	"time"
     6  
     7  	"github.com/fxamacker/cbor/v2"
     8  	"github.com/vmihailenco/msgpack/v4"
     9  
    10  	cborcodec "github.com/onflow/flow-go/model/encoding/cbor"
    11  	"github.com/onflow/flow-go/model/fingerprint"
    12  )
    13  
    14  // Header contains all meta-data for a block, as well as a hash representing
    15  // the combined payload of the entire block. It is what consensus nodes agree
    16  // on after validating the contents against the payload hash.
    17  type Header struct {
    18  	// ChainID is a chain-specific value to prevent replay attacks.
    19  	ChainID ChainID
    20  	// ParentID is the ID of this block's parent.
    21  	ParentID Identifier
    22  	// Height is the height of the parent + 1
    23  	Height uint64
    24  	// PayloadHash is a hash of the payload of this block.
    25  	PayloadHash Identifier
    26  	// Timestamp is the time at which this block was proposed.
    27  	// The proposer can choose any time, so this should not be trusted as accurate.
    28  	Timestamp time.Time
    29  	// View number at which this block was proposed.
    30  	View uint64
    31  	// ParentView number at which parent block was proposed.
    32  	ParentView uint64
    33  	// ParentVoterIndices is a bitvector that represents all the voters for the parent block.
    34  	ParentVoterIndices []byte
    35  	// ParentVoterSigData is an aggregated signature over the parent block. Not a single cryptographic
    36  	// signature since the data represents cryptographic signatures serialized in some way (concatenation or other)
    37  	// A quorum certificate can be extracted from the header.
    38  	// This field is the SigData field of the extracted quorum certificate.
    39  	ParentVoterSigData []byte
    40  	// ProposerID is a proposer identifier for the block
    41  	ProposerID Identifier
    42  	// ProposerSigData is a signature of the proposer over the new block. Not a single cryptographic
    43  	// signature since the data represents cryptographic signatures serialized in some way (concatenation or other)
    44  	ProposerSigData []byte
    45  	// LastViewTC is a timeout certificate for previous view, it can be nil
    46  	// it has to be present if previous round ended with timeout.
    47  	LastViewTC *TimeoutCertificate
    48  }
    49  
    50  // Body returns the immutable part of the block header.
    51  func (h Header) Body() interface{} {
    52  	return struct {
    53  		ChainID            ChainID
    54  		ParentID           Identifier
    55  		Height             uint64
    56  		PayloadHash        Identifier
    57  		Timestamp          uint64
    58  		View               uint64
    59  		ParentView         uint64
    60  		ParentVoterIndices []byte
    61  		ParentVoterSigData []byte
    62  		ProposerID         Identifier
    63  		LastViewTCID       Identifier
    64  	}{
    65  		ChainID:            h.ChainID,
    66  		ParentID:           h.ParentID,
    67  		Height:             h.Height,
    68  		PayloadHash:        h.PayloadHash,
    69  		Timestamp:          uint64(h.Timestamp.UnixNano()),
    70  		View:               h.View,
    71  		ParentView:         h.ParentView,
    72  		ParentVoterIndices: h.ParentVoterIndices,
    73  		ParentVoterSigData: h.ParentVoterSigData,
    74  		ProposerID:         h.ProposerID,
    75  		LastViewTCID:       h.LastViewTC.ID(),
    76  	}
    77  }
    78  
    79  // QuorumCertificate returns quorum certificate that is incorporated in the block header.
    80  func (h Header) QuorumCertificate() *QuorumCertificate {
    81  	return &QuorumCertificate{
    82  		BlockID:       h.ParentID,
    83  		View:          h.ParentView,
    84  		SignerIndices: h.ParentVoterIndices,
    85  		SigData:       h.ParentVoterSigData,
    86  	}
    87  }
    88  
    89  func (h Header) Fingerprint() []byte {
    90  	return fingerprint.Fingerprint(h.Body())
    91  }
    92  
    93  // ID returns a unique ID to singularly identify the header and its block
    94  // within the flow system.
    95  func (h Header) ID() Identifier {
    96  	return MakeID(h)
    97  }
    98  
    99  // Checksum returns the checksum of the header.
   100  func (h Header) Checksum() Identifier {
   101  	return MakeID(h)
   102  }
   103  
   104  // MarshalJSON makes sure the timestamp is encoded in UTC.
   105  func (h Header) MarshalJSON() ([]byte, error) {
   106  
   107  	// NOTE: this is just a sanity check to make sure that we don't get
   108  	// different encodings if someone forgets to use UTC timestamps
   109  	if h.Timestamp.Location() != time.UTC {
   110  		h.Timestamp = h.Timestamp.UTC()
   111  	}
   112  
   113  	// we use an alias to avoid endless recursion; the alias will not have the
   114  	// marshal function and encode like a raw header
   115  	type Encodable Header
   116  	return json.Marshal(struct {
   117  		Encodable
   118  		ID string
   119  	}{
   120  		Encodable: Encodable(h),
   121  		ID:        h.ID().String(),
   122  	})
   123  }
   124  
   125  // UnmarshalJSON makes sure the timestamp is decoded in UTC.
   126  func (h *Header) UnmarshalJSON(data []byte) error {
   127  
   128  	// we use an alias to avoid endless recursion; the alias will not have the
   129  	// unmarshal function and decode like a raw header
   130  	type Decodable *Header
   131  	err := json.Unmarshal(data, Decodable(h))
   132  
   133  	// NOTE: the timezone check is not required for JSON, as it already encodes
   134  	// timezones, but it doesn't hurt to add it in case someone messes with the
   135  	// raw encoded format
   136  	if h.Timestamp.Location() != time.UTC {
   137  		h.Timestamp = h.Timestamp.UTC()
   138  	}
   139  
   140  	return err
   141  }
   142  
   143  // MarshalCBOR makes sure the timestamp is encoded in UTC.
   144  func (h Header) MarshalCBOR() ([]byte, error) {
   145  
   146  	// NOTE: this is just a sanity check to make sure that we don't get
   147  	// different encodings if someone forgets to use UTC timestamps
   148  	if h.Timestamp.Location() != time.UTC {
   149  		h.Timestamp = h.Timestamp.UTC()
   150  	}
   151  
   152  	// we use an alias to avoid endless recursion; the alias will not have the
   153  	// marshal function and encode like a raw header
   154  	type Encodable Header
   155  	return cborcodec.EncMode.Marshal(Encodable(h))
   156  }
   157  
   158  // UnmarshalCBOR makes sure the timestamp is decoded in UTC.
   159  func (h *Header) UnmarshalCBOR(data []byte) error {
   160  
   161  	// we use an alias to avoid endless recursion; the alias will not have the
   162  	// unmarshal function and decode like a raw header
   163  	// NOTE: for some reason, the pointer alias works for JSON to not recurse,
   164  	// but msgpack will still recurse; we have to do an extra struct copy here
   165  	type Decodable Header
   166  	decodable := Decodable(*h)
   167  	err := cbor.Unmarshal(data, &decodable)
   168  	*h = Header(decodable)
   169  
   170  	// NOTE: the timezone check is not required for CBOR, as it already encodes
   171  	// timezones, but it doesn't hurt to add it in case someone messes with the
   172  	// raw encoded format
   173  	if h.Timestamp.Location() != time.UTC {
   174  		h.Timestamp = h.Timestamp.UTC()
   175  	}
   176  
   177  	return err
   178  }
   179  
   180  // MarshalMsgpack makes sure the timestamp is encoded in UTC.
   181  func (h Header) MarshalMsgpack() ([]byte, error) {
   182  
   183  	// NOTE: this is just a sanity check to make sure that we don't get
   184  	// different encodings if someone forgets to use UTC timestamps
   185  	if h.Timestamp.Location() != time.UTC {
   186  		h.Timestamp = h.Timestamp.UTC()
   187  	}
   188  
   189  	// we use an alias to avoid endless recursion; the alias will not have the
   190  	// marshal function and encode like a raw header
   191  	type Encodable Header
   192  	return msgpack.Marshal(Encodable(h))
   193  }
   194  
   195  // UnmarshalMsgpack makes sure the timestamp is decoded in UTC.
   196  func (h *Header) UnmarshalMsgpack(data []byte) error {
   197  
   198  	// we use an alias to avoid endless recursion; the alias will not have the
   199  	// unmarshal function and decode like a raw header
   200  	// NOTE: for some reason, the pointer alias works for JSON to not recurse,
   201  	// but msgpack will still recurse; we have to do an extra struct copy here
   202  	type Decodable Header
   203  	decodable := Decodable(*h)
   204  	err := msgpack.Unmarshal(data, &decodable)
   205  	*h = Header(decodable)
   206  
   207  	// NOTE: Msgpack unmarshals timestamps with the local timezone, which means
   208  	// that a block ID would suddenly be different after encoding and decoding
   209  	// on a machine with non-UTC local time
   210  	if h.Timestamp.Location() != time.UTC {
   211  		h.Timestamp = h.Timestamp.UTC()
   212  	}
   213  
   214  	return err
   215  }