github.com/onflow/flow-go@v0.33.17/ledger/trie.go (about) 1 package ledger 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "errors" 8 "fmt" 9 10 "github.com/fxamacker/cbor/v2" 11 12 cryptoHash "github.com/onflow/flow-go/crypto/hash" 13 "github.com/onflow/flow-go/ledger/common/bitutils" 14 "github.com/onflow/flow-go/ledger/common/hash" 15 ) 16 17 // Path captures storage path of a payload; 18 // where we store a payload in the ledger 19 type Path hash.Hash 20 21 func (p Path) MarshalJSON() ([]byte, error) { 22 return json.Marshal(hex.EncodeToString(p[:])) 23 } 24 25 // DummyPath is an arbitrary path value, used in function error returns. 26 var DummyPath = Path(hash.DummyHash) 27 28 // PathLen is the size of paths in bytes. 29 const PathLen = 32 30 31 // The node maximum height or the tree height. 32 // It corresponds to the path size in bits. 33 const NodeMaxHeight = PathLen * 8 34 35 // we are currently supporting paths of a size equal to 32 bytes. 36 // I.e. path length from the rootNode of a fully expanded tree to the leaf node is 256. 37 // A path of length k is comprised of k+1 vertices. Hence, we need 257 default hashes. 38 const defaultHashesNum = NodeMaxHeight + 1 39 40 // array to store all default hashes 41 var defaultHashes [defaultHashesNum]hash.Hash 42 43 func init() { 44 45 // default value and default hash value for a default node 46 var defaultLeafHash hash.Hash 47 castedPointer := (*[hash.HashLen]byte)(&defaultLeafHash) 48 cryptoHash.ComputeSHA3_256(castedPointer, []byte("default:")) 49 50 // Creates the Default hashes from base to level height 51 defaultHashes[0] = defaultLeafHash 52 for i := 1; i < defaultHashesNum; i++ { 53 defaultHashes[i] = hash.HashInterNode(defaultHashes[i-1], defaultHashes[i-1]) 54 } 55 } 56 57 // GetDefaultHashForHeight returns the default hashes of the SMT at a specified height. 58 // 59 // For each tree level N, there is a default hash equal to the chained 60 // hashing of the default value N times. 61 func GetDefaultHashForHeight(height int) hash.Hash { 62 return defaultHashes[height] 63 } 64 65 // ComputeCompactValue computes the value for the node considering the sub tree 66 // to only include this value and default values. It writes the hash result to the result input. 67 // UNCHECKED: payload!= nil 68 func ComputeCompactValue(path hash.Hash, value []byte, nodeHeight int) hash.Hash { 69 // if register is unallocated: return default hash 70 if len(value) == 0 { 71 return GetDefaultHashForHeight(nodeHeight) 72 } 73 74 var out hash.Hash 75 out = hash.HashLeaf(path, value) // we first compute the hash of the fully-expanded leaf 76 for h := 1; h <= nodeHeight; h++ { // then, we hash our way upwards towards the root until we hit the specified nodeHeight 77 // h is the height of the node, whose hash we are computing in this iteration. 78 // The hash is computed from the node's children at height h-1. 79 bit := bitutils.ReadBit(path[:], NodeMaxHeight-h) 80 if bit == 1 { // right branching 81 out = hash.HashInterNode(GetDefaultHashForHeight(h-1), out) 82 } else { // left branching 83 out = hash.HashInterNode(out, GetDefaultHashForHeight(h-1)) 84 } 85 } 86 return out 87 } 88 89 // TrieRead captures a trie read query 90 type TrieRead struct { 91 RootHash RootHash 92 Paths []Path 93 } 94 95 // TrieReadSinglePayload contains trie read query for a single payload 96 type TrieReadSingleValue struct { 97 RootHash RootHash 98 Path Path 99 } 100 101 // TrieUpdate holds all data for a trie update 102 type TrieUpdate struct { 103 RootHash RootHash 104 Paths []Path 105 Payloads []*Payload 106 } 107 108 // Size returns number of paths in the trie update 109 func (u *TrieUpdate) Size() int { 110 return len(u.Paths) 111 } 112 113 // IsEmpty returns true if key or value is not empty 114 func (u *TrieUpdate) IsEmpty() bool { 115 return u.Size() == 0 116 } 117 118 func (u *TrieUpdate) String() string { 119 str := "Trie Update:\n " 120 str += "\t triehash : " + u.RootHash.String() + "\n" 121 for i, p := range u.Paths { 122 str += fmt.Sprintf("\t\t path %d : %s\n", i, p) 123 } 124 str += fmt.Sprintf("\t paths len: %d , bytesize: %d\n", len(u.Paths), len(u.Paths)*PathLen) 125 tp := 0 126 for _, p := range u.Payloads { 127 tp += p.Size() 128 } 129 str += fmt.Sprintf("\t total size of payloads : %d \n", tp) 130 return str 131 } 132 133 // Equals compares this trie update to another trie update 134 func (u *TrieUpdate) Equals(other *TrieUpdate) bool { 135 if other == nil { 136 return false 137 } 138 if !u.RootHash.Equals(other.RootHash) { 139 return false 140 } 141 if len(u.Paths) != len(other.Paths) { 142 return false 143 } 144 for i := range u.Paths { 145 if !u.Paths[i].Equals(other.Paths[i]) { 146 return false 147 } 148 } 149 150 if len(u.Payloads) != len(other.Payloads) { 151 return false 152 } 153 for i := range u.Payloads { 154 if !u.Payloads[i].Equals(other.Payloads[i]) { 155 return false 156 } 157 } 158 return true 159 } 160 161 // RootHash captures the root hash of a trie 162 type RootHash hash.Hash 163 164 func (rh RootHash) MarshalJSON() ([]byte, error) { 165 return json.Marshal(rh.String()) 166 } 167 168 func (rh RootHash) String() string { 169 return hex.EncodeToString(rh[:]) 170 } 171 172 // Equals compares the root hash to another one 173 func (rh RootHash) Equals(o RootHash) bool { 174 return rh == o 175 } 176 177 // ToRootHash converts a byte slice into a root hash. 178 // It returns an error if the slice has an invalid length. 179 func ToRootHash(rootHashBytes []byte) (RootHash, error) { 180 var rootHash RootHash 181 if len(rootHashBytes) != len(rootHash) { 182 return RootHash(hash.DummyHash), fmt.Errorf("expecting %d bytes but got %d bytes", len(rootHash), len(rootHashBytes)) 183 } 184 copy(rootHash[:], rootHashBytes) 185 return rootHash, nil 186 } 187 188 func (p Path) String() string { 189 str := "" 190 for _, i := range p { 191 str += fmt.Sprintf("%08b", i) 192 } 193 str = str[0:8] + "..." + str[len(str)-8:] 194 return str 195 } 196 197 // Equals compares this path to another path 198 func (p Path) Equals(o Path) bool { 199 return p == o 200 } 201 202 // ToPath converts a byte slice into a path. 203 // It returns an error if the slice has an invalid length. 204 func ToPath(pathBytes []byte) (Path, error) { 205 var path Path 206 if len(pathBytes) != len(path) { 207 return DummyPath, fmt.Errorf("expecting %d bytes but got %d bytes", len(path), len(pathBytes)) 208 } 209 copy(path[:], pathBytes) 210 return path, nil 211 } 212 213 // encKey represents an encoded ledger key. 214 type encKey []byte 215 216 // Size returns the byte size of the encoded key. 217 func (k encKey) Size() int { 218 return len(k) 219 } 220 221 // String returns the string representation of the encoded key. 222 func (k encKey) String() string { 223 return hex.EncodeToString(k) 224 } 225 226 // Equals compares this encoded key to another encoded key. 227 // A nil encoded key is equivalent to an empty encoded key. 228 func (k encKey) Equals(other encKey) bool { 229 return bytes.Equal(k, other) 230 } 231 232 // DeepCopy returns a deep copy of the encoded key. 233 func (k encKey) DeepCopy() encKey { 234 newK := make([]byte, len(k)) 235 copy(newK, k) 236 return newK 237 } 238 239 // Payload is the smallest immutable storable unit in ledger 240 type Payload struct { 241 // encKey is key encoded using PayloadVersion. 242 // Version and type data are not encoded to save 3 bytes. 243 // NOTE: encKey translates to Key{} when encKey is 244 // one of these three values: 245 // nil, []byte{}, []byte{0,0}. 246 encKey encKey 247 value Value 248 } 249 250 // serializablePayload is used to serialize ledger.Payload. 251 // Encoder only serializes exported fields and ledger.Payload's 252 // key and value fields are not exported. So it is necessary to 253 // use serializablePayload for encoding. 254 type serializablePayload struct { 255 Key Key 256 Value Value 257 } 258 259 // MarshalJSON returns JSON encoding of p. 260 func (p Payload) MarshalJSON() ([]byte, error) { 261 k, err := p.Key() 262 if err != nil { 263 return nil, err 264 } 265 sp := serializablePayload{Key: k, Value: p.value} 266 return json.Marshal(sp) 267 } 268 269 // UnmarshalJSON unmarshals a JSON value of payload. 270 func (p *Payload) UnmarshalJSON(b []byte) error { 271 if p == nil { 272 return errors.New("UnmarshalJSON on nil Payload") 273 } 274 var sp serializablePayload 275 if err := json.Unmarshal(b, &sp); err != nil { 276 return err 277 } 278 p.encKey = encodeKey(&sp.Key, PayloadVersion) 279 p.value = sp.Value 280 return nil 281 } 282 283 // MarshalCBOR returns CBOR encoding of p. 284 func (p Payload) MarshalCBOR() ([]byte, error) { 285 k, err := p.Key() 286 if err != nil { 287 return nil, err 288 } 289 sp := serializablePayload{Key: k, Value: p.value} 290 return cbor.Marshal(sp) 291 } 292 293 // UnmarshalCBOR unmarshals a CBOR value of payload. 294 func (p *Payload) UnmarshalCBOR(b []byte) error { 295 if p == nil { 296 return errors.New("UnmarshalCBOR on nil payload") 297 } 298 var sp serializablePayload 299 if err := cbor.Unmarshal(b, &sp); err != nil { 300 return err 301 } 302 p.encKey = encodeKey(&sp.Key, PayloadVersion) 303 p.value = sp.Value 304 return nil 305 } 306 307 // Key returns payload key. 308 // Error indicates that ledger.Key can't be created from payload key, so 309 // migration and reporting (known callers) should abort. 310 // CAUTION: do not modify returned key because it shares underlying data with payload key. 311 func (p *Payload) Key() (Key, error) { 312 if p == nil || len(p.encKey) == 0 { 313 return Key{}, nil 314 } 315 k, err := decodeKey(p.encKey, true, PayloadVersion) 316 if err != nil { 317 return Key{}, err 318 } 319 return *k, nil 320 } 321 322 // EncodedKey returns payload key. 323 // CAUTION: do not modify returned encoded key 324 // because it shares underlying data with payload key. 325 func (p *Payload) EncodedKey() []byte { 326 if p == nil { 327 return nil 328 } 329 return p.encKey 330 } 331 332 // Value returns payload value. 333 // CAUTION: do not modify returned value because it shares underlying data with payload value. 334 func (p *Payload) Value() Value { 335 if p == nil { 336 return Value{} 337 } 338 return p.value 339 } 340 341 // Size returns the size of the payload 342 func (p *Payload) Size() int { 343 if p == nil { 344 return 0 345 } 346 return p.encKey.Size() + p.value.Size() 347 } 348 349 // IsEmpty returns true if payload is nil or value is empty 350 func (p *Payload) IsEmpty() bool { 351 return p == nil || p.value.Size() == 0 352 } 353 354 // TODO fix me 355 func (p *Payload) String() string { 356 // TODO improve this key, values 357 return p.encKey.String() + " " + p.value.String() 358 } 359 360 // Equals compares this payload to another payload 361 // A nil payload is equivalent to an empty payload. 362 func (p *Payload) Equals(other *Payload) bool { 363 if p == nil || (p.encKey.Size() == 0 && p.value.Size() == 0) { 364 return other == nil || (other.encKey.Size() == 0 && other.value.Size() == 0) 365 } 366 if other == nil { 367 return false 368 } 369 return p.encKey.Equals(other.encKey) && p.value.Equals(other.value) 370 } 371 372 // ValueEquals compares this payload value to another payload value. 373 // A nil payload is equivalent to an empty payload. 374 // NOTE: prefer using this function over payload.Value.Equals() 375 // when comparing payload values. payload.ValueEquals() handles 376 // nil payload, while payload.Value.Equals() panics on nil payload. 377 func (p *Payload) ValueEquals(other *Payload) bool { 378 pEmpty := p.IsEmpty() 379 otherEmpty := other.IsEmpty() 380 if pEmpty != otherEmpty { 381 // Only one payload is empty 382 return false 383 } 384 if pEmpty { 385 // Both payloads are empty 386 return true 387 } 388 // Compare values since both payloads are not empty. 389 return p.value.Equals(other.value) 390 } 391 392 // DeepCopy returns a deep copy of the payload 393 func (p *Payload) DeepCopy() *Payload { 394 if p == nil { 395 return nil 396 } 397 k := p.encKey.DeepCopy() 398 v := p.value.DeepCopy() 399 return &Payload{encKey: k, value: v} 400 } 401 402 // NewPayload returns a new payload 403 func NewPayload(key Key, value Value) *Payload { 404 ek := encodeKey(&key, PayloadVersion) 405 return &Payload{encKey: ek, value: value} 406 } 407 408 // EmptyPayload returns an empty payload 409 func EmptyPayload() *Payload { 410 return &Payload{} 411 } 412 413 // TrieProof includes all the information needed to walk 414 // through a trie branch from an specific leaf node (key) 415 // up to the root of the trie. 416 type TrieProof struct { 417 Path Path // path 418 Payload *Payload // payload 419 Interims []hash.Hash // the non-default intermediate nodes in the proof 420 Inclusion bool // flag indicating if this is an inclusion or exclusion proof 421 Flags []byte // The flags of the proofs (is set if an intermediate node has a non-default) 422 Steps uint8 // number of steps for the proof (path len) // TODO: should this be a type allowing for larger values? 423 } 424 425 // NewTrieProof creates a new instance of Trie Proof 426 func NewTrieProof() *TrieProof { 427 return &TrieProof{ 428 Payload: EmptyPayload(), 429 Interims: make([]hash.Hash, 0), 430 Inclusion: false, 431 Flags: make([]byte, PathLen), 432 Steps: 0, 433 } 434 } 435 436 func (p *TrieProof) String() string { 437 flagStr := "" 438 for _, f := range p.Flags { 439 flagStr += fmt.Sprintf("%08b", f) 440 } 441 proofStr := fmt.Sprintf("size: %d flags: %v\n", p.Steps, flagStr) 442 proofStr += fmt.Sprintf("\t path: %v payload: %v\n", p.Path, p.Payload) 443 444 if p.Inclusion { 445 proofStr += "\t inclusion proof:\n" 446 } else { 447 proofStr += "\t noninclusion proof:\n" 448 } 449 interimIndex := 0 450 for j := 0; j < int(p.Steps); j++ { 451 // if bit is set 452 if p.Flags[j/8]&(1<<(7-j%8)) != 0 { 453 proofStr += fmt.Sprintf("\t\t %d: [%x]\n", j, p.Interims[interimIndex]) 454 interimIndex++ 455 } 456 } 457 return proofStr 458 } 459 460 // Equals compares this proof to another payload 461 func (p *TrieProof) Equals(o *TrieProof) bool { 462 if o == nil { 463 return false 464 } 465 if !p.Path.Equals(o.Path) { 466 return false 467 } 468 if !p.Payload.Equals(o.Payload) { 469 return false 470 } 471 if len(p.Interims) != len(o.Interims) { 472 return false 473 } 474 for i, inter := range p.Interims { 475 if inter != o.Interims[i] { 476 return false 477 } 478 } 479 if p.Inclusion != o.Inclusion { 480 return false 481 } 482 if !bytes.Equal(p.Flags, o.Flags) { 483 return false 484 } 485 if p.Steps != o.Steps { 486 return false 487 } 488 return true 489 } 490 491 // TrieBatchProof is a struct that holds the proofs for several keys 492 // 493 // so there is no need for two calls (read, proofs) 494 type TrieBatchProof struct { 495 Proofs []*TrieProof 496 } 497 498 // NewTrieBatchProof creates a new instance of BatchProof 499 func NewTrieBatchProof() *TrieBatchProof { 500 bp := new(TrieBatchProof) 501 bp.Proofs = make([]*TrieProof, 0) 502 return bp 503 } 504 505 // NewTrieBatchProofWithEmptyProofs creates an instance of Batchproof 506 // filled with n newly created proofs (empty) 507 func NewTrieBatchProofWithEmptyProofs(numberOfProofs int) *TrieBatchProof { 508 bp := new(TrieBatchProof) 509 bp.Proofs = make([]*TrieProof, numberOfProofs) 510 for i := 0; i < numberOfProofs; i++ { 511 bp.Proofs[i] = NewTrieProof() 512 } 513 return bp 514 } 515 516 // Size returns the number of proofs 517 func (bp *TrieBatchProof) Size() int { 518 return len(bp.Proofs) 519 } 520 521 // Paths returns the slice of paths for this batch proof 522 func (bp *TrieBatchProof) Paths() []Path { 523 paths := make([]Path, len(bp.Proofs)) 524 for i, p := range bp.Proofs { 525 paths[i] = p.Path 526 } 527 return paths 528 } 529 530 // Payloads returns the slice of paths for this batch proof 531 func (bp *TrieBatchProof) Payloads() []*Payload { 532 payloads := make([]*Payload, len(bp.Proofs)) 533 for i, p := range bp.Proofs { 534 payloads[i] = p.Payload 535 } 536 return payloads 537 } 538 539 func (bp *TrieBatchProof) String() string { 540 res := fmt.Sprintf("trie batch proof includes %d proofs: \n", bp.Size()) 541 for _, proof := range bp.Proofs { 542 res = res + "\n" + proof.String() 543 } 544 return res 545 } 546 547 // AppendProof adds a proof to the batch proof 548 func (bp *TrieBatchProof) AppendProof(p *TrieProof) { 549 bp.Proofs = append(bp.Proofs, p) 550 } 551 552 // MergeInto adds all of its proofs into the dest batch proof 553 func (bp *TrieBatchProof) MergeInto(dest *TrieBatchProof) { 554 for _, p := range bp.Proofs { 555 dest.AppendProof(p) 556 } 557 } 558 559 // Equals compares this batch proof to another batch proof 560 func (bp *TrieBatchProof) Equals(o *TrieBatchProof) bool { 561 if o == nil { 562 return false 563 } 564 if len(bp.Proofs) != len(o.Proofs) { 565 return false 566 } 567 for i, proof := range bp.Proofs { 568 if !proof.Equals(o.Proofs[i]) { 569 return false 570 } 571 } 572 return true 573 }