func (w *LibbitcoinWallet) GetCurrentKey(purpose bitcoin.KeyPurpose) *b32.Key { key, used, _ := w.db.Keys().GetLastKey(purpose) if key == nil { // No keys in this chain have been generated yet. Let's generate key 0. childKey := w.generateChildKey(purpose, 0) addr, _ := btc.NewAddressPubKey(childKey.PublicKey().Key, w.params) script, _ := txscript.PayToAddrScript(addr.AddressPubKeyHash()) w.db.Keys().Put(childKey, script, purpose) if purpose == bitcoin.RECEIVING || purpose == bitcoin.REFUND { w.SubscribeAddress(addr.AddressPubKeyHash()) } return childKey } else if used { // The last key in the chain has been used. Let's generated a new key and save it in the db. index := binary.BigEndian.Uint32(key.ChildNumber) childKey := w.generateChildKey(purpose, index+1) addr, _ := btc.NewAddressPubKey(childKey.PublicKey().Key, w.params) script, _ := txscript.PayToAddrScript(addr.AddressPubKeyHash()) w.db.Keys().Put(childKey, script, purpose) if purpose == bitcoin.RECEIVING || purpose == bitcoin.REFUND { w.SubscribeAddress(addr.AddressPubKeyHash()) } return childKey } else { // The last key in the chain is unused so let's just return it. return key } }
// This example demonstrates creating a script which pays to a bitcoin address. // It also prints the created script hex and uses the DisasmString function to // display the disassembled script. func ExamplePayToAddrScript() { // Parse the address to send the coins to into a btcutil.Address // which is useful to ensure the accuracy of the address and determine // the address type. It is also required for the upcoming call to // PayToAddrScript. addressStr := "12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV" address, err := btcutil.DecodeAddress(addressStr, &chaincfg.MainNetParams) if err != nil { fmt.Println(err) return } // Create a public key script that pays to the address. script, err := txscript.PayToAddrScript(address) if err != nil { fmt.Println(err) return } fmt.Printf("Script Hex: %x\n", script) disasm, err := txscript.DisasmString(script) if err != nil { fmt.Println(err) return } fmt.Println("Script Disassembly:", disasm) // Output: // Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac // Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG }
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy // based on the passed block height to the provided address. When the address // is nil, the coinbase transaction will instead be redeemable by anyone. // // See the comment for NewBlockTemplate for more information about why the nil // address handling is useful. func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) { // Create the script to pay to the provided payment address if one was // specified. Otherwise create a script that allows the coinbase to be // redeemable by anyone. var pkScript []byte if addr != nil { var err error pkScript, err = txscript.PayToAddrScript(addr) if err != nil { return nil, err } } else { var err error scriptBuilder := txscript.NewScriptBuilder() pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script() if err != nil { return nil, err } } tx := wire.NewMsgTx(wire.TxVersion) tx.AddTxIn(&wire.TxIn{ // Coinbase transactions have no inputs, so previous outpoint is // zero hash and max index. PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{}, wire.MaxPrevOutIndex), SignatureScript: coinbaseScript, Sequence: wire.MaxTxInSequenceNum, }) tx.AddTxOut(&wire.TxOut{ Value: blockchain.CalcBlockSubsidy(nextBlockHeight, params), PkScript: pkScript, }) return btcutil.NewTx(tx), nil }
// TstCreateSeriesCredits creates a new credit for every item in the amounts // slice, locked to the given series' address with branch==1 and index==0. func TstCreateSeriesCredits(t *testing.T, pool *Pool, seriesID uint32, amounts []int64) []credit { addr := TstNewWithdrawalAddress(t, pool, seriesID, Branch(1), Index(0)) pkScript, err := txscript.PayToAddrScript(addr.addr) if err != nil { t.Fatal(err) } msgTx := createMsgTx(pkScript, amounts) txHash := msgTx.TxHash() credits := make([]credit, len(amounts)) for i := range msgTx.TxOut { c := wtxmgr.Credit{ OutPoint: wire.OutPoint{ Hash: txHash, Index: uint32(i), }, BlockMeta: wtxmgr.BlockMeta{ Block: wtxmgr.Block{Height: TstInputsBlock}, }, Amount: btcutil.Amount(msgTx.TxOut[i].Value), PkScript: msgTx.TxOut[i].PkScript, } credits[i] = newCredit(c, *addr) } return credits }
// makeDestinationScriptSource creates a ChangeSource which is used to receive // all correlated previous input value. A non-change address is created by this // function. func makeDestinationScriptSource(rpcClient *btcrpcclient.Client, accountName string) txauthor.ChangeSource { return func() ([]byte, error) { destinationAddress, err := rpcClient.GetNewAddress(accountName) if err != nil { return nil, err } return txscript.PayToAddrScript(destinationAddress) } }
// createTxOut generates a TxOut that can be added to a transaction. func createTxOut(outCoins uint64, addr btcutil.Address) *wire.TxOut { // Take the address and generate a PubKeyScript out of it script, err := txscript.PayToAddrScript(addr) if err != nil { log.Fatal(err) } txout := wire.NewTxOut(int64(outCoins), script) return txout }
// createTxOut generates a TxOut that can be added to a transaction. func createTxOut(inCoin int64, addr btcutil.Address) *wire.TxOut { // Pay the minimum network fee so that nodes will broadcast the tx. outCoin := inCoin - TX_FEE // Take the address and generate a PubKeyScript out of it script, err := txscript.PayToAddrScript(addr) if err != nil { log.Fatal(err) } txout := wire.NewTxOut(outCoin, script) return txout }
func TestFakeTxs(t *testing.T) { // First we need a wallet. w, err := keystore.NewStore("banana wallet", "", []byte("banana"), wire.MainNet, &keystore.BlockStamp{}, 100) if err != nil { t.Errorf("Can not create encrypted wallet: %s", err) return } a := &Wallet{ Wallet: w, lockedOutpoints: map[wire.OutPoint]struct{}{}, } w.Unlock([]byte("banana")) // Create and add a fake Utxo so we have some funds to spend. // // This will pass validation because txcscript is unaware of invalid // tx inputs, however, this example would fail in btcd. utxo := &tx.Utxo{} addr, err := w.NextChainedAddress(&keystore.BlockStamp{}, 100) if err != nil { t.Errorf("Cannot get next address: %s", err) return } copy(utxo.AddrHash[:], addr.ScriptAddress()) ophash := (wire.ShaHash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}) out := wire.NewOutPoint(&ophash, 0) utxo.Out = tx.OutPoint(*out) ss, err := txscript.PayToAddrScript(addr) if err != nil { t.Errorf("Could not create utxo PkScript: %s", err) return } utxo.Subscript = tx.PkScript(ss) utxo.Amt = 1000000 utxo.Height = 12345 a.UtxoStore = append(a.UtxoStore, utxo) // Fake our current block height so btcd doesn't need to be queried. curBlock.BlockStamp.Height = 12346 // Create the transaction. pairs := map[string]int64{ "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000, } _, err = a.txToPairs(pairs, 1) if err != nil { t.Errorf("Tx creation failed: %s", err) return } }
func (w *LibbitcoinWallet) GetFreshKey(purpose bitcoin.KeyPurpose) *b32.Key { key, _, _ := w.db.Keys().GetLastKey(purpose) index := binary.BigEndian.Uint32(key.ChildNumber) childKey := w.generateChildKey(purpose, index+1) addr, _ := btc.NewAddressPubKey(childKey.PublicKey().Key, w.params) script, _ := txscript.PayToAddrScript(addr.AddressPubKeyHash()) w.db.Keys().Put(childKey, script, purpose) if purpose == bitcoin.RECEIVING || purpose == bitcoin.REFUND { w.SubscribeAddress(addr.AddressPubKeyHash()) } return childKey }
func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, idx Index) []byte { script := TstEnsureUsedAddr(t, p, seriesID, branch, idx) addr, err := p.addressFor(script) if err != nil { t.Fatal(err) } pkScript, err := txscript.PayToAddrScript(addr) if err != nil { t.Fatal(err) } return pkScript }
// addChange adds a new output with the given amount and address, and // randomizes the index (and returns it) of the newly added output. func addChange(msgtx *wire.MsgTx, change btcutil.Amount, changeAddr btcutil.Address) (int, error) { pkScript, err := txscript.PayToAddrScript(changeAddr) if err != nil { return 0, fmt.Errorf("cannot create txout script: %s", err) } msgtx.AddTxOut(wire.NewTxOut(int64(change), pkScript)) // Randomize index of the change output. rng := badrand.New(badrand.NewSource(time.Now().UnixNano())) r := rng.Int31n(int32(len(msgtx.TxOut))) // random index c := len(msgtx.TxOut) - 1 // change index msgtx.TxOut[r], msgtx.TxOut[c] = msgtx.TxOut[c], msgtx.TxOut[r] return int(r), nil }
// finalizeCurrentTx finalizes the transaction in w.current, moves it to the // list of finalized transactions and replaces w.current with a new empty // transaction. func (w *withdrawal) finalizeCurrentTx() error { log.Debug("Finalizing current transaction") tx := w.current if len(tx.outputs) == 0 { log.Debug("Current transaction has no outputs, doing nothing") return nil } pkScript, err := txscript.PayToAddrScript(w.status.nextChangeAddr.addr) if err != nil { return newError(ErrWithdrawalProcessing, "failed to generate pkScript for change address", err) } if tx.addChange(pkScript) { var err error w.status.nextChangeAddr, err = nextChangeAddress(w.status.nextChangeAddr) if err != nil { return newError(ErrWithdrawalProcessing, "failed to get next change address", err) } } ntxid := tx.ntxid() for i, txOut := range tx.outputs { outputStatus := w.status.outputs[txOut.request.outBailmentID()] outputStatus.addOutpoint( OutBailmentOutpoint{ntxid: ntxid, index: uint32(i), amount: txOut.amount}) } // Check that WithdrawalOutput entries with status==success have the sum of // their outpoint amounts matching the requested amount. for _, txOut := range tx.outputs { // Look up the original request we received because txOut.request may // represent a split request and thus have a different amount from the // original one. outputStatus := w.status.outputs[txOut.request.outBailmentID()] origRequest := outputStatus.request amtFulfilled := btcutil.Amount(0) for _, outpoint := range outputStatus.outpoints { amtFulfilled += outpoint.amount } if outputStatus.status == statusSuccess && amtFulfilled != origRequest.Amount { msg := fmt.Sprintf("%s was not completely fulfilled; only %v fulfilled", origRequest, amtFulfilled) return newError(ErrWithdrawalProcessing, msg, nil) } } w.transactions = append(w.transactions, tx) w.current = newWithdrawalTx(w.txOptions) return nil }
func TestSignMultiSigUTXOPkScriptNotP2SH(t *testing.T) { tearDown, pool, _ := TstCreatePoolAndTxStore(t) defer tearDown() mgr := pool.Manager() tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams()) pubKeyHashPkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressPubKeyHash)) msgtx := tx.toMsgTx() err := signMultiSigUTXO(mgr, msgtx, 0, pubKeyHashPkScript, []RawSig{RawSig{}}) TstCheckError(t, "", err, ErrTxSigning) }
func TstNewOutputRequest(t *testing.T, transaction uint32, address string, amount btcutil.Amount, net *chaincfg.Params) OutputRequest { addr, err := btcutil.DecodeAddress(address, net) if err != nil { t.Fatalf("Unable to decode address %s", address) } pkScript, err := txscript.PayToAddrScript(addr) if err != nil { t.Fatalf("Unable to generate pkScript for %v", addr) } return OutputRequest{ PkScript: pkScript, Address: addr, Amount: amount, Server: "server", Transaction: transaction, } }
// createTxOut generates a TxOut that can be added to a transaction. func createTxOut(inCoin int64, addr btcutil.Address) *wire.TxOut { // Pay the minimum network fee so that nodes will broadcast the tx. outCoin := *amount if outCoin == 0 { log.Fatal("You probably don't want to transfer 0 satoshis") } if outCoin > inCoin-TX_FEE { log.Fatal("Can't complete transaction--the request amount" + " is larger than available funds after transaction fee") } // Take the address and generate a PubKeyScript out of it script, err := txscript.PayToAddrScript(addr) if err != nil { log.Fatal(err) } txout := wire.NewTxOut(outCoin, script) return txout }
func (t *TxStore) SignThis(tx *wire.MsgTx) error { fmt.Printf("-= SignThis =-\n") // sort tx before signing. txsort.InPlaceSort(tx) sigs := make([][]byte, len(tx.TxIn)) // first iterate over each input for j, in := range tx.TxIn { for k := uint32(0); k < uint32(len(t.Adrs)); k++ { child, err := t.rootPrivKey.Child(k + hdkeychain.HardenedKeyStart) if err != nil { return err } myadr, err := child.Address(t.Param) if err != nil { return err } adrScript, err := txscript.PayToAddrScript(myadr) if err != nil { return err } if bytes.Equal(adrScript, in.SignatureScript) { fmt.Printf("Hit; key %d matches input %d. Signing.\n", k, j) priv, err := child.ECPrivKey() if err != nil { return err } sigs[j], err = txscript.SignatureScript( tx, j, in.SignatureScript, txscript.SigHashAll, priv, true) if err != nil { return err } break } } } for i, s := range sigs { if s != nil { tx.TxIn[i].SignatureScript = s } } return nil }
// newBobNode generates a test "ln node" to interact with Alice (us). For the // funding transaction, bob has a single output totaling 7BTC. For our basic // test, he'll fund the channel with 5BTC, leaving 2BTC to the change output. // TODO(roasbeef): proper handling of change etc. func newBobNode() (*bobNode, error) { // First, parse Bob's priv key in order to obtain a key he'll use for the // multi-sig funding transaction. privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), bobsPrivKey) // Next, generate an output redeemable by bob. bobAddr, err := btcutil.NewAddressPubKey(privKey.PubKey().SerializeCompressed(), ActiveNetParams) if err != nil { return nil, err } bobAddrScript, err := txscript.PayToAddrScript(bobAddr.AddressPubKeyHash()) if err != nil { return nil, err } prevOut := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0)) // TODO(roasbeef): When the chain rpc is hooked in, assert bob's output // actually exists and it unspent in the chain. bobTxIn := wire.NewTxIn(prevOut, nil) // Using bobs priv key above, create a change address he can spend. bobChangeOutput := wire.NewTxOut(2*1e8, bobAddrScript) // Bob's initial revocation hash is just his private key with the first // byte changed... var revocation [20]byte copy(revocation[:], bobsPrivKey) revocation[0] = 0xff // His ID is just as creative... var id [wire.HashSize]byte id[0] = 0xff return &bobNode{ id: id, privKey: privKey, channelKey: pubKey, deliveryAddress: bobAddr, revocation: revocation, delay: 5, availableOutputs: []*wire.TxIn{bobTxIn}, changeOutputs: []*wire.TxOut{bobChangeOutput}, }, nil }
func TestSignMultiSigUTXORedeemScriptNotFound(t *testing.T) { tearDown, pool, _ := TstCreatePoolAndTxStore(t) defer tearDown() mgr := pool.Manager() tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) // This is a P2SH address for which the addr manager doesn't have the redeem // script. addr, _ := btcutil.DecodeAddress("3Hb4xcebcKg4DiETJfwjh8sF4uDw9rqtVC", mgr.ChainParams()) if _, err := mgr.Address(addr); err == nil { t.Fatalf("Address %s found in manager when it shouldn't", addr) } msgtx := tx.toMsgTx() pkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressScriptHash)) err := signMultiSigUTXO(mgr, msgtx, 0, pkScript, []RawSig{RawSig{}}) TstCheckError(t, "", err, ErrTxSigning) }
func createTxRemainder(inCoin int64) *wire.TxOut { remainder := inCoin - *amount - TX_FEE // Put the remainder back in our wallet pkBytes, err := hex.DecodeString(*privkey) if err != nil { log.Fatal(err) } // Get pubkey object _, pubkey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Get an address object from WIF string changeAddress := generateAddr(pubkey) script, err := txscript.PayToAddrScript(changeAddress) if err != nil { log.Fatal(err) } remtx := wire.NewTxOut(remainder, script) return remtx }
// addOutputs adds the given address/amount pairs as outputs to msgtx, // returning their total amount. func addOutputs(msgtx *wire.MsgTx, pairs map[string]btcutil.Amount, chainParams *chaincfg.Params) (btcutil.Amount, error) { var minAmount btcutil.Amount for addrStr, amt := range pairs { if amt <= 0 { return minAmount, ErrNonPositiveAmount } minAmount += amt addr, err := btcutil.DecodeAddress(addrStr, chainParams) if err != nil { return minAmount, fmt.Errorf("cannot decode address: %s", err) } // Add output to spend amt to addr. pkScript, err := txscript.PayToAddrScript(addr) if err != nil { return minAmount, fmt.Errorf("cannot create txout script: %s", err) } txout := wire.NewTxOut(int64(amt), pkScript) msgtx.AddTxOut(txout) } return minAmount, nil }
func testMemWalletLockedOutputs(r *Harness, t *testing.T) { // Obtain the initial balance of the wallet at this point. startingBalance := r.ConfirmedBalance() // First, create a signed transaction spending some outputs. addr, err := r.NewAddress() if err != nil { t.Fatalf("unable to generate new address: %v", err) } pkScript, err := txscript.PayToAddrScript(addr) if err != nil { t.Fatalf("unable to create script: %v", err) } outputAmt := btcutil.Amount(50 * btcutil.SatoshiPerBitcoin) output := wire.NewTxOut(int64(outputAmt), pkScript) tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) if err != nil { t.Fatalf("unable to create transaction: %v", err) } // The current wallet balance should now be at least 50 BTC less // (accounting for fees) than the period balance currentBalance := r.ConfirmedBalance() if !(currentBalance <= startingBalance-outputAmt) { t.Fatalf("spent outputs not locked: previous balance %v, "+ "current balance %v", startingBalance, currentBalance) } // Now unlocked all the spent inputs within the unbroadcast signed // transaction. The current balance should now be exactly that of the // starting balance. r.UnlockOutputs(tx.TxIn) currentBalance = r.ConfirmedBalance() if currentBalance != startingBalance { t.Fatalf("current and starting balance should now match: "+ "expected %v, got %v", startingBalance, currentBalance) } }
// createCoinbaseTx returns a coinbase transaction paying an appropriate // subsidy based on the passed block height to the provided address. func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address, net *chaincfg.Params) (*btcutil.Tx, error) { // Create the script to pay to the provided payment address. pkScript, err := txscript.PayToAddrScript(addr) if err != nil { return nil, err } tx := wire.NewMsgTx() tx.AddTxIn(&wire.TxIn{ // Coinbase transactions have no inputs, so previous outpoint is // zero hash and max index. PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{}, wire.MaxPrevOutIndex), SignatureScript: coinbaseScript, Sequence: wire.MaxTxInSequenceNum, }) tx.AddTxOut(&wire.TxOut{ Value: blockchain.CalcBlockSubsidy(nextBlockHeight, net), PkScript: pkScript, }) return btcutil.NewTx(tx), nil }
// This example demonstrates manually creating and signing a redeem transaction. func ExampleSignTxOutput() { // Ordinarily the private key would come from whatever storage mechanism // is being used, but for this example just hard code it. privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" + "d4f8720ee63e502ee2869afab7de234b80c") if err != nil { fmt.Println(err) return } privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, &chaincfg.MainNetParams) if err != nil { fmt.Println(err) return } // For this example, create a fake transaction that represents what // would ordinarily be the real transaction that is being spent. It // contains a single output that pays to address in the amount of 1 BTC. originTx := wire.NewMsgTx() prevOut := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0)) txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0}) originTx.AddTxIn(txIn) pkScript, err := txscript.PayToAddrScript(addr) if err != nil { fmt.Println(err) return } txOut := wire.NewTxOut(100000000, pkScript) originTx.AddTxOut(txOut) originTxHash, err := originTx.TxSha() if err != nil { fmt.Println(err) return } // Create the transaction to redeem the fake transaction. redeemTx := wire.NewMsgTx() // Add the input(s) the redeeming transaction will spend. There is no // signature script at this point since it hasn't been created or signed // yet, hence nil is provided for it. prevOut = wire.NewOutPoint(&originTxHash, 0) txIn = wire.NewTxIn(prevOut, nil) redeemTx.AddTxIn(txIn) // Ordinarily this would contain that actual destination of the funds, // but for this example don't bother. txOut = wire.NewTxOut(0, nil) redeemTx.AddTxOut(txOut) // Sign the redeeming transaction. lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, bool, error) { // Ordinarily this function would involve looking up the private // key for the provided address, but since the only thing being // signed in this example uses the address associated with the // private key from above, simply return it with the compressed // flag set since the address is using the associated compressed // public key. // // NOTE: If you want to prove the code is actually signing the // transaction properly, uncomment the following line which // intentionally returns an invalid key to sign with, which in // turn will result in a failure during the script execution // when verifying the signature. // // privKey.D.SetInt64(12345) // return privKey, true, nil } // Notice that the script database parameter is nil here since it isn't // used. It must be specified when pay-to-script-hash transactions are // being signed. sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams, redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll, txscript.KeyClosure(lookupKey), nil, nil) if err != nil { fmt.Println(err) return } redeemTx.TxIn[0].SignatureScript = sigScript // Prove that the transaction has been validly signed by executing the // script pair. flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures | txscript.ScriptStrictMultiSig | txscript.ScriptDiscourageUpgradableNops s, err := txscript.NewScript(redeemTx.TxIn[0].SignatureScript, originTx.TxOut[0].PkScript, 0, redeemTx, flags) if err != nil { fmt.Println(err) return } if err := s.Execute(); err != nil { fmt.Println(err) return } fmt.Println("Transaction successfully signed") // Output: // Transaction successfully signed }
func (s *walletServer) FundTransaction(ctx context.Context, req *pb.FundTransactionRequest) ( *pb.FundTransactionResponse, error) { // TODO: A predicate function for selecting outputs should be created // and passed to a database view of just a particular account's utxos to // prevent reading every unspent transaction output from every account // into memory at once. syncBlock := s.wallet.Manager.SyncedTo() outputs, err := s.wallet.TxStore.UnspentOutputs() if err != nil { return nil, translateError(err) } selectedOutputs := make([]*pb.FundTransactionResponse_PreviousOutput, 0, len(outputs)) var totalAmount btcutil.Amount for i := range outputs { output := &outputs[i] if !confirmed(req.RequiredConfirmations, output.Height, syncBlock.Height) { continue } target := int32(s.wallet.ChainParams().CoinbaseMaturity) if !req.IncludeImmatureCoinbases && output.FromCoinBase && !confirmed(target, output.Height, syncBlock.Height) { continue } _, addrs, _, err := txscript.ExtractPkScriptAddrs( output.PkScript, s.wallet.ChainParams()) if err != nil || len(addrs) == 0 { // Cannot determine which account this belongs to // without a valid address. Fix this by saving // outputs per account (per-account wtxmgr). continue } outputAcct, err := s.wallet.Manager.AddrAccount(addrs[0]) if err != nil { return nil, translateError(err) } if outputAcct != req.Account { continue } selectedOutputs = append(selectedOutputs, &pb.FundTransactionResponse_PreviousOutput{ TransactionHash: output.OutPoint.Hash[:], OutputIndex: output.Index, Amount: int64(output.Amount), PkScript: output.PkScript, ReceiveTime: output.Received.Unix(), FromCoinbase: output.FromCoinBase, }) totalAmount += output.Amount if req.TargetAmount != 0 && totalAmount > btcutil.Amount(req.TargetAmount) { break } } var changeScript []byte if req.IncludeChangeScript && totalAmount > btcutil.Amount(req.TargetAmount) { changeAddr, err := s.wallet.NewChangeAddress(req.Account) if err != nil { return nil, translateError(err) } changeScript, err = txscript.PayToAddrScript(changeAddr) if err != nil { return nil, translateError(err) } } return &pb.FundTransactionResponse{ SelectedOutputs: selectedOutputs, TotalAmount: int64(totalAmount), ChangePkScript: changeScript, }, nil }
// SendCoins does send coins, but it's very rudimentary func SendCoins(s uspv.SPVCon, adr btcutil.Address, sendAmt int64) error { var err error var score int64 allUtxos, err := s.TS.GetAllUtxos() if err != nil { return err } for _, utxo := range allUtxos { score += utxo.Value } // important rule in bitcoin, output total > input total is invalid. if sendAmt > score { return fmt.Errorf("trying to send %d but %d available.", sendAmt, score) } tx := wire.NewMsgTx() // make new tx // make address script 76a914...88ac adrScript, err := txscript.PayToAddrScript(adr) if err != nil { return err } // make user specified txout and add to tx txout := wire.NewTxOut(sendAmt, adrScript) tx.AddTxOut(txout) nokori := sendAmt // nokori is how much is needed on input side for _, utxo := range allUtxos { // generate pkscript to sign prevPKscript, err := txscript.PayToAddrScript( s.TS.Adrs[utxo.KeyIdx].PkhAdr) if err != nil { return err } // make new input from this utxo thisInput := wire.NewTxIn(&utxo.Op, prevPKscript) tx.AddTxIn(thisInput) nokori -= utxo.Value if nokori < -10000 { // minimum overage / fee is 1K now break } } // there's enough left to make a change output if nokori < -200000 { change, err := s.TS.NewAdr() if err != nil { return err } changeScript, err := txscript.PayToAddrScript(change) if err != nil { return err } changeOut := wire.NewTxOut((-100000)-nokori, changeScript) tx.AddTxOut(changeOut) } // use txstore method to sign err = s.TS.SignThis(tx) if err != nil { return err } fmt.Printf("tx: %s", uspv.TxToString(tx)) buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) tx.Serialize(buf) fmt.Printf("tx: %x\n", buf.Bytes()) // send it out on the wire. hope it gets there. // we should deal with rejects. Don't yet. err = s.NewOutgoingTx(tx) if err != nil { return err } return nil }
func TestSignTxOutput(t *testing.T) { t.Parallel() // make key // make script based on key. // sign with magic pixie dust. hashTypes := []txscript.SigHashType{ txscript.SigHashOld, // no longer used but should act like all txscript.SigHashAll, txscript.SigHashNone, txscript.SigHashSingle, txscript.SigHashAll | txscript.SigHashAnyOneCanPay, txscript.SigHashNone | txscript.SigHashAnyOneCanPay, txscript.SigHashSingle | txscript.SigHashAnyOneCanPay, } tx := &wire.MsgTx{ Version: 1, TxIn: []*wire.TxIn{ { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 0, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 1, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 2, }, Sequence: 4294967295, }, }, TxOut: []*wire.TxOut{ { Value: 1, }, { Value: 2, }, { Value: 3, }, }, LockTime: 0, } // Pay to Pubkey Hash (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (uncompressed) (merging with correct) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to Pubkey Hash (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, pkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // As before, but with p2sh now. // Pay to Pubkey Hash (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) break } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (uncompressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) break } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to Pubkey Hash (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to Pubkey Hash (compressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKeyHash( btcutil.Hash160(pk), &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (uncompressed) with duplicate merge for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeUncompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, false}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Pay to PubKey (compressed) for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk := (*btcec.PublicKey)(&key.PublicKey). SerializeCompressed() address, err := btcutil.NewAddressPubKey(pk, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } pkScript, err := txscript.PayToAddrScript(address) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // by the above loop, this should be valid, now sign // again and merge. sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address.EncodeAddress(): {key, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("twice signed script invalid for "+ "%s: %v", msg, err) break } } } // Basic Multisig for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil); err != nil { t.Error(err) break } } } // Two part multisig, sign with one key then the other. for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Only 1 out of 2 signed, this *should* fail. if checkScripts(msg, tx, i, sigScript, scriptPkScript) == nil { t.Errorf("part signed script valid for %s", msg) break } // Sign with the other key and merge sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), sigScript) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("fully signed script invalid for "+ "%s: %v", msg, err) break } } } // Two part multisig, sign with one key then both, check key dedup // correctly. for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) key1, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey for %s: %v", msg, err) break } pk1 := (*btcec.PublicKey)(&key1.PublicKey). SerializeCompressed() address1, err := btcutil.NewAddressPubKey(pk1, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } key2, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { t.Errorf("failed to make privKey 2 for %s: %v", msg, err) break } pk2 := (*btcec.PublicKey)(&key2.PublicKey). SerializeCompressed() address2, err := btcutil.NewAddressPubKey(pk2, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := txscript.MultiSigScript( []*btcutil.AddressPubKey{address1, address2}, 2) if err != nil { t.Errorf("failed to make pkscript "+ "for %s: %v", msg, err) } scriptAddr, err := btcutil.NewAddressScriptHash( pkScript, &chaincfg.TestNet3Params) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } scriptPkScript, err := txscript.PayToAddrScript( scriptAddr) if err != nil { t.Errorf("failed to make script pkscript for "+ "%s: %v", msg, err) break } sigScript, err := txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Only 1 out of 2 signed, this *should* fail. if checkScripts(msg, tx, i, sigScript, scriptPkScript) == nil { t.Errorf("part signed script valid for %s", msg) break } // Sign with the other key and merge sigScript, err = txscript.SignTxOutput( &chaincfg.TestNet3Params, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ address1.EncodeAddress(): {key1, true}, address2.EncodeAddress(): {key2, true}, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): pkScript, }), sigScript) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) break } // Now we should pass. err = checkScripts(msg, tx, i, sigScript, scriptPkScript) if err != nil { t.Errorf("fully signed script invalid for "+ "%s: %v", msg, err) break } } } }
// TestPayToAddrScript ensures the PayToAddrScript function generates the // correct scripts for the various types of addresses. func TestPayToAddrScript(t *testing.T) { t.Parallel() // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX p2pkhMain, err := btcutil.NewAddressPubKeyHash(decodeHex("e34cce70c863"+ "73273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create public key hash address: %v", err) return } // Taken from transaction: // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d p2shMain, _ := btcutil.NewAddressScriptHashFromHash(decodeHex("e8c300"+ "c87986efa84c37c0519929019ef86eb5b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create script hash address: %v", err) return } // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg p2pkCompressedMain, err := btcutil.NewAddressPubKey(decodeHex("02192d74"+ "d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed): %v", err) return } p2pkCompressed2Main, err := btcutil.NewAddressPubKey(decodeHex("03b0bd"+ "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed 2): %v", err) return } p2pkUncompressedMain, err := btcutil.NewAddressPubKey(decodeHex("0411db"+ "93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2"+ "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (uncompressed): %v", err) return } tests := []struct { in btcutil.Address expected string err error }{ // pay-to-pubkey-hash address on mainnet { p2pkhMain, "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + "91bb4a0e8488 CHECKSIG", nil, }, // pay-to-script-hash address on mainnet { p2shMain, "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + "6eb5b4 EQUAL", nil, }, // pay-to-pubkey address on mainnet. compressed key. { p2pkCompressedMain, "DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c3" + "ebec3a957724895dca52c6b4 CHECKSIG", nil, }, // pay-to-pubkey address on mainnet. compressed key (other way). { p2pkCompressed2Main, "DATA_33 0x03b0bd634234abbb1ba1e986e884185c61cf43e001" + "f9137f23c2c409273eb16e65 CHECKSIG", nil, }, // pay-to-pubkey address on mainnet. uncompressed key. { p2pkUncompressedMain, "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" + "97b1482ecad7b148a6909a5cb2e0eaddfb84ccf97444" + "64f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 " + "CHECKSIG", nil, }, // Supported address types with nil pointers. {(*btcutil.AddressPubKeyHash)(nil), "", txscript.ErrUnsupportedAddress}, {(*btcutil.AddressScriptHash)(nil), "", txscript.ErrUnsupportedAddress}, {(*btcutil.AddressPubKey)(nil), "", txscript.ErrUnsupportedAddress}, // Unsupported address type. {&bogusAddress{}, "", txscript.ErrUnsupportedAddress}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { pkScript, err := txscript.PayToAddrScript(test.in) if err != test.err { t.Errorf("PayToAddrScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue } expected := mustParseShortForm(test.expected) if !bytes.Equal(pkScript, expected) { t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", i, pkScript, expected) continue } } }
// This example demonstrates how to use the Pool.StartWithdrawal method. func Example_startWithdrawal() { // Create the address manager and votingpool DB namespace. See the example // for the Create() function for more info on how this is done. mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace() if err != nil { fmt.Println(err) return } defer tearDownFunc() // Create a pool and a series. See the DepositAddress example for more info // on how this is done. pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace) if err != nil { fmt.Println(err) return } // Unlock the manager if err := mgr.Unlock(privPassphrase); err != nil { fmt.Println(err) return } defer mgr.Lock() addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams()) pkScript, _ := txscript.PayToAddrScript(addr) requests := []votingpool.OutputRequest{ votingpool.OutputRequest{ PkScript: pkScript, Address: addr, Amount: 1e6, Server: "server-id", Transaction: 123}, } changeStart, err := pool.ChangeAddress(seriesID, votingpool.Index(0)) if err != nil { fmt.Println(err) return } // This is only needed because we have not used any deposit addresses from // the series, and we cannot create a WithdrawalAddress for an unused // branch/idx pair. if err = pool.EnsureUsedAddr(seriesID, votingpool.Branch(1), votingpool.Index(0)); err != nil { fmt.Println(err) return } startAddr, err := pool.WithdrawalAddress(seriesID, votingpool.Branch(1), votingpool.Index(0)) if err != nil { fmt.Println(err) return } lastSeriesID := seriesID dustThreshold := btcutil.Amount(1e4) currentBlock := int32(19432) roundID := uint32(0) txstore, tearDownFunc, err := exampleCreateTxStore() if err != nil { fmt.Println(err) return } _, err = pool.StartWithdrawal( roundID, requests, *startAddr, lastSeriesID, *changeStart, txstore, currentBlock, dustThreshold) if err != nil { fmt.Println(err) } // Output: // }
func loadTestCredits(w *LightningWallet, numOutputs, btcPerOutput int) error { // Import the priv key (converting to WIF) above that controls all our // available outputs. privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), testWalletPrivKey) if err := w.Unlock(privPass, time.Duration(0)); err != nil { return err } bs := &waddrmgr.BlockStamp{Hash: *genBlockHash(1), Height: 1} wif, err := btcutil.NewWIF(privKey, ActiveNetParams, true) if err != nil { return err } if _, err := w.ImportPrivateKey(wif, bs, false); err != nil { return nil } if err := w.Manager.SetSyncedTo(&waddrmgr.BlockStamp{int32(1), *genBlockHash(1)}); err != nil { return err } blk := wtxmgr.BlockMeta{wtxmgr.Block{Hash: *genBlockHash(2), Height: 2}, time.Now()} // Create a simple P2PKH pubkey script spendable by Alice. For simplicity // all of Alice's spendable funds will reside in this output. satosihPerOutput := int64(btcPerOutput * 1e8) walletAddr, err := btcutil.NewAddressPubKey(privKey.PubKey().SerializeCompressed(), ActiveNetParams) if err != nil { return err } walletScriptCredit, err := txscript.PayToAddrScript(walletAddr.AddressPubKeyHash()) if err != nil { return err } // Create numOutputs outputs spendable by our wallet each holding btcPerOutput // in satoshis. tx := wire.NewMsgTx() prevOut := wire.NewOutPoint(genBlockHash(999), 1) txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0}) tx.AddTxIn(txIn) for i := 0; i < numOutputs; i++ { tx.AddTxOut(wire.NewTxOut(satosihPerOutput, walletScriptCredit)) } txCredit, err := wtxmgr.NewTxRecordFromMsgTx(tx, time.Now()) if err != nil { return err } if err := addTestTx(w, txCredit, &blk); err != nil { return err } if err := w.Manager.SetSyncedTo(&waddrmgr.BlockStamp{int32(2), *genBlockHash(2)}); err != nil { return err } // Make the wallet think it's been synced to block 10. This way the // outputs we added above will have sufficient confirmations // (hard coded to 6 atm). for i := 3; i < 10; i++ { sha := *genBlockHash(i) if err := w.Manager.SetSyncedTo(&waddrmgr.BlockStamp{int32(i), sha}); err != nil { return err } } return nil }
func TestLimitAndSkipFetchTxsForAddr(t *testing.T) { testDb, err := setUpTestDb(t, "tstdbtxaddr") if err != nil { t.Errorf("Failed to open test database %v", err) return } defer testDb.cleanUpFunc() // Insert a block with some fake test transactions. The block will have // 10 copies of a fake transaction involving same address. addrString := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" targetAddr, err := btcutil.DecodeAddress(addrString, &chaincfg.MainNetParams) if err != nil { t.Fatalf("Unable to decode test address: %v", err) } outputScript, err := txscript.PayToAddrScript(targetAddr) if err != nil { t.Fatalf("Unable make test pkScript %v", err) } fakeTxOut := wire.NewTxOut(10, outputScript) var emptyHash wire.ShaHash fakeHeader := wire.NewBlockHeader(&emptyHash, &emptyHash, 1, 1) msgBlock := wire.NewMsgBlock(fakeHeader) for i := 0; i < 10; i++ { mtx := wire.NewMsgTx() mtx.AddTxOut(fakeTxOut) msgBlock.AddTransaction(mtx) } // Insert the test block into the DB. testBlock := btcutil.NewBlock(msgBlock) newheight, err := testDb.db.InsertBlock(testBlock) if err != nil { t.Fatalf("Unable to insert block into db: %v", err) } // Create and insert an address index for out test addr. txLoc, _ := testBlock.TxLoc() index := make(database.BlockAddrIndex) for i := range testBlock.Transactions() { var hash160 [ripemd160.Size]byte scriptAddr := targetAddr.ScriptAddress() copy(hash160[:], scriptAddr[:]) index[hash160] = append(index[hash160], &txLoc[i]) } blkSha := testBlock.Sha() err = testDb.db.UpdateAddrIndexForBlock(blkSha, newheight, index) if err != nil { t.Fatalf("UpdateAddrIndexForBlock: failed to index"+ " addrs for block #%d (%s) "+ "err %v", newheight, blkSha, err) return } // Try skipping the first 4 results, should get 6 in return. txReply, err := testDb.db.FetchTxsForAddr(targetAddr, 4, 100000) if err != nil { t.Fatalf("Unable to fetch transactions for address: %v", err) } if len(txReply) != 6 { t.Fatalf("Did not correctly skip forward in txs for address reply"+ " got %v txs, expected %v", len(txReply), 6) } // Limit the number of results to 3. txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 0, 3) if err != nil { t.Fatalf("Unable to fetch transactions for address: %v", err) } if len(txReply) != 3 { t.Fatalf("Did not correctly limit in txs for address reply"+ " got %v txs, expected %v", len(txReply), 3) } // Skip 1, limit 5. txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 1, 5) if err != nil { t.Fatalf("Unable to fetch transactions for address: %v", err) } if len(txReply) != 5 { t.Fatalf("Did not correctly limit in txs for address reply"+ " got %v txs, expected %v", len(txReply), 5) } }