mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-25 21:07:18 +00:00
0d400faea2
* Remove unused parameters * Remove unused deposit contract config
227 lines
6.4 KiB
Go
227 lines
6.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
|
|
prysmKeyStore "github.com/prysmaticlabs/prysm/shared/keystore"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/version"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli"
|
|
prefixed "github.com/x-cray/logrus-prefixed-formatter"
|
|
)
|
|
|
|
var (
|
|
log = logrus.WithField("prefix", "main")
|
|
)
|
|
|
|
func main() {
|
|
var keystoreUTCPath string
|
|
var prysmKeystorePath string
|
|
var ipcPath string
|
|
var passwordFile string
|
|
var httpPath string
|
|
var privKeyString string
|
|
var depositContractAddr string
|
|
var numberOfDeposits int64
|
|
var depositAmount int64
|
|
var depositDelay int64
|
|
var randomKey bool
|
|
|
|
customFormatter := new(prefixed.TextFormatter)
|
|
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
|
customFormatter.FullTimestamp = true
|
|
logrus.SetFormatter(customFormatter)
|
|
|
|
app := cli.NewApp()
|
|
app.Name = "sendDepositTx"
|
|
app.Usage = "this is a util to send deposit transactions"
|
|
app.Version = version.GetVersion()
|
|
app.Flags = []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "keystoreUTCPath",
|
|
Usage: "Location of keystore",
|
|
Destination: &keystoreUTCPath,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "prysm-keystore",
|
|
Usage: "The path to the existing prysm keystore. This flag is ignored if used with --random-key",
|
|
Destination: &prysmKeystorePath,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "ipcPath",
|
|
Usage: "Filename for IPC socket/pipe within the datadir",
|
|
Destination: &ipcPath,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "httpPath",
|
|
Value: "http://localhost:8545/",
|
|
Usage: "HTTP-RPC server listening interface",
|
|
Destination: &httpPath,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "passwordFile",
|
|
Value: "./password.txt",
|
|
Usage: "Password file for unlock account",
|
|
Destination: &passwordFile,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "privKey",
|
|
Usage: "Private key to send ETH transaction",
|
|
Destination: &privKeyString,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "depositContract",
|
|
Usage: "Address of the deposit contract",
|
|
Destination: &depositContractAddr,
|
|
},
|
|
cli.Int64Flag{
|
|
Name: "numberOfDeposits",
|
|
Value: 1,
|
|
Usage: "number of deposits to send to the contract",
|
|
Destination: &numberOfDeposits,
|
|
},
|
|
cli.Int64Flag{
|
|
Name: "depositAmount",
|
|
Value: 3200,
|
|
Usage: "Maximum deposit value allowed in contract(in gwei)",
|
|
Destination: &depositAmount,
|
|
},
|
|
cli.Int64Flag{
|
|
Name: "depositDelay",
|
|
Value: 5,
|
|
Usage: "The time delay between sending the deposits to the contract(in seconds)",
|
|
Destination: &depositDelay,
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "random-key",
|
|
Usage: "Use a randomly generated keystore key",
|
|
Destination: &randomKey,
|
|
},
|
|
}
|
|
|
|
app.Action = func(c *cli.Context) {
|
|
// Set up RPC client
|
|
var rpcClient *rpc.Client
|
|
var err error
|
|
var txOps *bind.TransactOpts
|
|
|
|
// Uses HTTP-RPC if IPC is not set
|
|
if ipcPath == "" {
|
|
rpcClient, err = rpc.Dial(httpPath)
|
|
} else {
|
|
rpcClient, err = rpc.Dial(ipcPath)
|
|
}
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
client := ethclient.NewClient(rpcClient)
|
|
depositAmountInGwei := uint64(depositAmount)
|
|
|
|
if privKeyString != "" {
|
|
// User inputs private key, sign tx with private key
|
|
privKey, err := crypto.HexToECDSA(privKeyString)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
txOps = bind.NewKeyedTransactor(privKey)
|
|
txOps.Value = new(big.Int).Mul(big.NewInt(depositAmount), big.NewInt(1e9))
|
|
} else {
|
|
// User inputs keystore json file, sign tx with keystore json
|
|
password := loadTextFromFile(passwordFile)
|
|
|
|
// #nosec - Inclusion of file via variable is OK for this tool.
|
|
keyJSON, err := ioutil.ReadFile(keystoreUTCPath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
privKey, err := keystore.DecryptKey(keyJSON, password)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
txOps = bind.NewKeyedTransactor(privKey.PrivateKey)
|
|
txOps.Value = new(big.Int).Mul(big.NewInt(depositAmount), big.NewInt(1e9))
|
|
txOps.GasLimit = 500000
|
|
}
|
|
|
|
depositContract, err := contracts.NewDepositContract(common.HexToAddress(depositContractAddr), client)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
validatorKeys := make(map[string]*prysmKeyStore.Key)
|
|
if randomKey {
|
|
validatorKey, err := prysmKeyStore.NewKey()
|
|
validatorKeys[hex.EncodeToString(validatorKey.PublicKey.Marshal())] = validatorKey
|
|
if err != nil {
|
|
log.Errorf("Could not generate random key: %v", err)
|
|
}
|
|
} else {
|
|
// Load from keystore
|
|
store := prysmKeyStore.NewKeystore(prysmKeystorePath)
|
|
rawPassword := loadTextFromFile(passwordFile)
|
|
prefix := params.BeaconConfig().ValidatorPrivkeyFileName
|
|
validatorKeys, err = store.GetKeys(prysmKeystorePath, prefix, rawPassword)
|
|
if err != nil {
|
|
log.WithField("path", prysmKeystorePath).WithField("password", rawPassword).Errorf("Could not get keys: %v", err)
|
|
}
|
|
}
|
|
|
|
keyCounter := int64(0)
|
|
for _, validatorKey := range validatorKeys {
|
|
data, depositRoot, err := prysmKeyStore.DepositInput(validatorKey, validatorKey, depositAmountInGwei)
|
|
if err != nil {
|
|
log.Errorf("Could not generate deposit input data: %v", err)
|
|
continue
|
|
}
|
|
for j := int64(0); j < numberOfDeposits; j++ {
|
|
tx, err := depositContract.Deposit(txOps, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoot)
|
|
if err != nil {
|
|
log.Errorf("unable to send transaction to contract: %v", err)
|
|
continue
|
|
}
|
|
|
|
log.WithFields(logrus.Fields{
|
|
"Transaction Hash": fmt.Sprintf("%#x", tx.Hash()),
|
|
}).Infof("Deposit %d sent to contract address %v for validator with a public key %#x", (keyCounter*numberOfDeposits)+j, depositContractAddr, validatorKey.PublicKey.Marshal())
|
|
|
|
time.Sleep(time.Duration(depositDelay) * time.Second)
|
|
}
|
|
keyCounter++
|
|
}
|
|
}
|
|
|
|
err := app.Run(os.Args)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func loadTextFromFile(filepath string) string {
|
|
// #nosec - Inclusion of file via variable is OK for this tool.
|
|
file, err := os.Open(filepath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Split(bufio.ScanWords)
|
|
scanner.Scan()
|
|
return scanner.Text()
|
|
}
|