mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
clique, signer: implement clique signing for clef
This commit is contained in:
parent
8e0bc14235
commit
9e3f27fc18
8 changed files with 69 additions and 45 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -444,16 +454,16 @@ func (s *Ethereum) StopMining() {
|
|||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||
|
||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
||||
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||
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) BlockChain() *core.BlockChain { return s.blockchain }
|
||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
||||
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||
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.ExternalSignerClient { return s.externalSigner }
|
||||
|
||||
// Protocols implements node.Service, returning all the currently configured
|
||||
// network protocols to start.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ type LightEthereum struct {
|
|||
|
||||
eventMux *event.TypeMux
|
||||
engine consensus.Engine
|
||||
externalSigner *ethapi.ExternalSignerAPI
|
||||
externalSigner *ethapi.ExternalSignerClient
|
||||
|
||||
networkId uint64
|
||||
netRPCService *ethapi.PublicNetAPI
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue