api_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // Copyright 2021 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package catalyst
  17. import (
  18. "bytes"
  19. "fmt"
  20. "math/big"
  21. "testing"
  22. "time"
  23. "github.com/ethereum/go-ethereum/common"
  24. "github.com/ethereum/go-ethereum/common/hexutil"
  25. "github.com/ethereum/go-ethereum/consensus/ethash"
  26. "github.com/ethereum/go-ethereum/core"
  27. "github.com/ethereum/go-ethereum/core/beacon"
  28. "github.com/ethereum/go-ethereum/core/rawdb"
  29. "github.com/ethereum/go-ethereum/core/types"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. "github.com/ethereum/go-ethereum/eth"
  32. "github.com/ethereum/go-ethereum/eth/downloader"
  33. "github.com/ethereum/go-ethereum/eth/ethconfig"
  34. "github.com/ethereum/go-ethereum/node"
  35. "github.com/ethereum/go-ethereum/p2p"
  36. "github.com/ethereum/go-ethereum/params"
  37. "github.com/ethereum/go-ethereum/trie"
  38. )
  39. var (
  40. // testKey is a private key to use for funding a tester account.
  41. testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
  42. // testAddr is the Ethereum address of the tester account.
  43. testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
  44. testBalance = big.NewInt(2e18)
  45. )
  46. func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
  47. db := rawdb.NewMemoryDatabase()
  48. config := params.AllEthashProtocolChanges
  49. genesis := &core.Genesis{
  50. Config: config,
  51. Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
  52. ExtraData: []byte("test genesis"),
  53. Timestamp: 9000,
  54. BaseFee: big.NewInt(params.InitialBaseFee),
  55. Difficulty: big.NewInt(0),
  56. }
  57. testNonce := uint64(0)
  58. generate := func(i int, g *core.BlockGen) {
  59. g.OffsetTime(5)
  60. g.SetExtra([]byte("test"))
  61. tx, _ := types.SignTx(types.NewTransaction(testNonce, common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(config), testKey)
  62. g.AddTx(tx)
  63. testNonce++
  64. }
  65. gblock := genesis.MustCommit(db)
  66. engine := ethash.NewFaker()
  67. blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate)
  68. totalDifficulty := big.NewInt(0)
  69. for _, b := range blocks {
  70. totalDifficulty.Add(totalDifficulty, b.Difficulty())
  71. }
  72. config.TerminalTotalDifficulty = totalDifficulty
  73. return genesis, blocks
  74. }
  75. func TestEth2AssembleBlock(t *testing.T) {
  76. genesis, blocks := generatePreMergeChain(10)
  77. n, ethservice := startEthService(t, genesis, blocks)
  78. defer n.Close()
  79. api := NewConsensusAPI(ethservice)
  80. signer := types.NewEIP155Signer(ethservice.BlockChain().Config().ChainID)
  81. tx, err := types.SignTx(types.NewTransaction(uint64(10), blocks[9].Coinbase(), big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, testKey)
  82. if err != nil {
  83. t.Fatalf("error signing transaction, err=%v", err)
  84. }
  85. ethservice.TxPool().AddLocal(tx)
  86. blockParams := beacon.PayloadAttributesV1{
  87. Timestamp: blocks[9].Time() + 5,
  88. }
  89. execData, err := assembleBlock(api, blocks[9].Hash(), &blockParams)
  90. if err != nil {
  91. t.Fatalf("error producing block, err=%v", err)
  92. }
  93. if len(execData.Transactions) != 1 {
  94. t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
  95. }
  96. }
  97. func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
  98. genesis, blocks := generatePreMergeChain(10)
  99. n, ethservice := startEthService(t, genesis, blocks[:9])
  100. defer n.Close()
  101. api := NewConsensusAPI(ethservice)
  102. // Put the 10th block's tx in the pool and produce a new block
  103. api.eth.TxPool().AddRemotesSync(blocks[9].Transactions())
  104. blockParams := beacon.PayloadAttributesV1{
  105. Timestamp: blocks[8].Time() + 5,
  106. }
  107. execData, err := assembleBlock(api, blocks[8].Hash(), &blockParams)
  108. if err != nil {
  109. t.Fatalf("error producing block, err=%v", err)
  110. }
  111. if len(execData.Transactions) != blocks[9].Transactions().Len() {
  112. t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
  113. }
  114. }
  115. func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
  116. genesis, blocks := generatePreMergeChain(10)
  117. n, ethservice := startEthService(t, genesis, blocks)
  118. defer n.Close()
  119. api := NewConsensusAPI(ethservice)
  120. fcState := beacon.ForkchoiceStateV1{
  121. HeadBlockHash: blocks[5].Hash(),
  122. SafeBlockHash: common.Hash{},
  123. FinalizedBlockHash: common.Hash{},
  124. }
  125. if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  126. t.Errorf("fork choice updated should not error: %v", err)
  127. } else if resp.PayloadStatus.Status != beacon.INVALID_TERMINAL_BLOCK.Status {
  128. t.Errorf("fork choice updated before total terminal difficulty should be INVALID")
  129. }
  130. }
  131. func TestEth2PrepareAndGetPayload(t *testing.T) {
  132. genesis, blocks := generatePreMergeChain(10)
  133. // We need to properly set the terminal total difficulty
  134. genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty())
  135. n, ethservice := startEthService(t, genesis, blocks[:9])
  136. defer n.Close()
  137. api := NewConsensusAPI(ethservice)
  138. // Put the 10th block's tx in the pool and produce a new block
  139. ethservice.TxPool().AddLocals(blocks[9].Transactions())
  140. blockParams := beacon.PayloadAttributesV1{
  141. Timestamp: blocks[8].Time() + 5,
  142. }
  143. fcState := beacon.ForkchoiceStateV1{
  144. HeadBlockHash: blocks[8].Hash(),
  145. SafeBlockHash: common.Hash{},
  146. FinalizedBlockHash: common.Hash{},
  147. }
  148. _, err := api.ForkchoiceUpdatedV1(fcState, &blockParams)
  149. if err != nil {
  150. t.Fatalf("error preparing payload, err=%v", err)
  151. }
  152. payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams)
  153. execData, err := api.GetPayloadV1(payloadID)
  154. if err != nil {
  155. t.Fatalf("error getting payload, err=%v", err)
  156. }
  157. if len(execData.Transactions) != blocks[9].Transactions().Len() {
  158. t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
  159. }
  160. // Test invalid payloadID
  161. var invPayload beacon.PayloadID
  162. copy(invPayload[:], payloadID[:])
  163. invPayload[0] = ^invPayload[0]
  164. _, err = api.GetPayloadV1(invPayload)
  165. if err == nil {
  166. t.Fatal("expected error retrieving invalid payload")
  167. }
  168. }
  169. func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan core.RemovedLogsEvent, wantNew, wantRemoved int) {
  170. t.Helper()
  171. if len(logsCh) != wantNew {
  172. t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew)
  173. }
  174. if len(rmLogsCh) != wantRemoved {
  175. t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved)
  176. }
  177. // Drain events.
  178. for i := 0; i < len(logsCh); i++ {
  179. <-logsCh
  180. }
  181. for i := 0; i < len(rmLogsCh); i++ {
  182. <-rmLogsCh
  183. }
  184. }
  185. func TestInvalidPayloadTimestamp(t *testing.T) {
  186. genesis, preMergeBlocks := generatePreMergeChain(10)
  187. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  188. defer n.Close()
  189. var (
  190. api = NewConsensusAPI(ethservice)
  191. parent = ethservice.BlockChain().CurrentBlock()
  192. )
  193. tests := []struct {
  194. time uint64
  195. shouldErr bool
  196. }{
  197. {0, true},
  198. {parent.Time(), true},
  199. {parent.Time() - 1, true},
  200. // TODO (MariusVanDerWijden) following tests are currently broken,
  201. // fixed in upcoming merge-kiln-v2 pr
  202. //{parent.Time() + 1, false},
  203. //{uint64(time.Now().Unix()) + uint64(time.Minute), false},
  204. }
  205. for i, test := range tests {
  206. t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) {
  207. params := beacon.PayloadAttributesV1{
  208. Timestamp: test.time,
  209. Random: crypto.Keccak256Hash([]byte{byte(123)}),
  210. SuggestedFeeRecipient: parent.Coinbase(),
  211. }
  212. fcState := beacon.ForkchoiceStateV1{
  213. HeadBlockHash: parent.Hash(),
  214. SafeBlockHash: common.Hash{},
  215. FinalizedBlockHash: common.Hash{},
  216. }
  217. _, err := api.ForkchoiceUpdatedV1(fcState, &params)
  218. if test.shouldErr && err == nil {
  219. t.Fatalf("expected error preparing payload with invalid timestamp, err=%v", err)
  220. } else if !test.shouldErr && err != nil {
  221. t.Fatalf("error preparing payload with valid timestamp, err=%v", err)
  222. }
  223. })
  224. }
  225. }
  226. func TestEth2NewBlock(t *testing.T) {
  227. genesis, preMergeBlocks := generatePreMergeChain(10)
  228. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  229. defer n.Close()
  230. var (
  231. api = NewConsensusAPI(ethservice)
  232. parent = preMergeBlocks[len(preMergeBlocks)-1]
  233. // This EVM code generates a log when the contract is created.
  234. logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
  235. )
  236. // The event channels.
  237. newLogCh := make(chan []*types.Log, 10)
  238. rmLogsCh := make(chan core.RemovedLogsEvent, 10)
  239. ethservice.BlockChain().SubscribeLogsEvent(newLogCh)
  240. ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh)
  241. for i := 0; i < 10; i++ {
  242. statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
  243. nonce := statedb.GetNonce(testAddr)
  244. tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
  245. ethservice.TxPool().AddLocal(tx)
  246. execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
  247. Timestamp: parent.Time() + 5,
  248. })
  249. if err != nil {
  250. t.Fatalf("Failed to create the executable data %v", err)
  251. }
  252. block, err := beacon.ExecutableDataToBlock(*execData)
  253. if err != nil {
  254. t.Fatalf("Failed to convert executable data to block %v", err)
  255. }
  256. newResp, err := api.NewPayloadV1(*execData)
  257. if err != nil || newResp.Status != "VALID" {
  258. t.Fatalf("Failed to insert block: %v", err)
  259. }
  260. if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 {
  261. t.Fatalf("Chain head shouldn't be updated")
  262. }
  263. checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
  264. fcState := beacon.ForkchoiceStateV1{
  265. HeadBlockHash: block.Hash(),
  266. SafeBlockHash: block.Hash(),
  267. FinalizedBlockHash: block.Hash(),
  268. }
  269. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  270. t.Fatalf("Failed to insert block: %v", err)
  271. }
  272. if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
  273. t.Fatalf("Chain head should be updated")
  274. }
  275. checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
  276. parent = block
  277. }
  278. // Introduce fork chain
  279. var (
  280. head = ethservice.BlockChain().CurrentBlock().NumberU64()
  281. )
  282. parent = preMergeBlocks[len(preMergeBlocks)-1]
  283. for i := 0; i < 10; i++ {
  284. execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
  285. Timestamp: parent.Time() + 6,
  286. })
  287. if err != nil {
  288. t.Fatalf("Failed to create the executable data %v", err)
  289. }
  290. block, err := beacon.ExecutableDataToBlock(*execData)
  291. if err != nil {
  292. t.Fatalf("Failed to convert executable data to block %v", err)
  293. }
  294. newResp, err := api.NewPayloadV1(*execData)
  295. if err != nil || newResp.Status != "VALID" {
  296. t.Fatalf("Failed to insert block: %v", err)
  297. }
  298. if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
  299. t.Fatalf("Chain head shouldn't be updated")
  300. }
  301. fcState := beacon.ForkchoiceStateV1{
  302. HeadBlockHash: block.Hash(),
  303. SafeBlockHash: block.Hash(),
  304. FinalizedBlockHash: block.Hash(),
  305. }
  306. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  307. t.Fatalf("Failed to insert block: %v", err)
  308. }
  309. if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
  310. t.Fatalf("Chain head should be updated")
  311. }
  312. parent, head = block, block.NumberU64()
  313. }
  314. }
  315. func TestEth2DeepReorg(t *testing.T) {
  316. // TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
  317. // before the totalTerminalDifficulty threshold
  318. /*
  319. genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2)
  320. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  321. defer n.Close()
  322. var (
  323. api = NewConsensusAPI(ethservice, nil)
  324. parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1]
  325. head = ethservice.BlockChain().CurrentBlock().NumberU64()
  326. )
  327. if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) {
  328. t.Errorf("Block %d not pruned", parent.NumberU64())
  329. }
  330. for i := 0; i < 10; i++ {
  331. execData, err := api.assembleBlock(AssembleBlockParams{
  332. ParentHash: parent.Hash(),
  333. Timestamp: parent.Time() + 5,
  334. })
  335. if err != nil {
  336. t.Fatalf("Failed to create the executable data %v", err)
  337. }
  338. block, err := ExecutableDataToBlock(ethservice.BlockChain().Config(), parent.Header(), *execData)
  339. if err != nil {
  340. t.Fatalf("Failed to convert executable data to block %v", err)
  341. }
  342. newResp, err := api.ExecutePayload(*execData)
  343. if err != nil || newResp.Status != "VALID" {
  344. t.Fatalf("Failed to insert block: %v", err)
  345. }
  346. if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
  347. t.Fatalf("Chain head shouldn't be updated")
  348. }
  349. if err := api.setHead(block.Hash()); err != nil {
  350. t.Fatalf("Failed to set head: %v", err)
  351. }
  352. if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
  353. t.Fatalf("Chain head should be updated")
  354. }
  355. parent, head = block, block.NumberU64()
  356. }
  357. */
  358. }
  359. // startEthService creates a full node instance for testing.
  360. func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) {
  361. t.Helper()
  362. n, err := node.New(&node.Config{
  363. P2P: p2p.Config{
  364. ListenAddr: "0.0.0.0:0",
  365. NoDiscovery: true,
  366. MaxPeers: 25,
  367. }})
  368. if err != nil {
  369. t.Fatal("can't create node:", err)
  370. }
  371. ethcfg := &ethconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
  372. ethservice, err := eth.New(n, ethcfg)
  373. if err != nil {
  374. t.Fatal("can't create eth service:", err)
  375. }
  376. if err := n.Start(); err != nil {
  377. t.Fatal("can't start node:", err)
  378. }
  379. if _, err := ethservice.BlockChain().InsertChain(blocks); err != nil {
  380. n.Close()
  381. t.Fatal("can't import test blocks:", err)
  382. }
  383. time.Sleep(500 * time.Millisecond) // give txpool enough time to consume head event
  384. ethservice.SetEtherbase(testAddr)
  385. ethservice.SetSynced()
  386. return n, ethservice
  387. }
  388. func TestFullAPI(t *testing.T) {
  389. genesis, preMergeBlocks := generatePreMergeChain(10)
  390. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  391. defer n.Close()
  392. var (
  393. parent = ethservice.BlockChain().CurrentBlock()
  394. // This EVM code generates a log when the contract is created.
  395. logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
  396. )
  397. callback := func(parent *types.Block) {
  398. statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
  399. nonce := statedb.GetNonce(testAddr)
  400. tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
  401. ethservice.TxPool().AddLocal(tx)
  402. }
  403. setupBlocks(t, ethservice, 10, parent, callback)
  404. }
  405. func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) {
  406. api := NewConsensusAPI(ethservice)
  407. for i := 0; i < n; i++ {
  408. callback(parent)
  409. payload := getNewPayload(t, api, parent)
  410. execResp, err := api.NewPayloadV1(*payload)
  411. if err != nil {
  412. t.Fatalf("can't execute payload: %v", err)
  413. }
  414. if execResp.Status != beacon.VALID {
  415. t.Fatalf("invalid status: %v", execResp.Status)
  416. }
  417. fcState := beacon.ForkchoiceStateV1{
  418. HeadBlockHash: payload.BlockHash,
  419. SafeBlockHash: payload.ParentHash,
  420. FinalizedBlockHash: payload.ParentHash,
  421. }
  422. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  423. t.Fatalf("Failed to insert block: %v", err)
  424. }
  425. if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
  426. t.Fatal("Chain head should be updated")
  427. }
  428. if ethservice.BlockChain().CurrentFinalizedBlock().NumberU64() != payload.Number-1 {
  429. t.Fatal("Finalized block should be updated")
  430. }
  431. parent = ethservice.BlockChain().CurrentBlock()
  432. }
  433. }
  434. func TestExchangeTransitionConfig(t *testing.T) {
  435. genesis, preMergeBlocks := generatePreMergeChain(10)
  436. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  437. defer n.Close()
  438. var (
  439. api = NewConsensusAPI(ethservice)
  440. )
  441. // invalid ttd
  442. config := beacon.TransitionConfigurationV1{
  443. TerminalTotalDifficulty: (*hexutil.Big)(big.NewInt(0)),
  444. TerminalBlockHash: common.Hash{},
  445. TerminalBlockNumber: 0,
  446. }
  447. if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
  448. t.Fatal("expected error on invalid config, invalid ttd")
  449. }
  450. // invalid terminal block hash
  451. config = beacon.TransitionConfigurationV1{
  452. TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
  453. TerminalBlockHash: common.Hash{1},
  454. TerminalBlockNumber: 0,
  455. }
  456. if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
  457. t.Fatal("expected error on invalid config, invalid hash")
  458. }
  459. // valid config
  460. config = beacon.TransitionConfigurationV1{
  461. TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
  462. TerminalBlockHash: common.Hash{},
  463. TerminalBlockNumber: 0,
  464. }
  465. if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
  466. t.Fatalf("expected no error on valid config, got %v", err)
  467. }
  468. // valid config
  469. config = beacon.TransitionConfigurationV1{
  470. TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
  471. TerminalBlockHash: preMergeBlocks[5].Hash(),
  472. TerminalBlockNumber: 6,
  473. }
  474. if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
  475. t.Fatalf("expected no error on valid config, got %v", err)
  476. }
  477. }
  478. /*
  479. TestNewPayloadOnInvalidChain sets up a valid chain and tries to feed blocks
  480. from an invalid chain to test if latestValidHash (LVH) works correctly.
  481. We set up the following chain where P1 ... Pn and P1'' are valid while
  482. P1' is invalid.
  483. We expect
  484. (1) The LVH to point to the current inserted payload if it was valid.
  485. (2) The LVH to point to the valid parent on an invalid payload (if the parent is available).
  486. (3) If the parent is unavailable, the LVH should not be set.
  487. CommonAncestor◄─▲── P1 ◄── P2 ◄─ P3 ◄─ ... ◄─ Pn
  488. └── P1' ◄─ P2' ◄─ P3' ◄─ ... ◄─ Pn'
  489. └── P1''
  490. */
  491. func TestNewPayloadOnInvalidChain(t *testing.T) {
  492. genesis, preMergeBlocks := generatePreMergeChain(10)
  493. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  494. defer n.Close()
  495. var (
  496. api = NewConsensusAPI(ethservice)
  497. parent = ethservice.BlockChain().CurrentBlock()
  498. // This EVM code generates a log when the contract is created.
  499. logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
  500. )
  501. for i := 0; i < 10; i++ {
  502. statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
  503. nonce := statedb.GetNonce(testAddr)
  504. tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
  505. ethservice.TxPool().AddLocal(tx)
  506. params := beacon.PayloadAttributesV1{
  507. Timestamp: parent.Time() + 1,
  508. Random: crypto.Keccak256Hash([]byte{byte(i)}),
  509. SuggestedFeeRecipient: parent.Coinbase(),
  510. }
  511. fcState := beacon.ForkchoiceStateV1{
  512. HeadBlockHash: parent.Hash(),
  513. SafeBlockHash: common.Hash{},
  514. FinalizedBlockHash: common.Hash{},
  515. }
  516. resp, err := api.ForkchoiceUpdatedV1(fcState, &params)
  517. if err != nil {
  518. t.Fatalf("error preparing payload, err=%v", err)
  519. }
  520. if resp.PayloadStatus.Status != beacon.VALID {
  521. t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status)
  522. }
  523. payload, err := api.GetPayloadV1(*resp.PayloadID)
  524. if err != nil {
  525. t.Fatalf("can't get payload: %v", err)
  526. }
  527. // TODO(493456442, marius) this test can be flaky since we rely on a 100ms
  528. // allowance for block generation internally.
  529. if len(payload.Transactions) == 0 {
  530. t.Fatalf("payload should not be empty")
  531. }
  532. execResp, err := api.NewPayloadV1(*payload)
  533. if err != nil {
  534. t.Fatalf("can't execute payload: %v", err)
  535. }
  536. if execResp.Status != beacon.VALID {
  537. t.Fatalf("invalid status: %v", execResp.Status)
  538. }
  539. fcState = beacon.ForkchoiceStateV1{
  540. HeadBlockHash: payload.BlockHash,
  541. SafeBlockHash: payload.ParentHash,
  542. FinalizedBlockHash: payload.ParentHash,
  543. }
  544. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  545. t.Fatalf("Failed to insert block: %v", err)
  546. }
  547. if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
  548. t.Fatalf("Chain head should be updated")
  549. }
  550. parent = ethservice.BlockChain().CurrentBlock()
  551. }
  552. }
  553. func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) {
  554. block, err := api.eth.Miner().GetSealingBlockSync(parentHash, params.Timestamp, params.SuggestedFeeRecipient, params.Random, false)
  555. if err != nil {
  556. return nil, err
  557. }
  558. return beacon.BlockToExecutableData(block), nil
  559. }
  560. func TestEmptyBlocks(t *testing.T) {
  561. genesis, preMergeBlocks := generatePreMergeChain(10)
  562. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  563. defer n.Close()
  564. commonAncestor := ethservice.BlockChain().CurrentBlock()
  565. api := NewConsensusAPI(ethservice)
  566. // Setup 10 blocks on the canonical chain
  567. setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
  568. // (1) check LatestValidHash by sending a normal payload (P1'')
  569. payload := getNewPayload(t, api, commonAncestor)
  570. status, err := api.NewPayloadV1(*payload)
  571. if err != nil {
  572. t.Fatal(err)
  573. }
  574. if status.Status != beacon.VALID {
  575. t.Errorf("invalid status: expected VALID got: %v", status.Status)
  576. }
  577. if !bytes.Equal(status.LatestValidHash[:], payload.BlockHash[:]) {
  578. t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, payload.BlockHash)
  579. }
  580. // (2) Now send P1' which is invalid
  581. payload = getNewPayload(t, api, commonAncestor)
  582. payload.GasUsed += 1
  583. payload = setBlockhash(payload)
  584. // Now latestValidHash should be the common ancestor
  585. status, err = api.NewPayloadV1(*payload)
  586. if err != nil {
  587. t.Fatal(err)
  588. }
  589. if status.Status != beacon.INVALID {
  590. t.Errorf("invalid status: expected INVALID got: %v", status.Status)
  591. }
  592. // Expect 0x0 on INVALID block on top of PoW block
  593. expected := common.Hash{}
  594. if !bytes.Equal(status.LatestValidHash[:], expected[:]) {
  595. t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, expected)
  596. }
  597. // (3) Now send a payload with unknown parent
  598. payload = getNewPayload(t, api, commonAncestor)
  599. payload.ParentHash = common.Hash{1}
  600. payload = setBlockhash(payload)
  601. // Now latestValidHash should be the common ancestor
  602. status, err = api.NewPayloadV1(*payload)
  603. if err != nil {
  604. t.Fatal(err)
  605. }
  606. if status.Status != beacon.SYNCING {
  607. t.Errorf("invalid status: expected SYNCING got: %v", status.Status)
  608. }
  609. if status.LatestValidHash != nil {
  610. t.Fatalf("invalid LVH: got %v wanted nil", status.LatestValidHash)
  611. }
  612. }
  613. func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 {
  614. params := beacon.PayloadAttributesV1{
  615. Timestamp: parent.Time() + 1,
  616. Random: crypto.Keccak256Hash([]byte{byte(1)}),
  617. SuggestedFeeRecipient: parent.Coinbase(),
  618. }
  619. payload, err := assembleBlock(api, parent.Hash(), &params)
  620. if err != nil {
  621. t.Fatal(err)
  622. }
  623. return payload
  624. }
  625. // setBlockhash sets the blockhash of a modified ExecutableData.
  626. // Can be used to make modified payloads look valid.
  627. func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 {
  628. txs, _ := decodeTransactions(data.Transactions)
  629. number := big.NewInt(0)
  630. number.SetUint64(data.Number)
  631. header := &types.Header{
  632. ParentHash: data.ParentHash,
  633. UncleHash: types.EmptyUncleHash,
  634. Coinbase: data.FeeRecipient,
  635. Root: data.StateRoot,
  636. TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
  637. ReceiptHash: data.ReceiptsRoot,
  638. Bloom: types.BytesToBloom(data.LogsBloom),
  639. Difficulty: common.Big0,
  640. Number: number,
  641. GasLimit: data.GasLimit,
  642. GasUsed: data.GasUsed,
  643. Time: data.Timestamp,
  644. BaseFee: data.BaseFeePerGas,
  645. Extra: data.ExtraData,
  646. MixDigest: data.Random,
  647. }
  648. block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
  649. data.BlockHash = block.Hash()
  650. return data
  651. }
  652. func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
  653. var txs = make([]*types.Transaction, len(enc))
  654. for i, encTx := range enc {
  655. var tx types.Transaction
  656. if err := tx.UnmarshalBinary(encTx); err != nil {
  657. return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
  658. }
  659. txs[i] = &tx
  660. }
  661. return txs, nil
  662. }
  663. func TestTrickRemoteBlockCache(t *testing.T) {
  664. // Setup two nodes
  665. genesis, preMergeBlocks := generatePreMergeChain(10)
  666. nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks)
  667. nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks)
  668. defer nodeA.Close()
  669. defer nodeB.Close()
  670. for nodeB.Server().NodeInfo().Ports.Listener == 0 {
  671. time.Sleep(250 * time.Millisecond)
  672. }
  673. nodeA.Server().AddPeer(nodeB.Server().Self())
  674. nodeB.Server().AddPeer(nodeA.Server().Self())
  675. apiA := NewConsensusAPI(ethserviceA)
  676. apiB := NewConsensusAPI(ethserviceB)
  677. commonAncestor := ethserviceA.BlockChain().CurrentBlock()
  678. // Setup 10 blocks on the canonical chain
  679. setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {})
  680. commonAncestor = ethserviceA.BlockChain().CurrentBlock()
  681. var invalidChain []*beacon.ExecutableDataV1
  682. // create a valid payload (P1)
  683. //payload1 := getNewPayload(t, apiA, commonAncestor)
  684. //invalidChain = append(invalidChain, payload1)
  685. // create an invalid payload2 (P2)
  686. payload2 := getNewPayload(t, apiA, commonAncestor)
  687. //payload2.ParentHash = payload1.BlockHash
  688. payload2.GasUsed += 1
  689. payload2 = setBlockhash(payload2)
  690. invalidChain = append(invalidChain, payload2)
  691. head := payload2
  692. // create some valid payloads on top
  693. for i := 0; i < 10; i++ {
  694. payload := getNewPayload(t, apiA, commonAncestor)
  695. payload.ParentHash = head.BlockHash
  696. payload = setBlockhash(payload)
  697. invalidChain = append(invalidChain, payload)
  698. head = payload
  699. }
  700. // feed the payloads to node B
  701. for _, payload := range invalidChain {
  702. status, err := apiB.NewPayloadV1(*payload)
  703. if err != nil {
  704. panic(err)
  705. }
  706. if status.Status == beacon.VALID {
  707. t.Error("invalid status: VALID on an invalid chain")
  708. }
  709. // Now reorg to the head of the invalid chain
  710. resp, err := apiB.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil)
  711. if err != nil {
  712. t.Fatal(err)
  713. }
  714. if resp.PayloadStatus.Status == beacon.VALID {
  715. t.Error("invalid status: VALID on an invalid chain")
  716. }
  717. time.Sleep(100 * time.Millisecond)
  718. }
  719. }
  720. func TestInvalidBloom(t *testing.T) {
  721. genesis, preMergeBlocks := generatePreMergeChain(10)
  722. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  723. ethservice.Merger().ReachTTD()
  724. defer n.Close()
  725. commonAncestor := ethservice.BlockChain().CurrentBlock()
  726. api := NewConsensusAPI(ethservice)
  727. // Setup 10 blocks on the canonical chain
  728. setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
  729. // (1) check LatestValidHash by sending a normal payload (P1'')
  730. payload := getNewPayload(t, api, commonAncestor)
  731. payload.LogsBloom = append(payload.LogsBloom, byte(1))
  732. status, err := api.NewPayloadV1(*payload)
  733. if err != nil {
  734. t.Fatal(err)
  735. }
  736. if status.Status != beacon.INVALIDBLOCKHASH {
  737. t.Errorf("invalid status: expected VALID got: %v", status.Status)
  738. }
  739. }
  740. func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
  741. genesis, preMergeBlocks := generatePreMergeChain(100)
  742. fmt.Println(genesis.Config.TerminalTotalDifficulty)
  743. genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
  744. fmt.Println(genesis.Config.TerminalTotalDifficulty)
  745. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  746. defer n.Close()
  747. var (
  748. api = NewConsensusAPI(ethservice)
  749. parent = preMergeBlocks[len(preMergeBlocks)-1]
  750. )
  751. // Test parent already post TTD in FCU
  752. fcState := beacon.ForkchoiceStateV1{
  753. HeadBlockHash: parent.Hash(),
  754. SafeBlockHash: common.Hash{},
  755. FinalizedBlockHash: common.Hash{},
  756. }
  757. resp, err := api.ForkchoiceUpdatedV1(fcState, nil)
  758. if err != nil {
  759. t.Fatalf("error sending forkchoice, err=%v", err)
  760. }
  761. if resp.PayloadStatus != beacon.INVALID_TERMINAL_BLOCK {
  762. t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
  763. }
  764. // Test parent already post TTD in NewPayload
  765. params := beacon.PayloadAttributesV1{
  766. Timestamp: parent.Time() + 1,
  767. Random: crypto.Keccak256Hash([]byte{byte(1)}),
  768. SuggestedFeeRecipient: parent.Coinbase(),
  769. }
  770. empty, err := api.eth.Miner().GetSealingBlockSync(parent.Hash(), params.Timestamp, params.SuggestedFeeRecipient, params.Random, true)
  771. if err != nil {
  772. t.Fatalf("error preparing payload, err=%v", err)
  773. }
  774. data := *beacon.BlockToExecutableData(empty)
  775. resp2, err := api.NewPayloadV1(data)
  776. if err != nil {
  777. t.Fatalf("error sending NewPayload, err=%v", err)
  778. }
  779. if resp2 != beacon.INVALID_TERMINAL_BLOCK {
  780. t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
  781. }
  782. }