func (c *LogClient) QueueLeaf(ctx context.Context, data []byte) error {
	leaf := c.BuildLeaf(data)
	_, err := c.client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
		LogId: c.LogID,
		Leaf:  leaf,
	})
	return err
}
QueueLeaf adds a leaf to a Trillian log without blocking.
AlreadyExists is considered a success case by this function.
package client
import (
	"bytes"
	"context"
	"fmt"
	"sort"
	"sync"
	"time"
	"github.com/google/trillian"
	"github.com/google/trillian/client/backoff"
	"github.com/google/trillian/types"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
type LogClient struct {
	*LogVerifier
	LogID         int64
	MinMergeDelay time.Duration
	client        trillian.TrillianLogClient
	root          types.LogRootV1
	rootLock      sync.Mutex
	updateLock    sync.Mutex
}
func New(logID int64, client trillian.TrillianLogClient, verifier *LogVerifier, root types.LogRootV1) *LogClient {
	return &LogClient{
		LogVerifier: verifier,
		LogID:       logID,
		client:      client,
		root:        root,
	}
}
func NewFromTree(client trillian.TrillianLogClient, config *trillian.Tree, root types.LogRootV1) (*LogClient, error) {
	verifier, err := NewLogVerifierFromTree(config)
	if err != nil {
		return nil, err
	}
	return New(config.GetTreeId(), client, verifier, root), nil
}
func (c *LogClient) AddLeaf(ctx context.Context, data []byte) error {
	if err := c.QueueLeaf(ctx, data); err != nil {
		return fmt.Errorf("QueueLeaf(): %v", err)
	}
	if err := c.WaitForInclusion(ctx, data); err != nil {
		return fmt.Errorf("WaitForInclusion(): %v", err)
	}
	return nil
}
func (c *LogClient) ListByIndex(ctx context.Context, start, count int64) ([]*trillian.LogLeaf, error) {
	resp, err := c.client.GetLeavesByRange(ctx,
		&trillian.GetLeavesByRangeRequest{
			LogId:      c.LogID,
			StartIndex: start,
			Count:      count,
		})
	if err != nil {
		return nil, err
	}
	if len(resp.Leaves) < int(count) {
		return nil, fmt.Errorf("len(Leaves)=%d, want %d", len(resp.Leaves), count)
	}
	for i, l := range resp.Leaves {
		if want := start + int64(i); l.LeafIndex != want {
			return nil, fmt.Errorf("Leaves[%d].LeafIndex=%d, want %d", i, l.LeafIndex, want)
		}
	}
	return resp.Leaves, nil
}
func (c *LogClient) WaitForRootUpdate(ctx context.Context) (*types.LogRootV1, error) {
	b := &backoff.Backoff{
		Min:    100 * time.Millisecond,
		Max:    10 * time.Second,
		Factor: 2,
		Jitter: true,
	}
	for {
		newTrusted, err := c.UpdateRoot(ctx)
		switch status.Code(err) {
		case codes.OK:
			if newTrusted != nil {
				return newTrusted, nil
			}
		case codes.Unavailable, codes.NotFound, codes.FailedPrecondition:
		default:
			return nil, err
		}
		select {
		case <-ctx.Done():
			return nil, status.Errorf(codes.DeadlineExceeded, "%v", ctx.Err())
		case <-time.After(b.Duration()):
		}
	}
}
func (c *LogClient) getAndVerifyLatestRoot(ctx context.Context, trusted *types.LogRootV1) (*types.LogRootV1, error) {
	resp, err := c.client.GetLatestSignedLogRoot(ctx,
		&trillian.GetLatestSignedLogRootRequest{
			LogId:         c.LogID,
			FirstTreeSize: int64(trusted.TreeSize),
		})
	if err != nil {
		return nil, err
	}
	var logRoot types.LogRootV1
	if err := logRoot.UnmarshalBinary(resp.GetSignedLogRoot().LogRoot); err != nil {
		return nil, err
	}
	if trusted.TreeSize > 0 &&
		logRoot.TreeSize == trusted.TreeSize &&
		bytes.Equal(logRoot.RootHash, trusted.RootHash) {
		return &logRoot, nil
	}
	if logRoot.TreeSize > 0 {
		if _, err := c.VerifyRoot(trusted, resp.GetSignedLogRoot(), resp.GetProof().GetHashes()); err != nil {
			return nil, err
		}
	}
	return &logRoot, nil
}
func (c *LogClient) GetRoot() *types.LogRootV1 {
	c.rootLock.Lock()
	defer c.rootLock.Unlock()
	ret := c.root
	return &ret
}
func (c *LogClient) UpdateRoot(ctx context.Context) (*types.LogRootV1, error) {
	c.updateLock.Lock()
	defer c.updateLock.Unlock()
	currentlyTrusted := c.GetRoot()
	newTrusted, err := c.getAndVerifyLatestRoot(ctx, currentlyTrusted)
	if err != nil {
		return nil, err
	}
	c.rootLock.Lock()
	defer c.rootLock.Unlock()
	if newTrusted.TimestampNanos > currentlyTrusted.TimestampNanos &&
		newTrusted.TreeSize >= currentlyTrusted.TreeSize {
		c.root = *newTrusted
		return newTrusted, nil
	}
	return nil, nil
}
func (c *LogClient) WaitForInclusion(ctx context.Context, data []byte) error {
	leaf := c.BuildLeaf(data)
	if c.MinMergeDelay > 0 {
		select {
		case <-ctx.Done():
			return status.Errorf(codes.DeadlineExceeded, "%v", ctx.Err())
		case <-time.After(c.MinMergeDelay):
		}
	}
	var root *types.LogRootV1
	for {
		root = c.GetRoot()
		if root.TreeSize >= 1 {
			ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
			if err != nil && status.Code(err) != codes.NotFound {
				return err
			} else if ok {
				return nil
			}
		}
		if _, err := c.WaitForRootUpdate(ctx); err != nil {
			return err
		}
	}
}
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 false, err
	}
	if len(resp.Proof) < 1 {
		return false, nil
	}
	for _, proof := range resp.Proof {
		if err := c.VerifyInclusionByHash(sth, leafHash, proof); err != nil {
			return false, fmt.Errorf("VerifyInclusionByHash(): %v", err)
		}
	}
	return true, nil
}
func (c *LogClient) AddSequencedLeaves(ctx context.Context, dataByIndex map[int64][]byte) error {
	if len(dataByIndex) == 0 {
		return nil
	}
	leaves := make([]*trillian.LogLeaf, 0, len(dataByIndex))
	indexes := make([]int64, 0, len(dataByIndex))
	for index := range dataByIndex {
		indexes = append(indexes, index)
	}
	sort.Slice(indexes, func(a, b int) bool { return indexes[a] < indexes[b] })
	for i, index := range indexes {
		if want := indexes[0] + int64(i); index != want {
			return fmt.Errorf("missing index in contiugous index range. got: %v, want: %v", index, want)
		}
		leaf := c.BuildLeaf(dataByIndex[index])
		leaf.LeafIndex = index
		leaves = append(leaves, leaf)
	}
	_, err := c.client.AddSequencedLeaves(ctx, &trillian.AddSequencedLeavesRequest{
		LogId:  c.LogID,
		Leaves: leaves,
	})
	return err
}