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