2013-08-26 16:48:42 +02:00
|
|
|
/*
|
2014-01-09 20:12:20 +01:00
|
|
|
* Copyright (c) 2013, 2014 Conformal Systems LLC <info@conformal.com>
|
2013-08-26 16:48:42 +02:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
package tx_test
|
2013-08-26 16:48:42 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-02-24 20:35:30 +01:00
|
|
|
"encoding/hex"
|
2013-08-26 16:48:42 +02:00
|
|
|
"testing"
|
2014-02-24 20:35:30 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/conformal/btcutil"
|
|
|
|
. "github.com/conformal/btcwallet/tx"
|
|
|
|
"github.com/conformal/btcwire"
|
2013-08-26 16:48:42 +02:00
|
|
|
)
|
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
// Received transaction output for mainnet outpoint
|
|
|
|
// 61d3696de4c888730cbe06b0ad8ecb6d72d6108e893895aa9bc067bd7eba3fad:0
|
2013-08-26 16:48:42 +02:00
|
|
|
var (
|
2014-02-24 20:35:30 +01:00
|
|
|
TstRecvSerializedTx, _ = hex.DecodeString("010000000114d9ff358894c486b4ae11c2a8cf7851b1df64c53d2e511278eff17c22fb7373000000008c493046022100995447baec31ee9f6d4ec0e05cb2a44f6b817a99d5f6de167d1c75354a946410022100c9ffc23b64d770b0e01e7ff4d25fbc2f1ca8091053078a247905c39fce3760b601410458b8e267add3c1e374cf40f1de02b59213a82e1d84c2b94096e22e2f09387009c96debe1d0bcb2356ffdcf65d2a83d4b34e72c62eccd8490dbf2110167783b2bffffffff0280969800000000001976a914479ed307831d0ac19ebc5f63de7d5f1a430ddb9d88ac38bfaa00000000001976a914dadf9e3484f28b385ddeaa6c575c0c0d18e9788a88ac00000000")
|
|
|
|
TstRecvTx, _ = btcutil.NewTxFromBytes(TstRecvSerializedTx)
|
|
|
|
TstRecvTxSpendingTxBlockHash, _ = btcwire.NewShaHashFromStr("00000000000000017188b968a371bab95aa43522665353b646e41865abae02a4")
|
|
|
|
TstRecvAmt = int64(10000000)
|
|
|
|
TstRecvTxBlockDetails = &BlockDetails{
|
|
|
|
Height: 276425,
|
|
|
|
Hash: *TstRecvTxSpendingTxBlockHash,
|
|
|
|
Index: 684,
|
|
|
|
Time: time.Unix(1387737310, 0),
|
|
|
|
}
|
|
|
|
|
|
|
|
TstRecvCurrentHeight = int32(284498) // mainnet blockchain height at time of writing
|
|
|
|
TstRecvTxOutConfirms = 8074 // hardcoded number of confirmations given the above block height
|
|
|
|
|
|
|
|
TstSpendingTxBlockHeight = int32(279143)
|
|
|
|
TstSignedTxBlockHash, _ = btcwire.NewShaHashFromStr("00000000000000017188b968a371bab95aa43522665353b646e41865abae02a4")
|
|
|
|
TstSignedTxBlockDetails = &BlockDetails{
|
|
|
|
Height: TstSpendingTxBlockHeight,
|
|
|
|
Hash: *TstSignedTxBlockHash,
|
|
|
|
Index: 123,
|
|
|
|
Time: time.Unix(1389114091, 0),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTxStore(t *testing.T) {
|
|
|
|
// Create a double spend of the received blockchain transaction.
|
|
|
|
dupRecvTx, _ := btcutil.NewTxFromBytes(TstRecvSerializedTx)
|
|
|
|
// Switch txout amount to 1 BTC. Transaction store doesn't
|
|
|
|
// validate txs, so this is fine for testing a double spend
|
|
|
|
// removal.
|
|
|
|
TstDupRecvAmount := int64(1e8)
|
|
|
|
newDupMsgTx := dupRecvTx.MsgTx()
|
|
|
|
newDupMsgTx.TxOut[0].Value = TstDupRecvAmount
|
|
|
|
TstDoubleSpendTx := btcutil.NewTx(newDupMsgTx)
|
|
|
|
|
|
|
|
// Create a "signed" (with invalid sigs) tx that spends output 0 of
|
|
|
|
// the double spend.
|
|
|
|
spendingTx := btcwire.NewMsgTx()
|
|
|
|
spendingTxIn := btcwire.NewTxIn(btcwire.NewOutPoint(TstDoubleSpendTx.Sha(), 0), []byte{0, 1, 2, 3, 4})
|
|
|
|
spendingTx.AddTxIn(spendingTxIn)
|
|
|
|
spendingTxOut1 := btcwire.NewTxOut(1e7, []byte{5, 6, 7, 8, 9})
|
|
|
|
spendingTxOut2 := btcwire.NewTxOut(9e7, []byte{10, 11, 12, 13, 14})
|
|
|
|
spendingTx.AddTxOut(spendingTxOut1)
|
|
|
|
spendingTx.AddTxOut(spendingTxOut2)
|
|
|
|
TstSpendingTx := btcutil.NewTx(spendingTx)
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2014-02-28 19:03:23 +01:00
|
|
|
f func(*Store) (*Store, error)
|
|
|
|
err error
|
2014-02-24 20:35:30 +01:00
|
|
|
bal, unc int64
|
|
|
|
unspents map[btcwire.OutPoint]struct{}
|
|
|
|
unmined map[btcwire.ShaHash]struct{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "new store",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(_ *Store) (*Store, error) {
|
|
|
|
return NewStore(), nil
|
2014-02-24 20:35:30 +01:00
|
|
|
},
|
2014-02-28 19:03:23 +01:00
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
|
|
|
name: "txout insert",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, time.Now(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// If the above succeeded, try using the record. This will
|
|
|
|
// dereference the tx and panic if the above didn't catch
|
|
|
|
// an inconsistant insert.
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: TstRecvTx.MsgTx().TxOut[0].Value,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
2014-02-28 19:03:23 +01:00
|
|
|
name: "insert duplicate unconfirmed",
|
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, time.Now(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
|
|
|
bal: 0,
|
|
|
|
unc: TstRecvTx.MsgTx().TxOut[0].Value,
|
2014-02-24 20:35:30 +01:00
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
2014-02-28 19:03:23 +01:00
|
|
|
name: "confirmed txout insert",
|
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, TstRecvTxBlockDetails.Time, TstRecvTxBlockDetails)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstRecvTx.MsgTx().TxOut[0].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
2014-02-28 19:03:23 +01:00
|
|
|
name: "insert duplicate confirmed",
|
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, TstRecvTxBlockDetails.Time, TstRecvTxBlockDetails)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstRecvTx.MsgTx().TxOut[0].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-28 19:03:23 +01:00
|
|
|
{
|
|
|
|
name: "insert duplicate unconfirmed",
|
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, time.Now(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: ErrInconsistantStore,
|
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
|
|
|
name: "insert double spend with new txout value",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstDoubleSpendTx, 0, false, TstRecvTxBlockDetails.Time, TstRecvTxBlockDetails)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstDoubleSpendTx.MsgTx().TxOut[0].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstDoubleSpendTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
2013-08-26 19:34:18 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
|
|
|
name: "insert unconfirmed signed tx",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-03-18 23:52:08 +01:00
|
|
|
r, err := s.InsertSignedTx(TstSpendingTx, time.Now(), nil)
|
2014-02-28 19:03:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
|
|
|
},
|
2013-09-04 15:32:14 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
|
|
|
name: "insert unconfirmed signed tx again",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-03-18 23:52:08 +01:00
|
|
|
r, err := s.InsertSignedTx(TstSpendingTx, time.Now(), nil)
|
2014-02-28 19:03:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
2013-09-04 22:16:20 +02:00
|
|
|
},
|
2013-08-26 16:48:42 +02:00
|
|
|
},
|
2014-02-24 20:35:30 +01:00
|
|
|
{
|
|
|
|
name: "insert change (index 0)",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstSpendingTx, 0, true, time.Now(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: TstSpendingTx.MsgTx().TxOut[0].Value,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "insert output back to this own wallet (index 1)",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstSpendingTx, 1, true, time.Now(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "confirmed signed tx",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-03-18 23:52:08 +01:00
|
|
|
r, err := s.InsertSignedTx(TstSpendingTx, TstSignedTxBlockDetails.Time, TstSignedTxBlockDetails)
|
2014-02-28 19:03:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "rollback after spending tx",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-02-24 20:35:30 +01:00
|
|
|
s.Rollback(TstSignedTxBlockDetails.Height + 1)
|
2014-02-28 19:03:23 +01:00
|
|
|
return s, nil
|
2014-02-24 20:35:30 +01:00
|
|
|
},
|
2014-02-28 19:03:23 +01:00
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "rollback spending tx block",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-02-24 20:35:30 +01:00
|
|
|
s.Rollback(TstSignedTxBlockDetails.Height)
|
2014-02-28 19:03:23 +01:00
|
|
|
return s, nil
|
2014-02-24 20:35:30 +01:00
|
|
|
},
|
2014-02-28 19:03:23 +01:00
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "rollback double spend tx block",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
2014-02-24 20:35:30 +01:00
|
|
|
s.Rollback(TstRecvTxBlockDetails.Height)
|
2014-02-28 19:03:23 +01:00
|
|
|
return s, nil
|
2014-02-24 20:35:30 +01:00
|
|
|
},
|
2014-02-28 19:03:23 +01:00
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: 0,
|
|
|
|
unc: TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 0): struct{}{},
|
|
|
|
*btcwire.NewOutPoint(TstSpendingTx.Sha(), 1): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{
|
|
|
|
*TstSpendingTx.Sha(): struct{}{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "insert original recv txout",
|
2014-02-28 19:03:23 +01:00
|
|
|
f: func(s *Store) (*Store, error) {
|
|
|
|
r, err := s.InsertRecvTxOut(TstRecvTx, 0, false, TstRecvTxBlockDetails.Time, TstRecvTxBlockDetails)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = r.TxInfo("", 100, btcwire.MainNet)
|
|
|
|
return s, nil
|
|
|
|
},
|
|
|
|
err: nil,
|
2014-02-24 20:35:30 +01:00
|
|
|
bal: TstRecvTx.MsgTx().TxOut[0].Value,
|
|
|
|
unc: 0,
|
|
|
|
unspents: map[btcwire.OutPoint]struct{}{
|
|
|
|
*btcwire.NewOutPoint(TstRecvTx.Sha(), 0): struct{}{},
|
|
|
|
},
|
|
|
|
unmined: map[btcwire.ShaHash]struct{}{},
|
|
|
|
},
|
2013-08-26 16:48:42 +02:00
|
|
|
}
|
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
var s *Store
|
|
|
|
for _, test := range tests {
|
2014-02-28 19:03:23 +01:00
|
|
|
tmpStore, err := test.f(s)
|
|
|
|
if err != test.err {
|
|
|
|
t.Fatalf("%s: error mismatch: expected: %v, got: %v", test.name, test.err, err)
|
|
|
|
}
|
|
|
|
if test.err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
s = tmpStore
|
2014-02-24 20:35:30 +01:00
|
|
|
bal := s.Balance(1, TstRecvCurrentHeight)
|
|
|
|
if bal != test.bal {
|
2014-02-28 19:03:23 +01:00
|
|
|
t.Errorf("%s: balance mismatch: expected: %d, got: %d", test.name, test.bal, bal)
|
2013-08-26 16:48:42 +02:00
|
|
|
}
|
2014-02-24 20:35:30 +01:00
|
|
|
unc := s.Balance(0, TstRecvCurrentHeight) - bal
|
|
|
|
if unc != test.unc {
|
|
|
|
t.Errorf("%s: unconfimred balance mismatch: expected %d, got %d", test.name, test.unc, unc)
|
2013-11-22 19:42:25 +01:00
|
|
|
}
|
2013-08-26 16:48:42 +02:00
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
// Check that unspent outputs match expected.
|
|
|
|
for _, record := range s.UnspentOutputs() {
|
|
|
|
if record.Spent() {
|
|
|
|
t.Errorf("%s: unspent record marked as spent", test.name)
|
|
|
|
}
|
2013-08-26 16:48:42 +02:00
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
op := *record.OutPoint()
|
|
|
|
if _, ok := test.unspents[op]; !ok {
|
|
|
|
t.Errorf("%s: unexpected unspent output: %v", test.name, op)
|
|
|
|
}
|
|
|
|
delete(test.unspents, op)
|
|
|
|
}
|
|
|
|
if len(test.unspents) != 0 {
|
|
|
|
t.Errorf("%s: missing expected unspent output(s)", test.name)
|
|
|
|
}
|
2013-08-26 19:34:18 +02:00
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
// Check that unmined signed txs match expected.
|
|
|
|
for _, tx := range s.UnminedSignedTxs() {
|
|
|
|
if _, ok := test.unmined[*tx.Sha()]; !ok {
|
|
|
|
t.Errorf("%s: unexpected unmined signed tx: %v", test.name, *tx.Sha())
|
|
|
|
}
|
|
|
|
delete(test.unmined, *tx.Sha())
|
|
|
|
}
|
|
|
|
if len(test.unmined) != 0 {
|
|
|
|
t.Errorf("%s: missing expected unmined signed tx(s)", test.name)
|
|
|
|
}
|
2013-08-26 19:34:18 +02:00
|
|
|
|
2014-02-24 20:35:30 +01:00
|
|
|
// Pass a re-serialized version of the store to each next test.
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
nWritten, err := s.WriteTo(buf)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%v: serialization failed: %v (wrote %v bytes)", test.name, err, nWritten)
|
|
|
|
}
|
|
|
|
if nWritten != int64(buf.Len()) {
|
|
|
|
t.Errorf("%v: wrote %v bytes but buffer has %v", test.name, nWritten, buf.Len())
|
|
|
|
}
|
|
|
|
nRead, err := s.ReadFrom(buf)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%v: deserialization failed: %v (read %v bytes after writing %v)",
|
|
|
|
test.name, err, nRead, nWritten)
|
|
|
|
}
|
|
|
|
if nWritten != nRead {
|
|
|
|
t.Errorf("%v: number of bytes written (%v) does not match those read (%v)",
|
|
|
|
test.name, nWritten, nRead)
|
|
|
|
}
|
2013-08-26 19:34:18 +02:00
|
|
|
}
|
|
|
|
}
|