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

     1  // Copyright (c) 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 tstore
     6  
     7  import (
     8  	"errors"
     9  
    10  	backend "github.com/decred/politeia/politeiad/backendv2"
    11  	"github.com/google/trillian"
    12  )
    13  
    14  // freezeTreeCheck checks if any trillian trees meet the requirements to be
    15  // frozen. If they do, their status is updated in trillian to frozen.
    16  //
    17  // A frozen trillian tree can no longer be appended to. The trillian_log_signer
    18  // will no longer poll the MySQL database for updates to a tree once it has
    19  // been marked as frozen. This reduces the load on the server and helps prevent
    20  // the CPUs from spinning.
    21  //
    22  // A record is marked as frozen when it can no longer be updated, such as when
    23  // a record status is set to archived. The trillian tree, however, cannot be
    24  // frozen until the record is frozen AND a final dcr timestamp has been added
    25  // to tree. This means that we cannot simply freeze the tree at the same time
    26  // that the record is frozen since it will still need to be timestamped one
    27  // last time.
    28  func (t *Tstore) freezeTreeCheck() error {
    29  	log.Infof("Checking if any trillian trees can be frozen")
    30  
    31  	trees, err := t.tlog.TreesAll()
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	active := make([]*trillian.Tree, 0, len(trees))
    37  	for _, v := range trees {
    38  		if v.TreeState == trillian.TreeState_ACTIVE {
    39  			active = append(active, v)
    40  		}
    41  	}
    42  
    43  	log.Infof("%v/%v active trillian trees found", len(active), len(trees))
    44  
    45  	var frozen int
    46  	for _, tree := range active {
    47  		freeze, err := t.treeShouldBeFrozen(tree)
    48  		if err != nil {
    49  			log.Errorf("treeShouldBeFrozen %v: %v", tree.TreeId, err)
    50  			continue
    51  		}
    52  		if !freeze {
    53  			// Tree shouldn't be frozen. Nothing else to do.
    54  			continue
    55  		}
    56  		_, err = t.tlog.TreeFreeze(tree.TreeId)
    57  		if err != nil {
    58  			return err
    59  		}
    60  
    61  		log.Infof("Tree frozen %v %x", tree.TreeId, tokenFromTreeID(tree.TreeId))
    62  
    63  		frozen++
    64  	}
    65  
    66  	log.Infof("%v trees were frozen; %v active trees remaining",
    67  		frozen, len(active)-frozen)
    68  
    69  	return nil
    70  }
    71  
    72  // treeShouldBeFrozen returns whether a trillian tree meets the requirements to
    73  // have it's status updated from ACTIVE to FROZEN. The requirments are that the
    74  // tree is currently active, the record saved to the tree has been frozen, and
    75  // a final dcr timestamp has been added to the tree.
    76  func (t *Tstore) treeShouldBeFrozen(tree *trillian.Tree) (bool, error) {
    77  	if tree.TreeState != trillian.TreeState_ACTIVE {
    78  		return false, nil
    79  	}
    80  	leaves, err := t.tlog.LeavesAll(tree.TreeId)
    81  	if err != nil {
    82  		return false, err
    83  	}
    84  	if len(leaves) == 0 {
    85  		return false, nil
    86  	}
    87  	r, err := t.recordIndexLatest(leaves)
    88  	switch {
    89  	case errors.Is(err, backend.ErrRecordNotFound):
    90  		// A record index doesn't exist on this tree
    91  		return false, nil
    92  	case err != nil:
    93  		return false, err
    94  	}
    95  	if !r.Frozen {
    96  		// The record has not been frozen yet
    97  		return false, nil
    98  	}
    99  	// The record has been frozen. Check for a final
   100  	// timestamp leaf.
   101  	lastLeaf := leaves[len(leaves)-1]
   102  	d, err := extraDataDecode(lastLeaf.ExtraData)
   103  	if err != nil {
   104  		return false, err
   105  	}
   106  	if d.Desc != dataDescriptorAnchor {
   107  		// The tree still needs a final timestamp.
   108  		return false, nil
   109  	}
   110  	// The record has been frozen and a final timestamp
   111  	// has been added to the tree. The tree can now be
   112  	// frozen.
   113  	return true, nil
   114  }