github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/tstore/record.go (about) 1 // Copyright (c) 2020-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package tstore 6 7 import ( 8 "bytes" 9 "encoding/base64" 10 "encoding/hex" 11 "encoding/json" 12 "fmt" 13 "sort" 14 15 backend "github.com/decred/politeia/politeiad/backendv2" 16 "github.com/decred/politeia/politeiad/backendv2/tstorebe/store" 17 "github.com/decred/politeia/politeiad/backendv2/tstorebe/tlog" 18 "github.com/decred/politeia/util" 19 "github.com/google/trillian" 20 "google.golang.org/grpc/codes" 21 ) 22 23 const ( 24 // Blob entry data descriptors 25 dataDescriptorRecordMetadata = "pd-recordmd-v1" 26 dataDescriptorMetadataStream = "pd-mdstream-v1" 27 dataDescriptorFile = "pd-file-v1" 28 dataDescriptorRecordIndex = "pd-rindex-v1" 29 dataDescriptorAnchor = "pd-anchor-v1" 30 ) 31 32 // RecordNew creates a new record in the tstore and returns the record token 33 // that serves as the unique identifier for the record. Creating a new record 34 // means creating a tlog tree for the record. Nothing is saved to the tree yet. 35 func (t *Tstore) RecordNew() ([]byte, error) { 36 var token []byte 37 for retries := 0; retries < 10; retries++ { 38 tree, _, err := t.tlog.TreeNew() 39 if err != nil { 40 return nil, err 41 } 42 token = tokenFromTreeID(tree.TreeId) 43 44 // Check for shortened token collisions 45 if t.tokenCollision(token) { 46 // This is a collision. We cannot use this tree. Try again. 47 log.Infof("Token collision %x, creating new token", token) 48 continue 49 } 50 51 // We've found a valid token. Update the tokens cache. This must 52 // be done even if the record creation fails since the tree will 53 // still exist. 54 t.tokenAdd(token) 55 break 56 } 57 58 return token, nil 59 } 60 61 // recordSave saves the provided record content to the kv store, appends a leaf 62 // to the trillian tree for each piece of content, then returns a record 63 // index for the newly saved record. If the record state is unvetted the record 64 // content will be saved to the key-value store encrypted. 65 // 66 // If the record is being made public the record version and iteration are both 67 // reset back to 1. This function detects when a record is being made public 68 // and re-saves any encrypted content that is part of the public record as 69 // clear text in the key-value store. 70 func (t *Tstore) recordSave(treeID int64, recordMD backend.RecordMetadata, metadata []backend.MetadataStream, files []backend.File) (*recordIndex, error) { 71 // Get tree leaves 72 leavesAll, err := t.leavesAll(treeID) 73 if err != nil { 74 return nil, err 75 } 76 77 // Get the existing record index 78 currIdx, err := t.recordIndexLatest(leavesAll) 79 if err == backend.ErrRecordNotFound { 80 // No record versions exist yet. This is ok. 81 currIdx = &recordIndex{ 82 Metadata: make(map[string]map[uint32][]byte), 83 Files: make(map[string][]byte), 84 } 85 } else if err != nil { 86 return nil, fmt.Errorf("recordIndexLatest: %v", err) 87 } 88 89 // Verify tree is not frozen 90 if currIdx.Frozen { 91 return nil, backend.ErrRecordLocked 92 } 93 94 // Verify there are no duplicate metadata streams 95 md := make(map[string]map[uint32]struct{}, len(metadata)) 96 for _, v := range metadata { 97 if v.PluginID == "" || v.StreamID == 0 { 98 return nil, fmt.Errorf("invalid metadata stream: '%v' %v", 99 v.PluginID, v.StreamID) 100 } 101 pmd, ok := md[v.PluginID] 102 if !ok { 103 pmd = make(map[uint32]struct{}, len(metadata)) 104 } 105 _, ok = pmd[v.StreamID] 106 if ok { 107 return nil, fmt.Errorf("duplicate metadata stream: %v %v", 108 v.PluginID, v.StreamID) 109 } 110 pmd[v.StreamID] = struct{}{} 111 md[v.PluginID] = pmd 112 } 113 114 // Verify there are no duplicate files 115 fn := make(map[string]struct{}, len(files)) 116 for _, v := range files { 117 if v.Name == "" { 118 return nil, fmt.Errorf("empty filename") 119 } 120 _, ok := fn[v.Name] 121 if ok { 122 return nil, fmt.Errorf("duplicate filename found: %v", v.Name) 123 } 124 fn[v.Name] = struct{}{} 125 } 126 127 // Prepare the blob entries. The record index can also be created 128 // during this step. 129 var ( 130 // [pluginID][streamID]BlobEntry 131 beMetadata = make(map[string]map[uint32]store.BlobEntry, len(metadata)) 132 133 // [filename]BlobEntry 134 beFiles = make(map[string]store.BlobEntry, len(files)) 135 136 idx = recordIndex{ 137 State: recordMD.State, 138 Version: recordMD.Version, 139 Iteration: recordMD.Iteration, 140 Metadata: make(map[string]map[uint32][]byte, len(metadata)), 141 Files: make(map[string][]byte, len(files)), 142 } 143 144 // digests is used to aggregate the digests from all record 145 // content. This is used later on to see if any of the content 146 // already exists in the tstore. 147 digests = make(map[string]struct{}, 256) 148 ) 149 150 // Setup record metadata 151 beRecordMD, err := convertBlobEntryFromRecordMetadata(recordMD) 152 if err != nil { 153 return nil, err 154 } 155 m, err := merkleLeafHashForBlobEntry(*beRecordMD) 156 if err != nil { 157 return nil, err 158 } 159 idx.RecordMetadata = m 160 digests[beRecordMD.Digest] = struct{}{} 161 162 // Setup metdata streams 163 for _, v := range metadata { 164 // Blob entry 165 be, err := convertBlobEntryFromMetadataStream(v) 166 if err != nil { 167 return nil, err 168 } 169 streams, ok := beMetadata[v.PluginID] 170 if !ok { 171 streams = make(map[uint32]store.BlobEntry, len(metadata)) 172 } 173 streams[v.StreamID] = *be 174 beMetadata[v.PluginID] = streams 175 176 // Record index 177 m, err := merkleLeafHashForBlobEntry(*be) 178 if err != nil { 179 return nil, err 180 } 181 streamsIdx, ok := idx.Metadata[v.PluginID] 182 if !ok { 183 streamsIdx = make(map[uint32][]byte, len(metadata)) 184 } 185 streamsIdx[v.StreamID] = m 186 idx.Metadata[v.PluginID] = streamsIdx 187 188 // Aggregate digest 189 digests[be.Digest] = struct{}{} 190 } 191 192 // Setup files 193 for _, v := range files { 194 // Blob entry 195 be, err := convertBlobEntryFromFile(v) 196 if err != nil { 197 return nil, err 198 } 199 beFiles[v.Name] = *be 200 201 // Record Index 202 m, err := merkleLeafHashForBlobEntry(*be) 203 if err != nil { 204 return nil, err 205 } 206 idx.Files[v.Name] = m 207 208 // Aggregate digest 209 digests[be.Digest] = struct{}{} 210 } 211 212 // Check if any of the content already exists. Different record 213 // versions that reference the same data is fine, but this data 214 // should not be saved to the store again. We can find duplicates 215 // by comparing the blob entry digest to the log leaf value. They 216 // will be the same if the record content is the same. 217 dups := make(map[string]struct{}, len(digests)) 218 for _, v := range leavesAll { 219 d := hex.EncodeToString(v.LeafValue) 220 _, ok := digests[d] 221 if ok { 222 // A piece of the new record content already exsits in the 223 // tstore. Save the digest as a duplcate. 224 dups[d] = struct{}{} 225 } 226 } 227 228 // Prepare blobs for the kv store 229 var ( 230 blobs = make(map[string][]byte, len(digests)) 231 leaves = make([]*trillian.LogLeaf, 0, len(blobs)) 232 233 // dupBlobs contains the blob entries for record content that 234 // already exists. We may need these blob entries later on if 235 // the duplicate content is encrypted and it needs to be saved 236 // plain text. 237 dupBlobs = make(map[string]store.BlobEntry, len(digests)) 238 ) 239 240 // Only vetted data should be saved plain text 241 var encrypt bool 242 switch idx.State { 243 case backend.StateUnvetted: 244 encrypt = true 245 case backend.StateVetted: 246 // Save plain text 247 encrypt = false 248 default: 249 // Something is wrong 250 panic(fmt.Sprintf("invalid record state %v %v", treeID, idx.State)) 251 } 252 253 // Prepare record metadata blobs and leaves 254 _, ok := dups[beRecordMD.Digest] 255 if !ok { 256 // Not a duplicate. Prepare kv store blob. 257 b, err := store.Blobify(*beRecordMD) 258 if err != nil { 259 return nil, err 260 } 261 k := storeKeyNew(encrypt) 262 blobs[k] = b 263 264 // Prepare tlog leaf 265 extraData, err := extraDataEncode(k, 266 dataDescriptorRecordMetadata, idx.State) 267 if err != nil { 268 return nil, err 269 } 270 digest, err := hex.DecodeString(beRecordMD.Digest) 271 if err != nil { 272 return nil, err 273 } 274 leaves = append(leaves, tlog.NewLogLeaf(digest, extraData)) 275 } else { 276 // This is a duplicate. Stash is for now. We may need to save 277 // it as plain text later. 278 dupBlobs[beRecordMD.Digest] = *beRecordMD 279 } 280 281 // Prepare metadata stream blobs and leaves 282 for _, v := range beMetadata { 283 for _, be := range v { 284 _, ok := dups[be.Digest] 285 if ok { 286 // This is a duplicate. Stash is for now. We may need to save 287 // it as plain text later. 288 dupBlobs[be.Digest] = be 289 continue 290 } 291 292 // Not a duplicate. Prepare kv store blob. 293 b, err := store.Blobify(be) 294 if err != nil { 295 return nil, err 296 } 297 k := storeKeyNew(encrypt) 298 blobs[k] = b 299 300 // Prepare tlog leaf 301 extraData, err := extraDataEncode(k, 302 dataDescriptorMetadataStream, idx.State) 303 if err != nil { 304 return nil, err 305 } 306 digest, err := hex.DecodeString(be.Digest) 307 if err != nil { 308 return nil, err 309 } 310 311 leaves = append(leaves, tlog.NewLogLeaf(digest, extraData)) 312 } 313 } 314 315 // Prepare file blobs and leaves 316 for _, be := range beFiles { 317 _, ok := dups[be.Digest] 318 if ok { 319 // This is a duplicate. Stash is for now. We may need to save 320 // it as plain text later. 321 dupBlobs[be.Digest] = be 322 continue 323 } 324 325 // Not a duplicate. Prepare kv store blob. 326 b, err := store.Blobify(be) 327 if err != nil { 328 return nil, err 329 } 330 k := storeKeyNew(encrypt) 331 blobs[k] = b 332 333 // Prepare tlog leaf 334 extraData, err := extraDataEncode(k, dataDescriptorFile, idx.State) 335 if err != nil { 336 return nil, err 337 } 338 digest, err := hex.DecodeString(be.Digest) 339 if err != nil { 340 return nil, err 341 } 342 343 leaves = append(leaves, tlog.NewLogLeaf(digest, extraData)) 344 } 345 346 // Verify at least one new blob is being saved to the kv store 347 if len(blobs) == 0 { 348 return nil, backend.ErrNoRecordChanges 349 } 350 351 log.Debugf("Saving %v record content blobs", len(blobs)) 352 353 // Save blobs to the kv store 354 err = t.store.Put(blobs, encrypt) 355 if err != nil { 356 return nil, fmt.Errorf("store Put: %v", err) 357 } 358 359 // Append leaves onto the trillian tree 360 queued, _, err := t.tlog.LeavesAppend(treeID, leaves) 361 if err != nil { 362 return nil, fmt.Errorf("LeavesAppend: %v", err) 363 } 364 failed := make([]string, 0, len(queued)) 365 for _, v := range queued { 366 c := codes.Code(v.QueuedLeaf.GetStatus().GetCode()) 367 if c != codes.OK { 368 failed = append(failed, fmt.Sprintf("%v", c)) 369 } 370 } 371 if len(failed) > 0 { 372 return nil, fmt.Errorf("append leaves failed: %v", failed) 373 } 374 375 // When a record is made public the record content needs to be 376 // resaved to the key-value store as unencrypted. 377 var ( 378 isPublic = recordMD.Status == backend.StatusPublic 379 380 // Iteration and version are reset back to 1 when a record is 381 // made public. 382 iterIsReset = recordMD.Iteration == 1 383 ) 384 if !isPublic || !iterIsReset { 385 // Record is not being made public. Nothing else to do. 386 return &idx, nil 387 } 388 389 // Resave all of the duplicate blobs as plain text. A duplicate 390 // blob means the record content existed prior to the status 391 // change. 392 blobs = make(map[string][]byte, len(dupBlobs)) 393 for _, v := range leavesAll { 394 d := hex.EncodeToString(v.LeafValue) 395 _, ok := dups[d] 396 if !ok { 397 // Not a duplicate 398 continue 399 } 400 401 // This is a duplicate. If its unvetted it will need to be 402 // resaved as plain text. 403 ed, err := extraDataDecode(v.ExtraData) 404 if err != nil { 405 return nil, err 406 } 407 if ed.State == backend.StateVetted { 408 // Not unvetted. No need to resave it. 409 continue 410 } 411 412 // Prepare plain text blob 413 be, ok := dupBlobs[d] 414 if !ok { 415 // Should not happen 416 return nil, fmt.Errorf("blob entry not found %v", d) 417 } 418 b, err := store.Blobify(be) 419 if err != nil { 420 return nil, err 421 } 422 blobs[ed.storeKeyNoPrefix()] = b 423 } 424 if len(blobs) == 0 { 425 // This should not happen 426 return nil, fmt.Errorf("no blobs found to resave as plain text") 427 } 428 429 log.Debugf("Resaving %v encrypted blobs as plain text", len(blobs)) 430 431 err = t.store.Put(blobs, false) 432 if err != nil { 433 return nil, fmt.Errorf("store Put: %v", err) 434 } 435 436 return &idx, nil 437 } 438 439 // RecordSave saves the provided record to tstore. Once the record contents 440 // have been successfully saved to tstore, a recordIndex is created for this 441 // version of the record and saved to tstore as well. The record update is not 442 // considered to be valid until the record index has been successfully saved. 443 // If the record content makes it in but the record index does not, the record 444 // content blobs are orphaned and ignored. 445 func (t *Tstore) RecordSave(token []byte, rm backend.RecordMetadata, metadata []backend.MetadataStream, files []backend.File) error { 446 log.Tracef("RecordSave: %x", token) 447 448 // Verify token is valid. The full length token must be used when 449 // writing data. 450 if !tokenIsFullLength(token) { 451 return backend.ErrTokenInvalid 452 } 453 454 // Save the record 455 treeID := treeIDFromToken(token) 456 idx, err := t.recordSave(treeID, rm, metadata, files) 457 if err != nil { 458 return err 459 } 460 461 // Save the record index 462 err = t.recordIndexSave(treeID, *idx) 463 if err != nil { 464 return fmt.Errorf("recordIndexSave: %v", err) 465 } 466 467 return nil 468 } 469 470 // RecordDel walks the provided tree and deletes all blobs in the store that 471 // correspond to record files. This is done for all versions and all iterations 472 // of the record. Record metadata and metadata stream blobs are not deleted. 473 func (t *Tstore) RecordDel(token []byte) error { 474 log.Tracef("RecordDel: %x", token) 475 476 // Verify token is valid. The full length token must be used when 477 // writing data. 478 if !tokenIsFullLength(token) { 479 return backend.ErrTokenInvalid 480 } 481 482 // Get all tree leaves 483 treeID := treeIDFromToken(token) 484 leavesAll, err := t.leavesAll(treeID) 485 if err != nil { 486 return err 487 } 488 489 // Ensure tree is frozen. Deleting files from the store is only 490 // allowed on frozen trees. 491 currIdx, err := t.recordIndexLatest(leavesAll) 492 if err != nil { 493 return err 494 } 495 if !currIdx.Frozen { 496 return fmt.Errorf("tree is not frozen") 497 } 498 499 // Retrieve all record indexes 500 indexes, err := t.recordIndexes(leavesAll) 501 if err != nil { 502 return err 503 } 504 505 // Aggregate the keys for all file blobs of all versions. The 506 // record index points to the log leaf merkle leaf hash. The log 507 // leaf contains the kv store key. 508 merkles := make(map[string]struct{}, len(leavesAll)) 509 for _, v := range indexes { 510 for _, merkle := range v.Files { 511 merkles[hex.EncodeToString(merkle)] = struct{}{} 512 } 513 } 514 keys := make([]string, 0, len(merkles)) 515 for _, v := range leavesAll { 516 _, ok := merkles[hex.EncodeToString(v.MerkleLeafHash)] 517 if ok { 518 ed, err := extraDataDecode(v.ExtraData) 519 if err != nil { 520 return err 521 } 522 keys = append(keys, ed.storeKey()) 523 524 // When a record is made public the encrypted blobs in the kv 525 // store are re-saved as clear text, but the tlog leaf remains 526 // the same since the record content did not actually change. 527 // Both of these blobs need to be deleted. 528 if ed.storeKey() != ed.storeKeyNoPrefix() { 529 // This blob might have a clear text entry and an encrypted 530 // entry. Add both keys to be sure all content is deleted. 531 keys = append(keys, ed.storeKeyNoPrefix()) 532 } 533 } 534 } 535 536 // Delete file blobs from the store 537 err = t.store.Del(keys) 538 if err != nil { 539 return fmt.Errorf("store Del: %v", err) 540 } 541 542 return nil 543 } 544 545 // RecordFreeze updates the status of a record then freezes the trillian tree 546 // to prevent any additional updates. 547 // 548 // A tree is considered to be frozen once the record index has been saved with 549 // its Frozen field set to true. The only thing that can be appended onto a 550 // frozen tree is one additional anchor record. Once a frozen tree has been 551 // anchored, the tstore fsck function will update the status of the tree to 552 // frozen in trillian, at which point trillian will prevent any changes to the 553 // tree. 554 func (t *Tstore) RecordFreeze(token []byte, rm backend.RecordMetadata, metadata []backend.MetadataStream, files []backend.File) error { 555 log.Tracef("RecordFreeze: %x", token) 556 557 // Verify token is valid. The full length token must be used when 558 // writing data. 559 if !tokenIsFullLength(token) { 560 return backend.ErrTokenInvalid 561 } 562 563 // Save updated record 564 treeID := treeIDFromToken(token) 565 idx, err := t.recordSave(treeID, rm, metadata, files) 566 if err != nil { 567 return err 568 } 569 570 // Mark the record as frozen 571 idx.Frozen = true 572 573 // Save the record index 574 return t.recordIndexSave(treeID, *idx) 575 } 576 577 // RecordExists returns whether a record exists. 578 // 579 // This method only returns whether a tree exists for the provided token. It's 580 // possible for a tree to exist that does not correspond to a record in the 581 // rare case that a tree was created but an unexpected error, such as a network 582 // error, was encoutered prior to the record being saved to the tree. We ignore 583 // this edge case because: 584 // 585 // 1. A user has no way to obtain this token unless the trillian instance has 586 // been opened to the public. 587 // 588 // 2. Even if they have the token they cannot do anything with it. Any attempt 589 // to read from the tree or write to the tree will return a RecordNotFound 590 // error. 591 // 592 // Pulling the leaves from the tree to see if a record has been saved to the 593 // tree adds a large amount of overhead to this call, which should be a very 594 // light weight. Its for this reason that we rely on the tree exists call 595 // despite the edge case. 596 func (t *Tstore) RecordExists(token []byte) bool { 597 // Read methods are allowed to use short tokens. Lookup the full 598 // length token. 599 var err error 600 token, err = t.fullLengthToken(token) 601 if err != nil { 602 return false 603 } 604 605 _, err = t.tlog.Tree(treeIDFromToken(token)) 606 return err == nil 607 } 608 609 // record returns the specified record. 610 // 611 // Version is used to request a specific version of a record. If no version is 612 // provided then the most recent version of the record will be returned. 613 // 614 // Filenames can be used to request specific files. If filenames is not empty 615 // then the specified files will be the only files returned. 616 // 617 // OmitAllFiles can be used to retrieve a record without any of the record 618 // files. This supersedes the filenames argument. 619 func (t *Tstore) record(treeID int64, version uint32, filenames []string, omitAllFiles bool) (*backend.Record, error) { 620 // Get tree leaves 621 leaves, err := t.leavesAll(treeID) 622 if err != nil { 623 return nil, err 624 } 625 626 // Use the record index to pull the record content from the store. 627 // The keys for the record content first need to be extracted from 628 // their log leaf. 629 idx, err := t.recordIndex(leaves, version) 630 if err != nil { 631 return nil, err 632 } 633 634 // Compile merkle root hashes of record content 635 merkles := make(map[string]struct{}, 64) 636 merkles[hex.EncodeToString(idx.RecordMetadata)] = struct{}{} 637 for _, streams := range idx.Metadata { 638 for _, v := range streams { 639 merkles[hex.EncodeToString(v)] = struct{}{} 640 } 641 } 642 switch { 643 case omitAllFiles: 644 // Don't include any files 645 case len(filenames) > 0: 646 // Only included the specified files 647 filesToInclude := make(map[string]struct{}, len(filenames)) 648 for _, v := range filenames { 649 filesToInclude[v] = struct{}{} 650 } 651 for fn, v := range idx.Files { 652 if _, ok := filesToInclude[fn]; ok { 653 merkles[hex.EncodeToString(v)] = struct{}{} 654 } 655 } 656 default: 657 // Include all files 658 for _, v := range idx.Files { 659 merkles[hex.EncodeToString(v)] = struct{}{} 660 } 661 } 662 663 // Walk the tree and extract the record content keys 664 keys := make([]string, 0, len(idx.Metadata)+len(idx.Files)+1) 665 for _, v := range leaves { 666 _, ok := merkles[hex.EncodeToString(v.MerkleLeafHash)] 667 if !ok { 668 // Not part of the record content 669 continue 670 } 671 672 // Leaf is part of record content. Save the kv store key. 673 ed, err := extraDataDecode(v.ExtraData) 674 if err != nil { 675 return nil, err 676 } 677 678 var key string 679 switch idx.State { 680 case backend.StateVetted: 681 // If the record is vetted the content may exist in the store 682 // as both an encrypted blob and a plain text blob. Always pull 683 // the plaintext blob. 684 key = ed.storeKeyNoPrefix() 685 default: 686 // Pull the encrypted blob 687 key = ed.storeKey() 688 } 689 keys = append(keys, key) 690 } 691 692 // Get record content from store 693 blobs, err := t.store.Get(keys) 694 if err != nil { 695 return nil, fmt.Errorf("store Get: %v", err) 696 } 697 if len(keys) != len(blobs) { 698 // One or more blobs were not found. This is allowed since the 699 // blobs for a censored record will not exist, but the record 700 // metadata and metadata streams should still be returned. 701 log.Tracef("Blobs not found %v: want %v, got %v", 702 treeID, len(keys), len(blobs)) 703 } 704 705 // Decode blobs 706 entries := make([]store.BlobEntry, 0, len(keys)) 707 // To ensure that the ordering of the record's files and metadata streams 708 // is always consistent, we need iterate over the blobs map in a 709 // deterministic manner, which requires sorting the map keys. 710 sortedKeys := getSortedKeys(blobs) 711 for _, key := range sortedKeys { 712 v := blobs[key] 713 be, err := store.Deblob(v) 714 if err != nil { 715 return nil, err 716 } 717 entries = append(entries, *be) 718 } 719 720 // Decode blob entries 721 var ( 722 recordMD *backend.RecordMetadata 723 metadata = make([]backend.MetadataStream, 0, len(idx.Metadata)) 724 files = make([]backend.File, 0, len(idx.Files)) 725 ) 726 for _, v := range entries { 727 // Decode the data hint 728 b, err := base64.StdEncoding.DecodeString(v.DataHint) 729 if err != nil { 730 return nil, fmt.Errorf("decode DataHint: %v", err) 731 } 732 var dd store.DataDescriptor 733 err = json.Unmarshal(b, &dd) 734 if err != nil { 735 return nil, fmt.Errorf("unmarshal DataHint: %v", err) 736 } 737 if dd.Type != store.DataTypeStructure { 738 return nil, fmt.Errorf("invalid data type; got %v, want %v", 739 dd.Type, store.DataTypeStructure) 740 } 741 742 // Decode the data 743 b, err = base64.StdEncoding.DecodeString(v.Data) 744 if err != nil { 745 return nil, fmt.Errorf("decode Data: %v", err) 746 } 747 digest, err := hex.DecodeString(v.Digest) 748 if err != nil { 749 return nil, fmt.Errorf("decode Hash: %v", err) 750 } 751 if !bytes.Equal(util.Digest(b), digest) { 752 return nil, fmt.Errorf("data is not coherent; got %x, want %x", 753 util.Digest(b), digest) 754 } 755 switch dd.Descriptor { 756 case dataDescriptorRecordMetadata: 757 var rm backend.RecordMetadata 758 err = json.Unmarshal(b, &rm) 759 if err != nil { 760 return nil, fmt.Errorf("unmarshal RecordMetadata: %v", err) 761 } 762 recordMD = &rm 763 case dataDescriptorMetadataStream: 764 var ms backend.MetadataStream 765 err = json.Unmarshal(b, &ms) 766 if err != nil { 767 return nil, fmt.Errorf("unmarshal MetadataStream: %v", err) 768 } 769 metadata = append(metadata, ms) 770 case dataDescriptorFile: 771 var f backend.File 772 err = json.Unmarshal(b, &f) 773 if err != nil { 774 return nil, fmt.Errorf("unmarshal File: %v", err) 775 } 776 files = append(files, f) 777 default: 778 return nil, fmt.Errorf("invalid descriptor %v", dd.Descriptor) 779 } 780 } 781 782 return &backend.Record{ 783 RecordMetadata: *recordMD, 784 Metadata: metadata, 785 Files: files, 786 }, nil 787 } 788 789 // getSortedKeys accepts a map of record blobs indexed by string keys, 790 // and it returns the keys in a sorted slice. 791 func getSortedKeys(blobs map[string][]byte) []string { 792 keys := make([]string, 0, len(blobs)) 793 for k := range blobs { 794 keys = append(keys, k) 795 } 796 797 // Sort keys 798 sort.Strings(keys) 799 800 return keys 801 } 802 803 // Record returns the specified version of the record. 804 func (t *Tstore) Record(token []byte, version uint32) (*backend.Record, error) { 805 log.Tracef("Record: %x %v", token, version) 806 807 // Read methods are allowed to use short tokens. Lookup the full 808 // length token. 809 var err error 810 token, err = t.fullLengthToken(token) 811 if err != nil { 812 return nil, err 813 } 814 815 treeID := treeIDFromToken(token) 816 return t.record(treeID, version, []string{}, false) 817 } 818 819 // RecordLatest returns the latest version of a record. 820 func (t *Tstore) RecordLatest(token []byte) (*backend.Record, error) { 821 log.Tracef("RecordLatest: %x", token) 822 823 // Read methods are allowed to use short tokens. Lookup the full 824 // length token. 825 var err error 826 token, err = t.fullLengthToken(token) 827 if err != nil { 828 return nil, err 829 } 830 831 treeID := treeIDFromToken(token) 832 return t.record(treeID, 0, []string{}, false) 833 } 834 835 // RecordPartial returns a partial record. This method gives the caller fine 836 // grained control over what version and what files are returned. The only 837 // required field is the token. All other fields are optional. 838 // 839 // Version is used to request a specific version of a record. If no version is 840 // provided then the most recent version of the record will be returned. 841 // 842 // Filenames can be used to request specific files. If filenames is not empty 843 // then the specified files will be the only files returned. 844 // 845 // OmitAllFiles can be used to retrieve a record without any of the record 846 // files. This supersedes the filenames argument. 847 func (t *Tstore) RecordPartial(token []byte, version uint32, filenames []string, omitAllFiles bool) (*backend.Record, error) { 848 log.Tracef("RecordPartial: %x %v %v %v", 849 token, version, omitAllFiles, filenames) 850 851 // Read methods are allowed to use short tokens. Lookup the full 852 // length token. 853 var err error 854 token, err = t.fullLengthToken(token) 855 if err != nil { 856 return nil, err 857 } 858 859 treeID := treeIDFromToken(token) 860 return t.record(treeID, version, filenames, omitAllFiles) 861 } 862 863 // RecordState returns the state of a record. This call does not require 864 // retrieving any blobs from the kv store. The record state can be derived from 865 // only the tlog leaves. 866 func (t *Tstore) RecordState(token []byte) (backend.StateT, error) { 867 log.Tracef("RecordState: %x", token) 868 869 // Read methods are allowed to use short tokens. Lookup the full 870 // length token. 871 var err error 872 token, err = t.fullLengthToken(token) 873 if err != nil { 874 return backend.StateInvalid, err 875 } 876 877 treeID := treeIDFromToken(token) 878 leaves, err := t.leavesAll(treeID) 879 if err != nil { 880 return backend.StateInvalid, err 881 } 882 if recordIsVetted(leaves) { 883 return backend.StateVetted, nil 884 } 885 886 return backend.StateUnvetted, nil 887 } 888 889 // timestamp returns the timestamp given a tlog tree merkle leaf hash. 890 func (t *Tstore) timestamp(treeID int64, merkleLeafHash []byte, leaves []*trillian.LogLeaf) (*backend.Timestamp, error) { 891 // Find the leaf 892 var l *trillian.LogLeaf 893 for _, v := range leaves { 894 if bytes.Equal(merkleLeafHash, v.MerkleLeafHash) { 895 l = v 896 break 897 } 898 } 899 if l == nil { 900 return nil, fmt.Errorf("leaf not found") 901 } 902 903 // Get blob entry from the kv store 904 ed, err := extraDataDecode(l.ExtraData) 905 if err != nil { 906 return nil, err 907 } 908 blobs, err := t.store.Get([]string{ed.storeKey()}) 909 if err != nil { 910 return nil, fmt.Errorf("store get: %v", err) 911 } 912 913 // Extract the data blob. Its possible for the data blob to not 914 // exist if it has been censored. This is ok. We'll still return 915 // the rest of the timestamp. 916 var data []byte 917 if len(blobs) == 1 { 918 b, ok := blobs[ed.storeKey()] 919 if !ok { 920 return nil, fmt.Errorf("blob not found %v", ed.storeKey()) 921 } 922 be, err := store.Deblob(b) 923 if err != nil { 924 return nil, err 925 } 926 data, err = base64.StdEncoding.DecodeString(be.Data) 927 if err != nil { 928 return nil, err 929 } 930 // Sanity check 931 if !bytes.Equal(l.LeafValue, util.Digest(data)) { 932 return nil, fmt.Errorf("data digest does not match leaf value") 933 } 934 } 935 936 // Setup timestamp 937 ts := backend.Timestamp{ 938 Data: string(data), 939 Digest: hex.EncodeToString(l.LeafValue), 940 Proofs: []backend.Proof{}, 941 } 942 943 // Get the anchor record for this leaf 944 a, err := t.anchorForLeaf(treeID, merkleLeafHash, leaves) 945 if err != nil { 946 if err == errAnchorNotFound { 947 // This data has not been anchored yet 948 return &ts, nil 949 } 950 return nil, fmt.Errorf("anchor: %v", err) 951 } 952 953 // Get trillian inclusion proof 954 p, err := t.tlog.InclusionProof(treeID, l.MerkleLeafHash, a.LogRoot) 955 if err != nil { 956 return nil, fmt.Errorf("InclusionProof %v %x: %v", 957 treeID, l.MerkleLeafHash, err) 958 } 959 960 // Setup proof for data digest inclusion in the log merkle root 961 edt := backend.ExtraDataTrillianRFC6962{ 962 LeafIndex: p.LeafIndex, 963 TreeSize: int64(a.LogRoot.TreeSize), 964 } 965 extraData, err := json.Marshal(edt) 966 if err != nil { 967 return nil, err 968 } 969 merklePath := make([]string, 0, len(p.Hashes)) 970 for _, v := range p.Hashes { 971 merklePath = append(merklePath, hex.EncodeToString(v)) 972 } 973 trillianProof := backend.Proof{ 974 Type: backend.ProofTypeTrillianRFC6962, 975 Digest: ts.Digest, 976 MerkleRoot: hex.EncodeToString(a.LogRoot.RootHash), 977 MerklePath: merklePath, 978 ExtraData: string(extraData), 979 } 980 981 // Setup proof for log merkle root inclusion in the dcrtime merkle 982 // root 983 if a.VerifyDigest.Digest != trillianProof.MerkleRoot { 984 return nil, fmt.Errorf("trillian merkle root not anchored") 985 } 986 var ( 987 numLeaves = a.VerifyDigest.ChainInformation.MerklePath.NumLeaves 988 hashes = a.VerifyDigest.ChainInformation.MerklePath.Hashes 989 flags = a.VerifyDigest.ChainInformation.MerklePath.Flags 990 ) 991 edd := backend.ExtraDataDcrtime{ 992 NumLeaves: numLeaves, 993 Flags: base64.StdEncoding.EncodeToString(flags), 994 } 995 extraData, err = json.Marshal(edd) 996 if err != nil { 997 return nil, err 998 } 999 merklePath = make([]string, 0, len(hashes)) 1000 for _, v := range hashes { 1001 merklePath = append(merklePath, hex.EncodeToString(v[:])) 1002 } 1003 dcrtimeProof := backend.Proof{ 1004 Type: backend.ProofTypeDcrtime, 1005 Digest: a.VerifyDigest.Digest, 1006 MerkleRoot: a.VerifyDigest.ChainInformation.MerkleRoot, 1007 MerklePath: merklePath, 1008 ExtraData: string(extraData), 1009 } 1010 1011 // Update timestamp 1012 ts.TxID = a.VerifyDigest.ChainInformation.Transaction 1013 ts.MerkleRoot = a.VerifyDigest.ChainInformation.MerkleRoot 1014 ts.Proofs = []backend.Proof{ 1015 trillianProof, 1016 dcrtimeProof, 1017 } 1018 1019 // Verify timestamp 1020 err = backend.VerifyTimestamp(ts) 1021 if err != nil { 1022 return nil, fmt.Errorf("VerifyTimestamp: %v", err) 1023 } 1024 1025 return &ts, nil 1026 } 1027 1028 // RecordTimestamps returns the timestamps for the contents of a record. 1029 // Timestamps for the record metadata, metadata streams, and files are all 1030 // returned. 1031 func (t *Tstore) RecordTimestamps(token []byte, version uint32) (*backend.RecordTimestamps, error) { 1032 log.Tracef("RecordTimestamps: %x %v", token, version) 1033 1034 // Read methods are allowed to use short tokens. Lookup the full 1035 // length token. 1036 var err error 1037 token, err = t.fullLengthToken(token) 1038 if err != nil { 1039 return nil, err 1040 } 1041 1042 // Get record index 1043 treeID := treeIDFromToken(token) 1044 leaves, err := t.leavesAll(treeID) 1045 if err != nil { 1046 return nil, err 1047 } 1048 idx, err := t.recordIndex(leaves, version) 1049 if err != nil { 1050 return nil, err 1051 } 1052 1053 // Get record metadata timestamp 1054 rm, err := t.timestamp(treeID, idx.RecordMetadata, leaves) 1055 if err != nil { 1056 return nil, fmt.Errorf("record metadata timestamp: %v", err) 1057 } 1058 1059 // Get metadata timestamps 1060 metadata := make(map[string]map[uint32]backend.Timestamp, len(idx.Metadata)) 1061 for pluginID, streams := range idx.Metadata { 1062 for streamID, merkle := range streams { 1063 ts, err := t.timestamp(treeID, merkle, leaves) 1064 if err != nil { 1065 return nil, fmt.Errorf("metadata %v %v timestamp: %v", 1066 pluginID, streamID, err) 1067 } 1068 sts, ok := metadata[pluginID] 1069 if !ok { 1070 sts = make(map[uint32]backend.Timestamp, 64) 1071 } 1072 sts[streamID] = *ts 1073 metadata[pluginID] = sts 1074 } 1075 } 1076 1077 // Get file timestamps 1078 files := make(map[string]backend.Timestamp, len(idx.Files)) 1079 for k, v := range idx.Files { 1080 ts, err := t.timestamp(treeID, v, leaves) 1081 if err != nil { 1082 return nil, fmt.Errorf("file %v timestamp: %v", k, err) 1083 } 1084 files[k] = *ts 1085 } 1086 1087 return &backend.RecordTimestamps{ 1088 RecordMetadata: *rm, 1089 Metadata: metadata, 1090 Files: files, 1091 }, nil 1092 } 1093 1094 // Inventory returns all record tokens that are in the tstore. Its possible for 1095 // a token to be returned that does not correspond to an actual record. For 1096 // example, if the tlog tree was created but saving the record to the tree 1097 // failed due to an unexpected error then a empty tree with exist. This 1098 // function does not filter those tokens out. 1099 func (t *Tstore) Inventory() ([][]byte, error) { 1100 trees, err := t.tlog.TreesAll() 1101 if err != nil { 1102 return nil, err 1103 } 1104 tokens := make([][]byte, 0, len(trees)) 1105 for _, v := range trees { 1106 tokens = append(tokens, tokenFromTreeID(v.TreeId)) 1107 } 1108 return tokens, nil 1109 } 1110 1111 // recordIsVetted returns whether the provided leaves contain any vetted record 1112 // indexes. The presence of a vetted record index means the record is vetted. 1113 // The state of a record index is saved to the leaf extra data, which is how we 1114 // determine if a record index is vetted. 1115 func recordIsVetted(leaves []*trillian.LogLeaf) bool { 1116 for _, v := range leaves { 1117 ed, err := extraDataDecode(v.ExtraData) 1118 if err != nil { 1119 panic(err) 1120 } 1121 if ed.Desc == dataDescriptorRecordIndex && 1122 ed.State == backend.StateVetted { 1123 // Vetted record index found 1124 return true 1125 } 1126 } 1127 return false 1128 } 1129 1130 // merkleLeafHashForBlobEntry returns the merkle leaf hash for a blob entry. 1131 // The merkle leaf hash can be used to retrieve a leaf from its tlog tree. 1132 func merkleLeafHashForBlobEntry(be store.BlobEntry) ([]byte, error) { 1133 leafValue, err := hex.DecodeString(be.Digest) 1134 if err != nil { 1135 return nil, err 1136 } 1137 return tlog.MerkleLeafHash(leafValue), nil 1138 } 1139 1140 func convertBlobEntryFromFile(f backend.File) (*store.BlobEntry, error) { 1141 data, err := json.Marshal(f) 1142 if err != nil { 1143 return nil, err 1144 } 1145 hint, err := json.Marshal( 1146 store.DataDescriptor{ 1147 Type: store.DataTypeStructure, 1148 Descriptor: dataDescriptorFile, 1149 }) 1150 if err != nil { 1151 return nil, err 1152 } 1153 be := store.NewBlobEntry(hint, data) 1154 return &be, nil 1155 } 1156 1157 func convertBlobEntryFromMetadataStream(ms backend.MetadataStream) (*store.BlobEntry, error) { 1158 data, err := json.Marshal(ms) 1159 if err != nil { 1160 return nil, err 1161 } 1162 hint, err := json.Marshal( 1163 store.DataDescriptor{ 1164 Type: store.DataTypeStructure, 1165 Descriptor: dataDescriptorMetadataStream, 1166 }) 1167 if err != nil { 1168 return nil, err 1169 } 1170 be := store.NewBlobEntry(hint, data) 1171 return &be, nil 1172 } 1173 1174 func convertBlobEntryFromRecordMetadata(rm backend.RecordMetadata) (*store.BlobEntry, error) { 1175 data, err := json.Marshal(rm) 1176 if err != nil { 1177 return nil, err 1178 } 1179 hint, err := json.Marshal( 1180 store.DataDescriptor{ 1181 Type: store.DataTypeStructure, 1182 Descriptor: dataDescriptorRecordMetadata, 1183 }) 1184 if err != nil { 1185 return nil, err 1186 } 1187 be := store.NewBlobEntry(hint, data) 1188 return &be, nil 1189 }