github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/transactionpool/persist.go (about)

     1  package transactionpool
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/NebulousLabs/Sia/modules"
     9  	"github.com/NebulousLabs/Sia/persist"
    10  	"github.com/NebulousLabs/Sia/types"
    11  
    12  	"github.com/NebulousLabs/bolt"
    13  )
    14  
    15  var (
    16  	// bucketRecentConsensusChange holds the most recent consensus change seen
    17  	// by the transaction pool.
    18  	bucketRecentConsensusChange = []byte("RecentConsensusChange")
    19  
    20  	// bucketConfirmedTransactions holds the ids of every transaction that has
    21  	// been confirmed on the blockchain.
    22  	bucketConfirmedTransactions = []byte("ConfirmedTransactions")
    23  
    24  	// errNilConsensusChange is returned if there is no consensus change in the
    25  	// database.
    26  	errNilConsensusChange = errors.New("no consensus change found")
    27  
    28  	// fieldRecentConsensusChange is the field in bucketRecentConsensusChange
    29  	// that holds the value of the most recent consensus change.
    30  	fieldRecentConsensusChange = []byte("RecentConsensusChange")
    31  )
    32  
    33  // resetDB deletes all consensus related persistence from the transaction pool.
    34  func (tp *TransactionPool) resetDB(tx *bolt.Tx) error {
    35  	err := tx.DeleteBucket(bucketConfirmedTransactions)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	err = tp.putRecentConsensusChange(tx, modules.ConsensusChangeBeginning)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	_, err = tx.CreateBucket(bucketConfirmedTransactions)
    44  	return err
    45  }
    46  
    47  // initPersist creates buckets in the database
    48  func (tp *TransactionPool) initPersist() error {
    49  	// Create the persist directory if it does not yet exist.
    50  	err := os.MkdirAll(tp.persistDir, 0700)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	// Open the database file.
    56  	tp.db, err = persist.OpenDatabase(dbMetadata, filepath.Join(tp.persistDir, dbFilename))
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	// Create the database and get the most recent consensus change.
    62  	var cc modules.ConsensusChangeID
    63  	err = tp.db.Update(func(tx *bolt.Tx) error {
    64  		// Create the database buckets.
    65  		buckets := [][]byte{
    66  			bucketRecentConsensusChange,
    67  			bucketConfirmedTransactions,
    68  		}
    69  		for _, bucket := range buckets {
    70  			_, err := tx.CreateBucketIfNotExists(bucket)
    71  			if err != nil {
    72  				return err
    73  			}
    74  		}
    75  
    76  		// Get the recent consensus change.
    77  		cc, err = tp.getRecentConsensusChange(tx)
    78  		if err == errNilConsensusChange {
    79  			return tp.putRecentConsensusChange(tx, modules.ConsensusChangeBeginning)
    80  		}
    81  		return err
    82  	})
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	// Subscribe to the consensus set using the most recent consensus change.
    88  	err = tp.consensusSet.ConsensusSetSubscribe(tp, cc)
    89  	if err == modules.ErrInvalidConsensusChangeID {
    90  		// Reset and rescan because the consensus set does not recognize the
    91  		// provided consensus change id.
    92  		resetErr := tp.db.Update(func(tx *bolt.Tx) error {
    93  			return tp.resetDB(tx)
    94  		})
    95  		if resetErr != nil {
    96  			return resetErr
    97  		}
    98  		return tp.consensusSet.ConsensusSetSubscribe(tp, modules.ConsensusChangeBeginning)
    99  	}
   100  	return err
   101  }
   102  
   103  // getRecentConsensusChange returns the most recent consensus change from the
   104  // database.
   105  func (tp *TransactionPool) getRecentConsensusChange(tx *bolt.Tx) (cc modules.ConsensusChangeID, err error) {
   106  	ccBytes := tx.Bucket(bucketRecentConsensusChange).Get(fieldRecentConsensusChange)
   107  	if ccBytes == nil {
   108  		return modules.ConsensusChangeID{}, errNilConsensusChange
   109  	}
   110  	copy(cc[:], ccBytes)
   111  	return cc, nil
   112  }
   113  
   114  // putRecentConsensusChange updates the most recent consensus change seen by
   115  // the transaction pool.
   116  func (tp *TransactionPool) putRecentConsensusChange(tx *bolt.Tx, cc modules.ConsensusChangeID) error {
   117  	return tx.Bucket(bucketRecentConsensusChange).Put(fieldRecentConsensusChange, cc[:])
   118  }
   119  
   120  // transactionConfirmed returns true if the transaction has been confirmed on
   121  // the blockchain and false if the transaction has not been confirmed on the
   122  // blockchain.
   123  func (tp *TransactionPool) transactionConfirmed(tx *bolt.Tx, id types.TransactionID) bool {
   124  	confirmedBytes := tx.Bucket(bucketConfirmedTransactions).Get(id[:])
   125  	if confirmedBytes == nil {
   126  		return false
   127  	}
   128  	return true
   129  }
   130  
   131  // addTransaction adds a transaction to the list of confirmed transactions.
   132  func (tp *TransactionPool) addTransaction(tx *bolt.Tx, id types.TransactionID) error {
   133  	return tx.Bucket(bucketConfirmedTransactions).Put(id[:], []byte{})
   134  }
   135  
   136  // deleteTransaction deletes a transaction from the list of confirmed
   137  // transactions.
   138  func (tp *TransactionPool) deleteTransaction(tx *bolt.Tx, id types.TransactionID) error {
   139  	return tx.Bucket(bucketConfirmedTransactions).Delete(id[:])
   140  }