Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR to see changes from base repository #1

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a19e55e
rpc\legacyrpc\methods: Add transferTransaction handler
farukterzioglu Oct 4, 2018
0697c2d
wallet\wallet: Add TransferTx method for transfertransaction RPC command
farukterzioglu Oct 4, 2018
81adaa2
Merge pull request #1 from farukterzioglu/post-dated
farukterzioglu Oct 4, 2018
4edeca7
wallet, rpc\legacyrpc\methods: Fix multiple bugs
farukterzioglu Oct 6, 2018
7cd00ae
wallet, rpc\legacyrpc\methods: Convert txId(string) to txHash (chainH…
farukterzioglu Oct 6, 2018
c6f81a8
wallet\transferTx : Add transferTx.go which includes transaction tran…
farukterzioglu Oct 6, 2018
fcd0c93
wallet\author: Add NewUnsignedTransactionFromInput method for post-dated
farukterzioglu Oct 6, 2018
5599c4e
wallet\transferTx: Add logic for finding transaction from wallet db.
farukterzioglu Oct 6, 2018
0a84362
Merge pull request #2 from farukterzioglu/post-dated
farukterzioglu Oct 6, 2018
420fb8b
wallet: Use publishTransaction in TransferTx method.
farukterzioglu Oct 6, 2018
5b92c6b
Merge branch 'master' of https://github.com/farukterzioglu/btcwallet
farukterzioglu Oct 6, 2018
2b6f207
methods: Return hash of transaction instead of dummy hash
farukterzioglu Oct 7, 2018
3810cf1
transferTx: Return relevant types errors, randomize change output.
farukterzioglu Oct 7, 2018
7ece4db
transferTx: Fix unnecessary loops
farukterzioglu Oct 10, 2018
5d08f43
wallet: Fix wrong wait group count
farukterzioglu Oct 10, 2018
834bebb
Merge pull request #3 from farukterzioglu/develop
farukterzioglu Oct 10, 2018
6e18c96
txauthor/author: Add tx to be transferred as input to created tx
farukterzioglu Oct 11, 2018
3299345
wallet\: Add 'transferTxError' for transaction transfer errors
farukterzioglu Oct 11, 2018
8b45f96
Closing issue 1
farukterzioglu Oct 11, 2018
f88df66
Merge pull request #4 from farukterzioglu/develop
farukterzioglu Oct 11, 2018
4de3e99
Merge pull request #3 from farukterzioglu/develop
farukterzioglu Oct 13, 2018
d1aadab
wallet/transferTx: Discard utxo from eligible utxo list
farukterzioglu Oct 14, 2018
8555cfe
Add readme file for use case of transaction transfer.
farukterzioglu Oct 14, 2018
8f4258c
Merge pull request #7 from farukterzioglu/develop
farukterzioglu Oct 14, 2018
d48ab39
Update README.md
farukterzioglu Oct 14, 2018
337b0a6
wallet/txtransfer/author: Add newCoincaseTransaction method
farukterzioglu Oct 24, 2018
15fd86e
Merge pull request #8 from farukterzioglu/post-dated
farukterzioglu Oct 24, 2018
e78bdde
wallet: Move transaction transfer related codes to transferTx.go
farukterzioglu Oct 25, 2018
c6115d7
wallet/postdated: Add post dated transaction implementations
farukterzioglu Oct 25, 2018
384ce05
Merge pull request #9 from farukterzioglu/post-dated
farukterzioglu Oct 25, 2018
7e187e0
Add&Refactor post dated tx related implementations.
farukterzioglu Oct 29, 2018
6707d41
wallet/coincasetx: Add coincase tx related implementations.
farukterzioglu Oct 29, 2018
4ba13df
wallet/postdated: Fix&Notes&Refactor
farukterzioglu Oct 29, 2018
05dac5b
Merge pull request #10 from farukterzioglu/post-dated
farukterzioglu Oct 29, 2018
1a27b81
Use AuthoredTx instead of AuthoredPostDatedTx. Sign the created tx.
farukterzioglu Nov 1, 2018
44ebf3f
Merge branch 'master' into post-dated
farukterzioglu Nov 1, 2018
a41363d
Merge pull request #11 from farukterzioglu/post-dated
farukterzioglu Nov 1, 2018
5de3670
Merge branch 'master' of https://github.com/farukterzioglu/btcwallet
farukterzioglu Nov 2, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
btcwallet
vendor
.idea
*.exe
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Check use case for transferring a transaction as a whole
[Transaction transfer use case](/wallet/txtransfer/README-SampleUsage.md)

btcwallet
=========

Expand Down
1 change: 1 addition & 0 deletions internal/rpchelp/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var Methods = []struct {
{"sendfrom", returnsString},
{"sendmany", returnsString},
{"sendtoaddress", returnsString},
{"transfertransaction", returnsString},
{"settxfee", returnsBool},
{"signmessage", returnsString},
{"signrawtransaction", []interface{}{(*btcjson.SignRawTransactionResult)(nil)}},
Expand Down
59 changes: 59 additions & 0 deletions rpc/legacyrpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ var rpcHandlers = map[string]struct {
"lockunspent": {handler: lockUnspent},
"sendfrom": {handlerWithChain: sendFrom},
"sendmany": {handler: sendMany},
"sendPostDatedTx": {handler: sendPostDatedTx},
"transfertransaction": {handler: transferTransaction},
"sendtoaddress": {handler: sendToAddress},
"settxfee": {handler: setTxFee},
"signmessage": {handler: signMessage},
Expand Down Expand Up @@ -1492,6 +1494,63 @@ func sendMany(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
return sendPairs(w, pairs, account, minConf, txrules.DefaultRelayFeePerKb)
}

// TODO : write summary
func sendPostDatedTx(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
cmd := icmd.(*btcjson.SendPostDatedTxCmd)

redeemTxHash, _ := w.SendPostDated(cmd.Address, cmd.Amount, cmd.LockTime, waddrmgr.DefaultAccountNum) //txHash
// TODO : Check for error

txHashStr := redeemTxHash.String()
log.Infof("Successfully transferred transaction %v", txHashStr)
return txHashStr, nil
}

// TODO : write summary
func transferTransaction(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
cmd := icmd.(*btcjson.TransferTransactionCmd)

address := cmd.Address
txHash, err := chainhash.NewHashFromStr(cmd.TxId)
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCDecodeHexString,
Message: "Transaction hash string decode failed: " + err.Error(),
}
}

return transferToAddress(w, address, *txHash,
waddrmgr.DefaultAccountNum, 1, txrules.DefaultRelayFeePerKb)
}

func transferToAddress(w *wallet.Wallet, addrStr string, txHash chainhash.Hash,
account uint32, minconf int32, feeSatPerKb btcutil.Amount) (string, error) {

redeemTxHash, err := w.TransferTx(addrStr, txHash, account, minconf, feeSatPerKb) //txHash
if err != nil {
// TODO : check for tx is not found error
// TODO : check for tx is not mature error
// TODO : check for fee not enough

if waddrmgr.IsError(err, waddrmgr.ErrLocked) {
return "", &ErrWalletUnlockNeeded
}
switch err.(type) {
case btcjson.RPCError:
return "", err
}

return "", &btcjson.RPCError{
Code: btcjson.ErrRPCInternal.Code,
Message: err.Error(),
}
}

txHashStr := redeemTxHash.String()
log.Infof("Successfully transferred transaction %v", txHashStr)
return txHashStr, nil
}

// sendToAddress handles a sendtoaddress RPC request by creating a new
// transaction spending unspent transaction outputs for a wallet to another
// payment address. Leftover inputs not sent to the payment address or a fee
Expand Down
1 change: 1 addition & 0 deletions rpc/legacyrpc/rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func helpDescsEnUS() map[string]string {
"lockunspent": "lockunspent unlock [{\"txid\":\"value\",\"vout\":n},...]\n\nLocks or unlocks an unspent output.\nLocked outputs are not chosen for transaction inputs of authored transactions and are not included in 'listunspent' results.\nLocked outputs are volatile and are not saved across wallet restarts.\nIf unlock is true and no transaction outputs are specified, all locked outputs are marked unlocked.\n\nArguments:\n1. unlock (boolean, required) True to unlock outputs, false to lock\n2. transactions (array of object, required) Transaction outputs to lock or unlock\n[{\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n},...]\n\nResult:\ntrue|false (boolean) The boolean 'true'\n",
"sendfrom": "sendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\n\nDEPRECATED -- Authors, signs, and sends a transaction that outputs some amount to a payment address.\nA change output is automatically included to send extra output value back to the original account.\n\nArguments:\n1. fromaccount (string, required) Account to pick unspent outputs from\n2. toaddress (string, required) Address to pay\n3. amount (numeric, required) Amount to send to the payment address valued in bitcoin\n4. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction output is eligible to be spent\n5. comment (string, optional) Unused\n6. commentto (string, optional) Unused\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
"sendmany": "sendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\n\nAuthors, signs, and sends a transaction that outputs to many payment addresses.\nA change output is automatically included to send extra output value back to the original account.\n\nArguments:\n1. fromaccount (string, required) DEPRECATED -- Account to pick unspent outputs from\n2. amounts (object, required) Pairs of payment addresses and the output amount to pay each\n{\n \"Address to pay\": Amount to send to the payment address valued in bitcoin, (object) JSON object using payment addresses as keys and output amounts valued in bitcoin to send to each address\n ...\n}\n3. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction output is eligible to be spent\n4. comment (string, optional) Unused\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
"transfertransaction": "transfertransaction",
"sendtoaddress": "sendtoaddress \"address\" amount (\"comment\" \"commentto\")\n\nAuthors, signs, and sends a transaction that outputs some amount to a payment address.\nUnlike sendfrom, outputs are always chosen from the default account.\nA change output is automatically included to send extra output value back to the original account.\n\nArguments:\n1. address (string, required) Address to pay\n2. amount (numeric, required) Amount to send to the payment address valued in bitcoin\n3. comment (string, optional) Unused\n4. commentto (string, optional) Unused\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
"settxfee": "settxfee amount\n\nModify the increment used each time more fee is required for an authored transaction.\n\nArguments:\n1. amount (numeric, required) The new fee increment valued in bitcoin\n\nResult:\ntrue|false (boolean) The boolean 'true'\n",
"signmessage": "signmessage \"address\" \"message\"\n\nSigns a message using the private key of a payment address.\n\nArguments:\n1. address (string, required) Payment address of private key used to sign the message with\n2. message (string, required) Message to sign\n\nResult:\n\"value\" (string) The signed message encoded as a base64 string\n",
Expand Down
66 changes: 66 additions & 0 deletions wallet/coincasetx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package wallet

import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)

const (
coincaseTxFlags = "/POSTDATED/"

// TODO : Need to be in wire package
PostDatedTxVersion = 2
)

func createCoincaseScript() ([]byte, error) {
return txscript.NewScriptBuilder().AddData([]byte(coincaseTxFlags)).Script()
}

// Reference : btcsuite\btcd\mining\mining.go:253
func newCoincaseTransaction(pkScript []byte, amount int64, lockTime uint32) (
*btcutil.Tx, error) {
var err error

postDatedScript, err := createCoincaseScript()
if err != nil {
return nil, err
}

tx := wire.NewMsgTx(PostDatedTxVersion)

tx.AddTxIn(&wire.TxIn{
// Coincase transactions have no inputs, so previous outpoint is
// zero hash and max index.
PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
wire.MaxPrevOutIndex),
SignatureScript: postDatedScript,
Sequence: wire.MaxTxInSequenceNum,
})
tx.AddTxOut(&wire.TxOut{
Value: amount,
PkScript: pkScript,
})

tx.LockTime = lockTime

// Reference : btcsuite\btcd\mining\mining.go:805
// TODO : Check segwit related codes

return btcutil.NewTx(tx), nil
}

