github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/types/config.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 types 18 19 import ( 20 "crypto/sha256" 21 "fmt" 22 "math" 23 "os" 24 "slices" 25 "sort" 26 "strconv" 27 "strings" 28 29 "github.com/ethereum/go-ethereum/beacon/merkle" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/common/hexutil" 32 "github.com/ethereum/go-ethereum/log" 33 "gopkg.in/yaml.v3" 34 ) 35 36 // syncCommitteeDomain specifies the signatures specific use to avoid clashes 37 // across signing different data structures. 38 const syncCommitteeDomain = 7 39 40 var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"} 41 42 // Fork describes a single beacon chain fork and also stores the calculated 43 // signature domain used after this fork. 44 type Fork struct { 45 // Name of the fork in the chain config (config.yaml) file 46 Name string 47 48 // Epoch when given fork version is activated 49 Epoch uint64 50 51 // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types 52 Version []byte 53 54 // index in list of known forks or MaxInt if unknown 55 knownIndex int 56 57 // calculated by computeDomain, based on fork version and genesis validators root 58 domain merkle.Value 59 } 60 61 // computeDomain returns the signature domain based on the given fork version 62 // and genesis validator set root. 63 func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) { 64 var ( 65 hasher = sha256.New() 66 forkVersion32 merkle.Value 67 forkDataRoot merkle.Value 68 ) 69 copy(forkVersion32[:], f.Version) 70 hasher.Write(forkVersion32[:]) 71 hasher.Write(genesisValidatorsRoot[:]) 72 hasher.Sum(forkDataRoot[:0]) 73 74 f.domain[0] = syncCommitteeDomain 75 copy(f.domain[4:], forkDataRoot[:28]) 76 } 77 78 // Forks is the list of all beacon chain forks in the chain configuration. 79 type Forks []*Fork 80 81 // domain returns the signature domain for the given epoch (assumes that domains 82 // have already been calculated). 83 func (f Forks) domain(epoch uint64) (merkle.Value, error) { 84 for i := len(f) - 1; i >= 0; i-- { 85 if epoch >= f[i].Epoch { 86 return f[i].domain, nil 87 } 88 } 89 return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch) 90 } 91 92 // SigningRoot calculates the signing root of the given header. 93 func (f Forks) SigningRoot(header Header) (common.Hash, error) { 94 domain, err := f.domain(header.Epoch()) 95 if err != nil { 96 return common.Hash{}, err 97 } 98 var ( 99 signingRoot common.Hash 100 headerHash = header.Hash() 101 hasher = sha256.New() 102 ) 103 hasher.Write(headerHash[:]) 104 hasher.Write(domain[:]) 105 hasher.Sum(signingRoot[:0]) 106 107 return signingRoot, nil 108 } 109 110 func (f Forks) Len() int { return len(f) } 111 func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] } 112 func (f Forks) Less(i, j int) bool { 113 if f[i].Epoch != f[j].Epoch { 114 return f[i].Epoch < f[j].Epoch 115 } 116 return f[i].knownIndex < f[j].knownIndex 117 } 118 119 // ChainConfig contains the beacon chain configuration. 120 type ChainConfig struct { 121 GenesisTime uint64 // Unix timestamp of slot 0 122 GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation 123 Forks Forks 124 } 125 126 // ForkAtEpoch returns the latest active fork at the given epoch. 127 func (c *ChainConfig) ForkAtEpoch(epoch uint64) Fork { 128 for i := len(c.Forks) - 1; i >= 0; i-- { 129 if c.Forks[i].Epoch <= epoch { 130 return *c.Forks[i] 131 } 132 } 133 return Fork{} 134 } 135 136 // AddFork adds a new item to the list of forks. 137 func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { 138 knownIndex := slices.Index(knownForks, name) 139 if knownIndex == -1 { 140 knownIndex = math.MaxInt // assume that the unknown fork happens after the known ones 141 if epoch != math.MaxUint64 { 142 log.Warn("Unknown fork in config.yaml", "fork name", name, "known forks", knownForks) 143 } 144 } 145 fork := &Fork{ 146 Name: name, 147 Epoch: epoch, 148 Version: version, 149 knownIndex: knownIndex, 150 } 151 fork.computeDomain(c.GenesisValidatorsRoot) 152 c.Forks = append(c.Forks, fork) 153 sort.Sort(c.Forks) 154 return c 155 } 156 157 // LoadForks parses the beacon chain configuration file (config.yaml) and extracts 158 // the list of forks. 159 func (c *ChainConfig) LoadForks(path string) error { 160 file, err := os.ReadFile(path) 161 if err != nil { 162 return fmt.Errorf("failed to read beacon chain config file: %v", err) 163 } 164 config := make(map[string]string) 165 if err := yaml.Unmarshal(file, &config); err != nil { 166 return fmt.Errorf("failed to parse beacon chain config file: %v", err) 167 } 168 var ( 169 versions = make(map[string][]byte) 170 epochs = make(map[string]uint64) 171 ) 172 epochs["GENESIS"] = 0 173 174 for key, value := range config { 175 if strings.HasSuffix(key, "_FORK_VERSION") { 176 name := key[:len(key)-len("_FORK_VERSION")] 177 if v, err := hexutil.Decode(value); err == nil { 178 versions[name] = v 179 } else { 180 return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err) 181 } 182 } 183 if strings.HasSuffix(key, "_FORK_EPOCH") { 184 name := key[:len(key)-len("_FORK_EPOCH")] 185 if v, err := strconv.ParseUint(value, 10, 64); err == nil { 186 epochs[name] = v 187 } else { 188 return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err) 189 } 190 } 191 } 192 for name, epoch := range epochs { 193 if version, ok := versions[name]; ok { 194 delete(versions, name) 195 c.AddFork(name, epoch, version) 196 } else { 197 return fmt.Errorf("fork id missing for %q in beacon chain config file", name) 198 } 199 } 200 for name := range versions { 201 return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name) 202 } 203 return nil 204 }