more stress testing stuff

This commit is contained in:
Tadge Dryja 2016-02-24 17:27:29 -08:00
parent df04a73e1a
commit f9a740d392
4 changed files with 189 additions and 30 deletions

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"sort"
"strconv" "strconv"
"strings" "strings"
@ -147,6 +148,13 @@ func Shellparse(cmdslice []string) error {
} }
return nil return nil
} }
if cmd == "sweep" {
err = Sweep(args)
if err != nil {
fmt.Printf("sweep error: %s\n", err)
}
return nil
}
if cmd == "txs" { if cmd == "txs" {
err = Txs(args) err = Txs(args)
if err != nil { if err != nil {
@ -202,10 +210,17 @@ func Bal(args []string) error {
return fmt.Errorf("Can't get balance, spv connection broken") return fmt.Errorf("Can't get balance, spv connection broken")
} }
fmt.Printf(" ----- Account Balance ----- \n") fmt.Printf(" ----- Account Balance ----- \n")
allUtxos, err := SCon.TS.GetAllUtxos() rawUtxos, err := SCon.TS.GetAllUtxos()
if err != nil { if err != nil {
return err return err
} }
var allUtxos uspv.SortableUtxoSlice
for _, utxo := range rawUtxos {
allUtxos = append(allUtxos, *utxo)
}
// smallest and unconfirmed last (because it's reversed)
sort.Sort(sort.Reverse(allUtxos))
var score, confScore int64 var score, confScore int64
for i, u := range allUtxos { for i, u := range allUtxos {
fmt.Printf("\tutxo %d height %d %s key:%d amt %d", fmt.Printf("\tutxo %d height %d %s key:%d amt %d",
@ -221,6 +236,10 @@ func Bal(args []string) error {
} }
height, _ := SCon.TS.GetDBSyncHeight() height, _ := SCon.TS.GetDBSyncHeight()
atx, err := SCon.TS.GetAllTxs()
stxos, err := SCon.TS.GetAllStxos()
for i, a := range SCon.TS.Adrs { for i, a := range SCon.TS.Adrs {
wa, err := btcutil.NewAddressWitnessPubKeyHash( wa, err := btcutil.NewAddressWitnessPubKeyHash(
a.PkhAdr.ScriptAddress(), Params) a.PkhAdr.ScriptAddress(), Params)
@ -229,8 +248,9 @@ func Bal(args []string) error {
} }
fmt.Printf("address %d %s OR %s\n", i, a.PkhAdr.String(), wa.String()) fmt.Printf("address %d %s OR %s\n", i, a.PkhAdr.String(), wa.String())
} }
fmt.Printf("Total known txs: %d\n", len(atx))
fmt.Printf("Total known utxos: %d\n", len(allUtxos)) fmt.Printf("Known utxos: %d\tPreviously spent txos: %d\n",
len(allUtxos), len(stxos))
fmt.Printf("Total coin: %d confirmed: %d\n", score, confScore) fmt.Printf("Total coin: %d confirmed: %d\n", score, confScore)
fmt.Printf("DB sync height: %d\n", height) fmt.Printf("DB sync height: %d\n", height)
return nil return nil
@ -268,13 +288,62 @@ func Adr(args []string) error {
return nil return nil
} }
// Sweep sends every confirmed uxto in your wallet to an address.
// it does them all individually to there are a lot of txs generated.
// syntax: sweep adr
func Sweep(args []string) error {
if len(args) < 2 {
return fmt.Errorf("sweep syntax: sweep adr")
}
adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param)
if err != nil {
fmt.Printf("error parsing %s as address\t", args[0])
return err
}
numTxs, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return err
}
if numTxs < 1 {
return fmt.Errorf("can't send %d txs", numTxs)
}
rawUtxos, err := SCon.TS.GetAllUtxos()
if err != nil {
return err
}
var allUtxos uspv.SortableUtxoSlice
for _, utxo := range rawUtxos {
allUtxos = append(allUtxos, *utxo)
}
// smallest and unconfirmed last (because it's reversed)
sort.Sort(sort.Reverse(allUtxos))
for i, u := range allUtxos {
if u.AtHeight != 0 {
err = SCon.SendOne(allUtxos[i], adr)
if err != nil {
return err
}
numTxs--
if numTxs == 0 {
return nil
}
}
}
fmt.Printf("spent all confirmed utxos; not enough by %d\n", numTxs)
return nil
}
// Fan generates a bunch of fanout. Only for testing, can be expensive. // Fan generates a bunch of fanout. Only for testing, can be expensive.
// syntax: fan adr numOutputs valOutputs witty // syntax: fan adr numOutputs valOutputs witty
func Fan(args []string) error { func Fan(args []string) error {
if len(args) < 3 { if len(args) < 3 {
return fmt.Errorf("fan syntax: fan adr numOutputs valOutputs") return fmt.Errorf("fan syntax: fan adr numOutputs valOutputs")
} }
adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param) adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param)
if err != nil { if err != nil {
fmt.Printf("error parsing %s as address\t", args[0]) fmt.Printf("error parsing %s as address\t", args[0])
@ -296,9 +365,7 @@ func Fan(args []string) error {
adrs[i] = adr adrs[i] = adr
amts[i] = valOutputs + i amts[i] = valOutputs + i
} }
return SCon.SendCoins(adrs, amts) return SCon.SendCoins(adrs, amts)
} }
// Send sends coins. // Send sends coins.

@ -189,7 +189,6 @@ func (s *SPVCon) GetDataHandler(m *wire.MsgGetData) {
log.Printf("error getting tx %s: %s", log.Printf("error getting tx %s: %s",
thing.Hash.String(), err.Error()) thing.Hash.String(), err.Error())
} }
fmt.Printf(TxToString(tx))
s.outMsgQueue <- tx s.outMsgQueue <- tx
sent++ sent++
continue continue

