github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/transactionpool/persist.go (about) 1 package transactionpool 2 3 import ( 4 "errors" 5 "os" 6 "path/filepath" 7 8 "github.com/NebulousLabs/Sia/modules" 9 "github.com/NebulousLabs/Sia/persist" 10 "github.com/NebulousLabs/Sia/types" 11 12 "github.com/NebulousLabs/bolt" 13 ) 14 15 var ( 16 // bucketRecentConsensusChange holds the most recent consensus change seen 17 // by the transaction pool. 18 bucketRecentConsensusChange = []byte("RecentConsensusChange") 19 20 // bucketConfirmedTransactions holds the ids of every transaction that has 21 // been confirmed on the blockchain. 22 bucketConfirmedTransactions = []byte("ConfirmedTransactions") 23 24 // errNilConsensusChange is returned if there is no consensus change in the 25 // database. 26 errNilConsensusChange = errors.New("no consensus change found") 27 28 // fieldRecentConsensusChange is the field in bucketRecentConsensusChange 29 // that holds the value of the most recent consensus change. 30 fieldRecentConsensusChange = []byte("RecentConsensusChange") 31 ) 32 33 // resetDB deletes all consensus related persistence from the transaction pool. 34 func (tp *TransactionPool) resetDB(tx *bolt.Tx) error { 35 err := tx.DeleteBucket(bucketConfirmedTransactions) 36 if err != nil { 37 return err 38 } 39 err = tp.putRecentConsensusChange(tx, modules.ConsensusChangeBeginning) 40 if err != nil { 41 return err 42 } 43 _, err = tx.CreateBucket(bucketConfirmedTransactions) 44 return err 45 } 46 47 // initPersist creates buckets in the database 48 func (tp *TransactionPool) initPersist() error { 49 // Create the persist directory if it does not yet exist. 50 err := os.MkdirAll(tp.persistDir, 0700) 51 if err != nil { 52 return err 53 } 54 55 // Open the database file. 56 tp.db, err = persist.OpenDatabase(dbMetadata, filepath.Join(tp.persistDir, dbFilename)) 57 if err != nil { 58 return err 59 } 60 61 // Create the database and get the most recent consensus change. 62 var cc modules.ConsensusChangeID 63 err = tp.db.Update(func(tx *bolt.Tx) error { 64 // Create the database buckets. 65 buckets := [][]byte{ 66 bucketRecentConsensusChange, 67 bucketConfirmedTransactions, 68 } 69 for _, bucket := range buckets { 70 _, err := tx.CreateBucketIfNotExists(bucket) 71 if err != nil { 72 return err 73 } 74 } 75 76 // Get the recent consensus change. 77 cc, err = tp.getRecentConsensusChange(tx) 78 if err == errNilConsensusChange { 79 return tp.putRecentConsensusChange(tx, modules.ConsensusChangeBeginning) 80 } 81 return err 82 }) 83 if err != nil { 84 return err 85 } 86 87 // Subscribe to the consensus set using the most recent consensus change. 88 err = tp.consensusSet.ConsensusSetSubscribe(tp, cc) 89 if err == modules.ErrInvalidConsensusChangeID { 90 // Reset and rescan because the consensus set does not recognize the 91 // provided consensus change id. 92 resetErr := tp.db.Update(func(tx *bolt.Tx) error { 93 return tp.resetDB(tx) 94 }) 95 if resetErr != nil { 96 return resetErr 97 } 98 return tp.consensusSet.ConsensusSetSubscribe(tp, modules.ConsensusChangeBeginning) 99 } 100 return err 101 } 102 103 // getRecentConsensusChange returns the most recent consensus change from the 104 // database. 105 func (tp *TransactionPool) getRecentConsensusChange(tx *bolt.Tx) (cc modules.ConsensusChangeID, err error) { 106 ccBytes := tx.Bucket(bucketRecentConsensusChange).Get(fieldRecentConsensusChange) 107 if ccBytes == nil { 108 return modules.ConsensusChangeID{}, errNilConsensusChange 109 } 110 copy(cc[:], ccBytes) 111 return cc, nil 112 } 113 114 // putRecentConsensusChange updates the most recent consensus change seen by 115 // the transaction pool. 116 func (tp *TransactionPool) putRecentConsensusChange(tx *bolt.Tx, cc modules.ConsensusChangeID) error { 117 return tx.Bucket(bucketRecentConsensusChange).Put(fieldRecentConsensusChange, cc[:]) 118 } 119 120 // transactionConfirmed returns true if the transaction has been confirmed on 121 // the blockchain and false if the transaction has not been confirmed on the 122 // blockchain. 123 func (tp *TransactionPool) transactionConfirmed(tx *bolt.Tx, id types.TransactionID) bool { 124 confirmedBytes := tx.Bucket(bucketConfirmedTransactions).Get(id[:]) 125 if confirmedBytes == nil { 126 return false 127 } 128 return true 129 } 130 131 // addTransaction adds a transaction to the list of confirmed transactions. 132 func (tp *TransactionPool) addTransaction(tx *bolt.Tx, id types.TransactionID) error { 133 return tx.Bucket(bucketConfirmedTransactions).Put(id[:], []byte{}) 134 } 135 136 // deleteTransaction deletes a transaction from the list of confirmed 137 // transactions. 138 func (tp *TransactionPool) deleteTransaction(tx *bolt.Tx, id types.TransactionID) error { 139 return tx.Bucket(bucketConfirmedTransactions).Delete(id[:]) 140 }