2019-11-15 16:50:16 +00:00
// 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/>.
package trie
2019-12-09 14:59:30 +00:00
import (
2019-12-12 17:17:13 +00:00
"fmt"
2020-05-26 16:53:50 +00:00
"github.com/holiman/uint256"
2019-12-09 14:59:30 +00:00
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/turbo/rlphacks"
2019-12-09 14:59:30 +00:00
)
2019-11-15 16:50:16 +00:00
// Experimental code for separating data and structural information
// Each function corresponds to an opcode
// DESCRIBED: docs/programmers_guide/guide.md#separation-of-keys-and-the-structure
type structInfoReceiver interface {
2020-01-15 13:56:50 +00:00
leaf ( length int , keyHex [ ] byte , val rlphacks . RlpSerializable ) error
leafHash ( length int , keyHex [ ] byte , val rlphacks . RlpSerializable ) error
2020-07-07 11:24:55 +00:00
accountLeaf ( length int , keyHex [ ] byte , balance * uint256 . Int , nonce uint64 , incarnation uint64 , fieldset uint32 , codeSize int ) error
2020-05-26 16:53:50 +00:00
accountLeafHash ( length int , keyHex [ ] byte , balance * uint256 . Int , nonce uint64 , incarnation uint64 , fieldset uint32 ) error
2019-11-15 16:50:16 +00:00
extension ( key [ ] byte ) error
extensionHash ( key [ ] byte ) error
branch ( set uint16 ) error
branchHash ( set uint16 ) error
2020-07-05 06:17:27 +00:00
hash ( hash [ ] byte ) error
2020-05-31 12:23:34 +00:00
topHash ( ) [ ] byte
2021-02-21 18:41:59 +00:00
topHashes ( prefix [ ] byte , branches , children uint16 ) [ ] byte
printTopHashes ( prefix [ ] byte , branches , children uint16 )
2019-11-15 16:50:16 +00:00
}
2020-05-31 12:23:34 +00:00
// hashCollector gets called whenever there might be a need to create intermediate hash record
2020-07-02 10:55:35 +00:00
type HashCollector func ( keyHex [ ] byte , hash [ ] byte ) error
2021-02-21 18:41:59 +00:00
type StorageHashCollector func ( accWithInc [ ] byte , keyHex [ ] byte , hash [ ] byte ) error
2021-03-13 02:30:54 +00:00
type HashCollector2 func ( keyHex [ ] byte , hasState , hasTree , hasHash uint16 , hashes , rootHash [ ] byte ) error
type StorageHashCollector2 func ( accWithInc [ ] byte , keyHex [ ] byte , hasState , hasTree , hasHash uint16 , hashes , rootHash [ ] byte ) error
2020-05-31 12:23:34 +00:00
2019-12-12 17:17:13 +00:00
func calcPrecLen ( groups [ ] uint16 ) int {
if len ( groups ) == 0 {
return 0
}
return len ( groups ) - 1
}
type GenStructStepData interface {
GenStructStepData ( )
}
type GenStructStepAccountData struct {
FieldSet uint32
2020-05-26 16:53:50 +00:00
Balance uint256 . Int
2019-12-12 17:17:13 +00:00
Nonce uint64
2020-01-15 14:12:33 +00:00
Incarnation uint64
2019-12-12 17:17:13 +00:00
}
func ( GenStructStepAccountData ) GenStructStepData ( ) { }
type GenStructStepLeafData struct {
2020-01-15 13:56:50 +00:00
Value rlphacks . RlpSerializable
2019-12-12 17:17:13 +00:00
}
func ( GenStructStepLeafData ) GenStructStepData ( ) { }
type GenStructStepHashData struct {
2021-03-13 02:30:54 +00:00
Hash common . Hash
HasTree bool
2019-12-12 17:17:13 +00:00
}
func ( GenStructStepHashData ) GenStructStepData ( ) { }
2019-11-15 16:50:16 +00:00
// GenStructStep is one step of the algorithm that generates the structural information based on the sequence of keys.
2020-05-12 14:24:43 +00:00
// `retain` parameter is the function that, called for a certain prefix, determines whether the trie node for that prefix needs to be
// compressed into just hash (if `false` is returned), or constructed (if `true` is returned). Usually the `retain` function is
// implemented in such a way to guarantee that certain keys are always accessible in the resulting trie (see RetainList.Retain function).
2019-12-12 17:17:13 +00:00
// `buildExtensions` is set to true if the algorithm's step is invoked recursively, i.e. not after a freshly provided leaf or hash
2019-11-15 22:48:49 +00:00
// `curr`, `succ` are two full keys or prefixes that are currently visible to the algorithm. By comparing these, the algorithm
2021-03-29 03:58:45 +00:00
// makes decisions about the local structure, i.e. the presence of the prefix groups.
2019-11-15 16:50:16 +00:00
// `e` parameter is the trie builder, which uses the structure information to assemble trie on the stack and compute its hash.
2020-05-31 12:23:34 +00:00
// `h` parameter is the hash collector, which is notified whenever branch node is constructed.
2019-12-12 17:17:13 +00:00
// `data` parameter specified if a hash or a binary string or an account should be emitted.
2021-03-13 02:30:54 +00:00
// `groups` parameter is the map of the stack. each element of the `groups` slice is a bitmask, one bit per element currently on the stack. Meaning - which children of given prefix have dbutils.HashedAccount records
// `hasTree` same as `groups`, but meaning - which children of given prefix have dbutils.TrieOfAccountsBucket record
// `hasHash` same as `groups`, but meaning - which children of given prefix are branch nodes and their hashes can be saved and used on next trie resolution.
2019-11-15 16:50:16 +00:00
// Whenever a `BRANCH` or `BRANCHHASH` opcode is emitted, the set of digits is taken from the corresponding `groups` item, which is
// then removed from the slice. This signifies the usage of the number of the stack items by the `BRANCH` or `BRANCHHASH` opcode.
// DESCRIBED: docs/programmers_guide/guide.md#separation-of-keys-and-the-structure
func GenStructStep (
2021-02-21 18:41:59 +00:00
retain func ( prefix [ ] byte ) bool ,
curr , succ [ ] byte ,
e structInfoReceiver ,
h HashCollector2 ,
data GenStructStepData ,
groups [ ] uint16 ,
2021-03-13 02:30:54 +00:00
hasTree [ ] uint16 ,
2021-02-21 18:41:59 +00:00
hasHash [ ] uint16 ,
trace bool ,
) ( [ ] uint16 , [ ] uint16 , [ ] uint16 , error ) {
for precLen , buildExtensions := calcPrecLen ( groups ) , false ; precLen >= 0 ; precLen , buildExtensions = calcPrecLen ( groups ) , true {
var precExists = len ( groups ) > 0
// Calculate the prefix of the smallest prefix group containing curr
var precLen int
if len ( groups ) > 0 {
precLen = len ( groups ) - 1
}
succLen := prefixLen ( succ , curr )
var maxLen int
if precLen > succLen {
maxLen = precLen
} else {
maxLen = succLen
}
2021-06-06 21:44:14 +00:00
if trace || maxLen >= len ( curr ) {
fmt . Printf ( "curr: %x, succ: %x, maxLen %d, groups: %b, precLen: %d, succLen: %d, buildExtensions: %t\n" , curr , succ , maxLen , groups , precLen , succLen , buildExtensions )
}
2021-02-21 18:41:59 +00:00
// Add the digit immediately following the max common prefix and compute length of remainder length
extraDigit := curr [ maxLen ]
for maxLen >= len ( groups ) {
groups = append ( groups , 0 )
}
groups [ maxLen ] |= 1 << extraDigit
remainderStart := maxLen
if len ( succ ) > 0 || precExists {
remainderStart ++
}
remainderLen := len ( curr ) - remainderStart
2021-03-13 02:30:54 +00:00
for remainderStart + remainderLen >= len ( hasTree ) {
hasTree = append ( hasTree , 0 )
2021-02-21 18:41:59 +00:00
hasHash = append ( hasHash , 0 )
}
//fmt.Printf("groups is now %x,%d,%b\n", extraDigit, maxLen, groups)
if ! buildExtensions {
switch v := data . ( type ) {
case * GenStructStepHashData :
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "HashData before: %x, %t,%b,%b,%b\n" , curr , v . HasTree , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
2021-03-13 02:30:54 +00:00
if v . HasTree {
hasTree [ len ( curr ) - 1 ] |= 1 << curr [ len ( curr ) - 1 ] // keep track of existing records in DB
2021-02-21 18:41:59 +00:00
}
hasHash [ len ( curr ) - 1 ] |= 1 << curr [ len ( curr ) - 1 ] // register myself in parent bitmap
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "HashData: %x, %t,%b,%b,%b\n" , curr , v . HasTree , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
/* building a hash */
if err := e . hash ( v . Hash [ : ] ) ; err != nil {
return nil , nil , nil , err
}
buildExtensions = true
case * GenStructStepAccountData :
if retain ( curr [ : maxLen ] ) {
if err := e . accountLeaf ( remainderLen , curr , & v . Balance , v . Nonce , v . Incarnation , v . FieldSet , codeSizeUncached ) ; err != nil {
return nil , nil , nil , err
}
} else {
if err := e . accountLeafHash ( remainderLen , curr , & v . Balance , v . Nonce , v . Incarnation , v . FieldSet ) ; err != nil {
return nil , nil , nil , err
}
}
case * GenStructStepLeafData :
/* building leafs */
if retain ( curr [ : maxLen ] ) {
if err := e . leaf ( remainderLen , curr , v . Value ) ; err != nil {
return nil , nil , nil , err
}
} else {
if err := e . leafHash ( remainderLen , curr , v . Value ) ; err != nil {
return nil , nil , nil , err
}
}
default :
panic ( fmt . Errorf ( "unknown data type: %T" , data ) )
}
}
if buildExtensions {
if remainderLen > 0 {
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "Extension before: %x->%x,%b, %b, %b\n" , curr [ : remainderStart ] , curr [ remainderStart : remainderStart + remainderLen ] , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
2021-03-03 08:54:42 +00:00
// can't use hash of extension node
// but must propagate hasBranch bits to keep tracking all existing DB records
// groups bit also require propagation, but it's done automatically
2021-02-21 18:41:59 +00:00
from := remainderStart
if from == 0 {
from = 1
}
2021-03-03 08:54:42 +00:00
hasHash [ from - 1 ] &^= 1 << curr [ from - 1 ]
2021-02-21 18:41:59 +00:00
for i := from ; i < remainderStart + remainderLen ; i ++ {
2021-03-13 02:30:54 +00:00
if 1 << curr [ i ] & hasTree [ i ] != 0 {
hasTree [ from - 1 ] |= 1 << curr [ from - 1 ]
2021-02-21 18:41:59 +00:00
}
if h != nil {
if err := h ( curr [ : i ] , 0 , 0 , 0 , nil , nil ) ; err != nil {
return nil , nil , nil , err
}
}
}
2021-03-13 02:30:54 +00:00
hasTree = hasTree [ : from ]
2021-02-21 18:41:59 +00:00
hasHash = hasHash [ : from ]
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "Extension: %x, %b, %b, %b\n" , curr [ remainderStart : remainderStart + remainderLen ] , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
/* building extensions */
if retain ( curr [ : maxLen ] ) {
if err := e . extension ( curr [ remainderStart : remainderStart + remainderLen ] ) ; err != nil {
return nil , nil , nil , err
}
} else {
if err := e . extensionHash ( curr [ remainderStart : remainderStart + remainderLen ] ) ; err != nil {
return nil , nil , nil , err
}
}
}
}
// Check for the optional part
if precLen <= succLen && len ( succ ) > 0 {
2021-03-13 02:30:54 +00:00
return groups , hasTree , hasHash , nil
2021-02-21 18:41:59 +00:00
}
var usefulHashes [ ] byte
2021-03-13 02:30:54 +00:00
if h != nil && ( hasHash [ maxLen ] != 0 || hasTree [ maxLen ] != 0 ) { // top level must be in db
if trace {
fmt . Printf ( "why now: %x,%b,%b,%b\n" , curr [ : maxLen ] , hasHash , hasTree , groups )
}
usefulHashes = e . topHashes ( curr [ : maxLen ] , hasHash [ maxLen ] , groups [ maxLen ] )
if maxLen != 0 {
hasTree [ maxLen - 1 ] |= 1 << curr [ maxLen - 1 ] // register myself in parent bitmap
}
if maxLen > 1 {
if err := h ( curr [ : maxLen ] , groups [ maxLen ] , hasTree [ maxLen ] , hasHash [ maxLen ] , usefulHashes , nil ) ; err != nil {
2021-02-21 18:41:59 +00:00
return nil , nil , nil , err
}
}
}
// Close the immediately encompassing prefix group, if needed
if len ( succ ) > 0 || precExists {
if maxLen > 0 {
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "Branch before: %x, %b, %b, %b\n" , curr [ : maxLen ] , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
hasHash [ maxLen - 1 ] |= 1 << curr [ maxLen - 1 ]
2021-03-13 02:30:54 +00:00
if hasTree [ maxLen ] != 0 {
hasTree [ maxLen - 1 ] |= 1 << curr [ maxLen - 1 ]
2021-02-21 18:41:59 +00:00
}
if trace {
2021-03-13 02:30:54 +00:00
fmt . Printf ( "Branch: %x, %b, %b, %b\n" , curr [ : maxLen ] , hasHash , hasTree , groups )
2021-02-21 18:41:59 +00:00
}
}
if trace {
e . printTopHashes ( curr [ : maxLen ] , 0 , groups [ maxLen ] )
}
if retain ( curr [ : maxLen ] ) {
if err := e . branch ( groups [ maxLen ] ) ; err != nil {
return nil , nil , nil , err
}
} else {
if err := e . branchHash ( groups [ maxLen ] ) ; err != nil {
return nil , nil , nil , err
}
}
}
2021-03-13 02:30:54 +00:00
if h != nil {
send := maxLen == 0 && ( hasTree [ maxLen ] != 0 || hasHash [ maxLen ] != 0 ) // account.root - store only if have useful info
send = send || ( maxLen == 1 && groups [ maxLen ] != 0 ) // first level of trie_account - store in any case
if send {
if err := h ( curr [ : maxLen ] , groups [ maxLen ] , hasTree [ maxLen ] , hasHash [ maxLen ] , usefulHashes , e . topHash ( ) ) ; err != nil {
return nil , nil , nil , err
}
2021-02-21 18:41:59 +00:00
}
}
groups = groups [ : maxLen ]
2021-03-13 02:30:54 +00:00
hasTree = hasTree [ : maxLen ]
2021-02-21 18:41:59 +00:00
hasHash = hasHash [ : maxLen ]
// Check the end of recursion
if precLen == 0 {
2021-03-13 02:30:54 +00:00
return groups , hasTree , hasHash , nil
2021-02-21 18:41:59 +00:00
}
// Identify preceding key for the buildExtensions invocation
curr = curr [ : precLen ]
for len ( groups ) > 0 && groups [ len ( groups ) - 1 ] == 0 {
groups = groups [ : len ( groups ) - 1 ]
}
}
return nil , nil , nil , nil
}
func GenStructStepOld (
2020-05-12 14:24:43 +00:00
retain func ( prefix [ ] byte ) bool ,
2019-11-15 22:48:49 +00:00
curr , succ [ ] byte ,
2019-11-15 16:50:16 +00:00
e structInfoReceiver ,
2020-05-31 12:23:34 +00:00
h HashCollector ,
2019-12-12 17:17:13 +00:00
data GenStructStepData ,
2019-11-15 16:50:16 +00:00
groups [ ] uint16 ,
2020-01-30 13:16:12 +00:00
trace bool ,
2019-11-15 16:50:16 +00:00
) ( [ ] uint16 , error ) {
2019-12-12 17:17:13 +00:00
for precLen , buildExtensions := calcPrecLen ( groups ) , false ; precLen >= 0 ; precLen , buildExtensions = calcPrecLen ( groups ) , true {
var precExists = len ( groups ) > 0
// Calculate the prefix of the smallest prefix group containing curr
var precLen int
if len ( groups ) > 0 {
precLen = len ( groups ) - 1
2019-12-09 14:59:30 +00:00
}
2019-12-12 17:17:13 +00:00
succLen := prefixLen ( succ , curr )
var maxLen int
if precLen > succLen {
maxLen = precLen
} else {
maxLen = succLen
2019-11-15 22:48:49 +00:00
}
2020-06-26 06:46:05 +00:00
if trace || maxLen >= len ( curr ) {
2020-01-30 13:16:12 +00:00
fmt . Printf ( "curr: %x, succ: %x, maxLen %d, groups: %b, precLen: %d, succLen: %d, buildExtensions: %t\n" , curr , succ , maxLen , groups , precLen , succLen , buildExtensions )
}
2019-12-12 17:17:13 +00:00
// Add the digit immediately following the max common prefix and compute length of remainder length
extraDigit := curr [ maxLen ]
for maxLen >= len ( groups ) {
groups = append ( groups , 0 )
}
2021-02-21 18:41:59 +00:00
groups [ maxLen ] |= 1 << extraDigit
2019-12-12 17:17:13 +00:00
//fmt.Printf("groups is now %b\n", groups)
remainderStart := maxLen
if len ( succ ) > 0 || precExists {
remainderStart ++
2019-11-15 16:50:16 +00:00
}
2019-12-12 17:17:13 +00:00
remainderLen := len ( curr ) - remainderStart
2020-01-30 13:16:12 +00:00
if ! buildExtensions {
2019-12-12 17:17:13 +00:00
switch v := data . ( type ) {
2020-01-30 13:16:12 +00:00
case * GenStructStepHashData :
2019-12-12 17:17:13 +00:00
/* building a hash */
2020-07-05 06:17:27 +00:00
if err := e . hash ( v . Hash [ : ] ) ; err != nil {
2019-12-09 14:59:30 +00:00
return nil , err
}
2020-01-30 13:16:12 +00:00
buildExtensions = true
case * GenStructStepAccountData :
2020-05-12 14:24:43 +00:00
if retain ( curr [ : maxLen ] ) {
2020-07-07 11:24:55 +00:00
if err := e . accountLeaf ( remainderLen , curr , & v . Balance , v . Nonce , v . Incarnation , v . FieldSet , codeSizeUncached ) ; err != nil {
2019-11-15 22:48:49 +00:00
return nil , err
}
} else {
2020-05-12 14:24:43 +00:00
if err := e . accountLeafHash ( remainderLen , curr , & v . Balance , v . Nonce , v . Incarnation , v . FieldSet ) ; err != nil {
2019-11-15 22:48:49 +00:00
return nil , err
}
2019-11-15 16:50:16 +00:00
}
2020-01-30 13:16:12 +00:00
case * GenStructStepLeafData :
2019-12-12 17:17:13 +00:00
/* building leafs */
2020-05-12 14:24:43 +00:00
if retain ( curr [ : maxLen ] ) {
if err := e . leaf ( remainderLen , curr , v . Value ) ; err != nil {
2019-11-15 22:48:49 +00:00
return nil , err
}
} else {
2020-05-12 14:24:43 +00:00
if err := e . leafHash ( remainderLen , curr , v . Value ) ; err != nil {
2019-11-15 22:48:49 +00:00
return nil , err
}
2019-11-15 16:50:16 +00:00
}
2019-12-12 17:17:13 +00:00
default :
panic ( fmt . Errorf ( "unknown data type: %T" , data ) )
2019-11-15 16:50:16 +00:00
}
}
2020-01-30 13:16:12 +00:00
if buildExtensions {
if remainderLen > 0 {
if trace {
fmt . Printf ( "Extension %x\n" , curr [ remainderStart : remainderStart + remainderLen ] )
}
/* building extensions */
2020-05-12 14:24:43 +00:00
if retain ( curr [ : maxLen ] ) {
if err := e . extension ( curr [ remainderStart : remainderStart + remainderLen ] ) ; err != nil {
2020-01-30 13:16:12 +00:00
return nil , err
}
} else {
2020-05-12 14:24:43 +00:00
if err := e . extensionHash ( curr [ remainderStart : remainderStart + remainderLen ] ) ; err != nil {
2020-01-30 13:16:12 +00:00
return nil , err
}
}
}
}
2019-12-12 17:17:13 +00:00
// Check for the optional part
if precLen <= succLen && len ( succ ) > 0 {
return groups , nil
}
// Close the immediately encompassing prefix group, if needed
if len ( succ ) > 0 || precExists {
2020-05-12 14:24:43 +00:00
if retain ( curr [ : maxLen ] ) {
if err := e . branch ( groups [ maxLen ] ) ; err != nil {
2019-12-12 17:17:13 +00:00
return nil , err
}
} else {
2020-05-12 14:24:43 +00:00
if err := e . branchHash ( groups [ maxLen ] ) ; err != nil {
2019-12-12 17:17:13 +00:00
return nil , err
}
2019-11-15 16:50:16 +00:00
}
2020-05-31 12:23:34 +00:00
if h != nil {
2020-07-02 10:55:35 +00:00
if err := h ( curr [ : maxLen ] , e . topHash ( ) ) ; err != nil {
2020-05-31 12:23:34 +00:00
return nil , err
}
}
2019-11-15 16:50:16 +00:00
}
2019-12-12 17:17:13 +00:00
groups = groups [ : maxLen ]
// Check the end of recursion
if precLen == 0 {
return groups , nil
}
// Identify preceding key for the buildExtensions invocation
curr = curr [ : precLen ]
for len ( groups ) > 0 && groups [ len ( groups ) - 1 ] == 0 {
groups = groups [ : len ( groups ) - 1 ]
}
2019-11-15 16:50:16 +00:00
}
2019-12-12 17:17:13 +00:00
return nil , nil
2019-11-15 16:50:16 +00:00
}