add fanout. fix boltdb weirdness.

again with keys / values within the bolttx acting weird.
it wasn't deleting utxos that had been spent by the ingested tx.
it'd do the first 30 then stop.  Deferred deletion and copied the
serialized utxo.  Not sure which of those fixed it.  Maybe both.
This commit is contained in:
Tadge Dryja 2016-02-22 16:32:58 -08:00
parent bc4cf5ba80
commit dd1f2c00fe
3 changed files with 104 additions and 31 deletions

@ -140,6 +140,13 @@ func Shellparse(cmdslice []string) error {
} }
return nil return nil
} }
if cmd == "fan" {
err = Fan(args)
if err != nil {
fmt.Printf("fan error: %s\n", err)
}
return nil
}
if cmd == "txs" { if cmd == "txs" {
err = Txs(args) err = Txs(args)
if err != nil { if err != nil {
@ -238,6 +245,14 @@ func Adr(args []string) error {
} }
} }
} }
if len(args) > 1 {
for i := 0; i < 1000; i++ {
_, err := SCon.TS.NewAdr()
if err != nil {
return err
}
}
}
// always make one // always make one
a, err := SCon.TS.NewAdr() a, err := SCon.TS.NewAdr()
@ -250,6 +265,50 @@ func Adr(args []string) error {
return nil return nil
} }
// Fan generates a bunch of fanout. Only for testing, can be expensive.
// syntax: fan numOutputs valOutputs witty
func Fan(args []string) error {
if len(args) < 3 {
return fmt.Errorf("fan syntax: fan numOutputs valOutputs witty")
}
numOutputs, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return err
}
valOutputs, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return err
}
wittynum, err := strconv.ParseInt(args[2], 10, 64)
if err != nil {
return err
}
adrs := make([]btcutil.Address, numOutputs)
amts := make([]int64, numOutputs)
oAdr, err := SCon.TS.NewAdr()
if err != nil {
return err
}
for i := int64(0); i < numOutputs; i++ {
if wittynum != 0 {
wAdr, err := btcutil.NewAddressWitnessPubKeyHash(
oAdr.ScriptAddress(), SCon.TS.Param)
if err != nil {
return err
}
adrs[i] = wAdr
} else {
adrs[i] = oAdr
}
amts[i] = valOutputs + i
}
return SCon.SendCoins(adrs, amts)
}
// Send sends coins. // Send sends coins.
func Send(args []string) error { func Send(args []string) error {
if SCon.RBytes == 0 { if SCon.RBytes == 0 {

@ -160,33 +160,39 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
} }
tx.AddTxIn(wire.NewTxIn(&utxo.Op, prevPKs, nil)) tx.AddTxIn(wire.NewTxIn(&utxo.Op, prevPKs, nil))
nokori -= utxo.Value nokori -= utxo.Value
fee = EstFee(tx, satPerByte) // if nokori is positive, don't bother checking fee yet.
if nokori < -fee { // done adding utxos: nokori below negative est. fee if nokori < 0 {
break fee = EstFee(tx, satPerByte)
if nokori < -fee { // done adding utxos: nokori below negative est. fee
break
}
} }
} }
// see if there's enough left to also add a change output // see if there's enough left to also add a change output
if nokori < -dustCutoff {
changeOld, err := s.TS.NewAdr() // change is witnessy
if err != nil {
return err
}
changeAdr, err := btcutil.NewAddressWitnessPubKeyHash(
changeOld.ScriptAddress(), s.TS.Param)
if err != nil {
return err
}
changeScript, err := txscript.PayToAddrScript(changeAdr) changeOld, err := s.TS.NewAdr() // change is witnessy
if err != nil { if err != nil {
return err return err
} }
changeAdr, err := btcutil.NewAddressWitnessPubKeyHash(
changeOld.ScriptAddress(), s.TS.Param)
if err != nil {
return err
}
changeOut := wire.NewTxOut(0, changeScript) changeScript, err := txscript.PayToAddrScript(changeAdr)
tx.AddTxOut(changeOut) if err != nil {
fee = EstFee(tx, satPerByte) return err
changeOut.Value = -(nokori + fee) }
changeOut := wire.NewTxOut(0, changeScript)
tx.AddTxOut(changeOut)
fee = EstFee(tx, satPerByte)
changeOut.Value = -(nokori + fee)
if changeOut.Value < dustCutoff {
// remove last output (change) : not worth it
tx.TxOut = tx.TxOut[:len(tx.TxOut)-1]
} }
// sort utxos on the input side. use this instead of txsort // sort utxos on the input side. use this instead of txsort

