-
Notifications
You must be signed in to change notification settings - Fork 3k
/
client.go
100 lines (87 loc) · 2.72 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package client
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"math/big"
"net/http"
"os"
"time"
optls "github.com/ethereum-optimism/optimism/op-service/tls"
"github.com/ethereum-optimism/optimism/op-service/tls/certman"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
type SignerClient struct {
client *rpc.Client
status string
logger log.Logger
}
func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConfig) (*SignerClient, error) {
caCert, err := os.ReadFile(tlsConfig.TLSCaCert)
if err != nil {
return nil, fmt.Errorf("failed to read tls.ca: %w", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// certman watches for newer client certifictes and automatically reloads them
cm, err := certman.New(logger, tlsConfig.TLSCert, tlsConfig.TLSKey)
if err != nil {
logger.Error("failed to read tls cert or key", "err", err)
return nil, err
}
if err := cm.Watch(); err != nil {
logger.Error("failed to start certman watcher", "err", err)
return nil, err
}
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS13,
RootCAs: caCertPool,
GetClientCertificate: func(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
return cm.GetCertificate(nil)
},
},
},
}
rpcClient, err := rpc.DialOptions(context.Background(), endpoint, rpc.WithHTTPClient(httpClient))
if err != nil {
return nil, err
}
signer := &SignerClient{logger: logger, client: rpcClient}
// Check if reachable
version, err := signer.pingVersion()
if err != nil {
return nil, err
}
signer.status = fmt.Sprintf("ok [version=%v]", version)
return signer, nil
}
func NewSignerClientFromConfig(logger log.Logger, config CLIConfig) (*SignerClient, error) {
return NewSignerClient(logger, config.Endpoint, config.TLSConfig)
}
func (s *SignerClient) pingVersion() (string, error) {
var v string
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
if err := s.client.CallContext(ctx, &v, "health_status"); err != nil {
return "", err
}
return v, nil
}
func (s *SignerClient) SignTransaction(ctx context.Context, chainId *big.Int, tx *types.Transaction) (*types.Transaction, error) {
args := NewTransactionArgsFromTransaction(chainId, tx)
var result hexutil.Bytes
if err := s.client.CallContext(ctx, &result, "eth_signTransaction", args); err != nil {
return nil, fmt.Errorf("eth_signTransaction failed: %w", err)
}
signed := &types.Transaction{}
if err := signed.UnmarshalBinary(result); err != nil {
return nil, err
}
return signed, nil
}