mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
[NOD-374] Create transaction signer tool (#435)
* [NOD-374 ] Create transaction signer tool * [NOD-374] Rename variables * [NOD-374] Add network selection; Move error handling to control-flow function * [NOD-374] Rename variables * [NOD-374] Add new line after if blocks * [NOD-374] Fix formatting error (gofmt)
This commit is contained in:
parent
e2d3c4c821
commit
7c9f5a65d8
56
cmd/txsigner/config.go
Normal file
56
cmd/txsigner/config.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/daglabs/btcd/dagconfig"
|
||||||
|
"github.com/jessevdk/go-flags"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var activeNetParams = &dagconfig.MainNetParams
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
Transaction string `long:"transaction" short:"t" description:"Unsigned transaction in HEX format" required:"true"`
|
||||||
|
PrivateKey string `long:"private-key" short:"p" description:"Private key" required:"true"`
|
||||||
|
TestNet bool `long:"testnet" description:"Use the test network"`
|
||||||
|
RegressionTest bool `long:"regtest" description:"Use the regression test network"`
|
||||||
|
SimNet bool `long:"simnet" description:"Use the simulation test network"`
|
||||||
|
DevNet bool `long:"devnet" description:"Use the development test network"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCommandLine() (*config, error) {
|
||||||
|
cfg := &config{}
|
||||||
|
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag)
|
||||||
|
_, err := parser.Parse()
|
||||||
|
// Multiple networks can't be selected simultaneously.
|
||||||
|
funcName := "loadConfig"
|
||||||
|
numNets := 0
|
||||||
|
// Count number of network flags passed; assign active network params
|
||||||
|
// while we're at it
|
||||||
|
if cfg.TestNet {
|
||||||
|
numNets++
|
||||||
|
activeNetParams = &dagconfig.TestNetParams
|
||||||
|
}
|
||||||
|
if cfg.RegressionTest {
|
||||||
|
numNets++
|
||||||
|
activeNetParams = &dagconfig.RegressionNetParams
|
||||||
|
}
|
||||||
|
if cfg.SimNet {
|
||||||
|
numNets++
|
||||||
|
activeNetParams = &dagconfig.SimNetParams
|
||||||
|
}
|
||||||
|
if cfg.DevNet {
|
||||||
|
numNets++
|
||||||
|
activeNetParams = &dagconfig.DevNetParams
|
||||||
|
}
|
||||||
|
if numNets > 1 {
|
||||||
|
str := "%s: The testnet, regtest, simnet and devent params can't be " +
|
||||||
|
"used together -- choose one of the four"
|
||||||
|
err := fmt.Errorf(str, funcName)
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
parser.WriteHelp(os.Stderr)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, err
|
||||||
|
}
|
88
cmd/txsigner/txsigner.go
Normal file
88
cmd/txsigner/txsigner.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/daglabs/btcd/btcec"
|
||||||
|
"github.com/daglabs/btcd/txscript"
|
||||||
|
"github.com/daglabs/btcd/util"
|
||||||
|
"github.com/daglabs/btcd/wire"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := parseCommandLine()
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to parse arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := parsePrivateKey(cfg.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to decode private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction, err := parseTransaction(cfg.Transaction)
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to decode transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptPubKey, err := createScriptPubKey(privateKey.PubKey())
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to create scriptPubKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = signTransaction(transaction, privateKey, scriptPubKey)
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to sign transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedTransaction, err := serializeTransaction(transaction)
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err, "Failed to serialize transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Signed Transaction (hex): %s\n\n", serializedTransaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePrivateKey(privateKeyHex string) (*btcec.PrivateKey, error) {
|
||||||
|
privateKeyBytes, err := hex.DecodeString(privateKeyHex)
|
||||||
|
privateKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privateKeyBytes)
|
||||||
|
return privateKey, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTransaction(transactionHex string) (*wire.MsgTx, error) {
|
||||||
|
serializedTx, err := hex.DecodeString(transactionHex)
|
||||||
|
var transaction wire.MsgTx
|
||||||
|
err = transaction.Deserialize(bytes.NewReader(serializedTx))
|
||||||
|
return &transaction, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createScriptPubKey(publicKey *btcec.PublicKey) ([]byte, error) {
|
||||||
|
p2pkhAddress, err := util.NewAddressPubKeyHashFromPublicKey(publicKey.SerializeCompressed(), activeNetParams.Prefix)
|
||||||
|
scriptPubKey, err := txscript.PayToAddrScript(p2pkhAddress)
|
||||||
|
return scriptPubKey, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func signTransaction(transaction *wire.MsgTx, privateKey *btcec.PrivateKey, scriptPubKey []byte) error {
|
||||||
|
for i, transactionInput := range transaction.TxIn {
|
||||||
|
signatureScript, err := txscript.SignatureScript(transaction, i, scriptPubKey, txscript.SigHashAll, privateKey, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
transactionInput.SignatureScript = signatureScript
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeTransaction(transaction *wire.MsgTx) (string, error) {
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, transaction.SerializeSize()))
|
||||||
|
err := transaction.Serialize(buf)
|
||||||
|
serializedTransaction := hex.EncodeToString(buf.Bytes())
|
||||||
|
return serializedTransaction, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func printErrorAndExit(err error, message string) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s", message, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user