github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/tlog/client.go (about)

     1  // Copyright (c) 2021-2022 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package tlog
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"fmt"
    11  	"time"
    12  
    13  	"github.com/golang/protobuf/ptypes"
    14  	"github.com/google/trillian"
    15  	tclient "github.com/google/trillian/client"
    16  	"github.com/google/trillian/merkle/rfc6962"
    17  	"github.com/google/trillian/types"
    18  	"google.golang.org/genproto/protobuf/field_mask"
    19  	"google.golang.org/grpc"
    20  	"google.golang.org/grpc/codes"
    21  	"google.golang.org/grpc/connectivity"
    22  	"google.golang.org/grpc/status"
    23  )
    24  
    25  const (
    26  	// waitForInclusionTimeout is the amount of time that we wait for
    27  	// a queued leaf to be appended onto a tlog tree before timing out.
    28  	waitForInclusionTimeout = 120 * time.Second
    29  )
    30  
    31  var (
    32  	_ Client = (*client)(nil)
    33  )
    34  
    35  // client implements the Client interface using the trillian provided
    36  // TrillianLogClient and TrillianAdminClient.
    37  type client struct {
    38  	host  string
    39  	grpc  *grpc.ClientConn
    40  	log   trillian.TrillianLogClient
    41  	admin trillian.TrillianAdminClient
    42  	ctx   context.Context
    43  }
    44  
    45  // NewClient returns a new client.
    46  func NewClient(host string) (*client, error) {
    47  	// Default gprc max message size is ~4MB (4194304 bytes). This is
    48  	// not large enough for trees with tens of thousands of leaves.
    49  	// Increase it to 20MB.
    50  	maxMsgSize := grpc.WithMaxMsgSize(20 * 1024 * 1024)
    51  
    52  	// Setup trillian connection
    53  	g, err := grpc.Dial(host, grpc.WithInsecure(), maxMsgSize)
    54  	if err != nil {
    55  		return nil, fmt.Errorf("grpc dial: %v", err)
    56  	}
    57  
    58  	t := client{
    59  		grpc:  g,
    60  		log:   trillian.NewTrillianLogClient(g),
    61  		admin: trillian.NewTrillianAdminClient(g),
    62  		ctx:   context.Background(),
    63  	}
    64  
    65  	// The grpc dial requires a little time to connect
    66  	time.Sleep(time.Second)
    67  
    68  	// Ensure trillian is up and running
    69  	for t.grpc.GetState() != connectivity.Ready {
    70  		wait := 15 * time.Second
    71  		log.Infof("Cannot connect to trillian at %v; retry in %v ", host, wait)
    72  		time.Sleep(wait)
    73  	}
    74  
    75  	return &t, nil
    76  }
    77  
    78  // Close closes the trillian grpc connection.
    79  //
    80  // This function satisfies the Client interface.
    81  func (t *client) Close() {
    82  	log.Tracef("Close %v", t.host)
    83  
    84  	t.grpc.Close()
    85  }
    86  
    87  // TreeNew returns a new trillian tree and verifies that the signatures are
    88  // correct. It returns the tree and the signed log root which can be externally
    89  // verified.
    90  //
    91  // This function satisfies the Client interface.
    92  func (t *client) TreeNew() (*trillian.Tree, *trillian.SignedLogRoot, error) {
    93  	log.Tracef("TreeNew")
    94  
    95  	// Create new trillian tree
    96  	tree, err := t.admin.CreateTree(t.ctx, &trillian.CreateTreeRequest{
    97  		Tree: &trillian.Tree{
    98  			TreeState:       trillian.TreeState_ACTIVE,
    99  			TreeType:        trillian.TreeType_LOG,
   100  			DisplayName:     "",
   101  			Description:     "",
   102  			MaxRootDuration: ptypes.DurationProto(0),
   103  		},
   104  	})
   105  	if err != nil {
   106  		return nil, nil, err
   107  	}
   108  
   109  	// Init tree or signer goes bananas
   110  	ilr, err := t.log.InitLog(t.ctx, &trillian.InitLogRequest{
   111  		LogId: tree.TreeId,
   112  	})
   113  	if err != nil {
   114  		return nil, nil, err
   115  	}
   116  
   117  	// Check trillian errors
   118  	switch code := status.Code(err); code {
   119  	case codes.Unavailable:
   120  		err = fmt.Errorf("log server unavailable: %v", err)
   121  	case codes.AlreadyExists:
   122  		err = fmt.Errorf("just-created Log (%v) is already initialised: %v",
   123  			tree.TreeId, err)
   124  	case codes.OK:
   125  		log.Debugf("Initialised Log: %v", tree.TreeId)
   126  	default:
   127  		err = fmt.Errorf("failed to InitLog (unknown error)")
   128  	}
   129  	if err != nil {
   130  		return nil, nil, err
   131  	}
   132  
   133  	return tree, ilr.Created, nil
   134  }
   135  
   136  // TreeFreeze sets the status of a tree to frozen and returns the updated tree.
   137  //
   138  // This function satisfies the Client interface.
   139  func (t *client) TreeFreeze(treeID int64) (*trillian.Tree, error) {
   140  	log.Tracef("TreeFreeze: %v", treeID)
   141  
   142  	// Get the current tree
   143  	tree, err := t.Tree(treeID)
   144  	if err != nil {
   145  		return nil, fmt.Errorf("tree: %v", err)
   146  	}
   147  
   148  	// Update the tree state
   149  	tree.TreeState = trillian.TreeState_FROZEN
   150  
   151  	// Apply update
   152  	updated, err := t.admin.UpdateTree(t.ctx, &trillian.UpdateTreeRequest{
   153  		Tree: tree,
   154  		UpdateMask: &field_mask.FieldMask{
   155  			Paths: []string{"tree_state"},
   156  		},
   157  	})
   158  	if err != nil {
   159  		return nil, fmt.Errorf("UpdateTree: %v", err)
   160  	}
   161  
   162  	return updated, nil
   163  }
   164  
   165  // Tree returns a trillian tree.
   166  //
   167  // This function satisfies the Client interface.
   168  func (t *client) Tree(treeID int64) (*trillian.Tree, error) {
   169  	log.Tracef("Tree: %v", treeID)
   170  
   171  	tree, err := t.admin.GetTree(t.ctx, &trillian.GetTreeRequest{
   172  		TreeId: treeID,
   173  	})
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	if tree.TreeId != treeID {
   178  		// Sanity check
   179  		return nil, fmt.Errorf("wrong tree returned; got %v, want %v",
   180  			tree.TreeId, treeID)
   181  	}
   182  
   183  	return tree, nil
   184  }
   185  
   186  // TreesAll returns all trees in the trillian instance.
   187  //
   188  // This function satisfies the Client interface
   189  func (t *client) TreesAll() ([]*trillian.Tree, error) {
   190  	log.Tracef("TreesAll")
   191  
   192  	ltr, err := t.admin.ListTrees(t.ctx, &trillian.ListTreesRequest{})
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	return ltr.Tree, nil
   198  }
   199  
   200  // InclusionProof returns a proof for the inclusion of a merkle leaf hash in a
   201  // log root.
   202  //
   203  // This function satisfies the Client interface
   204  func (t *client) InclusionProof(treeID int64, merkleLeafHash []byte, lrv1 *types.LogRootV1) (*trillian.Proof, error) {
   205  	log.Tracef("InclusionProof: %v %x", treeID, merkleLeafHash)
   206  
   207  	resp, err := t.log.GetInclusionProofByHash(t.ctx,
   208  		&trillian.GetInclusionProofByHashRequest{
   209  			LogId:    treeID,
   210  			LeafHash: merkleLeafHash,
   211  			TreeSize: int64(lrv1.TreeSize),
   212  		})
   213  	if err != nil {
   214  		return nil, fmt.Errorf("GetInclusionProof: %v", err)
   215  	}
   216  	if len(resp.Proof) != 1 {
   217  		return nil, fmt.Errorf("invalid number of proofs: got %v, want 1",
   218  			len(resp.Proof))
   219  	}
   220  	proof := resp.Proof[0]
   221  
   222  	// Verify inclusion proof
   223  	verifier := tclient.NewLogVerifier(rfc6962.DefaultHasher)
   224  	err = verifier.VerifyInclusionByHash(lrv1, merkleLeafHash, proof)
   225  	if err != nil {
   226  		return nil, fmt.Errorf("VerifyInclusionByHash: %v", err)
   227  	}
   228  
   229  	return proof, nil
   230  }
   231  
   232  // SignedLogRoot returns the signed log root of a trillian tree.
   233  //
   234  // This function satisfies the Client interface.
   235  func (t *client) SignedLogRoot(tree *trillian.Tree) (*trillian.SignedLogRoot, *types.LogRootV1, error) {
   236  	log.Tracef("SignedLogRoot %+v", tree)
   237  
   238  	// Get the signed log root for the current tree height
   239  	resp, err := t.log.GetLatestSignedLogRoot(t.ctx,
   240  		&trillian.GetLatestSignedLogRootRequest{LogId: tree.TreeId})
   241  	if err != nil {
   242  		return nil, nil, err
   243  	}
   244  
   245  	var lrv1 types.LogRootV1
   246  	if err := lrv1.UnmarshalBinary(resp.SignedLogRoot.GetLogRoot()); err != nil {
   247  		return nil, nil, err
   248  	}
   249  
   250  	return resp.SignedLogRoot, &lrv1, nil
   251  }
   252  
   253  // LeavesAppend appends leaves onto a tlog tree. The queued leaf and the leaf
   254  // inclusion proof are returned. If a leaf was not successfully appended, the
   255  // queued leaf will still be returned and the error will be in the queued leaf.
   256  // Inclusion proofs will not exist for leaves that fail to be appended. Note
   257  // leaves that are duplicates will fail and it is the callers responsibility to
   258  // determine how they should be handled.
   259  //
   260  // Trillian DOES NOT guarantee that the leaves of a queued leaves batch are
   261  // appended in the order in which they were received. Trillian is also not
   262  // consistent about the order that leaves are appended in. At the time of
   263  // writing this I have not looked into why this is or if there are other
   264  // methods that can be used. DO NOT rely on the leaves being in a specific
   265  // order.
   266  //
   267  // This function satisfies the Client interface.
   268  func (t *client) LeavesAppend(treeID int64, leaves []*trillian.LogLeaf) ([]QueuedLeafProof, *types.LogRootV1, error) {
   269  	log.Tracef("LeavesAppend: %v %v", treeID, len(leaves))
   270  
   271  	// Get the latest signed log root
   272  	tree, err := t.Tree(treeID)
   273  	if err != nil {
   274  		return nil, nil, err
   275  	}
   276  	slr, _, err := t.SignedLogRoot(tree)
   277  	if err != nil {
   278  		return nil, nil, fmt.Errorf("SignedLogRoot pre update: %v", err)
   279  	}
   280  	if tree.TreeState == trillian.TreeState_FROZEN {
   281  		return nil, nil, fmt.Errorf("tree is frozen")
   282  	}
   283  
   284  	// Append leaves
   285  	queuedLeaves := make([]*trillian.QueuedLogLeaf, 0, len(leaves))
   286  	for _, l := range leaves {
   287  		qlr, err := t.log.QueueLeaf(t.ctx,
   288  			&trillian.QueueLeafRequest{
   289  				LogId: treeID,
   290  				Leaf:  l,
   291  			})
   292  		if err != nil {
   293  			return nil, nil, fmt.Errorf("QueueLeaf: %v", err)
   294  		}
   295  		queuedLeaves = append(queuedLeaves, qlr.QueuedLeaf)
   296  	}
   297  
   298  	// Wait for inclusion of all queued leaves in the root. We must
   299  	// check for inclusion instead of simply waiting for a root update
   300  	// because a root update doesn't necessarily mean the queued leaves
   301  	// from this request were added yet. The root will be updated as
   302  	// soon as the first leaf in the queue is added, which can lead to
   303  	// errors when the queue contains multiple leaves and we try to
   304  	// fetch the inclusion proof in the code below for leaves that are
   305  	// still in the process of being taken out of the queue.
   306  	var n int
   307  	for _, ql := range queuedLeaves {
   308  		c := codes.Code(ql.GetStatus().GetCode())
   309  		if c != codes.OK {
   310  			n++
   311  		}
   312  	}
   313  
   314  	log.Tracef("Queued/Ignored leaves: %v/%v", len(leaves)-n, n)
   315  	log.Tracef("Waiting for inclusion of queued leaves...")
   316  
   317  	var logRoot types.LogRootV1
   318  	err = logRoot.UnmarshalBinary(slr.LogRoot)
   319  	if err != nil {
   320  		return nil, nil, err
   321  	}
   322  	c, err := tclient.NewFromTree(t.log, tree, logRoot)
   323  	if err != nil {
   324  		return nil, nil, err
   325  	}
   326  	for _, v := range queuedLeaves {
   327  		ctx, cancel := context.WithTimeout(context.Background(),
   328  			waitForInclusionTimeout)
   329  		defer cancel()
   330  		err = c.WaitForInclusion(ctx, v.Leaf.LeafValue)
   331  		if err != nil {
   332  			return nil, nil, fmt.Errorf("WaitForInclusion: %v", err)
   333  		}
   334  	}
   335  
   336  	// Get the latest signed log root
   337  	_, lr, err := t.SignedLogRoot(tree)
   338  	if err != nil {
   339  		return nil, nil, fmt.Errorf("SignedLogRoot post update: %v", err)
   340  	}
   341  
   342  	// Get inclusion proofs
   343  	proofs := make([]QueuedLeafProof, 0, len(queuedLeaves))
   344  	var failed int
   345  	for _, v := range queuedLeaves {
   346  		qlp := QueuedLeafProof{
   347  			QueuedLeaf: v,
   348  		}
   349  
   350  		// Only retrieve the inclusion proof if the leaf was successfully
   351  		// appended. Leaves that were not successfully appended will be
   352  		// returned without an inclusion proof and the caller can decide
   353  		// what to do with them. Note this includes leaves that were not
   354  		// appended because they were a duplicate.
   355  		c := codes.Code(v.GetStatus().GetCode())
   356  		if c == codes.OK {
   357  			// Verify that the merkle leaf hash is using the expected
   358  			// hashing algorithm.
   359  			m := MerkleLeafHash(v.Leaf.LeafValue)
   360  			if !bytes.Equal(m, v.Leaf.MerkleLeafHash) {
   361  				e := fmt.Sprintf("unknown merkle leaf hash: got %x, want %x",
   362  					m, v.Leaf.MerkleLeafHash)
   363  				panic(e)
   364  			}
   365  
   366  			// The LeafIndex of a QueuedLogLeaf will not be set. Get the
   367  			// inclusion proof by MerkleLeafHash.
   368  			qlp.Proof, err = t.InclusionProof(treeID, v.Leaf.MerkleLeafHash, lr)
   369  			if err != nil {
   370  				return nil, nil, fmt.Errorf("InclusionProof %v %x: %v",
   371  					treeID, v.Leaf.MerkleLeafHash, err)
   372  			}
   373  		} else {
   374  			// Leaf contains an error
   375  			failed++
   376  		}
   377  
   378  		proofs = append(proofs, qlp)
   379  	}
   380  
   381  	// Sanity check
   382  	if len(proofs) != len(leaves) {
   383  		return nil, nil, fmt.Errorf("got %v queued leaves, want %v",
   384  			len(proofs), len(leaves))
   385  	}
   386  
   387  	log.Debugf("Appended leaves (%v/%v) to tree %v",
   388  		len(leaves)-failed, len(leaves), treeID)
   389  
   390  	return proofs, lr, nil
   391  }
   392  
   393  // leavesByRange returns the log leaves of a trillian tree by the range provided
   394  // by the user.
   395  //
   396  // This function satisfies the Client interface.
   397  func (t *client) leavesByRange(treeID int64, startIndex, count int64) ([]*trillian.LogLeaf, error) {
   398  	log.Tracef("leavesByRange: %v %v %v", treeID, startIndex, count)
   399  
   400  	glbrr, err := t.log.GetLeavesByRange(t.ctx,
   401  		&trillian.GetLeavesByRangeRequest{
   402  			LogId:      treeID,
   403  			StartIndex: startIndex,
   404  			Count:      count,
   405  		})
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  
   410  	return glbrr.Leaves, nil
   411  }
   412  
   413  // LeavesAll returns all of the leaves for the provided treeID.
   414  //
   415  // This function satisfies the Client interface.
   416  func (t *client) LeavesAll(treeID int64) ([]*trillian.LogLeaf, error) {
   417  	log.Tracef("LeavesAll: %v", treeID)
   418  
   419  	// Get tree
   420  	tree, err := t.Tree(treeID)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	// Get signed log root
   426  	_, lr, err := t.SignedLogRoot(tree)
   427  	if err != nil {
   428  		return nil, fmt.Errorf("SignedLogRoot: %v", err)
   429  	}
   430  	if lr.TreeSize == 0 {
   431  		return []*trillian.LogLeaf{}, nil
   432  	}
   433  
   434  	// Get all leaves
   435  	leaves, err := t.leavesByRange(treeID, 0, int64(lr.TreeSize))
   436  	if err != nil {
   437  		return nil, fmt.Errorf("leavesByRange: %v", err)
   438  	}
   439  
   440  	return leaves, nil
   441  }