From 46ac0b224e673b969457597b15af2d125ae8c5c2 Mon Sep 17 00:00:00 2001 From: Hayden B Date: Tue, 2 May 2023 12:20:19 -0700 Subject: [PATCH] Refactor Trillian client with exported methods (#1454) This allows the Trillian client to be used in other parts of the codebase besides the api package. The changes included exporting the Response fields and all but one of the struct methods. Also removed ranges since these weren't used outside the api package. Signed-off-by: Hayden Blauzvern --- pkg/api/api.go | 3 +- pkg/api/entries.go | 58 +++--- pkg/api/public_key.go | 4 +- pkg/api/tlog.go | 40 ++--- pkg/{api => util}/trillian_client.go | 255 +++++++++++++-------------- 5 files changed, 179 insertions(+), 181 deletions(-) rename pkg/{api => util}/trillian_client.go (62%) diff --git a/pkg/api/api.go b/pkg/api/api.go index 2883a8814..32dd15532 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -34,6 +34,7 @@ import ( "github.com/sigstore/rekor/pkg/sharding" "github.com/sigstore/rekor/pkg/signer" "github.com/sigstore/rekor/pkg/storage" + "github.com/sigstore/rekor/pkg/util" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" @@ -82,7 +83,7 @@ func NewAPI(treeID uint) (*API, error) { tid := int64(treeID) if tid == 0 { log.Logger.Info("No tree ID specified, attempting to create a new tree") - t, err := createAndInitTree(ctx, logAdminClient, logClient) + t, err := util.CreateAndInitTree(ctx, logAdminClient, logClient) if err != nil { return nil, fmt.Errorf("create and init tree: %w", err) } diff --git a/pkg/api/entries.go b/pkg/api/entries.go index 294304bc4..4abc5db89 100644 --- a/pkg/api/entries.go +++ b/pkg/api/entries.go @@ -67,7 +67,7 @@ func signEntry(ctx context.Context, signer signature.Signer, entry models.LogEnt } // logEntryFromLeaf creates a signed LogEntry struct from trillian structs -func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianClient, leaf *trillian.LogLeaf, +func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc util.TrillianClient, leaf *trillian.LogLeaf, signedLogRoot *trillian.SignedLogRoot, proof *trillian.Proof, tid int64, ranges sharding.LogRanges) (models.LogEntry, error) { log.ContextLogger(ctx).Debugf("log entry from leaf %d", leaf.GetLeafIndex()) @@ -93,7 +93,7 @@ func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianC return nil, fmt.Errorf("signing entry error: %w", err) } - scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tid, root, api.signer) if err != nil { return nil, err } @@ -186,16 +186,16 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry) } - tc := NewTrillianClient(ctx) + tc := util.NewTrillianClient(ctx, api.logClient, api.logID) - resp := tc.addLeaf(leaf) + resp := tc.AddLeaf(leaf) // this represents overall GRPC response state (not the results of insertion into the log) - if resp.status != codes.OK { - return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult) + if resp.Status != codes.OK { + return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianUnexpectedResult) } // this represents the results of inserting the proposed leaf into the log; status is nil in success path - insertionStatus := resp.getAddResult.QueuedLeaf.Status + insertionStatus := resp.GetAddResult.QueuedLeaf.Status if insertionStatus != nil { switch insertionStatus.Code { case int32(code.Code_OK): @@ -212,10 +212,10 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl // We made it this far, that means the entry was successfully added. metricNewEntries.Inc() - queuedLeaf := resp.getAddResult.QueuedLeaf.Leaf + queuedLeaf := resp.GetAddResult.QueuedLeaf.Leaf uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash()) - activeTree := fmt.Sprintf("%x", tc.logID) + activeTree := fmt.Sprintf("%x", api.logID) entryIDstruct, err := sharding.CreateEntryIDFromParts(activeTree, uuid) if err != nil { err := fmt.Errorf("error creating EntryID from active treeID %v and uuid %v: %w", activeTree, uuid, err) @@ -271,15 +271,15 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl } root := &ttypes.LogRootV1{} - if err := root.UnmarshalBinary(resp.getLeafAndProofResult.SignedLogRoot.LogRoot); err != nil { + if err := root.UnmarshalBinary(resp.GetLeafAndProofResult.SignedLogRoot.LogRoot); err != nil { return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error unmarshalling log root: %v", err), sthGenerateError) } hashes := []string{} - for _, hash := range resp.getLeafAndProofResult.Proof.Hashes { + for _, hash := range resp.GetLeafAndProofResult.Proof.Hashes { hashes = append(hashes, hex.EncodeToString(hash)) } - scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), api.logID, root, api.signer) if err != nil { return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError) } @@ -405,22 +405,22 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo for i, hash := range searchHashes { var results map[int64]*trillian.GetEntryAndProofResponse for _, shard := range api.logRanges.AllShards() { - tcs := NewTrillianClientFromTreeID(httpReqCtx, shard) - resp := tcs.getLeafAndProofByHash(hash) - switch resp.status { + tcs := util.NewTrillianClient(httpReqCtx, api.logClient, shard) + resp := tcs.GetLeafAndProofByHash(hash) + switch resp.Status { case codes.OK: - leafResult := resp.getLeafAndProofResult + leafResult := resp.GetLeafAndProofResult if leafResult != nil && leafResult.Leaf != nil { if results == nil { results = map[int64]*trillian.GetEntryAndProofResponse{} } - results[shard] = resp.getLeafAndProofResult + results[shard] = resp.GetLeafAndProofResult } case codes.NotFound: // do nothing here, do not throw 404 error continue default: - return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.status, resp.err), trillianCommunicationError) + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.Status, resp.Err), trillianCommunicationError) } } searchByHashResults[i] = results @@ -431,7 +431,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo if leafResp == nil { continue } - tcs := NewTrillianClientFromTreeID(httpReqCtx, shard) + tcs := util.NewTrillianClient(httpReqCtx, api.logClient, shard) logEntry, err := logEntryFromLeaf(httpReqCtx, api.signer, tcs, leafResp.Leaf, leafResp.SignedLogRoot, leafResp.Proof, shard, api.logRanges) if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error()) @@ -461,19 +461,19 @@ func retrieveLogEntryByIndex(ctx context.Context, logIndex int) (models.LogEntry log.ContextLogger(ctx).Infof("Retrieving log entry by index %d", logIndex) tid, resolvedIndex := api.logRanges.ResolveVirtualIndex(logIndex) - tc := NewTrillianClientFromTreeID(ctx, tid) + tc := util.NewTrillianClient(ctx, api.logClient, tid) log.ContextLogger(ctx).Debugf("Retrieving resolved index %v from TreeID %v", resolvedIndex, tid) - resp := tc.getLeafAndProofByIndex(resolvedIndex) - switch resp.status { + resp := tc.GetLeafAndProofByIndex(resolvedIndex) + switch resp.Status { case codes.OK: case codes.NotFound, codes.OutOfRange, codes.InvalidArgument: return models.LogEntry{}, ErrNotFound default: - return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.err, trillianCommunicationError) + return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.Err, trillianCommunicationError) } - result := resp.getLeafAndProofResult + result := resp.GetLeafAndProofResult leaf := result.Leaf if leaf == nil { return models.LogEntry{}, ErrNotFound @@ -525,13 +525,13 @@ func retrieveUUIDFromTree(ctx context.Context, uuid string, tid int64) (models.L return models.LogEntry{}, types.ValidationError(err) } - tc := NewTrillianClientFromTreeID(ctx, tid) + tc := util.NewTrillianClient(ctx, api.logClient, tid) log.ContextLogger(ctx).Debugf("Attempting to retrieve UUID %v from TreeID %v", uuid, tid) - resp := tc.getLeafAndProofByHash(hashValue) - switch resp.status { + resp := tc.GetLeafAndProofByHash(hashValue) + switch resp.Status { case codes.OK: - result := resp.getLeafAndProofResult + result := resp.GetLeafAndProofResult leaf := result.Leaf if leaf == nil { return models.LogEntry{}, ErrNotFound @@ -546,7 +546,7 @@ func retrieveUUIDFromTree(ctx context.Context, uuid string, tid int64) (models.L case codes.NotFound: return models.LogEntry{}, ErrNotFound default: - log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.status) + log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.Status) return models.LogEntry{}, errors.New("unexpected error") } } diff --git a/pkg/api/public_key.go b/pkg/api/public_key.go index 22e0c0436..e7e6b0fbc 100644 --- a/pkg/api/public_key.go +++ b/pkg/api/public_key.go @@ -26,10 +26,8 @@ import ( ) func GetPublicKeyHandler(params pubkey.GetPublicKeyParams) middleware.Responder { - ctx := params.HTTPRequest.Context() treeID := swag.StringValue(params.TreeID) - tc := NewTrillianClient(ctx) - pk, err := tc.ranges.PublicKey(api.pubkey, treeID) + pk, err := api.logRanges.PublicKey(api.pubkey, treeID) if err != nil { return handleRekorAPIError(params, http.StatusBadRequest, err, "") } diff --git a/pkg/api/tlog.go b/pkg/api/tlog.go index e6bbdcc68..4419a9515 100644 --- a/pkg/api/tlog.go +++ b/pkg/api/tlog.go @@ -36,12 +36,12 @@ import ( // GetLogInfoHandler returns the current size of the tree and the STH func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { - tc := NewTrillianClient(params.HTTPRequest.Context()) + tc := util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID) // for each inactive shard, get the loginfo var inactiveShards []*models.InactiveShardLogInfo - for _, shard := range tc.ranges.GetInactive() { - if shard.TreeID == tc.ranges.ActiveTreeID() { + for _, shard := range api.logRanges.GetInactive() { + if shard.TreeID == api.logRanges.ActiveTreeID() { break } // Get details for this inactive shard @@ -52,11 +52,11 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { inactiveShards = append(inactiveShards, is) } - resp := tc.getLatest(0) - if resp.status != codes.OK { - return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError) + resp := tc.GetLatest(0) + if resp.Status != codes.OK { + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError) } - result := resp.getLatestResult + result := resp.GetLatestResult root := &types.LogRootV1{} if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { @@ -67,7 +67,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { treeSize := int64(root.TreeSize) scBytes, err := util.CreateAndSignCheckpoint(params.HTTPRequest.Context(), - viper.GetString("rekor_server.hostname"), tc.ranges.ActiveTreeID(), root, api.signer) + viper.GetString("rekor_server.hostname"), api.logRanges.ActiveTreeID(), root, api.signer) if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError) } @@ -76,7 +76,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { RootHash: &hashString, TreeSize: &treeSize, SignedTreeHead: stringPointer(string(scBytes)), - TreeID: stringPointer(fmt.Sprintf("%d", tc.logID)), + TreeID: stringPointer(fmt.Sprintf("%d", api.logID)), InactiveShards: inactiveShards, } @@ -92,21 +92,21 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder { if *params.FirstSize > params.LastSize { return handleRekorAPIError(params, http.StatusBadRequest, nil, fmt.Sprintf(firstSizeLessThanLastSize, *params.FirstSize, params.LastSize)) } - tc := NewTrillianClient(params.HTTPRequest.Context()) + tc := util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID) if treeID := swag.StringValue(params.TreeID); treeID != "" { id, err := strconv.Atoi(treeID) if err != nil { log.Logger.Infof("Unable to convert %s to string, skipping initializing client with Tree ID: %v", treeID, err) } else { - tc = NewTrillianClientFromTreeID(params.HTTPRequest.Context(), int64(id)) + tc = util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, int64(id)) } } - resp := tc.getConsistencyProof(*params.FirstSize, params.LastSize) - if resp.status != codes.OK { - return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError) + resp := tc.GetConsistencyProof(*params.FirstSize, params.LastSize) + if resp.Status != codes.OK { + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError) } - result := resp.getConsistencyProofResult + result := resp.GetConsistencyProofResult var root types.LogRootV1 if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { @@ -136,12 +136,12 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder { } func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShardLogInfo, error) { - tc := NewTrillianClientFromTreeID(ctx, tid) - resp := tc.getLatest(0) - if resp.status != codes.OK { - return nil, fmt.Errorf("resp code is %d", resp.status) + tc := util.NewTrillianClient(ctx, api.logClient, tid) + resp := tc.GetLatest(0) + if resp.Status != codes.OK { + return nil, fmt.Errorf("resp code is %d", resp.Status) } - result := resp.getLatestResult + result := resp.GetLatestResult root := &types.LogRootV1{} if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { diff --git a/pkg/api/trillian_client.go b/pkg/util/trillian_client.go similarity index 62% rename from pkg/api/trillian_client.go rename to pkg/util/trillian_client.go index f0043d9b4..e1d0d5d6d 100644 --- a/pkg/api/trillian_client.go +++ b/pkg/util/trillian_client.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package util import ( "context" @@ -22,7 +22,6 @@ import ( "time" "github.com/sigstore/rekor/pkg/log" - "github.com/sigstore/rekor/pkg/sharding" "github.com/transparency-dev/merkle/proof" "github.com/transparency-dev/merkle/rfc6962" @@ -35,38 +34,38 @@ import ( "github.com/google/trillian/types" ) +// TrillianClient provides a wrapper around the Trillian client type TrillianClient struct { client trillian.TrillianLogClient - ranges sharding.LogRanges logID int64 context context.Context } -func NewTrillianClient(ctx context.Context) TrillianClient { +// NewTrillianClient creates a TrillianClient with the given Trillian client and log/tree ID. +func NewTrillianClient(ctx context.Context, logClient trillian.TrillianLogClient, logID int64) TrillianClient { return TrillianClient{ - client: api.logClient, - ranges: api.logRanges, - logID: api.logID, - context: ctx, - } -} - -func NewTrillianClientFromTreeID(ctx context.Context, tid int64) TrillianClient { - return TrillianClient{ - client: api.logClient, - logID: tid, + client: logClient, + logID: logID, context: ctx, } } +// Response includes a status code, an optional error message, and one of the results based on the API call type Response struct { - status codes.Code - err error - getAddResult *trillian.QueueLeafResponse - getProofResult *trillian.GetInclusionProofByHashResponse - getLeafAndProofResult *trillian.GetEntryAndProofResponse - getLatestResult *trillian.GetLatestSignedLogRootResponse - getConsistencyProofResult *trillian.GetConsistencyProofResponse + // Status is the status code of the response + Status codes.Code + // Error contains an error on request or client failure + Err error + // GetAddResult contains the response from queueing a leaf in Trillian + GetAddResult *trillian.QueueLeafResponse + // GetLeafAndProofResult contains the response for fetching an inclusion proof and leaf + GetLeafAndProofResult *trillian.GetEntryAndProofResponse + // GetLatestResult contains the response for the latest checkpoint + GetLatestResult *trillian.GetLatestSignedLogRootResponse + // GetConsistencyProofResult contains the response for a consistency proof between two log sizes + GetConsistencyProofResult *trillian.GetConsistencyProofResponse + // getProofResult contains the response for an inclusion proof fetched by leaf hash + getProofResult *trillian.GetInclusionProofByHashResponse } func unmarshalLogRoot(logRoot []byte) (types.LogRootV1, error) { @@ -88,7 +87,7 @@ func (t *TrillianClient) root() (types.LogRootV1, error) { return unmarshalLogRoot(resp.SignedLogRoot.LogRoot) } -func (t *TrillianClient) addLeaf(byteValue []byte) *Response { +func (t *TrillianClient) AddLeaf(byteValue []byte) *Response { leaf := &trillian.LogLeaf{ LeafValue: byteValue, } @@ -101,18 +100,18 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { // check for error if err != nil || (resp.QueuedLeaf.Status != nil && resp.QueuedLeaf.Status.Code != int32(codes.OK)) { return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } root, err := t.root() if err != nil { return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } v := client.NewLogVerifier(rfc6962.DefaultHasher) @@ -123,8 +122,8 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { select { case <-ctx.Done(): return &Response{ - status: codes.DeadlineExceeded, - err: ctx.Err(), + Status: codes.DeadlineExceeded, + Err: ctx.Err(), } case <-time.After(logClient.MinMergeDelay): } @@ -134,7 +133,7 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if root.TreeSize >= 1 { proofResp := t.getProofByHash(resp.QueuedLeaf.Leaf.MerkleLeafHash) // if this call succeeds or returns an error other than "not found", return - if proofResp.err == nil || (proofResp.err != nil && status.Code(proofResp.err) != codes.NotFound) { + if proofResp.Err == nil || (proofResp.Err != nil && status.Code(proofResp.Err) != codes.NotFound) { return proofResp } // otherwise wait for a root update before trying again @@ -142,19 +141,19 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if _, err := logClient.WaitForRootUpdate(ctx); err != nil { return &Response{ - status: codes.Unknown, - err: err, + Status: codes.Unknown, + Err: err, } } } } proofResp := waitForInclusion(t.context, resp.QueuedLeaf.Leaf.MerkleLeafHash) - if proofResp.err != nil { + if proofResp.Err != nil { return &Response{ - status: status.Code(proofResp.err), - err: proofResp.err, - getAddResult: resp, + Status: status.Code(proofResp.Err), + Err: proofResp.Err, + GetAddResult: resp, } } @@ -162,41 +161,41 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if len(proofs) != 1 { err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(resp.QueuedLeaf.Leaf.MerkleLeafHash), len(proofs)) return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } leafIndex := proofs[0].LeafIndex - leafResp := t.getLeafAndProofByIndex(leafIndex) - if leafResp.err != nil { + leafResp := t.GetLeafAndProofByIndex(leafIndex) + if leafResp.Err != nil { return &Response{ - status: status.Code(leafResp.err), - err: leafResp.err, - getAddResult: resp, + Status: status.Code(leafResp.Err), + Err: leafResp.Err, + GetAddResult: resp, } } // overwrite queued leaf that doesn't have index set - resp.QueuedLeaf.Leaf = leafResp.getLeafAndProofResult.Leaf + resp.QueuedLeaf.Leaf = leafResp.GetLeafAndProofResult.Leaf return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, // include getLeafAndProofResult for inclusion proof - getLeafAndProofResult: leafResp.getLeafAndProofResult, + GetLeafAndProofResult: leafResp.GetLeafAndProofResult, } } -func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response { +func (t *TrillianClient) GetLeafAndProofByHash(hash []byte) *Response { // get inclusion proof for hash, extract index, then fetch leaf using index proofResp := t.getProofByHash(hash) - if proofResp.err != nil { + if proofResp.Err != nil { return &Response{ - status: status.Code(proofResp.err), - err: proofResp.err, + Status: status.Code(proofResp.Err), + Err: proofResp.Err, } } @@ -204,31 +203,31 @@ func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response { if len(proofs) != 1 { err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(hash), len(proofs)) return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } - return t.getLeafAndProofByIndex(proofs[0].LeafIndex) + return t.GetLeafAndProofByIndex(proofs[0].LeafIndex) } -func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response { +func (t *TrillianClient) GetLeafAndProofByIndex(index int64) *Response { ctx, cancel := context.WithTimeout(t.context, 20*time.Second) defer cancel() - rootResp := t.getLatest(0) - if rootResp.err != nil { + rootResp := t.GetLatest(0) + if rootResp.Err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } - root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot) + root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot) if err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } @@ -242,24 +241,61 @@ func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response { if resp != nil && resp.Proof != nil { if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(index), root.TreeSize, resp.GetLeaf().MerkleLeafHash, resp.Proof.Hashes, root.RootHash); err != nil { return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } return &Response{ - status: status.Code(err), - err: err, - getLeafAndProofResult: &trillian.GetEntryAndProofResponse{ + Status: status.Code(err), + Err: err, + GetLeafAndProofResult: &trillian.GetEntryAndProofResponse{ Proof: resp.Proof, Leaf: resp.Leaf, - SignedLogRoot: rootResp.getLatestResult.SignedLogRoot, + SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot, }, } } return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, + } +} + +func (t *TrillianClient) GetLatest(leafSizeInt int64) *Response { + + ctx, cancel := context.WithTimeout(t.context, 20*time.Second) + defer cancel() + + resp, err := t.client.GetLatestSignedLogRoot(ctx, + &trillian.GetLatestSignedLogRootRequest{ + LogId: t.logID, + FirstTreeSize: leafSizeInt, + }) + + return &Response{ + Status: status.Code(err), + Err: err, + GetLatestResult: resp, + } +} + +func (t *TrillianClient) GetConsistencyProof(firstSize, lastSize int64) *Response { + + ctx, cancel := context.WithTimeout(t.context, 20*time.Second) + defer cancel() + + resp, err := t.client.GetConsistencyProof(ctx, + &trillian.GetConsistencyProofRequest{ + LogId: t.logID, + FirstTreeSize: firstSize, + SecondTreeSize: lastSize, + }) + + return &Response{ + Status: status.Code(err), + Err: err, + GetConsistencyProofResult: resp, } } @@ -267,26 +303,26 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response { ctx, cancel := context.WithTimeout(t.context, 20*time.Second) defer cancel() - rootResp := t.getLatest(0) - if rootResp.err != nil { + rootResp := t.GetLatest(0) + if rootResp.Err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } - root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot) + root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot) if err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } // issue 1308: if the tree is empty, there's no way we can return a proof if root.TreeSize == 0 { return &Response{ - status: codes.NotFound, - err: status.Error(codes.NotFound, "tree is empty"), + Status: codes.NotFound, + Err: status.Error(codes.NotFound, "tree is empty"), } } @@ -302,66 +338,29 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response { for _, proof := range resp.Proof { if err := v.VerifyInclusionByHash(&root, hashValue, proof); err != nil { return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } } // Return an inclusion proof response with the requested return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, getProofResult: &trillian.GetInclusionProofByHashResponse{ Proof: resp.Proof, - SignedLogRoot: rootResp.getLatestResult.SignedLogRoot, + SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot, }, } } return &Response{ - status: status.Code(err), - err: err, - } -} - -func (t *TrillianClient) getLatest(leafSizeInt int64) *Response { - - ctx, cancel := context.WithTimeout(t.context, 20*time.Second) - defer cancel() - - resp, err := t.client.GetLatestSignedLogRoot(ctx, - &trillian.GetLatestSignedLogRootRequest{ - LogId: t.logID, - FirstTreeSize: leafSizeInt, - }) - - return &Response{ - status: status.Code(err), - err: err, - getLatestResult: resp, - } -} - -func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) *Response { - - ctx, cancel := context.WithTimeout(t.context, 20*time.Second) - defer cancel() - - resp, err := t.client.GetConsistencyProof(ctx, - &trillian.GetConsistencyProofRequest{ - LogId: t.logID, - FirstTreeSize: firstSize, - SecondTreeSize: lastSize, - }) - - return &Response{ - status: status.Code(err), - err: err, - getConsistencyProofResult: resp, + Status: status.Code(err), + Err: err, } } -func createAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) { +func CreateAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) { t, err := adminClient.CreateTree(ctx, &trillian.CreateTreeRequest{ Tree: &trillian.Tree{ TreeType: trillian.TreeType_LOG,