simplify boltdb ingest

This commit is contained in:
Tadge Dryja 2016-02-24 02:37:52 -08:00
parent a14b9a9e70
commit df04a73e1a
3 changed files with 96 additions and 91 deletions

@ -206,7 +206,7 @@ func Bal(args []string) error {
if err != nil {
return err
}
var score int64
var score, confScore int64
for i, u := range allUtxos {
fmt.Printf("\tutxo %d height %d %s key:%d amt %d",
i, u.AtHeight, u.Op.String(), u.KeyIdx, u.Value)
@ -215,6 +215,9 @@ func Bal(args []string) error {
}
fmt.Printf("\n")
score += u.Value
if u.AtHeight != 0 {
confScore += u.Value
}
}
height, _ := SCon.TS.GetDBSyncHeight()
@ -228,7 +231,7 @@ func Bal(args []string) error {
}
fmt.Printf("Total known utxos: %d\n", len(allUtxos))
fmt.Printf("Total spendable coin: %d\n", score)
fmt.Printf("Total coin: %d confirmed: %d\n", score, confScore)
fmt.Printf("DB sync height: %d\n", height)
return nil
}
@ -266,20 +269,22 @@ func Adr(args []string) error {
}
// Fan generates a bunch of fanout. Only for testing, can be expensive.
// syntax: fan numOutputs valOutputs witty
// syntax: fan adr numOutputs valOutputs witty
func Fan(args []string) error {
if len(args) < 3 {
return fmt.Errorf("fan syntax: fan numOutputs valOutputs witty")
return fmt.Errorf("fan syntax: fan adr numOutputs valOutputs")
}
numOutputs, err := strconv.ParseInt(args[0], 10, 64)
adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param)
if err != nil {
fmt.Printf("error parsing %s as address\t", args[0])
return err
}
numOutputs, err := strconv.ParseInt(args[1], 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)
valOutputs, err := strconv.ParseInt(args[2], 10, 64)
if err != nil {
return err
}
@ -287,21 +292,8 @@ func Fan(args []string) error {
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
}
adrs[i] = adr
amts[i] = valOutputs + i
}
@ -331,21 +323,21 @@ func Send(args []string) error {
}
// need args, fail
if len(args) < 2 {
return fmt.Errorf("need args: ssend amount(satoshis) address wit?")
return fmt.Errorf("need args: ssend address amount(satoshis) wit?")
}
amt, err := strconv.ParseInt(args[0], 10, 64)
adr, err := btcutil.DecodeAddress(args[0], SCon.TS.Param)
if err != nil {
fmt.Printf("error parsing %s as address\t", args[0])
return err
}
amt, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return err
}
if amt < 1000 {
return fmt.Errorf("can't send %d, too small", amt)
}
adr, err := btcutil.DecodeAddress(args[1], SCon.TS.Param)
if err != nil {
fmt.Printf("error parsing %s as address\t", args[1])
return err
}
fmt.Printf("send %d to address: %s \n",
amt, adr.String())

