From 6024b11771ea6e251b51c187e4d36994d5a8947f Mon Sep 17 00:00:00 2001 From: Dennis Gloss Date: Sun, 14 Nov 2021 16:28:09 +0300 Subject: [PATCH] utxo outidx, fix sign tx --- README.md | 15 +++++++++++---- addressinfo/api.go | 2 +- addressinfo/blockchain.go | 2 +- addressinfo/blockcypher.go | 2 +- addressinfo/mock.go | 3 ++- .../main.go | 0 txutil/create.go | 8 ++++---- txutil/create_test.go | 4 ++-- 8 files changed, 22 insertions(+), 14 deletions(-) rename examples/{create-transaction => send-transaction}/main.go (100%) diff --git a/README.md b/README.md index 290c44f..4722f2e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ func main() { fmt.Printf("Private Key: %s\nBitcoin address: %s\n", privateKey, address) } ``` +If you just started learning about bitcoins and blockchain, you probably **don't have any testnet bitcoins**, wondering where I can get some. +People on [bitcoin.stackexchange](https://bitcoin.stackexchange.com/questions/17690/is-there-any-where-to-get-free-testnet-bitcoins) provided a lot of links. ## Sending transaction First we need to create a transaction then broadcast it to blockchain. @@ -59,7 +61,12 @@ func main() { **For testing purposes** I used `netchain.TestNet`. If you want to send real bitcoins to blockchain you need to specify BTC_API_KEY env var for blockcypher or you could pass your own txutil.CreateParams.Fetch function to txutil.Create. --- -You can send your bitcoins from multiple wallets by specifying `CreateParams.PrivateKeys`, an array of private keys. -If you specified only one destination address you can set `CreateParams.SendAll` to `true` to send all your bitcoins from your private key or keys. -You can also send your bitcoins to multiple addresses by specifying `CreateParams.Destinations`. -For the full list of transaction parameters look inside `txutil.CreateParams`. +#### More options +`txutil.CreateParams`: + +| Field | Type | Usage | +|:-------------:|:--------------------:|------- | +| PrivateKeys | []string | send your bitcoins from multiple wallets | +| Destinations | []txutil.Destination | send your bitcoins to multiple addresses | +| SendAll | bool | send all your bitcoins from your private key or keys, but it only works if you specified just one destination | +For the full list of the transaction parameters look inside `txutil.CreateParams`. diff --git a/addressinfo/api.go b/addressinfo/api.go index 89ae96d..44c0da5 100644 --- a/addressinfo/api.go +++ b/addressinfo/api.go @@ -11,7 +11,7 @@ type UTXO struct { TxID string Pbscript string Balance int64 - TxOutIdx uint32 + TxOutIdx int } type Fetch func(address string, net netchain.Net) (Address, error) \ No newline at end of file diff --git a/addressinfo/blockchain.go b/addressinfo/blockchain.go index 1e23bde..ed2e01b 100644 --- a/addressinfo/blockchain.go +++ b/addressinfo/blockchain.go @@ -45,7 +45,7 @@ func FetchFromBlockchain(address string, net netchain.Net) (Address, error) { TxID: output.TxID, Pbscript: output.Script, Balance: output.Value, - TxOutIdx: uint32(output.TxOutputN), + TxOutIdx: output.TxOutputN, }) balance += output.Value } diff --git a/addressinfo/blockcypher.go b/addressinfo/blockcypher.go index 69a06b6..e9b7ce9 100644 --- a/addressinfo/blockcypher.go +++ b/addressinfo/blockcypher.go @@ -17,7 +17,7 @@ func FetchFromBlockcypher(address string, net netchain.Net) (Address, error) { for outputIdx, output := range tx.Outputs { if len(output.Addresses) == 1 && output.Addresses[0] == address { if output.SpentBy == "" { - utxos = append(utxos, UTXO{TxID: tx.Hash, Balance: output.Value.Int64(), Pbscript: output.Script, TxOutIdx: uint32(outputIdx)}) + utxos = append(utxos, UTXO{TxID: tx.Hash, Balance: output.Value.Int64(), Pbscript: output.Script, TxOutIdx: outputIdx}) } } } diff --git a/addressinfo/mock.go b/addressinfo/mock.go index 0529b03..cf69f4d 100644 --- a/addressinfo/mock.go +++ b/addressinfo/mock.go @@ -1,13 +1,14 @@ package addressinfo import ( + "github.com/btcsuite/btcd/wire" "github.com/glossd/btc/netchain" mathrand "math/rand" ) func FetchMock(address string, net netchain.Net) (Address, error) { var utxoMock = UTXO{ - TxID: "5dcb1e3a6fcd02e9e216113deda9a914b2b2191a0bb42383817b737c4c3280e2", + TxID: wire.NewMsgTx(wire.TxVersion).TxHash().String(), Balance: mathrand.Int63n(50000000) + 1000000, Pbscript: "76a914fee7132bbe9201c4f1a0f846b5f714d9335e263088ac", TxOutIdx: 1, diff --git a/examples/create-transaction/main.go b/examples/send-transaction/main.go similarity index 100% rename from examples/create-transaction/main.go rename to examples/send-transaction/main.go diff --git a/txutil/create.go b/txutil/create.go index f839ccf..75b29a0 100644 --- a/txutil/create.go +++ b/txutil/create.go @@ -12,6 +12,7 @@ import ( "github.com/glossd/btc/netchain" "github.com/glossd/btc/wallet" "sort" + "strconv" ) const defaultMinerFee = 5000 @@ -208,7 +209,7 @@ func addInputs(tx *wire.MsgTx, utxos []addressinfo.UTXO) error { if err != nil { return err } - outPoint := wire.NewOutPoint(utxoHash, utxo.TxOutIdx) + outPoint := wire.NewOutPoint(utxoHash, uint32(utxo.TxOutIdx)) txIn := wire.NewTxIn(outPoint, nil, nil) tx.AddTxIn(txIn) } @@ -301,7 +302,6 @@ func toPayAddress(address string, net netchain.Net) ([]byte, error) { } func signTx(tx *wire.MsgTx, addresses []address) error { - type utxoWithKey struct { addressinfo.UTXO wif *btcutil.WIF @@ -318,12 +318,12 @@ func signTx(tx *wire.MsgTx, addresses []address) error { if err != nil { return fmt.Errorf("signing transaction failed, could compute hash utxo=%v", u) } - utxosToSpendMap[h.String()] = utxoWithKey{UTXO: u, wif: wif} + utxosToSpendMap[h.String() + strconv.Itoa(u.TxOutIdx)] = utxoWithKey{UTXO: u, wif: wif} } } for i, in := range tx.TxIn { - utxoOfIn := utxosToSpendMap[in.PreviousOutPoint.Hash.String()] + utxoOfIn := utxosToSpendMap[in.PreviousOutPoint.Hash.String() + strconv.Itoa(int(in.PreviousOutPoint.Index))] sourcePkString, err := hex.DecodeString(utxoOfIn.Pbscript) if err != nil { return err diff --git a/txutil/create_test.go b/txutil/create_test.go index a57df61..7c14a81 100644 --- a/txutil/create_test.go +++ b/txutil/create_test.go @@ -49,8 +49,8 @@ func TestCreate_SendAll(t *testing.T) { func TestCreate_MultiplePrivateKeys(t *testing.T) { rawTx, err := Create(CreateParams{ - PrivateKeys: []string{privateKey1, "cMvRbsVJKjRkZTV7tosWEYEu1x8tQcnLEbC64RiKwPeeEz29j8QZ"}, - Destination: "mwRL1TpsRSFy5KXbxEd2KrHiD16VvbbAdj", + PrivateKeys: []string{privateKey1, privateKey2}, + Destination: destination3, SendAll: true, Net: netchain.TestNet, })