func (w *Wallet) createCoincase(
coincaseAddr btcutil.Address,
amount int64, lockTime uint32) (coincaseTx *btcutil.Tx, err error) {

// Create coincase
pkScript, err := txscript.PayToAddrScript(coincaseAddr)
if err != nil {
return
}

coincaseTx, err = newCoincaseTransaction(pkScript, amount, lockTime)
return
}
153 changes: 153 additions & 0 deletions wallet/postdated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// TODO : License related notes

package wallet

import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wallet/txrules"
"github.com/btcsuite/btcwallet/walletdb"
)

// wallet/wallet.go
func (w *Wallet) SendPostDated(addrStr string, amount int64, lockTime uint32,
account uint32) (*chainhash.Hash, error) {
createdTx, err := w.createSimplePostDatedTx(addrStr, amount, lockTime, account)
if err != nil {
return nil, err
}

return w.publishTransaction(createdTx.Tx)
}

// wallet/wallet.go
type (
createPostDatedTxRequest struct {
account uint32
address string
amount int64
lockTime uint32
feeSatPerKB btcutil.Amount
resp chan createPostDatedTxResponse
}
createPostDatedTxResponse struct {
tx *txauthor.AuthoredTx
err error
}
)

// wallet/wallet.go
func (w *Wallet) createSimplePostDatedTx(address string, amount int64, lockTime uint32,
account uint32) (*txauthor.AuthoredTx, error) {
req := createPostDatedTxRequest{
account: account,
address: address,
lockTime: lockTime,
amount: amount,
resp: make(chan createPostDatedTxResponse),
}

// TODO : use channels instead of direct call
//w.createPostDatedTxRequests <- req
//resp := <-req.resp
resp := w.createPostDatedTx(req)
return resp.tx, resp.err
}

