gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/explorer/database.go (about)

     1  package explorer
     2  
     3  import (
     4  	"errors"
     5  
     6  	"gitlab.com/SiaPrime/SiaPrime/encoding"
     7  	"gitlab.com/SiaPrime/SiaPrime/types"
     8  
     9  	bolt "github.com/coreos/bbolt"
    10  )
    11  
    12  var (
    13  	// database buckets
    14  	bucketBlockFacts            = []byte("BlockFacts")
    15  	bucketBlockIDs              = []byte("BlockIDs")
    16  	bucketBlocksDifficulty      = []byte("BlocksDifficulty")
    17  	bucketBlockTargets          = []byte("BlockTargets")
    18  	bucketFileContractHistories = []byte("FileContractHistories")
    19  	bucketFileContractIDs       = []byte("FileContractIDs")
    20  	// bucketInternal is used to store values internal to the explorer
    21  	bucketInternal         = []byte("Internal")
    22  	bucketSiacoinOutputIDs = []byte("SiacoinOutputIDs")
    23  	bucketSiacoinOutputs   = []byte("SiacoinOutputs")
    24  	bucketSiafundOutputIDs = []byte("SiafundOutputIDs")
    25  	bucketSiafundOutputs   = []byte("SiafundOutputs")
    26  	bucketTransactionIDs   = []byte("TransactionIDs")
    27  	bucketUnlockHashes     = []byte("UnlockHashes")
    28  
    29  	errNotExist = errors.New("entry does not exist")
    30  
    31  	// keys for bucketInternal
    32  	internalBlockHeight  = []byte("BlockHeight")
    33  	internalRecentChange = []byte("RecentChange")
    34  )
    35  
    36  // These functions all return a 'func(*bolt.Tx) error', which, allows them to
    37  // be called concisely with the db.View and db.Update functions, e.g.:
    38  //
    39  //    var height types.BlockHeight
    40  //    db.View(dbGetAndDecode(bucketBlockIDs, id, &height))
    41  //
    42  // Instead of:
    43  //
    44  //   var height types.BlockHeight
    45  //   db.View(func(tx *bolt.Tx) error {
    46  //       bytes := tx.Bucket(bucketBlockIDs).Get(encoding.Marshal(id))
    47  //       return encoding.Unmarshal(bytes, &height)
    48  //   })
    49  
    50  // dbGetAndDecode returns a 'func(*bolt.Tx) error' that retrieves and decodes
    51  // a value from the specified bucket. If the value does not exist,
    52  // dbGetAndDecode returns errNotExist.
    53  func dbGetAndDecode(bucket []byte, key, val interface{}) func(*bolt.Tx) error {
    54  	return func(tx *bolt.Tx) error {
    55  		valBytes := tx.Bucket(bucket).Get(encoding.Marshal(key))
    56  		if valBytes == nil {
    57  			return errNotExist
    58  		}
    59  		return encoding.Unmarshal(valBytes, val)
    60  	}
    61  }
    62  
    63  // dbGetTransactionIDSet returns a 'func(*bolt.Tx) error' that decodes a
    64  // bucket of transaction IDs into a slice. If the bucket is nil,
    65  // dbGetTransactionIDSet returns errNotExist.
    66  func dbGetTransactionIDSet(bucket []byte, key interface{}, ids *[]types.TransactionID) func(*bolt.Tx) error {
    67  	return func(tx *bolt.Tx) error {
    68  		b := tx.Bucket(bucket).Bucket(encoding.Marshal(key))
    69  		if b == nil {
    70  			return errNotExist
    71  		}
    72  		// decode into a local slice
    73  		var txids []types.TransactionID
    74  		err := b.ForEach(func(txid, _ []byte) error {
    75  			var id types.TransactionID
    76  			err := encoding.Unmarshal(txid, &id)
    77  			if err != nil {
    78  				return err
    79  			}
    80  			txids = append(txids, id)
    81  			return nil
    82  		})
    83  		if err != nil {
    84  			return err
    85  		}
    86  		// set pointer
    87  		*ids = txids
    88  		return nil
    89  	}
    90  }
    91  
    92  // dbGetBlockFacts returns a 'func(*bolt.Tx) error' that decodes
    93  // the block facts for `height` into blockfacts
    94  func (e *Explorer) dbGetBlockFacts(height types.BlockHeight, bf *blockFacts) func(*bolt.Tx) error {
    95  	return func(tx *bolt.Tx) error {
    96  		block, exists := e.cs.BlockAtHeight(height)
    97  		if !exists {
    98  			return errors.New("requested block facts for a block that does not exist")
    99  		}
   100  		return dbGetAndDecode(bucketBlockFacts, block.ID(), bf)(tx)
   101  	}
   102  }
   103  
   104  // dbSetInternal sets the specified key of bucketInternal to the encoded value.
   105  func dbSetInternal(key []byte, val interface{}) func(*bolt.Tx) error {
   106  	return func(tx *bolt.Tx) error {
   107  		return tx.Bucket(bucketInternal).Put(key, encoding.Marshal(val))
   108  	}
   109  }
   110  
   111  // dbGetInternal decodes the specified key of bucketInternal into the supplied pointer.
   112  func dbGetInternal(key []byte, val interface{}) func(*bolt.Tx) error {
   113  	return func(tx *bolt.Tx) error {
   114  		return encoding.Unmarshal(tx.Bucket(bucketInternal).Get(key), val)
   115  	}
   116  }