diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index e40c180aa421..1984b55e4f42 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -393,82 +393,13 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // Assign the final state root to header. header.Root = state.IntermediateRoot(true) + // Associate current conversion state to computed state // root and store it in the database for later recovery. state.Database().SaveTransitionState(header.Root) - var ( - p *verkle.VerkleProof - k verkle.StateDiff - keys = state.Witness().Keys() - ) - if chain.Config().IsPrague(header.Number, header.Time) { - // Open the pre-tree to prove the pre-state against - parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1) - if parent == nil { - return nil, fmt.Errorf("nil parent header for block %d", header.Number) - } - - // Load transition state at beginning of block, because - // OpenTrie needs to know what the conversion status is. - state.Database().LoadTransitionState(parent.Root) - - if chain.Config().ProofInBlocks { - preTrie, err := state.Database().OpenTrie(parent.Root) - if err != nil { - return nil, fmt.Errorf("error opening pre-state tree root: %w", err) - } - - var okpre, okpost bool - var vtrpre, vtrpost *trie.VerkleTrie - switch pre := preTrie.(type) { - case *trie.VerkleTrie: - vtrpre, okpre = preTrie.(*trie.VerkleTrie) - switch tr := state.GetTrie().(type) { - case *trie.VerkleTrie: - vtrpost = tr - okpost = true - // This is to handle a situation right at the start of the conversion: - // the post trie is a transition tree when the pre tree is an empty - // verkle tree. - case *trie.TransitionTrie: - vtrpost = tr.Overlay() - okpost = true - default: - okpost = false - } - case *trie.TransitionTrie: - vtrpre = pre.Overlay() - okpre = true - post, _ := state.GetTrie().(*trie.TransitionTrie) - vtrpost = post.Overlay() - okpost = true - default: - // This should only happen for the first block of the - // conversion, when the previous tree is a merkle tree. - // Logically, the "previous" verkle tree is an empty tree. - okpre = true - vtrpre = trie.NewVerkleTrie(verkle.New(), state.Database().TrieDB(), utils.NewPointCache(), false) - post := state.GetTrie().(*trie.TransitionTrie) - vtrpost = post.Overlay() - okpost = true - } - if okpre && okpost { - if len(keys) > 0 { - p, k, err = trie.ProveAndSerialize(vtrpre, vtrpost, keys, vtrpre.FlatdbNodeResolver) - if err != nil { - return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err) - } - } - } - } - } - // Assemble and return the final block. block := types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)) - if chain.Config().IsPrague(header.Number, header.Time) && chain.Config().ProofInBlocks { - block.SetVerkleProof(p, k) - } return block, nil } diff --git a/core/state/access_witness.go b/core/state/access_witness.go index 4c9d3218ad96..cb9493ba1d27 100644 --- a/core/state/access_witness.go +++ b/core/state/access_witness.go @@ -17,6 +17,8 @@ package state import ( + "os" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" @@ -158,6 +160,23 @@ func (aw *AccessWitness) TouchSlotAndChargeGas(addr []byte, slot common.Hash, is return aw.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite) } +func AppendBytesToFile(filename string, bytes []byte) error { + // Open or create file for writing; append data if file exists + file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + + // Write bytes to file + _, err = file.Write(bytes) + if err != nil { + return err + } + + return nil +} + func (aw *AccessWitness) touchAddressAndChargeGas(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 { stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := aw.touchAddress(addr, treeIndex, subIndex, isWrite) diff --git a/core/state_processor.go b/core/state_processor.go index d6a01673c6ab..aaf16edf786b 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -31,6 +31,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-verkle" + "github.com/pk910/dynamic-ssz" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -109,6 +111,90 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) + header.Root = statedb.IntermediateRoot(true) + // Associate current conversion state to computed state + // root and store it in the database for later recovery. + statedb.Database().SaveTransitionState(header.Root) + + var ( + proof *verkle.VerkleProof + statediff verkle.StateDiff + keys = statedb.Witness().Keys() + ) + // Open the pre-tree to prove the pre-state against + parent := p.bc.GetHeaderByNumber(header.Number.Uint64() - 1) + if parent == nil { + return nil, nil, 0, fmt.Errorf("nil parent header for block %d", header.Number) + } + + // Load transition state at beginning of block, because + // OpenTrie needs to know what the conversion status is. + // statedb.Database().LoadTransitionState(parent.Root) + + preTrie, err := statedb.Database().OpenTrie(parent.Root) + if err != nil { + return nil, nil, 0, fmt.Errorf("error opening pre-state tree root: %w", err) + } + // statedb.Database().LoadTransitionState(header.Root) + + var okpre, okpost bool + var vtrpre, vtrpost *trie.VerkleTrie + switch pre := preTrie.(type) { + case *trie.VerkleTrie: + vtrpre, okpre = preTrie.(*trie.VerkleTrie) + switch tr := statedb.GetTrie().(type) { + case *trie.VerkleTrie: + vtrpost = tr + okpost = true + // This is to handle a situation right at the start of the conversion: + // the post trie is a transition tree when the pre tree is an empty + // verkle tree. + case *trie.TransitionTrie: + vtrpost = tr.Overlay() + okpost = true + default: + okpost = false + } + case *trie.TransitionTrie: + vtrpre = pre.Overlay() + okpre = true + post, _ := statedb.GetTrie().(*trie.TransitionTrie) + vtrpost = post.Overlay() + okpost = true + default: + // This should only happen for the first block of the + // conversion, when the previous tree is a merkle tree. + // Logically, the "previous" verkle tree is an empty tree. + okpre = true + vtrpre = trie.NewVerkleTrie(verkle.New(), statedb.Database().TrieDB(), utils.NewPointCache(), false) + post := statedb.GetTrie().(*trie.TransitionTrie) + vtrpost = post.Overlay() + okpost = true + } + if okpre && okpost { + if len(keys) > 0 { + proof, statediff, err = trie.ProveAndSerialize(vtrpre, vtrpost, keys, vtrpre.FlatdbNodeResolver) + if err != nil { + return nil, nil, 0, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err) + } + } + + ew := types.ExecutionWitness{StateDiff: statediff, VerkleProof: proof} + encoder := dynssz.NewDynSsz(map[string]any{}) + encoded, err := encoder.MarshalSSZ(&ew) + if err != nil { + spew.Dump(ew) + panic(err) + } + state.AppendBytesToFile("witness_size.csv", []byte(fmt.Sprintf("%d,%d\n", header.Number, len(encoded)))) + if header.Number.Uint64()%10000 == 0 { + data := make([]byte, 8+len(encoded)) + copy(data[8:], encoded) + binary.LittleEndian.PutUint64(data[:8], block.NumberU64()) + state.AppendBytesToFile("witnesses.ssz", data) + } + } + if block.NumberU64()%100 == 0 { stateRoot := statedb.GetTrie().Hash() log.Info("State root", "number", block.NumberU64(), "hash", stateRoot) diff --git a/go.mod b/go.mod index 3f7010a4989d..1c67a0a31752 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v0.3.0 - github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 + github.com/ethereum/go-verkle v0.1.1-0.20240710134556-4941876f32aa github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 @@ -65,8 +65,8 @@ require ( go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.10.0 golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc - golang.org/x/sync v0.4.0 - golang.org/x/sys v0.13.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.22.0 golang.org/x/text v0.10.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.9.1 @@ -86,7 +86,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -114,6 +114,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/pk910/dynamic-ssz v0.0.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect @@ -129,6 +130,7 @@ require ( golang.org/x/net v0.10.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 6b0fd1e7566c..011f258b3c74 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= @@ -131,6 +133,8 @@ github.com/ethereum/go-verkle v0.1.1-0.20240306114018-819f7d81e58c h1:+6lz/7jTYZ github.com/ethereum/go-verkle v0.1.1-0.20240306114018-819f7d81e58c/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= +github.com/ethereum/go-verkle v0.1.1-0.20240710134556-4941876f32aa h1:y++iijsIJTH+K6vxdRmH2nwBPL6d6vwVuZ8DxQnKyqg= +github.com/ethereum/go-verkle v0.1.1-0.20240710134556-4941876f32aa/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -371,6 +375,8 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQm github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pk910/dynamic-ssz v0.0.4 h1:DT29+1055tCEPCaR4V/ez+MOKW7BzBsmjyFvBRqx0ME= +github.com/pk910/dynamic-ssz v0.0.4/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -533,6 +539,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -573,6 +581,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -639,6 +649,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/trie/verkle.go b/trie/verkle.go index f0568077fb35..fbbf9d33d67f 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -337,22 +337,22 @@ func DeserializeAndVerifyVerkleProof(vp *verkle.VerkleProof, preStateRoot []byte // TODO this should not be necessary, remove it // after the new proof generation code has stabilized. for _, stemdiff := range statediff { - for _, suffixdiff := range stemdiff.SuffixDiffs { + for i, suffix := range stemdiff.Suffixes { var key [32]byte copy(key[:31], stemdiff.Stem[:]) - key[31] = suffixdiff.Suffix + key[31] = suffix val, err := pretree.Get(key[:], nil) if err != nil { return fmt.Errorf("could not find key %x in tree rebuilt from proof: %w", key, err) } if len(val) > 0 { - if !bytes.Equal(val, suffixdiff.CurrentValue[:]) { - return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) + if !bytes.Equal(val, stemdiff.Current[i]) { + return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, stemdiff.Current[i]) } } else { - if suffixdiff.CurrentValue != nil && len(suffixdiff.CurrentValue) != 0 { - return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) + if stemdiff.Current[i] != nil && len(stemdiff.Current[i]) != 0 { + return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, stemdiff.Current[i]) } } }