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"
"log"
"os"
"sort"
"strconv"
"strings"
@ -147,6 +148,13 @@ func Shellparse(cmdslice []string) error {
}
return nil
}
if cmd == "sweep" {
err = Sweep(args)
if err != nil {
fmt.Printf("sweep error: %s\n", err)
}
return nil
}
if cmd == "txs" {
err = Txs(args)
if err != nil {
@ -202,10 +210,17 @@ func Bal(args []string) error {
return fmt.Errorf("Can't get balance, spv connection broken")
}
fmt.Printf(" ----- Account Balance ----- \n")
allUtxos, err := SCon.TS.GetAllUtxos()
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))
var score, confScore int64
for i, u := range allUtxos {
fmt.Printf("\tutxo %d height %d %s key:%d amt %d",
@ -221,6 +236,10 @@ func Bal(args []string) error {
}
height, _ := SCon.TS.GetDBSyncHeight()
atx, err := SCon.TS.GetAllTxs()
stxos, err := SCon.TS.GetAllStxos()
for i, a := range SCon.TS.Adrs {
wa, err := btcutil.NewAddressWitnessPubKeyHash(
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("Total known utxos: %d\n", len(allUtxos))
fmt.Printf("Total known txs: %d\n", len(atx))
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("DB sync height: %d\n", height)
return nil
@ -268,13 +288,62 @@ func Adr(args []string) error {
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.
// syntax: fan adr numOutputs valOutputs witty
func Fan(args []string) error {
if len(args) < 3 {
return fmt.Errorf("fan syntax: fan adr numOutputs valOutputs")
}
adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param)
if err != nil {
fmt.Printf("error parsing %s as address\t", args[0])
@ -296,9 +365,7 @@ func Fan(args []string) error {
adrs[i] = adr
amts[i] = valOutputs + i
}
return SCon.SendCoins(adrs, amts)
}
// Send sends coins.

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

@ -68,12 +68,22 @@ func (s utxoSlice) Less(i, j int) bool {
return bytes.Compare(ihash[:], jhash[:]) == -1
}
type utxoByAmt []Utxo
type SortableUtxoSlice []Utxo
// utxoByAmts get sorted by utxo value
func (s utxoByAmt) Len() int { return len(s) }
func (s utxoByAmt) 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 }
// utxoByAmts get sorted by utxo value. also put unconfirmed last
func (s SortableUtxoSlice) Len() int { return len(s) }
func (s SortableUtxoSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// 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 {
txid := tx.TxSha()
@ -97,6 +107,84 @@ func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error {
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
// wit makes it into p2wpkh. Which is not yet spendable.
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 {
return err
}
var allUtxos utxoByAmt
var allUtxos SortableUtxoSlice
// start with utxos sorted by value.
for _, utxo := range rawUtxos {
score += utxo.Value
allUtxos = append(allUtxos, *utxo)
}
// smallest and unconfirmed last (because it's reversed)
sort.Sort(sort.Reverse(allUtxos))
// sort.Reverse(allUtxos)
for _, u := range allUtxos {
fmt.Printf("%d ", u.Value)
}
for _, amt := range sendAmts {
totalSend += amt
}
@ -272,10 +359,8 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
}
fmt.Printf("tx: %s", TxToString(tx))
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
tx.SerializeWitness(buf)
fmt.Printf("tx: %x\n", buf.Bytes())
// fmt.Printf("tx: %s", TxToString(tx))
// buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
// send it out on the wire. hope it gets there.
// 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
}
}
// 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
// convert regular address to witness address. (split adrs later)
wa, err := btcutil.NewAddressWitnessPubKeyHash(
@ -383,28 +389,30 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
return hits, err
}
wPKscript, err := txscript.PayToAddrScript(wa)
wPKscripts[i], err = txscript.PayToAddrScript(wa)
if err != nil {
return hits, err
}
aPKscript, err := txscript.PayToAddrScript(adr.PkhAdr)
aPKscripts[i], err = txscript.PayToAddrScript(adr.PkhAdr)
if err != nil {
return hits, err
}
}
// iterate through all outputs of this tx, see if we gain
for i, out := range tx.TxOut {
for j, ascr := range aPKscripts {
// detect p2wpkh
witBool := false
if bytes.Equal(out.PkScript, wPKscript) {
if bytes.Equal(out.PkScript, wPKscripts[j]) {
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
newu.AtHeight = height
newu.KeyIdx = adr.KeyIdx
newu.KeyIdx = ts.Adrs[j].KeyIdx
newu.Value = out.Value
newu.IsWit = witBool // copy witness version from pkscript
var newop wire.OutPoint
@ -417,7 +425,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
}
nUtxoBytes = append(nUtxoBytes, b)
hits++
// break // keep looking! address re-use in same tx
break // txos can match only 1 script
}
}
}