Skip to content

Commit 71abcf4

Browse files
committed
eth/catalyst: add an unit test for verifying new payload against inclusion list
1 parent 0f64aac commit 71abcf4

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

eth/catalyst/api_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,3 +1799,121 @@ func TestValidateRequests(t *testing.T) {
17991799
})
18001800
}
18011801
}
1802+
1803+
func TestInclusionList(t *testing.T) {
1804+
genesis, blocks := generateMergeChain(100, false)
1805+
1806+
// Set cancun time to last block + 5 seconds
1807+
timestamp := blocks[len(blocks)-1].Time() + 5
1808+
genesis.Config.ShanghaiTime = &timestamp
1809+
genesis.Config.CancunTime = &timestamp
1810+
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule
1811+
1812+
n, ethservice := startEthService(t, genesis, blocks)
1813+
defer n.Close()
1814+
1815+
api := NewConsensusAPI(ethservice)
1816+
parent := ethservice.BlockChain().CurrentHeader()
1817+
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
1818+
1819+
// Prepare transactions.
1820+
signer := types.LatestSigner(ethservice.BlockChain().Config())
1821+
testUserKey, _ := crypto.GenerateKey()
1822+
testUserAddress := crypto.PubkeyToAddress(testUserKey.PublicKey)
1823+
validTx1 := types.MustSignNewTx(testKey, signer, &types.LegacyTx{
1824+
Nonce: statedb.GetNonce(testAddr),
1825+
To: &testUserAddress,
1826+
Value: big.NewInt(1000),
1827+
Gas: params.TxGas,
1828+
GasPrice: big.NewInt(params.InitialBaseFee),
1829+
})
1830+
validTx2 := types.MustSignNewTx(testKey, signer, &types.AccessListTx{
1831+
ChainID: ethservice.BlockChain().Config().ChainID,
1832+
Nonce: statedb.GetNonce(testAddr) + 1,
1833+
To: &testUserAddress,
1834+
Value: big.NewInt(1000),
1835+
Gas: params.TxGas,
1836+
GasPrice: big.NewInt(params.InitialBaseFee),
1837+
})
1838+
invalidTx := types.MustSignNewTx(testUserKey, signer, &types.AccessListTx{
1839+
ChainID: ethservice.BlockChain().Config().ChainID,
1840+
Nonce: statedb.GetNonce(testUserAddress),
1841+
To: &testAddr,
1842+
Value: big.NewInt(1000),
1843+
Gas: params.TxGas,
1844+
GasPrice: big.NewInt(params.InitialBaseFee),
1845+
}) // This tx is invalid as `testUserAddress` has insufficient funds for `gas` * `price` + `value`.
1846+
1847+
// Add `validTx1` to the pool.
1848+
ethservice.TxPool().Add([]*types.Transaction{validTx1}, true)
1849+
1850+
for i, tt := range []*struct {
1851+
name string
1852+
inclusionList types.InclusionList
1853+
expectedStatus string
1854+
}{
1855+
{
1856+
name: "Block contains all transactions in the inclusion list",
1857+
inclusionList: types.TransactionsToInclusionList([]*types.Transaction{validTx1}),
1858+
expectedStatus: engine.VALID,
1859+
},
1860+
{
1861+
name: "Block misses one transaction in the inclusion list, which could have been included",
1862+
inclusionList: types.TransactionsToInclusionList([]*types.Transaction{validTx1, validTx2}),
1863+
expectedStatus: engine.INCLUSION_LIST_UNSATISFIED,
1864+
},
1865+
{
1866+
name: "Block misses only invalid transactions in the inclusion list",
1867+
inclusionList: types.TransactionsToInclusionList([]*types.Transaction{validTx1, invalidTx}),
1868+
expectedStatus: engine.VALID,
1869+
},
1870+
} {
1871+
t.Run(tt.name, func(t *testing.T) {
1872+
// Build Shanghai block.
1873+
blockParams := engine.PayloadAttributes{
1874+
Timestamp: parent.Time + 5 + uint64(i),
1875+
Random: crypto.Keccak256Hash([]byte{byte(0)}),
1876+
SuggestedFeeRecipient: parent.Coinbase,
1877+
Withdrawals: make([]*types.Withdrawal, 0),
1878+
BeaconRoot: &common.Hash{42},
1879+
}
1880+
fcState := engine.ForkchoiceStateV1{
1881+
HeadBlockHash: parent.Hash(),
1882+
SafeBlockHash: common.Hash{},
1883+
FinalizedBlockHash: common.Hash{},
1884+
}
1885+
1886+
var (
1887+
payload *engine.ExecutionPayloadEnvelope
1888+
resp engine.ForkChoiceResponse
1889+
err error
1890+
)
1891+
1892+
// Start building the payload.
1893+
if resp, err = api.ForkchoiceUpdatedV3(fcState, &blockParams); err != nil {
1894+
t.Fatalf("error preparing payload, err=%v", err)
1895+
}
1896+
if resp.PayloadStatus.Status != engine.VALID {
1897+
t.Fatalf("error preparing payload, invalid status=%v", resp.PayloadStatus.Status)
1898+
}
1899+
1900+
// Get the payload.
1901+
if payload, err = api.getPayload(*resp.PayloadID, true); err != nil {
1902+
t.Fatalf("error getting payload, err=%v", err)
1903+
}
1904+
// The payload is expected to have 1 transaction, which is `validTx1`.
1905+
if len(payload.ExecutionPayload.Transactions) != 1 {
1906+
t.Fatalf("expected 1 transaction but got %d", len(payload.ExecutionPayload.Transactions))
1907+
}
1908+
1909+
// Verify if the block satisfies the inclusion list constraints.
1910+
status, err := api.newPayload(*payload.ExecutionPayload, []common.Hash{}, &common.Hash{42}, nil, tt.inclusionList, false)
1911+
if err != nil {
1912+
t.Fatalf("error validating payload, err=%v", err)
1913+
}
1914+
if status.Status != tt.expectedStatus {
1915+
t.Fatalf("expected status %v but got %v", tt.expectedStatus, status.Status)
1916+
}
1917+
})
1918+
}
1919+
}

0 commit comments

Comments
 (0)