core, trie: verkle state processor tests (#30672)
Tests that are crucial to for verifying the verkle testnet functions properly. --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Gary Rong <garyrong0905@gmail.com> Co-authored-by: Martin HS <martin@swende.se>
This commit is contained in:
parent
014e2b037f
commit
06cbc80754
|
@ -398,21 +398,25 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
|
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
preTrie, err := state.Database().OpenTrie(parent.Root)
|
preTrie, err := state.Database().OpenTrie(parent.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
|
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
|
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
|
||||||
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
|
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
|
||||||
|
|
||||||
|
// The witness is only attached iff both parent and current block are
|
||||||
|
// using verkle tree.
|
||||||
if okpre && okpost {
|
if okpre && okpost {
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver)
|
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
|
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
|
||||||
}
|
}
|
||||||
block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof})
|
block = block.WithWitness(&types.ExecutionWitness{
|
||||||
|
StateDiff: stateDiff,
|
||||||
|
VerkleProof: verkleProof,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCreateCPreheck charges access costs before
|
// ContractCreatePreCheckGas charges access costs before
|
||||||
// a contract creation is initiated. It is just reads, because the
|
// a contract creation is initiated. It is just reads, because the
|
||||||
// address collision is done before the transfer, and so no write
|
// address collision is done before the transfer, and so no write
|
||||||
// are guaranteed to happen at this point.
|
// are guaranteed to happen at this point.
|
||||||
|
|
|
@ -1068,7 +1068,8 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno
|
||||||
deletes[addrHash] = op
|
deletes[addrHash] = op
|
||||||
|
|
||||||
// Short circuit if the origin storage was empty.
|
// Short circuit if the origin storage was empty.
|
||||||
if prev.Root == types.EmptyRootHash {
|
|
||||||
|
if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Remove storage slots belonging to the account.
|
// Remove storage slots belonging to the account.
|
||||||
|
|
|
@ -18,7 +18,6 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -30,14 +29,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
|
||||||
"github.com/ethereum/go-verkle"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
@ -426,193 +422,3 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||||
}
|
}
|
||||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`)
|
|
||||||
intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, true, true, true, true)
|
|
||||||
// A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness
|
|
||||||
// will not contain that copied data.
|
|
||||||
// Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985
|
|
||||||
codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`)
|
|
||||||
intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, true, true, true, true)
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestProcessVerkle(t *testing.T) {
|
|
||||||
var (
|
|
||||||
config = ¶ms.ChainConfig{
|
|
||||||
ChainID: big.NewInt(1),
|
|
||||||
HomesteadBlock: big.NewInt(0),
|
|
||||||
EIP150Block: big.NewInt(0),
|
|
||||||
EIP155Block: big.NewInt(0),
|
|
||||||
EIP158Block: big.NewInt(0),
|
|
||||||
ByzantiumBlock: big.NewInt(0),
|
|
||||||
ConstantinopleBlock: big.NewInt(0),
|
|
||||||
PetersburgBlock: big.NewInt(0),
|
|
||||||
IstanbulBlock: big.NewInt(0),
|
|
||||||
MuirGlacierBlock: big.NewInt(0),
|
|
||||||
BerlinBlock: big.NewInt(0),
|
|
||||||
LondonBlock: big.NewInt(0),
|
|
||||||
Ethash: new(params.EthashConfig),
|
|
||||||
ShanghaiTime: u64(0),
|
|
||||||
VerkleTime: u64(0),
|
|
||||||
TerminalTotalDifficulty: common.Big0,
|
|
||||||
}
|
|
||||||
signer = types.LatestSigner(config)
|
|
||||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
||||||
bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain
|
|
||||||
coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
|
|
||||||
gspec = &Genesis{
|
|
||||||
Config: config,
|
|
||||||
Alloc: GenesisAlloc{
|
|
||||||
coinbase: GenesisAccount{
|
|
||||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
|
||||||
Nonce: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// Verkle trees use the snapshot, which must be enabled before the
|
|
||||||
// data is saved into the tree+database.
|
|
||||||
// genesis := gspec.MustCommit(bcdb, triedb)
|
|
||||||
cacheConfig := DefaultCacheConfigWithScheme("path")
|
|
||||||
cacheConfig.SnapshotLimit = 0
|
|
||||||
blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
|
||||||
defer blockchain.Stop()
|
|
||||||
|
|
||||||
txCost1 := params.TxGas
|
|
||||||
txCost2 := params.TxGas
|
|
||||||
contractCreationCost := intrinsicContractCreationGas +
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */
|
|
||||||
739 /* execution costs */
|
|
||||||
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas +
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
|
||||||
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
|
||||||
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
|
||||||
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
|
||||||
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
|
||||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */
|
|
||||||
15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */
|
|
||||||
4844 /* execution costs */
|
|
||||||
blockGasUsagesExpected := []uint64{
|
|
||||||
txCost1*2 + txCost2,
|
|
||||||
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
|
||||||
}
|
|
||||||
_, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
|
||||||
gen.SetPoS()
|
|
||||||
|
|
||||||
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
|
||||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i)*3, common.Address{byte(i), 2, 3}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+1, common.Address{}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+2, common.Address{}, big.NewInt(0), txCost2, big.NewInt(875000000), nil), signer, testKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
|
|
||||||
// Add two contract creations in block #2
|
|
||||||
if i == 1 {
|
|
||||||
tx, _ = types.SignTx(types.NewContractCreation(6, big.NewInt(16), 3000000, big.NewInt(875000000), code), signer, testKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
|
|
||||||
tx, _ = types.SignTx(types.NewContractCreation(7, big.NewInt(0), 3000000, big.NewInt(875000000), codeWithExtCodeCopy), signer, testKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check proof for both blocks
|
|
||||||
err := verkle.Verify(proofs[0], gspec.ToBlock().Root().Bytes(), chain[0].Root().Bytes(), statediffs[0])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err = verkle.Verify(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), statediffs[1])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log("verified verkle proof, inserting blocks into the chain")
|
|
||||||
|
|
||||||
endnum, err := blockchain.InsertChain(chain)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("block %d imported with error: %v", endnum, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
b := blockchain.GetBlockByNumber(uint64(i) + 1)
|
|
||||||
if b == nil {
|
|
||||||
t.Fatalf("expected block %d to be present in chain", i+1)
|
|
||||||
}
|
|
||||||
if b.Hash() != chain[i].Hash() {
|
|
||||||
t.Fatalf("block #%d not found at expected height", b.NumberU64())
|
|
||||||
}
|
|
||||||
if b.GasUsed() != blockGasUsagesExpected[i] {
|
|
||||||
t.Fatalf("expected block #%d txs to use %d, got %d\n", b.NumberU64(), blockGasUsagesExpected[i], b.GasUsed())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProcessParentBlockHash(t *testing.T) {
|
|
||||||
var (
|
|
||||||
chainConfig = params.MergedTestChainConfig
|
|
||||||
hashA = common.Hash{0x01}
|
|
||||||
hashB = common.Hash{0x02}
|
|
||||||
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
|
|
||||||
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
|
|
||||||
coinbase = common.Address{}
|
|
||||||
)
|
|
||||||
test := func(statedb *state.StateDB) {
|
|
||||||
statedb.SetNonce(params.HistoryStorageAddress, 1)
|
|
||||||
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
|
|
||||||
statedb.IntermediateRoot(true)
|
|
||||||
|
|
||||||
vmContext := NewEVMBlockContext(header, nil, &coinbase)
|
|
||||||
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
|
||||||
ProcessParentBlockHash(header.ParentHash, evm, statedb)
|
|
||||||
|
|
||||||
vmContext = NewEVMBlockContext(parent, nil, &coinbase)
|
|
||||||
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
|
||||||
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
|
|
||||||
|
|
||||||
// make sure that the state is correct
|
|
||||||
if have := getParentBlockHash(statedb, 1); have != hashA {
|
|
||||||
t.Errorf("want parent hash %v, have %v", hashA, have)
|
|
||||||
}
|
|
||||||
if have := getParentBlockHash(statedb, 0); have != hashB {
|
|
||||||
t.Errorf("want parent hash %v, have %v", hashB, have)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Run("MPT", func(t *testing.T) {
|
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
|
||||||
test(statedb)
|
|
||||||
})
|
|
||||||
t.Run("Verkle", func(t *testing.T) {
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
|
||||||
cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme)
|
|
||||||
cacheConfig.SnapshotLimit = 0
|
|
||||||
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
|
|
||||||
statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil))
|
|
||||||
test(statedb)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
|
|
||||||
ringIndex := number % params.HistoryServeWindow
|
|
||||||
var key common.Hash
|
|
||||||
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
|
||||||
return statedb.GetState(params.HistoryStorageAddress, key)
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -204,10 +204,10 @@ func CodeChunkKey(address []byte, chunk *uint256.Int) []byte {
|
||||||
return GetTreeKey(address, treeIndex, subIndex)
|
return GetTreeKey(address, treeIndex, subIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StorageIndex(bytes []byte) (*uint256.Int, byte) {
|
func StorageIndex(storageKey []byte) (*uint256.Int, byte) {
|
||||||
// If the storage slot is in the header, we need to add the header offset.
|
// If the storage slot is in the header, we need to add the header offset.
|
||||||
var key uint256.Int
|
var key uint256.Int
|
||||||
key.SetBytes(bytes)
|
key.SetBytes(storageKey)
|
||||||
if key.Cmp(codeStorageDelta) < 0 {
|
if key.Cmp(codeStorageDelta) < 0 {
|
||||||
// This addition is always safe; it can't ever overflow since pos<codeStorageDelta.
|
// This addition is always safe; it can't ever overflow since pos<codeStorageDelta.
|
||||||
key.Add(headerStorageOffset, &key)
|
key.Add(headerStorageOffset, &key)
|
||||||
|
@ -216,6 +216,18 @@ func StorageIndex(bytes []byte) (*uint256.Int, byte) {
|
||||||
// and the sub-index is the LSB of the modified storage key.
|
// and the sub-index is the LSB of the modified storage key.
|
||||||
return zero, byte(key[0] & 0xFF)
|
return zero, byte(key[0] & 0xFF)
|
||||||
}
|
}
|
||||||
|
// If the storage slot is in the main storage, we need to add the main storage offset.
|
||||||
|
|
||||||
|
// The first MAIN_STORAGE_OFFSET group will see its
|
||||||
|
// first 64 slots unreachable. This is either a typo in the
|
||||||
|
// spec or intended to conserve the 256-u256
|
||||||
|
// aligment. If we decide to ever access these 64
|
||||||
|
// slots, uncomment this.
|
||||||
|
// // Get the new offset since we now know that we are above 64.
|
||||||
|
// pos.Sub(&pos, codeStorageDelta)
|
||||||
|
// suffix := byte(pos[0] & 0xFF)
|
||||||
|
suffix := storageKey[len(storageKey)-1]
|
||||||
|
|
||||||
// We first divide by VerkleNodeWidth to create room to avoid an overflow next.
|
// We first divide by VerkleNodeWidth to create room to avoid an overflow next.
|
||||||
key.Rsh(&key, uint(verkleNodeWidthLog2))
|
key.Rsh(&key, uint(verkleNodeWidthLog2))
|
||||||
|
|
||||||
|
@ -224,7 +236,7 @@ func StorageIndex(bytes []byte) (*uint256.Int, byte) {
|
||||||
|
|
||||||
// The sub-index is the LSB of the original storage key, since mainStorageOffset
|
// The sub-index is the LSB of the original storage key, since mainStorageOffset
|
||||||
// doesn't affect this byte, so we can avoid masks or shifts.
|
// doesn't affect this byte, so we can avoid masks or shifts.
|
||||||
return &key, byte(key[0] & 0xFF)
|
return &key, suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageSlotKey returns the verkle tree key of the storage slot for the
|
// StorageSlotKey returns the verkle tree key of the storage slot for the
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -32,7 +33,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
zero [32]byte
|
|
||||||
errInvalidRootType = errors.New("invalid node type for root")
|
errInvalidRootType = errors.New("invalid node type for root")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -170,25 +170,35 @@ func (t *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) er
|
||||||
return t.root.Insert(k, v[:], t.nodeResolver)
|
return t.root.Insert(k, v[:], t.nodeResolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAccount implements state.Trie, deleting the specified account from the
|
// DeleteAccount leaves the account untouched, as no account deletion can happen
|
||||||
// trie. If the account was not existent in the trie, no error will be returned.
|
// in verkle.
|
||||||
// If the trie is corrupted, an error will be returned.
|
// There is a special corner case, in which an account that is prefunded, CREATE2-d
|
||||||
|
// and then SELFDESTRUCT-d should see its funds drained. EIP161 says that account
|
||||||
|
// should be removed, but this is verboten by the verkle spec. This contains a
|
||||||
|
// workaround in which the method checks for this corner case, and if so, overwrites
|
||||||
|
// the balance with 0. This will be removed once the spec has been clarified.
|
||||||
func (t *VerkleTrie) DeleteAccount(addr common.Address) error {
|
func (t *VerkleTrie) DeleteAccount(addr common.Address) error {
|
||||||
var (
|
k := utils.BasicDataKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()))
|
||||||
err error
|
values, err := t.root.(*verkle.InternalNode).GetValuesAtStem(k, t.nodeResolver)
|
||||||
values = make([][]byte, verkle.NodeWidth)
|
|
||||||
)
|
|
||||||
for i := 0; i < verkle.NodeWidth; i++ {
|
|
||||||
values[i] = zero[:]
|
|
||||||
}
|
|
||||||
switch n := t.root.(type) {
|
|
||||||
case *verkle.InternalNode:
|
|
||||||
err = n.InsertValuesAtStem(t.cache.GetStem(addr.Bytes()), values, t.nodeResolver)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("DeleteAccount (%x) error: %v", addr, err)
|
return fmt.Errorf("Error getting data at %x in delete: %w", k, err)
|
||||||
}
|
}
|
||||||
|
var prefunded bool
|
||||||
|
for i, v := range values {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
prefunded = len(v) == 32
|
||||||
|
case 1:
|
||||||
|
prefunded = len(v) == 32 && bytes.Equal(v, types.EmptyCodeHash[:])
|
||||||
default:
|
default:
|
||||||
return errInvalidRootType
|
prefunded = v == nil
|
||||||
|
}
|
||||||
|
if !prefunded {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prefunded {
|
||||||
|
t.root.Insert(k, common.Hash{}.Bytes(), t.nodeResolver)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -302,21 +312,19 @@ func (t *VerkleTrie) IsVerkle() bool {
|
||||||
// Proof builds and returns the verkle multiproof for keys, built against
|
// Proof builds and returns the verkle multiproof for keys, built against
|
||||||
// the pre tree. The post tree is passed in order to add the post values
|
// the pre tree. The post tree is passed in order to add the post values
|
||||||
// to that proof.
|
// to that proof.
|
||||||
func (t *VerkleTrie) Proof(posttrie *VerkleTrie, keys [][]byte, resolver verkle.NodeResolverFn) (*verkle.VerkleProof, verkle.StateDiff, error) {
|
func (t *VerkleTrie) Proof(posttrie *VerkleTrie, keys [][]byte) (*verkle.VerkleProof, verkle.StateDiff, error) {
|
||||||
var postroot verkle.VerkleNode
|
var postroot verkle.VerkleNode
|
||||||
if posttrie != nil {
|
if posttrie != nil {
|
||||||
postroot = posttrie.root
|
postroot = posttrie.root
|
||||||
}
|
}
|
||||||
proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, resolver)
|
proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, t.FlatdbNodeResolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, kvps, err := verkle.SerializeProof(proof)
|
p, kvps, err := verkle.SerializeProof(proof)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, kvps, nil
|
return p, kvps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue