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  }