clique, signer: implement clique signing for clef

This commit is contained in:
Martin Holst Swende 2018-09-25 11:07:18 +02:00
parent 8e0bc14235
commit 9e3f27fc18
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
8 changed files with 69 additions and 45 deletions

View file

@ -39,7 +39,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
lru "github.com/hashicorp/golang-lru"
"github.com/hashicorp/golang-lru"
)
const (
@ -136,9 +136,9 @@ var (
errRecentlySigned = errors.New("recently signed")
)
// SignerFn is a signer callback function to request a hash to be signed by a
// SignerFn is a signer callback function to request a block header to be signed by a
// backing account.
type SignerFn func(accounts.Account, []byte) ([]byte, error)
type SignerFn func(accounts.Account, *types.Header) ([]byte, error)
// sigHash returns the hash which is used as input for the proof-of-authority
// signing. It is the hash of the entire header apart from the 65 byte signature
@ -646,7 +646,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
}
// Sign all the things!
sighash, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes())
sighash, err := signFn(accounts.Account{Address: signer}, header)
if err != nil {
return err
}

View file

@ -219,7 +219,7 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
}
}
func (b *EthAPIBackend) ExternalSigner() *ethapi.ExternalSignerAPI {
func (b *EthAPIBackend) ExternalSigner() *ethapi.ExternalSignerClient {
return b.eth.externalSigner
}

View file

@ -20,6 +20,7 @@ package eth
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"math/big"
"runtime"
"sync"
@ -76,7 +77,7 @@ type Ethereum struct {
eventMux *event.TypeMux
engine consensus.Engine
externalSigner *ethapi.ExternalSignerAPI
externalSigner *ethapi.ExternalSignerClient
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
@ -100,7 +101,7 @@ func (s *Ethereum) AddLesServer(ls LesServer) {
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
func New(ctx *node.ServiceContext, config *Config, api *ethapi.ExternalSignerAPI) (*Ethereum, error) {
func New(ctx *node.ServiceContext, config *Config, api *ethapi.ExternalSignerClient) (*Ethereum, error) {
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
@ -413,10 +414,19 @@ func (s *Ethereum) StartMining(threads int) error {
log.Error("Cannot start mining without etherbase", "err", err)
return fmt.Errorf("etherbase missing: %v", err)
}
if _, ok := s.engine.(*clique.Clique); ok {
//TODO @holiman
log.Error("Etherbase account unavailable locally", "err", err)
return fmt.Errorf("signer not configured: %v", err)
if clique, ok := s.engine.(*clique.Clique); ok {
if s.ExternalSigner() != nil {
signerFn := func(a accounts.Account, header *types.Header) ([]byte, error) {
rlpHeader, err := rlp.EncodeToBytes(header)
if err != nil {
return nil, err
}
return s.ExternalSigner().SignCliqueBlock(a.Address, rlpHeader)
}
clique.Authorize(eb, signerFn)
} else {
return fmt.Errorf("external signer not configured")
}
}
// If mining is started, we can disable the transaction rejection mechanism
// introduced to speed sync times.
@ -453,7 +463,7 @@ func (s *Ethereum) IsListening() bool { return true } //
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
func (s *Ethereum) ExternalSigner() *ethapi.ExternalSignerAPI { return s.externalSigner }
func (s *Ethereum) ExternalSigner() *ethapi.ExternalSignerClient { return s.externalSigner }
// Protocols implements node.Service, returning all the currently configured
// network protocols to start.

View file

@ -183,7 +183,7 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
type PrivateAccountAPI struct {
nonceLock *AddrLocker
b Backend
extapi *ExternalSignerAPI // external signer, nil if not used
extapi *ExternalSignerClient // external signer, nil if not used
}
// NewPrivateAccountAPI create a new PrivateAccountAPI.
@ -200,7 +200,7 @@ func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI {
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
addresses := make([]common.Address, 0) // return [] instead of nil if empty
if s.extapi != nil {
if accounts, err := s.extapi.listAccounts(); err == nil {
if accounts, err := s.extapi.ListAccounts(); err == nil {
return accounts
}
return addresses
@ -219,7 +219,7 @@ type rawWallet struct {
// NewAccount will create a new account and returns the address for the new account.
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
return s.extapi.newAccount()
return s.extapi.NewAccount()
}
// fetchKeystore retrives the encrypted keystore from the account manager.
@ -253,7 +253,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs
if err := args.setDefaults(ctx, s.b); err != nil {
return nil, err
}
return s.extapi.signTransaction(ctx, args)
return s.extapi.SignTransaction(ctx, args)
}
// SendTransaction will create a transaction from the given arguments and
@ -806,7 +806,7 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa
type PublicTransactionPoolAPI struct {
b Backend
nonceLock *AddrLocker
extapi *ExternalSignerAPI // external signer, nil if not used
extapi *ExternalSignerClient // external signer, nil if not used
}
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
@ -1057,7 +1057,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
if err := args.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err
}
signed, err := s.extapi.signTransaction(ctx, args)
signed, err := s.extapi.SignTransaction(ctx, args)
if err != nil {
return common.Hash{}, err
}
@ -1114,7 +1114,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
err error
)
tx, err = s.extapi.signTransaction(ctx, args)
tx, err = s.extapi.SignTransaction(ctx, args)
if err != nil {
return nil, err
@ -1166,7 +1166,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
if gasLimit != nil && *gasLimit != 0 {
sendArgs.Gas = gasLimit
}
signedTx, err = s.extapi.signTransaction(ctx, sendArgs)
signedTx, err = s.extapi.SignTransaction(ctx, sendArgs)
if err != nil {
return common.Hash{}, err
}
@ -1300,24 +1300,24 @@ func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion)
}
// ExternalSignerAPI provides an API to interact with an external signer (clef)
// ExternalSignerClient provides an API to interact with an external signer (clef)
// It proxies request to the external signer while forwarding relevant
// request headers
type ExternalSignerAPI struct {
type ExternalSignerClient struct {
client *rpc.Client
}
func NewExternalSigner(endpoint string) (*ExternalSignerAPI, error) {
func NewExternalSigner(endpoint string) (*ExternalSignerClient, error) {
client, err := rpc.DialHTTP(endpoint)
if err != nil {
return nil, err
}
return &ExternalSignerAPI{
return &ExternalSignerClient{
client: client,
}, nil
}
func (api *ExternalSignerAPI) signTransaction(ctx context.Context, args SendTxArgs) (*types.Transaction, error) {
func (api *ExternalSignerClient) SignTransaction(ctx context.Context, args SendTxArgs) (*types.Transaction, error) {
if api == nil{
return nil, errors.New("External API not initialized")
}
@ -1327,7 +1327,7 @@ func (api *ExternalSignerAPI) signTransaction(ctx context.Context, args SendTxAr
}
return res.Tx, nil
}
func (api *ExternalSignerAPI) listAccounts() ([]common.Address, error) {
func (api *ExternalSignerClient) ListAccounts() ([]common.Address, error) {
if api == nil{
return []common.Address{}, errors.New("External API not initialized")
}
@ -1337,15 +1337,29 @@ func (api *ExternalSignerAPI) listAccounts() ([]common.Address, error) {
}
return res, nil
}
func (api *ExternalSignerAPI) newAccount() (common.Address, error) {
func (api *ExternalSignerClient) NewAccount() (common.Address, error) {
if api == nil{
return common.Address{}, errors.New("External API not initialized")
}
var res accounts.Account
if err := api.client.Call(&res, "account_new"); err != nil {
return res.Address, nil
return common.Address{}, err
}
return common.Address{}, nil
return res.Address, nil
}
func (api *ExternalSignerClient) SignCliqueBlock(a common.Address, rlpBlock hexutil.Bytes) (hexutil.Bytes, error) {
if api == nil{
return nil, errors.New("External API not initialized")
}
var sig hexutil.Bytes
if err := api.client.Call(&sig, "account_signData", "application/clique", a, rlpBlock); err != nil {
return nil, err
}
if sig[64] != 27 && sig[64] != 28 {
return nil, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
}
sig[64] -= 27 // Transform V from 27/28 to 0/1 for Clique use
return sig, nil
}

View file

@ -42,7 +42,7 @@ type Backend interface {
SuggestPrice(ctx context.Context) (*big.Int, error)
ChainDb() ethdb.Database
EventMux() *event.TypeMux
ExternalSigner() *ExternalSignerAPI
ExternalSigner() *ExternalSignerClient
// BlockChain API
SetHead(number uint64)

View file

@ -183,7 +183,7 @@ func (b *LesApiBackend) EventMux() *event.TypeMux {
return b.eth.eventMux
}
func (b *LesApiBackend) ExternalSigner() *ethapi.ExternalSignerAPI{
func (b *LesApiBackend) ExternalSigner() *ethapi.ExternalSignerClient {
return b.eth.externalSigner
}

View file

@ -68,7 +68,7 @@ type LightEthereum struct {
eventMux *event.TypeMux
engine consensus.Engine
externalSigner *ethapi.ExternalSignerAPI
externalSigner *ethapi.ExternalSignerClient
networkId uint64
netRPCService *ethapi.PublicNetAPI

View file

@ -40,7 +40,7 @@ import (
type Node struct {
eventmux *event.TypeMux // Event multiplexer used between the services of a stack
config *Config
extapi *ethapi.ExternalSignerAPI// If non-empty, the ipc-path or http(s)-url to an external signer
extapi *ethapi.ExternalSignerClient // If non-empty, the ipc-path or http(s)-url to an external signer
instanceDirLock flock.Releaser // prevents concurrent use of instance directory
@ -554,11 +554,11 @@ func (n *Node) ResolvePath(x string) string {
return n.config.ResolvePath(x)
}
func (n *Node) SetExternalAPI(api *ethapi.ExternalSignerAPI){
func (n *Node) SetExternalAPI(api *ethapi.ExternalSignerClient){
n.extapi = api
}
func (n *Node) ExternalSignerAPI() *ethapi.ExternalSignerAPI{
func (n *Node) ExternalSignerAPI() *ethapi.ExternalSignerClient {
return n.extapi
}
// apis returns the collection of RPC descriptors this node offers.