@@ -73,10 +73,10 @@ type DB interface {
7373 Snapshot () ReadonlyDB
7474}
7575
76- // A ReadonlyDB is a read-only, point-in-time view of a DB. Because it exposes
77- // no mutating methods, the underlying database cannot be modified through it.
76+ // A ReadonlyDB is a read-only, point-in-time view of a DB. It exposes
77+ // no mutating methods. The underlying database cannot be modified through it.
7878type ReadonlyDB interface {
79- Bucket (name []byte ) DBBucket
79+ Bucket (name []byte ) ReadonlyDBBucket
8080 // Close releases the resources held by the snapshot.
8181 Close () error
8282}
@@ -90,15 +90,21 @@ type noSnapshotDB struct {
9090 }
9191}
9292
93- func (s noSnapshotDB ) Bucket (name []byte ) DBBucket { return s .db .Bucket (name ) }
94- func (noSnapshotDB ) Close () error { return nil }
93+ func (s noSnapshotDB ) Bucket (name []byte ) ReadonlyDBBucket { return s .db .Bucket (name ) }
94+ func (noSnapshotDB ) Close () error { return nil }
95+
96+ // A ReadonlyDBBucket is a read-only view of a DBBucket; it exposes no mutating
97+ // methods, so a bucket obtained from a ReadonlyDB cannot be written to.
98+ type ReadonlyDBBucket interface {
99+ Get (key []byte ) []byte
100+ Iter () iter.Seq2 [[]byte , []byte ]
101+ }
95102
96103// A DBBucket is a set of key-value pairs.
97104type DBBucket interface {
98- Get ( key [] byte ) [] byte
105+ ReadonlyDBBucket
99106 Put (key , value []byte ) error
100107 Delete (key []byte ) error
101- Iter () iter.Seq2 [[]byte , []byte ]
102108}
103109
104110// MemDB implements DB with an in-memory map.
@@ -395,10 +401,17 @@ func check(err error) {
395401
396402// dbBucket is a helper type for implementing Store.
397403type dbBucket struct {
398- b DBBucket
404+ b ReadonlyDBBucket
399405 db * DBStore
400406}
401407
408+ // writable returns the bucket as a DBBucket for mutation. It is only reached
409+ // from write paths, which only run on a writable DBStore; such a store is
410+ // always backed by a full DB, so its buckets always implement DBBucket.
411+ func (b * dbBucket ) writable () DBBucket {
412+ return b .b .(DBBucket )
413+ }
414+
402415func (b * dbBucket ) getRaw (key []byte ) []byte {
403416 if b .b == nil {
404417 return nil
@@ -421,7 +434,7 @@ func (b *dbBucket) get(key []byte, v types.DecoderFrom) bool {
421434}
422435
423436func (b * dbBucket ) putRaw (key , value []byte ) {
424- check (b .b .Put (key , value ))
437+ check (b .writable () .Put (key , value ))
425438 b .db .unflushed += len (value )
426439}
427440
@@ -434,7 +447,7 @@ func (b *dbBucket) put(key []byte, v types.EncoderTo) {
434447}
435448
436449func (b * dbBucket ) delete (key []byte ) {
437- check (b .b .Delete (key ))
450+ check (b .writable () .Delete (key ))
438451 b .db .unflushed += len (key )
439452}
440453
@@ -456,11 +469,19 @@ var (
456469// snapshot can satisfy it (see roDB), letting a snapshot reuse DBStore's
457470// accessors without exposing any write methods.
458471type rwDB interface {
459- Bucket (name []byte ) DBBucket
472+ Bucket (name []byte ) ReadonlyDBBucket
460473 Flush () error
461474 Snapshot () ReadonlyDB
462475}
463476
477+ // rwView adapts a full DB to the rwDB interface, narrowing Bucket's return type
478+ // to ReadonlyDBBucket so that DBStore's shared read path cannot mutate through
479+ // it. Write paths recover the full DBBucket via dbBucket.writable, which is
480+ // sound because a writable DBStore is always backed by a full DB.
481+ type rwView struct { DB }
482+
483+ func (v rwView ) Bucket (name []byte ) ReadonlyDBBucket { return v .DB .Bucket (name ) }
484+
464485// DBStore implements Store using a key-value database.
465486type DBStore struct {
466487 db rwDB
@@ -1053,7 +1074,7 @@ func NewDBStore(db DB, n *consensus.Network, genesisBlock types.Block, logger Mi
10531074 }
10541075
10551076 dbs := & DBStore {
1056- db : db ,
1077+ db : rwView { db } ,
10571078 n : n ,
10581079 }
10591080
@@ -1129,7 +1150,7 @@ func NewDBStoreAtCheckpoint(db DB, cs consensus.State, b types.Block, logger Mig
11291150 }
11301151
11311152 dbs := & DBStore {
1132- db : db ,
1153+ db : rwView { db } ,
11331154 n : cs .Network ,
11341155 }
11351156
0 commit comments