Skip to content

Commit

Permalink
Example of dealing with server skew. (#995)
Browse files Browse the repository at this point in the history
  • Loading branch information
benlaurie authored and AlCutter committed Apr 16, 2018
1 parent 6bd2b5f commit 9a5dc62
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 64 deletions.
39 changes: 22 additions & 17 deletions client/log_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package client
import (
"bytes"
"context"
"errors"
"fmt"
"time"

Expand Down Expand Up @@ -222,19 +221,18 @@ func (c *LogClient) WaitForInclusion(ctx context.Context, data []byte) error {
return err
}
for {
err = c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
switch status.Code(err) {
case codes.OK:
ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
if err != nil && status.Code(err) != codes.NotFound {
return err
}
if ok {
return nil
case codes.NotFound:
// Wait for TreeSize to update.
if root, err = c.WaitForRootUpdate(ctx, root.TreeSize+1); err != nil {
return err
}
// Retry
default:
}
// Wait for TreeSize to update.
if root, err = c.WaitForRootUpdate(ctx, root.TreeSize+1); err != nil {
return err
}
// Retry
}
}

Expand All @@ -248,7 +246,14 @@ func (c *LogClient) VerifyInclusion(ctx context.Context, data []byte) error {
if err != nil {
return fmt.Errorf("UpdateRoot(): %v", err)
}
return c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("no proof")
}
return nil
}

// GetAndVerifyInclusionAtIndex updates the log root and ensures that the given leaf data has been included in the log at a particular index.
Expand All @@ -269,25 +274,25 @@ func (c *LogClient) GetAndVerifyInclusionAtIndex(ctx context.Context, data []byt
return c.VerifyInclusionAtIndex(root, data, index, resp.Proof.Hashes)
}

func (c *LogClient) getAndVerifyInclusionProof(ctx context.Context, leafHash []byte, sth *types.LogRootV1) error {
func (c *LogClient) getAndVerifyInclusionProof(ctx context.Context, leafHash []byte, sth *types.LogRootV1) (bool, error) {
resp, err := c.client.GetInclusionProofByHash(ctx,
&trillian.GetInclusionProofByHashRequest{
LogId: c.LogID,
LeafHash: leafHash,
TreeSize: int64(sth.TreeSize),
})
if err != nil {
return err
return false, err
}
if len(resp.Proof) < 1 {
return errors.New("no inclusion proof supplied")
return false, nil
}
for _, proof := range resp.Proof {
if err := c.VerifyInclusionByHash(sth, leafHash, proof); err != nil {
return fmt.Errorf("VerifyInclusionByHash(): %v", err)
return false, fmt.Errorf("VerifyInclusionByHash(): %v", err)
}
}
return nil
return true, nil
}

// QueueLeaf adds a leaf to a Trillian log without blocking.
Expand Down
37 changes: 31 additions & 6 deletions integration/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,20 +404,34 @@ func checkInclusionProofLeafOutOfRange(logID int64, client trillian.TrillianLogC
}

// checkInclusionProofTreeSizeOutOfRange requests an inclusion proof for a leaf within the tree size at
// a tree size larger than the current tree size. This should fail.
// a tree size larger than the current tree size. This should succeed but with an STH for the current
// tree and an empty proof, because it is a result of skew.
func checkInclusionProofTreeSizeOutOfRange(logID int64, client trillian.TrillianLogClient, params TestParameters) error {
// Test is an in range leaf index for a tree size that doesn't exist
ctx, cancel := getRPCDeadlineContext(params)
proof, err := client.GetInclusionProof(ctx, &trillian.GetInclusionProofRequest{
req := &trillian.GetInclusionProofRequest{
LogId: logID,
LeafIndex: int64(params.sequencerBatchSize),
TreeSize: params.leafCount + int64(params.sequencerBatchSize),
})
}
proof, err := client.GetInclusionProof(ctx, req)
cancel()
if err != nil {
return fmt.Errorf("log returned error for tree size outside tree: %d v %d: %v", params.leafCount, req.TreeSize, err)
}

if err == nil {
return fmt.Errorf("log returned proof for tree size outside tree: %d v %d: %v", params.sequencerBatchSize, params.leafCount+int64(params.sequencerBatchSize), proof)
var root types.LogRootV1
if err := root.UnmarshalBinary(proof.SignedLogRoot.LogRoot); err != nil {
return fmt.Errorf("could not read current log root: %v", err)
}

if proof.Proof != nil {
return fmt.Errorf("log returned proof for tree size outside tree: %d v %d: %v", params.leafCount, req.TreeSize, proof)
}
if int64(root.TreeSize) >= req.TreeSize {
return fmt.Errorf("log returned bad root for tree size outside tree: %d v %d: %v", params.leafCount, req.TreeSize, proof)
}

return nil
}

Expand Down Expand Up @@ -468,11 +482,22 @@ func checkConsistencyProof(consistParams consistencyProofParams, treeID int64, t
}
resp, err := client.GetConsistencyProof(ctx, req)
cancel()

if err != nil {
return fmt.Errorf("GetConsistencyProof(%v) = %v %v", consistParams, err, resp)
}

if resp.SignedLogRoot == nil || resp.SignedLogRoot.LogRoot == nil {
return fmt.Errorf("received invalid response: %v", resp)
}
var root types.LogRootV1
if err := root.UnmarshalBinary(resp.SignedLogRoot.LogRoot); err != nil {
return fmt.Errorf("could not read current log root: %v", err)
}

if req.SecondTreeSize > int64(root.TreeSize) {
return fmt.Errorf("requested tree size %d > available tree size %d", req.SecondTreeSize, root.TreeSize)
}

verifier := merkle.NewLogVerifier(rfc6962.DefaultHasher)
root1 := tree.RootAtSnapshot(req.FirstTreeSize).Hash()
root2 := tree.RootAtSnapshot(req.SecondTreeSize).Hash()
Expand Down
4 changes: 3 additions & 1 deletion quota/etcd/quotapb/quotapb.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 13 additions & 9 deletions quota/etcd/quotapb/quotapb.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion quota/etcd/storagepb/storagepb.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9a5dc62

Please sign in to comment.