From e8114e8415678e7f83cba61ece01cf9a0317e0e4 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 8 Feb 2022 08:07:23 +0100 Subject: [PATCH] copy the pre-state, use an untouched copy for the proof (#72) --- core/chain_makers.go | 44 ++++++++++++++++++++------------------------ miner/worker.go | 4 +++- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index b28c2f78dc10..11ae0b195ca8 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -295,6 +295,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} b.header = makeHeader(chainreader, parent, statedb, b.engine) + preState := statedb.Copy() // Mutate the state and block according to any hard-fork specs if daoBlock := config.DAOForkBlock; daoBlock != nil { @@ -329,30 +330,25 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine } // Generate an associated verkle proof - if tr := statedb.GetTrie(); tr.IsVerkle() { - vtr := tr.(*trie.VerkleTrie) - // Generate the proof if we are using a verkle tree - // WORKAROUND: make sure all keys are resolved - // before building the proof. Ultimately, node - // resolution can be done with a prefetcher or - // from GetCommitmentsAlongPath. - - keys := statedb.Witness().Keys() - for _, key := range keys { - out, err := vtr.TryGet(key) - if err != nil { - panic(err) - } - if len(out) == 0 { - panic(fmt.Sprintf("%x should be present in the tree", key)) - } - } - vtr.Hash() - p, k, err := vtr.ProveAndSerialize(keys, statedb.Witness().KeyVals()) - block.SetVerkleProof(p, k) - if err != nil { - panic(err) - } + tr := preState.GetTrie() + if !tr.IsVerkle() { + panic("tree should be verkle") + } + + vtr := tr.(*trie.VerkleTrie) + // Make sure all keys are resolved before + // building the proof. Ultimately, node + // resolution can be done with a prefetcher + // or from GetCommitmentsAlongPath. + keys := statedb.Witness().Keys() + for _, key := range keys { + vtr.TryGet(key) + } + vtr.Hash() + p, k, err := vtr.ProveAndSerialize(keys, statedb.Witness().KeyVals()) + block.SetVerkleProof(p, k) + if err != nil { + panic(err) } return block, b.receipts } diff --git a/miner/worker.go b/miner/worker.go index b35fd9ca3d99..5a329da527a3 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -82,6 +82,7 @@ type environment struct { signer types.Signer state *state.StateDB // apply state changes here + original *state.StateDB // verkle: keep the orignal data to prove the pre-state ancestors mapset.Set // ancestor set (used for checking uncle parent validity) family mapset.Set // family set (used for checking uncle invalidity) uncles mapset.Set // uncle set @@ -692,6 +693,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { env := &environment{ signer: types.MakeSigner(w.chainConfig, header.Number), state: state, + original: state.Copy(), ancestors: mapset.NewSet(), family: mapset.NewSet(), uncles: mapset.NewSet(), @@ -1039,7 +1041,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st if err != nil { return err } - if tr := s.GetTrie(); tr.IsVerkle() { + if tr := w.current.original.GetTrie(); tr.IsVerkle() { vtr := tr.(*trie.VerkleTrie) // Generate the proof if we are using a verkle tree p, k, err := vtr.ProveAndSerialize(s.Witness().Keys(), s.Witness().KeyVals())