github.com/zorawar87/trillian@v1.2.1/server/proof_fetcher.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 21 "github.com/google/trillian" 22 "github.com/google/trillian/merkle" 23 "github.com/google/trillian/merkle/hashers" 24 "github.com/google/trillian/storage" 25 ) 26 27 // fetchNodesAndBuildProof is used by both inclusion and consistency proofs. It fetches the nodes 28 // from storage and converts them into the proof proto that will be returned to the client. 29 // This includes rehashing where necessary to serve proofs for tree sizes between stored tree 30 // revisions. This code only relies on the NodeReader interface so can be tested without 31 // a complete storage implementation. 32 func fetchNodesAndBuildProof(ctx context.Context, tx storage.NodeReader, th hashers.LogHasher, treeRevision, leafIndex int64, proofNodeFetches []merkle.NodeFetch) (trillian.Proof, error) { 33 proofNodes, err := fetchNodes(ctx, tx, treeRevision, proofNodeFetches) 34 if err != nil { 35 return trillian.Proof{}, err 36 } 37 38 r := &rehasher{th: th} 39 for i, node := range proofNodes { 40 r.process(node, proofNodeFetches[i]) 41 } 42 43 return r.rehashedProof(leafIndex) 44 } 45 46 // rehasher bundles the rehashing logic into a simple state machine 47 type rehasher struct { 48 th hashers.LogHasher 49 rehashing bool 50 rehashNode storage.Node 51 proof [][]byte 52 proofError error 53 } 54 55 func (r *rehasher) process(node storage.Node, fetch merkle.NodeFetch) { 56 switch { 57 case !r.rehashing && fetch.Rehash: 58 // Start of a rehashing chain 59 r.startRehashing(node) 60 61 case r.rehashing && !fetch.Rehash: 62 // End of a rehash chain, resulting in a rehashed proof node 63 r.endRehashing() 64 // And the current node needs to be added to the proof 65 r.emitNode(node) 66 67 case r.rehashing && fetch.Rehash: 68 // Continue with rehashing, update the node we're recomputing 69 r.rehashNode.Hash = r.th.HashChildren(node.Hash, r.rehashNode.Hash) 70 71 default: 72 // Not rehashing, just pass the node through 73 r.emitNode(node) 74 } 75 } 76 77 func (r *rehasher) emitNode(node storage.Node) { 78 r.proof = append(r.proof, node.Hash) 79 } 80 81 func (r *rehasher) startRehashing(node storage.Node) { 82 r.rehashNode = storage.Node{Hash: node.Hash} 83 r.rehashing = true 84 } 85 86 func (r *rehasher) endRehashing() { 87 if r.rehashing { 88 r.proof = append(r.proof, r.rehashNode.Hash) 89 r.rehashing = false 90 } 91 } 92 93 func (r *rehasher) rehashedProof(leafIndex int64) (trillian.Proof, error) { 94 r.endRehashing() 95 return trillian.Proof{ 96 LeafIndex: leafIndex, 97 Hashes: r.proof, 98 }, r.proofError 99 } 100 101 // fetchNodes extracts the NodeIDs from a list of NodeFetch structs and passes them 102 // to storage, returning the result after some additional validation checks. 103 func fetchNodes(ctx context.Context, tx storage.NodeReader, treeRevision int64, fetches []merkle.NodeFetch) ([]storage.Node, error) { 104 proofNodeIDs := make([]storage.NodeID, 0, len(fetches)) 105 106 for _, fetch := range fetches { 107 proofNodeIDs = append(proofNodeIDs, fetch.NodeID) 108 } 109 110 proofNodes, err := tx.GetMerkleNodes(ctx, treeRevision, proofNodeIDs) 111 if err != nil { 112 return nil, err 113 } 114 115 if len(proofNodes) != len(proofNodeIDs) { 116 return nil, fmt.Errorf("expected %d nodes from storage but got %d", len(proofNodeIDs), len(proofNodes)) 117 } 118 119 for i, node := range proofNodes { 120 // additional check that the correct node was returned 121 if !node.NodeID.Equivalent(fetches[i].NodeID) { 122 return []storage.Node{}, fmt.Errorf("expected node %v at proof pos %d but got %v", fetches[i], i, node.NodeID) 123 } 124 } 125 126 return proofNodes, nil 127 }