// TODO : move to wallet/wallet.go
func (w *Wallet) postDatedTxCreator() {
quit := w.quitChan()
out:
for {
select {
case txr := <-w.createPostDatedTxRequests:
heldUnlock, err := w.holdUnlock()
if err != nil {
txr.resp <- createPostDatedTxResponse{nil, err}
continue
}
res := w.createPostDatedTx(txr)
heldUnlock.release()
txr.resp <- res
case <-quit:
break out
}
}
w.wg.Done()
}

func NewUnsignedTransactionFromCoincase(coincaseTx *btcutil.Tx, output *wire.TxOut) (*txauthor.AuthoredTx, error) {
// Create unsigned tx
unsignedTransaction := &wire.MsgTx{
Version: PostDatedTxVersion,
}

outpoint := wire.NewOutPoint(coincaseTx.Hash(), 0)
txIn := wire.NewTxIn(outpoint, nil, nil)

unsignedTransaction.AddTxIn(txIn)
unsignedTransaction.AddTxOut(output)
unsignedTransaction.LockTime = coincaseTx.MsgTx().LockTime

// Get amount from coincase
amount := btcutil.Amount(coincaseTx.MsgTx().TxOut[0].Value)
currentInputValues := []btcutil.Amount{amount}

// Get pkScript from coincase
currentScripts := [][]byte{coincaseTx.MsgTx().TxOut[0].PkScript}

return &txauthor.AuthoredTx{
Tx: unsignedTransaction,
PrevScripts: currentScripts,
PrevInputValues: currentInputValues,
TotalInput: 1,
ChangeIndex: -1,
}, nil
}