@ -68,12 +68,22 @@ func (s utxoSlice) Less(i, j int) bool {
return bytes.Compare(ihash[:], jhash[:]) == -1 return bytes.Compare(ihash[:], jhash[:]) == -1
} }
type utxoByAmt []Utxo type SortableUtxoSlice []Utxo
// utxoByAmts get sorted by utxo value // utxoByAmts get sorted by utxo value. also put unconfirmed last
func (s utxoByAmt) Len() int { return len(s) } func (s SortableUtxoSlice) Len() int { return len(s) }
func (s utxoByAmt) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s SortableUtxoSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s utxoByAmt) Less(i, j int) bool { return s[i].Value < s[j].Value }
// height 0 means your lesser
func (s SortableUtxoSlice) Less(i, j int) bool {
if s[i].AtHeight == 0 {
return true
}
if s[j].AtHeight == 0 {
return false
}
return s[i].Value < s[j].Value
}
func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error { func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error {
txid := tx.TxSha() txid := tx.TxSha()
@ -97,6 +107,84 @@ func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error {
return nil return nil
} }
func (s *SPVCon) SendOne(u Utxo, adr btcutil.Address) error {
// fixed fee
fee := int64(5000)
sendAmt := u.Value - fee
tx := wire.NewMsgTx() // make new tx
// add single output
outAdrScript, err := txscript.PayToAddrScript(adr)
if err != nil {
return err
}
// make user specified txout and add to tx
txout := wire.NewTxOut(sendAmt, outAdrScript)
tx.AddTxOut(txout)
var prevPKs []byte
if u.IsWit {
tx.Flags = 0x01
wa, err := btcutil.NewAddressWitnessPubKeyHash(
s.TS.Adrs[u.KeyIdx].PkhAdr.ScriptAddress(), s.TS.Param)
prevPKs, err = txscript.PayToAddrScript(wa)
if err != nil {
return err
}
} else { // otherwise generate directly
prevPKs, err = txscript.PayToAddrScript(
s.TS.Adrs[u.KeyIdx].PkhAdr)
if err != nil {
return err
}
}
tx.AddTxIn(wire.NewTxIn(&u.Op, prevPKs, nil))
var sig []byte
var wit [][]byte
hCache := txscript.CalcHashCache(tx, 0, txscript.SigHashAll)
child, err := s.TS.rootPrivKey.Child(u.KeyIdx + hdkeychain.HardenedKeyStart)
if err != nil {
return err
}
priv, err := child.ECPrivKey()
if err != nil {
return err
}
// This is where witness based sighash types need to happen
// sign into stash
if u.IsWit {
wit, err = txscript.WitnessScript(
tx, hCache, 0, u.Value, tx.TxIn[0].SignatureScript,
txscript.SigHashAll, priv, true)
if err != nil {
return err
}
} else {
sig, err = txscript.SignatureScript(
tx, 0, tx.TxIn[0].SignatureScript,
txscript.SigHashAll, priv, true)
if err != nil {
return err
}
}
// swap sigs into sigScripts in txins
if sig != nil {
tx.TxIn[0].SignatureScript = sig
}
if wit != nil {
tx.TxIn[0].Witness = wit
tx.TxIn[0].SignatureScript = nil
}
return s.NewOutgoingTx(tx)
}
// SendCoins does send coins, but it's very rudimentary // SendCoins does send coins, but it's very rudimentary
// wit makes it into p2wpkh. Which is not yet spendable. // wit makes it into p2wpkh. Which is not yet spendable.
func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error { func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
@ -111,18 +199,17 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
if err != nil { if err != nil {
return err return err
} }
var allUtxos utxoByAmt var allUtxos SortableUtxoSlice
// start with utxos sorted by value. // start with utxos sorted by value.
for _, utxo := range rawUtxos { for _, utxo := range rawUtxos {
score += utxo.Value score += utxo.Value
allUtxos = append(allUtxos, *utxo) allUtxos = append(allUtxos, *utxo)
} }
// smallest and unconfirmed last (because it's reversed)
sort.Sort(sort.Reverse(allUtxos)) sort.Sort(sort.Reverse(allUtxos))
// sort.Reverse(allUtxos) // sort.Reverse(allUtxos)
for _, u := range allUtxos {
fmt.Printf("%d ", u.Value)
}
for _, amt := range sendAmts { for _, amt := range sendAmts {
totalSend += amt totalSend += amt
} }
@ -272,10 +359,8 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
} }
fmt.Printf("tx: %s", TxToString(tx)) // fmt.Printf("tx: %s", TxToString(tx))
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) // buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
tx.SerializeWitness(buf)
fmt.Printf("tx: %x\n", buf.Bytes())
// send it out on the wire. hope it gets there. // send it out on the wire. hope it gets there.
// we should deal with rejects. Don't yet. // we should deal with rejects. Don't yet.