@ -353,7 +353,6 @@ func (ts *TxStore) PopulateAdrs(lastKey uint32) error {
func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
var hits uint32 var hits uint32
var err error var err error
var spentOPs [][]byte
var nUtxoBytes [][]byte var nUtxoBytes [][]byte
// tx has been OK'd by SPV; check tx sanity // tx has been OK'd by SPV; check tx sanity
@ -366,13 +365,14 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
// note that you can't check signatures; this is SPV. // note that you can't check signatures; this is SPV.
// 0 conf SPV means pretty much nothing. Anyone can say anything. // 0 conf SPV means pretty much nothing. Anyone can say anything.
spentOPs := make([][]byte, len(tx.TxIn))
// before entering into db, serialize all inputs of the ingested tx // before entering into db, serialize all inputs of the ingested tx
for _, txin := range tx.TxIn { for i, txin := range tx.TxIn {
nOP, err := outPointToBytes(&txin.PreviousOutPoint) nOP, err := outPointToBytes(&txin.PreviousOutPoint)
if err != nil { if err != nil {
return hits, err return hits, err
} }
spentOPs = append(spentOPs, nOP) spentOPs[i] = nOP
} }
// also generate PKscripts for all addresses (maybe keep storing these?) // also generate PKscripts for all addresses (maybe keep storing these?)
for _, adr := range ts.Adrs { for _, adr := range ts.Adrs {
@ -419,7 +419,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
} }
nUtxoBytes = append(nUtxoBytes, b) nUtxoBytes = append(nUtxoBytes, b)
hits++ hits++
break // only one match // break // keep looking! address re-use in same tx
} }
} }
} }
@ -437,24 +437,25 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
// first see if we lose utxos // first see if we lose utxos
// iterate through duffel bag and look for matches // iterate through duffel bag and look for matches
// this makes us lose money, which is regrettable, but we need to know. // this makes us lose money, which is regrettable, but we need to know.
var delOPs [][]byte
fmt.Printf("%d nOP to iterate over\n", len(spentOPs))
for _, nOP := range spentOPs { for _, nOP := range spentOPs {
duf.ForEach(func(k, v []byte) error { duf.ForEach(func(k, v []byte) error {
if bytes.Equal(k, nOP) { // matched, we lost utxo if bytes.Equal(k, nOP) { // matched, we lost utxo
// do all this just to figure out value we lost // do all this just to figure out value we lost
x := make([]byte, len(k)+len(v)) x := make([]byte, len(k)+len(v))
copy(x, k) copy(x, k)
// mark utxos for deletion
delOPs = append(delOPs, x)
copy(x[len(k):], v) copy(x[len(k):], v)
lostTxo, err := UtxoFromBytes(x) lostTxo, err := UtxoFromBytes(x)
if err != nil { if err != nil {
return err return err
} }
hits++ hits++
// then delete the utxo from duf, save to old
err = duf.Delete(k) // after marking for deletion, save stxo to old bucket
if err != nil {
return err
}
// after deletion, save stxo to old bucket
var st Stxo // generate spent txo var st Stxo // generate spent txo
st.Utxo = lostTxo // assign outpoint st.Utxo = lostTxo // assign outpoint
st.SpendHeight = height // spent at height st.SpendHeight = height // spent at height
@ -480,6 +481,13 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
} }
return nil // no match return nil // no match
}) })
// delete after done with foreach
for _, k := range delOPs {
err = duf.Delete(k)
if err != nil {
return err
}
}
} // done losing utxos, next gain utxos } // done losing utxos, next gain utxos
// next add all new utxos to db, this is quick as the work is above // next add all new utxos to db, this is quick as the work is above
for _, ub := range nUtxoBytes { for _, ub := range nUtxoBytes {