github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/utils.go (about) 1 // Copyright 2017 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 istanbul 18 19 import ( 20 "encoding/hex" 21 "errors" 22 blscrypto "github.com/ethereum/go-ethereum/crypto/bls" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/crypto" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/p2p/enode" 29 "github.com/ethereum/go-ethereum/rlp" 30 "golang.org/x/crypto/sha3" 31 ) 32 33 func RLPHash(v interface{}) (h common.Hash) { 34 hw := sha3.NewLegacyKeccak256() 35 rlp.Encode(hw, v) 36 hw.Sum(h[:0]) 37 return h 38 } 39 40 // GetSignatureAddress gets the signer address from the signature 41 func GetSignatureAddress(data []byte, sig []byte) (common.Address, error) { 42 // 1. Keccak data 43 hashData := crypto.Keccak256(data) 44 // 2. Recover public key 45 pubkey, err := crypto.SigToPub(hashData, sig) 46 if err != nil { 47 return common.Address{}, err 48 } 49 return crypto.PubkeyToAddress(*pubkey), nil 50 } 51 52 func CheckValidatorSignature(valSet ValidatorSet, data []byte, sig []byte) (common.Address, error) { 53 // 1. Get signature address 54 signer, err := GetSignatureAddress(data, sig) 55 if err != nil { 56 log.Error("Failed to get signer address", "err", err) 57 return common.Address{}, err 58 } 59 60 // 2. Check validator 61 if _, val := valSet.GetByAddress(signer); val != nil { 62 return val.Address(), nil 63 } 64 65 return common.Address{}, ErrUnauthorizedAddress 66 } 67 68 // Retrieves the block number within an epoch. The return value will be 1-based. 69 // There is a special case if the number == 0. It is basically the last block of the 0th epoch, and should have a value of epochSize 70 func GetNumberWithinEpoch(number uint64, epochSize uint64) uint64 { 71 number = number % epochSize 72 if number == 0 { 73 return epochSize 74 } else { 75 return number 76 } 77 } 78 79 func IsLastBlockOfEpoch(number uint64, epochSize uint64) bool { 80 return GetNumberWithinEpoch(number, epochSize) == epochSize 81 } 82 83 func IsFirstBlockOfEpoch(number uint64, epochSize uint64) bool { 84 return GetNumberWithinEpoch(number, epochSize) == 1 85 } 86 87 // Retrieves the epoch number given the block number. 88 // There is a special case if the number == 0 (the genesis block). That block will be in the 89 // 1st epoch. 90 func GetEpochNumber(number uint64, epochSize uint64) uint64 { 91 epochNumber := number / epochSize 92 if IsLastBlockOfEpoch(number, epochSize) { 93 return epochNumber 94 } else { 95 return epochNumber + 1 96 } 97 } 98 99 func GetEpochFirstBlockNumber(epochNumber uint64, epochSize uint64) (uint64, error) { 100 if epochNumber == 0 { 101 return 0, errors.New("No first block for epoch 0") 102 } 103 104 return ((epochNumber - 1) * epochSize) + 1, nil 105 } 106 107 func GetEpochLastBlockNumber(epochNumber uint64, epochSize uint64) uint64 { 108 if epochNumber == 0 { 109 return 0 110 } 111 112 firstBlockNum, _ := GetEpochFirstBlockNumber(epochNumber, epochSize) 113 return firstBlockNum + (epochSize - 1) 114 } 115 116 func GetValScoreTallyFirstBlockNumber(epochNumber uint64, epochSize uint64, lookbackWindowSize uint64) uint64 { 117 // We need to wait for the completion of the first window with the start window's block being the 118 // 2nd block of the epoch, before we start tallying the validator score for epoch "epochNumber". 119 // We can't include the epoch's first block since it's aggregated parent seals 120 // is for the previous epoch's valset. 121 122 epochFirstBlock, _ := GetEpochFirstBlockNumber(epochNumber, epochSize) 123 return epochFirstBlock + 1 + (lookbackWindowSize - 1) 124 } 125 126 func GetValScoreTallyLastBlockNumber(epochNumber uint64, epochSize uint64) uint64 { 127 // We stop tallying for epoch "epochNumber" at the second to last block of that epoch. 128 // We can't include that epoch's last block as part of the tally because the epoch val score is calculated 129 // using a tally that is updated AFTER a block is finalized. 130 // Note that it's possible to count up to the last block of the epoch, but it's much harder to implement 131 // than couting up to the second to last one. 132 133 return GetEpochLastBlockNumber(epochNumber, epochSize) - 1 134 } 135 136 func ValidatorSetDiff(oldValSet []ValidatorData, newValSet []ValidatorData) ([]ValidatorData, *big.Int) { 137 valSetMap := make(map[common.Address]bool) 138 oldValSetIndices := make(map[common.Address]int) 139 140 for i, oldVal := range oldValSet { 141 if (oldVal.Address != common.Address{}) { 142 valSetMap[oldVal.Address] = true 143 oldValSetIndices[oldValSet[i].Address] = i 144 } 145 } 146 147 var addedValidators []ValidatorData 148 for _, newVal := range newValSet { 149 index, ok := oldValSetIndices[newVal.Address] 150 if ok && (oldValSet[index].BLSPublicKey == newVal.BLSPublicKey) { 151 // We found a common validator. Pop from the map 152 delete(valSetMap, newVal.Address) 153 } else { 154 // We found a new validator that is not in the old validator set 155 addedValidators = append(addedValidators, ValidatorData{ 156 newVal.Address, 157 newVal.BLSPublicKey, 158 }) 159 } 160 } 161 162 removedValidatorsBitmap := big.NewInt(0) 163 for rmVal := range valSetMap { 164 removedValidatorsBitmap = removedValidatorsBitmap.SetBit(removedValidatorsBitmap, oldValSetIndices[rmVal], 1) 165 } 166 167 return addedValidators, removedValidatorsBitmap 168 } 169 170 // This function assumes that valSet1 and valSet2 are ordered in the same way 171 func CompareValidatorSlices(valSet1 []common.Address, valSet2 []common.Address) bool { 172 if len(valSet1) != len(valSet2) { 173 return false 174 } 175 176 for i := 0; i < len(valSet1); i++ { 177 if valSet1[i] != valSet2[i] { 178 return false 179 } 180 } 181 182 return true 183 } 184 185 func CompareValidatorPublicKeySlices(valSet1 []blscrypto.SerializedPublicKey, valSet2 []blscrypto.SerializedPublicKey) bool { 186 if len(valSet1) != len(valSet2) { 187 return false 188 } 189 190 for i := 0; i < len(valSet1); i++ { 191 if valSet1[i] != valSet2[i] { 192 return false 193 } 194 } 195 196 return true 197 } 198 199 func ConvertPublicKeysToStringSlice(publicKeys []blscrypto.SerializedPublicKey) []string { 200 publicKeyStrs := []string{} 201 for i := 0; i < len(publicKeys); i++ { 202 publicKeyStrs = append(publicKeyStrs, hex.EncodeToString(publicKeys[i][:])) 203 } 204 205 return publicKeyStrs 206 } 207 208 func GetNodeID(enodeURL string) (*enode.ID, error) { 209 node, err := enode.ParseV4(enodeURL) 210 if err != nil { 211 return nil, err 212 } 213 214 id := node.ID() 215 return &id, nil 216 }