mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
signer,clef: implement timeout for external api
This commit is contained in:
parent
1ff152f3a4
commit
a043ed2ff6
3 changed files with 157 additions and 10 deletions
|
|
@ -49,12 +49,6 @@ import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExternalAPIVersion -- see extapi_changelog.md
|
|
||||||
const ExternalAPIVersion = "4.0.0"
|
|
||||||
|
|
||||||
// InternalAPIVersion -- see intapi_changelog.md
|
|
||||||
const InternalAPIVersion = "3.0.0"
|
|
||||||
|
|
||||||
const legalWarning = `
|
const legalWarning = `
|
||||||
WARNING!
|
WARNING!
|
||||||
|
|
||||||
|
|
@ -110,6 +104,11 @@ var (
|
||||||
Usage: "File used to emit audit logs. Set to \"\" to disable",
|
Usage: "File used to emit audit logs. Set to \"\" to disable",
|
||||||
Value: "audit.log",
|
Value: "audit.log",
|
||||||
}
|
}
|
||||||
|
timeoutFlag = cli.DurationFlag{
|
||||||
|
Name: "timeout",
|
||||||
|
Usage: "Specify a timeout, so external callers get a response within a certain time (default 0 = no timeout)",
|
||||||
|
Value: 0,
|
||||||
|
}
|
||||||
ruleFlag = cli.StringFlag{
|
ruleFlag = cli.StringFlag{
|
||||||
Name: "rules",
|
Name: "rules",
|
||||||
Usage: "Enable rule-engine",
|
Usage: "Enable rule-engine",
|
||||||
|
|
@ -194,6 +193,7 @@ func init() {
|
||||||
dBFlag,
|
dBFlag,
|
||||||
customDBFlag,
|
customDBFlag,
|
||||||
auditLogFlag,
|
auditLogFlag,
|
||||||
|
timeoutFlag,
|
||||||
ruleFlag,
|
ruleFlag,
|
||||||
stdiouiFlag,
|
stdiouiFlag,
|
||||||
testFlag,
|
testFlag,
|
||||||
|
|
@ -414,6 +414,12 @@ func signer(c *cli.Context) error {
|
||||||
c.GlobalBool(utils.LightKDFFlag.Name),
|
c.GlobalBool(utils.LightKDFFlag.Name),
|
||||||
c.GlobalBool(advancedMode.Name))
|
c.GlobalBool(advancedMode.Name))
|
||||||
api = apiImpl
|
api = apiImpl
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
if timeout := c.GlobalDuration(timeoutFlag.Name); timeout > 0 {
|
||||||
|
log.Info("extapi timeout set", "time", timeout)
|
||||||
|
api = core.NewTimedExternalAPI(api, timeout)
|
||||||
|
}
|
||||||
// Audit logging
|
// Audit logging
|
||||||
if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" {
|
if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" {
|
||||||
api, err = core.NewAuditLogger(logfile, api)
|
api, err = core.NewAuditLogger(logfile, api)
|
||||||
|
|
@ -479,8 +485,8 @@ func signer(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
ui.OnSignerStartup(core.StartupInfo{
|
ui.OnSignerStartup(core.StartupInfo{
|
||||||
Info: map[string]interface{}{
|
Info: map[string]interface{}{
|
||||||
"extapi_version": ExternalAPIVersion,
|
"extapi_version": core.ExternalAPIVersion,
|
||||||
"intapi_version": InternalAPIVersion,
|
"intapi_version": core.InternalAPIVersion,
|
||||||
"extapi_http": extapiURL,
|
"extapi_http": extapiURL,
|
||||||
"extapi_ipc": ipcapiURL,
|
"extapi_ipc": ipcapiURL,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// numberOfAccountsToDerive For hardware wallets, the number of accounts to derive
|
const(
|
||||||
const numberOfAccountsToDerive = 10
|
// numberOfAccountsToDerive For hardware wallets, the number of accounts to derive
|
||||||
|
numberOfAccountsToDerive = 10
|
||||||
|
// ExternalAPIVersion -- see extapi_changelog.md
|
||||||
|
ExternalAPIVersion = "4.0.0"
|
||||||
|
// InternalAPIVersion -- see intapi_changelog.md
|
||||||
|
InternalAPIVersion = "3.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
// ExternalAPI defines the external API through which signing requests are made.
|
// ExternalAPI defines the external API through which signing requests are made.
|
||||||
type ExternalAPI interface {
|
type ExternalAPI interface {
|
||||||
|
|
|
||||||
135
signer/core/timeout.go
Normal file
135
signer/core/timeout.go
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The TimedExternalAPI implements ExternalAPI, but can be configured to time out after a specified interval.
|
||||||
|
// This can be used to ensure that callers get a response within reasonable time,
|
||||||
|
// even if the user is unresponsive.
|
||||||
|
type TimedExternalAPI struct {
|
||||||
|
timeout time.Duration
|
||||||
|
next ExternalAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimedExternalAPI(next ExternalAPI, timeout time.Duration) ExternalAPI {
|
||||||
|
return &TimedExternalAPI{timeout, next}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTimeout = fmt.Errorf("timeout occurred")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) List(ctx context.Context) ([]common.Address, error) {
|
||||||
|
type response struct {
|
||||||
|
addr []common.Address
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
ch := make(chan response)
|
||||||
|
go func() {
|
||||||
|
addr, err := t.next.List(ctx)
|
||||||
|
ch <- response{addr, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case r := <-ch:
|
||||||
|
return r.addr, r.err
|
||||||
|
case <-time.After(t.timeout):
|
||||||
|
log.Info("timeout", "op", "list")
|
||||||
|
go func() { <-ch }()
|
||||||
|
return []common.Address{}, ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) New(ctx context.Context) (accounts.Account, error) {
|
||||||
|
type response struct {
|
||||||
|
acc accounts.Account
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
ch := make(chan response)
|
||||||
|
go func() {
|
||||||
|
acc, err := t.next.New(ctx)
|
||||||
|
ch <- response{acc, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case r := <-ch:
|
||||||
|
return r.acc, r.err
|
||||||
|
case <-time.After(t.timeout):
|
||||||
|
log.Info("timeout", "op", "list")
|
||||||
|
go func() { <-ch }()
|
||||||
|
return accounts.Account{}, ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) {
|
||||||
|
type response struct {
|
||||||
|
res *ethapi.SignTransactionResult
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
ch := make(chan response)
|
||||||
|
go func() {
|
||||||
|
res, err := t.next.SignTransaction(ctx, args, methodSelector)
|
||||||
|
ch <- response{res, err}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case r := <-ch:
|
||||||
|
return r.res, r.err
|
||||||
|
case <-time.After(t.timeout):
|
||||||
|
log.Info("timeout", "op", "signTransaction")
|
||||||
|
go func() { <-ch }()
|
||||||
|
return nil, ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||||
|
type response struct {
|
||||||
|
res hexutil.Bytes
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
ch := make(chan response)
|
||||||
|
go func() {
|
||||||
|
res, err := t.next.Sign(ctx, addr, data)
|
||||||
|
ch <- response{res, err}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case r := <-ch:
|
||||||
|
return r.res, r.err
|
||||||
|
case <-time.After(t.timeout):
|
||||||
|
log.Info("timeout", "op", "sign")
|
||||||
|
go func() { <-ch }()
|
||||||
|
return nil, ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
|
||||||
|
type response struct {
|
||||||
|
res json.RawMessage
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
ch := make(chan response)
|
||||||
|
go func() {
|
||||||
|
res, err := t.next.Export(ctx, addr)
|
||||||
|
ch <- response{res, err}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case r := <-ch:
|
||||||
|
return r.res, r.err
|
||||||
|
case <-time.After(t.timeout):
|
||||||
|
log.Info("timeout", "op", "sign")
|
||||||
|
go func() { <-ch }()
|
||||||
|
return json.RawMessage{}, ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TimedExternalAPI) Version(ctx context.Context) (string, error) {
|
||||||
|
return ExternalAPIVersion, nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue