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 }