Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions muxdb/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ func (c *cache) log() {

// AddNodeBlob adds encoded node blob into the cache.
func (c *cache) AddNodeBlob(keyBuf *[]byte, name string, path []byte, ver trie.Version, blob []byte, isCommitting bool) {
// skip root node cache, since root node is already cached in root node cache
if len(path) == 0 {
return
}
// the version part
v := binary.AppendUvarint((*keyBuf)[:0], uint64(ver.Major))
v = binary.AppendUvarint(v, uint64(ver.Minor))
Expand All @@ -102,6 +106,10 @@ func (c *cache) AddNodeBlob(keyBuf *[]byte, name string, path []byte, ver trie.V

// GetNodeBlob returns the cached node blob.
func (c *cache) GetNodeBlob(keyBuf *[]byte, name string, path []byte, ver trie.Version, peek bool) []byte {
// skip root node cache, since root node is already cached in root node cache
if len(path) == 0 {
return nil
}
// the version part
v := binary.AppendUvarint((*keyBuf)[:0], uint64(ver.Major))
v = binary.AppendUvarint(v, uint64(ver.Minor))
Expand Down
8 changes: 4 additions & 4 deletions muxdb/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ func TestCacheNodeBlob(t *testing.T) {
)

// add to committing cache
cache.AddNodeBlob(&keyBuf, "", nil, ver, blob, true)
assert.Equal(t, blob, cache.GetNodeBlob(&keyBuf, "", nil, ver, false))
cache.AddNodeBlob(&keyBuf, "", []byte{0x0a}, ver, blob, true)
assert.Equal(t, blob, cache.GetNodeBlob(&keyBuf, "", []byte{0x0a}, ver, false))
// minor ver not matched
assert.Nil(t, cache.GetNodeBlob(&keyBuf, "", nil, trie.Version{Major: 1}, false))

cache = newCache(1, 0)

// add to querying cache
cache.AddNodeBlob(&keyBuf, "", nil, ver, blob, false)
assert.Equal(t, blob, cache.GetNodeBlob(&keyBuf, "", nil, ver, false))
cache.AddNodeBlob(&keyBuf, "", []byte{0x0b}, ver, blob, false)
assert.Equal(t, blob, cache.GetNodeBlob(&keyBuf, "", []byte{0x0b}, ver, false))
// minor ver not matched
assert.Nil(t, cache.GetNodeBlob(&keyBuf, "", nil, trie.Version{Major: 1}, false))
}
Expand Down
7 changes: 7 additions & 0 deletions muxdb/trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package muxdb

import (
"context"
"errors"

"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/trie"
Expand Down Expand Up @@ -73,6 +74,12 @@ func (t *Trie) newDatabaseReader() trie.DatabaseReader {
return
}

// enforce root node to be only fetched from hist space
// to prevent accessing root node of a revision that has been pruned
if len(path) == 0 {
return nil, errors.New("not found")
}

// then from deduped space
keyBuf = t.back.AppendDedupedNodeKey(keyBuf[:0], t.name, path, ver)
return snapshot.Get(keyBuf)
Expand Down
79 changes: 79 additions & 0 deletions muxdb/trie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ package muxdb
import (
"context"
"encoding/binary"
"strconv"
"testing"

"github.com/stretchr/testify/assert"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"

"github.com/vechain/thor/v2/kv"
"github.com/vechain/thor/v2/muxdb/engine"
"github.com/vechain/thor/v2/trie"
)
Expand Down Expand Up @@ -242,3 +244,80 @@ func TestContextChecker(t *testing.T) {
}
t.Error("Expected context canceled error")
}

func TestGetAfterPrune(t *testing.T) {
var (
name = "prune-test"
back = newTestBackend()
)

db, _ := leveldb.Open(storage.NewMemStorage(), nil)
engine := engine.NewLevelEngine(db)

engine.DeleteRange(context.Background(), kv.Range{
Start: []byte{trieHistSpace},
Limit: []byte{trieHistSpace + 1},
})

mux := &MuxDB{
engine: engine,
trieBackend: back,
done: make(chan struct{}),
}

key := []byte("key")
root := trie.Root{}
root2 := trie.Root{}
root3 := trie.Root{}
for i := range uint32(5) {
tr := newTrie(name, back, root)

value := []byte("checkpoint-" + strconv.Itoa(int(i)))

err := tr.Update(key, value, nil)
assert.Nil(t, err)

ver := trie.Version{Major: i + 1}
err = tr.Commit(ver, false)
assert.Nil(t, err)
root = trie.Root{
Hash: tr.Hash(),
Ver: ver,
}

if i == 2 {
root2 = root
}
if i == 3 {
root3 = root
}
}

tr := newTrie(name, back, root3)
value, _, err := tr.Get(key)
assert.Nil(t, err)
assert.Equal(t, "checkpoint-3", string(value))

// checkpoint(squash) for [0,3], keep 4 in the hist space
tr.Checkpoint(context.Background(), 0, nil)

tr = newTrie(name, back, root2)
value, _, err = tr.Get(key)
assert.Nil(t, err)
assert.Equal(t, "checkpoint-2", string(value))

// delete [0,4) in hist space
err = mux.DeleteTrieHistoryNodes(context.Background(), 0, 4)
assert.Nil(t, err)

// version 4 can be still read
tr = newTrie(name, back, root3)
value, _, err = tr.Get(key)
assert.Nil(t, err)
assert.Equal(t, "checkpoint-3", string(value))

// version 2 can not be read
tr = newTrie(name, back, root2)
_, _, err = tr.Get(key)
assert.Contains(t, err.Error(), "missing trie node")
}
Loading