github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/slasherkv/kv.go (about) 1 // Package slasherkv defines a bolt-db, key-value store implementation 2 // of the slasher database interface for Prysm. 3 package slasherkv 4 5 import ( 6 "context" 7 "os" 8 "path" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/prysmaticlabs/prysm/beacon-chain/db/iface" 13 "github.com/prysmaticlabs/prysm/shared/fileutil" 14 "github.com/prysmaticlabs/prysm/shared/params" 15 bolt "go.etcd.io/bbolt" 16 ) 17 18 var _ iface.SlasherDatabase = (*Store)(nil) 19 20 const ( 21 // DatabaseFileName is the name of the beacon node database. 22 DatabaseFileName = "slasher.db" 23 boltAllocSize = 8 * 1024 * 1024 24 ) 25 26 // Config for the bolt db kv store. 27 type Config struct { 28 InitialMMapSize int 29 } 30 31 // Store defines an implementation of the Prysm Database interface 32 // using BoltDB as the underlying persistent kv-store for Ethereum consensus. 33 type Store struct { 34 db *bolt.DB 35 databasePath string 36 ctx context.Context 37 } 38 39 // NewKVStore initializes a new boltDB key-value store at the directory 40 // path specified, creates the kv-buckets based on the schema, and stores 41 // an open connection db object as a property of the Store struct. 42 func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, error) { 43 hasDir, err := fileutil.HasDir(dirPath) 44 if err != nil { 45 return nil, err 46 } 47 if !hasDir { 48 if err := fileutil.MkdirAll(dirPath); err != nil { 49 return nil, err 50 } 51 } 52 datafile := path.Join(dirPath, DatabaseFileName) 53 boltDB, err := bolt.Open( 54 datafile, 55 params.BeaconIoConfig().ReadWritePermissions, 56 &bolt.Options{ 57 Timeout: 1 * time.Second, 58 InitialMmapSize: config.InitialMMapSize, 59 }, 60 ) 61 if err != nil { 62 if errors.Is(err, bolt.ErrTimeout) { 63 return nil, errors.New("cannot obtain database lock, database may be in use by another process") 64 } 65 return nil, err 66 } 67 boltDB.AllocSize = boltAllocSize 68 kv := &Store{ 69 db: boltDB, 70 databasePath: dirPath, 71 ctx: ctx, 72 } 73 74 if err := kv.db.Update(func(tx *bolt.Tx) error { 75 return createBuckets( 76 tx, 77 // Slasher buckets. 78 attestedEpochsByValidator, 79 attestationRecordsBucket, 80 attestationDataRootsBucket, 81 proposalRecordsBucket, 82 slasherChunksBucket, 83 ) 84 }); err != nil { 85 return nil, err 86 } 87 88 return kv, err 89 } 90 91 // ClearDB removes the previously stored database in the data directory. 92 func (s *Store) ClearDB() error { 93 if _, err := os.Stat(s.databasePath); os.IsNotExist(err) { 94 return nil 95 } 96 if err := os.Remove(path.Join(s.databasePath, DatabaseFileName)); err != nil { 97 return errors.Wrap(err, "could not remove database file") 98 } 99 return nil 100 } 101 102 // Close closes the underlying BoltDB database. 103 func (s *Store) Close() error { 104 return s.db.Close() 105 } 106 107 // DatabasePath at which this database writes files. 108 func (s *Store) DatabasePath() string { 109 return s.databasePath 110 } 111 112 func createBuckets(tx *bolt.Tx, buckets ...[]byte) error { 113 for _, bucket := range buckets { 114 if _, err := tx.CreateBucketIfNotExists(bucket); err != nil { 115 return err 116 } 117 } 118 return nil 119 }