[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:
Dan Aharoni 2019-10-29 15:00:03 +02:00 committed by stasatdaglabs
parent e2d3c4c821
commit 7c9f5a65d8
2 changed files with 144 additions and 0 deletions

56
cmd/txsigner/config.go Normal file
View 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
View 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)
}