Skip to content

Commit

Permalink
Merge pull request #405 from CosmWasm/404_tm-db
Browse files Browse the repository at this point in the history
Remove tendermint-db dependency
  • Loading branch information
webmaster128 authored Mar 8, 2023
2 parents 30a4edc + b54ad58 commit cd6e131
Show file tree
Hide file tree
Showing 12 changed files with 455 additions and 220 deletions.
21 changes: 3 additions & 18 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,14 @@ module github.com/CosmWasm/wasmvm
go 1.18

require (
github.com/google/btree v1.0.0
github.com/stretchr/testify v1.8.1
github.com/tendermint/tm-db v0.6.7
)

require (
github.com/DataDog/zstd v1.4.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
173 changes: 0 additions & 173 deletions go.sum

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions internal/api/callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ import (
"runtime/debug"
"unsafe"

dbm "github.com/tendermint/tm-db"

"github.com/CosmWasm/wasmvm/types"
)

Expand Down Expand Up @@ -140,7 +138,7 @@ const frameLenLimit = 32768

// contract: original pointer/struct referenced must live longer than C.Db struct
// since this is only used internally, we can verify the code that this is the case
func buildIterator(callID uint64, it dbm.Iterator) (C.iterator_t, error) {
func buildIterator(callID uint64, it types.Iterator) (C.iterator_t, error) {
idx, err := storeIterator(callID, it, frameLenLimit)
if err != nil {
return C.iterator_t{}, err
Expand Down Expand Up @@ -246,7 +244,7 @@ func cScan(ptr *C.db_t, gasMeter *C.gas_meter_t, usedGas *cu64, start C.U8SliceV
s := copyU8Slice(start)
e := copyU8Slice(end)

var iter dbm.Iterator
var iter types.Iterator
gasBefore := gm.GasConsumed()
switch order {
case 1: // Ascending
Expand Down
8 changes: 4 additions & 4 deletions internal/api/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"fmt"
"sync"

dbm "github.com/tendermint/tm-db"
"github.com/CosmWasm/wasmvm/types"
)

// frame stores all Iterators for one contract call
type frame []dbm.Iterator
type frame []types.Iterator

// iteratorFrames contains one frame for each contract call, indexed by contract call ID.
var (
Expand Down Expand Up @@ -56,7 +56,7 @@ func endCall(callID uint64) {
// storeIterator will add this to the end of the frame for the given ID and return a reference to it.
// We start counting with 1, so the 0 value is flagged as an error. This means we must
// remember to do idx-1 when retrieving
func storeIterator(callID uint64, it dbm.Iterator, frameLenLimit int) (uint64, error) {
func storeIterator(callID uint64, it types.Iterator, frameLenLimit int) (uint64, error) {
iteratorFramesMutex.Lock()
defer iteratorFramesMutex.Unlock()

Expand All @@ -75,7 +75,7 @@ func storeIterator(callID uint64, it dbm.Iterator, frameLenLimit int) (uint64, e
// retrieveIterator will recover an iterator based on index. This ensures it will not be garbage collected.
// We start counting with 1, in storeIterator so the 0 value is flagged as an error. This means we must
// remember to do idx-1 when retrieving
func retrieveIterator(callID uint64, index uint64) dbm.Iterator {
func retrieveIterator(callID uint64, index uint64) types.Iterator {
iteratorFramesMutex.Lock()
defer iteratorFramesMutex.Unlock()
myFrame := iteratorFrames[callID]
Expand Down
15 changes: 7 additions & 8 deletions internal/api/iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

dbm "github.com/tendermint/tm-db"

"github.com/CosmWasm/wasmvm/internal/api/testdb"
"github.com/CosmWasm/wasmvm/types"
)

Expand Down Expand Up @@ -68,8 +67,8 @@ func TestStoreIterator(t *testing.T) {
callID1 := startCall()
callID2 := startCall()

store := dbm.NewMemDB()
var iter dbm.Iterator
store := testdb.NewMemDB()
var iter types.Iterator
var index uint64
var err error

Expand Down Expand Up @@ -102,8 +101,8 @@ func TestStoreIterator(t *testing.T) {
func TestStoreIteratorHitsLimit(t *testing.T) {
callID := startCall()

store := dbm.NewMemDB()
var iter dbm.Iterator
store := testdb.NewMemDB()
var iter types.Iterator
var err error
const limit = 2

Expand All @@ -127,8 +126,8 @@ func TestRetrieveIterator(t *testing.T) {
callID1 := startCall()
callID2 := startCall()

store := dbm.NewMemDB()
var iter dbm.Iterator
store := testdb.NewMemDB()
var iter types.Iterator
var err error

iter, _ = store.Iterator(nil, nil)
Expand Down
2 changes: 1 addition & 1 deletion internal/api/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestInitAndReleaseCache(t *testing.T) {
ReleaseCache(cache)
}

// wasmd expectes us to create the base directory
// wasmd expects us to create the base directory
// https://github.com/CosmWasm/wasmd/blob/v0.30.0/x/wasm/keeper/keeper.go#L128
func TestInitCacheWorksForNonExistentDir(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "wasmvm-testing")
Expand Down
10 changes: 5 additions & 5 deletions internal/api/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"

"github.com/CosmWasm/wasmvm/internal/api/testdb"
"github.com/CosmWasm/wasmvm/types"
)

Expand Down Expand Up @@ -255,13 +255,13 @@ const (
)

type Lookup struct {
db *dbm.MemDB
db *testdb.MemDB
meter MockGasMeter
}

func NewLookup(meter MockGasMeter) *Lookup {
return &Lookup{
db: dbm.NewMemDB(),
db: testdb.NewMemDB(),
meter: meter,
}
}
Expand Down Expand Up @@ -305,7 +305,7 @@ func (l Lookup) Delete(key []byte) {
}

// Iterator wraps the underlying DB's Iterator method panicing on error.
func (l Lookup) Iterator(start, end []byte) dbm.Iterator {
func (l Lookup) Iterator(start, end []byte) types.Iterator {
l.meter.ConsumeGas(RangePrice, "range")
iter, err := l.db.Iterator(start, end)
if err != nil {
Expand All @@ -316,7 +316,7 @@ func (l Lookup) Iterator(start, end []byte) dbm.Iterator {
}

// ReverseIterator wraps the underlying DB's ReverseIterator method panicing on error.
func (l Lookup) ReverseIterator(start, end []byte) dbm.Iterator {
func (l Lookup) ReverseIterator(start, end []byte) types.Iterator {
l.meter.ConsumeGas(RangePrice, "range")
iter, err := l.db.ReverseIterator(start, end)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions internal/api/testdb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Testdb
This package contains an in memory DB for testing purpose only. The original code was copied from
https://github.com/tendermint/tm-db/tree/v0.6.7 to decouple project dependencies.

All credits and a big thank you go to the original authors!
195 changes: 195 additions & 0 deletions internal/api/testdb/memdb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package testdb

import (
"bytes"
"fmt"
"sync"

"github.com/google/btree"
)

const (
// The approximate number of items and children per B-tree node. Tuned with benchmarks.
bTreeDegree = 32
)

// item is a btree.Item with byte slices as keys and values
type item struct {
key []byte
value []byte
}

// Less implements btree.Item.
func (i *item) Less(other btree.Item) bool {
// this considers nil == []byte{}, but that's ok since we handle nil endpoints
// in iterators specially anyway
return bytes.Compare(i.key, other.(*item).key) == -1
}

// newKey creates a new key item.
func newKey(key []byte) *item {
return &item{key: key}
}

// newPair creates a new pair item.
func newPair(key, value []byte) *item {
return &item{key: key, value: value}
}

// MemDB is an in-memory database backend using a B-tree for storage.
//
// For performance reasons, all given and returned keys and values are pointers to the in-memory
// database, so modifying them will cause the stored values to be modified as well. All DB methods
// already specify that keys and values should be considered read-only, but this is especially
// important with MemDB.
type MemDB struct {
mtx sync.RWMutex
btree *btree.BTree
}

// NewMemDB creates a new in-memory database.
func NewMemDB() *MemDB {
database := &MemDB{
btree: btree.New(bTreeDegree),
}
return database
}

// Get implements DB.
func (db *MemDB) Get(key []byte) ([]byte, error) {
if len(key) == 0 {
return nil, errKeyEmpty
}
db.mtx.RLock()
defer db.mtx.RUnlock()

i := db.btree.Get(newKey(key))
if i != nil {
return i.(*item).value, nil
}
return nil, nil
}

// Has implements DB.
func (db *MemDB) Has(key []byte) (bool, error) {
if len(key) == 0 {
return false, errKeyEmpty
}
db.mtx.RLock()
defer db.mtx.RUnlock()

return db.btree.Has(newKey(key)), nil
}

// Set implements DB.
func (db *MemDB) Set(key []byte, value []byte) error {
if len(key) == 0 {
return errKeyEmpty
}
if value == nil {
return errValueNil
}
db.mtx.Lock()
defer db.mtx.Unlock()

db.set(key, value)
return nil
}

// set sets a value without locking the mutex.
func (db *MemDB) set(key []byte, value []byte) {
db.btree.ReplaceOrInsert(newPair(key, value))
}

// SetSync implements DB.
func (db *MemDB) SetSync(key []byte, value []byte) error {
return db.Set(key, value)
}

// Delete implements DB.
func (db *MemDB) Delete(key []byte) error {
if len(key) == 0 {
return errKeyEmpty
}
db.mtx.Lock()
defer db.mtx.Unlock()

db.delete(key)
return nil
}

// delete deletes a key without locking the mutex.
func (db *MemDB) delete(key []byte) {
db.btree.Delete(newKey(key))
}

// DeleteSync implements DB.
func (db *MemDB) DeleteSync(key []byte) error {
return db.Delete(key)
}

// Close implements DB.
func (db *MemDB) Close() error {
// Close is a noop since for an in-memory database, we don't have a destination to flush
// contents to nor do we want any data loss on invoking Close().
// See the discussion in https://github.com/tendermint/tendermint/libs/pull/56
return nil
}

// Print implements DB.
func (db *MemDB) Print() error {
db.mtx.RLock()
defer db.mtx.RUnlock()

db.btree.Ascend(func(i btree.Item) bool {
item := i.(*item)
fmt.Printf("[%X]:\t[%X]\n", item.key, item.value)
return true
})
return nil
}

// Stats implements DB.
func (db *MemDB) Stats() map[string]string {
db.mtx.RLock()
defer db.mtx.RUnlock()

stats := make(map[string]string)
stats["database.type"] = "memDB"
stats["database.size"] = fmt.Sprintf("%d", db.btree.Len())
return stats
}

// Iterator implements DB.
// Takes out a read-lock on the database until the iterator is closed.
func (db *MemDB) Iterator(start, end []byte) (Iterator, error) {
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
return nil, errKeyEmpty
}
return newMemDBIterator(db, start, end, false), nil
}

// ReverseIterator implements DB.
// Takes out a read-lock on the database until the iterator is closed.
func (db *MemDB) ReverseIterator(start, end []byte) (Iterator, error) {
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
return nil, errKeyEmpty
}
return newMemDBIterator(db, start, end, true), nil
}

// IteratorNoMtx makes an iterator with no mutex.
func (db *MemDB) IteratorNoMtx(start, end []byte) (Iterator, error) {
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
return nil, errKeyEmpty
}
return newMemDBIteratorMtxChoice(db, start, end, false, false), nil
}

// ReverseIteratorNoMtx makes an iterator with no mutex.
func (db *MemDB) ReverseIteratorNoMtx(start, end []byte) (Iterator, error) {
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
return nil, errKeyEmpty
}
return newMemDBIteratorMtxChoice(db, start, end, true, false), nil
}
Loading

0 comments on commit cd6e131

Please sign in to comment.