github.com/zorawar87/trillian@v1.2.1/server/map_rpc_server.go (about)

     1  // Copyright 2016 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 server
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/google/trillian"
    23  	"github.com/google/trillian/extension"
    24  	"github.com/google/trillian/merkle"
    25  	"github.com/google/trillian/merkle/hashers"
    26  	"github.com/google/trillian/storage"
    27  	"github.com/google/trillian/trees"
    28  	"github.com/google/trillian/types"
    29  
    30  	"github.com/golang/glog"
    31  	"google.golang.org/grpc/codes"
    32  	"google.golang.org/grpc/status"
    33  )
    34  
    35  const (
    36  	// Used internally by GetLeaves.
    37  	mostRecentRevision = -1
    38  )
    39  
    40  var (
    41  	optsMapInit  = trees.NewGetOpts(trees.Admin, trillian.TreeType_MAP)
    42  	optsMapRead  = trees.NewGetOpts(trees.Query, trillian.TreeType_MAP)
    43  	optsMapWrite = trees.NewGetOpts(trees.UpdateMap, trillian.TreeType_MAP)
    44  )
    45  
    46  // TODO(codingllama): There is no access control in the server yet and clients could easily modify
    47  // any tree.
    48  
    49  // TrillianMapServer implements the RPC API defined in the proto
    50  type TrillianMapServer struct {
    51  	registry extension.Registry
    52  }
    53  
    54  // NewTrillianMapServer creates a new RPC server backed by registry
    55  func NewTrillianMapServer(registry extension.Registry) *TrillianMapServer {
    56  	return &TrillianMapServer{registry}
    57  }
    58  
    59  // IsHealthy returns nil if the server is healthy, error otherwise.
    60  func (t *TrillianMapServer) IsHealthy() error {
    61  	ctx, span := spanFor(context.Background(), "IsHealthy")
    62  	defer span.End()
    63  	return t.registry.MapStorage.CheckDatabaseAccessible(ctx)
    64  }
    65  
    66  // GetLeaves implements the GetLeaves RPC method.  Each requested index will
    67  // return an inclusion proof to either the leaf, or nil if the leaf does not
    68  // exist.
    69  func (t *TrillianMapServer) GetLeaves(ctx context.Context, req *trillian.GetMapLeavesRequest) (*trillian.GetMapLeavesResponse, error) {
    70  	ctx, span := spanFor(ctx, "GetLeaves")
    71  	defer span.End()
    72  	return t.getLeavesByRevision(ctx, req.MapId, req.Index, mostRecentRevision)
    73  }
    74  
    75  // GetLeavesByRevision implements the GetLeavesByRevision RPC method.
    76  func (t *TrillianMapServer) GetLeavesByRevision(ctx context.Context, req *trillian.GetMapLeavesByRevisionRequest) (*trillian.GetMapLeavesResponse, error) {
    77  	ctx, span := spanFor(ctx, "GetLeavesByRevision")
    78  	defer span.End()
    79  	if req.Revision < 0 {
    80  		return nil, fmt.Errorf("map revision %d must be >= 0", req.Revision)
    81  	}
    82  	return t.getLeavesByRevision(ctx, req.MapId, req.Index, req.Revision)
    83  }
    84  
    85  func (t *TrillianMapServer) getLeavesByRevision(ctx context.Context, mapID int64, indices [][]byte, revision int64) (*trillian.GetMapLeavesResponse, error) {
    86  	tree, hasher, err := t.getTreeAndHasher(ctx, mapID, optsMapRead)
    87  	if err != nil {
    88  		return nil, fmt.Errorf("could not get map %v: %v", mapID, err)
    89  	}
    90  	ctx = trees.NewContext(ctx, tree)
    91  
    92  	tx, err := t.registry.MapStorage.SnapshotForTree(ctx, tree)
    93  	if err != nil {
    94  		return nil, fmt.Errorf("could not create database snapshot: %v", err)
    95  	}
    96  	defer tx.Close()
    97  
    98  	var root *trillian.SignedMapRoot
    99  	if revision < 0 {
   100  		// need to know the newest published revision
   101  		r, err := tx.LatestSignedMapRoot(ctx)
   102  		if err != nil {
   103  			return nil, fmt.Errorf("could not fetch the latest SignedMapRoot: %v", err)
   104  		}
   105  		root = &r
   106  	} else {
   107  		r, err := tx.GetSignedMapRoot(ctx, revision)
   108  		if err != nil {
   109  			return nil, fmt.Errorf("could not fetch SignedMapRoot %v: %v", revision, err)
   110  		}
   111  		root = &r
   112  	}
   113  
   114  	var mapRoot types.MapRootV1
   115  	if err := mapRoot.UnmarshalBinary(root.MapRoot); err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	smtReader := merkle.NewSparseMerkleTreeReader(int64(mapRoot.Revision), hasher, tx)
   120  
   121  	inclusions := make([]*trillian.MapLeafInclusion, 0, len(indices))
   122  	found := 0
   123  	for _, index := range indices {
   124  		if err := checkIndexSize(index, hasher); err != nil {
   125  			return nil, err
   126  		}
   127  		// Fetch the leaf if it exists.
   128  		leaves, err := tx.Get(ctx, int64(mapRoot.Revision), [][]byte{index})
   129  		if err != nil {
   130  			return nil, fmt.Errorf("could not fetch leaf %x: %v", index, err)
   131  		}
   132  		var leaf *trillian.MapLeaf
   133  		if len(leaves) == 1 {
   134  			leaf = &leaves[0]
   135  			found++
   136  		} else {
   137  			// Empty leaf for proof of non-existence.
   138  			leafHash, err := hasher.HashLeaf(mapID, index, nil)
   139  			if err != nil {
   140  				return nil, fmt.Errorf("HashLeaf(nil): %v", err)
   141  			}
   142  			leaf = &trillian.MapLeaf{
   143  				Index:     index,
   144  				LeafValue: nil,
   145  				LeafHash:  leafHash,
   146  			}
   147  		}
   148  
   149  		// Fetch the proof regardless of whether the leaf exists.
   150  		proof, err := smtReader.InclusionProof(ctx, int64(mapRoot.Revision), index)
   151  		if err != nil {
   152  			return nil, fmt.Errorf("could not get inclusion proof for leaf %x: %v", index, err)
   153  		}
   154  
   155  		inclusions = append(inclusions, &trillian.MapLeafInclusion{
   156  			Leaf:      leaf,
   157  			Inclusion: proof,
   158  		})
   159  	}
   160  	glog.V(1).Infof("%v: wanted %v leaves, found %v", mapID, len(indices), found)
   161  
   162  	if err := tx.Commit(); err != nil {
   163  		return nil, fmt.Errorf("could not commit db transaction: %v", err)
   164  	}
   165  
   166  	return &trillian.GetMapLeavesResponse{
   167  		MapLeafInclusion: inclusions,
   168  		MapRoot:          root,
   169  	}, nil
   170  }
   171  
   172  func checkIndexSize(index []byte, hasher hashers.MapHasher) error {
   173  	// The parameter is named 'index' (here and in the RPC API) because it's the ordinal number
   174  	// of the leaf, but that number is obtained by hashing the key value that corresponds to the
   175  	// leaf.  Leaf "indices" are therefore sparsely scattered in the range [0, 2^hashsize) and
   176  	// are represented as a []byte, and every leaf must have an index that is the same size.
   177  	//
   178  	// We currently police this by requiring that the hash size for the index space be the same
   179  	// as the hash size for the tree itself, although that's not strictly required (e.g. could
   180  	// have SHA-256 for generating leaf indices, but SHA-512 for building the root hash).
   181  	if len(index) != hasher.Size() {
   182  		return status.Errorf(codes.InvalidArgument, "index len(%x) is not %d", index, hasher.Size())
   183  	}
   184  	return nil
   185  }
   186  
   187  // SetLeaves implements the SetLeaves RPC method.
   188  func (t *TrillianMapServer) SetLeaves(ctx context.Context, req *trillian.SetMapLeavesRequest) (*trillian.SetMapLeavesResponse, error) {
   189  	// Check leaves all have unique indices.
   190  	seen := make(map[string]bool)
   191  	for _, leaf := range req.Leaves {
   192  		k := fmt.Sprintf("%x", leaf.Index)
   193  		if seen[k] {
   194  			return nil, status.Errorf(codes.InvalidArgument, "index %s duplicated", k)
   195  		}
   196  		seen[k] = true
   197  	}
   198  
   199  	ctx, span := spanFor(ctx, "SetLeaves")
   200  	defer span.End()
   201  	mapID := req.MapId
   202  	tree, hasher, err := t.getTreeAndHasher(ctx, mapID, optsMapWrite)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	ctx = trees.NewContext(ctx, tree)
   207  
   208  	var newRoot *trillian.SignedMapRoot
   209  	err = t.registry.MapStorage.ReadWriteTransaction(ctx, tree, func(ctx context.Context, tx storage.MapTreeTX) error {
   210  		glog.V(2).Infof("%v: Writing at revision %v", mapID, tx.WriteRevision())
   211  		smtWriter, err := merkle.NewSparseMerkleTreeWriter(
   212  			ctx,
   213  			req.MapId,
   214  			tx.WriteRevision(),
   215  			hasher, func(ctx context.Context, f func(context.Context, storage.MapTreeTX) error) error {
   216  				return t.registry.MapStorage.ReadWriteTransaction(ctx, tree, f)
   217  			})
   218  		if err != nil {
   219  			return err
   220  		}
   221  
   222  		for _, l := range req.Leaves {
   223  			if err := checkIndexSize(l.Index, hasher); err != nil {
   224  				return err
   225  			}
   226  			if l.LeafValue == nil {
   227  				// Leaves are empty by default. Do not allow clients to store
   228  				// empty leaf values as this messes up the calculation of empty
   229  				// branches.
   230  				continue
   231  			}
   232  			leafHash, err := hasher.HashLeaf(mapID, l.Index, l.LeafValue)
   233  			if err != nil {
   234  				return fmt.Errorf("HashLeaf(): %v", err)
   235  			}
   236  			l.LeafHash = leafHash
   237  
   238  			if err = tx.Set(ctx, l.Index, *l); err != nil {
   239  				return err
   240  			}
   241  			if err = smtWriter.SetLeaves(ctx, []merkle.HashKeyValue{
   242  				{
   243  					HashedKey:   l.Index,
   244  					HashedValue: l.LeafHash,
   245  				},
   246  			}); err != nil {
   247  				return err
   248  			}
   249  		}
   250  
   251  		rootHash, err := smtWriter.CalculateRoot()
   252  		if err != nil {
   253  			return fmt.Errorf("CalculateRoot(): %v", err)
   254  		}
   255  
   256  		newRoot, err = t.makeSignedMapRoot(ctx, tree, time.Now(), rootHash, req.MapId, tx.WriteRevision(), req.Metadata)
   257  		if err != nil {
   258  			return fmt.Errorf("makeSignedMapRoot(): %v", err)
   259  		}
   260  
   261  		// TODO(al): need an smtWriter.Rollback() or similar I think.
   262  		return tx.StoreSignedMapRoot(ctx, *newRoot)
   263  	})
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	return &trillian.SetMapLeavesResponse{MapRoot: newRoot}, nil
   268  }
   269  
   270  func (t *TrillianMapServer) makeSignedMapRoot(ctx context.Context, tree *trillian.Tree, smrTs time.Time,
   271  	rootHash []byte, mapID, revision int64, meta []byte) (*trillian.SignedMapRoot, error) {
   272  	smr := &types.MapRootV1{
   273  		RootHash:       rootHash,
   274  		TimestampNanos: uint64(smrTs.UnixNano()),
   275  		Revision:       uint64(revision),
   276  		Metadata:       meta,
   277  	}
   278  	signer, err := trees.Signer(ctx, tree)
   279  	if err != nil {
   280  		return nil, fmt.Errorf("trees.Signer(): %v", err)
   281  	}
   282  	root, err := signer.SignMapRoot(smr)
   283  	if err != nil {
   284  		return nil, fmt.Errorf("SignMapRoot(): %v", err)
   285  	}
   286  	return root, nil
   287  }
   288  
   289  // GetSignedMapRoot implements the GetSignedMapRoot RPC method.
   290  func (t *TrillianMapServer) GetSignedMapRoot(ctx context.Context, req *trillian.GetSignedMapRootRequest) (*trillian.GetSignedMapRootResponse, error) {
   291  	ctx, span := spanFor(ctx, "GetSignedMapRoot")
   292  	defer span.End()
   293  	tree, ctx, err := t.getTreeAndContext(ctx, req.MapId, optsMapRead)
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  	tx, err := t.registry.MapStorage.SnapshotForTree(ctx, tree)
   298  	if err != nil {
   299  		return nil, err
   300  	}
   301  	defer tx.Close()
   302  
   303  	r, err := tx.LatestSignedMapRoot(ctx)
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	if err := tx.Commit(); err != nil {
   309  		glog.Warningf("%v: Commit failed for GetSignedMapRoot: %v", req.MapId, err)
   310  		return nil, err
   311  	}
   312  
   313  	return &trillian.GetSignedMapRootResponse{
   314  		MapRoot: &r,
   315  	}, nil
   316  }
   317  
   318  // GetSignedMapRootByRevision implements the GetSignedMapRootByRevision RPC
   319  // method.
   320  func (t *TrillianMapServer) GetSignedMapRootByRevision(ctx context.Context, req *trillian.GetSignedMapRootByRevisionRequest) (*trillian.GetSignedMapRootResponse, error) {
   321  	ctx, span := spanFor(ctx, "GetSignedMapRootByRevision")
   322  	defer span.End()
   323  	if req.Revision < 0 {
   324  		return nil, fmt.Errorf("map revision %d must be >= 0", req.Revision)
   325  	}
   326  	tree, ctx, err := t.getTreeAndContext(ctx, req.MapId, optsMapRead)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  	tx, err := t.registry.MapStorage.SnapshotForTree(ctx, tree)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	defer tx.Close()
   335  
   336  	r, err := tx.GetSignedMapRoot(ctx, req.Revision)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	if err := tx.Commit(); err != nil {
   342  		glog.Warningf("%v: Commit failed for GetSignedMapRootByRevision: %v", req.MapId, err)
   343  		return nil, err
   344  	}
   345  
   346  	return &trillian.GetSignedMapRootResponse{
   347  		MapRoot: &r,
   348  	}, nil
   349  }
   350  
   351  func (t *TrillianMapServer) getTreeAndHasher(ctx context.Context, treeID int64, opts trees.GetOpts) (*trillian.Tree, hashers.MapHasher, error) {
   352  	tree, err := trees.GetTree(ctx, t.registry.AdminStorage, treeID, opts)
   353  	if err != nil {
   354  		return nil, nil, err
   355  	}
   356  	th, err := hashers.NewMapHasher(tree.HashStrategy)
   357  	if err != nil {
   358  		return nil, nil, err
   359  	}
   360  	return tree, th, nil
   361  }
   362  
   363  func (t *TrillianMapServer) getTreeAndContext(ctx context.Context, treeID int64, opts trees.GetOpts) (*trillian.Tree, context.Context, error) {
   364  	tree, err := trees.GetTree(ctx, t.registry.AdminStorage, treeID, opts)
   365  	if err != nil {
   366  		return nil, nil, err
   367  	}
   368  	return tree, trees.NewContext(ctx, tree), nil
   369  }
   370  
   371  // InitMap implements the RPC Method of the same name.
   372  func (t *TrillianMapServer) InitMap(ctx context.Context, req *trillian.InitMapRequest) (*trillian.InitMapResponse, error) {
   373  	ctx, span := spanFor(ctx, "InitMap")
   374  	defer span.End()
   375  	mapID := req.MapId
   376  	tree, hasher, err := t.getTreeAndHasher(ctx, mapID, optsMapInit)
   377  	if err != nil {
   378  		return nil, status.Errorf(codes.FailedPrecondition, "getTreeAndHasher(): %v", err)
   379  	}
   380  	ctx = trees.NewContext(ctx, tree)
   381  
   382  	var rev0Root *trillian.SignedMapRoot
   383  	err = t.registry.MapStorage.ReadWriteTransaction(ctx, tree, func(ctx context.Context, tx storage.MapTreeTX) error {
   384  		// Check that the map actually needs initialising
   385  		latestRoot, err := tx.LatestSignedMapRoot(ctx)
   386  		if err != nil && err != storage.ErrTreeNeedsInit {
   387  			return status.Errorf(codes.FailedPrecondition, "LatestSignedMapRoot(): %v", err)
   388  		}
   389  		// Belt and braces check.
   390  		if latestRoot.GetMapRoot() != nil {
   391  			return status.Errorf(codes.AlreadyExists, "map is already initialised")
   392  		}
   393  
   394  		rev0Root = nil
   395  
   396  		glog.V(2).Infof("%v: Need to init map root revision 0", mapID)
   397  		rootHash := hasher.HashEmpty(mapID, make([]byte, hasher.Size()), hasher.BitLen())
   398  		rev0Root, err = t.makeSignedMapRoot(ctx, tree, time.Now(), rootHash, mapID, 0 /*revision*/, nil /* metadata */)
   399  		if err != nil {
   400  			return fmt.Errorf("makeSignedMapRoot(): %v", err)
   401  		}
   402  
   403  		return tx.StoreSignedMapRoot(ctx, *rev0Root)
   404  	})
   405  	if err != nil {
   406  		return nil, err
   407  	}
   408  
   409  	return &trillian.InitMapResponse{
   410  		Created: rev0Root,
   411  	}, nil
   412  }