@@ -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