github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/internal/era/accumulator.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package era 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 24 "github.com/ethereum/go-ethereum/common" 25 ssz "github.com/ferranbt/fastssz" 26 ) 27 28 // ComputeAccumulator calculates the SSZ hash tree root of the Era1 29 // accumulator of header records. 30 func ComputeAccumulator(hashes []common.Hash, tds []*big.Int) (common.Hash, error) { 31 if len(hashes) != len(tds) { 32 return common.Hash{}, errors.New("must have equal number hashes as td values") 33 } 34 if len(hashes) > MaxEra1Size { 35 return common.Hash{}, fmt.Errorf("too many records: have %d, max %d", len(hashes), MaxEra1Size) 36 } 37 hh := ssz.NewHasher() 38 for i := range hashes { 39 rec := headerRecord{hashes[i], tds[i]} 40 root, err := rec.HashTreeRoot() 41 if err != nil { 42 return common.Hash{}, err 43 } 44 hh.Append(root[:]) 45 } 46 hh.MerkleizeWithMixin(0, uint64(len(hashes)), uint64(MaxEra1Size)) 47 return hh.HashRoot() 48 } 49 50 // headerRecord is an individual record for a historical header. 51 // 52 // See https://github.com/ethereum/portal-network-specs/blob/master/history-network.md#the-header-accumulator 53 // for more information. 54 type headerRecord struct { 55 Hash common.Hash 56 TotalDifficulty *big.Int 57 } 58 59 // GetTree completes the ssz.HashRoot interface, but is unused. 60 func (h *headerRecord) GetTree() (*ssz.Node, error) { 61 return nil, nil 62 } 63 64 // HashTreeRoot ssz hashes the headerRecord object. 65 func (h *headerRecord) HashTreeRoot() ([32]byte, error) { 66 return ssz.HashWithDefaultHasher(h) 67 } 68 69 // HashTreeRootWith ssz hashes the headerRecord object with a hasher. 70 func (h *headerRecord) HashTreeRootWith(hh ssz.HashWalker) (err error) { 71 hh.PutBytes(h.Hash[:]) 72 td := bigToBytes32(h.TotalDifficulty) 73 hh.PutBytes(td[:]) 74 hh.Merkleize(0) 75 return 76 } 77 78 // bigToBytes32 converts a big.Int into a little-endian 32-byte array. 79 func bigToBytes32(n *big.Int) (b [32]byte) { 80 n.FillBytes(b[:]) 81 reverseOrder(b[:]) 82 return 83 } 84 85 // reverseOrder reverses the byte order of a slice. 86 func reverseOrder(b []byte) []byte { 87 for i := 0; i < 16; i++ { 88 b[i], b[32-i-1] = b[32-i-1], b[i] 89 } 90 return b 91 }