Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add precompiles to access validator set #441

Merged
merged 6 commits into from
Sep 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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