mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-06 01:32:18 +00:00
9614c81228
Former-commit-id: 54da8e259e6abae30c61dc6301cbfeeb0ede8570 [formerly 31f207fb38d4a1699dc60c294cf99a1673b54ab7] Former-commit-id: c70fc84a836a6b03bcaf07b5fe7a9eb5c116e0da
181 lines
4.8 KiB
Go
181 lines
4.8 KiB
Go
package client
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
|
|
"github.com/ethereum/go-ethereum"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
"github.com/ethereum/go-ethereum/sharding/contracts"
|
|
cli "gopkg.in/urfave/cli.v1"
|
|
)
|
|
|
|
const (
|
|
clientIdentifier = "geth" // Used to determine the ipc name.
|
|
)
|
|
|
|
// General Client for Collator. Communicates to Geth node via JSON RPC.
|
|
|
|
type ShardingClient struct {
|
|
endpoint string // Endpoint to JSON RPC
|
|
client *ethclient.Client // Ethereum RPC client.
|
|
keystore *keystore.KeyStore // Keystore containing the single signer
|
|
Ctx *cli.Context // Command line context
|
|
Smc *contracts.SMC // The deployed sharding management contract
|
|
}
|
|
|
|
type Client interface {
|
|
MakeClient(*cli.Context) *ShardingClient
|
|
Start() error
|
|
CreateTXOps(*big.Int) (*bind.TransactOpts, error)
|
|
initSMC() error
|
|
}
|
|
|
|
func MakeClient(ctx *cli.Context) *ShardingClient {
|
|
path := node.DefaultDataDir()
|
|
if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
|
|
path = ctx.GlobalString(utils.DataDirFlag.Name)
|
|
}
|
|
|
|
endpoint := ctx.Args().First()
|
|
if endpoint == "" {
|
|
endpoint = fmt.Sprintf("%s/%s.ipc", path, clientIdentifier)
|
|
}
|
|
if ctx.GlobalIsSet(utils.IPCPathFlag.Name) {
|
|
endpoint = ctx.GlobalString(utils.IPCPathFlag.Name)
|
|
}
|
|
|
|
config := &node.Config{
|
|
DataDir: path,
|
|
}
|
|
|
|
scryptN, scryptP, keydir, err := config.AccountConfig()
|
|
if err != nil {
|
|
panic(err) // TODO(prestonvanloon): handle this
|
|
}
|
|
ks := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
|
|
|
return &ShardingClient{
|
|
endpoint: endpoint,
|
|
keystore: ks,
|
|
Ctx: ctx,
|
|
}
|
|
}
|
|
|
|
// Start the sharding client.
|
|
// * Connects to Geth node.
|
|
// * Verifies or deploys the sharding manager contract.
|
|
func (c *ShardingClient) Start() (*rpc.Client, error) {
|
|
rpcClient, err := dialRPC(c.endpoint)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot start rpc client. %v", err)
|
|
}
|
|
c.client = ethclient.NewClient(rpcClient)
|
|
|
|
// Check account existence and unlock account before starting collator client
|
|
accounts := c.keystore.Accounts()
|
|
if len(accounts) == 0 {
|
|
return nil, fmt.Errorf("no accounts found")
|
|
}
|
|
|
|
if err := c.unlockAccount(accounts[0]); err != nil {
|
|
return nil, fmt.Errorf("cannot unlock account. %v", err)
|
|
}
|
|
|
|
if err := initSMC(c); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rpcClient, nil
|
|
}
|
|
|
|
// Wait until collator client is shutdown.
|
|
func (c *ShardingClient) Wait() {
|
|
log.Info("Sharding client has been shutdown...")
|
|
}
|
|
|
|
// UnlockAccount will unlock the specified account using utils.PasswordFileFlag or empty string if unset.
|
|
func (c *ShardingClient) unlockAccount(account accounts.Account) error {
|
|
pass := ""
|
|
|
|
if c.Ctx.GlobalIsSet(utils.PasswordFileFlag.Name) {
|
|
file, err := os.Open(c.Ctx.GlobalString(utils.PasswordFileFlag.Name))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to open file containing account password %s. %v", utils.PasswordFileFlag.Value, err)
|
|
}
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Split(bufio.ScanWords)
|
|
if !scanner.Scan() {
|
|
err = scanner.Err()
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read contents of file %v", err)
|
|
}
|
|
return errors.New("password not found in file")
|
|
}
|
|
|
|
pass = scanner.Text()
|
|
}
|
|
|
|
return c.keystore.Unlock(account, pass)
|
|
}
|
|
|
|
func (c *ShardingClient) CreateTXOps(value *big.Int) (*bind.TransactOpts, error) {
|
|
account := c.Account()
|
|
|
|
return &bind.TransactOpts{
|
|
From: account.Address,
|
|
Value: value,
|
|
Signer: func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
|
networkID, err := c.client.NetworkID(context.Background())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to fetch networkID: %v", err)
|
|
}
|
|
return c.keystore.SignTx(*account, tx, networkID /* chainID */)
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// Account to use for sharding transactions.
|
|
func (c *ShardingClient) Account() *accounts.Account {
|
|
accounts := c.keystore.Accounts()
|
|
|
|
return &accounts[0]
|
|
}
|
|
|
|
// ChainReader for interacting with the chain.
|
|
func (c *ShardingClient) ChainReader() ethereum.ChainReader {
|
|
return ethereum.ChainReader(c.client)
|
|
}
|
|
|
|
// Client to interact with ethereum node.
|
|
func (c *ShardingClient) ethereumClient() *ethclient.Client {
|
|
return c.client
|
|
}
|
|
|
|
// SMCCaller to interact with the sharding manager contract.
|
|
func (c *ShardingClient) SMCCaller() *contracts.SMCCaller {
|
|
return &c.Smc.SMCCaller
|
|
}
|
|
|
|
// dialRPC endpoint to node.
|
|
func dialRPC(endpoint string) (*rpc.Client, error) {
|
|
if endpoint == "" {
|
|
endpoint = node.DefaultIPCEndpoint(clientIdentifier)
|
|
}
|
|
return rpc.Dial(endpoint)
|
|
}
|