From 1f40c7214ef1087b4f64025956b5b18711ec7aa7 Mon Sep 17 00:00:00 2001 From: Tadge Dryja Date: Wed, 20 Jan 2016 01:23:47 -0800 Subject: [PATCH] good enough storage of spent txs --- uspv/txstore.go | 15 +++++++++++---- uspv/utxodb.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/uspv/txstore.go b/uspv/txstore.go index a0332ee5..7c1abee3 100644 --- a/uspv/txstore.go +++ b/uspv/txstore.go @@ -83,7 +83,7 @@ func (t *TxStore) IngestTx(tx *wire.MsgTx) error { if err != nil { return err } - err = t.ExpellTx(tx) + err = t.ExpellTx(tx, height) if err != nil { return err } @@ -115,7 +115,10 @@ func (t *TxStore) AbsorbTx(tx *wire.MsgTx, height int32) error { newop.Hash = tx.TxSha() newop.Index = uint32(i) newu.Op = newop - + err := newu.SaveToDB(t.StateDB) + if err != nil { + return err + } t.Utxos = append(t.Utxos, newu) break } @@ -127,7 +130,7 @@ func (t *TxStore) AbsorbTx(tx *wire.MsgTx, height int32) error { } // Expell money from wallet due to a tx -func (t *TxStore) ExpellTx(tx *wire.MsgTx) error { +func (t *TxStore) ExpellTx(tx *wire.MsgTx, height int32) error { if tx == nil { return fmt.Errorf("Tried to add nil tx") } @@ -139,7 +142,11 @@ func (t *TxStore) ExpellTx(tx *wire.MsgTx) error { if myutxo.Op == in.PreviousOutPoint { hits++ loss += myutxo.Txo.Value - // delete from my utxo set + err := t.MarkSpent(&myutxo.Op, height, tx) + if err != nil { + return err + } + // delete from my in-ram utxo set t.Utxos = append(t.Utxos[:i], t.Utxos[i+1:]...) } } diff --git a/uspv/utxodb.go b/uspv/utxodb.go index abfb2f94..32fcf06b 100644 --- a/uspv/utxodb.go +++ b/uspv/utxodb.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "fmt" + "github.com/btcsuite/btcd/wire" + "github.com/boltdb/bolt" ) @@ -26,8 +28,32 @@ func (u *Utxo) SaveToDB(dbx *bolt.DB) error { }) } -func (ts *TxStore) LoadUtxos() error { +func (ts *TxStore) MarkSpent(op *wire.OutPoint, h int32, stx *wire.MsgTx) error { + // we write in key = outpoint (32 hash, 4 index) + // value = spending txid + // if we care about the spending tx we can store that in another bucket. + return ts.StateDB.Update(func(tx *bolt.Tx) error { + old := tx.Bucket(BKTOld) + opb, err := outPointToBytes(op) + if err != nil { + return err + } + var buf bytes.Buffer + err = binary.Write(&buf, binary.BigEndian, h) + if err != nil { + return err + } + sha := stx.TxSha() + err = old.Put(opb, sha.Bytes()) // write k:v outpoint:txid + if err != nil { + return err + } + return nil + }) +} + +func (ts *TxStore) LoadUtxos() error { err := ts.StateDB.View(func(tx *bolt.Tx) error { duf := tx.Bucket(BKTUtxos) if duf == nil { @@ -41,7 +67,8 @@ func (ts *TxStore) LoadUtxos() error { duf.ForEach(func(k, v []byte) error { // have to copy these here, otherwise append will crash it. // not quite sure why but append does weird stuff I guess. - if spent.Get(k) == nil { // if it's not in the spent bucket + stx := spent.Get(k) + if stx == nil { // if it's not in the spent bucket // create a new utxo x := make([]byte, len(k)+len(v)) copy(x, k) @@ -52,6 +79,9 @@ func (ts *TxStore) LoadUtxos() error { } // and add it to ram ts.Utxos = append(ts.Utxos, newU) + } else { + fmt.Printf("had utxo %x but spent by tx %x...\n", + k, stx[:8]) } return nil }) @@ -63,6 +93,21 @@ func (ts *TxStore) LoadUtxos() error { return nil } +// outPointToBytes turns an outpoint into 36 bytes. +func outPointToBytes(op *wire.OutPoint) ([]byte, error) { + var buf bytes.Buffer + _, err := buf.Write(op.Hash.Bytes()) + if err != nil { + return nil, err + } + // write 4 byte outpoint index within the tx to spend + err = binary.Write(&buf, binary.BigEndian, op.Index) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + // ToBytes turns a Utxo into some bytes. // note that the txid is the first 36 bytes and in our use cases will be stripped // off, but is left here for other applications