state/block.go
160 lines
1package state23import (4"crypto/sha256"5"encoding/binary"6"errors"78"peoplecoin/trie"9)1011// Header is a block header. Its hash is the signing message; the block12// hash is SHA256(header_hash ‖ sig).13type Header struct {14Number uint6415Slot uint6416Time uint64 // Unix time of the slot's start: prev.time + (slot − prev.slot)·6017TxTrie Hash18Coin Hash19Token Hash20Election [2]Hash21Rng [2]Hash22Reg [2]Hash23Prev Hash // previous block hash; zero for the first block24Validator Address25Nonce Hash // election commit preimage: SHA256(validator ‖ nonce) is the vote26Sig [64]byte27}2829// HeaderSize is the fixed encoded size: 3×8 + 12×32 + 64.30const HeaderSize = 24 + 384 + 643132var ErrHeaderSize = errors.New("state: bad header size")3334// signingBytes is the header without the signature.35func (h *Header) signingBytes() []byte {36b := make([]byte, 0, HeaderSize-64)37b = binary.BigEndian.AppendUint64(b, h.Number)38b = binary.BigEndian.AppendUint64(b, h.Slot)39b = binary.BigEndian.AppendUint64(b, h.Time)40for _, r := range []Hash{h.TxTrie, h.Coin, h.Token, h.Election[0], h.Election[1], h.Rng[0], h.Rng[1], h.Reg[0], h.Reg[1], h.Prev, h.Validator, h.Nonce} {41b = append(b, r[:]...)42}43return b44}4546// SigningHash is SHA256 over number ‖ slot ‖ time ‖ the nine roots ‖ prev ‖47// validator ‖ nonce.48func (h *Header) SigningHash() Hash { return sha256.Sum256(h.signingBytes()) }4950// Hash is the block hash, SHA256(header_hash ‖ sig).51func (h *Header) Hash() Hash {52sh := h.SigningHash()53return sha256.Sum256(append(sh[:], h.Sig[:]...))54}5556// Bytes encodes the header.57func (h *Header) Bytes() []byte { return append(h.signingBytes(), h.Sig[:]...) }5859// DecodeHeader parses a header.60func DecodeHeader(b []byte) (*Header, error) {61if len(b) != HeaderSize {62return nil, ErrHeaderSize63}64h := &Header{}65h.Number = binary.BigEndian.Uint64(b)66h.Slot = binary.BigEndian.Uint64(b[8:])67h.Time = binary.BigEndian.Uint64(b[16:])68p := 2469for _, dst := range []*Hash{&h.TxTrie, &h.Coin, &h.Token, &h.Election[0], &h.Election[1], &h.Rng[0], &h.Rng[1], &h.Reg[0], &h.Reg[1], &h.Prev, &h.Validator, &h.Nonce} {70copy(dst[:], b[p:p+32])71p += 3272}73copy(h.Sig[:], b[p:])74return h, nil75}7677// setRoots writes the state roots into the header.78func (h *Header) setRoots(tx trie.Hash, r Roots) {79h.TxTrie = Hash(tx)80h.Coin = Hash(r.Coin)81h.Token = Hash(r.Token)82h.Election = [2]Hash{Hash(r.Election[0]), Hash(r.Election[1])}83h.Rng = [2]Hash{Hash(r.Rng[0]), Hash(r.Rng[1])}84h.Reg = [2]Hash{Hash(r.Reg[0]), Hash(r.Reg[1])}85}8687// rootsMatch reports whether the header commits to exactly these roots.88func (h *Header) rootsMatch(tx trie.Hash, r Roots) bool {89return h.TxTrie == Hash(tx) && h.Coin == Hash(r.Coin) && h.Token == Hash(r.Token) &&90h.Election[0] == Hash(r.Election[0]) && h.Election[1] == Hash(r.Election[1]) &&91h.Rng[0] == Hash(r.Rng[0]) && h.Rng[1] == Hash(r.Rng[1]) &&92h.Reg[0] == Hash(r.Reg[0]) && h.Reg[1] == Hash(r.Reg[1])93}9495// Block is a header and its operations. The order of operations does not96// matter to validation; the tx trie commits to the set.97type Block struct {98Header Header99Ops []Op100}101102// Bytes encodes header ‖ uint32 n ‖ (uint32 len ‖ op)…103func (b *Block) Bytes() []byte {104out := b.Header.Bytes()105out = binary.BigEndian.AppendUint32(out, uint32(len(b.Ops)))106for _, op := range b.Ops {107enc := op.Bytes()108out = binary.BigEndian.AppendUint32(out, uint32(len(enc)))109out = append(out, enc...)110}111return out112}113114// DecodeBlock parses a block.115func DecodeBlock(b []byte) (*Block, error) {116if len(b) < HeaderSize+4 {117return nil, ErrEncoding118}119h, err := DecodeHeader(b[:HeaderSize])120if err != nil {121return nil, err122}123blk := &Block{Header: *h}124b = b[HeaderSize:]125n := binary.BigEndian.Uint32(b)126b = b[4:]127for i := uint32(0); i < n; i++ {128if len(b) < 4 {129return nil, ErrEncoding130}131l := binary.BigEndian.Uint32(b)132b = b[4:]133if uint64(len(b)) < uint64(l) {134return nil, ErrEncoding135}136op, err := DecodeOp(b[:l])137if err != nil {138return nil, err139}140blk.Ops = append(blk.Ops, op)141b = b[l:]142}143if len(b) != 0 {144return nil, ErrEncoding145}146return blk, nil147}148149// Better reports whether tip a should be preferred over tip b under the150// fork choice: the higher block number wins; at equal numbers the lower151// slot (fewer skipped slots) wins; otherwise keep b. The rule that forks152// cannot reach back past two period boundaries is enforced by whoever153// keeps the chains, by refusing to consider a fork that diverges earlier.154func Better(a, b *State) bool {155if a.Number != b.Number {156return a.Number > b.Number157}158return a.Slot < b.Slot159}