Skip to content

Commit

Permalink
Support validator key rotation (ethereum#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
Asa Oines authored Nov 16, 2019
1 parent 1601c0b commit 3761688
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
command: |
set -euo pipefail
export CELO_MONOREPO_DIR="$PWD"
git clone --depth 1 https://github.com/celo-org/celo-monorepo.git ${CELO_MONOREPO_DIR} -b master
git clone --depth 1 https://github.com/celo-org/celo-monorepo.git ${CELO_MONOREPO_DIR} -b asaj/e2e-key-swap
yarn install || yarn install
# separate build to avoid ENOMEM in CI :(
yarn build --scope @celo/utils
Expand Down
2 changes: 1 addition & 1 deletion consensus/istanbul/core/persistent_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func writeToDisk(filePath string, data []byte) error {
if err4 != nil {
return err4
}
log.Debug("Syncing dir %s\n", fpDir.Name())
log.Debug("Syncing dir", "dir", fpDir.Name())
err5 := fpDir.Sync()
if err5 != nil {
return err5
Expand Down
11 changes: 6 additions & 5 deletions consensus/istanbul/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,19 @@ func GetEpochLastBlockNumber(epochNumber uint64, epochSize uint64) uint64 {

func ValidatorSetDiff(oldValSet []ValidatorData, newValSet []ValidatorData) ([]ValidatorData, *big.Int) {
valSetMap := make(map[common.Address]bool)
oldValSetMap := make(map[common.Address]int)
oldValSetIndices := make(map[common.Address]int)

for i, oldVal := range oldValSet {
if (oldVal.Address != common.Address{}) {
valSetMap[oldVal.Address] = true
oldValSetMap[oldValSet[i].Address] = i
oldValSetIndices[oldValSet[i].Address] = i
}
}

removedValidatorsBitmap := big.NewInt(0)
var addedValidators []ValidatorData
for _, newVal := range newValSet {
if _, ok := valSetMap[newVal.Address]; ok {
index, ok := oldValSetIndices[newVal.Address]
if ok && bytes.Equal(oldValSet[index].BLSPublicKey, newVal.BLSPublicKey) {
// We found a common validator. Pop from the map
delete(valSetMap, newVal.Address)
} else {
Expand All @@ -134,8 +134,9 @@ func ValidatorSetDiff(oldValSet []ValidatorData, newValSet []ValidatorData) ([]V
}
}

removedValidatorsBitmap := big.NewInt(0)
for rmVal := range valSetMap {
removedValidatorsBitmap = removedValidatorsBitmap.SetBit(removedValidatorsBitmap, oldValSetMap[rmVal], 1)
removedValidatorsBitmap = removedValidatorsBitmap.SetBit(removedValidatorsBitmap, oldValSetIndices[rmVal], 1)
}

return addedValidators, removedValidatorsBitmap
Expand Down
4 changes: 2 additions & 2 deletions contract_comm/election/election.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
const electionABIString string = `[
{"constant": true,
"inputs": [],
"name": "electValidators",
"name": "electValidatorSigners",
"outputs": [
{
"name": "",
Expand Down Expand Up @@ -118,7 +118,7 @@ var electionABI, _ = abi.JSON(strings.NewReader(electionABIString))
func GetElectedValidators(header *types.Header, state vm.StateDB) ([]common.Address, error) {
var newValSet []common.Address
// Get the new epoch's validator set
_, err := contract_comm.MakeStaticCall(params.ElectionRegistryId, electionABI, "electValidators", []interface{}{}, &newValSet, params.MaxGasForElectValidators, header, state)
_, err := contract_comm.MakeStaticCall(params.ElectionRegistryId, electionABI, "electValidatorSigners", []interface{}{}, &newValSet, params.MaxGasForElectValidators, header, state)
if err != nil {
return nil, err
}
Expand Down
84 changes: 55 additions & 29 deletions contract_comm/validators/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,40 @@ import (

// This is taken from celo-monorepo/packages/protocol/build/<env>/contracts/Validators.json
const validatorsABIString string = `[
{
"constant": true,
"inputs": [],
"name": "getRegisteredValidators",
"outputs": [
{
"constant": true,
"inputs": [],
"name": "getRegisteredValidatorSigners",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "signer",
"type": "address"
}
],
"name": "getValidatorBlsPublicKeyFromSigner",
"outputs": [
{
"name": "blsKey",
"type": "bytes"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
Expand All @@ -57,7 +76,11 @@ const validatorsABIString string = `[
"name": "getValidator",
"outputs": [
{
"name": "publicKeysData",
"name": "ecdsaPublicKey",
"type": "bytes"
},
{
"name": "blsPublicKey",
"type": "bytes"
},
{
Expand Down Expand Up @@ -85,7 +108,7 @@ const validatorsABIString string = `[
"type": "uint256"
}
],
"name": "distributeEpochPayment",
"name": "distributeEpochPaymentsFromSigner",
"outputs": [
{
"name": "",
Expand All @@ -108,7 +131,7 @@ const validatorsABIString string = `[
"type": "uint256"
}
],
"name": "updateValidatorScore",
"name": "updateValidatorScoreFromSigner",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
Expand All @@ -122,7 +145,7 @@ const validatorsABIString string = `[
"type": "address"
}
],
"name": "getMembershipInLastEpoch",
"name": "getMembershipInLastEpochFromSigner",
"outputs": [
{
"name": "",
Expand All @@ -136,7 +159,8 @@ const validatorsABIString string = `[
]`

type ValidatorContractData struct {
PublicKeysData []byte
EcdsaPublicKey []byte
BlsPublicKey []byte
Affiliation common.Address
Score *big.Int
}
Expand All @@ -147,7 +171,7 @@ func RetrieveRegisteredValidators(header *types.Header, state vm.StateDB) ([]com
var regVals []common.Address

// Get the new epoch's validator set
if _, err := contract_comm.MakeStaticCall(params.ValidatorsRegistryId, validatorsABI, "getRegisteredValidators", []interface{}{}, &regVals, params.MaxGasForGetRegisteredValidators, header, state); err != nil {
if _, err := contract_comm.MakeStaticCall(params.ValidatorsRegistryId, validatorsABI, "getRegisteredValidatorSigners", []interface{}{}, &regVals, params.MaxGasForGetRegisteredValidators, header, state); err != nil {
return nil, err
}

Expand All @@ -169,24 +193,26 @@ func GetValidator(header *types.Header, state vm.StateDB, validatorAddress commo
if err != nil {
return validator, err
}
expectedLength := 64 + blscrypto.PUBLICKEYBYTES + blscrypto.SIGNATUREBYTES
if len(validator.PublicKeysData) != expectedLength {
return validator, fmt.Errorf("length of publicKeysData incorrect. Expected %d, got %d", expectedLength, len(validator.PublicKeysData))
if len(validator.BlsPublicKey) != blscrypto.PUBLICKEYBYTES {
return validator, fmt.Errorf("length of bls public key incorrect. Expected %d, got %d", blscrypto.PUBLICKEYBYTES, len(validator.BlsPublicKey))
}
return validator, nil
}

func GetValidatorData(header *types.Header, state vm.StateDB, validatorAddresses []common.Address) ([]istanbul.ValidatorData, error) {
var validatorData []istanbul.ValidatorData
for _, addr := range validatorAddresses {
validator, err := GetValidator(header, state, addr)
var blsKey []byte
_, err := contract_comm.MakeStaticCall(params.ValidatorsRegistryId, validatorsABI, "getValidatorBlsPublicKeyFromSigner", []interface{}{addr}, &blsKey, params.MaxGasForGetValidator, header, state)
if err != nil {
return nil, err
}
blsPublicKey := validator.PublicKeysData[64 : 64+blscrypto.PUBLICKEYBYTES]
if len(blsKey) != blscrypto.PUBLICKEYBYTES {
return nil, fmt.Errorf("length of BLS key incorrect. Expected %d, got %d", blscrypto.PUBLICKEYBYTES, len(blsKey))
}
validatorData = append(validatorData, istanbul.ValidatorData{
addr,
blsPublicKey,
blsKey,
})
}
return validatorData, nil
Expand All @@ -196,7 +222,7 @@ func UpdateValidatorScore(header *types.Header, state vm.StateDB, address common
_, err := contract_comm.MakeCall(
params.ValidatorsRegistryId,
validatorsABI,
"updateValidatorScore",
"updateValidatorScoreFromSigner",
[]interface{}{address, uptime},
nil,
params.MaxGasForUpdateValidatorScore,
Expand All @@ -213,7 +239,7 @@ func DistributeEpochPayment(header *types.Header, state vm.StateDB, address comm
_, err := contract_comm.MakeCall(
params.ValidatorsRegistryId,
validatorsABI,
"distributeEpochPayment",
"distributeEpochPaymentsFromSigner",
[]interface{}{address, maxPayment},
&epochPayment,
params.MaxGasForDistributeEpochPayment,
Expand All @@ -227,7 +253,7 @@ func DistributeEpochPayment(header *types.Header, state vm.StateDB, address comm

func GetMembershipInLastEpoch(header *types.Header, state vm.StateDB, validator common.Address) (common.Address, error) {
var group common.Address
_, err := contract_comm.MakeStaticCall(params.ValidatorsRegistryId, validatorsABI, "getMembershipInLastEpoch", []interface{}{validator}, &group, params.MaxGasForGetMembershipInLastEpoch, header, state)
_, err := contract_comm.MakeStaticCall(params.ValidatorsRegistryId, validatorsABI, "getMembershipInLastEpochFromSigner", []interface{}{validator}, &group, params.MaxGasForGetMembershipInLastEpoch, header, state)
if err != nil {
return common.ZeroAddress, err
}
Expand Down
4 changes: 2 additions & 2 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,8 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
// Heuristic limit, reject transactions over MaxCodeSize to prevent DOS attacks
if tx.Size() > params.MaxCodeSize {
return ErrOversizedData
}
// Transactions can't be negative. This may never happen using RLP decoded
Expand Down
5 changes: 3 additions & 2 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,9 +560,10 @@ func (c *proofOfPossession) Run(input []byte, caller common.Address, evm *EVM, g
return nil, gas, err
}

// input is comprised of 2 arguments:
// input is comprised of 3 arguments:
// address: 20 bytes, an address used to generate the proof-of-possession
// publicKey: 48 bytes, representing the public key (defined as a const in bls package)
// signature: 96 bytes, representing the signature (defined as a const in bls package)
// signature: 96 bytes, representing the signature on `address` (defined as a const in bls package)
// the total length of input required is the sum of these constants
if len(input) != common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.SIGNATUREBYTES {
return nil, gas, ErrInputLength
Expand Down
23 changes: 12 additions & 11 deletions ethstats/ethstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
blscrypto "github.com/ethereum/go-ethereum/crypto/bls"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
Expand Down Expand Up @@ -694,11 +693,12 @@ type validatorSet struct {
}

type validatorInfo struct {
Address common.Address `json:"address"`
Name string `json:"name"`
Score string `json:"score"`
BLSPublicKey []byte `json:"blsPublicKey"`
Affiliation common.Address `json:"affiliation"`
Address common.Address `json:"address"`
Name string `json:"name"`
Score string `json:"score"`
BLSPublicKey []byte `json:"blsPublicKey"`
EcdsaPublicKey []byte `json:"ecdsaPublicKey"`
Affiliation common.Address `json:"affiliation"`
}

func (s *Service) assembleValidatorSet(block *types.Block, state vm.StateDB) validatorSet {
Expand All @@ -720,11 +720,12 @@ func (s *Service) assembleValidatorSet(block *types.Block, state vm.StateDB) val
address)

valsRegistered = append(valsRegistered, validatorInfo{
Address: address,
Score: fmt.Sprintf("%d", valData.Score),
Name: address.String(),
BLSPublicKey: valData.PublicKeysData[64 : 64+blscrypto.PUBLICKEYBYTES],
Affiliation: valData.Affiliation,
Address: address,
Score: fmt.Sprintf("%d", valData.Score),
Name: address.String(),
BLSPublicKey: valData.BlsPublicKey,
EcdsaPublicKey: valData.EcdsaPublicKey,
Affiliation: valData.Affiliation,
})
}

Expand Down

0 comments on commit 3761688

Please sign in to comment.