github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/tlog/testclient.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  	"fmt"
     9  	"math/rand"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/google/trillian"
    14  	"github.com/google/trillian/types"
    15  	rstatus "google.golang.org/genproto/googleapis/rpc/status"
    16  )
    17  
    18  var (
    19  	_ Client = (*testClient)(nil)
    20  )
    21  
    22  // testClient provides an implemenation of the Client interface that can be
    23  // used for testing. No RPC connection is made to a trillian log and all data
    24  // is stored in memory.
    25  type testClient struct {
    26  	sync.Mutex
    27  
    28  	trees  map[int64]*trillian.Tree      // [treeID]Tree
    29  	leaves map[int64][]*trillian.LogLeaf // [treeID][]LogLeaf
    30  }
    31  
    32  // NewTestClient returns a new testClient.
    33  func NewTestClient(t *testing.T) *testClient {
    34  	return &testClient{
    35  		trees:  make(map[int64]*trillian.Tree),
    36  		leaves: make(map[int64][]*trillian.LogLeaf),
    37  	}
    38  }
    39  
    40  // Close closes the client connection. There is nothing to do for the test tlog
    41  // client.
    42  //
    43  // This function satisfies the Client interface.
    44  func (t *testClient) Close() {}
    45  
    46  // TreeNew creates a new tree.
    47  //
    48  // This function satisfies the Client interface.
    49  func (t *testClient) TreeNew() (*trillian.Tree, *trillian.SignedLogRoot, error) {
    50  	t.Lock()
    51  	defer t.Unlock()
    52  
    53  	// Create trillian tree
    54  	tree := trillian.Tree{
    55  		TreeId:      rand.Int63(),
    56  		TreeState:   trillian.TreeState_ACTIVE,
    57  		TreeType:    trillian.TreeType_LOG,
    58  		DisplayName: "",
    59  		Description: "",
    60  	}
    61  	t.trees[tree.TreeId] = &tree
    62  
    63  	// Initialize leaves
    64  	t.leaves[tree.TreeId] = []*trillian.LogLeaf{}
    65  
    66  	return &tree, nil, nil
    67  }
    68  
    69  // TreeFreeze sets the status of a tree to frozen and returns the updated tree.
    70  //
    71  // This function satisfies the Client interface.
    72  func (t *testClient) TreeFreeze(treeID int64) (*trillian.Tree, error) {
    73  	t.Lock()
    74  	defer t.Unlock()
    75  
    76  	tree, ok := t.trees[treeID]
    77  	if !ok {
    78  		return nil, fmt.Errorf("tree not found")
    79  	}
    80  	tree.TreeState = trillian.TreeState_FROZEN
    81  	t.trees[treeID] = tree
    82  
    83  	return tree, nil
    84  }
    85  
    86  // Tree returns a tree.
    87  //
    88  // This function satisfies the Client interface.
    89  func (t *testClient) Tree(treeID int64) (*trillian.Tree, error) {
    90  	t.Lock()
    91  	defer t.Unlock()
    92  
    93  	tree, ok := t.trees[treeID]
    94  	if !ok {
    95  		return nil, fmt.Errorf("tree not found")
    96  	}
    97  
    98  	return tree, nil
    99  }
   100  
   101  // TreesAll returns all trees in the trillian instance.
   102  //
   103  // This function satisfies the Client interface.
   104  func (t *testClient) TreesAll() ([]*trillian.Tree, error) {
   105  	t.Lock()
   106  	defer t.Unlock()
   107  
   108  	trees := make([]*trillian.Tree, len(t.trees))
   109  	for _, v := range t.trees {
   110  		trees = append(trees, &trillian.Tree{
   111  			TreeId:      v.TreeId,
   112  			TreeState:   v.TreeState,
   113  			TreeType:    v.TreeType,
   114  			DisplayName: v.DisplayName,
   115  			Description: v.Description,
   116  		})
   117  	}
   118  
   119  	return trees, nil
   120  }
   121  
   122  // LeavesAppend appends leaves onto a tree.
   123  //
   124  // This function satisfies the Client interface.
   125  func (t *testClient) LeavesAppend(treeID int64, leavesAppend []*trillian.LogLeaf) ([]QueuedLeafProof, *types.LogRootV1, error) {
   126  	t.Lock()
   127  	defer t.Unlock()
   128  
   129  	leaves, ok := t.leaves[treeID]
   130  	if !ok {
   131  		leaves = make([]*trillian.LogLeaf, 0, len(leavesAppend))
   132  	}
   133  
   134  	// Get last leaf index
   135  	var index int64
   136  	if len(leaves) > 0 {
   137  		index = int64(len(leaves)) - 1
   138  	}
   139  
   140  	// Append leaves
   141  	queued := make([]QueuedLeafProof, 0, len(leavesAppend))
   142  	for _, v := range leavesAppend {
   143  		// Append to leaves
   144  		v.MerkleLeafHash = MerkleLeafHash(v.LeafValue)
   145  		v.LeafIndex = index + 1
   146  		leaves = append(leaves, v)
   147  		index++
   148  
   149  		// Append to reply
   150  		queued = append(queued, QueuedLeafProof{
   151  			QueuedLeaf: &trillian.QueuedLogLeaf{
   152  				Leaf: v,
   153  				Status: &rstatus.Status{
   154  					Code: 0, // 0 indicates OK
   155  				},
   156  			},
   157  		})
   158  	}
   159  
   160  	// Save updated leaves
   161  	t.leaves[treeID] = leaves
   162  
   163  	return queued, nil, nil
   164  }
   165  
   166  // LeavesAll returns all leaves of a tree.
   167  //
   168  // This function satisfies the Client interface.
   169  func (t *testClient) LeavesAll(treeID int64) ([]*trillian.LogLeaf, error) {
   170  	t.Lock()
   171  	defer t.Unlock()
   172  
   173  	// Verify tree exists
   174  	_, ok := t.trees[treeID]
   175  	if !ok {
   176  		return nil, fmt.Errorf("tree not found")
   177  	}
   178  
   179  	// Get leaves
   180  	leaves, ok := t.leaves[treeID]
   181  	if !ok {
   182  		leaves = make([]*trillian.LogLeaf, 0)
   183  	}
   184  
   185  	// Copy leaves
   186  	leavesCopy := make([]*trillian.LogLeaf, 0, len(leaves))
   187  	for _, v := range leaves {
   188  		var (
   189  			leafValue []byte
   190  			extraData []byte
   191  		)
   192  		copy(leafValue, v.LeafValue)
   193  		copy(extraData, v.ExtraData)
   194  		leavesCopy = append(leavesCopy, &trillian.LogLeaf{
   195  			MerkleLeafHash: MerkleLeafHash(leafValue),
   196  			LeafValue:      leafValue,
   197  			ExtraData:      extraData,
   198  			LeafIndex:      v.LeafIndex,
   199  		})
   200  	}
   201  
   202  	return leavesCopy, nil
   203  }
   204  
   205  // SignedLogRoot has not been implemented yet.
   206  //
   207  // This function satisfies the Client interface.
   208  func (t *testClient) SignedLogRoot(tree *trillian.Tree) (*trillian.SignedLogRoot, *types.LogRootV1, error) {
   209  	return nil, nil, fmt.Errorf("not implemented")
   210  }
   211  
   212  // InclusionProof has not been implement yet.
   213  //
   214  // This function satisfies the Client interface.
   215  func (t *testClient) InclusionProof(treeID int64, merkleLeafHash []byte, lr *types.LogRootV1) (*trillian.Proof, error) {
   216  	return nil, fmt.Errorf("not implemented")
   217  }