From c037f214e407bcfa9695c011b590a5311b39f3b0 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:27:14 +0100 Subject: [PATCH 1/3] alter Trie interface to use caching for slots --- core/chain_makers.go | 2 +- core/state/database.go | 6 +- core/state/state_object.go | 16 ++---- core/state/trie_prefetcher.go | 2 +- go.mod | 6 +- go.sum | 6 ++ light/trie.go | 10 ++-- trie/secure_trie.go | 16 +++--- trie/trie.go | 4 +- trie/verkle.go | 101 +++++++++++++++------------------- 10 files changed, 77 insertions(+), 92 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 5b9bbec284d5..531079ccaeb2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -365,7 +365,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine kvs := make(map[string][]byte) keys := statedb.Witness().Keys() for _, key := range keys { - v, err := vtr.TryGet(key) + v, err := vtr.GetWithHashedKey(key) if err != nil { panic(err) } diff --git a/core/state/database.go b/core/state/database.go index 69a65cdcd835..6a4135940974 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -74,7 +74,7 @@ type Trie interface { // TryGet returns the value for key stored in the trie. The value bytes must // not be modified by the caller. If a node was not found in the database, a // trie.MissingNodeError is returned. - TryGet(key []byte) ([]byte, error) + TryGet(address, key []byte) ([]byte, error) // TryGetAccount abstract an account read from the trie. TryGetAccount(key []byte) (*types.StateAccount, error) @@ -83,14 +83,14 @@ type Trie interface { // existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. - TryUpdate(key, value []byte) error + TryUpdate(address, key, value []byte) error // TryUpdateAccount abstract an account write to the trie. TryUpdateAccount(key []byte, account *types.StateAccount) error // TryDelete removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. - TryDelete(key []byte) error + TryDelete(address, key []byte) error // TryDeleteAccount abstracts an account deletion from the trie. TryDeleteAccount(key []byte) error diff --git a/core/state/state_object.go b/core/state/state_object.go index 05e508565ae6..1b4f60a382ee 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -29,8 +29,6 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - trieUtils "github.com/ethereum/go-ethereum/trie/utils" - "github.com/holiman/uint256" ) var emptyCodeHash = crypto.Keccak256(nil) @@ -227,7 +225,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has panic("verkle trees use the snapshot") } start := time.Now() - enc, err = s.getTrie(db).TryGet(key.Bytes()) + enc, err = s.getTrie(db).TryGet(s.address[:], key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -343,22 +341,16 @@ func (s *stateObject) updateTrie(db Database) Trie { var v []byte if (value == common.Hash{}) { - if tr.IsVerkle() { - k := trieUtils.GetTreeKeyStorageSlotWithEvaluatedAddress(s.db.db.(*VerkleDB).GetTreeKeyHeader(s.address[:]), new(uint256.Int).SetBytes(key[:])) - s.setError(tr.TryDelete(k)) - //s.db.db.TrieDB().DiskDB().Delete(append(s.address[:], key[:]...)) - } else { - s.setError(tr.TryDelete(key[:])) - } + s.setError(tr.TryDelete(s.address[:], key[:])) s.db.StorageDeleted += 1 } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) if !tr.IsVerkle() { - s.setError(tr.TryUpdate(key[:], v)) + s.setError(tr.TryUpdate(s.address[:], key[:], v)) } else { // Update the trie, with v as a value - s.setError(tr.TryUpdate(key[:], value[:])) + s.setError(tr.TryUpdate(s.address[:], key[:], value[:])) } s.db.StorageUpdated += 1 } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 2e16f587ce56..ad2383103ab4 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -339,7 +339,7 @@ func (sf *subfetcher) loop() { if len(task) == len(common.Address{}) { sf.trie.TryGetAccount(task) } else { - sf.trie.TryGet(task) + sf.trie.TryGet(nil, task) } sf.seen[string(task)] = struct{}{} } diff --git a/go.mod b/go.mod index ed075c50f249..2903a6e92fe4 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f - github.com/crate-crypto/go-ipa v0.0.0-20230202201618-2e6f5bfc5401 + github.com/crate-crypto/go-ipa v0.0.0-20230315201338-1643fdc2ead8 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 github.com/docker/docker v1.6.2 @@ -23,7 +23,7 @@ require ( github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20230303104313-a4243d1136b3 + github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467 github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 @@ -60,7 +60,7 @@ require ( github.com/urfave/cli/v2 v2.10.2 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sync v0.1.0 golang.org/x/sys v0.6.0 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/text v0.3.7 diff --git a/go.sum b/go.sum index ac5302ca67a8..20af5d184b30 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,8 @@ github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc h1:mtR7MuscVeP github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/crate-crypto/go-ipa v0.0.0-20230202201618-2e6f5bfc5401 h1:TSXRL74LZ7R2xWOI1M0mz9E56PiPKGlSw0drgR8g7CE= github.com/crate-crypto/go-ipa v0.0.0-20230202201618-2e6f5bfc5401/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= +github.com/crate-crypto/go-ipa v0.0.0-20230315201338-1643fdc2ead8 h1:2EBbIwPDRqlCD2K34Eojyy0x9d3RhOuHAZfbQm508X8= +github.com/crate-crypto/go-ipa v0.0.0-20230315201338-1643fdc2ead8/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -143,6 +145,8 @@ github.com/gballet/go-verkle v0.0.0-20221129125207-513116151b28 h1:UbB7D2R1OQCkN github.com/gballet/go-verkle v0.0.0-20221129125207-513116151b28/go.mod h1:DMDd04jjQgdynaAwbEgiRERIGpC8fDjx0+y06an7Psg= github.com/gballet/go-verkle v0.0.0-20230303104313-a4243d1136b3 h1:UfRrJQF6ohVQGdi3MTU/8dPnayaIR2RuulZ55gUYXIE= github.com/gballet/go-verkle v0.0.0-20230303104313-a4243d1136b3/go.mod h1:NR+n/LUx+m5SyVTRObiuNdJ50q309MGPD0VrIMDZJuc= +github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467 h1:LkJAMgQtzKrWIr8m513poIhG2eBC1OZqIeziw9jkXPI= +github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467/go.mod h1:NR+n/LUx+m5SyVTRObiuNdJ50q309MGPD0VrIMDZJuc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -518,6 +522,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/light/trie.go b/light/trie.go index abb7e6557732..83c9f6910661 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGet(key []byte) ([]byte, error) { +func (t *odrTrie) TryGet(_, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -142,17 +142,17 @@ func (t *odrTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { }) } -func (t *odrTrie) TryUpdate(key, value []byte) error { +func (t *odrTrie) TryUpdate(_, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDelete(key []byte) error { +func (t *odrTrie) TryDelete(_, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.TryDelete(nil, key) }) } @@ -160,7 +160,7 @@ func (t *odrTrie) TryDelete(key []byte) error { func (t *odrTrie) TryDeleteAccount(key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.TryDelete(nil, key) }) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 68b0a07cbfa0..f48b3a6ca3b1 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,7 +75,7 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGet(key) + res, err := t.TryGet(nil, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } @@ -86,7 +86,7 @@ func (t *StateTrie) Get(key []byte) []byte { // The value bytes must not be modified by the caller. // If the specified node is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGet(key []byte) ([]byte, error) { +func (t *StateTrie) TryGet(_, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } @@ -131,7 +131,7 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { + if err := t.TryUpdate(nil, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdate(key, value []byte) error { +func (t *StateTrie) TryUpdate(_, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -171,7 +171,7 @@ func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { + if err := t.TryDelete(nil, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } @@ -179,17 +179,17 @@ func (t *StateTrie) Delete(key []byte) { // TryDelete removes any existing value for key from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDelete(key []byte) error { +func (t *StateTrie) TryDelete(_, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.TryDelete(nil, hk) } // TryDeleteAccount abstracts an account deletion from the trie. func (t *StateTrie) TryDeleteAccount(key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.TryDelete(nil, hk) } // GetKey returns the sha3 preimage of a hashed key that was diff --git a/trie/trie.go b/trie/trie.go index bec6a1cc7891..49b1d9d8d4cd 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -389,14 +389,14 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error // Delete removes any existing value for key from the trie. func (t *Trie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { + if err := t.TryDelete(nil, key); err != nil { log.Error("Unhandled trie error in Trie.Delete", "err", err) } } // TryDelete removes any existing value for key from the trie. // If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryDelete(key []byte) error { +func (t *Trie) TryDelete(_, key []byte) error { t.unhashed++ k := keybytesToHex(key) _, n, err := t.delete(t.root, nil, k) diff --git a/trie/verkle.go b/trie/verkle.go index 17c3d16500ca..9ee89456d8f4 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -62,55 +62,45 @@ func (trie *VerkleTrie) GetKey(key []byte) []byte { // TryGet returns the value for key stored in the trie. The value bytes must // not be modified by the caller. If a node was not found in the database, a // trie.MissingNodeError is returned. -func (trie *VerkleTrie) TryGet(key []byte) ([]byte, error) { +func (trie *VerkleTrie) TryGet(addr, key []byte) ([]byte, error) { + pointEval := trie.pointCache.GetTreeKeyHeader(key) + k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(pointEval, new(uint256.Int).SetBytes(key)) + return trie.root.Get(k, trie.db.diskdb.Get) +} + +// GetWithHashedKey returns the value, assuming that the key has already +// been hashed. +func (trie *VerkleTrie) GetWithHashedKey(key []byte) ([]byte, error) { return trie.root.Get(key, trie.db.diskdb.Get) } func (t *VerkleTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { var ( - err error - balancekey, cskey, ckkey, noncekey [32]byte - acc *types.StateAccount = &types.StateAccount{} + acc *types.StateAccount = &types.StateAccount{} + resolver = func(hash []byte) ([]byte, error) { + return t.db.diskdb.Get(hash) + } ) - - // Only evaluate the polynomial once - // TODO implement GetStem as well, so that the trie is only traversed once - // it's not as bad because the commitments aren't updated, but it could, in - // theory, have to deserialize some more nodes (if there is some sort of cache - // dump) versionkey := t.pointCache.GetTreeKeyVersionCached(key) - copy(balancekey[:], versionkey) - balancekey[31] = utils.BalanceLeafKey - copy(noncekey[:], versionkey) - noncekey[31] = utils.NonceLeafKey - copy(cskey[:], versionkey) - cskey[31] = utils.CodeSizeLeafKey - copy(ckkey[:], versionkey) - ckkey[31] = utils.CodeKeccakLeafKey - - nonce, err := t.TryGet(noncekey[:]) + values, err := t.root.(*verkle.InternalNode).GetStem(versionkey[:31], resolver) if err != nil { return nil, fmt.Errorf("TryGetAccount (%x) error: %v", key, err) } - if len(nonce) > 0 { - acc.Nonce = binary.LittleEndian.Uint64(nonce) + + if values == nil { + return nil, nil } - balance, err := t.TryGet(balancekey[:]) - if err != nil { - return nil, fmt.Errorf("updateStateObject (%x) error: %v", key, err) + if len(values[utils.NonceLeafKey]) > 0 { + acc.Nonce = binary.LittleEndian.Uint64(values[utils.NonceLeafKey]) } + balance := values[utils.BalanceLeafKey] if len(balance) > 0 { for i := 0; i < len(balance)/2; i++ { balance[len(balance)-i-1], balance[i] = balance[i], balance[len(balance)-i-1] } } acc.Balance = new(big.Int).SetBytes(balance[:]) - ck, err := t.TryGet(ckkey[:]) - if err != nil { - return nil, fmt.Errorf("updateStateObject (%x) error: %v", key, err) - } - acc.CodeHash = ck - + acc.CodeHash = values[utils.CodeKeccakLeafKey] // TODO fix the code size as well return acc, nil @@ -177,8 +167,8 @@ func (trie *VerkleTrie) TryUpdateStem(key []byte, values [][]byte) error { // existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. -func (trie *VerkleTrie) TryUpdate(key, value []byte) error { - k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(trie.pointCache.GetTreeKeyHeader(key), new(uint256.Int).SetBytes(key[:])) +func (trie *VerkleTrie) TryUpdate(address, key, value []byte) error { + k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(trie.pointCache.GetTreeKeyHeader(address), new(uint256.Int).SetBytes(key[:])) var v [32]byte copy(v[:], value[:]) return trie.root.Insert(k, v[:], func(h []byte) ([]byte, error) { @@ -188,33 +178,28 @@ func (trie *VerkleTrie) TryUpdate(key, value []byte) error { func (t *VerkleTrie) TryDeleteAccount(key []byte) error { var ( - err error - balancekey, cskey, ckkey, noncekey [32]byte + err error + values = make([][]byte, verkle.NodeWidth) + stem = t.pointCache.GetTreeKeyVersionCached(key[:]) ) - // Only evaluate the polynomial once - // TODO InsertStem with overwrite of values 0 - versionkey := t.pointCache.GetTreeKeyVersionCached(key) - copy(balancekey[:], versionkey) - balancekey[31] = utils.BalanceLeafKey - copy(noncekey[:], versionkey) - noncekey[31] = utils.NonceLeafKey - copy(cskey[:], versionkey) - cskey[31] = utils.CodeSizeLeafKey - copy(ckkey[:], versionkey) - ckkey[31] = utils.CodeKeccakLeafKey - - if err = t.TryDelete(versionkey); err != nil { - return fmt.Errorf("updateStateObject (%x) error: %v", key, err) + for i := 0; i < verkle.NodeWidth; i++ { + + values[i] = zero[:] } - if err = t.TryDelete(noncekey[:]); err != nil { - return fmt.Errorf("updateStateObject (%x) error: %v", key, err) + + resolver := func(hash []byte) ([]byte, error) { + return t.db.diskdb.Get(hash) } - if err = t.TryDelete(balancekey[:]); err != nil { - return fmt.Errorf("updateStateObject (%x) error: %v", key, err) + + switch root := t.root.(type) { + case *verkle.InternalNode: + err = root.InsertStem(stem, values, resolver) + case *verkle.StatelessNode: + err = root.InsertAtStem(stem, values, resolver, true) } - if err = t.TryDelete(ckkey[:]); err != nil { - return fmt.Errorf("updateStateObject (%x) error: %v", key, err) + if err != nil { + return fmt.Errorf("TryDeleteAccount (%x) error: %v", key, err) } // TODO figure out if the code size needs to be updated, too @@ -223,8 +208,10 @@ func (t *VerkleTrie) TryDeleteAccount(key []byte) error { // TryDelete removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. -func (trie *VerkleTrie) TryDelete(key []byte) error { - return trie.root.Delete(key, func(h []byte) ([]byte, error) { +func (trie *VerkleTrie) TryDelete(addr, key []byte) error { + pointEval := trie.pointCache.GetTreeKeyHeader(key) + k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(pointEval, new(uint256.Int).SetBytes(key)) + return trie.root.Delete(k, func(h []byte) ([]byte, error) { return trie.db.diskdb.Get(h) }) } From 7a73bb0ba053f6564d37d33c3a6a7f8fdddaa2e9 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Sun, 19 Mar 2023 19:50:17 +0100 Subject: [PATCH 2/3] fix: use a lock to protect the point cache (#185) --- core/state/database.go | 8 ++++---- trie/utils/verkle.go | 28 ++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 6a4135940974..77c80f10dd9c 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -142,7 +142,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { diskdb: db, codeSizeCache: csc, codeCache: fastcache.New(codeCacheSize), - addrToPoint: make(utils.PointCache), + addrToPoint: utils.NewPointCache(), } } return &cachingDB{ @@ -246,7 +246,7 @@ type VerkleDB struct { // Caches all the points that correspond to an address, // so they are not recalculated. - addrToPoint utils.PointCache + addrToPoint *utils.PointCache } func (db *VerkleDB) GetTreeKeyHeader(addr []byte) *verkle.Point { @@ -256,7 +256,7 @@ func (db *VerkleDB) GetTreeKeyHeader(addr []byte) *verkle.Point { // OpenTrie opens the main account trie. func (db *VerkleDB) OpenTrie(root common.Hash) (Trie, error) { if root == (common.Hash{}) || root == emptyRoot { - return trie.NewVerkleTrie(verkle.New(), db.db, &db.addrToPoint), nil + return trie.NewVerkleTrie(verkle.New(), db.db, db.addrToPoint), nil } payload, err := db.DiskDB().Get(root[:]) if err != nil { @@ -267,7 +267,7 @@ func (db *VerkleDB) OpenTrie(root common.Hash) (Trie, error) { if err != nil { panic(err) } - return trie.NewVerkleTrie(r, db.db, &db.addrToPoint), err + return trie.NewVerkleTrie(r, db.db, db.addrToPoint), err } // OpenStorageTrie opens the storage trie of an account. diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 9ec41ebb090f..f40f5b71112c 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -17,6 +17,8 @@ package utils import ( + "sync" + "github.com/crate-crypto/go-ipa/bandersnatch/fr" "github.com/gballet/go-verkle" "github.com/holiman/uint256" @@ -41,19 +43,33 @@ var ( getTreePolyIndex0Point *verkle.Point ) -type PointCache map[string]*verkle.Point +type PointCache struct { + cache map[string]*verkle.Point + lock sync.RWMutex +} + +func NewPointCache() *PointCache { + return &PointCache{ + cache: make(map[string]*verkle.Point), + } +} -func (pc PointCache) GetTreeKeyHeader(addr []byte) *verkle.Point { - if point, ok := pc[string(addr)]; ok { +func (pc *PointCache) GetTreeKeyHeader(addr []byte) *verkle.Point { + pc.lock.RLock() + point, ok := pc.cache[string(addr)] + pc.lock.RUnlock() + if ok { return point } - point := EvaluateAddressPoint(addr) - pc[string(addr)] = point + point = EvaluateAddressPoint(addr) + pc.lock.Lock() + pc.cache[string(addr)] = point + pc.lock.Unlock() return point } -func (pc PointCache) GetTreeKeyVersionCached(addr []byte) []byte { +func (pc *PointCache) GetTreeKeyVersionCached(addr []byte) []byte { p := pc.GetTreeKeyHeader(addr) v := PointToHash(p, VersionLeafKey) return v[:] From af726a0e848fa14cfa1110e6c8015c72899b8399 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Sun, 19 Mar 2023 15:56:37 -0300 Subject: [PATCH 3/3] use fastest non-master go-verkle version & pull trie/Verkle.go changes to use new api (#184) * mod: update to fastest go-verkle version today Signed-off-by: Ignacio Hagopian * trie/verkle: use new batch serialization api Signed-off-by: Ignacio Hagopian --------- Signed-off-by: Ignacio Hagopian --- go.mod | 2 +- go.sum | 18 ++---------------- trie/verkle.go | 41 ++++++++++++++--------------------------- 3 files changed, 17 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 2903a6e92fe4..94f82043bf54 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467 + github.com/gballet/go-verkle v0.0.0-20230317174103-141354da6b11 github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index 20af5d184b30..4a3b92eff6df 100644 --- a/go.sum +++ b/go.sum @@ -86,10 +86,6 @@ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc h1:mtR7MuscVeP/s0/ERWA2uSr5QOrRYy1pdvZqG1USfXI= -github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= -github.com/crate-crypto/go-ipa v0.0.0-20230202201618-2e6f5bfc5401 h1:TSXRL74LZ7R2xWOI1M0mz9E56PiPKGlSw0drgR8g7CE= -github.com/crate-crypto/go-ipa v0.0.0-20230202201618-2e6f5bfc5401/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/crate-crypto/go-ipa v0.0.0-20230315201338-1643fdc2ead8 h1:2EBbIwPDRqlCD2K34Eojyy0x9d3RhOuHAZfbQm508X8= github.com/crate-crypto/go-ipa v0.0.0-20230315201338-1643fdc2ead8/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -139,14 +135,8 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgx github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.0.0-20221122140954-75ceda26b7db h1:YvtZfE11QEYWPjsQCyZLoZCGMsxJs9mTEbhF3MnM32Q= -github.com/gballet/go-verkle v0.0.0-20221122140954-75ceda26b7db/go.mod h1:DMDd04jjQgdynaAwbEgiRERIGpC8fDjx0+y06an7Psg= -github.com/gballet/go-verkle v0.0.0-20221129125207-513116151b28 h1:UbB7D2R1OQCkNFX+LYoo2pHZ0u5LhwR9ldUsY4ZbZqI= -github.com/gballet/go-verkle v0.0.0-20221129125207-513116151b28/go.mod h1:DMDd04jjQgdynaAwbEgiRERIGpC8fDjx0+y06an7Psg= -github.com/gballet/go-verkle v0.0.0-20230303104313-a4243d1136b3 h1:UfRrJQF6ohVQGdi3MTU/8dPnayaIR2RuulZ55gUYXIE= -github.com/gballet/go-verkle v0.0.0-20230303104313-a4243d1136b3/go.mod h1:NR+n/LUx+m5SyVTRObiuNdJ50q309MGPD0VrIMDZJuc= -github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467 h1:LkJAMgQtzKrWIr8m513poIhG2eBC1OZqIeziw9jkXPI= -github.com/gballet/go-verkle v0.0.0-20230314090848-2b9d2a2f7467/go.mod h1:NR+n/LUx+m5SyVTRObiuNdJ50q309MGPD0VrIMDZJuc= +github.com/gballet/go-verkle v0.0.0-20230317174103-141354da6b11 h1:x4hiQFgr1SlqR4IoAZiXLFZK4L7KbibqkORqa1fwKp8= +github.com/gballet/go-verkle v0.0.0-20230317174103-141354da6b11/go.mod h1:IyOnn1kujMWaT+wet/6Ix1BtvYwateOBy9puuWH/8sw= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -520,7 +510,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -564,10 +553,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/trie/verkle.go b/trie/verkle.go index 9ee89456d8f4..8d8fc089230a 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -149,10 +149,9 @@ func (t *VerkleTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error } func (trie *VerkleTrie) TryUpdateStem(key []byte, values [][]byte) error { - resolver := - func(h []byte) ([]byte, error) { - return trie.db.diskdb.Get(h) - } + resolver := func(h []byte) ([]byte, error) { + return trie.db.diskdb.Get(h) + } switch root := trie.root.(type) { case *verkle.InternalNode: return root.InsertStem(key, values, resolver) @@ -184,7 +183,6 @@ func (t *VerkleTrie) TryDeleteAccount(key []byte) error { ) for i := 0; i < verkle.NodeWidth; i++ { - values[i] = zero[:] } @@ -230,33 +228,22 @@ func nodeToDBKey(n verkle.VerkleNode) []byte { // Commit writes all nodes to the trie's memory database, tracking the internal // and external (for account tries) references. func (trie *VerkleTrie) Commit(_ bool) (common.Hash, *NodeSet, error) { - flush := make(chan verkle.VerkleNode) - resolver := func(n verkle.VerkleNode) { - flush <- n + root, ok := trie.root.(*verkle.InternalNode) + if !ok { + return common.Hash{}, nil, errors.New("unexpected root node type") + } + nodes, err := root.BatchSerialize() + if err != nil { + return common.Hash{}, nil, fmt.Errorf("serializing tree nodes: %s", err) } - go func() { - switch root := trie.root.(type) { - case *verkle.InternalNode: - root.Flush(resolver) - case *verkle.StatelessNode: - root.Flush(resolver) - } - close(flush) - }() - var commitCount int - for n := range flush { - commitCount += 1 - value, err := n.Serialize() - if err != nil { - panic(err) - } - if err := trie.db.diskdb.Put(nodeToDBKey(n), value); err != nil { - return common.Hash{}, NewNodeSet(common.Hash{}), err + for _, node := range nodes { + if err := trie.db.diskdb.Put(node.CommitmentBytes[:], node.SerializedBytes); err != nil { + return common.Hash{}, nil, fmt.Errorf("put node to disk: %s", err) } } - return trie.Hash(), NewNodeSet(common.Hash{}), nil + return nodes[0].CommitmentBytes, NewNodeSet(common.Hash{}), nil } // NodeIterator returns an iterator that returns nodes of the trie. Iteration