diff --git a/.gitignore b/.gitignore index 72fb9416..c95eaa22 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,8 @@ _cgo_export.* _testmain.go *.exe + +# bins + +btcd +cmd/btcctl diff --git a/btcjson/walletsvrcmds.go b/btcjson/walletsvrcmds.go index 66975551..e7ac5a78 100644 --- a/btcjson/walletsvrcmds.go +++ b/btcjson/walletsvrcmds.go @@ -600,6 +600,24 @@ type SignRawTransactionCmd struct { Flags *string `jsonrpcdefault:"\"ALL\""` } +// NewSignRawTransactionWithWalletCmd returns a new instance which can be used to issue a +// signrawtransaction JSON-RPC command. +// +// The parameters which are pointers indicate they are optional. Passing nil +// for optional parameters will use the default value. +func NewSignRawTransactionWithWalletCmd(hexEncodedTx string, inputs *[]RawTxInput) *SignRawTransactionWithWalletCmd { + return &SignRawTransactionWithWalletCmd{ + RawTx: hexEncodedTx, + Inputs: inputs, + } +} + +// SignRawTransactionWithWalletCmd defines the signrawtransactionwithwallet JSON-RPC command. +type SignRawTransactionWithWalletCmd struct { + RawTx string + Inputs *[]RawTxInput +} + // NewSignRawTransactionCmd returns a new instance which can be used to issue a // signrawtransaction JSON-RPC command. // @@ -693,6 +711,7 @@ func init() { MustRegisterCmd("settxfee", (*SetTxFeeCmd)(nil), flags) MustRegisterCmd("signmessage", (*SignMessageCmd)(nil), flags) MustRegisterCmd("signrawtransaction", (*SignRawTransactionCmd)(nil), flags) + MustRegisterCmd("signrawtransactionwithwallet", (*SignRawTransactionWithWalletCmd)(nil), flags) MustRegisterCmd("walletlock", (*WalletLockCmd)(nil), flags) MustRegisterCmd("walletpassphrase", (*WalletPassphraseCmd)(nil), flags) MustRegisterCmd("walletpassphrasechange", (*WalletPassphraseChangeCmd)(nil), flags) diff --git a/btcjson/walletsvrresults.go b/btcjson/walletsvrresults.go index 9246d131..3a08ef60 100644 --- a/btcjson/walletsvrresults.go +++ b/btcjson/walletsvrresults.go @@ -137,6 +137,14 @@ type SignRawTransactionResult struct { Errors []SignRawTransactionError `json:"errors,omitempty"` } +// SignRawTransactionWithWalletResult models the data from the +// signrawtransactionwithwallet command. +type SignRawTransactionWithWalletResult struct { + Hex string `json:"hex"` + Complete bool `json:"complete"` + Errors []SignRawTransactionError `json:"errors,omitempty"` +} + // ValidateAddressWalletResult models the data returned by the wallet server // validateaddress command. type ValidateAddressWalletResult struct { diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index 4bf4ee57..ac6598cc 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -402,6 +402,72 @@ func (c *Client) SignRawTransaction(tx *wire.MsgTx) (*wire.MsgTx, bool, error) { return c.SignRawTransactionAsync(tx).Receive() } +// FutureSignRawTransactionWithWalletResult is a future promise to deliver the result +// of the SignRawTransactionWithKeyAsync family of RPC invocations (or an +// applicable error). +type FutureSignRawTransactionWithWalletResult chan *response + +// Receive waits for the response promised by the future and returns the +// signed transaction as well as whether or not all inputs are now signed. +func (r FutureSignRawTransactionWithWalletResult) Receive() (*wire.MsgTx, bool, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, false, err + } + + // Unmarshal as a signrawtransaction result. + var signRawTxResult btcjson.SignRawTransactionResult + err = json.Unmarshal(res, &signRawTxResult) + if err != nil { + return nil, false, err + } + + // Decode the serialized transaction hex to raw bytes. + serializedTx, err := hex.DecodeString(signRawTxResult.Hex) + if err != nil { + return nil, false, err + } + + // Deserialize the transaction and return it. + var msgTx wire.MsgTx + if err := msgTx.Deserialize(bytes.NewReader(serializedTx)); err != nil { + return nil, false, err + } + + return &msgTx, signRawTxResult.Complete, nil +} + +// SignRawTransactionWithWalletAsync returns an instance of a type that can be used to get +// the result of the RPC at some future time by invoking the Receive function on +// the returned instance. +// +// See SignRawTransaction for the blocking version and more details. +func (c *Client) SignRawTransactionWithWalletAsync(tx *wire.MsgTx) FutureSignRawTransactionResult { + txHex := "" + if tx != nil { + // Serialize the transaction and convert to hex string. + buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) + if err := tx.Serialize(buf); err != nil { + return newFutureError(err) + } + txHex = hex.EncodeToString(buf.Bytes()) + } + + cmd := btcjson.NewSignRawTransactionWithWalletCmd(txHex, nil) + return c.sendCmd(cmd) +} + +// SignRawTransactionWithWallet signs inputs for the passed transaction and returns the +// signed transaction as well as whether or not all inputs are now signed. +// +// This function assumes the RPC server already knows the input transactions and +// private keys for the passed transaction which needs to be signed and uses the +// default signature hash type. Use one of the SignRawTransaction# variants to +// specify that information if needed. +func (c *Client) SignRawTransactionWithWallet(tx *wire.MsgTx) (*wire.MsgTx, bool, error) { + return c.SignRawTransactionWithWalletAsync(tx).Receive() +} + // SignRawTransaction2Async returns an instance of a type that can be used to // get the result of the RPC at some future time by invoking the Receive // function on the returned instance. diff --git a/rpcserver.go b/rpcserver.go index e762cc1a..33ed8df4 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -179,48 +179,49 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ // it lacks support for wallet functionality. For these commands the user // should ask a connected instance of btcwallet. var rpcAskWallet = map[string]struct{}{ - "addmultisigaddress": {}, - "backupwallet": {}, - "createencryptedwallet": {}, - "createmultisig": {}, - "dumpprivkey": {}, - "dumpwallet": {}, - "encryptwallet": {}, - "getaccount": {}, - "getaccountaddress": {}, - "getaddressesbyaccount": {}, - "getbalance": {}, - "getnewaddress": {}, - "getrawchangeaddress": {}, - "getreceivedbyaccount": {}, - "getreceivedbyaddress": {}, - "gettransaction": {}, - "gettxoutsetinfo": {}, - "getunconfirmedbalance": {}, - "getwalletinfo": {}, - "importprivkey": {}, - "importwallet": {}, - "keypoolrefill": {}, - "listaccounts": {}, - "listaddressgroupings": {}, - "listlockunspent": {}, - "listreceivedbyaccount": {}, - "listreceivedbyaddress": {}, - "listsinceblock": {}, - "listtransactions": {}, - "listunspent": {}, - "lockunspent": {}, - "move": {}, - "sendfrom": {}, - "sendmany": {}, - "sendtoaddress": {}, - "setaccount": {}, - "settxfee": {}, - "signmessage": {}, - "signrawtransaction": {}, - "walletlock": {}, - "walletpassphrase": {}, - "walletpassphrasechange": {}, + "addmultisigaddress": {}, + "backupwallet": {}, + "createencryptedwallet": {}, + "createmultisig": {}, + "dumpprivkey": {}, + "dumpwallet": {}, + "encryptwallet": {}, + "getaccount": {}, + "getaccountaddress": {}, + "getaddressesbyaccount": {}, + "getbalance": {}, + "getnewaddress": {}, + "getrawchangeaddress": {}, + "getreceivedbyaccount": {}, + "getreceivedbyaddress": {}, + "gettransaction": {}, + "gettxoutsetinfo": {}, + "getunconfirmedbalance": {}, + "getwalletinfo": {}, + "importprivkey": {}, + "importwallet": {}, + "keypoolrefill": {}, + "listaccounts": {}, + "listaddressgroupings": {}, + "listlockunspent": {}, + "listreceivedbyaccount": {}, + "listreceivedbyaddress": {}, + "listsinceblock": {}, + "listtransactions": {}, + "listunspent": {}, + "lockunspent": {}, + "move": {}, + "sendfrom": {}, + "sendmany": {}, + "sendtoaddress": {}, + "setaccount": {}, + "settxfee": {}, + "signmessage": {}, + "signrawtransaction": {}, + "signrawtransactionWithWallet": {}, + "walletlock": {}, + "walletpassphrase": {}, + "walletpassphrasechange": {}, } // Commands that are currently unimplemented, but should ultimately be.