mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
beacon/engine, core, eth/catalyst: verify if a block satisfies the inclusion list constraints
This commit is contained in:
parent
1986e8134b
commit
dffe6d31a5
9 changed files with 195 additions and 67 deletions
|
|
@ -237,8 +237,8 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||||
// and that the blockhash of the constructed block matches the parameters. Nil
|
// and that the blockhash of the constructed block matches the parameters. Nil
|
||||||
// Withdrawals value will propagate through the returned block. Empty
|
// Withdrawals value will propagate through the returned block. Empty
|
||||||
// Withdrawals value must be passed via non-nil, length 0 value in data.
|
// Withdrawals value must be passed via non-nil, length 0 value in data.
|
||||||
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, inclusionListTxs []*types.Transaction) (*types.Block, error) {
|
||||||
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot, requests)
|
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot, requests, inclusionListTxs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +251,7 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
||||||
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
||||||
// for stateless execution, so it skips checking if the executable data hashes to
|
// for stateless execution, so it skips checking if the executable data hashes to
|
||||||
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, inclusionListTxs []*types.Transaction) (*types.Block, error) {
|
||||||
txs, err := decodeTransactions(data.Transactions)
|
txs, err := decodeTransactions(data.Transactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -317,7 +317,8 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
}
|
}
|
||||||
return types.NewBlockWithHeader(header).
|
return types.NewBlockWithHeader(header).
|
||||||
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}).
|
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}).
|
||||||
WithWitness(data.ExecutionWitness),
|
WithWitness(data.ExecutionWitness).
|
||||||
|
WithInclusionListTransactions(inclusionListTxs),
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1741,7 +1741,7 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
}
|
}
|
||||||
defer bc.chainmu.Unlock()
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
_, n, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large)
|
_, n, _, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large)
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1753,10 +1753,10 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
// racey behaviour. If a sidechain import is in progress, and the historic state
|
// racey behaviour. If a sidechain import is in progress, and the historic state
|
||||||
// is imported, but then new canon-head is added before the actual sidechain
|
// is imported, but then new canon-head is added before the actual sidechain
|
||||||
// completes, then the historic state could be pruned again
|
// completes, then the historic state could be pruned again
|
||||||
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, error) {
|
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, *bool, error) {
|
||||||
// If the chain is terminating, don't even bother starting up.
|
// If the chain is terminating, don't even bother starting up.
|
||||||
if bc.insertStopped() {
|
if bc.insertStopped() {
|
||||||
return nil, 0, nil
|
return nil, 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if atomic.AddInt32(&bc.blockProcCounter, 1) == 1 {
|
if atomic.AddInt32(&bc.blockProcCounter, 1) == 1 {
|
||||||
|
|
@ -1821,7 +1821,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
for block != nil && bc.skipBlock(err, it) {
|
for block != nil && bc.skipBlock(err, it) {
|
||||||
log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash())
|
log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash())
|
||||||
if err := bc.writeKnownBlock(block); err != nil {
|
if err := bc.writeKnownBlock(block); err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
lastCanon = block
|
lastCanon = block
|
||||||
|
|
||||||
|
|
@ -1840,7 +1840,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
// We're post-merge and the parent is pruned, try to recover the parent state
|
// We're post-merge and the parent is pruned, try to recover the parent state
|
||||||
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
|
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
|
||||||
_, err := bc.recoverAncestors(block, makeWitness)
|
_, err := bc.recoverAncestors(block, makeWitness)
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
// Some other error(except ErrKnownBlock) occurred, abort.
|
// Some other error(except ErrKnownBlock) occurred, abort.
|
||||||
// ErrKnownBlock is allowed here since some known blocks
|
// ErrKnownBlock is allowed here since some known blocks
|
||||||
|
|
@ -1848,7 +1848,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
case err != nil && !errors.Is(err, ErrKnownBlock):
|
case err != nil && !errors.Is(err, ErrKnownBlock):
|
||||||
stats.ignored += len(it.chain)
|
stats.ignored += len(it.chain)
|
||||||
bc.reportBlock(block, nil, err)
|
bc.reportBlock(block, nil, err)
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
// Track the singleton witness from this chain insertion (if any)
|
// Track the singleton witness from this chain insertion (if any)
|
||||||
var witness *stateless.Witness
|
var witness *stateless.Witness
|
||||||
|
|
@ -1889,7 +1889,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
"hash", block.Hash(), "number", block.NumberU64())
|
"hash", block.Hash(), "number", block.NumberU64())
|
||||||
}
|
}
|
||||||
if err := bc.writeKnownBlock(block); err != nil {
|
if err := bc.writeKnownBlock(block); err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
stats.processed++
|
stats.processed++
|
||||||
if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
|
if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
|
||||||
|
|
@ -1913,7 +1913,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
// Report the import stats before returning the various results
|
// Report the import stats before returning the various results
|
||||||
stats.processed++
|
stats.processed++
|
||||||
|
|
@ -1934,7 +1934,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
// After merge we expect few side chains. Simply count
|
// After merge we expect few side chains. Simply count
|
||||||
// all blocks the CL gives us for GC processing time
|
// all blocks the CL gives us for GC processing time
|
||||||
bc.gcproc += res.procTime
|
bc.gcproc += res.procTime
|
||||||
return witness, it.index, nil // Direct block insertion of a single block
|
return witness, it.index, res.inclusionListSatisfied, nil // Direct block insertion of a single block
|
||||||
}
|
}
|
||||||
switch res.status {
|
switch res.status {
|
||||||
case CanonStatTy:
|
case CanonStatTy:
|
||||||
|
|
@ -1965,7 +1965,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.ignored += it.remaining()
|
stats.ignored += it.remaining()
|
||||||
return witness, it.index, err
|
return witness, it.index, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockProcessingResult is a summary of block processing
|
// blockProcessingResult is a summary of block processing
|
||||||
|
|
@ -1975,6 +1975,7 @@ type blockProcessingResult struct {
|
||||||
procTime time.Duration
|
procTime time.Duration
|
||||||
status WriteStatus
|
status WriteStatus
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
|
inclusionListSatisfied *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
|
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
|
||||||
|
|
@ -2183,6 +2184,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
procTime: proctime,
|
procTime: proctime,
|
||||||
status: status,
|
status: status,
|
||||||
witness: witness,
|
witness: witness,
|
||||||
|
inclusionListSatisfied: res.InclusionListSatisfied,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2193,7 +2195,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
// The method writes all (header-and-body-valid) blocks to disk, then tries to
|
// The method writes all (header-and-body-valid) blocks to disk, then tries to
|
||||||
// switch over to the new chain if the TD exceeded the current chain.
|
// switch over to the new chain if the TD exceeded the current chain.
|
||||||
// insertSideChain is only used pre-merge.
|
// insertSideChain is only used pre-merge.
|
||||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) {
|
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, *bool, error) {
|
||||||
var current = bc.CurrentBlock()
|
var current = bc.CurrentBlock()
|
||||||
|
|
||||||
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
||||||
|
|
@ -2222,13 +2224,13 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
||||||
// If someone legitimately side-mines blocks, they would still be imported as usual. However,
|
// If someone legitimately side-mines blocks, they would still be imported as usual. However,
|
||||||
// we cannot risk writing unverified blocks to disk when they obviously target the pruning
|
// we cannot risk writing unverified blocks to disk when they obviously target the pruning
|
||||||
// mechanism.
|
// mechanism.
|
||||||
return nil, it.index, errors.New("sidechain ghost-state attack")
|
return nil, it.index, nil, errors.New("sidechain ghost-state attack")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !bc.HasBlock(block.Hash(), block.NumberU64()) {
|
if !bc.HasBlock(block.Hash(), block.NumberU64()) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := bc.writeBlockWithoutState(block); err != nil {
|
if err := bc.writeBlockWithoutState(block); err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, nil, err
|
||||||
}
|
}
|
||||||
log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
|
log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
|
||||||
"diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
|
"diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
|
||||||
|
|
@ -2245,7 +2247,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
||||||
for parent != nil && !bc.HasState(parent.Root) {
|
for parent != nil && !bc.HasState(parent.Root) {
|
||||||
if bc.stateRecoverable(parent.Root) {
|
if bc.stateRecoverable(parent.Root) {
|
||||||
if err := bc.triedb.Recover(parent.Root); err != nil {
|
if err := bc.triedb.Recover(parent.Root); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -2255,7 +2257,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
||||||
parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1)
|
parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1)
|
||||||
}
|
}
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, it.index, errors.New("missing parent")
|
return nil, it.index, nil, errors.New("missing parent")
|
||||||
}
|
}
|
||||||
// Import all the pruned blocks to make the state available
|
// Import all the pruned blocks to make the state available
|
||||||
var (
|
var (
|
||||||
|
|
@ -2274,15 +2276,15 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
||||||
// memory here.
|
// memory here.
|
||||||
if len(blocks) >= 2048 || memory > 64*1024*1024 {
|
if len(blocks) >= 2048 || memory > 64*1024*1024 {
|
||||||
log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64())
|
log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64())
|
||||||
if _, _, err := bc.insertChain(blocks, true, false); err != nil {
|
if _, _, _, err := bc.insertChain(blocks, true, false); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
blocks, memory = blocks[:0], 0
|
blocks, memory = blocks[:0], 0
|
||||||
|
|
||||||
// If the chain is terminating, stop processing blocks
|
// If the chain is terminating, stop processing blocks
|
||||||
if bc.insertStopped() {
|
if bc.insertStopped() {
|
||||||
log.Debug("Abort during blocks processing")
|
log.Debug("Abort during blocks processing")
|
||||||
return nil, 0, nil
|
return nil, 0, nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2290,7 +2292,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
||||||
log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
|
log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
|
||||||
return bc.insertChain(blocks, true, makeWitness)
|
return bc.insertChain(blocks, true, makeWitness)
|
||||||
}
|
}
|
||||||
return nil, 0, nil
|
return nil, 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// recoverAncestors finds the closest ancestor with available state and re-execute
|
// recoverAncestors finds the closest ancestor with available state and re-execute
|
||||||
|
|
@ -2337,7 +2339,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
|
||||||
} else {
|
} else {
|
||||||
b = bc.GetBlock(hashes[i], numbers[i])
|
b = bc.GetBlock(hashes[i], numbers[i])
|
||||||
}
|
}
|
||||||
if _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil {
|
if _, _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil {
|
||||||
return b.ParentHash(), err
|
return b.ParentHash(), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2564,14 +2566,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error
|
||||||
// The key difference between the InsertChain is it won't do the canonical chain
|
// The key difference between the InsertChain is it won't do the canonical chain
|
||||||
// updating. It relies on the additional SetCanonical call to finalize the entire
|
// updating. It relies on the additional SetCanonical call to finalize the entire
|
||||||
// procedure.
|
// procedure.
|
||||||
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) {
|
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, *bool, error) {
|
||||||
if !bc.chainmu.TryLock() {
|
if !bc.chainmu.TryLock() {
|
||||||
return nil, errChainStopped
|
return nil, nil, errChainStopped
|
||||||
}
|
}
|
||||||
defer bc.chainmu.Unlock()
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness)
|
witness, _, inclusionListSatisfied, err := bc.insertChain(types.Blocks{block}, false, makeWitness)
|
||||||
return witness, err
|
return witness, inclusionListSatisfied, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCanonical rewinds the chain to set the new head block as the specified
|
// SetCanonical rewinds the chain to set the new head block as the specified
|
||||||
|
|
|
||||||
|
|
@ -3456,7 +3456,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
})
|
})
|
||||||
for _, block := range side {
|
for _, block := range side {
|
||||||
_, err := chain.InsertBlockWithoutSetHead(block, false)
|
_, _, err := chain.InsertBlockWithoutSetHead(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to insert into chain: %v", err)
|
t.Fatalf("Failed to insert into chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isInclusionListSatisfied := ValidateInclusionListTransactions(evm, block, statedb, block.InclusionListTransactions())
|
||||||
|
|
||||||
// Read requests if Prague is enabled.
|
// Read requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if config.IsPrague(block.Number(), block.Time()) {
|
if config.IsPrague(block.Number(), block.Time()) {
|
||||||
|
|
@ -134,6 +137,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
Requests: requests,
|
Requests: requests,
|
||||||
Logs: allLogs,
|
Logs: allLogs,
|
||||||
GasUsed: *usedGas,
|
GasUsed: *usedGas,
|
||||||
|
InclusionListSatisfied: &isInclusionListSatisfied,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,6 +319,66 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateInclusionListTransactions verifies that all transactions in the inclusion list
|
||||||
|
// are either included in the block or cannot be appended at the end of the block.
|
||||||
|
// If any appendable transaction is found, the block fails to meet the inclusion list constraints.
|
||||||
|
func ValidateInclusionListTransactions(evm *vm.EVM, block *types.Block, statedb *state.StateDB, inclusionListTxs []*types.Transaction) bool {
|
||||||
|
// Create a map of transaction hashes present in the block.
|
||||||
|
isIncludedTx := make(map[common.Hash]bool)
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
isIncludedTx[tx.Hash()] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the block's gas limit and gas left.
|
||||||
|
gasLimit := block.GasLimit()
|
||||||
|
gasLeft := gasLimit - block.GasUsed()
|
||||||
|
|
||||||
|
// Make a singer to get transaction senders.
|
||||||
|
signer := types.MakeSigner(evm.ChainConfig(), block.Number(), block.Time())
|
||||||
|
|
||||||
|
// Iterate over each transaction in the inclusion list and check if it is either included in the block or cannot be placed at the end of the block.
|
||||||
|
for _, tx := range inclusionListTxs {
|
||||||
|
// Check if the transaction is included in the block.
|
||||||
|
if isIncludedTx[tx.Hash()] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIP-7805 doesn't support blob transactions in inclusion list
|
||||||
|
if tx.Type() == types.BlobTxType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is not enough gas left to execute the transaction.
|
||||||
|
if tx.Gas() > gasLeft {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the transaction sender.
|
||||||
|
from, err := types.Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sender has not enough balance to cover the transaction cost.
|
||||||
|
balance := statedb.GetBalance(from).ToBig()
|
||||||
|
cost := tx.Cost()
|
||||||
|
if balance.Cmp(cost) < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sender has a nonce that doesn't match with the transaction nonce.
|
||||||
|
nonce := statedb.GetNonce(from)
|
||||||
|
if nonce != tx.Nonce() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// This transaction could have been appended at the end of the block. The block fails to satisfy the inclusion list constraints.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")
|
var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")
|
||||||
|
|
||||||
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,5 @@ type ProcessResult struct {
|
||||||
Requests [][]byte
|
Requests [][]byte
|
||||||
Logs []*types.Log
|
Logs []*types.Log
|
||||||
GasUsed uint64
|
GasUsed uint64
|
||||||
|
InclusionListSatisfied *bool
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,11 @@ type Block struct {
|
||||||
// that process it.
|
// that process it.
|
||||||
witness *ExecutionWitness
|
witness *ExecutionWitness
|
||||||
|
|
||||||
|
// inclusion list transactions are not an encoded part of the block body.
|
||||||
|
// It is held in Block in order for easy relaying to the places
|
||||||
|
// that process it.
|
||||||
|
inclusionListTxs Transactions
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
hash atomic.Pointer[common.Hash]
|
hash atomic.Pointer[common.Hash]
|
||||||
size atomic.Uint64
|
size atomic.Uint64
|
||||||
|
|
@ -432,6 +437,9 @@ func (b *Block) BlobGasUsed() *uint64 {
|
||||||
// ExecutionWitness returns the verkle execution witneess + proof for a block
|
// ExecutionWitness returns the verkle execution witneess + proof for a block
|
||||||
func (b *Block) ExecutionWitness() *ExecutionWitness { return b.witness }
|
func (b *Block) ExecutionWitness() *ExecutionWitness { return b.witness }
|
||||||
|
|
||||||
|
// InclusionListTransactions returns the inclusion list transactions for a block
|
||||||
|
func (b *Block) InclusionListTransactions() Transactions { return b.inclusionListTxs }
|
||||||
|
|
||||||
// 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 {
|
||||||
|
|
@ -495,6 +503,7 @@ func (b *Block) WithSeal(header *Header) *Block {
|
||||||
uncles: b.uncles,
|
uncles: b.uncles,
|
||||||
withdrawals: b.withdrawals,
|
withdrawals: b.withdrawals,
|
||||||
witness: b.witness,
|
witness: b.witness,
|
||||||
|
inclusionListTxs: b.inclusionListTxs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,6 +516,7 @@ func (b *Block) WithBody(body Body) *Block {
|
||||||
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,
|
witness: b.witness,
|
||||||
|
inclusionListTxs: b.inclusionListTxs,
|
||||||
}
|
}
|
||||||
for i := range body.Uncles {
|
for i := range body.Uncles {
|
||||||
block.uncles[i] = CopyHeader(body.Uncles[i])
|
block.uncles[i] = CopyHeader(body.Uncles[i])
|
||||||
|
|
@ -521,6 +531,18 @@ func (b *Block) WithWitness(witness *ExecutionWitness) *Block {
|
||||||
uncles: b.uncles,
|
uncles: b.uncles,
|
||||||
withdrawals: b.withdrawals,
|
withdrawals: b.withdrawals,
|
||||||
witness: witness,
|
witness: witness,
|
||||||
|
inclusionListTxs: b.inclusionListTxs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) WithInclusionListTransactions(inclusionListTxs Transactions) *Block {
|
||||||
|
return &Block{
|
||||||
|
header: b.header,
|
||||||
|
transactions: b.transactions,
|
||||||
|
uncles: b.uncles,
|
||||||
|
withdrawals: b.withdrawals,
|
||||||
|
witness: b.witness,
|
||||||
|
inclusionListTxs: inclusionListTxs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package catalyst
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -31,6 +32,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/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/txpool"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
|
|
@ -768,7 +770,8 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
||||||
defer api.newPayloadLock.Unlock()
|
defer api.newPayloadLock.Unlock()
|
||||||
|
|
||||||
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
||||||
block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot, requests)
|
inclusionListTxs := api.getValidInclusionListTransactions(inclusionList)
|
||||||
|
block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot, requests, inclusionListTxs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bgu := "nil"
|
bgu := "nil"
|
||||||
if params.BlobGasUsed != nil {
|
if params.BlobGasUsed != nil {
|
||||||
|
|
@ -841,7 +844,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
||||||
return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil
|
return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil
|
||||||
}
|
}
|
||||||
log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number())
|
log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number())
|
||||||
proofs, err := api.eth.BlockChain().InsertBlockWithoutSetHead(block, witness)
|
proofs, inclusionListSatisfied, err := api.eth.BlockChain().InsertBlockWithoutSetHead(block, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("NewPayload: inserting block failed", "error", err)
|
log.Warn("NewPayload: inserting block failed", "error", err)
|
||||||
|
|
||||||
|
|
@ -852,6 +855,13 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
||||||
|
|
||||||
return api.invalid(err, parent.Header()), nil
|
return api.invalid(err, parent.Header()), nil
|
||||||
}
|
}
|
||||||
|
if inclusionListSatisfied != nil && !*inclusionListSatisfied {
|
||||||
|
return engine.PayloadStatusV1{
|
||||||
|
Status: engine.INCLUSION_LIST_UNSATISFIED,
|
||||||
|
LatestValidHash: nil,
|
||||||
|
ValidationError: nil,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
|
|
||||||
// If witness collection was requested, inject that into the result too
|
// If witness collection was requested, inject that into the result too
|
||||||
|
|
@ -1110,6 +1120,34 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV2(start, count hexutil.Uint64)
|
||||||
return api.getBodiesByRange(start, count)
|
return api.getBodiesByRange(start, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *ConsensusAPI) getValidInclusionListTransactions(inclusionList types.InclusionList) []*types.Transaction {
|
||||||
|
txs := types.InclusionListToTransactions(inclusionList)
|
||||||
|
|
||||||
|
head := api.eth.BlockChain().CurrentBlock()
|
||||||
|
signer := types.MakeSigner(api.config(), head.Number, head.Time)
|
||||||
|
|
||||||
|
validTxs := make([]*types.Transaction, 0, len(txs))
|
||||||
|
for _, tx := range txs {
|
||||||
|
opts := &txpool.ValidationOptions{
|
||||||
|
Config: api.config(),
|
||||||
|
Accept: 0 |
|
||||||
|
1<<types.LegacyTxType |
|
||||||
|
1<<types.AccessListTxType |
|
||||||
|
1<<types.DynamicFeeTxType |
|
||||||
|
1<<types.SetCodeTxType,
|
||||||
|
MaxSize: params.MaxBytesPerInclusionList,
|
||||||
|
MinTip: new(big.Int).SetUint64(ethconfig.Defaults.TxPool.PriceLimit),
|
||||||
|
}
|
||||||
|
if err := txpool.ValidateTransaction(tx, head, signer, opts); err != nil {
|
||||||
|
log.Warn("invalid inclusion list transaction", "hash", tx.Hash(), "error", err)
|
||||||
|
} else {
|
||||||
|
validTxs = append(validTxs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validTxs
|
||||||
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) getBodiesByRange(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) {
|
func (api *ConsensusAPI) getBodiesByRange(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBody, error) {
|
||||||
if start == 0 || count == 0 {
|
if start == 0 || count == 0 {
|
||||||
return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count))
|
return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count))
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create the executable data, block %d: %v", i, err)
|
t.Fatalf("Failed to create the executable data, block %d: %v", i, err)
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +352,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create the executable data %v", err)
|
t.Fatalf("Failed to create the executable data %v", err)
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -947,7 +947,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||||
t.Fatal(testErr)
|
t.Fatal(testErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1541,7 +1541,7 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
|
||||||
if got := len(envelope.BlobsBundle.Blobs); got != want {
|
if got := len(envelope.BlobsBundle.Blobs); got != want {
|
||||||
t.Fatalf("invalid number of blobs: got %v, want %v", got, want)
|
t.Fatalf("invalid number of blobs: got %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
_, err := engine.ExecutableDataToBlock(*envelope.ExecutionPayload, make([]common.Hash, 1), nil, nil)
|
_, err := engine.ExecutableDataToBlock(*envelope.ExecutionPayload, make([]common.Hash, 1), nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
|
||||||
|
|
||||||
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
||||||
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
||||||
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests)
|
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bgu := "nil"
|
bgu := "nil"
|
||||||
if params.BlobGasUsed != nil {
|
if params.BlobGasUsed != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue