2023-03-13 21:58:59 +00:00
|
|
|
package trie_builder_utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
)
|
|
|
|
|
2023-03-28 13:04:05 +00:00
|
|
|
// BuildAndReportKeySetWithBranchToDepth takes a depth argument and returns
|
|
|
|
// the first two slots that (when hashed into trie keys) intersect at or below the provided depth.
|
|
|
|
// It then hashes the slots and converts to nibbles before finding their intersection.
|
|
|
|
// It also returns the nibble and hex string representations of the two intersecting keys.
|
|
|
|
// This is useful for identifying what contract slots need to be occupied to cause branching in the storage trie
|
|
|
|
// at or below a provided height.
|
2023-03-13 21:58:59 +00:00
|
|
|
func BuildAndReportKeySetWithBranchToDepth(depth int) (string, string, []byte, []byte, string, string) {
|
|
|
|
slots, storageLeafKeys, storageLeafKeyStrs, key1, key2 := buildKeySetWithBranchToDepth(depth)
|
|
|
|
var slot1 string
|
|
|
|
var slot2 string
|
|
|
|
var key1Str string
|
|
|
|
var key2Str string
|
|
|
|
for i, storageLeafKey := range storageLeafKeys {
|
|
|
|
if bytes.Equal(storageLeafKey, key1) {
|
|
|
|
slot1 = slots[i]
|
|
|
|
key1Str = storageLeafKeyStrs[i]
|
|
|
|
}
|
|
|
|
if bytes.Equal(storageLeafKey, key2) {
|
|
|
|
slot2 = slots[i]
|
|
|
|
key2Str = storageLeafKeyStrs[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return slot1, slot2, key1, key2, key1Str, key2Str
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildKeySetWithBranchToDepth(depth int) ([]string, [][]byte, []string, []byte, []byte) {
|
|
|
|
slots := make([]string, 0)
|
|
|
|
storageLeafKeys := make([][]byte, 0)
|
|
|
|
storageLeafKeyStrs := make([]string, 0)
|
|
|
|
i := 0
|
|
|
|
j := 1
|
|
|
|
k := depth
|
|
|
|
if depth > 5 {
|
|
|
|
k = 10000
|
|
|
|
}
|
|
|
|
if depth > 7 {
|
|
|
|
k = 50000
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
slots = append(slots, common.BigToHash(big.NewInt(int64(i))).String())
|
|
|
|
storageLeafKeys = append(storageLeafKeys, LeafKeyToHexNibbles(crypto.Keccak256(common.BigToHash(big.NewInt(int64(i))).Bytes())))
|
|
|
|
storageLeafKeyStrs = append(storageLeafKeyStrs, crypto.Keccak256Hash(common.BigToHash(big.NewInt(int64(i))).Bytes()).String())
|
|
|
|
i++
|
|
|
|
if len(storageLeafKeys) > k*j {
|
|
|
|
j++
|
|
|
|
ok, key1, key2 := checkBranchDepthOfSet(storageLeafKeys, depth)
|
|
|
|
if ok {
|
|
|
|
return slots, storageLeafKeys, storageLeafKeyStrs, key1, key2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkBranchDepthOfSet(storageLeafKeys [][]byte, depth int) (bool, []byte, []byte) {
|
|
|
|
for i, key1 := range storageLeafKeys {
|
|
|
|
for j, key2 := range storageLeafKeys {
|
|
|
|
if i == j {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
var ok bool
|
|
|
|
var growingPrefix []byte
|
|
|
|
for _, by := range key1 {
|
|
|
|
ok, growingPrefix = containsPrefix(key2, growingPrefix, []byte{by})
|
|
|
|
if ok {
|
|
|
|
if len(growingPrefix) >= depth {
|
|
|
|
return true, key1, key2
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func containsPrefix(key, growingPrefix, potentialAddition []byte) (bool, []byte) {
|
|
|
|
if bytes.HasPrefix(key, append(growingPrefix, potentialAddition...)) {
|
|
|
|
return true, append(growingPrefix, potentialAddition...)
|
|
|
|
}
|
|
|
|
return false, growingPrefix
|
|
|
|
}
|
|
|
|
|
|
|
|
func LeafKeyToHexNibbles(compactLeafKey []byte) []byte {
|
|
|
|
if len(compactLeafKey) == 0 {
|
|
|
|
return compactLeafKey
|
|
|
|
}
|
|
|
|
return keybytesToHex(compactLeafKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
func keybytesToHex(str []byte) []byte {
|
|
|
|
l := len(str) * 2
|
|
|
|
var nibbles = make([]byte, l)
|
|
|
|
for i, b := range str {
|
|
|
|
nibbles[i*2] = b / 16
|
|
|
|
nibbles[i*2+1] = b % 16
|
|
|
|
}
|
|
|
|
return nibbles
|
|
|
|
}
|