api_test.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2022 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. "math/big"
  19. "testing"
  20. "github.com/ethereum/go-ethereum/common"
  21. "github.com/ethereum/go-ethereum/consensus/ethash"
  22. "github.com/ethereum/go-ethereum/core"
  23. "github.com/ethereum/go-ethereum/core/beacon"
  24. "github.com/ethereum/go-ethereum/core/rawdb"
  25. "github.com/ethereum/go-ethereum/core/types"
  26. "github.com/ethereum/go-ethereum/crypto"
  27. "github.com/ethereum/go-ethereum/eth/downloader"
  28. "github.com/ethereum/go-ethereum/eth/ethconfig"
  29. "github.com/ethereum/go-ethereum/les"
  30. "github.com/ethereum/go-ethereum/node"
  31. "github.com/ethereum/go-ethereum/params"
  32. "github.com/ethereum/go-ethereum/trie"
  33. )
  34. var (
  35. // testKey is a private key to use for funding a tester account.
  36. testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
  37. // testAddr is the Ethereum address of the tester account.
  38. testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
  39. testBalance = big.NewInt(2e18)
  40. )
  41. func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Block) {
  42. db := rawdb.NewMemoryDatabase()
  43. config := params.AllEthashProtocolChanges
  44. genesis := &core.Genesis{
  45. Config: config,
  46. Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
  47. ExtraData: []byte("test genesis"),
  48. Timestamp: 9000,
  49. BaseFee: big.NewInt(params.InitialBaseFee),
  50. }
  51. gblock := genesis.MustCommit(db)
  52. engine := ethash.NewFaker()
  53. blocks, _ := core.GenerateChain(config, gblock, engine, db, n, nil)
  54. totalDifficulty := big.NewInt(0)
  55. var headers []*types.Header
  56. for _, b := range blocks {
  57. totalDifficulty.Add(totalDifficulty, b.Difficulty())
  58. headers = append(headers, b.Header())
  59. }
  60. config.TerminalTotalDifficulty = totalDifficulty
  61. return genesis, headers, blocks
  62. }
  63. func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
  64. genesis, headers, blocks := generatePreMergeChain(10)
  65. n, lesService := startLesService(t, genesis, headers)
  66. defer n.Close()
  67. api := NewConsensusAPI(lesService)
  68. fcState := beacon.ForkchoiceStateV1{
  69. HeadBlockHash: blocks[5].Hash(),
  70. SafeBlockHash: common.Hash{},
  71. FinalizedBlockHash: common.Hash{},
  72. }
  73. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err == nil {
  74. t.Errorf("fork choice updated before total terminal difficulty should fail")
  75. }
  76. }
  77. func TestExecutePayloadV1(t *testing.T) {
  78. genesis, headers, blocks := generatePreMergeChain(10)
  79. n, lesService := startLesService(t, genesis, headers[:9])
  80. lesService.Merger().ReachTTD()
  81. defer n.Close()
  82. api := NewConsensusAPI(lesService)
  83. fcState := beacon.ForkchoiceStateV1{
  84. HeadBlockHash: blocks[8].Hash(),
  85. SafeBlockHash: common.Hash{},
  86. FinalizedBlockHash: common.Hash{},
  87. }
  88. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  89. t.Errorf("Failed to update head %v", err)
  90. }
  91. block := blocks[9]
  92. fakeBlock := types.NewBlock(&types.Header{
  93. ParentHash: block.ParentHash(),
  94. UncleHash: crypto.Keccak256Hash(nil),
  95. Coinbase: block.Coinbase(),
  96. Root: block.Root(),
  97. TxHash: crypto.Keccak256Hash(nil),
  98. ReceiptHash: crypto.Keccak256Hash(nil),
  99. Bloom: block.Bloom(),
  100. Difficulty: big.NewInt(0),
  101. Number: block.Number(),
  102. GasLimit: block.GasLimit(),
  103. GasUsed: block.GasUsed(),
  104. Time: block.Time(),
  105. Extra: block.Extra(),
  106. MixDigest: block.MixDigest(),
  107. Nonce: types.BlockNonce{},
  108. BaseFee: block.BaseFee(),
  109. }, nil, nil, nil, trie.NewStackTrie(nil))
  110. _, err := api.ExecutePayloadV1(beacon.ExecutableDataV1{
  111. ParentHash: fakeBlock.ParentHash(),
  112. FeeRecipient: fakeBlock.Coinbase(),
  113. StateRoot: fakeBlock.Root(),
  114. ReceiptsRoot: fakeBlock.ReceiptHash(),
  115. LogsBloom: fakeBlock.Bloom().Bytes(),
  116. Random: fakeBlock.MixDigest(),
  117. Number: fakeBlock.NumberU64(),
  118. GasLimit: fakeBlock.GasLimit(),
  119. GasUsed: fakeBlock.GasUsed(),
  120. Timestamp: fakeBlock.Time(),
  121. ExtraData: fakeBlock.Extra(),
  122. BaseFeePerGas: fakeBlock.BaseFee(),
  123. BlockHash: fakeBlock.Hash(),
  124. Transactions: encodeTransactions(fakeBlock.Transactions()),
  125. })
  126. if err != nil {
  127. t.Errorf("Failed to execute payload %v", err)
  128. }
  129. headHeader := api.les.BlockChain().CurrentHeader()
  130. if headHeader.Number.Uint64() != fakeBlock.NumberU64()-1 {
  131. t.Fatal("Unexpected chain head update")
  132. }
  133. fcState = beacon.ForkchoiceStateV1{
  134. HeadBlockHash: fakeBlock.Hash(),
  135. SafeBlockHash: common.Hash{},
  136. FinalizedBlockHash: common.Hash{},
  137. }
  138. if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
  139. t.Fatal("Failed to update head")
  140. }
  141. headHeader = api.les.BlockChain().CurrentHeader()
  142. if headHeader.Number.Uint64() != fakeBlock.NumberU64() {
  143. t.Fatal("Failed to update chain head")
  144. }
  145. }
  146. func TestEth2DeepReorg(t *testing.T) {
  147. // TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
  148. // before the totalTerminalDifficulty threshold
  149. /*
  150. genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2)
  151. n, ethservice := startEthService(t, genesis, preMergeBlocks)
  152. defer n.Close()
  153. var (
  154. api = NewConsensusAPI(ethservice, nil)
  155. parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1]
  156. head = ethservice.BlockChain().CurrentBlock().NumberU64()
  157. )
  158. if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) {
  159. t.Errorf("Block %d not pruned", parent.NumberU64())
  160. }
  161. for i := 0; i < 10; i++ {
  162. execData, err := api.assembleBlock(AssembleBlockParams{
  163. ParentHash: parent.Hash(),
  164. Timestamp: parent.Time() + 5,
  165. })
  166. if err != nil {
  167. t.Fatalf("Failed to create the executable data %v", err)
  168. }
  169. block, err := ExecutableDataToBlock(ethservice.BlockChain().Config(), parent.Header(), *execData)
  170. if err != nil {
  171. t.Fatalf("Failed to convert executable data to block %v", err)
  172. }
  173. newResp, err := api.ExecutePayload(*execData)
  174. if err != nil || newResp.Status != "VALID" {
  175. t.Fatalf("Failed to insert block: %v", err)
  176. }
  177. if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
  178. t.Fatalf("Chain head shouldn't be updated")
  179. }
  180. if err := api.setCanonical(block.Hash()); err != nil {
  181. t.Fatalf("Failed to set head: %v", err)
  182. }
  183. if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
  184. t.Fatalf("Chain head should be updated")
  185. }
  186. parent, head = block, block.NumberU64()
  187. }
  188. */
  189. }
  190. // startEthService creates a full node instance for testing.
  191. func startLesService(t *testing.T, genesis *core.Genesis, headers []*types.Header) (*node.Node, *les.LightEthereum) {
  192. t.Helper()
  193. n, err := node.New(&node.Config{})
  194. if err != nil {
  195. t.Fatal("can't create node:", err)
  196. }
  197. ethcfg := &ethconfig.Config{
  198. Genesis: genesis,
  199. Ethash: ethash.Config{PowMode: ethash.ModeFake},
  200. SyncMode: downloader.LightSync,
  201. TrieDirtyCache: 256,
  202. TrieCleanCache: 256,
  203. LightPeers: 10,
  204. }
  205. lesService, err := les.New(n, ethcfg)
  206. if err != nil {
  207. t.Fatal("can't create eth service:", err)
  208. }
  209. if err := n.Start(); err != nil {
  210. t.Fatal("can't start node:", err)
  211. }
  212. if _, err := lesService.BlockChain().InsertHeaderChain(headers, 0); err != nil {
  213. n.Close()
  214. t.Fatal("can't import test headers:", err)
  215. }
  216. return n, lesService
  217. }
  218. func encodeTransactions(txs []*types.Transaction) [][]byte {
  219. var enc = make([][]byte, len(txs))
  220. for i, tx := range txs {
  221. enc[i], _ = tx.MarshalBinary()
  222. }
  223. return enc
  224. }