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 }