Skip to content

Commit

Permalink
Add precompiles to access validator set (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-chrzan committed Sep 13, 2019
1 parent c599cdb commit d4b48f3
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 1 deletion.
5 changes: 5 additions & 0 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -268,6 +269,10 @@ func (c *Clique) Author(header *types.Header) (common.Address, error) {
return ecrecover(header, c.signatures)
}

func (c *Clique) GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator {
return []istanbul.Validator{}
}

// VerifyHeader checks whether a header conforms to the consensus rules.
func (c *Clique) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
return c.verifyHeader(chain, header, nil)
Expand Down
4 changes: 4 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
Expand Down Expand Up @@ -102,6 +103,9 @@ type Engine interface {
// that a new block should have.
CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int

// GetValidators returns the list of current validators.
GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator

// APIs returns the RPC APIs this consensus engine provides.
APIs(chain ChainReader) []rpc.API

Expand Down
5 changes: 5 additions & 0 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -80,6 +81,10 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) {
return header.Coinbase, nil
}

func (ethash *Ethash) GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator {
return []istanbul.Validator{}
}

// VerifyHeader checks whether a header conforms to the consensus rules of the
// stock Ethereum ethash engine.
func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
Expand Down
5 changes: 5 additions & 0 deletions consensus/istanbul/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ func (sb *Backend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet
return sb.getValidators(proposal.Number().Uint64(), proposal.Hash())
}

func (sb *Backend) GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator {
validatorSet := sb.getValidators(blockNumber.Uint64(), headerHash)
return validatorSet.FilteredList()
}

// Broadcast implements istanbul.Backend.Broadcast
func (sb *Backend) Broadcast(valSet istanbul.ValidatorSet, payload []byte) error {
// send to others
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
// further limitations on the content of transactions that can be
// added. If contract code relies on the BLOCKHASH instruction,
// the block in chain will be returned.
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
func (b *BlockGen) AddTxWithChain(bc ChainContext, tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
Expand Down
6 changes: 6 additions & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
beneficiary = *author
}

var engine consensus.Engine
if chain != nil {
engine = chain.Engine()
}

return vm.Context{
CanTransfer: CanTransfer,
Transfer: Transfer,
Expand All @@ -68,6 +73,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(msg.GasPrice()),
Engine: engine,
}
}

Expand Down
49 changes: 49 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ var requestAttestationAddress = common.BytesToAddress(append([]byte{0}, CeloPrec
var transferAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 2)))
var fractionMulExpAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 3)))
var proofOfPossessionAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 4)))
var getValidatorAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 5)))
var numberValidatorsAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 6)))

// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release.
Expand All @@ -75,6 +77,8 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
transferAddress: &transfer{},
fractionMulExpAddress: &fractionMulExp{},
proofOfPossessionAddress: &proofOfPossession{},
getValidatorAddress: &getValidator{},
numberValidatorsAddress: &numberValidators{},
}

// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
Expand Down Expand Up @@ -588,3 +592,48 @@ func (c *proofOfPossession) Run(input []byte, caller common.Address, evm *EVM, g

return true32Byte, gas, nil
}

type getValidator struct{}

func (c *getValidator) RequiredGas(input []byte) uint64 {
return params.GetValidatorGas
}

func (c *getValidator) Run(input []byte, caller common.Address, evm *EVM, gas uint64) ([]byte, uint64, error) {
index := (&big.Int{}).SetBytes(input[0:32])
blockNumber := evm.Context.BlockNumber
validators := evm.Context.Engine.GetValidators(blockNumber, evm.Context.GetHash(blockNumber.Uint64()))
gas, err := debitRequiredGas(c, input, gas)
if err != nil {
return nil, gas, err
}

if index.Cmp(big.NewInt(int64(len(validators)))) >= 0 {
return nil, gas, ErrValidatorsOutOfBounds
}

validatorAddress := validators[index.Uint64()].Address()
addressBytes := common.LeftPadBytes(validatorAddress[:], 32)

return addressBytes, gas, nil
}

type numberValidators struct{}

func (c *numberValidators) RequiredGas(input []byte) uint64 {
return params.GetValidatorGas
}

func (c *numberValidators) Run(input []byte, caller common.Address, evm *EVM, gas uint64) ([]byte, uint64, error) {
blockNumber := evm.Context.BlockNumber
validators := evm.Context.Engine.GetValidators(blockNumber, evm.Context.GetHash(blockNumber.Uint64()))
gas, err := debitRequiredGas(c, input, gas)
if err != nil {
return nil, gas, err
}

numberValidators := big.NewInt(int64(len(validators))).Bytes()
numberValidatorsBytes := common.LeftPadBytes(numberValidators[:], 32)

return numberValidatorsBytes, gas, nil
}
1 change: 1 addition & 0 deletions core/vm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ var (
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
ErrContractAddressCollision = errors.New("contract address collision")
ErrNoCompatibleInterpreter = errors.New("no compatible interpreter")
ErrValidatorsOutOfBounds = errors.New("getValidators out of bounds")
)
3 changes: 3 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/contract_comm/errors"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -99,6 +100,8 @@ type Context struct {
Difficulty *big.Int // Provides information for DIFFICULTY

Header *types.Header

Engine consensus.Engine
}

// EVM is the Ethereum Virtual Machine base object and provides
Expand Down
1 change: 1 addition & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const (
FractionMulExpGas uint64 = 1050 // Cost of performing multiplication and exponentiation of fractions to an exponent of up to 10^3.
// TODO(kobigurk): Figure out what the actual gas cost of this contract should be.
ProofOfPossessionGas uint64 = 1050 // Cost of verifying a BLS proof of possession.
GetValidatorGas uint64 = 5000 // Cost of reading a validator's address
)

var (
Expand Down

0 comments on commit d4b48f3

Please sign in to comment.