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