@ -43,7 +43,7 @@ func (s *SPVCon) Rebroadcast() {
return
}
// make utxo slices sortable
// make utxo slices sortable -- same as txsort
type utxoSlice []Utxo
// Sort utxos just like txins -- Len, Less, Swap
@ -68,6 +68,13 @@ func (s utxoSlice) Less(i, j int) bool {
return bytes.Compare(ihash[:], jhash[:]) == -1
}
type utxoByAmt []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 }
func (s *SPVCon) NewOutgoingTx(tx *wire.MsgTx) error {
txid := tx.TxSha()
// assign height of zero for txs we create
@ -99,14 +106,22 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
var err error
var score, totalSend, fee int64
dustCutoff := int64(20000) // below this amount, just give to miners
satPerByte := int64(30) // satoshis per byte fee; have as arg later
allUtxos, err := s.TS.GetAllUtxos()
satPerByte := int64(80) // satoshis per byte fee; have as arg later
rawUtxos, err := s.TS.GetAllUtxos()
if err != nil {
return err
}
var allUtxos utxoByAmt
// start with utxos sorted by value.
for _, utxo := range allUtxos {
for _, utxo := range rawUtxos {
score += utxo.Value
allUtxos = append(allUtxos, *utxo)
}
sort.Sort(sort.Reverse(allUtxos))
// sort.Reverse(allUtxos)
for _, u := range allUtxos {
fmt.Printf("%d ", u.Value)
}
for _, amt := range sendAmts {
totalSend += amt
@ -136,8 +151,13 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
// add utxos until we've had enough
nokori := totalSend // nokori is how much is needed on input side
for _, utxo := range allUtxos {
// skip unconfirmed. Or de-prioritize?
// if utxo.AtHeight == 0 {
// continue
// }
// yeah, lets add this utxo!
ins = append(ins, *utxo)
ins = append(ins, utxo)
// as we add utxos, fill in sigscripts
// generate previous pkscripts (subscritpt?) for all utxos
// then make txins with the utxo and prevpk, and insert them into the tx
@ -205,6 +225,11 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
// tx is ready for signing,
sigStash := make([][]byte, len(ins))
witStash := make([][][]byte, len(ins))
// generate tx-wide hashCache for segwit stuff
// middle index number doesn't matter for sighashAll.
hCache := txscript.CalcHashCache(tx, 0, txscript.SigHashAll)
for i, txin := range tx.TxIn {
// pick key
child, err := s.TS.rootPrivKey.Child(
@ -221,7 +246,7 @@ func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error {
// sign into stash
if ins[i].IsWit {
witStash[i], err = txscript.WitnessScript(
tx, i, ins[i].Value, txin.SignatureScript,
tx, hCache, i, ins[i].Value, txin.SignatureScript,
txscript.SigHashAll, priv, true)
if err != nil {
return err

@ -368,16 +368,14 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
spentOPs := make([][]byte, len(tx.TxIn))
// before entering into db, serialize all inputs of the ingested tx
for i, txin := range tx.TxIn {
nOP, err := outPointToBytes(&txin.PreviousOutPoint)
spentOPs[i], err = outPointToBytes(&txin.PreviousOutPoint)
if err != nil {
return hits, err
}
spentOPs[i] = nOP
}
// also generate PKscripts for all addresses (maybe keep storing these?)
for _, adr := range ts.Adrs {
// iterate through all our addresses
// convert regular address to witness address. (split adrs later)
wa, err := btcutil.NewAddressWitnessPubKeyHash(
adr.PkhAdr.ScriptAddress(), ts.Param)
@ -437,59 +435,49 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) {
// first see if we lose utxos
// iterate through duffel bag and look for matches
// 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))
// var delOPs [][]byte
for _, nOP := range spentOPs {
duf.ForEach(func(k, v []byte) error {
if bytes.Equal(k, nOP) { // matched, we lost utxo
fmt.Printf("will delete point %x\n", k)
hits++
// do all this just to figure out value we lost
x := make([]byte, len(k)+len(v))
copy(x, k)
y := make([]byte, len(k))
// mark utxo for deletion
copy(y, k)
delOPs = append(delOPs, y)
copy(x[len(k):], v)
lostTxo, err := UtxoFromBytes(x)
if err != nil {
return err
}
// after marking for deletion, save stxo to old bucket
var st Stxo // generate spent txo
st.Utxo = lostTxo // assign outpoint
st.SpendHeight = height // spent at height
st.SpendTxid = tx.TxSha() // spent by txid
stxb, err := st.ToBytes() // serialize
if err != nil {
return err
}
err = old.Put(k, stxb) // write k:v outpoint:stxo bytes
if err != nil {
return err
}
// store this relevant tx
sha := tx.TxSha()
var buf bytes.Buffer
tx.SerializeWitness(&buf) // always store witness version
err = txns.Put(sha.Bytes(), buf.Bytes())
if err != nil {
return err
}
return nil // matched utxo k, won't match another
v := duf.Get(nOP)
if v != nil {
hits++
// do all this just to figure out value we lost
x := make([]byte, len(nOP)+len(v))
copy(x, nOP)
copy(x[len(nOP):], v)
lostTxo, err := UtxoFromBytes(x)
if err != nil {
return err
}
return nil // no match
})
// delete after done with foreach
// after marking for deletion, save stxo to old bucket
var st Stxo // generate spent txo
st.Utxo = lostTxo // assign outpoint
st.SpendHeight = height // spent at height
st.SpendTxid = tx.TxSha() // spent by txid
stxb, err := st.ToBytes() // serialize
if err != nil {
return err
}
err = old.Put(nOP, stxb) // write nOP:v outpoint:stxo bytes
if err != nil {
return err
}
// store this relevant tx
sha := tx.TxSha()
var buf bytes.Buffer
tx.SerializeWitness(&buf) // always store witness version
err = txns.Put(sha.Bytes(), buf.Bytes())
if err != nil {
return err
}
// stash for deletion
// delOPs = append(delOPs, nOP)
}
}
for _, y := range delOPs {
fmt.Printf("deleting outpoint %x\n", y)
err = duf.Delete(y)
//delete everything even if it doesn't exist!
for _, dOP := range spentOPs {
err = duf.Delete(dOP)
if err != nil {
return err
}