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