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 }