From 3d88e391d7d9403596ab5fdcdcff50432f2fe64b Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 3 Mar 2022 08:51:05 +0100 Subject: [PATCH] creation-time CODECOPY adds no code to the witness (#86) * creation-time CODECOPY adds no code to the witness * Add a more complex test to ensure EXTCODECOPY is called * Fix offset calculations in the slot function * minor tweaks * fix initial value capture for storage * fix build * fix: get the proper byte in get_tree_key_for_storage_slot * fix length calculation in getDataAndAdjustedBounds * fix verkle test --- core/state/state_object.go | 12 ++++++++++++ core/state_processor_test.go | 18 ++++++++++++++++-- core/types/access_witness.go | 1 + core/vm/common.go | 2 +- core/vm/gas_table.go | 4 ++-- core/vm/instructions.go | 23 +++++++++++------------ core/vm/interpreter.go | 2 +- go.mod | 4 ++-- go.sum | 6 ++++++ trie/utils/verkle.go | 19 +++++++++++-------- trie/verkle.go | 6 +++++- trie/verkle_test.go | 3 ++- 12 files changed, 70 insertions(+), 30 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 4ab2c215db85..485d491ec1b0 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -248,6 +248,18 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has return common.Hash{} } enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) + + // Capture the initial value of the location in the verkle proof witness + if s.db.GetTrie().IsVerkle() { + if err != nil { + s.setError(err) + return common.Hash{} + } + addr := s.Address() + loc := new(uint256.Int).SetBytes(key[:]) + index := trieUtils.GetTreeKeyStorageSlot(addr[:], loc) + s.db.Witness().SetLeafValue(index, enc) + } } // If the snapshot is unavailable or reading from it fails, load from the database. if s.db.snap == nil || err != nil { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index d3ba106aa89f..27b30395a7c4 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -345,6 +345,14 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) } +// 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 +var ( + codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) + codeWithExtCodeCopyGas = uint64(192372) +) + func TestProcessStateless(t *testing.T) { var ( config = ¶ms.ChainConfig{ @@ -387,7 +395,10 @@ func TestProcessStateless(t *testing.T) { txCost2 := params.WitnessBranchWriteCost + params.WitnessBranchReadCost*2 + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*10 + params.TxGas intrinsic, _ := IntrinsicGas(code, nil, true, true, true) contractCreationCost := intrinsic + (2*params.WitnessChunkReadCost+params.WitnessChunkWriteCost)*10 + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + uint64(3639) // standard cost of executing the contract - blockGasUsagesExpected := []uint64{txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost} + blockGasUsagesExpected := []uint64{ + txCost1*2 + txCost2, + txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, + } chain, _ := GenerateVerkleChain(gspec.Config, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { // 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) @@ -397,10 +408,13 @@ func TestProcessStateless(t *testing.T) { 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 a contract creation in block #2 + // 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(32), 3000000, big.NewInt(875000000), codeWithExtCodeCopy), signer, testKey) + gen.AddTx(tx) } }) diff --git a/core/types/access_witness.go b/core/types/access_witness.go index b84d9375c4fd..81802bc429a8 100644 --- a/core/types/access_witness.go +++ b/core/types/access_witness.go @@ -270,6 +270,7 @@ func (aw *AccessWitness) TouchAndChargeContractCreateInit(addr []byte, createSen if createSendsValue { gas += aw.TouchAddressOnWriteAndComputeGas(utils.GetTreeKeyBalance(addr[:])) } + gas += aw.TouchAddressOnWriteAndComputeGas(utils.GetTreeKeyCodeKeccak(addr[:])) return gas } diff --git a/core/vm/common.go b/core/vm/common.go index b79186c24513..ba75950e370b 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -72,7 +72,7 @@ func getDataAndAdjustedBounds(data []byte, start uint64, size uint64) (codeCopyP if end > length { end = length } - return common.RightPadBytes(data[start:end], int(size)), start, end + return common.RightPadBytes(data[start:end], int(size)), start, end - start } // toWordSize returns the ceiled word size required for memory expansion. diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4b1dbab52973..94e3792797b5 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -122,7 +122,7 @@ func gasCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory uint64Length = 0xffffffffffffffff } _, offset, nonPaddedSize := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, uint64Length) - statelessGas = touchEachChunksOnReadAndChargeGas(offset, nonPaddedSize, contract.Address().Bytes()[:], nil, nil, evm.Accesses) + statelessGas = touchEachChunksOnReadAndChargeGas(offset, nonPaddedSize, contract.Address().Bytes()[:], nil, nil, evm.Accesses, contract.IsDeployment) } usedGas, err := gasCodeCopyStateful(evm, contract, stack, mem, memorySize) return usedGas + statelessGas, err @@ -150,7 +150,7 @@ func gasExtCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem // behavior from CODECOPY which only charges witness access costs for the part of the range // which overlaps in the account code. TODO: clarify this is desired behavior and amend the // spec. - statelessGas = touchEachChunksOnReadAndChargeGas(uint64CodeOffset, uint64Length, targetAddr[:], nil, nil, evm.Accesses) + statelessGas = touchEachChunksOnReadAndChargeGas(uint64CodeOffset, uint64Length, targetAddr[:], nil, nil, evm.Accesses, contract.IsDeployment) } usedGas, err := gasExtCodeCopyStateful(evm, contract, stack, mem, memorySize) return usedGas + statelessGas, err diff --git a/core/vm/instructions.go b/core/vm/instructions.go index c5bb5e1cc910..6550fff1c5a1 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -373,14 +373,14 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64()) if interpreter.evm.chainConfig.IsCancun(interpreter.evm.Context.BlockNumber) { - touchEachChunksOnReadAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses) + touchEachChunksOnReadAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses, scope.Contract.IsDeployment) } scope.Memory.Set(memOffset.Uint64(), uint64(len(paddedCodeCopy)), paddedCodeCopy) return nil, nil } // touchEachChunksAndChargeGas is a helper function to touch every chunk in a code range and charge witness gas costs -func touchEachChunksOnReadAndChargeGas(offset, size uint64, address []byte, code []byte, contract AnalyzedContract, accesses *types.AccessWitness) uint64 { +func touchEachChunksOnReadAndChargeGas(offset, size uint64, address []byte, code []byte, contract AnalyzedContract, accesses *types.AccessWitness, deployment bool) uint64 { // note that in the case where the copied code is outside the range of the // contract code but touches the last leaf with contract code in it, // we don't include the last leaf of code in the AccessWitness. The @@ -392,7 +392,6 @@ func touchEachChunksOnReadAndChargeGas(offset, size uint64, address []byte, code } var ( statelessGasCharged uint64 - startLeafOffset uint64 endLeafOffset uint64 startOffset uint64 endOffset uint64 @@ -407,10 +406,10 @@ func touchEachChunksOnReadAndChargeGas(offset, size uint64, address []byte, code endOffset = startOffset + size } endLeafOffset = endOffset + (endOffset % 31) - numLeaves = (endLeafOffset - startLeafOffset) / 31 + numLeaves = (endLeafOffset - startOffset + 30) / 31 for i := 0; i < int(numLeaves); i++ { - index := trieUtils.GetTreeKeyCodeChunk(address, uint256.NewInt(uint64(i))) + index := trieUtils.GetTreeKeyCodeChunk(address, uint256.NewInt(uint64(i)+startOffset/31)) // TODO safe-add here to catch overflow statelessGasCharged += accesses.TouchAddressOnReadAndComputeGas(index) @@ -434,7 +433,11 @@ func touchEachChunksOnReadAndChargeGas(offset, size uint64, address []byte, code padding := make([]byte, 31-valueSize, 31-valueSize) copy(value[valueSize+1:], padding) } - accesses.SetLeafValue(index[:], value) + if deployment { + accesses.SetLeafValue(index[:], nil) + } else { + accesses.SetLeafValue(index[:], value) + } } } @@ -458,7 +461,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) code := interpreter.evm.StateDB.GetCode(addr) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) cb := codeBitmap(code) - touchEachChunksOnReadAndChargeGas(copyOffset, nonPaddedCopyLength, addr[:], code, &cb, interpreter.evm.Accesses) + touchEachChunksOnReadAndChargeGas(copyOffset, nonPaddedCopyLength, addr[:], code, &cb, interpreter.evm.Accesses, false) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), paddedCodeCopy) } else { codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64()) @@ -591,10 +594,6 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by hash := common.Hash(loc.Bytes32()) val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash) - if interpreter.evm.chainConfig.IsCancun(interpreter.evm.Context.BlockNumber) { - index := trieUtils.GetTreeKeyStorageSlot(scope.Contract.Address().Bytes(), loc) - interpreter.evm.Accesses.SetLeafValue(index, val.Bytes()) - } loc.SetBytes(val.Bytes()) return nil, nil } @@ -980,7 +979,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { } if interpreter.evm.chainConfig.IsCancun(interpreter.evm.Context.BlockNumber) { - statelessGas := touchEachChunksOnReadAndChargeGas(uint64(startMin), uint64(pushByteSize), scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses) + statelessGas := touchEachChunksOnReadAndChargeGas(uint64(startMin), uint64(pushByteSize), scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses, scope.Contract.IsDeployment) scope.Contract.UseGas(statelessGas) } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 64fd386ad490..103c17f1e0a8 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -194,7 +194,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if in.evm.ChainConfig().IsCancun(in.evm.Context.BlockNumber) && !contract.IsDeployment { // if the PC ends up in a new "page" of verkleized code, charge the // associated witness costs. - contract.Gas -= touchEachChunksOnReadAndChargeGas(pc, 1, contract.Address().Bytes()[:], contract.Code, contract, in.evm.TxContext.Accesses) + contract.Gas -= touchEachChunksOnReadAndChargeGas(pc, 1, contract.Address().Bytes()[:], contract.Code, contract, in.evm.TxContext.Accesses, contract.IsDeployment) } // TODO how can we tell if we are in stateless mode here and need to get the op from the witness diff --git a/go.mod b/go.mod index ab2c7a005983..097edaaa6ffc 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/fatih/color v1.7.0 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20220217102726-664ad58b43cd + github.com/gballet/go-verkle v0.0.0-20220228192133-5773319d4d56 github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.4.3 @@ -66,7 +66,7 @@ require ( golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 + golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 golang.org/x/text v0.3.6 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce diff --git a/go.sum b/go.sum index 56fefafc9dae..3403050409e3 100644 --- a/go.sum +++ b/go.sum @@ -173,6 +173,8 @@ github.com/gballet/go-verkle v0.0.0-20220209120303-88a3fa537cf1 h1:mkoUQjsrx/6hH github.com/gballet/go-verkle v0.0.0-20220209120303-88a3fa537cf1/go.mod h1:NhFaKv4U1IBG8QkKCsKh4xBMmdori0B0eZjdywcrktE= github.com/gballet/go-verkle v0.0.0-20220217102726-664ad58b43cd h1:kvZpVdKgiVfxi+8Wvlm9FknyA4b+T5bp3ajZEMlp6N0= github.com/gballet/go-verkle v0.0.0-20220217102726-664ad58b43cd/go.mod h1:NhFaKv4U1IBG8QkKCsKh4xBMmdori0B0eZjdywcrktE= +github.com/gballet/go-verkle v0.0.0-20220228192133-5773319d4d56 h1:Zucd5Snqq+pzzpOuuj675QgOKvfWxpnouTqug4trGIA= +github.com/gballet/go-verkle v0.0.0-20220228192133-5773319d4d56/go.mod h1:mxWdGqfhWGZ0ckAEg+zHM8u4p1Tsw9mAsbSBtXb9AQE= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -577,6 +579,10 @@ golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBan golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/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 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 79610e77ad66..c2e228f89ce3 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -56,7 +56,8 @@ func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte { verkle.CopyFr(&poly[i], &verkle.FrZero) } - ret := verkle.GetConfig().CommitToPoly(poly[:], 0) + cfg, _ := verkle.GetConfig() + ret := cfg.CommitToPoly(poly[:], 0) retb := ret.Bytes() retb[31] = subIndex return retb[:] @@ -99,21 +100,23 @@ func GetTreeKeyCodeChunk(address []byte, chunk *uint256.Int) []byte { } func GetTreeKeyStorageSlot(address []byte, storageKey *uint256.Int) []byte { - treeIndex := storageKey.Clone() + pos := storageKey.Clone() if storageKey.Cmp(codeStorageDelta) < 0 { - treeIndex.Add(HeaderStorageOffset, storageKey) + pos.Add(HeaderStorageOffset, storageKey) } else { - treeIndex.Add(MainStorageOffset, storageKey) + pos.Add(MainStorageOffset, storageKey) } - treeIndex.Div(treeIndex, VerkleNodeWidth) + treeIndex := new(uint256.Int).Div(pos, VerkleNodeWidth) // calculate the sub_index, i.e. the index in the stem tree. // Because the modulus is 256, it's the last byte of treeIndex - subIndexMod := treeIndex.Bytes() + subIndexMod := new(uint256.Int).Mod(pos, VerkleNodeWidth).Bytes() var subIndex byte if len(subIndexMod) != 0 { - // Get the last byte, as uint256.Int is big-endian - subIndex = subIndexMod[len(subIndexMod)-1] + // uint256 is broken into 4 little-endian quads, + // each with native endianness. Extract the least + // significant byte. + subIndex = byte(subIndexMod[0] & 0xFF) } return GetTreeKey(address, treeIndex, subIndex) } diff --git a/trie/verkle.go b/trie/verkle.go index 61b8c2a2a4ab..32d25fd95bd1 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -206,7 +206,11 @@ func DeserializeAndVerifyVerkleProof(serialized []byte) (map[common.Hash]common. if err != nil { return nil, fmt.Errorf("could not deserialize proof: %w", err) } - if !verkle.VerifyVerkleProof(proof, cis, indices, yis, verkle.GetConfig()) { + cfg, err := verkle.GetConfig() + if err != nil { + return nil, err + } + if !verkle.VerifyVerkleProof(proof, cis, indices, yis, cfg) { return nil, errInvalidProof } diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 924110da97a6..fd07ba814cd3 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -70,7 +70,8 @@ func TestReproduceTree(t *testing.T) { } proof, Cs, zis, yis := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...), kv) - if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, verkle.GetConfig()) { + cfg, _ := verkle.GetConfig() + if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { t.Fatal("could not verify proof") }