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 }