2016-01-23 03:04:27 +03:00
|
|
|
package uspv
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2016-02-05 12:16:45 +03:00
|
|
|
"log"
|
2016-01-23 03:04:27 +03:00
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
2016-02-18 10:16:17 +03:00
|
|
|
"github.com/btcsuite/btcutil"
|
2016-02-05 12:16:45 +03:00
|
|
|
"github.com/btcsuite/btcutil/bloom"
|
2016-01-23 03:04:27 +03:00
|
|
|
"github.com/btcsuite/btcutil/hdkeychain"
|
|
|
|
"github.com/btcsuite/btcutil/txsort"
|
|
|
|
)
|
|
|
|
|
2016-02-05 12:16:45 +03:00
|
|
|
func (s *SPVCon) PongBack(nonce uint64) {
|
|
|
|
mpong := wire.NewMsgPong(nonce)
|
|
|
|
|
|
|
|
s.outMsgQueue <- mpong
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SPVCon) SendFilter(f *bloom.Filter) {
|
|
|
|
s.outMsgQueue <- f.MsgFilterLoad()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rebroadcast sends an inv message of all the unconfirmed txs the db is
|
|
|
|
// aware of. This is called after every sync. Only txids so hopefully not
|
|
|
|
// too annoying for nodes.
|
|
|
|
func (s *SPVCon) Rebroadcast() {
|
|
|
|
// get all unconfirmed txs
|
|
|
|
invMsg, err := s.TS.GetPendingInv()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Rebroadcast error: %s", err.Error())
|
|
|
|
}
|
|
|
|
if len(invMsg.InvList) == 0 { // nothing to broadcast, so don't
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.outMsgQueue <- invMsg
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-02-18 10:16:17 +03:00
|
|
|
func P2wpkhScript(adr btcutil.Address) ([]byte, error) {
|
|
|
|
switch adr := adr.(type) {
|
|
|
|
case *btcutil.AddressPubKeyHash:
|
|
|
|
sb := txscript.NewScriptBuilder()
|
|
|
|
sb.AddOp(txscript.OP_0)
|
|
|
|
sb.AddData(adr.ScriptAddress())
|
|
|
|
return sb.Script()
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("%s is not pkh address", adr.String())
|
|
|
|
}
|
|
|
|
|
2016-02-05 12:16:45 +03:00
|
|
|
func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error {
|
|
|
|
txid := tx.TxSha()
|
|
|
|
// assign height of zero for txs we create
|
|
|
|
err := s.TS.AddTxid(&txid, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = s.TS.Ingest(tx, 0) // our own tx; don't keep track of false positives
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// make an inv message instead of a tx message to be polite
|
2016-02-18 10:16:17 +03:00
|
|
|
iv1 := wire.NewInvVect(wire.InvTypeWitnessTx, &txid)
|
2016-02-05 12:16:45 +03:00
|
|
|
invMsg := wire.NewMsgInv()
|
|
|
|
err = invMsg.AddInvVect(iv1)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.outMsgQueue <- invMsg
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-01-23 03:04:27 +03:00
|
|
|
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
|
|
|
|
}
|