feat: init inclusion list structures

Add high level functions in txpool to server transactions for inclusion list when demanded. Define functions for new engine apis
This commit is contained in:
Manav Darji 2023-08-26 22:18:36 +05:30
parent 56d2366699
commit 5f4dd02074
7 changed files with 131 additions and 0 deletions

View file

@ -63,6 +63,8 @@ type ExecutableData struct {
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"`
Summary []*InclusionListEntry `json:"summary"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -277,3 +279,15 @@ type ExecutionPayloadBodyV1 struct {
TransactionData []hexutil.Bytes `json:"transactions"` TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
} }
// InclusionListV1 is used in the response to GetInclusionListV1 and request to NewInclusionListV1
type InclusionListV1 struct {
Summary []*InclusionListEntry `json:"summary"`
Transactions []*types.Transaction `json:"transactions"`
}
// InclusionListEntry denotes a summary entry of (address, gasLimit)
type InclusionListEntry struct {
address common.Address `json:"address"`
gasLimit uint32 `json:"gasLimit"` // TODO(manav): change to uint8
}

View file

@ -1526,3 +1526,8 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus {
} }
return txpool.TxStatusUnknown return txpool.TxStatusUnknown
} }
// GetInclusionList returns an inclusion list from the pool containing pairs
// of transaction summary and data which are executable. Currently blob txs
// aren't supported in the inclusion list.
func (pool *BlobPool) GetInclusionList() *types.InclusionList { return nil }

View file

@ -51,6 +51,14 @@ const (
// more expensive to propagate; larger transactions also take more resources // more expensive to propagate; larger transactions also take more resources
// to validate whether they fit into the pool or not. // to validate whether they fit into the pool or not.
txMaxSize = 4 * txSlotSize // 128KB txMaxSize = 4 * txSlotSize // 128KB
// maxTxsPerInclusionList is the maximum number of transactions that can be
// included in an inclusion list (MAX_TRANSACTIONS_PER_INCLUSION_LIST).
maxTxsPerInclusionList = 16
// maxGasPerInclusionList is the maximum amount of gas that can be included
// in an inclusion list (INCLUSION_LIST_MAX_GAS).
maxGasPerInclusionList = 5000000 // 5M
) )
var ( var (
@ -1670,6 +1678,57 @@ func (pool *LegacyPool) demoteUnexecutables() {
} }
} }
// GetInclusionList returns an inclusion list from the pool containing pairs
// of transaction summary and data which are executable.
func (pool *LegacyPool) GetInclusionList() *types.InclusionList {
// The following conditions should be satisfied while filling the inclusion list.
// 1. The size of IL should not exceed `maxTxsPerInclusionList`
//
// 2. The total gas limit should not exceed `maxGasPerInclusionList`
//
// 3. The `maxFeePerGas` of all the transactions should be 1.125 times
// the `baseFee` of the current block to account for increase in the
// next block due to EIP 1559.
summaries := make([]*types.InclusionListEntry, 0, maxTxsPerInclusionList)
transactions := make([]*types.Transaction, 0, maxTxsPerInclusionList)
// TODO(manav2401): Not sure what's the best way to fetch transactions for inclusion list.
// Few possibilities are: prioritise locals first, borrow the tx ordering
// logic from miner if we want to choose best transactions.
// TODO(manav): This is just a brute force logic - has a lot of scope for improvement
remoteTxs := pool.Pending(true)
for _, account := range pool.Locals() {
if txs := remoteTxs[account]; len(txs) > 0 {
delete(remoteTxs, account)
// TODO(manav): Decide if we want multiple txs from the same account.
for _, lasyTx := range txs {
tx := lasyTx.Resolve()
// TODO(manav): Perform checks for (2) and (3) here.
summary := types.InclusionListEntry{
Address: account,
GasLimit: uint32(tx.Gas()),
}
summaries = append(summaries, &summary)
transactions = append(transactions, tx)
if len(summaries) == maxTxsPerInclusionList {
break
}
}
if len(summaries) == maxTxsPerInclusionList {
break
}
}
}
// If we still have space, fill with remote txs
// TODO(manav): borrow ordering logic from miner OR write a simple one for IL
return &types.InclusionList{Summary: summaries, Transactions: transactions}
}
// addressByHeartbeat is an account address tagged with its last activity timestamp. // addressByHeartbeat is an account address tagged with its last activity timestamp.
type addressByHeartbeat struct { type addressByHeartbeat struct {
address common.Address address common.Address

View file

@ -121,6 +121,10 @@ type SubPool interface {
// Locals retrieves the accounts currently considered local by the pool. // Locals retrieves the accounts currently considered local by the pool.
Locals() []common.Address Locals() []common.Address
// GetInclusionList returns an inclusion list from the pool containing pairs
// of transaction summary and data which are executable.
GetInclusionList() *types.InclusionList
// Status returns the known status (unknown/pending/queued) of a transaction // Status returns the known status (unknown/pending/queued) of a transaction
// identified by their hashes. // identified by their hashes.
Status(hash common.Hash) TxStatus Status(hash common.Hash) TxStatus

View file

@ -413,3 +413,14 @@ func (p *TxPool) Status(hash common.Hash) TxStatus {
} }
return TxStatusUnknown return TxStatusUnknown
} }
// GetInclusionList returns an inclusion list from the pool containing pairs
// of transaction summary and data which are executable.
func (p *TxPool) GetInclusionList() *types.InclusionList {
for _, subpool := range p.subpools {
if list := subpool.GetInclusionList(); list != nil {
return list
}
}
return nil
}

View file

@ -173,6 +173,18 @@ type Body struct {
Withdrawals []*Withdrawal `rlp:"optional"` Withdrawals []*Withdrawal `rlp:"optional"`
} }
// InclusionList represents pairs of transaction summary and the transaction data itself
type InclusionList struct {
Summary []*InclusionListEntry `json:"summary"`
Transactions []*Transaction `json:"transactions"`
}
// InclusionListEntry denotes a summary entry of (address, gasLimit)
type InclusionListEntry struct {
Address common.Address `json:"address"`
GasLimit uint32 `json:"gasLimit"` // TODO(manav): change to uint8
}
// Block represents an Ethereum block. // Block represents an Ethereum block.
// //
// Note the Block type tries to be 'immutable', and contains certain caches that rely // Note the Block type tries to be 'immutable', and contains certain caches that rely
@ -196,6 +208,8 @@ type Block struct {
transactions Transactions transactions Transactions
withdrawals Withdrawals withdrawals Withdrawals
summary []*InclusionListEntry
// caches // caches
hash atomic.Value hash atomic.Value
size atomic.Value size atomic.Value

View file

@ -87,6 +87,9 @@ var caps = []string{
"engine_newPayloadV3", "engine_newPayloadV3",
"engine_getPayloadBodiesByHashV1", "engine_getPayloadBodiesByHashV1",
"engine_getPayloadBodiesByRangeV1", "engine_getPayloadBodiesByRangeV1",
"engine_getInclusionListV1",
"engine_newInclusionListV1",
"engine_newPayloadVePBS",
} }
type ConsensusAPI struct { type ConsensusAPI struct {
@ -156,6 +159,27 @@ func newConsensusAPIWithoutHeartbeat(eth *eth.Ethereum) *ConsensusAPI {
return api return api
} }
// GetInclusionListV1 returns an inclusion list which contains summary + list of transactions
// which are valid for the current slot.
func (api *ConsensusAPI) GetInclusionListV1() (*engine.InclusionListV1, error) {
// TODO(manav): Do we check here if we're on correct fork or are fully synced? If not
// we might end up delivering wrong IL. Other will reject it though but do we want to
// risk it?
// Call txpool.GetInclusion list here
return nil, nil
}
// NewInclusionListV1 validates whether an inclusion list (summary + txs) is
// correct for the current state or not.
func (api *ConsensusAPI) NewInclusionListV1() bool {
return false
}
// TODO: update/define executable params
func (api *ConsensusAPI) NewPayloadVePBS() bool {
return false
}
// ForkchoiceUpdatedV1 has several responsibilities: // ForkchoiceUpdatedV1 has several responsibilities:
// //
// We try to set our blockchain to the headBlock. // We try to set our blockchain to the headBlock.