github.com/ethereum/go-ethereum@v1.16.1/internal/era/era_test.go (about) 1 // Copyright 2024 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 era 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "math/big" 24 "os" 25 "testing" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/rlp" 30 ) 31 32 type testchain struct { 33 headers [][]byte 34 bodies [][]byte 35 receipts [][]byte 36 tds []*big.Int 37 } 38 39 func TestEra1Builder(t *testing.T) { 40 t.Parallel() 41 42 // Get temp directory. 43 f, err := os.CreateTemp(t.TempDir(), "era1-test") 44 if err != nil { 45 t.Fatalf("error creating temp file: %v", err) 46 } 47 defer f.Close() 48 49 var ( 50 builder = NewBuilder(f) 51 chain = testchain{} 52 ) 53 for i := 0; i < 128; i++ { 54 chain.headers = append(chain.headers, mustEncode(&types.Header{Number: big.NewInt(int64(i))})) 55 chain.bodies = append(chain.bodies, mustEncode(&types.Body{Transactions: []*types.Transaction{types.NewTransaction(0, common.Address{byte(i)}, nil, 0, nil, nil)}})) 56 chain.receipts = append(chain.receipts, mustEncode(&types.Receipts{{CumulativeGasUsed: uint64(i)}})) 57 chain.tds = append(chain.tds, big.NewInt(int64(i))) 58 } 59 60 // Write blocks to Era1. 61 for i := 0; i < len(chain.headers); i++ { 62 var ( 63 header = chain.headers[i] 64 body = chain.bodies[i] 65 receipts = chain.receipts[i] 66 hash = common.Hash{byte(i)} 67 td = chain.tds[i] 68 ) 69 if err = builder.AddRLP(header, body, receipts, uint64(i), hash, td, big.NewInt(1)); err != nil { 70 t.Fatalf("error adding entry: %v", err) 71 } 72 } 73 74 // Finalize Era1. 75 if _, err := builder.Finalize(); err != nil { 76 t.Fatalf("error finalizing era1: %v", err) 77 } 78 79 // Verify Era1 contents. 80 e, err := Open(f.Name()) 81 if err != nil { 82 t.Fatalf("failed to open era: %v", err) 83 } 84 defer e.Close() 85 it, err := NewRawIterator(e) 86 if err != nil { 87 t.Fatalf("failed to make iterator: %s", err) 88 } 89 for i := uint64(0); i < uint64(len(chain.headers)); i++ { 90 if !it.Next() { 91 t.Fatalf("expected more entries") 92 } 93 if it.Error() != nil { 94 t.Fatalf("unexpected error %v", it.Error()) 95 } 96 // Check headers. 97 rawHeader, err := io.ReadAll(it.Header) 98 if err != nil { 99 t.Fatalf("error reading header from iterator: %v", err) 100 } 101 if !bytes.Equal(rawHeader, chain.headers[i]) { 102 t.Fatalf("mismatched header: want %s, got %s", chain.headers[i], rawHeader) 103 } 104 105 // Check bodies. 106 body, err := io.ReadAll(it.Body) 107 if err != nil { 108 t.Fatalf("error reading body: %v", err) 109 } 110 if !bytes.Equal(body, chain.bodies[i]) { 111 t.Fatalf("mismatched body: want %s, got %s", chain.bodies[i], body) 112 } 113 114 // Check receipts. 115 rawReceipts, err := io.ReadAll(it.Receipts) 116 if err != nil { 117 t.Fatalf("error reading receipts from iterator: %v", err) 118 } 119 if !bytes.Equal(rawReceipts, chain.receipts[i]) { 120 t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], rawReceipts) 121 } 122 receipts, err := getReceiptsByNumber(e, i) 123 if err != nil { 124 t.Fatalf("error reading receipts: %v", err) 125 } 126 encReceipts, err := rlp.EncodeToBytes(receipts) 127 if err != nil { 128 t.Fatalf("error encoding receipts: %v", err) 129 } 130 if !bytes.Equal(encReceipts, chain.receipts[i]) { 131 t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], encReceipts) 132 } 133 134 // Check total difficulty. 135 rawTd, err := io.ReadAll(it.TotalDifficulty) 136 if err != nil { 137 t.Fatalf("error reading td: %v", err) 138 } 139 td := new(big.Int).SetBytes(reverseOrder(rawTd)) 140 if td.Cmp(chain.tds[i]) != 0 { 141 t.Fatalf("mismatched tds: want %s, got %s", chain.tds[i], td) 142 } 143 } 144 } 145 146 func TestEraFilename(t *testing.T) { 147 t.Parallel() 148 149 for i, tt := range []struct { 150 network string 151 epoch int 152 root common.Hash 153 expected string 154 }{ 155 {"mainnet", 1, common.Hash{1}, "mainnet-00001-01000000.era1"}, 156 } { 157 got := Filename(tt.network, tt.epoch, tt.root) 158 if tt.expected != got { 159 t.Errorf("test %d: invalid filename: want %s, got %s", i, tt.expected, got) 160 } 161 } 162 } 163 164 func mustEncode(obj any) []byte { 165 b, err := rlp.EncodeToBytes(obj) 166 if err != nil { 167 panic(fmt.Sprintf("failed in encode obj: %v", err)) 168 } 169 return b 170 } 171 172 func getReceiptsByNumber(e *Era, number uint64) (types.Receipts, error) { 173 r, err := e.GetRawReceiptsByNumber(number) 174 if err != nil { 175 return nil, err 176 } 177 var receipts types.Receipts 178 if err := rlp.DecodeBytes(r, &receipts); err != nil { 179 return nil, err 180 } 181 return receipts, nil 182 }