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