From 63b5926e01fe38c16c248fca5f372064abca499d Mon Sep 17 00:00:00 2001 From: Tadge Dryja Date: Fri, 5 Feb 2016 01:59:40 -0800 Subject: [PATCH] add getalltxs, dup checks Start of double spend detection for mempool and reorgs --- shell.go | 18 ++++++++++++++++++ uspv/txstore.go | 33 ++++++++++++++++++++++++++++++++- uspv/utxodb.go | 27 +++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/shell.go b/shell.go index cf1def75..21dd499a 100644 --- a/shell.go +++ b/shell.go @@ -144,11 +144,29 @@ func Shellparse(cmdslice []string) error { } return nil } + if cmd == "txs" { + err = Txs(args) + if err != nil { + fmt.Printf("txs error: %s\n", err) + } + return nil + } fmt.Printf("Command not recognized. type help for command list.\n") return nil } +func Txs(args []string) error { + alltx, err := SCon.TS.GetAllTxs() + if err != nil { + return err + } + for i, tx := range alltx { + fmt.Printf("tx %d %s\n", i, uspv.TxToString(tx)) + } + return nil +} + // Bal prints out your score. func Bal(args []string) error { if SCon.TS == nil { diff --git a/uspv/txstore.go b/uspv/txstore.go index 6fde5fe8..b5596ef7 100644 --- a/uspv/txstore.go +++ b/uspv/txstore.go @@ -100,9 +100,40 @@ func (t *TxStore) GimmeFilter() (*bloom.Filter, error) { return f, nil } +// GetDoubleSpends takes a transaction and compares it with +// all transactions in the db. It returns a slice of all txids in the db +// which are double spent by the received tx. +func GetDoubleSpends( + argTx *wire.MsgTx, txs []*wire.MsgTx) ([]*wire.ShaHash, error) { + + var dubs []*wire.ShaHash // slice of all double-spent txs + argTxid := argTx.TxSha() + + for _, compTx := range txs { + compTxid := compTx.TxSha() + // check if entire tx is dup + if argTxid.IsEqual(&compTxid) { + return nil, fmt.Errorf("tx %s is dup", argTxid.String()) + } + // not dup, iterate through inputs of argTx + for _, argIn := range argTx.TxIn { + // iterate through inputs of compTx + for _, compIn := range compTx.TxIn { + if OutPointsEqual( + argIn.PreviousOutPoint, compIn.PreviousOutPoint) { + // found double spend + dubs = append(dubs, &compTxid) + break // back to argIn loop + } + } + } + } + return dubs, nil +} + // TxToString prints out some info about a transaction. for testing / debugging func TxToString(tx *wire.MsgTx) string { - str := "\t\t\t - Tx - \n" + str := fmt.Sprintf("\t - Tx %s\n", tx.TxSha().String()) for i, in := range tx.TxIn { str += fmt.Sprintf("Input %d: %s\n", i, in.PreviousOutPoint.String()) str += fmt.Sprintf("SigScript for input %d: %x\n", i, in.SignatureScript) diff --git a/uspv/utxodb.go b/uspv/utxodb.go index 26e5360a..8c08449a 100644 --- a/uspv/utxodb.go +++ b/uspv/utxodb.go @@ -248,6 +248,33 @@ func (ts *TxStore) GetTx(txid *wire.ShaHash) (*wire.MsgTx, error) { return rtx, nil } +// GetTx takes a txid and returns the transaction. If we have it. +func (ts *TxStore) GetAllTxs() ([]*wire.MsgTx, error) { + var rtxs []*wire.MsgTx + + err := ts.StateDB.View(func(btx *bolt.Tx) error { + txns := btx.Bucket(BKTTxns) + if txns == nil { + return fmt.Errorf("no transactions in db") + } + + return txns.ForEach(func(k, v []byte) error { + tx := wire.NewMsgTx() + buf := bytes.NewBuffer(v) + err := tx.Deserialize(buf) + if err != nil { + return err + } + rtxs = append(rtxs, tx) + return nil + }) + }) + if err != nil { + return nil, err + } + return rtxs, nil +} + // GetPendingInv returns an inv message containing all txs known to the // db which are at height 0 (not known to be confirmed). // This can be useful on startup or to rebroadcast unconfirmed txs.