Commit d91fdd07 authored by Sabnock01's avatar Sabnock01

move op-signer v2

parent 76ac0cb4
# op-signer
op-signer service client
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"
"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) {
var httpClient *http.Client
if tlsConfig.TLSCaCert != "" {
logger.Info("tlsConfig specified, loading tls config")
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)
},
},
},
}
} else {
logger.Info("no tlsConfig specified, using default http client")
httpClient = http.DefaultClient
}
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 optls.SignerCLIConfig) (*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, from common.Address, tx *types.Transaction) (*types.Transaction, error) {
args := NewTransactionArgsFromTransaction(chainId, from, 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
}
package client
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// TransactionArgs represents the arguments to construct a new transaction
// or a message call.
type TransactionArgs struct {
From *common.Address `json:"from"`
To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons.
// "input" is the newer name and should be preferred by clients.
// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
}
// NewTransactionArgsFromTransaction creates a TransactionArgs struct from an EIP-1559 transaction
func NewTransactionArgsFromTransaction(chainId *big.Int, from common.Address, tx *types.Transaction) *TransactionArgs {
data := hexutil.Bytes(tx.Data())
nonce := hexutil.Uint64(tx.Nonce())
gas := hexutil.Uint64(tx.Gas())
accesses := tx.AccessList()
args := &TransactionArgs{
From: &from,
Input: &data,
Nonce: &nonce,
Value: (*hexutil.Big)(tx.Value()),
Gas: &gas,
To: tx.To(),
ChainID: (*hexutil.Big)(chainId),
MaxFeePerGas: (*hexutil.Big)(tx.GasFeeCap()),
MaxPriorityFeePerGas: (*hexutil.Big)(tx.GasTipCap()),
AccessList: &accesses,
}
return args
}
// data retrieves the transaction calldata. Input field is preferred.
func (args *TransactionArgs) data() []byte {
if args.Input != nil {
return *args.Input
}
if args.Data != nil {
return *args.Data
}
return nil
}
// ToTransaction converts the arguments to a transaction.
func (args *TransactionArgs) ToTransaction() *types.Transaction {
var data types.TxData
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
data = &types.DynamicFeeTx{
To: args.To,
ChainID: (*big.Int)(args.ChainID),
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
GasFeeCap: (*big.Int)(args.MaxFeePerGas),
GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
Value: (*big.Int)(args.Value),
Data: args.data(),
AccessList: al,
}
return types.NewTx(data)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment