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 }