2023-07-22 07:09:26 +00:00
|
|
|
package utils_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/cerc-io/plugeth-statediff/utils"
|
|
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
|
|
"github.com/ethereum/go-ethereum/trie"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
type kvs struct{ k, v string }
|
|
|
|
|
|
|
|
var (
|
|
|
|
testdata1 = []kvs{
|
|
|
|
{"barb", "ba"},
|
|
|
|
{"bard", "bc"},
|
|
|
|
{"bars", "bb"},
|
2023-08-01 14:50:59 +00:00
|
|
|
{"bar", "b"},
|
2023-07-22 07:09:26 +00:00
|
|
|
{"fab", "z"},
|
|
|
|
{"food", "ab"},
|
2023-08-01 14:50:59 +00:00
|
|
|
{"foo", "a"},
|
2023-07-22 07:09:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
testdata2 = []kvs{
|
|
|
|
{"aardvark", "c"},
|
|
|
|
{"bar", "b"},
|
|
|
|
{"barb", "bd"},
|
|
|
|
{"bars", "be"},
|
|
|
|
{"fab", "z"},
|
|
|
|
{"foo", "a"},
|
|
|
|
{"foos", "aa"},
|
|
|
|
{"jars", "d"},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSymmetricDifferenceIterator(t *testing.T) {
|
|
|
|
t.Run("with no difference", func(t *testing.T) {
|
|
|
|
db := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
2023-08-01 14:50:59 +00:00
|
|
|
triea := trie.NewEmpty(db)
|
|
|
|
di, count := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), triea.NodeIterator(nil))
|
2023-07-22 07:09:26 +00:00
|
|
|
for di.Next(true) {
|
|
|
|
t.Errorf("iterator should not yield any elements")
|
|
|
|
}
|
|
|
|
assert.Equal(t, 0, *count)
|
|
|
|
|
2023-08-01 14:50:59 +00:00
|
|
|
triea.MustUpdate([]byte("foo"), []byte("bar"))
|
|
|
|
di, count = utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), triea.NodeIterator(nil))
|
2023-07-22 07:09:26 +00:00
|
|
|
for di.Next(true) {
|
|
|
|
t.Errorf("iterator should not yield any elements")
|
|
|
|
}
|
2023-07-24 13:46:09 +00:00
|
|
|
assert.Equal(t, 4, *count)
|
2023-08-01 14:50:59 +00:00
|
|
|
|
2023-08-03 18:03:46 +00:00
|
|
|
// TODO will fail until fixed https://github.com/ethereum/go-ethereum/pull/27838
|
2023-08-01 14:50:59 +00:00
|
|
|
trieb := trie.NewEmpty(db)
|
|
|
|
di, count = utils.NewSymmetricDifferenceIterator(triea.NodeIterator([]byte("food")), trieb.NodeIterator(nil))
|
|
|
|
for di.Next(true) {
|
|
|
|
t.Errorf("iterator should not yield any elements")
|
|
|
|
t.Logf("%s", di.LeafKey())
|
|
|
|
}
|
|
|
|
assert.Equal(t, 0, *count)
|
2023-07-24 13:46:09 +00:00
|
|
|
})
|
|
|
|
|
2023-08-01 14:50:59 +00:00
|
|
|
t.Run("small difference", func(t *testing.T) {
|
2023-07-24 13:46:09 +00:00
|
|
|
dba := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
|
|
|
triea := trie.NewEmpty(dba)
|
|
|
|
|
|
|
|
dbb := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
|
|
|
trieb := trie.NewEmpty(dbb)
|
|
|
|
trieb.MustUpdate([]byte("foo"), []byte("bar"))
|
|
|
|
|
|
|
|
di, count := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
2023-08-01 14:50:59 +00:00
|
|
|
leaves := 0
|
2023-07-24 13:46:09 +00:00
|
|
|
for di.Next(true) {
|
|
|
|
if di.Leaf() {
|
|
|
|
assert.False(t, di.CommonPath())
|
2023-08-01 14:50:59 +00:00
|
|
|
assert.Equal(t, "foo", string(di.LeafKey()))
|
|
|
|
assert.Equal(t, "bar", string(di.LeafBlob()))
|
|
|
|
leaves++
|
2023-07-24 13:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-01 14:50:59 +00:00
|
|
|
assert.Equal(t, 1, leaves)
|
2023-07-24 13:46:09 +00:00
|
|
|
assert.Equal(t, 2, *count)
|
2023-08-01 14:50:59 +00:00
|
|
|
|
|
|
|
trieb.MustUpdate([]byte("quux"), []byte("bars"))
|
|
|
|
di, count = utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator([]byte("quux")))
|
|
|
|
leaves = 0
|
|
|
|
for di.Next(true) {
|
|
|
|
if di.Leaf() {
|
|
|
|
assert.False(t, di.CommonPath())
|
|
|
|
assert.Equal(t, "quux", string(di.LeafKey()))
|
|
|
|
assert.Equal(t, "bars", string(di.LeafBlob()))
|
|
|
|
leaves++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.Equal(t, 1, leaves)
|
|
|
|
assert.Equal(t, 1, *count)
|
2023-07-22 07:09:26 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
dba := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
|
|
|
triea := trie.NewEmpty(dba)
|
|
|
|
for _, val := range testdata1 {
|
|
|
|
triea.MustUpdate([]byte(val.k), []byte(val.v))
|
|
|
|
}
|
|
|
|
dbb := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
|
|
|
trieb := trie.NewEmpty(dbb)
|
|
|
|
for _, val := range testdata2 {
|
|
|
|
trieb.MustUpdate([]byte(val.k), []byte(val.v))
|
|
|
|
}
|
|
|
|
|
|
|
|
onlyA := make(map[string]string)
|
|
|
|
onlyB := make(map[string]string)
|
2023-07-24 13:46:09 +00:00
|
|
|
var deletions, creations []string
|
2023-07-22 07:09:26 +00:00
|
|
|
it, _ := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
|
|
|
for it.Next(true) {
|
|
|
|
if !it.Leaf() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
key, value := string(it.LeafKey()), string(it.LeafBlob())
|
|
|
|
if it.FromA() {
|
|
|
|
onlyA[key] = value
|
2023-07-24 13:46:09 +00:00
|
|
|
if !it.CommonPath() {
|
|
|
|
deletions = append(deletions, key)
|
|
|
|
}
|
2023-07-22 07:09:26 +00:00
|
|
|
} else {
|
|
|
|
onlyB[key] = value
|
2023-07-24 13:46:09 +00:00
|
|
|
if !it.CommonPath() {
|
|
|
|
creations = append(creations, key)
|
|
|
|
}
|
2023-07-22 07:09:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedOnlyA := map[string]string{
|
|
|
|
"barb": "ba",
|
|
|
|
"bard": "bc",
|
|
|
|
"bars": "bb",
|
|
|
|
"food": "ab",
|
|
|
|
}
|
|
|
|
expectedOnlyB := map[string]string{
|
|
|
|
"aardvark": "c",
|
|
|
|
"barb": "bd",
|
|
|
|
"bars": "be",
|
|
|
|
"foos": "aa",
|
|
|
|
"jars": "d",
|
|
|
|
}
|
2023-07-24 13:46:09 +00:00
|
|
|
expectedDeletions := []string{
|
|
|
|
"bard",
|
|
|
|
"food",
|
|
|
|
}
|
|
|
|
expectedCreations := []string{
|
|
|
|
"aardvark",
|
|
|
|
"foos",
|
|
|
|
"jars",
|
|
|
|
}
|
2023-07-22 07:09:26 +00:00
|
|
|
assert.Equal(t, expectedOnlyA, onlyA)
|
|
|
|
assert.Equal(t, expectedOnlyB, onlyB)
|
2023-07-24 13:46:09 +00:00
|
|
|
assert.Equal(t, expectedDeletions, deletions)
|
|
|
|
assert.Equal(t, expectedCreations, creations)
|
2023-07-22 07:09:26 +00:00
|
|
|
}
|