consensus/beacon, core/types: add verkle witness builder (#30129)
This PR adds the bulk verkle witness+proof production at the end of block production. It reads all data from the tree in one swoop and produces a verkle proof. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
ea3b5095f4
commit
e9467eec1c
@ -17,23 +17,24 @@ var _ = (*executableDataMarshaling)(nil)
|
|||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
var enc ExecutableData
|
var enc ExecutableData
|
||||||
enc.ParentHash = e.ParentHash
|
enc.ParentHash = e.ParentHash
|
||||||
@ -58,29 +59,31 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
|||||||
enc.Withdrawals = e.Withdrawals
|
enc.Withdrawals = e.Withdrawals
|
||||||
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
||||||
|
enc.ExecutionWitness = e.ExecutionWitness
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||||
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
var dec ExecutableData
|
var dec ExecutableData
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
@ -154,5 +157,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
|||||||
if dec.ExcessBlobGas != nil {
|
if dec.ExcessBlobGas != nil {
|
||||||
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
||||||
}
|
}
|
||||||
|
if dec.ExecutionWitness != nil {
|
||||||
|
e.ExecutionWitness = dec.ExecutionWitness
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -59,23 +59,24 @@ type payloadAttributesMarshaling struct {
|
|||||||
|
|
||||||
// ExecutableData is the data necessary to execute an EL payload.
|
// ExecutableData is the data necessary to execute an EL payload.
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number uint64 `json:"blockNumber" gencodec:"required"`
|
Number uint64 `json:"blockNumber" gencodec:"required"`
|
||||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for executableData.
|
// JSON type overrides for executableData.
|
||||||
@ -251,7 +252,9 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
|||||||
BlobGasUsed: data.BlobGasUsed,
|
BlobGasUsed: data.BlobGasUsed,
|
||||||
ParentBeaconRoot: beaconRoot,
|
ParentBeaconRoot: beaconRoot,
|
||||||
}
|
}
|
||||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals})
|
block := types.NewBlockWithHeader(header)
|
||||||
|
block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals})
|
||||||
|
block = block.WithWitness(data.ExecutionWitness)
|
||||||
if block.Hash() != data.BlockHash {
|
if block.Hash() != data.BlockHash {
|
||||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
||||||
}
|
}
|
||||||
@ -262,23 +265,24 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
|||||||
// fields from the given block. It assumes the given block is post-merge block.
|
// fields from the given block. It assumes the given block is post-merge block.
|
||||||
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope {
|
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope {
|
||||||
data := &ExecutableData{
|
data := &ExecutableData{
|
||||||
BlockHash: block.Hash(),
|
BlockHash: block.Hash(),
|
||||||
ParentHash: block.ParentHash(),
|
ParentHash: block.ParentHash(),
|
||||||
FeeRecipient: block.Coinbase(),
|
FeeRecipient: block.Coinbase(),
|
||||||
StateRoot: block.Root(),
|
StateRoot: block.Root(),
|
||||||
Number: block.NumberU64(),
|
Number: block.NumberU64(),
|
||||||
GasLimit: block.GasLimit(),
|
GasLimit: block.GasLimit(),
|
||||||
GasUsed: block.GasUsed(),
|
GasUsed: block.GasUsed(),
|
||||||
BaseFeePerGas: block.BaseFee(),
|
BaseFeePerGas: block.BaseFee(),
|
||||||
Timestamp: block.Time(),
|
Timestamp: block.Time(),
|
||||||
ReceiptsRoot: block.ReceiptHash(),
|
ReceiptsRoot: block.ReceiptHash(),
|
||||||
LogsBloom: block.Bloom().Bytes(),
|
LogsBloom: block.Bloom().Bytes(),
|
||||||
Transactions: encodeTransactions(block.Transactions()),
|
Transactions: encodeTransactions(block.Transactions()),
|
||||||
Random: block.MixDigest(),
|
Random: block.MixDigest(),
|
||||||
ExtraData: block.Extra(),
|
ExtraData: block.Extra(),
|
||||||
Withdrawals: block.Withdrawals(),
|
Withdrawals: block.Withdrawals(),
|
||||||
BlobGasUsed: block.BlobGasUsed(),
|
BlobGasUsed: block.BlobGasUsed(),
|
||||||
ExcessBlobGas: block.ExcessBlobGas(),
|
ExcessBlobGas: block.ExcessBlobGas(),
|
||||||
|
ExecutionWitness: block.ExecutionWitness(),
|
||||||
}
|
}
|
||||||
bundle := BlobsBundleV1{
|
bundle := BlobsBundleV1{
|
||||||
Commitments: make([]hexutil.Bytes, 0),
|
Commitments: make([]hexutil.Bytes, 0),
|
||||||
|
@ -387,8 +387,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
|||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(true)
|
header.Root = state.IntermediateRoot(true)
|
||||||
|
|
||||||
// Assemble and return the final block.
|
// Assemble the final block.
|
||||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||||
|
|
||||||
|
// Create the block witness and attach to block.
|
||||||
|
// This step needs to happen as late as possible to catch all access events.
|
||||||
|
if chain.Config().IsVerkle(header.Number, header.Time) {
|
||||||
|
keys := state.AccessEvents().Keys()
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
|
||||||
|
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
|
||||||
|
if okpre && okpost {
|
||||||
|
if len(keys) > 0 {
|
||||||
|
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
|
||||||
|
}
|
||||||
|
block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seal generates a new sealing request for the given input block and pushes
|
// Seal generates a new sealing request for the given input block and pushes
|
||||||
|
@ -467,9 +467,8 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
|||||||
panic(fmt.Sprintf("trie write error: %v", err))
|
panic(fmt.Sprintf("trie write error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO uncomment when proof generation is merged
|
proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||||
// proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||||
// keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
|
||||||
|
|
||||||
return block, b.receipts
|
return block, b.receipts
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,8 @@ type StateDB struct {
|
|||||||
preimages map[common.Hash][]byte
|
preimages map[common.Hash][]byte
|
||||||
|
|
||||||
// Per-transaction access list
|
// Per-transaction access list
|
||||||
accessList *accessList
|
accessList *accessList
|
||||||
|
accessEvents *AccessEvents
|
||||||
|
|
||||||
// Transient storage
|
// Transient storage
|
||||||
transientStorage transientStorage
|
transientStorage transientStorage
|
||||||
@ -184,6 +185,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
|||||||
transientStorage: newTransientStorage(),
|
transientStorage: newTransientStorage(),
|
||||||
hasher: crypto.NewKeccakState(),
|
hasher: crypto.NewKeccakState(),
|
||||||
}
|
}
|
||||||
|
if db.TrieDB().IsVerkle() {
|
||||||
|
sdb.accessEvents = NewAccessEvents(db.(*cachingDB).pointCache)
|
||||||
|
}
|
||||||
if sdb.snaps != nil {
|
if sdb.snaps != nil {
|
||||||
sdb.snap = sdb.snaps.Snapshot(root)
|
sdb.snap = sdb.snaps.Snapshot(root)
|
||||||
}
|
}
|
||||||
@ -709,6 +713,9 @@ func (s *StateDB) Copy() *StateDB {
|
|||||||
if s.witness != nil {
|
if s.witness != nil {
|
||||||
state.witness = s.witness.Copy()
|
state.witness = s.witness.Copy()
|
||||||
}
|
}
|
||||||
|
if s.accessEvents != nil {
|
||||||
|
state.accessEvents = s.accessEvents.Copy()
|
||||||
|
}
|
||||||
// Deep copy cached state objects.
|
// Deep copy cached state objects.
|
||||||
for addr, obj := range s.stateObjects {
|
for addr, obj := range s.stateObjects {
|
||||||
state.stateObjects[addr] = obj.deepCopy(state)
|
state.stateObjects[addr] = obj.deepCopy(state)
|
||||||
@ -1452,3 +1459,7 @@ func (s *StateDB) PointCache() *utils.PointCache {
|
|||||||
func (s *StateDB) Witness() *stateless.Witness {
|
func (s *StateDB) Witness() *stateless.Witness {
|
||||||
return s.witness
|
return s.witness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) AccessEvents() *AccessEvents {
|
||||||
|
return s.accessEvents
|
||||||
|
}
|
||||||
|
@ -153,6 +153,12 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||||
|
// all values, so that the witness can be built.
|
||||||
|
if statedb.GetTrie().IsVerkle() {
|
||||||
|
statedb.AccessEvents().Merge(evm.AccessEvents)
|
||||||
|
}
|
||||||
|
|
||||||
// Set the receipt logs and create the bloom filter.
|
// Set the receipt logs and create the bloom filter.
|
||||||
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
@ -38,6 +38,7 @@ import (
|
|||||||
"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-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"
|
||||||
)
|
)
|
||||||
@ -491,7 +492,7 @@ func TestProcessVerkle(t *testing.T) {
|
|||||||
txCost1*2 + txCost2,
|
txCost1*2 + txCost2,
|
||||||
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
||||||
}
|
}
|
||||||
_, chain, _, _, _ := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
_, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
||||||
gen.SetPoS()
|
gen.SetPoS()
|
||||||
|
|
||||||
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
||||||
@ -512,7 +513,17 @@ func TestProcessVerkle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Log("inserting blocks into the chain")
|
// 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)
|
endnum, err := blockchain.InsertChain(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-verkle"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A BlockNonce is a 64-bit hash which proves (combined with the
|
// A BlockNonce is a 64-bit hash which proves (combined with the
|
||||||
@ -59,6 +60,13 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
|
|||||||
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
|
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionWitness represents the witness + proof used in a verkle context,
|
||||||
|
// to provide the ability to execute a block statelessly.
|
||||||
|
type ExecutionWitness struct {
|
||||||
|
StateDiff verkle.StateDiff `json:"stateDiff"`
|
||||||
|
VerkleProof *verkle.VerkleProof `json:"verkleProof"`
|
||||||
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
//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
|
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
|
||||||
|
|
||||||
@ -197,6 +205,11 @@ type Block struct {
|
|||||||
transactions Transactions
|
transactions Transactions
|
||||||
withdrawals Withdrawals
|
withdrawals Withdrawals
|
||||||
|
|
||||||
|
// witness is not an encoded part of the block body.
|
||||||
|
// It is held in Block in order for easy relaying to the places
|
||||||
|
// that process it.
|
||||||
|
witness *ExecutionWitness
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
hash atomic.Pointer[common.Hash]
|
hash atomic.Pointer[common.Hash]
|
||||||
size atomic.Uint64
|
size atomic.Uint64
|
||||||
@ -401,6 +414,9 @@ func (b *Block) BlobGasUsed() *uint64 {
|
|||||||
return blobGasUsed
|
return blobGasUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionWitness returns the verkle execution witneess + proof for a block
|
||||||
|
func (b *Block) ExecutionWitness() *ExecutionWitness { return b.witness }
|
||||||
|
|
||||||
// Size returns the true RLP encoded storage size of the block, either by encoding
|
// Size returns the true RLP encoded storage size of the block, either by encoding
|
||||||
// and returning it, or returning a previously cached value.
|
// and returning it, or returning a previously cached value.
|
||||||
func (b *Block) Size() uint64 {
|
func (b *Block) Size() uint64 {
|
||||||
@ -448,6 +464,7 @@ func (b *Block) WithSeal(header *Header) *Block {
|
|||||||
transactions: b.transactions,
|
transactions: b.transactions,
|
||||||
uncles: b.uncles,
|
uncles: b.uncles,
|
||||||
withdrawals: b.withdrawals,
|
withdrawals: b.withdrawals,
|
||||||
|
witness: b.witness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,6 +476,7 @@ func (b *Block) WithBody(body Body) *Block {
|
|||||||
transactions: slices.Clone(body.Transactions),
|
transactions: slices.Clone(body.Transactions),
|
||||||
uncles: make([]*Header, len(body.Uncles)),
|
uncles: make([]*Header, len(body.Uncles)),
|
||||||
withdrawals: slices.Clone(body.Withdrawals),
|
withdrawals: slices.Clone(body.Withdrawals),
|
||||||
|
witness: b.witness,
|
||||||
}
|
}
|
||||||
for i := range body.Uncles {
|
for i := range body.Uncles {
|
||||||
block.uncles[i] = CopyHeader(body.Uncles[i])
|
block.uncles[i] = CopyHeader(body.Uncles[i])
|
||||||
@ -466,6 +484,16 @@ func (b *Block) WithBody(body Body) *Block {
|
|||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Block) WithWitness(witness *ExecutionWitness) *Block {
|
||||||
|
return &Block{
|
||||||
|
header: b.header,
|
||||||
|
transactions: b.transactions,
|
||||||
|
uncles: b.uncles,
|
||||||
|
withdrawals: b.withdrawals,
|
||||||
|
witness: witness,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hash returns the keccak256 hash of b's header.
|
// Hash returns the keccak256 hash of b's header.
|
||||||
// The hash is computed on the first call and cached thereafter.
|
// The hash is computed on the first call and cached thereafter.
|
||||||
func (b *Block) Hash() common.Hash {
|
func (b *Block) Hash() common.Hash {
|
||||||
|
2
go.mod
2
go.mod
@ -24,7 +24,7 @@ require (
|
|||||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||||
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0
|
github.com/ethereum/c-kzg-4844 v1.0.0
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa
|
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9
|
||||||
github.com/fatih/color v1.16.0
|
github.com/fatih/color v1.16.0
|
||||||
github.com/ferranbt/fastssz v0.1.2
|
github.com/ferranbt/fastssz v0.1.2
|
||||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
||||||
|
4
go.sum
4
go.sum
@ -170,8 +170,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
|
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa h1:mXkPoR07WlPVAClNzWuGAQNqmhxLqQILXhm73J5d9Ew=
|
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A=
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240726143912-7dc5142667fa/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w=
|
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
||||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
|
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
|
||||||
|
@ -69,6 +69,10 @@ func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCac
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *VerkleTrie) FlatdbNodeResolver(path []byte) ([]byte, error) {
|
||||||
|
return t.reader.node(path, common.Hash{})
|
||||||
|
}
|
||||||
|
|
||||||
// GetKey returns the sha3 preimage of a hashed key that was previously used
|
// GetKey returns the sha3 preimage of a hashed key that was previously used
|
||||||
// to store a value.
|
// to store a value.
|
||||||
func (t *VerkleTrie) GetKey(key []byte) []byte {
|
func (t *VerkleTrie) GetKey(key []byte) []byte {
|
||||||
@ -303,6 +307,27 @@ func (t *VerkleTrie) IsVerkle() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// to that proof.
|
||||||
|
func (t *VerkleTrie) Proof(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(t.root, postroot, keys, resolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, kvps, err := verkle.SerializeProof(proof)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, kvps, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which
|
// ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which
|
||||||
// are actual code, and 1 byte is the pushdata offset).
|
// are actual code, and 1 byte is the pushdata offset).
|
||||||
type ChunkedCode []byte
|
type ChunkedCode []byte
|
||||||
|
Loading…
Reference in New Issue
Block a user