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