github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/explorer/database.go (about) 1 package explorer 2 3 import ( 4 "errors" 5 6 "github.com/NebulousLabs/Sia/encoding" 7 "github.com/NebulousLabs/Sia/types" 8 9 "github.com/NebulousLabs/bolt" 10 ) 11 12 var ( 13 errNotExist = errors.New("entry does not exist") 14 15 // database buckets 16 bucketBlockFacts = []byte("BlockFacts") 17 bucketBlockIDs = []byte("BlockIDs") 18 bucketBlocksDifficulty = []byte("BlocksDifficulty") 19 bucketBlockTargets = []byte("BlockTargets") 20 bucketFileContractHistories = []byte("FileContractHistories") 21 bucketFileContractIDs = []byte("FileContractIDs") 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 // bucketInternal is used to store values internal to the explorer 30 bucketInternal = []byte("Internal") 31 32 // keys for bucketInternal 33 internalBlockHeight = []byte("BlockHeight") 34 internalRecentChange = []byte("RecentChange") 35 ) 36 37 // These functions all return a 'func(*bolt.Tx) error', which, allows them to 38 // be called concisely with the db.View and db.Update functions, e.g.: 39 // 40 // var height types.BlockHeight 41 // db.View(dbGetAndDecode(bucketBlockIDs, id, &height)) 42 // 43 // Instead of: 44 // 45 // var height types.BlockHeight 46 // db.View(func(tx *bolt.Tx) error { 47 // bytes := tx.Bucket(bucketBlockIDs).Get(encoding.Marshal(id)) 48 // return encoding.Unmarshal(bytes, &height) 49 // }) 50 51 // dbGetAndDecode returns a 'func(*bolt.Tx) error' that retrieves and decodes 52 // a value from the specified bucket. If the value does not exist, 53 // dbGetAndDecode returns errNotExist. 54 func dbGetAndDecode(bucket []byte, key, val interface{}) func(*bolt.Tx) error { 55 return func(tx *bolt.Tx) error { 56 valBytes := tx.Bucket(bucket).Get(encoding.Marshal(key)) 57 if valBytes == nil { 58 return errNotExist 59 } 60 return encoding.Unmarshal(valBytes, val) 61 } 62 } 63 64 // dbGetTransactionIDSet returns a 'func(*bolt.Tx) error' that decodes a 65 // bucket of transaction IDs into a slice. If the bucket is nil, 66 // dbGetTransactionIDSet returns errNotExist. 67 func dbGetTransactionIDSet(bucket []byte, key interface{}, ids *[]types.TransactionID) func(*bolt.Tx) error { 68 return func(tx *bolt.Tx) error { 69 b := tx.Bucket(bucket).Bucket(encoding.Marshal(key)) 70 if b == nil { 71 return errNotExist 72 } 73 // decode into a local slice 74 var txids []types.TransactionID 75 err := b.ForEach(func(txid, _ []byte) error { 76 var id types.TransactionID 77 err := encoding.Unmarshal(txid, &id) 78 if err != nil { 79 return err 80 } 81 txids = append(txids, id) 82 return nil 83 }) 84 if err != nil { 85 return err 86 } 87 // set pointer 88 *ids = txids 89 return nil 90 } 91 } 92 93 // dbSetInternal sets the specified key of bucketInternal to the encoded value. 94 func dbSetInternal(key []byte, val interface{}) func(*bolt.Tx) error { 95 return func(tx *bolt.Tx) error { 96 return tx.Bucket(bucketInternal).Put(key, encoding.Marshal(val)) 97 } 98 } 99 100 // dbGetInternal decodes the specified key of bucketInternal into the supplied pointer. 101 func dbGetInternal(key []byte, val interface{}) func(*bolt.Tx) error { 102 return func(tx *bolt.Tx) error { 103 return encoding.Unmarshal(tx.Bucket(bucketInternal).Get(key), val) 104 } 105 }