@ -373,8 +373,14 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
return hits, err return hits, err
} }
} }
// also generate PKscripts for all addresses (maybe keep storing these?)
for _, adr := range ts.Adrs { // go through txouts, and then go through addresses to match
// generate PKscripts for all addresses
wPKscripts := make([][]byte, len(ts.Adrs))
aPKscripts := make([][]byte, len(ts.Adrs))
for i, adr := range ts.Adrs {
// iterate through all our addresses // iterate through all our addresses
// convert regular address to witness address. (split adrs later) // convert regular address to witness address. (split adrs later)
wa, err := btcutil.NewAddressWitnessPubKeyHash( wa, err := btcutil.NewAddressWitnessPubKeyHash(
@ -383,28 +389,30 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
return hits, err return hits, err
} }
wPKscript, err := txscript.PayToAddrScript(wa) wPKscripts[i], err = txscript.PayToAddrScript(wa)
if err != nil { if err != nil {
return hits, err return hits, err
} }
aPKscript, err := txscript.PayToAddrScript(adr.PkhAdr) aPKscripts[i], err = txscript.PayToAddrScript(adr.PkhAdr)
if err != nil { if err != nil {
return hits, err return hits, err
} }
}
// iterate through all outputs of this tx, see if we gain // iterate through all outputs of this tx, see if we gain
for i, out := range tx.TxOut { for i, out := range tx.TxOut {
for j, ascr := range aPKscripts {
// detect p2wpkh // detect p2wpkh
witBool := false witBool := false
if bytes.Equal(out.PkScript, wPKscript) { if bytes.Equal(out.PkScript, wPKscripts[j]) {
witBool = true witBool = true
} }
if bytes.Equal(out.PkScript, aPKscript) || witBool { // new utxo found if bytes.Equal(out.PkScript, ascr) || witBool { // new utxo found
var newu Utxo // create new utxo and copy into it var newu Utxo // create new utxo and copy into it
newu.AtHeight = height newu.AtHeight = height
newu.KeyIdx = adr.KeyIdx newu.KeyIdx = ts.Adrs[j].KeyIdx
newu.Value = out.Value newu.Value = out.Value
newu.IsWit = witBool // copy witness version from pkscript newu.IsWit = witBool // copy witness version from pkscript
var newop wire.OutPoint var newop wire.OutPoint
@ -417,7 +425,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
} }
nUtxoBytes = append(nUtxoBytes, b) nUtxoBytes = append(nUtxoBytes, b)
hits++ hits++
// break // keep looking! address re-use in same tx break // txos can match only 1 script
} }
} }
} }