github.com/bartle-stripe/trillian@v1.2.1/storage/cache/map_subtree_cache.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cache
    16  
    17  import (
    18  	"encoding/base64"
    19  	"fmt"
    20  	"math/big"
    21  
    22  	"github.com/golang/glog"
    23  	"github.com/google/trillian/merkle"
    24  	"github.com/google/trillian/merkle/hashers"
    25  	"github.com/google/trillian/storage"
    26  	"github.com/google/trillian/storage/storagepb"
    27  )
    28  
    29  // NewMapSubtreeCache creates and returns a SubtreeCache appropriate for use with a map
    30  // tree. The caller must supply the strata depths to be used, the treeID and a suitable MapHasher.
    31  func NewMapSubtreeCache(mapStrata []int, treeID int64, hasher hashers.MapHasher) SubtreeCache {
    32  	return NewSubtreeCache(mapStrata, populateMapSubtreeNodes(treeID, hasher), prepareMapSubtreeWrite())
    33  }
    34  
    35  // populateMapSubtreeNodes re-creates Map subtree's InternalNodes from the
    36  // subtree Leaves map.
    37  //
    38  // This uses HStar2 to repopulate internal nodes.
    39  func populateMapSubtreeNodes(treeID int64, hasher hashers.MapHasher) storage.PopulateSubtreeFunc {
    40  	return func(st *storagepb.SubtreeProto) error {
    41  		st.InternalNodes = make(map[string][]byte)
    42  		leaves := make([]merkle.HStar2LeafHash, 0, len(st.Leaves))
    43  		for k64, v := range st.Leaves {
    44  			sfx, err := storage.ParseSuffix(k64)
    45  			if err != nil {
    46  				return err
    47  			}
    48  			// TODO(gdbelvin): test against subtree depth.
    49  			if sfx.Bits%depthQuantum != 0 {
    50  				return fmt.Errorf("unexpected non-leaf suffix found: %x", sfx.Bits)
    51  			}
    52  
    53  			leaves = append(leaves, merkle.HStar2LeafHash{
    54  				Index:    storage.NewNodeIDFromPrefixSuffix(st.Prefix, sfx, hasher.BitLen()).BigInt(),
    55  				LeafHash: v,
    56  			})
    57  		}
    58  		hs2 := merkle.NewHStar2(treeID, hasher)
    59  		root, err := hs2.HStar2Nodes(st.Prefix, int(st.Depth), leaves, nil,
    60  			func(depth int, index *big.Int, h []byte) error {
    61  				if depth == len(st.Prefix)*8 && len(st.Prefix) > 0 {
    62  					// no space for the root in the node cache
    63  					return nil
    64  				}
    65  				nodeID := storage.NewNodeIDFromBigInt(depth, index, hasher.BitLen())
    66  				_, sfx := nodeID.Split(len(st.Prefix), int(st.Depth))
    67  				sfxKey := sfx.String()
    68  				if glog.V(4) {
    69  					b, err := base64.StdEncoding.DecodeString(sfxKey)
    70  					if err != nil {
    71  						glog.Errorf("base64.DecodeString(%v): %v", sfxKey, err)
    72  					}
    73  					glog.Infof("PopulateMapSubtreeNodes.Set(%x, %d) suffix: %x: %x", index.Bytes(), depth, b, h)
    74  				}
    75  				st.InternalNodes[sfxKey] = h
    76  				return nil
    77  			})
    78  		if err != nil {
    79  			return err
    80  		}
    81  		st.RootHash = root
    82  		return err
    83  	}
    84  }
    85  
    86  // prepareMapSubtreeWrite prepares a map subtree for writing. For maps the internal
    87  // nodes are never written to storage and are thus always cleared.
    88  func prepareMapSubtreeWrite() storage.PrepareSubtreeWriteFunc {
    89  	return func(st *storagepb.SubtreeProto) error {
    90  		st.InternalNodes = nil
    91  		// We don't check the node count for map subtrees but ensure it's zero for consistency
    92  		st.InternalNodeCount = 0
    93  		return nil
    94  	}
    95  }