github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/transactionpool/database.go (about)

     1  package transactionpool
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"SiaPrime/build"
     7  	"SiaPrime/encoding"
     8  	"SiaPrime/modules"
     9  	"SiaPrime/types"
    10  
    11  	"gitlab.com/NebulousLabs/bolt"
    12  	"gitlab.com/NebulousLabs/errors"
    13  )
    14  
    15  // database.go contains objects related to the layout of the transaction pool's
    16  // database, as well as getters and setters. Logic for interacting with the
    17  // database can be found in persist.go
    18  
    19  // Buckets in the database.
    20  var (
    21  	// bucketBlockHeight holds the most recent block height seen by the
    22  	// transaction pool.
    23  	bucketBlockHeight = []byte("BlockHeight")
    24  
    25  	// bucketConfirmedTransactions holds the ids of every transaction that has
    26  	// been confirmed on the blockchain.
    27  	bucketConfirmedTransactions = []byte("ConfirmedTransactions")
    28  
    29  	// bucketFeeMedian stores all of the persist data relating to the fee
    30  	// median.
    31  	bucketFeeMedian = []byte("FeeMedian")
    32  
    33  	// bucketRecentConsensusChange holds the most recent consensus change seen
    34  	// by the transaction pool.
    35  	bucketRecentConsensusChange = []byte("RecentConsensusChange")
    36  )
    37  
    38  // Explicitly named fields in the database.
    39  var (
    40  	// fieldBlockHeight is the field in bucketBlockHeight that holds the value of
    41  	// the most recent block height.
    42  	fieldBlockHeight = []byte("BlockHeight")
    43  
    44  	// fieldFeeMedian is the fee median persist data stored in a fee median
    45  	// field.
    46  	fieldFeeMedian = []byte("FeeMedian")
    47  
    48  	// fieldRecentBlockID is used to store the id of the most recent block seen
    49  	// by the transaction pool.
    50  	fieldRecentBlockID = []byte("RecentBlockID")
    51  
    52  	// fieldRecentConsensusChange is the field in bucketRecentConsensusChange
    53  	// that holds the value of the most recent consensus change.
    54  	fieldRecentConsensusChange = []byte("RecentConsensusChange")
    55  )
    56  
    57  // Errors relating to the database.
    58  var (
    59  	// errNilConsensusChange is returned if there is no consensus change in the
    60  	// database.
    61  	errNilConsensusChange = errors.New("no consensus change found")
    62  
    63  	// errNilFeeMedian is the message returned if a database does not find fee
    64  	// median persistence.
    65  	errNilFeeMedian = errors.New("no fee median found")
    66  
    67  	// errNilRecentBlock is returned if there is no data stored in
    68  	// fieldRecentBlockID.
    69  	errNilRecentBlock = errors.New("no recent block found in the database")
    70  )
    71  
    72  // Complex objects that get stored in database fields.
    73  type (
    74  	// medianPersist is the json object that gets stored in the database so that
    75  	// the transaction pool can persist its block based fee estimations.
    76  	medianPersist struct {
    77  		RecentMedians   []types.Currency
    78  		RecentMedianFee types.Currency
    79  	}
    80  )
    81  
    82  // deleteTransaction deletes a transaction from the list of confirmed
    83  // transactions.
    84  func (tp *TransactionPool) deleteTransaction(tx *bolt.Tx, id types.TransactionID) error {
    85  	return tx.Bucket(bucketConfirmedTransactions).Delete(id[:])
    86  }
    87  
    88  // getBlockHeight returns the most recent block height from the database.
    89  func (tp *TransactionPool) getBlockHeight(tx *bolt.Tx) (bh types.BlockHeight, err error) {
    90  	err = encoding.Unmarshal(tx.Bucket(bucketBlockHeight).Get(fieldBlockHeight), &bh)
    91  	return
    92  }
    93  
    94  // getFeeMedian will get the fee median struct stored in the database.
    95  func (tp *TransactionPool) getFeeMedian(tx *bolt.Tx) (medianPersist, error) {
    96  	medianBytes := tp.dbTx.Bucket(bucketFeeMedian).Get(fieldFeeMedian)
    97  	if medianBytes == nil {
    98  		return medianPersist{}, errNilFeeMedian
    99  	}
   100  
   101  	var mp medianPersist
   102  	err := json.Unmarshal(medianBytes, &mp)
   103  	if err != nil {
   104  		return medianPersist{}, build.ExtendErr("unable to unmarshal median data:", err)
   105  	}
   106  	return mp, nil
   107  }
   108  
   109  // getRecentBlockID will fetch the most recent block id and most recent parent
   110  // id from the database.
   111  func (tp *TransactionPool) getRecentBlockID(tx *bolt.Tx) (recentID types.BlockID, err error) {
   112  	idBytes := tx.Bucket(bucketRecentConsensusChange).Get(fieldRecentBlockID)
   113  	if idBytes == nil {
   114  		return types.BlockID{}, errNilRecentBlock
   115  	}
   116  	copy(recentID[:], idBytes[:])
   117  	if recentID == (types.BlockID{}) {
   118  		return types.BlockID{}, errNilRecentBlock
   119  	}
   120  	return recentID, nil
   121  }
   122  
   123  // getRecentConsensusChange returns the most recent consensus change from the
   124  // database.
   125  func (tp *TransactionPool) getRecentConsensusChange(tx *bolt.Tx) (cc modules.ConsensusChangeID, err error) {
   126  	ccBytes := tx.Bucket(bucketRecentConsensusChange).Get(fieldRecentConsensusChange)
   127  	if ccBytes == nil {
   128  		return modules.ConsensusChangeID{}, errNilConsensusChange
   129  	}
   130  	copy(cc[:], ccBytes)
   131  	return cc, nil
   132  }
   133  
   134  // putBlockHeight updates the transaction pool's block height.
   135  func (tp *TransactionPool) putBlockHeight(tx *bolt.Tx, height types.BlockHeight) error {
   136  	tp.blockHeight = height
   137  	return tx.Bucket(bucketBlockHeight).Put(fieldBlockHeight, encoding.Marshal(height))
   138  }
   139  
   140  // putFeeMedian puts a median fees object into the database.
   141  func (tp *TransactionPool) putFeeMedian(tx *bolt.Tx, mp medianPersist) error {
   142  	objBytes, err := json.Marshal(mp)
   143  	if err != nil {
   144  		return err
   145  	}
   146  	return tx.Bucket(bucketFeeMedian).Put(fieldFeeMedian, objBytes)
   147  }
   148  
   149  // putRecentBlockID will store the most recent block id and the parent id of
   150  // that block in the database.
   151  func (tp *TransactionPool) putRecentBlockID(tx *bolt.Tx, recentID types.BlockID) error {
   152  	return tx.Bucket(bucketRecentConsensusChange).Put(fieldRecentBlockID, recentID[:])
   153  }
   154  
   155  // putRecentConsensusChange updates the most recent consensus change seen by
   156  // the transaction pool.
   157  func (tp *TransactionPool) putRecentConsensusChange(tx *bolt.Tx, cc modules.ConsensusChangeID) error {
   158  	return tx.Bucket(bucketRecentConsensusChange).Put(fieldRecentConsensusChange, cc[:])
   159  }
   160  
   161  // putTransaction adds a transaction to the list of confirmed transactions.
   162  func (tp *TransactionPool) putTransaction(tx *bolt.Tx, id types.TransactionID) error {
   163  	return tx.Bucket(bucketConfirmedTransactions).Put(id[:], []byte{})
   164  }