mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
395 lines
14 KiB
Go
395 lines
14 KiB
Go
// Copyright 2019 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty off
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Pruning of the Merkle Patricia trees
|
|
|
|
package trie
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type mockAccountEvicter struct {
|
|
keys [][]byte
|
|
}
|
|
|
|
func newMockAccountEvicter() *mockAccountEvicter {
|
|
return &mockAccountEvicter{make([][]byte, 0)}
|
|
}
|
|
|
|
func (m *mockAccountEvicter) EvictNode(key []byte) {
|
|
m.keys = append(m.keys, key)
|
|
}
|
|
|
|
func TestEvictionBasicOperations(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
key := []byte{0x01, 0x01, 0x01, 0x01}
|
|
hex := keybytesToHex(key)
|
|
eviction.CodeNodeCreated(hex, 1024)
|
|
|
|
assert.Equal(t, 1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 1024, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
// grow
|
|
eviction.CodeNodeSizeChanged(hex, 2048)
|
|
|
|
assert.Equal(t, 2048, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 2048, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
// shrink
|
|
eviction.CodeNodeSizeChanged(hex, 100)
|
|
|
|
assert.Equal(t, 100, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 100, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
// shrink
|
|
eviction.CodeNodeDeleted(hex)
|
|
|
|
assert.Equal(t, 0, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
}
|
|
|
|
func TestEvictionPartialSingleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 100kb or accounts
|
|
for i := 0; i < 100; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.BranchNodeCreated(keybytesToHex(key))
|
|
}
|
|
|
|
assert.Equal(t, 100, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 99)
|
|
|
|
assert.Equal(t, 0, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 0, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 2, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, len(mock.keys), "should evict all 100 accounts")
|
|
}
|
|
|
|
func TestEvictionFullSingleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 100kb or accounts
|
|
for i := 0; i < 100; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.BranchNodeCreated(keybytesToHex(key))
|
|
}
|
|
|
|
assert.Equal(t, 100, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 0)
|
|
|
|
assert.Equal(t, 0, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 0, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 2, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, len(mock.keys), "should evict all 100 accounts")
|
|
}
|
|
|
|
func TestEvictionNoNeedSingleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 100kb or accounts
|
|
for i := 0; i < 100; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.BranchNodeCreated(keybytesToHex(key))
|
|
}
|
|
|
|
assert.Equal(t, 100, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 100)
|
|
|
|
assert.Equal(t, 100, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
assert.Equal(t, 100, int(eviction.generations.blockNumToGeneration[1].totalSize), "should register size of gen")
|
|
|
|
assert.Equal(t, 0, len(mock.keys), "should evict all 100 accounts")
|
|
}
|
|
|
|
func TestEvictionNoNeedMultipleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(2)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x02, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(4)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x03, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(5)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x04, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(7)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x05, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
// 50 kb total
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 5, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
for _, i := range []uint64{1, 2, 4, 5, 7} {
|
|
assert.Equal(t, 10*1024, int(eviction.generations.blockNumToGeneration[i].totalSize), "should register size of gen")
|
|
}
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 50*1024)
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 5, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
|
|
assert.Equal(t, 0, len(mock.keys), "should not evict anything")
|
|
}
|
|
|
|
func TestEvictionPartialMultipleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(2)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x02, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(4)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x03, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(5)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x04, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(7)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x05, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
// 50 kb total
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 5, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
for _, i := range []uint64{1, 2, 4, 5, 7} {
|
|
assert.Equal(t, 10*1024, int(eviction.generations.blockNumToGeneration[i].totalSize), "should register size of gen")
|
|
}
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 20*1024)
|
|
|
|
assert.Equal(t, 20*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 2, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 5, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
for _, i := range []uint64{5, 7} {
|
|
assert.Equal(t, 10*1024, int(eviction.generations.blockNumToGeneration[i].totalSize), "should register size of gen")
|
|
}
|
|
assert.Equal(t, 30, len(mock.keys), "should evict only 3 generations")
|
|
}
|
|
|
|
func TestEvictionFullMultipleGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
eviction.SetBlockNumber(1)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(2)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x02, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(4)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x03, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(5)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x04, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(7)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x05, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
// 50 kb total
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 5, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 0, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
for _, i := range []uint64{1, 2, 4, 5, 7} {
|
|
assert.Equal(t, 10*1024, int(eviction.generations.blockNumToGeneration[i].totalSize), "should register size of gen")
|
|
}
|
|
|
|
mock := newMockAccountEvicter()
|
|
|
|
eviction.EvictToFitSize(mock, 0)
|
|
|
|
assert.Equal(t, 0, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 0, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 8, int(eviction.generations.oldestBlockNum), "should register block num")
|
|
|
|
assert.Equal(t, 50, len(mock.keys), "should evict only 3 generations")
|
|
|
|
}
|
|
|
|
func TestEvictionMoveBetweenGen(t *testing.T) {
|
|
eviction := NewEviction()
|
|
|
|
eviction.SetBlockNumber(2)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
key := []byte{0x01, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 10*1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(4)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 1; i++ {
|
|
key := []byte{0x04, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 20*1024)
|
|
}
|
|
|
|
eviction.SetBlockNumber(5)
|
|
|
|
// create 10kb or accounts
|
|
for i := 0; i < 10; i++ {
|
|
key := []byte{0x05, 0x01, 0x01, byte(i)}
|
|
eviction.CodeNodeCreated(keybytesToHex(key), 1024)
|
|
}
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 3, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
|
|
eviction.CodeNodeTouched(keybytesToHex([]byte{0x01, 0x01, 0x01, 0x00}))
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 3, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 1, len(eviction.generations.blockNumToGeneration[2].keys()), "should move one acc")
|
|
assert.Equal(t, 11, len(eviction.generations.blockNumToGeneration[5].keys()), "should move one acc to gen 5")
|
|
assert.Equal(t, CodeKeyFromAddrHash(keybytesToHex([]byte{0x01, 0x01, 0x01, 0x01})), []byte(eviction.generations.blockNumToGeneration[2].keys()[0]), "should move one acc")
|
|
|
|
// move the acc again to the new block!
|
|
eviction.SetBlockNumber(10)
|
|
eviction.CodeNodeTouched(keybytesToHex([]byte{0x01, 0x01, 0x01, 0x00}))
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 4, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
assert.Equal(t, 10, len(eviction.generations.blockNumToGeneration[5].keys()), "should move one acc from gen 5, again 10")
|
|
assert.Equal(t, CodeKeyFromAddrHash(keybytesToHex([]byte{0x01, 0x01, 0x01, 0x00})), []byte(eviction.generations.blockNumToGeneration[10].keys()[0]), "should move one acc")
|
|
|
|
// move the last acc from the gen
|
|
eviction.CodeNodeTouched(keybytesToHex([]byte{0x01, 0x01, 0x01, 0x01}))
|
|
|
|
assert.Equal(t, 50*1024, int(eviction.TotalSize()), "should register all accounts")
|
|
assert.Equal(t, 3, len(eviction.generations.blockNumToGeneration), "should register generation")
|
|
_, found := eviction.generations.blockNumToGeneration[2]
|
|
assert.False(t, found, "2nd generation is empty and should be removed")
|
|
|
|
assert.Equal(t, 2, len(eviction.generations.blockNumToGeneration[10].keys()), "should move one acc")
|
|
}
|