core/state/snapshot: node behavioural difference on bloom content

This commit is contained in:
Martin Holst Swende 2019-12-02 09:31:07 +01:00 committed by Péter Szilágyi
parent fd39f722a3
commit 3ad4335acc
No known key found for this signature in database
GPG Key ID: E9AE538CEDF8293D
2 changed files with 22 additions and 6 deletions

View File

@ -20,6 +20,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math" "math"
"math/rand"
"sort" "sort"
"sync" "sync"
"time" "time"
@ -63,8 +64,20 @@ var (
// bloom filter to keep its size to a minimum (given it's size and maximum // bloom filter to keep its size to a minimum (given it's size and maximum
// entry count). // entry count).
bloomFuncs = math.Round((bloomSize / float64(aggregatorItemLimit)) * math.Log(2)) bloomFuncs = math.Round((bloomSize / float64(aggregatorItemLimit)) * math.Log(2))
// bloomHashesOffset is a runtime constant which determines which part of the
// the account/storage hash the hasher functions looks at, to determine the
// bloom key for an account/slot. This is randomized at init(), so that the
// global population of nodes do not all display the exact same behaviour with
// regards to bloom content
bloomHasherOffset = 0
) )
func init() {
// Init bloomHasherOffset in the range [0:24] (requires 8 bytes)
bloomHasherOffset = rand.Intn(25)
}
// diffLayer represents a collection of modifications made to a state snapshot // diffLayer represents a collection of modifications made to a state snapshot
// after running a block on top. It contains one sorted list for the account trie // after running a block on top. It contains one sorted list for the account trie
// and one-one list for each storage tries. // and one-one list for each storage tries.
@ -100,7 +113,7 @@ func (h accountBloomHasher) Reset() { panic("not impl
func (h accountBloomHasher) BlockSize() int { panic("not implemented") } func (h accountBloomHasher) BlockSize() int { panic("not implemented") }
func (h accountBloomHasher) Size() int { return 8 } func (h accountBloomHasher) Size() int { return 8 }
func (h accountBloomHasher) Sum64() uint64 { func (h accountBloomHasher) Sum64() uint64 {
return binary.BigEndian.Uint64(h[:8]) return binary.BigEndian.Uint64(h[bloomHasherOffset : bloomHasherOffset+8])
} }
// storageBloomHasher is a wrapper around a [2]common.Hash to satisfy the interface // storageBloomHasher is a wrapper around a [2]common.Hash to satisfy the interface
@ -114,7 +127,8 @@ func (h storageBloomHasher) Reset() { panic("not impl
func (h storageBloomHasher) BlockSize() int { panic("not implemented") } func (h storageBloomHasher) BlockSize() int { panic("not implemented") }
func (h storageBloomHasher) Size() int { return 8 } func (h storageBloomHasher) Size() int { return 8 }
func (h storageBloomHasher) Sum64() uint64 { func (h storageBloomHasher) Sum64() uint64 {
return binary.BigEndian.Uint64(h[0][:8]) ^ binary.BigEndian.Uint64(h[1][:8]) return binary.BigEndian.Uint64(h[0][bloomHasherOffset:bloomHasherOffset+8]) ^
binary.BigEndian.Uint64(h[1][bloomHasherOffset:bloomHasherOffset+8])
} }
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low // newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
@ -205,7 +219,6 @@ func (dl *diffLayer) rebloom(origin *diskLayer) {
k := float64(dl.diffed.K()) k := float64(dl.diffed.K())
n := float64(dl.diffed.N()) n := float64(dl.diffed.N())
m := float64(dl.diffed.M()) m := float64(dl.diffed.M())
snapshotBloomErrorGauge.Update(math.Pow(1.0-math.Exp((-k)*(n+0.5)/(m-1)), k)) snapshotBloomErrorGauge.Update(math.Pow(1.0-math.Exp((-k)*(n+0.5)/(m-1)), k))
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -216,7 +217,7 @@ func BenchmarkSearch(b *testing.B) {
layer = fill(layer) layer = fill(layer)
} }
key := common.Hash{} key := crypto.Keccak256Hash([]byte{0x13, 0x38})
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
layer.AccountRLP(key) layer.AccountRLP(key)
@ -229,10 +230,12 @@ func BenchmarkSearch(b *testing.B) {
// BenchmarkSearchSlot-6 100000 14554 ns/op // BenchmarkSearchSlot-6 100000 14554 ns/op
// BenchmarkSearchSlot-6 100000 22254 ns/op (when checking parent root using mutex) // BenchmarkSearchSlot-6 100000 22254 ns/op (when checking parent root using mutex)
// BenchmarkSearchSlot-6 100000 14551 ns/op (when checking parent number using atomic) // BenchmarkSearchSlot-6 100000 14551 ns/op (when checking parent number using atomic)
// With bloom filter:
// BenchmarkSearchSlot-6 3467835 351 ns/op
func BenchmarkSearchSlot(b *testing.B) { func BenchmarkSearchSlot(b *testing.B) {
// First, we set up 128 diff layers, with 1K items each // First, we set up 128 diff layers, with 1K items each
accountKey := common.Hash{} accountKey := crypto.Keccak256Hash([]byte{0x13, 0x37})
storageKey := common.HexToHash("0x1337") storageKey := crypto.Keccak256Hash([]byte{0x13, 0x37})
accountRLP := randomAccount() accountRLP := randomAccount()
fill := func(parent snapshot) *diffLayer { fill := func(parent snapshot) *diffLayer {
accounts := make(map[common.Hash][]byte) accounts := make(map[common.Hash][]byte)