diff --git a/beacon/engine/gen_ed.go b/beacon/engine/gen_ed.go index 6893d64a1626..2a92e7420407 100644 --- a/beacon/engine/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -17,23 +17,24 @@ var _ = (*executableDataMarshaling)(nil) // MarshalJSON marshals as JSON. func (e ExecutableData) MarshalJSON() ([]byte, error) { type ExecutableData struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ExecutionWitness *types.ExecutionWitness `json:"executionWitness"` } var enc ExecutableData enc.ParentHash = e.ParentHash @@ -58,29 +59,31 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { enc.Withdrawals = e.Withdrawals enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) + enc.ExecutionWitness = e.ExecutionWitness return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. func (e *ExecutableData) UnmarshalJSON(input []byte) error { type ExecutableData struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random *common.Hash `json:"prevRandao" gencodec:"required"` - Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash *common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random *common.Hash `json:"prevRandao" gencodec:"required"` + Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash *common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` + ExecutionWitness *types.ExecutionWitness `json:"executionWitness"` } var dec ExecutableData if err := json.Unmarshal(input, &dec); err != nil { @@ -154,5 +157,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { if dec.ExcessBlobGas != nil { e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) } + if dec.ExecutionWitness != nil { + e.ExecutionWitness = dec.ExecutionWitness + } return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index f1801edd1a93..0066e9181756 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -64,6 +64,8 @@ type ExecutableData struct { Withdrawals []*types.Withdrawal `json:"withdrawals"` BlobGasUsed *uint64 `json:"blobGasUsed"` ExcessBlobGas *uint64 `json:"excessBlobGas"` + + ExecutionWitness *types.ExecutionWitness `json:"executionWitness"` } // JSON type overrides for executableData. @@ -208,24 +210,25 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash) withdrawalsRoot = &h } header := &types.Header{ - ParentHash: params.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, - TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.LogsBloom), - Difficulty: common.Big0, - Number: new(big.Int).SetUint64(params.Number), - GasLimit: params.GasLimit, - GasUsed: params.GasUsed, - Time: params.Timestamp, - BaseFee: params.BaseFeePerGas, - Extra: params.ExtraData, - MixDigest: params.Random, - WithdrawalsHash: withdrawalsRoot, - ExcessBlobGas: params.ExcessBlobGas, - BlobGasUsed: params.BlobGasUsed, + ParentHash: params.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: params.FeeRecipient, + Root: params.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: params.ReceiptsRoot, + Bloom: types.BytesToBloom(params.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(params.Number), + GasLimit: params.GasLimit, + GasUsed: params.GasUsed, + Time: params.Timestamp, + BaseFee: params.BaseFeePerGas, + Extra: params.ExtraData, + MixDigest: params.Random, + WithdrawalsHash: withdrawalsRoot, + ExcessBlobGas: params.ExcessBlobGas, + BlobGasUsed: params.BlobGasUsed, + ExecutionWitness: params.ExecutionWitness, } block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) if block.Hash() != params.BlockHash { @@ -238,23 +241,24 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash) // fields from the given block. It assumes the given block is post-merge block. func BlockToExecutableData(block *types.Block, fees *big.Int, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *ExecutionPayloadEnvelope { data := &ExecutableData{ - BlockHash: block.Hash(), - ParentHash: block.ParentHash(), - FeeRecipient: block.Coinbase(), - StateRoot: block.Root(), - Number: block.NumberU64(), - GasLimit: block.GasLimit(), - GasUsed: block.GasUsed(), - BaseFeePerGas: block.BaseFee(), - Timestamp: block.Time(), - ReceiptsRoot: block.ReceiptHash(), - LogsBloom: block.Bloom().Bytes(), - Transactions: encodeTransactions(block.Transactions()), - Random: block.MixDigest(), - ExtraData: block.Extra(), - Withdrawals: block.Withdrawals(), - BlobGasUsed: block.BlobGasUsed(), - ExcessBlobGas: block.ExcessBlobGas(), + BlockHash: block.Hash(), + ParentHash: block.ParentHash(), + FeeRecipient: block.Coinbase(), + StateRoot: block.Root(), + Number: block.NumberU64(), + GasLimit: block.GasLimit(), + GasUsed: block.GasUsed(), + BaseFeePerGas: block.BaseFee(), + Timestamp: block.Time(), + ReceiptsRoot: block.ReceiptHash(), + LogsBloom: block.Bloom().Bytes(), + Transactions: encodeTransactions(block.Transactions()), + Random: block.MixDigest(), + ExtraData: block.Extra(), + Withdrawals: block.Withdrawals(), + BlobGasUsed: block.BlobGasUsed(), + ExcessBlobGas: block.ExcessBlobGas(), + ExecutionWitness: block.ExecutionWitness(), } blobsBundle := BlobsBundleV1{ Commitments: make([]hexutil.Bytes, 0), diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 1a3de04bd4d2..bf01c6f91857 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -171,9 +171,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideCancun.Name) cfg.Eth.OverrideCancun = &v } - if ctx.IsSet(utils.OverrideVerkle.Name) { - v := ctx.Uint64(utils.OverrideVerkle.Name) - cfg.Eth.OverrideVerkle = &v + if ctx.IsSet(utils.OverridePrague.Name) { + v := ctx.Uint64(utils.OverridePrague.Name) + cfg.Eth.OverridePrague = &v } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a239f88499a1..38fb755b4b5a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -68,7 +68,7 @@ var ( utils.USBFlag, utils.SmartCardDaemonPathFlag, utils.OverrideCancun, - utils.OverrideVerkle, + utils.OverridePrague, utils.EnablePersonal, utils.TxPoolLocalsFlag, utils.TxPoolNoLocalsFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c92f49d432b6..b927d0f94f83 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -268,8 +268,8 @@ var ( Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } - OverrideVerkle = &cli.Uint64Flag{ - Name: "override.verkle", + OverridePrague = &cli.Uint64Flag{ + Name: "override.prague", Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 64be7b0005d3..94b316f19757 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/utils" + "github.com/gballet/go-verkle" "github.com/holiman/uint256" ) @@ -329,14 +330,14 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [ // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the beacon protocol. The changes are done inline. -func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header, statedb *state.StateDB) error { // Transition isn't triggered yet, use the legacy rules for preparation. reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) if err != nil { return err } if !reached { - return beacon.ethone.Prepare(chain, header) + return beacon.ethone.Prepare(chain, header, statedb) } header.Difficulty = beaconDifficulty return nil @@ -356,9 +357,17 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. state.AddBalance(w.Address, amount) // The returned gas is not charged + state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.VersionLeafKey) state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.BalanceLeafKey) - } - // No block reward which is issued by consensus layer instead. + state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.NonceLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.CodeKeccakLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.CodeSizeLeafKey) + } + state.Witness().TouchAddressOnWriteAndComputeGas(header.Coinbase[:], uint256.Int{}, utils.VersionLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(header.Coinbase[:], uint256.Int{}, utils.BalanceLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(header.Coinbase[:], uint256.Int{}, utils.NonceLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(header.Coinbase[:], uint256.Int{}, utils.CodeKeccakLeafKey) + state.Witness().TouchAddressOnWriteAndComputeGas(header.Coinbase[:], uint256.Int{}, utils.CodeSizeLeafKey) } // FinalizeAndAssemble implements consensus.Engine, setting the final state and @@ -384,8 +393,65 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // Assign the final state root to header. header.Root = state.IntermediateRoot(true) + var ( + p *verkle.VerkleProof + k verkle.StateDiff + keys = state.Witness().Keys() + ) + if chain.Config().IsPrague(header.Number, header.Time) && chain.Config().ProofInBlock { + // 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) + } + + 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) + vtrpost, okpost = state.GetTrie().(*trie.VerkleTrie) + case *trie.TransitionTrie: + vtrpre = pre.Overlay() + okpre = true + post, _ := state.GetTrie().(*trie.TransitionTrie) + vtrpost = post.Overlay() + okpost = true + default: + panic("invalid tree type") + } + if okpre && okpost { + // Resolve values from the pre state, the post + // state should already have the values in memory. + // TODO: see if this can be captured at the witness + // level, like it used to. + for _, key := range keys { + _, err := vtrpre.GetWithHashedKey(key) + if err != nil { + panic(err) + } + } + + 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. - return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil + block := types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)) + if chain.Config().IsPrague(header.Number, header.Time) && chain.Config().ProofInBlock { + block.SetVerkleProof(p, k) + } + return block, nil } // Seal generates a new sealing request for the given input block and pushes diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index f708050abd13..23c7d32755b2 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -499,7 +499,7 @@ func (c *Clique) verifySeal(snap *Snapshot, header *types.Header, parents []*typ // Prepare implements consensus.Engine, preparing all the consensus fields of the // header for running the transactions on top. -func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header, _ *state.StateDB) error { // If the block isn't a checkpoint, cast a random vote (good enough for now) header.Coinbase = common.Address{} header.Nonce = types.BlockNonce{} diff --git a/consensus/consensus.go b/consensus/consensus.go index 3a2c2d222916..aa5ad43ede3d 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -81,7 +81,7 @@ type Engine interface { // Prepare initializes the consensus fields of a block header according to the // rules of a particular engine. The changes are executed inline. - Prepare(chain ChainHeaderReader, header *types.Header) error + Prepare(chain ChainHeaderReader, header *types.Header, state *state.StateDB) error // Finalize runs any post-transaction state modifications (e.g. block rewards // or process withdrawals) but does not assemble the block. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 92f8100f6e63..d155a3521cbc 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -479,7 +479,7 @@ var DynamicDifficultyCalculator = makeDifficultyCalculator // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the ethash protocol. The changes are done inline. -func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.Header, _ *state.StateDB) error { parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) if parent == nil { return consensus.ErrUnknownAncestor @@ -568,7 +568,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header r.Div(r, big8) // This should not happen, but it's useful for replay tests - if config.IsVerkle(header.Number, header.Time) { + if config.IsPrague(header.Number, header.Time) { state.Witness().TouchAddressOnReadAndComputeGas(uncle.Coinbase.Bytes(), uint256.Int{}, utils.BalanceLeafKey) } state.AddBalance(uncle.Coinbase, r) @@ -576,7 +576,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header r.Div(blockReward, big32) reward.Add(reward, r) } - if config.IsVerkle(header.Number, header.Time) { + if config.IsPrague(header.Number, header.Time) { state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.BalanceLeafKey) state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.VersionLeafKey) state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.NonceLeafKey) diff --git a/core/blockchain.go b/core/blockchain.go index b3513ff4cd72..27a74de822bf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -310,8 +310,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // Make sure the state associated with the block is available head := bc.CurrentBlock() - // Declare the end of the verkle transition is need be - if bc.chainConfig.Rules(head.Number, false /* XXX */, head.Time).IsVerkle { + // Declare the end of the verkle transition if need be + if bc.chainConfig.Rules(head.Number, false /* XXX */, head.Time).IsPrague { bc.stateCache.EndVerkleTransition() } @@ -411,7 +411,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis Recovery: recover, NoBuild: bc.cacheConfig.SnapshotNoBuild, AsyncBuild: !bc.cacheConfig.SnapshotWait, - Verkle: chainConfig.IsVerkle(head.Number, head.Time), + Verkle: chainConfig.IsPrague(head.Number, head.Time), } bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) } @@ -1347,6 +1347,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } + state.Database().TrieDB().WritePreimages() // Commit all cached state changes into underlying memory database. root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) if err != nil { @@ -2531,8 +2532,11 @@ func (bc *BlockChain) GetTrieFlushInterval() time.Duration { return time.Duration(bc.flushInterval.Load()) } -func (bc *BlockChain) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, cancunTime *uint64) { - bc.stateCache.StartVerkleTransition(originalRoot, translatedRoot, chainConfig, cancunTime) +func (bc *BlockChain) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64) { + bc.stateCache.StartVerkleTransition(originalRoot, translatedRoot, chainConfig, pragueTime) +} +func (bc *BlockChain) ReorgThroughVerkleTransition() { + bc.stateCache.ReorgThroughVerkleTransition() } func (bc *BlockChain) EndVerkleTransition() { diff --git a/core/chain_makers.go b/core/chain_makers.go index d2aaef260971..5d8ade8a0fb0 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -357,7 +357,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, if err != nil { panic(err) } - if genesis.Config != nil && genesis.Config.IsVerkle(genesis.ToBlock().Number(), genesis.ToBlock().Time()) { + if genesis.Config != nil && genesis.Config.IsPrague(genesis.ToBlock().Number(), genesis.ToBlock().Time()) { blocks, receipts, _, _ := GenerateVerkleChain(genesis.Config, genesis.ToBlock(), engine, db, n, gen) return db, blocks, receipts } @@ -372,8 +372,13 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine proofs := make([]*verkle.VerkleProof, 0, n) keyvals := make([]verkle.StateDiff, 0, n) blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) - chainreader := &fakeChainReader{config: config} - var preStateTrie *trie.VerkleTrie + chainreader := &generatedLinearChainReader{ + config: config, + // GenerateVerkleChain should only be called with the genesis block + // as parent. + genesis: parent, + chain: blocks, + } 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) @@ -412,48 +417,8 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine panic(fmt.Sprintf("trie write error: %v", err)) } - // Generate an associated verkle proof - 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. - kvs := make(map[string][]byte) - keys := statedb.Witness().Keys() - for _, key := range keys { - v, err := vtr.GetWithHashedKey(key) - if err != nil { - panic(err) - } - kvs[string(key)] = v - } - - // Initialize the preStateTrie if it is nil, this should - // correspond to the genesis block. This is a workaround - // needed until the main verkle PR is rebased on top of - // PBSS. - if preStateTrie == nil { - preStateTrie = vtr - } - - vtr.Hash() - p, k, err := preStateTrie.ProveAndSerialize(statedb.Witness().Keys()) - if err != nil { - panic(err) - } - proofs = append(proofs, p) - keyvals = append(keyvals, k) - - // save the current state of the trie for producing the proof for the next block, - // since reading it from disk is broken with the intermediate PBSS-like system we - // have: it will read the post-state as this is the only state present on disk. - // This is a workaround needed until the main verkle PR is rebased on top of PBSS. - preStateTrie = statedb.GetTrie().(*trie.VerkleTrie) + proofs = append(proofs, block.ExecutionWitness().VerkleProof) + keyvals = append(keyvals, block.ExecutionWitness().StateDiff) return block, b.receipts } @@ -558,3 +523,59 @@ func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil } + +type generatedLinearChainReader struct { + config *params.ChainConfig + genesis *types.Block + chain []*types.Block +} + +func (v *generatedLinearChainReader) Config() *params.ChainConfig { + return v.config +} + +func (v *generatedLinearChainReader) CurrentHeader() *types.Header { + return nil +} + +func (v *generatedLinearChainReader) GetHeader(_ common.Hash, number uint64) *types.Header { + if number == 0 { + return v.genesis.Header() + } + return v.chain[number-1].Header() +} + +func (v *generatedLinearChainReader) GetHeaderByNumber(number uint64) *types.Header { + if number == 0 { + return v.genesis.Header() + } + return v.chain[number-1].Header() +} + +func (v *generatedLinearChainReader) GetHeaderByHash(hash common.Hash) *types.Header { + if hash == v.genesis.Hash() { + return v.genesis.Header() + } + + for _, block := range v.chain { + if block.Hash() == hash { + return block.Header() + } + } + + return nil +} + +func (v *generatedLinearChainReader) GetBlock(_ common.Hash, number uint64) *types.Block { + if number == 0 { + return v.genesis + } + return v.chain[number-1] +} + +func (v *generatedLinearChainReader) GetTd(_ common.Hash, number uint64) *big.Int { + if number == 0 { + return v.genesis.Difficulty() + } + return v.chain[number-1].Difficulty() +} diff --git a/core/genesis.go b/core/genesis.go index 6b521369bcbe..6ea848508270 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -125,7 +125,7 @@ func (ga *GenesisAlloc) deriveHash(cfg *params.ChainConfig, timestamp uint64) (c // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. db := state.NewDatabase(rawdb.NewMemoryDatabase()) - if cfg.IsVerkle(big.NewInt(int64(0)), timestamp) { + if cfg.IsPrague(big.NewInt(int64(0)), timestamp) { db.EndVerkleTransition() } statedb, err := state.New(types.EmptyRootHash, db, nil) @@ -289,7 +289,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { OverrideCancun *uint64 - OverrideVerkle *uint64 + OverridePrague *uint64 } // SetupGenesisBlock writes or updates the genesis block in db. @@ -318,8 +318,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen if overrides != nil && overrides.OverrideCancun != nil { config.CancunTime = overrides.OverrideCancun } - if overrides != nil && overrides.OverrideVerkle != nil { - config.VerkleTime = overrides.OverrideVerkle + if overrides != nil && overrides.OverridePrague != nil { + config.PragueTime = overrides.OverridePrague } } } @@ -545,7 +545,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // Note the state changes will be committed in hash-based scheme, use Commit // if path-scheme is preferred. func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { - triedb := trie.NewDatabaseWithConfig(db, &trie.Config{Verkle: g.Config != nil && g.Config.IsVerkle(big.NewInt(int64(g.Number)), g.Timestamp)}) + triedb := trie.NewDatabaseWithConfig(db, &trie.Config{Verkle: g.Config != nil && g.Config.IsPrague(big.NewInt(int64(g.Number)), g.Timestamp)}) block, err := g.Commit(db, triedb) if err != nil { panic(err) diff --git a/core/state/database.go b/core/state/database.go index a7a7ef4dd78f..3caee28c8f33 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -67,6 +67,8 @@ type Database interface { StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, cancunTime *uint64) + ReorgThroughVerkleTransition() + EndVerkleTransition() InTransition() bool @@ -210,7 +212,7 @@ func (db *cachingDB) Transitioned() bool { } // Fork implements the fork -func (db *cachingDB) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, cancunTime *uint64) { +func (db *cachingDB) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64) { fmt.Println(` __________.__ .__ .__ __ .__ .__ ____ \__ ___| |__ ____ ____ | | ____ ______ | |__ _____ _____/ |_ | |__ _____ ______ __ _ _|__| ____ / ___\ ______ @@ -219,11 +221,18 @@ func (db *cachingDB) StartVerkleTransition(originalRoot, translatedRoot common.H |____| |___| /\___ \___ |____/\___ | __/|___| (____ |___| |__| |___| (____ /_____/ \/\_/ |__|___| /_____//_____/ |__|`) db.started = true - db.AddTranslation(originalRoot, translatedRoot) + db.ended = false + // db.AddTranslation(originalRoot, translatedRoot) db.baseRoot = originalRoot // initialize so that the first storage-less accounts are processed db.StorageProcessed = true - chainConfig.CancunTime = cancunTime + if pragueTime != nil { + chainConfig.PragueTime = pragueTime + } +} + +func (db *cachingDB) ReorgThroughVerkleTransition() { + db.ended, db.started = false, false } func (db *cachingDB) EndVerkleTransition() { @@ -241,25 +250,6 @@ func (db *cachingDB) EndVerkleTransition() { db.ended = true } -func (db *cachingDB) AddTranslation(orig, trans common.Hash) { - // TODO make this persistent - db.translatedRootsLock.Lock() - defer db.translatedRootsLock.Unlock() - db.translatedRoots[db.translationIndex] = trans - db.origRoots[db.translationIndex] = orig - db.translationIndex = (db.translationIndex + 1) % len(db.translatedRoots) -} - -func (db *cachingDB) getTranslation(orig common.Hash) common.Hash { - db.translatedRootsLock.RLock() - defer db.translatedRootsLock.RUnlock() - for i, o := range db.origRoots { - if o == orig { - return db.translatedRoots[i] - } - } - return common.Hash{} -} type cachingDB struct { disk ethdb.KeyValueStore @@ -320,13 +310,8 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // TODO separate both cases when I can be certain that it won't // find a Verkle trie where is expects a Transitoion trie. if db.started || db.ended { - var r common.Hash - if db.ended { - r = root - } else { - r = db.getTranslation(root) - } - vkt, err := db.openVKTrie(r) + // NOTE this is a kaustinen-only change, it will break replay + vkt, err := db.openVKTrie(root) if err != nil { return nil, err } @@ -512,7 +497,6 @@ func (db *cachingDB) GetStorageProcessed() bool { } func (db *cachingDB) AddRootTranslation(originalRoot, translatedRoot common.Hash) { - db.AddTranslation(originalRoot, translatedRoot) } func (db *cachingDB) SetLastMerkleRoot(root common.Hash) { diff --git a/core/state/statedb.go b/core/state/statedb.go index 48d2a8e509db..e5c6669da751 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -191,12 +191,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) } if sdb.snaps != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap == nil { - if db, ok := db.(*cachingDB); ok { - trans := db.getTranslation(root) - if trans != (common.Hash{}) { - sdb.snap = sdb.snaps.Snapshot(trans) - } - } } } return sdb, nil diff --git a/core/state_processor_test.go b/core/state_processor_test.go index ffb3285b8f91..77088f86faa6 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -451,9 +451,10 @@ func TestProcessVerkle(t *testing.T) { LondonBlock: big.NewInt(0), Ethash: new(params.EthashConfig), ShanghaiTime: u64(0), - VerkleTime: u64(0), + PragueTime: u64(0), TerminalTotalDifficulty: common.Big0, TerminalTotalDifficultyPassed: true, + ProofInBlock: true, } signer = types.LatestSigner(config) testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") diff --git a/core/state_transition.go b/core/state_transition.go index 14dd86e4987d..2bdfef1c0552 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -403,7 +403,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } st.gasRemaining -= gas - if rules.IsVerkle { + if rules.IsPrague { targetAddr := msg.To originAddr := msg.From diff --git a/core/types/block.go b/core/types/block.go index 4452f4bb21f8..a704d23043ca 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rlp" + "github.com/gballet/go-verkle" ) // A BlockNonce is a 64-bit hash which proves (combined with the @@ -58,6 +59,18 @@ func (n *BlockNonce) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("BlockNonce", input, n[:]) } +type ExecutionWitness struct { + StateDiff verkle.StateDiff `json:"stateDiff"` + VerkleProof *verkle.VerkleProof `json:"verkleProof"` +} + +func (ew *ExecutionWitness) Copy() *ExecutionWitness { + return &ExecutionWitness{ + StateDiff: ew.StateDiff.Copy(), + VerkleProof: ew.VerkleProof.Copy(), + } +} + //go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go //go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go @@ -90,6 +103,8 @@ type Header struct { // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` + + ExecutionWitness *ExecutionWitness `json:"executionWitness" rlp:"-"` } // field type overrides for gencodec @@ -292,6 +307,10 @@ func CopyHeader(h *Header) *Header { cpy.BlobGasUsed = new(uint64) *cpy.BlobGasUsed = *h.BlobGasUsed } + if h.ExecutionWitness != nil { + cpy.ExecutionWitness = h.ExecutionWitness.Copy() + + } return &cpy } @@ -380,6 +399,8 @@ func (b *Block) BlobGasUsed() *uint64 { func (b *Block) Header() *Header { return CopyHeader(b.header) } +func (b *Block) ExecutionWitness() *ExecutionWitness { return b.header.ExecutionWitness } + // Body returns the non-header content of the block. func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.withdrawals} } @@ -401,6 +422,18 @@ func (b *Block) SanityCheck() error { return b.header.SanityCheck() } +func (b *Block) SetVerkleProof(vp *verkle.VerkleProof, statediff verkle.StateDiff) { + b.header.ExecutionWitness = &ExecutionWitness{statediff, vp} + if statediff == nil { + b.header.ExecutionWitness.StateDiff = []verkle.StemStateDiff{} + } + if vp == nil { + b.header.ExecutionWitness.VerkleProof = &verkle.VerkleProof{ + IPAProof: &verkle.IPAProof{}, + } + } +} + type writeCounter uint64 func (c *writeCounter) Write(b []byte) (int, error) { diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 2942755f3fae..036d18a078fe 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -150,7 +150,7 @@ func init() { // ActivePrecompiles returns the precompiles enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { switch { - case rules.IsVerkle: + case rules.IsPrague: return PrecompiledAddressesBerlin case rules.IsCancun: return PrecompiledAddressesCancun diff --git a/core/vm/evm.go b/core/vm/evm.go index 73c3c2150617..36bd6f32f8f7 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,7 +41,7 @@ type ( func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { - case evm.chainRules.IsVerkle: + case evm.chainRules.IsPrague: precompiles = PrecompiledContractsBerlin case evm.chainRules.IsCancun: precompiles = PrecompiledContractsCancun @@ -137,7 +137,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } - if txCtx.Accesses == nil && chainConfig.IsVerkle(blockCtx.BlockNumber, blockCtx.Time) { + if txCtx.Accesses == nil && chainConfig.IsPrague(blockCtx.BlockNumber, blockCtx.Time) { txCtx.Accesses = evm.StateDB.(*state.StateDB).NewAccessWitness() } evm.interpreter = NewEVMInterpreter(evm) @@ -147,7 +147,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig // Reset resets the EVM with a new transaction context.Reset // This is not threadsafe and should only be done very cautiously. func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { - if txCtx.Accesses == nil && evm.chainRules.IsVerkle { + if txCtx.Accesses == nil && evm.chainRules.IsPrague { txCtx.Accesses = evm.StateDB.(*state.StateDB).NewAccessWitness() } evm.TxContext = txCtx @@ -212,7 +212,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas var creation bool if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { // proof of absence tryConsumeGas(&gas, evm.Accesses.TouchAndChargeProofOfAbsence(caller.Address().Bytes())) } @@ -529,7 +529,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if err == nil && evm.chainRules.IsVerkle { + if err == nil && evm.chainRules.IsPrague { if !contract.UseGas(evm.Accesses.TouchAndChargeContractCreateCompleted(address.Bytes()[:])) { evm.StateDB.RevertToSnapshot(snapshot) err = ErrOutOfGas diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index dc307b82904d..f367c3c92978 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -101,7 +101,7 @@ var ( func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { usedGas := uint64(0) slot := stack.Back(0) - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { usedGas += evm.TxContext.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeSizeLeafKey) } @@ -111,7 +111,7 @@ func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem func gasSLoad(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { usedGas := uint64(0) - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { where := stack.Back(0) treeIndex, subIndex := trieUtils.GetTreeKeyStorageSlotTreeIndexes(where.Bytes()) usedGas += evm.Accesses.TouchAddressOnReadAndComputeGas(contract.Address().Bytes(), *treeIndex, subIndex) @@ -423,7 +423,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { if _, isPrecompile := evm.precompile(address); !isPrecompile { gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes()[:])) if overflow { @@ -463,7 +463,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { address := common.Address(stack.Back(1).Bytes20()) if _, isPrecompile := evm.precompile(address); !isPrecompile { gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes())) @@ -488,7 +488,7 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { address := common.Address(stack.Back(1).Bytes20()) if _, isPrecompile := evm.precompile(address); !isPrecompile { gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes())) @@ -513,7 +513,7 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { address := common.Address(stack.Back(1).Bytes20()) if _, isPrecompile := evm.precompile(address); !isPrecompile { gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes())) @@ -542,7 +542,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me } } - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { // TODO turn this into a panic (when we are sure this method // will never execute when verkle is enabled) log.Warn("verkle witness accumulation not supported for selfdestruct") diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 13252eda9df9..84edacb1b9bc 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -345,7 +345,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() cs := uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())) - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeSizeLeafKey) scope.Contract.UseGas(statelessGas) } @@ -373,7 +373,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ contractAddr := scope.Contract.Address() paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64()) - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { scope.Contract.UseGas(touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], copyOffset, nonPaddedCopyLength, uint64(len(scope.Contract.Code)), interpreter.evm.Accesses)) } scope.Memory.Set(memOffset.Uint64(), uint64(len(paddedCodeCopy)), paddedCodeCopy) @@ -426,7 +426,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = 0xffffffffffffffff } addr := common.Address(a.Bytes20()) - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { code := interpreter.evm.StateDB.GetCode(addr) contract := &Contract{ Code: code, @@ -641,7 +641,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) gas = scope.Contract.Gas ) - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { contractAddress := crypto.CreateAddress(scope.Contract.Address(), interpreter.evm.StateDB.GetNonce(scope.Contract.Address())) statelessGas := interpreter.evm.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], value.Sign() != 0) if !tryConsumeGas(&gas, statelessGas) { @@ -695,7 +695,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) gas = scope.Contract.Gas ) - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { codeAndHash := &codeAndHash{code: input} contractAddress := crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) statelessGas := interpreter.evm.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], endowment.Sign() != 0) @@ -959,7 +959,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by if *pc < codeLen { scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc]))) - if interpreter.evm.chainRules.IsVerkle && *pc%31 == 0 { + if interpreter.evm.chainRules.IsPrague && *pc%31 == 0 { // touch next chunk if PUSH1 is at the boundary. if so, *pc has // advanced past this boundary. contractAddr := scope.Contract.Address() @@ -987,7 +987,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { endMin = startMin + pushByteSize } - if interpreter.evm.chainRules.IsVerkle { + if interpreter.evm.chainRules.IsPrague { contractAddr := scope.Contract.Address() statelessGas := touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], uint64(startMin), uint64(pushByteSize), uint64(len(scope.Contract.Code)), interpreter.evm.Accesses) scope.Contract.UseGas(statelessGas) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index ad4222b447b7..1b980ccb131d 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -56,7 +56,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. var table *JumpTable switch { - case evm.chainRules.IsVerkle: + case evm.chainRules.IsPrague: // TODO replace with prooper instruction set when fork is specified table = &shanghaiInstructionSet case evm.chainRules.IsCancun: diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index 75bcb8d5bf9e..2ceb75e73273 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -26,11 +26,8 @@ import ( // the rules. func LookupInstructionSet(rules params.Rules) (JumpTable, error) { switch { - case rules.IsVerkle: - // TODO set to newCancunInstructionSet() when verkle-fork is defined - return newShanghaiInstructionSet(), errors.New("verkle-fork not defined yet") case rules.IsPrague: - return newCancunInstructionSet(), errors.New("prague-fork not defined yet") + return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet") case rules.IsCancun: return newCancunInstructionSet(), nil case rules.IsShanghai: diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 7d2296c4dc01..4d4fe8aed3e6 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -52,7 +52,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { } value := common.Hash(y.Bytes32()) - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { treeIndex, subIndex := utils.GetTreeKeyStorageSlotTreeIndexes(x.Bytes()) cost += evm.Accesses.TouchAddressOnWriteAndComputeGas(contract.Address().Bytes(), *treeIndex, subIndex) } @@ -111,7 +111,7 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me slot := common.Hash(loc.Bytes32()) var gasUsed uint64 - if evm.chainRules.IsVerkle { + if evm.chainRules.IsPrague { where := stack.Back(0) treeIndex, subIndex := utils.GetTreeKeyStorageSlotTreeIndexes(where.Bytes()) addr := contract.Address() diff --git a/eth/backend.go b/eth/backend.go index 667200bcedda..a6c80159077d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -198,8 +198,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideCancun != nil { overrides.OverrideCancun = config.OverrideCancun } - if config.OverrideVerkle != nil { - overrides.OverrideVerkle = config.OverrideVerkle + if config.OverridePrague != nil { + overrides.OverridePrague = config.OverridePrague } eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 1a221941427a..63079415fc14 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -528,6 +528,17 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time()) return api.invalid(errors.New("invalid timestamp"), parent.Header()), nil } + // Trigger the start of the verkle conversion if we're at the right block + if api.eth.BlockChain().Config().IsPrague(block.Number(), block.Time()) && !api.eth.BlockChain().Config().IsPrague(parent.Number(), parent.Time()) { + parent := api.eth.BlockChain().GetHeaderByNumber(block.NumberU64() - 1) + if !api.eth.BlockChain().Config().IsPrague(parent.Number, parent.Time) { + api.eth.BlockChain().StartVerkleTransition(parent.Root, common.Hash{}, api.eth.BlockChain().Config(), nil) + } + } + // Reset db merge state in case of a reorg + if !api.eth.BlockChain().Config().IsPrague(block.Number(), block.Time()) { + api.eth.BlockChain().ReorgThroughVerkleTransition() + } // Another cornercase: if the node is in snap sync mode, but the CL client // tries to make it import a block. That should be denied as pushing something // into the database directly will conflict with the assumptions of snap sync diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 4bc8b8dc6c6e..4606b60408dd 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -157,7 +157,7 @@ type Config struct { OverrideCancun *uint64 `toml:",omitempty"` // OverrideVerkle (TODO: remove after the fork) - OverrideVerkle *uint64 `toml:",omitempty"` + OverridePrague *uint64 `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain config. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 324fbe380ea3..2ad499a53485 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -52,7 +52,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCEVMTimeout time.Duration RPCTxFeeCap float64 OverrideCancun *uint64 `toml:",omitempty"` - OverrideVerkle *uint64 `toml:",omitempty"` + OverridePrague *uint64 `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -90,7 +90,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap enc.OverrideCancun = c.OverrideCancun - enc.OverrideVerkle = c.OverrideVerkle + enc.OverridePrague = c.OverridePrague return &enc, nil } @@ -132,7 +132,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 OverrideCancun *uint64 `toml:",omitempty"` - OverrideVerkle *uint64 `toml:",omitempty"` + OverridePrague *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -243,8 +243,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideCancun != nil { c.OverrideCancun = dec.OverrideCancun } - if dec.OverrideVerkle != nil { - c.OverrideVerkle = dec.OverrideVerkle + if dec.OverridePrague != nil { + c.OverridePrague = dec.OverridePrague } return nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 740a38ab9fbf..5e90180df8d5 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -1020,10 +1020,6 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.PragueTime = timestamp canon = false } - if timestamp := override.VerkleTime; timestamp != nil { - copy.VerkleTime = timestamp - canon = false - } return copy, canon } diff --git a/go.mod b/go.mod index c133d4bd5ba4..77651a84e427 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,8 @@ require ( github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 - github.com/consensys/gnark-crypto v0.10.0 + github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a + github.com/crate-crypto/go-ipa v0.0.0-20230914135612-d1b03fcb8e58 github.com/crate-crypto/go-kzg-4844 v0.3.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 @@ -25,7 +26,7 @@ require ( github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20230725193842-b2d852dc666b + github.com/gballet/go-verkle v0.1.1-0.20230921123936-6a6b1f7a751c github.com/go-stack/stack v1.8.1 github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 @@ -56,17 +57,17 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.24.1 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.9.0 + golang.org/x/crypto v0.10.0 golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/sync v0.3.0 - golang.org/x/sys v0.10.0 - golang.org/x/text v0.9.0 + golang.org/x/sys v0.12.0 + golang.org/x/text v0.10.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.9.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0 @@ -85,14 +86,13 @@ 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.7.0 // indirect + github.com/bits-and-blooms/bitset v1.8.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 github.com/cockroachdb/redact v1.1.3 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/crate-crypto/go-ipa v0.0.0-20230710183535-d5eb1c4661bd // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect diff --git a/go.sum b/go.sum index 47603d0dbc18..fb217e376795 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,8 @@ github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 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.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= +github.com/bits-and-blooms/bitset v1.8.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= @@ -75,8 +75,10 @@ github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= -github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.11.2 h1:GJjjtWJ+db1xGao7vTsOgAOGgjfPe7eRGPL+xxMX0qE= +github.com/consensys/gnark-crypto v0.11.2/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a h1:Rc86uLASrW3xpeWRH8V9W23v5QYegI/wjgbZzwPiC44= +github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -84,10 +86,14 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc 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-20230601170251-1830d0757c80 h1:DuBDHVjgGMPki7bAyh91+3cF1Vh34sAEdH8JQgbc2R0= -github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= -github.com/crate-crypto/go-ipa v0.0.0-20230710183535-d5eb1c4661bd h1:jgf65Q4+jHFuLlhVApaVfTUwcU7dAdXK+GESow2UlaI= -github.com/crate-crypto/go-ipa v0.0.0-20230710183535-d5eb1c4661bd/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= +github.com/crate-crypto/go-ipa v0.0.0-20230904185759-9f7637e8ddd0 h1:MztzKYOxMeC8HlWGXvq2wizas+QT0FgITjGThfmbh/0= +github.com/crate-crypto/go-ipa v0.0.0-20230904185759-9f7637e8ddd0/go.mod h1:7fZtshzGQ3dxVpDpF51K9mX8oziq8Xd5AoM/UT9fF5o= +github.com/crate-crypto/go-ipa v0.0.0-20230905211650-63ccabc1a949 h1:m73KBJvYRMuaUth425v6nKeEu6GSq9Zij01+jc2r2Y0= +github.com/crate-crypto/go-ipa v0.0.0-20230905211650-63ccabc1a949/go.mod h1:7fZtshzGQ3dxVpDpF51K9mX8oziq8Xd5AoM/UT9fF5o= +github.com/crate-crypto/go-ipa v0.0.0-20230911163631-de5e505e95bf h1:DwDzUJSm6lD9geUNtNQmMdfuNMo9ucHEVzY2aLkYUI8= +github.com/crate-crypto/go-ipa v0.0.0-20230911163631-de5e505e95bf/go.mod h1:J+gsi6D4peY0kyhaklyXFRVHOQWI2I5uU0c2+/90HYc= +github.com/crate-crypto/go-ipa v0.0.0-20230914135612-d1b03fcb8e58 h1:PwUlswsGOrLB677lW4XrlWLeszY3BaDGbvZ6dYk28tQ= +github.com/crate-crypto/go-ipa v0.0.0-20230914135612-d1b03fcb8e58/go.mod h1:J+gsi6D4peY0kyhaklyXFRVHOQWI2I5uU0c2+/90HYc= github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -146,10 +152,24 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILD github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= 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-20230607174250-df487255f46b h1:vMT47RYsrftsHSTQhqXwC3BYflo38OLC3Y4LtXtLyU0= -github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b/go.mod h1:CDncRYVRSDqwakm282WEkjfaAj1hxU/v5RXxk5nXOiI= -github.com/gballet/go-verkle v0.0.0-20230725193842-b2d852dc666b h1:2lDzSxjCii8FxrbuxtlFtFiw6c4nTPl9mhaZ6lgpwws= -github.com/gballet/go-verkle v0.0.0-20230725193842-b2d852dc666b/go.mod h1:+k9fzNguudDonU5q4/TUaTdmiHw3h3oGOIVmqyhaA3E= +github.com/gballet/go-verkle v0.0.0-20230905121642-6764a0cc51cf h1:nEiCdFdoQz4rDn5URrMOVira10+rLvJ82PfEbkMF3jo= +github.com/gballet/go-verkle v0.0.0-20230905121642-6764a0cc51cf/go.mod h1:vYx+8/EoJeRLJ3R5sCVhmAdpsZIqzxF6Tr5p+8kbJrg= +github.com/gballet/go-verkle v0.0.0-20230905122518-d220d72630e6 h1:o1G+rbcG/jWZWv+kWwwvE+TmFwXamUDEbvMUA6xR5fk= +github.com/gballet/go-verkle v0.0.0-20230905122518-d220d72630e6/go.mod h1:TPmzzGQJd4ZZxR3+hIn6SGnm9aYauFHkuYCOcTvzI6A= +github.com/gballet/go-verkle v0.0.0-20230906092655-319e750ea891 h1:nsdB5gaCl3J98ZRGHCDy3LSomfpY4fA5BvGa3Ux1e4A= +github.com/gballet/go-verkle v0.0.0-20230906092655-319e750ea891/go.mod h1:TPmzzGQJd4ZZxR3+hIn6SGnm9aYauFHkuYCOcTvzI6A= +github.com/gballet/go-verkle v0.0.0-20230906110906-5ce291aceda2 h1:qxP6c7XUjMScf/IzBJc3LdJ7+94UsVJJlYmowCqGkFQ= +github.com/gballet/go-verkle v0.0.0-20230906110906-5ce291aceda2/go.mod h1:g5tqVx8nLwDrC6Gki3pTRO4+VgusEMBJnDaQvi3A15g= +github.com/gballet/go-verkle v0.0.0-20230911184846-b1cb716e965e h1:Lw+ErC384jjxEqPekDeMbsQUuFHe9U9P/j2/wa11d1w= +github.com/gballet/go-verkle v0.0.0-20230911184846-b1cb716e965e/go.mod h1:g5tqVx8nLwDrC6Gki3pTRO4+VgusEMBJnDaQvi3A15g= +github.com/gballet/go-verkle v0.0.0-20230912081326-5a9b0c7bda0d h1:lJ+5o6tMVteFMFSaYw5P8T+s8jt2DMyBV7GvUZduozo= +github.com/gballet/go-verkle v0.0.0-20230912081326-5a9b0c7bda0d/go.mod h1:7JamHhSTnnHDhcI3G8r4sWaD9XlleriqVlC3FeAQJKM= +github.com/gballet/go-verkle v0.1.0 h1:DNQjU+M3fgbZR/rbiPban4oLl5T3bfijejmRHwwT6n0= +github.com/gballet/go-verkle v0.1.0/go.mod h1:7JamHhSTnnHDhcI3G8r4sWaD9XlleriqVlC3FeAQJKM= +github.com/gballet/go-verkle v0.1.1-0.20230921123058-fb04943e860f h1:v/wHViCd+qLWSoEB0fXhVds68lB/iFJc3vglb05fOCw= +github.com/gballet/go-verkle v0.1.1-0.20230921123058-fb04943e860f/go.mod h1:7JamHhSTnnHDhcI3G8r4sWaD9XlleriqVlC3FeAQJKM= +github.com/gballet/go-verkle v0.1.1-0.20230921123936-6a6b1f7a751c h1:sa+wcZ/O1bvCd4Zr5OJvKlvDSdwtNSXrgKxw48t3GPs= +github.com/gballet/go-verkle v0.1.1-0.20230921123936-6a6b1f7a751c/go.mod h1:7JamHhSTnnHDhcI3G8r4sWaD9XlleriqVlC3FeAQJKM= 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/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= @@ -306,7 +326,6 @@ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4F github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -428,8 +447,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b h1:u49mjRnygnB34h8OKbnNJFVUtWSKIKb1KukdV8bILUM= github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -480,8 +499,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= @@ -534,7 +553,6 @@ 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -569,17 +587,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/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-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= @@ -591,8 +606,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= diff --git a/les/client.go b/les/client.go index 132c857aa529..691635be0c59 100644 --- a/les/client.go +++ b/les/client.go @@ -95,8 +95,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if config.OverrideCancun != nil { overrides.OverrideCancun = config.OverrideCancun } - if config.OverrideVerkle != nil { - overrides.OverrideVerkle = config.OverrideVerkle + if config.OverridePrague != nil { + overrides.OverridePrague = config.OverridePrague } chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { diff --git a/light/trie.go b/light/trie.go index e0a283fdc1d7..53d54615d909 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,6 +105,10 @@ func (db *odrDatabase) StartVerkleTransition(originalRoot common.Hash, translate panic("not implemented") // TODO: Implement } +func (db *odrDatabase) ReorgThroughVerkleTransition() { + panic("not implemented") // TODO: Implement +} + func (db *odrDatabase) EndVerkleTransition() { panic("not implemented") // TODO: Implement } diff --git a/miner/worker.go b/miner/worker.go index 81aeb1d81388..8568abf37691 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -697,13 +697,7 @@ func (w *worker) resultLoop() { } // makeEnv creates a new environment for the sealing block. -func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { - // Retrieve the parent state to execute on top and start a prefetcher for - // the miner to speed block sealing up a bit. - state, err := w.chain.StateAt(parent.Root) - if err != nil { - return nil, err - } +func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, state *state.StateDB) (*environment, error) { state.StartPrefetcher("miner") // Note the passed coinbase may be different with header.Coinbase. @@ -895,15 +889,33 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) } } + + // Trigger the start of the verkle conversion if we're at the right block + if w.chain.Config().IsPrague(header.Number, header.Time) { + parent := w.chain.GetHeaderByNumber(header.Number.Uint64() - 1) + if !w.chain.Config().IsPrague(parent.Number, parent.Time) { + w.chain.StartVerkleTransition(parent.Root, common.Hash{}, w.chain.Config(), nil) + } + } + + // Retrieve the parent state to execute on top and start a prefetcher for + // the miner to speed block sealing up a bit. + state, err := w.chain.StateAt(parent.Root) + if err != nil { + return nil, err + } + if w.chain.Config().IsPrague(header.Number, header.Time) { + core.OverlayVerkleTransition(state) + } // Run the consensus preparation with the default or customized consensus engine. - if err := w.engine.Prepare(w.chain, header); err != nil { + if err := w.engine.Prepare(w.chain, header, state); err != nil { log.Error("Failed to prepare header for sealing", "err", err) return nil, err } // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. - env, err := w.makeEnv(parent, header, genParams.coinbase) + env, err := w.makeEnv(parent, header, genParams.coinbase, state) if err != nil { log.Error("Failed to create sealing context", "err", err) return nil, err diff --git a/params/config.go b/params/config.go index 75c8fd89d09f..0eb882a56ae6 100644 --- a/params/config.go +++ b/params/config.go @@ -128,7 +128,6 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, - VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: true, Ethash: new(EthashConfig), @@ -179,7 +178,6 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, - VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, Ethash: nil, @@ -209,7 +207,6 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, - VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, Ethash: new(EthashConfig), @@ -239,7 +236,6 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, - VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, Ethash: new(EthashConfig), @@ -289,7 +285,6 @@ type ChainConfig struct { ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) - VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -304,6 +299,9 @@ type ChainConfig struct { Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` IsDevMode bool `json:"isDev,omitempty"` + + // Proof in block + ProofInBlock bool `json:"proofInBlock,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -411,9 +409,6 @@ func (c *ChainConfig) Description() string { if c.PragueTime != nil { banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) } - if c.VerkleTime != nil { - banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime) - } return banner } @@ -512,11 +507,6 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } -// IsVerkle returns whether num is either equal to the Verkle fork time or greater. -func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { - return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) -} - // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { @@ -571,7 +561,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "shanghaiTime", timestamp: c.ShanghaiTime}, {name: "cancunTime", timestamp: c.CancunTime, optional: true}, {name: "pragueTime", timestamp: c.PragueTime, optional: true}, - {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, } { if lastFork.name != "" { switch { @@ -675,9 +664,6 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) { return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) } - if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { - return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) - } return nil } @@ -823,7 +809,6 @@ type Rules struct { IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool IsMerge, IsShanghai, IsCancun, IsPrague bool - IsVerkle bool } // Rules ensures c's ChainID is not nil. @@ -848,6 +833,5 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsShanghai: c.IsShanghai(num, timestamp), IsCancun: c.IsCancun(num, timestamp), IsPrague: c.IsPrague(num, timestamp), - IsVerkle: c.IsVerkle(num, timestamp), } } diff --git a/trie/transition.go b/trie/transition.go index ad5a7dc70152..083aa57db1ac 100644 --- a/trie/transition.go +++ b/trie/transition.go @@ -174,7 +174,7 @@ func (t *TransitionTrie) UpdateStem(key []byte, values [][]byte) error { trie := t.overlay switch root := trie.root.(type) { case *verkle.InternalNode: - return root.InsertStem(key, values, t.overlay.flatdbNodeResolver) + return root.InsertStem(key, values, t.overlay.FlatdbNodeResolver) default: panic("invalid root type") } diff --git a/trie/utils/verkle_test.go b/trie/utils/verkle_test.go index 744df9df26ac..f0a0ed7d2894 100644 --- a/trie/utils/verkle_test.go +++ b/trie/utils/verkle_test.go @@ -51,7 +51,7 @@ func TestConstantPoint(t *testing.T) { verkle.FromLEBytes(&expectedPoly[0], []byte{2, 64}) expected := cfg.CommitToPoly(expectedPoly[:], 1) - if !verkle.Equal(expected, getTreePolyIndex0Point) { + if !expected.Equal(getTreePolyIndex0Point) { t.Fatalf("Marshalled constant value is incorrect: %x != %x", expected.Bytes(), getTreePolyIndex0Point.Bytes()) } } diff --git a/trie/verkle.go b/trie/verkle.go index baf9fde541ac..174ebfce2306 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -54,12 +54,12 @@ func NewVerkleTrie(root verkle.VerkleNode, db *Database, pointCache *utils.Point } } -func (trie *VerkleTrie) flatdbNodeResolver(path []byte) ([]byte, error) { +func (trie *VerkleTrie) FlatdbNodeResolver(path []byte) ([]byte, error) { return trie.db.diskdb.Get(append(FlatDBVerkleNodeKeyPrefix, path...)) } func (trie *VerkleTrie) InsertMigratedLeaves(leaves []verkle.LeafNode) error { - return trie.root.(*verkle.InternalNode).InsertMigratedLeaves(leaves, trie.flatdbNodeResolver) + return trie.root.(*verkle.InternalNode).InsertMigratedLeaves(leaves, trie.FlatdbNodeResolver) } var ( @@ -90,13 +90,13 @@ func (trie *VerkleTrie) GetKey(key []byte) []byte { func (trie *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { pointEval := trie.pointCache.GetTreeKeyHeader(addr[:]) k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(pointEval, key) - return trie.root.Get(k, trie.flatdbNodeResolver) + return trie.root.Get(k, trie.FlatdbNodeResolver) } // 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.flatdbNodeResolver) + return trie.root.Get(key, trie.FlatdbNodeResolver) } func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error) { @@ -108,7 +108,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error ) switch t.root.(type) { case *verkle.InternalNode: - values, err = t.root.(*verkle.InternalNode).GetStem(versionkey[:31], t.flatdbNodeResolver) + values, err = t.root.(*verkle.InternalNode).GetStem(versionkey[:31], t.FlatdbNodeResolver) default: return nil, errInvalidRootType } @@ -177,7 +177,7 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) switch root := t.root.(type) { case *verkle.InternalNode: - err = root.InsertStem(stem, values, t.flatdbNodeResolver) + err = root.InsertStem(stem, values, t.FlatdbNodeResolver) default: return errInvalidRootType } @@ -192,7 +192,7 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) func (trie *VerkleTrie) UpdateStem(key []byte, values [][]byte) error { switch root := trie.root.(type) { case *verkle.InternalNode: - return root.InsertStem(key, values, trie.flatdbNodeResolver) + return root.InsertStem(key, values, trie.FlatdbNodeResolver) default: panic("invalid root type") } @@ -210,7 +210,7 @@ func (trie *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) } else { copy(v[32-len(value):], value[:]) } - return trie.root.Insert(k, v[:], trie.flatdbNodeResolver) + return trie.root.Insert(k, v[:], trie.FlatdbNodeResolver) } func (t *VerkleTrie) DeleteAccount(addr common.Address) error { @@ -226,7 +226,7 @@ func (t *VerkleTrie) DeleteAccount(addr common.Address) error { switch root := t.root.(type) { case *verkle.InternalNode: - err = root.InsertStem(stem, values, t.flatdbNodeResolver) + err = root.InsertStem(stem, values, t.FlatdbNodeResolver) default: return errInvalidRootType } @@ -244,7 +244,7 @@ func (trie *VerkleTrie) DeleteStorage(addr common.Address, key []byte) error { pointEval := trie.pointCache.GetTreeKeyHeader(addr[:]) k := utils.GetTreeKeyStorageSlotWithEvaluatedAddress(pointEval, key) var zero [32]byte - return trie.root.Insert(k, zero[:], trie.flatdbNodeResolver) + return trie.root.Insert(k, zero[:], trie.FlatdbNodeResolver) } // Hash returns the root hash of the trie. It does not write to the database and @@ -311,8 +311,9 @@ func (trie *VerkleTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { func (trie *VerkleTrie) Copy() *VerkleTrie { return &VerkleTrie{ - root: trie.root.Copy(), - db: trie.db, + root: trie.root.Copy(), + db: trie.db, + pointCache: trie.pointCache, } } @@ -320,8 +321,12 @@ func (trie *VerkleTrie) IsVerkle() bool { return true } -func (trie *VerkleTrie) ProveAndSerialize(keys [][]byte) (*verkle.VerkleProof, verkle.StateDiff, error) { - proof, _, _, _, err := verkle.MakeVerkleMultiProof(trie.root, keys) +func ProveAndSerialize(pretrie, posttrie *VerkleTrie, keys [][]byte, resolver verkle.NodeResolverFn) (*verkle.VerkleProof, verkle.StateDiff, error) { + var postroot verkle.VerkleNode + if posttrie != nil { + postroot = posttrie.root + } + proof, _, _, _, err := verkle.MakeVerkleMultiProof(pretrie.root, postroot, keys, resolver) if err != nil { return nil, nil, err } @@ -342,69 +347,53 @@ func addKey(s set, key []byte) { func DeserializeAndVerifyVerkleProof(vp *verkle.VerkleProof, root []byte, statediff verkle.StateDiff) error { rootC := new(verkle.Point) - rootC.SetBytesTrusted(root) - proof, cis, indices, yis, err := deserializeVerkleProof(vp, rootC, statediff) - if err != nil { - return fmt.Errorf("could not deserialize proof: %w", err) - } - cfg := verkle.GetConfig() - if !verkle.VerifyVerkleProof(proof, cis, indices, yis, cfg) { - return errInvalidProof - } + rootC.SetBytes(root) - return nil -} - -func deserializeVerkleProof(vp *verkle.VerkleProof, rootC *verkle.Point, statediff verkle.StateDiff) (*verkle.Proof, []*verkle.Point, []byte, []*verkle.Fr, error) { var others set = set{} // Mark when an "other" stem has been seen proof, err := verkle.DeserializeProof(vp, statediff) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("verkle proof deserialization error: %w", err) + return fmt.Errorf("verkle proof deserialization error: %w", err) } for _, stem := range proof.PoaStems { addKey(others, stem) } - if len(proof.Keys) != len(proof.Values) { - return nil, nil, nil, nil, fmt.Errorf("keys and values are of different length %d != %d", len(proof.Keys), len(proof.Values)) - } - - tree, err := verkle.TreeFromProof(proof, rootC) + pretree, err := verkle.PreStateTreeFromProof(proof, rootC) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("error rebuilding the tree from proof: %w", err) + return fmt.Errorf("error rebuilding the pre-tree from proof: %w", err) } + // 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 { var key [32]byte copy(key[:31], stemdiff.Stem[:]) key[31] = suffixdiff.Suffix - val, err := tree.Get(key[:], nil) + val, err := pretree.Get(key[:], nil) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("could not find key %x in tree rebuilt from proof: %w", key, err) + 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 nil, nil, nil, nil, fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) + return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) } } else { if suffixdiff.CurrentValue != nil && len(suffixdiff.CurrentValue) != 0 { - return nil, nil, nil, nil, fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) + return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue) } } } } - // no need to resolve as the tree has been reconstructed from the proof - // and must not contain any unresolved nodes. - pe, _, _, err := tree.GetProofItems(proof.Keys) + posttree, err := verkle.PostStateTreeFromStateDiff(pretree, statediff) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("could not get proof items from tree rebuilt from proof: %w", err) + return fmt.Errorf("error rebuilding the post-tree from proof: %w", err) } - return proof, pe.Cis, pe.Zis, pe.Yis, err + return verkle.VerifyVerkleProofWithPreAndPostTrie(proof, pretree, posttree) } // ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 4e21ee501a21..d92b1758d33b 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -70,9 +70,9 @@ func TestReproduceTree(t *testing.T) { root.Insert(key, values[i], nil) } - proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...)) + proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, nil, append(presentKeys, absentKeys...), nil) cfg := verkle.GetConfig() - if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { + if ok, err := verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg); !ok || err != nil { t.Fatal("could not verify proof") } @@ -289,9 +289,9 @@ func TestReproduceCondrieuStemAggregationInProofOfAbsence(t *testing.T) { root.Insert(key, values[i], nil) } - proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...)) + proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, nil, append(presentKeys, absentKeys...), nil) cfg := verkle.GetConfig() - if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { + if ok, err := verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg); !ok || err != nil { t.Fatal("could not verify proof") } @@ -334,9 +334,9 @@ func TestReproduceCondrieuPoAStemConflictWithAnotherStem(t *testing.T) { root.Insert(key, values[i], nil) } - proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...)) + proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, nil, append(presentKeys, absentKeys...), nil) cfg := verkle.GetConfig() - if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { + if ok, err := verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg); !ok || err != nil { t.Fatal("could not verify proof") } @@ -360,7 +360,7 @@ func TestReproduceCondrieuPoAStemConflictWithAnotherStem(t *testing.T) { func TestEmptyKeySetInProveAndSerialize(t *testing.T) { tree := verkle.New() - verkle.MakeVerkleMultiProof(tree, [][]byte{}) + verkle.MakeVerkleMultiProof(tree, nil, [][]byte{}, nil) } func TestGetTreeKeys(t *testing.T) {