github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/header.go (about)

     1  // Copyright (C) 2013-2017, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.)
     2  // Use of this source code is governed by GPLv3 found in the LICENSE file
     3  //----------------------------------------------------------------------------------------
     4  
     5  // implements chain header structures & coding
     6  
     7  package holochain
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/binary"
    12  	"fmt"
    13  	. "github.com/holochain/holochain-proto/hash"
    14  	b58 "github.com/jbenet/go-base58"
    15  	ic "github.com/libp2p/go-libp2p-crypto"
    16  	"io"
    17  	"time"
    18  )
    19  
    20  type Signature struct {
    21  	S []byte
    22  }
    23  
    24  // Header holds chain links, type, timestamp and signature
    25  type Header struct {
    26  	Type       string
    27  	Time       time.Time
    28  	HeaderLink Hash // link to previous header
    29  	EntryLink  Hash // link to entry
    30  	TypeLink   Hash // link to header of previous header of this type
    31  	Sig        Signature
    32  	Change     Hash
    33  }
    34  
    35  // newHeader makes Header object linked to a previous Header by hash
    36  func newHeader(hashSpec HashSpec, now time.Time, t string, entry Entry, privKey ic.PrivKey, prev Hash, prevType Hash, change Hash) (hash Hash, header *Header, err error) {
    37  	var hd Header
    38  	hd.Type = t
    39  	now = now.Round(0)
    40  	hd.Time = now
    41  	hd.HeaderLink = prev
    42  	hd.TypeLink = prevType
    43  	hd.Change = change
    44  
    45  	hd.EntryLink, err = entry.Sum(hashSpec)
    46  	if err != nil {
    47  		return
    48  	}
    49  
    50  	// sign the hash of the entry
    51  	sig, err := privKey.Sign([]byte(hd.EntryLink))
    52  	if err != nil {
    53  		return
    54  	}
    55  	hd.Sig = Signature{S: sig}
    56  
    57  	hash, _, err = (&hd).Sum(hashSpec)
    58  	if err != nil {
    59  		return
    60  	}
    61  
    62  	header = &hd
    63  	return
    64  }
    65  
    66  // Sum encodes and creates a hash digest of the header
    67  func (hd *Header) Sum(spec HashSpec) (hash Hash, b []byte, err error) {
    68  	b, err = hd.Marshal()
    69  	if err == nil {
    70  		hash, err = Sum(spec, b)
    71  	}
    72  	return
    73  }
    74  
    75  // B58String encodes a signature as a b58string
    76  func (sig Signature) B58String() (result string) {
    77  	return b58.Encode(sig.S)
    78  }
    79  
    80  // Equal tests signature equality
    81  func (sig1 Signature) Equal(sig2 Signature) bool {
    82  	return bytes.Equal(sig1.S, sig2.S)
    83  }
    84  
    85  // SignatureFromB58String encodes a signature as a b58string
    86  func SignatureFromB58String(encoded string) (sig Signature) {
    87  	sig.S = b58.Decode(encoded)
    88  	return
    89  }
    90  
    91  // ToJSON serializes a header to JSON
    92  func (hd *Header) ToJSON() (result string, err error) {
    93  	result = fmt.Sprintf(
    94  		`{"Type":"%s","Time":"%v","EntryLink":"%s","HeaderLink":"%s","TypeLink":"%s","Signature":"%s"}`,
    95  		jsSanitizeString(hd.Type),
    96  		hd.Time,
    97  		hd.EntryLink.String(),
    98  		hd.HeaderLink.String(),
    99  		hd.TypeLink.String(),
   100  		hd.Sig.B58String(),
   101  	)
   102  	return
   103  }
   104  
   105  // Marshal writes a header to bytes
   106  func (hd *Header) Marshal() (b []byte, err error) {
   107  	var s bytes.Buffer
   108  	err = MarshalHeader(&s, hd)
   109  	if err == nil {
   110  		b = s.Bytes()
   111  	}
   112  	return
   113  }
   114  
   115  func writeStr(writer io.Writer, str string) (err error) {
   116  	var b []byte
   117  	b = []byte(str)
   118  	l := uint8(len(b))
   119  	err = binary.Write(writer, binary.LittleEndian, l)
   120  	if err != nil {
   121  		return
   122  	}
   123  	err = binary.Write(writer, binary.LittleEndian, b)
   124  	return
   125  }
   126  
   127  // MarshalHeader writes a header to a binary stream
   128  func MarshalHeader(writer io.Writer, hd *Header) (err error) {
   129  	err = writeStr(writer, hd.Type)
   130  	if err != nil {
   131  		return
   132  	}
   133  
   134  	var b []byte
   135  	b, err = hd.Time.MarshalBinary()
   136  	err = binary.Write(writer, binary.LittleEndian, b)
   137  	if err != nil {
   138  		return
   139  	}
   140  
   141  	err = hd.HeaderLink.MarshalHash(writer)
   142  	if err != nil {
   143  		return
   144  	}
   145  
   146  	err = hd.EntryLink.MarshalHash(writer)
   147  	if err != nil {
   148  		return
   149  	}
   150  
   151  	err = hd.TypeLink.MarshalHash(writer)
   152  	if err != nil {
   153  		return
   154  	}
   155  	err = MarshalSignature(writer, &hd.Sig)
   156  	if err != nil {
   157  		return
   158  	}
   159  
   160  	err = hd.Change.MarshalHash(writer)
   161  	if err != nil {
   162  		return
   163  	}
   164  
   165  	// write out 0 for future expansion (meta)
   166  	z := uint64(0)
   167  	err = binary.Write(writer, binary.LittleEndian, &z)
   168  	if err != nil {
   169  		return
   170  	}
   171  	return
   172  }
   173  
   174  // Unmarshal reads a header from bytes
   175  func (hd *Header) Unmarshal(b []byte, hashSize int) (err error) {
   176  	s := bytes.NewBuffer(b)
   177  	err = UnmarshalHeader(s, hd, hashSize)
   178  	return
   179  }
   180  
   181  func readStr(reader io.Reader) (str string, err error) {
   182  	var l uint8
   183  	err = binary.Read(reader, binary.LittleEndian, &l)
   184  	if err != nil {
   185  		return
   186  	}
   187  
   188  	var b = make([]byte, l)
   189  	err = binary.Read(reader, binary.LittleEndian, b)
   190  	if err != nil {
   191  		return
   192  	}
   193  	str = string(b)
   194  	return
   195  }
   196  
   197  // UnmarshalHeader reads a Header from a binary stream
   198  func UnmarshalHeader(reader io.Reader, hd *Header, hashSize int) (err error) {
   199  
   200  	hd.Type, err = readStr(reader)
   201  	if err != nil {
   202  		return
   203  	}
   204  
   205  	var b = make([]byte, 15)
   206  	err = binary.Read(reader, binary.LittleEndian, b)
   207  	if err != nil {
   208  		return
   209  	}
   210  	hd.Time.UnmarshalBinary(b)
   211  
   212  	hd.HeaderLink, err = UnmarshalHash(reader)
   213  	if err != nil {
   214  		return
   215  	}
   216  
   217  	hd.EntryLink, err = UnmarshalHash(reader)
   218  	if err != nil {
   219  		return
   220  	}
   221  
   222  	hd.TypeLink, err = UnmarshalHash(reader)
   223  	if err != nil {
   224  		return
   225  	}
   226  
   227  	err = UnmarshalSignature(reader, &hd.Sig)
   228  	if err != nil {
   229  		return
   230  	}
   231  
   232  	hd.Change, err = UnmarshalHash(reader)
   233  	if err != nil {
   234  		return
   235  	}
   236  
   237  	z := uint64(0)
   238  	err = binary.Read(reader, binary.LittleEndian, &z)
   239  	if err != nil {
   240  		return
   241  	}
   242  	return
   243  }
   244  
   245  // MarshalSignature writes a signature to a binary stream
   246  func MarshalSignature(writer io.Writer, s *Signature) (err error) {
   247  	l := uint8(len(s.S))
   248  	err = binary.Write(writer, binary.LittleEndian, l)
   249  	if err != nil {
   250  		return
   251  	}
   252  	err = binary.Write(writer, binary.LittleEndian, s.S)
   253  	if err != nil {
   254  		return
   255  	}
   256  	return
   257  }
   258  
   259  // UnmarshalSignature reads a Signature from a binary stream
   260  func UnmarshalSignature(reader io.Reader, s *Signature) (err error) {
   261  	var l uint8
   262  	err = binary.Read(reader, binary.LittleEndian, &l)
   263  	if err != nil {
   264  		return
   265  	}
   266  	var b = make([]byte, l)
   267  	err = binary.Read(reader, binary.LittleEndian, b)
   268  	if err != nil {
   269  		return
   270  	}
   271  	s.S = b
   272  	return
   273  }