//
func (w *Wallet) createPostDatedTx(req createPostDatedTxRequest) createPostDatedTxResponse {
amount := btcutil.Amount(req.amount)
redeemOutput, err := makeOutput(req.address, amount, w.ChainParams())
if err != nil {
return createPostDatedTxResponse{nil, err}
}

if err := txrules.CheckOutput(redeemOutput, req.feeSatPerKB); err != nil {
return createPostDatedTxResponse{nil, err}
}

// Reference server.go:236
var coincaseAddr btcutil.Address
coincaseAddr, err = w.NewChangeAddress(req.account, waddrmgr.KeyScopeBIP0044)

coincaseTx, err := w.createCoincase(coincaseAddr, req.amount, req.lockTime)
if err != nil {
return createPostDatedTxResponse{nil, err}
}

var tx *txauthor.AuthoredTx
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
addrmgrNs := dbtx.ReadWriteBucket(waddrmgrNamespaceKey)

tx, err = NewUnsignedTransactionFromCoincase(coincaseTx, redeemOutput)
if err != nil {
return err
}

return tx.AddAllInputScripts(secretSource{w.Manager, addrmgrNs})
})
if err != nil {
return createPostDatedTxResponse{nil, err}
}

err = validateMsgTx(tx.Tx, tx.PrevScripts, tx.PrevInputValues)
if err != nil {
return createPostDatedTxResponse{nil, err}
}

return createPostDatedTxResponse{tx, nil}
}
Loading