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  }